mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-20 05:31:15 +00:00
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris:
"Highlights:
- PKCS#7 support added to support signed kexec, also utilized for
module signing. See comments in 3f1e1bea
.
** NOTE: this requires linking against the OpenSSL library, which
must be installed, e.g. the openssl-devel on Fedora **
- Smack
- add IPv6 host labeling; ignore labels on kernel threads
- support smack labeling mounts which use binary mount data
- SELinux:
- add ioctl whitelisting (see
http://kernsec.org/files/lss2015/vanderstoep.pdf)
- fix mprotect PROT_EXEC regression caused by mm change
- Seccomp:
- add ptrace options for suspend/resume"
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (57 commits)
PKCS#7: Add OIDs for sha224, sha284 and sha512 hash algos and use them
Documentation/Changes: Now need OpenSSL devel packages for module signing
scripts: add extract-cert and sign-file to .gitignore
modsign: Handle signing key in source tree
modsign: Use if_changed rule for extracting cert from module signing key
Move certificate handling to its own directory
sign-file: Fix warning about BIO_reset() return value
PKCS#7: Add MODULE_LICENSE() to test module
Smack - Fix build error with bringup unconfigured
sign-file: Document dependency on OpenSSL devel libraries
PKCS#7: Appropriately restrict authenticated attributes and content type
KEYS: Add a name for PKEY_ID_PKCS7
PKCS#7: Improve and export the X.509 ASN.1 time object decoder
modsign: Use extract-cert to process CONFIG_SYSTEM_TRUSTED_KEYS
extract-cert: Cope with multiple X.509 certificates in a single file
sign-file: Generate CMS message as signature instead of PKCS#7
PKCS#7: Support CMS messages also [RFC5652]
X.509: Change recorded SKID & AKID to not include Subject or Issuer
PKCS#7: Check content type and versions
MAINTAINERS: The keyrings mailing list has moved
...
This commit is contained in:
commit
b793c005ce
76 changed files with 3593 additions and 1412 deletions
2
scripts/.gitignore
vendored
2
scripts/.gitignore
vendored
|
@ -10,3 +10,5 @@ recordmcount
|
|||
docproc
|
||||
sortextable
|
||||
asn1_compiler
|
||||
extract-cert
|
||||
sign-file
|
||||
|
|
|
@ -303,3 +303,54 @@ why = \
|
|||
|
||||
echo-why = $(call escsq, $(strip $(why)))
|
||||
endif
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# When a Kconfig string contains a filename, it is suitable for
|
||||
# passing to shell commands. It is surrounded by double-quotes, and
|
||||
# any double-quotes or backslashes within it are escaped by
|
||||
# backslashes.
|
||||
#
|
||||
# This is no use for dependencies or $(wildcard). We need to strip the
|
||||
# surrounding quotes and the escaping from quotes and backslashes, and
|
||||
# we *do* need to escape any spaces in the string. So, for example:
|
||||
#
|
||||
# Usage: $(eval $(call config_filename,FOO))
|
||||
#
|
||||
# Defines FOO_FILENAME based on the contents of the CONFIG_FOO option,
|
||||
# transformed as described above to be suitable for use within the
|
||||
# makefile.
|
||||
#
|
||||
# Also, if the filename is a relative filename and exists in the source
|
||||
# tree but not the build tree, define FOO_SRCPREFIX as $(srctree)/ to
|
||||
# be prefixed to *both* command invocation and dependencies.
|
||||
#
|
||||
# Note: We also print the filenames in the quiet_cmd_foo text, and
|
||||
# perhaps ought to have a version specially escaped for that purpose.
|
||||
# But it's only cosmetic, and $(patsubst "%",%,$(CONFIG_FOO)) is good
|
||||
# enough. It'll strip the quotes in the common case where there's no
|
||||
# space and it's a simple filename, and it'll retain the quotes when
|
||||
# there's a space. There are some esoteric cases in which it'll print
|
||||
# the wrong thing, but we don't really care. The actual dependencies
|
||||
# and commands *do* get it right, with various combinations of single
|
||||
# and double quotes, backslashes and spaces in the filenames.
|
||||
#
|
||||
###############################################################################
|
||||
#
|
||||
space_escape := %%%SPACE%%%
|
||||
#
|
||||
define config_filename
|
||||
ifneq ($$(CONFIG_$(1)),"")
|
||||
$(1)_FILENAME := $$(subst \\,\,$$(subst \$$(quote),$$(quote),$$(subst $$(space_escape),\$$(space),$$(patsubst "%",%,$$(subst $$(space),$$(space_escape),$$(CONFIG_$(1)))))))
|
||||
ifneq ($$(patsubst /%,%,$$(firstword $$($(1)_FILENAME))),$$(firstword $$($(1)_FILENAME)))
|
||||
else
|
||||
ifeq ($$(wildcard $$($(1)_FILENAME)),)
|
||||
ifneq ($$(wildcard $$(srctree)/$$($(1)_FILENAME)),)
|
||||
$(1)_SRCPREFIX := $(srctree)/
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endef
|
||||
#
|
||||
###############################################################################
|
||||
|
|
|
@ -16,9 +16,13 @@ hostprogs-$(CONFIG_VT) += conmakehash
|
|||
hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
|
||||
hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
|
||||
hostprogs-$(CONFIG_ASN1) += asn1_compiler
|
||||
hostprogs-$(CONFIG_MODULE_SIG) += sign-file
|
||||
hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert
|
||||
|
||||
HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include
|
||||
HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
|
||||
HOSTLOADLIBES_sign-file = -lcrypto
|
||||
HOSTLOADLIBES_extract-cert = -lcrypto
|
||||
|
||||
always := $(hostprogs-y) $(hostprogs-m)
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ quiet_cmd_modules_install = INSTALL $@
|
|||
mkdir -p $(2) ; \
|
||||
cp $@ $(2) ; \
|
||||
$(mod_strip_cmd) $(2)/$(notdir $@) ; \
|
||||
$(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) ; \
|
||||
$(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) && \
|
||||
$(mod_compress_cmd) $(2)/$(notdir $@)
|
||||
|
||||
# Modules built outside the kernel source tree go into extra by default
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
|
@ -293,8 +294,8 @@ static const char *const directives[NR__DIRECTIVES] = {
|
|||
|
||||
struct action {
|
||||
struct action *next;
|
||||
char *name;
|
||||
unsigned char index;
|
||||
char name[];
|
||||
};
|
||||
|
||||
static struct action *action_list;
|
||||
|
@ -305,15 +306,17 @@ struct token {
|
|||
enum token_type token_type : 8;
|
||||
unsigned char size;
|
||||
struct action *action;
|
||||
const char *value;
|
||||
char *content;
|
||||
struct type *type;
|
||||
};
|
||||
|
||||
static struct token *token_list;
|
||||
static unsigned nr_tokens;
|
||||
static _Bool verbose;
|
||||
static bool verbose_opt;
|
||||
static bool debug_opt;
|
||||
|
||||
#define debug(fmt, ...) do { if (verbose) printf(fmt, ## __VA_ARGS__); } while (0)
|
||||
#define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0)
|
||||
#define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0)
|
||||
|
||||
static int directive_compare(const void *_key, const void *_pdir)
|
||||
{
|
||||
|
@ -325,11 +328,9 @@ static int directive_compare(const void *_key, const void *_pdir)
|
|||
dlen = strlen(dir);
|
||||
clen = (dlen < token->size) ? dlen : token->size;
|
||||
|
||||
//debug("cmp(%*.*s,%s) = ",
|
||||
// (int)token->size, (int)token->size, token->value,
|
||||
// dir);
|
||||
//debug("cmp(%s,%s) = ", token->content, dir);
|
||||
|
||||
val = memcmp(token->value, dir, clen);
|
||||
val = memcmp(token->content, dir, clen);
|
||||
if (val != 0) {
|
||||
//debug("%d [cmp]\n", val);
|
||||
return val;
|
||||
|
@ -349,7 +350,7 @@ static int directive_compare(const void *_key, const void *_pdir)
|
|||
static void tokenise(char *buffer, char *end)
|
||||
{
|
||||
struct token *tokens;
|
||||
char *line, *nl, *p, *q;
|
||||
char *line, *nl, *start, *p, *q;
|
||||
unsigned tix, lineno;
|
||||
|
||||
/* Assume we're going to have half as many tokens as we have
|
||||
|
@ -408,11 +409,11 @@ static void tokenise(char *buffer, char *end)
|
|||
break;
|
||||
|
||||
tokens[tix].line = lineno;
|
||||
tokens[tix].value = p;
|
||||
start = p;
|
||||
|
||||
/* Handle string tokens */
|
||||
if (isalpha(*p)) {
|
||||
const char **dir;
|
||||
const char **dir, *start = p;
|
||||
|
||||
/* Can be a directive, type name or element
|
||||
* name. Find the end of the name.
|
||||
|
@ -423,10 +424,18 @@ static void tokenise(char *buffer, char *end)
|
|||
tokens[tix].size = q - p;
|
||||
p = q;
|
||||
|
||||
tokens[tix].content = malloc(tokens[tix].size + 1);
|
||||
if (!tokens[tix].content) {
|
||||
perror(NULL);
|
||||
exit(1);
|
||||
}
|
||||
memcpy(tokens[tix].content, start, tokens[tix].size);
|
||||
tokens[tix].content[tokens[tix].size] = 0;
|
||||
|
||||
/* If it begins with a lowercase letter then
|
||||
* it's an element name
|
||||
*/
|
||||
if (islower(tokens[tix].value[0])) {
|
||||
if (islower(tokens[tix].content[0])) {
|
||||
tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
|
||||
continue;
|
||||
}
|
||||
|
@ -455,6 +464,13 @@ static void tokenise(char *buffer, char *end)
|
|||
q++;
|
||||
tokens[tix].size = q - p;
|
||||
p = q;
|
||||
tokens[tix].content = malloc(tokens[tix].size + 1);
|
||||
if (!tokens[tix].content) {
|
||||
perror(NULL);
|
||||
exit(1);
|
||||
}
|
||||
memcpy(tokens[tix].content, start, tokens[tix].size);
|
||||
tokens[tix].content[tokens[tix].size] = 0;
|
||||
tokens[tix++].token_type = TOKEN_NUMBER;
|
||||
continue;
|
||||
}
|
||||
|
@ -463,6 +479,7 @@ static void tokenise(char *buffer, char *end)
|
|||
if (memcmp(p, "::=", 3) == 0) {
|
||||
p += 3;
|
||||
tokens[tix].size = 3;
|
||||
tokens[tix].content = "::=";
|
||||
tokens[tix++].token_type = TOKEN_ASSIGNMENT;
|
||||
continue;
|
||||
}
|
||||
|
@ -472,12 +489,14 @@ static void tokenise(char *buffer, char *end)
|
|||
if (memcmp(p, "({", 2) == 0) {
|
||||
p += 2;
|
||||
tokens[tix].size = 2;
|
||||
tokens[tix].content = "({";
|
||||
tokens[tix++].token_type = TOKEN_OPEN_ACTION;
|
||||
continue;
|
||||
}
|
||||
if (memcmp(p, "})", 2) == 0) {
|
||||
p += 2;
|
||||
tokens[tix].size = 2;
|
||||
tokens[tix].content = "})";
|
||||
tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
|
||||
continue;
|
||||
}
|
||||
|
@ -488,22 +507,27 @@ static void tokenise(char *buffer, char *end)
|
|||
switch (*p) {
|
||||
case '{':
|
||||
p += 1;
|
||||
tokens[tix].content = "{";
|
||||
tokens[tix++].token_type = TOKEN_OPEN_CURLY;
|
||||
continue;
|
||||
case '}':
|
||||
p += 1;
|
||||
tokens[tix].content = "}";
|
||||
tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
|
||||
continue;
|
||||
case '[':
|
||||
p += 1;
|
||||
tokens[tix].content = "[";
|
||||
tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
|
||||
continue;
|
||||
case ']':
|
||||
p += 1;
|
||||
tokens[tix].content = "]";
|
||||
tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
|
||||
continue;
|
||||
case ',':
|
||||
p += 1;
|
||||
tokens[tix].content = ",";
|
||||
tokens[tix++].token_type = TOKEN_COMMA;
|
||||
continue;
|
||||
default:
|
||||
|
@ -518,22 +542,20 @@ static void tokenise(char *buffer, char *end)
|
|||
}
|
||||
|
||||
nr_tokens = tix;
|
||||
debug("Extracted %u tokens\n", nr_tokens);
|
||||
verbose("Extracted %u tokens\n", nr_tokens);
|
||||
|
||||
#if 0
|
||||
{
|
||||
int n;
|
||||
for (n = 0; n < nr_tokens; n++)
|
||||
debug("Token %3u: '%*.*s'\n",
|
||||
n,
|
||||
(int)token_list[n].size, (int)token_list[n].size,
|
||||
token_list[n].value);
|
||||
debug("Token %3u: '%s'\n", n, token_list[n].content);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void build_type_list(void);
|
||||
static void parse(void);
|
||||
static void dump_elements(void);
|
||||
static void render(FILE *out, FILE *hdr);
|
||||
|
||||
/*
|
||||
|
@ -548,16 +570,27 @@ int main(int argc, char **argv)
|
|||
char *kbuild_verbose;
|
||||
int fd;
|
||||
|
||||
kbuild_verbose = getenv("KBUILD_VERBOSE");
|
||||
if (kbuild_verbose)
|
||||
verbose_opt = atoi(kbuild_verbose);
|
||||
|
||||
while (argc > 4) {
|
||||
if (strcmp(argv[1], "-v") == 0)
|
||||
verbose_opt = true;
|
||||
else if (strcmp(argv[1], "-d") == 0)
|
||||
debug_opt = true;
|
||||
else
|
||||
break;
|
||||
memmove(&argv[1], &argv[2], (argc - 2) * sizeof(char *));
|
||||
argc--;
|
||||
}
|
||||
|
||||
if (argc != 4) {
|
||||
fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n",
|
||||
fprintf(stderr, "Format: %s [-v] [-d] <grammar-file> <c-file> <hdr-file>\n",
|
||||
argv[0]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
kbuild_verbose = getenv("KBUILD_VERBOSE");
|
||||
if (kbuild_verbose)
|
||||
verbose = atoi(kbuild_verbose);
|
||||
|
||||
filename = argv[1];
|
||||
outputname = argv[2];
|
||||
headername = argv[3];
|
||||
|
@ -608,6 +641,7 @@ int main(int argc, char **argv)
|
|||
tokenise(buffer, buffer + readlen);
|
||||
build_type_list();
|
||||
parse();
|
||||
dump_elements();
|
||||
|
||||
out = fopen(outputname, "w");
|
||||
if (!out) {
|
||||
|
@ -666,7 +700,7 @@ struct element {
|
|||
unsigned flags;
|
||||
#define ELEMENT_IMPLICIT 0x0001
|
||||
#define ELEMENT_EXPLICIT 0x0002
|
||||
#define ELEMENT_MARKED 0x0004
|
||||
#define ELEMENT_TAG_SPECIFIED 0x0004
|
||||
#define ELEMENT_RENDERED 0x0008
|
||||
#define ELEMENT_SKIPPABLE 0x0010
|
||||
#define ELEMENT_CONDITIONAL 0x0020
|
||||
|
@ -693,7 +727,7 @@ static int type_index_compare(const void *_a, const void *_b)
|
|||
if ((*a)->name->size != (*b)->name->size)
|
||||
return (*a)->name->size - (*b)->name->size;
|
||||
else
|
||||
return memcmp((*a)->name->value, (*b)->name->value,
|
||||
return memcmp((*a)->name->content, (*b)->name->content,
|
||||
(*a)->name->size);
|
||||
}
|
||||
|
||||
|
@ -706,7 +740,7 @@ static int type_finder(const void *_key, const void *_ti)
|
|||
if (token->size != type->name->size)
|
||||
return token->size - type->name->size;
|
||||
else
|
||||
return memcmp(token->value, type->name->value,
|
||||
return memcmp(token->content, type->name->content,
|
||||
token->size);
|
||||
}
|
||||
|
||||
|
@ -756,14 +790,11 @@ static void build_type_list(void)
|
|||
|
||||
qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
|
||||
|
||||
debug("Extracted %u types\n", nr_types);
|
||||
verbose("Extracted %u types\n", nr_types);
|
||||
#if 0
|
||||
for (n = 0; n < nr_types; n++) {
|
||||
struct type *type = type_index[n];
|
||||
debug("- %*.*s\n",
|
||||
(int)type->name->size,
|
||||
(int)type->name->size,
|
||||
type->name->value);
|
||||
debug("- %*.*s\n", type->name->content);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -793,15 +824,14 @@ static void parse(void)
|
|||
type->element->type_def = type;
|
||||
|
||||
if (cursor != type[1].name) {
|
||||
fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n",
|
||||
filename, cursor->line,
|
||||
(int)cursor->size, (int)cursor->size, cursor->value);
|
||||
fprintf(stderr, "%s:%d: Parse error at token '%s'\n",
|
||||
filename, cursor->line, cursor->content);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
} while (type++, !(type->flags & TYPE_STOP_MARKER));
|
||||
|
||||
debug("Extracted %u actions\n", nr_actions);
|
||||
verbose("Extracted %u actions\n", nr_actions);
|
||||
}
|
||||
|
||||
static struct element *element_list;
|
||||
|
@ -862,33 +892,31 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
|
|||
cursor++;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n",
|
||||
filename, cursor->line,
|
||||
(int)cursor->size, (int)cursor->size, cursor->value);
|
||||
fprintf(stderr, "%s:%d: Unrecognised tag class token '%s'\n",
|
||||
filename, cursor->line, cursor->content);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (cursor >= end)
|
||||
goto overrun_error;
|
||||
if (cursor->token_type != TOKEN_NUMBER) {
|
||||
fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n",
|
||||
filename, cursor->line,
|
||||
(int)cursor->size, (int)cursor->size, cursor->value);
|
||||
fprintf(stderr, "%s:%d: Missing tag number '%s'\n",
|
||||
filename, cursor->line, cursor->content);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
element->tag &= ~0x1f;
|
||||
element->tag |= strtoul(cursor->value, &p, 10);
|
||||
if (p - cursor->value != cursor->size)
|
||||
element->tag |= strtoul(cursor->content, &p, 10);
|
||||
element->flags |= ELEMENT_TAG_SPECIFIED;
|
||||
if (p - cursor->content != cursor->size)
|
||||
abort();
|
||||
cursor++;
|
||||
|
||||
if (cursor >= end)
|
||||
goto overrun_error;
|
||||
if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
|
||||
fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n",
|
||||
filename, cursor->line,
|
||||
(int)cursor->size, (int)cursor->size, cursor->value);
|
||||
fprintf(stderr, "%s:%d: Missing closing square bracket '%s'\n",
|
||||
filename, cursor->line, cursor->content);
|
||||
exit(1);
|
||||
}
|
||||
cursor++;
|
||||
|
@ -988,9 +1016,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
|
|||
ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
|
||||
type_finder);
|
||||
if (!ref) {
|
||||
fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n",
|
||||
filename, cursor->line,
|
||||
(int)cursor->size, (int)cursor->size, cursor->value);
|
||||
fprintf(stderr, "%s:%d: Type '%s' undefined\n",
|
||||
filename, cursor->line, cursor->content);
|
||||
exit(1);
|
||||
}
|
||||
cursor->type = *ref;
|
||||
|
@ -1039,9 +1066,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
|
|||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n",
|
||||
filename, cursor->line,
|
||||
(int)cursor->size, (int)cursor->size, cursor->value);
|
||||
fprintf(stderr, "%s:%d: Token '%s' does not introduce a type\n",
|
||||
filename, cursor->line, cursor->content);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -1058,20 +1084,18 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
|
|||
if (cursor >= end)
|
||||
goto overrun_error;
|
||||
if (cursor->token_type != TOKEN_ELEMENT_NAME) {
|
||||
fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n",
|
||||
filename, cursor->line,
|
||||
(int)cursor->size, (int)cursor->size, cursor->value);
|
||||
fprintf(stderr, "%s:%d: Token '%s' is not an action function name\n",
|
||||
filename, cursor->line, cursor->content);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
action = malloc(sizeof(struct action) + cursor->size + 1);
|
||||
action = malloc(sizeof(struct action));
|
||||
if (!action) {
|
||||
perror(NULL);
|
||||
exit(1);
|
||||
}
|
||||
action->index = 0;
|
||||
memcpy(action->name, cursor->value, cursor->size);
|
||||
action->name[cursor->size] = 0;
|
||||
action->name = cursor->content;
|
||||
|
||||
for (ppaction = &action_list;
|
||||
*ppaction;
|
||||
|
@ -1101,9 +1125,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
|
|||
if (cursor >= end)
|
||||
goto overrun_error;
|
||||
if (cursor->token_type != TOKEN_CLOSE_ACTION) {
|
||||
fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n",
|
||||
filename, cursor->line,
|
||||
(int)cursor->size, (int)cursor->size, cursor->value);
|
||||
fprintf(stderr, "%s:%d: Missing close action, got '%s'\n",
|
||||
filename, cursor->line, cursor->content);
|
||||
exit(1);
|
||||
}
|
||||
cursor++;
|
||||
|
@ -1113,9 +1136,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
|
|||
return top;
|
||||
|
||||
parse_error:
|
||||
fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n",
|
||||
filename, cursor->line,
|
||||
(int)cursor->size, (int)cursor->size, cursor->value);
|
||||
fprintf(stderr, "%s:%d: Unexpected token '%s'\n",
|
||||
filename, cursor->line, cursor->content);
|
||||
exit(1);
|
||||
|
||||
overrun_error:
|
||||
|
@ -1133,9 +1155,8 @@ static struct element *parse_compound(struct token **_cursor, struct token *end,
|
|||
struct token *cursor = *_cursor, *name;
|
||||
|
||||
if (cursor->token_type != TOKEN_OPEN_CURLY) {
|
||||
fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n",
|
||||
filename, cursor->line,
|
||||
(int)cursor->size, (int)cursor->size, cursor->value);
|
||||
fprintf(stderr, "%s:%d: Expected compound to start with brace not '%s'\n",
|
||||
filename, cursor->line, cursor->content);
|
||||
exit(1);
|
||||
}
|
||||
cursor++;
|
||||
|
@ -1176,9 +1197,8 @@ static struct element *parse_compound(struct token **_cursor, struct token *end,
|
|||
children->flags &= ~ELEMENT_CONDITIONAL;
|
||||
|
||||
if (cursor->token_type != TOKEN_CLOSE_CURLY) {
|
||||
fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n",
|
||||
filename, cursor->line,
|
||||
(int)cursor->size, (int)cursor->size, cursor->value);
|
||||
fprintf(stderr, "%s:%d: Expected compound closure, got '%s'\n",
|
||||
filename, cursor->line, cursor->content);
|
||||
exit(1);
|
||||
}
|
||||
cursor++;
|
||||
|
@ -1191,6 +1211,52 @@ overrun_error:
|
|||
exit(1);
|
||||
}
|
||||
|
||||
static void dump_element(const struct element *e, int level)
|
||||
{
|
||||
const struct element *c;
|
||||
const struct type *t = e->type_def;
|
||||
const char *name = e->name ? e->name->content : ".";
|
||||
const char *tname = t && t->name ? t->name->content : ".";
|
||||
char tag[32];
|
||||
|
||||
if (e->class == 0 && e->method == 0 && e->tag == 0)
|
||||
strcpy(tag, "<...>");
|
||||
else if (e->class == ASN1_UNIV)
|
||||
sprintf(tag, "%s %s %s",
|
||||
asn1_classes[e->class],
|
||||
asn1_methods[e->method],
|
||||
asn1_universal_tags[e->tag]);
|
||||
else
|
||||
sprintf(tag, "%s %s %u",
|
||||
asn1_classes[e->class],
|
||||
asn1_methods[e->method],
|
||||
e->tag);
|
||||
|
||||
printf("%c%c%c%c%c %c %*s[*] \e[33m%s\e[m %s %s \e[35m%s\e[m\n",
|
||||
e->flags & ELEMENT_IMPLICIT ? 'I' : '-',
|
||||
e->flags & ELEMENT_EXPLICIT ? 'E' : '-',
|
||||
e->flags & ELEMENT_TAG_SPECIFIED ? 'T' : '-',
|
||||
e->flags & ELEMENT_SKIPPABLE ? 'S' : '-',
|
||||
e->flags & ELEMENT_CONDITIONAL ? 'C' : '-',
|
||||
"-tTqQcaro"[e->compound],
|
||||
level, "",
|
||||
tag,
|
||||
tname,
|
||||
name,
|
||||
e->action ? e->action->name : "");
|
||||
if (e->compound == TYPE_REF)
|
||||
dump_element(e->type->type->element, level + 3);
|
||||
else
|
||||
for (c = e->children; c; c = c->next)
|
||||
dump_element(c, level + 3);
|
||||
}
|
||||
|
||||
static void dump_elements(void)
|
||||
{
|
||||
if (debug_opt)
|
||||
dump_element(type_list[0].element, 0);
|
||||
}
|
||||
|
||||
static void render_element(FILE *out, struct element *e, struct element *tag);
|
||||
static void render_out_of_line_list(FILE *out);
|
||||
|
||||
|
@ -1292,7 +1358,7 @@ static void render(FILE *out, FILE *hdr)
|
|||
}
|
||||
|
||||
/* We do two passes - the first one calculates all the offsets */
|
||||
debug("Pass 1\n");
|
||||
verbose("Pass 1\n");
|
||||
nr_entries = 0;
|
||||
root = &type_list[0];
|
||||
render_element(NULL, root->element, NULL);
|
||||
|
@ -1303,7 +1369,7 @@ static void render(FILE *out, FILE *hdr)
|
|||
e->flags &= ~ELEMENT_RENDERED;
|
||||
|
||||
/* And then we actually render */
|
||||
debug("Pass 2\n");
|
||||
verbose("Pass 2\n");
|
||||
fprintf(out, "\n");
|
||||
fprintf(out, "static const unsigned char %s_machine[] = {\n",
|
||||
grammar_name);
|
||||
|
@ -1376,7 +1442,7 @@ static void render_out_of_line_list(FILE *out)
|
|||
*/
|
||||
static void render_element(FILE *out, struct element *e, struct element *tag)
|
||||
{
|
||||
struct element *ec;
|
||||
struct element *ec, *x;
|
||||
const char *cond, *act;
|
||||
int entry, skippable = 0, outofline = 0;
|
||||
|
||||
|
@ -1389,9 +1455,7 @@ static void render_element(FILE *out, struct element *e, struct element *tag)
|
|||
outofline = 1;
|
||||
|
||||
if (e->type_def && out) {
|
||||
render_more(out, "\t// %*.*s\n",
|
||||
(int)e->type_def->name->size, (int)e->type_def->name->size,
|
||||
e->type_def->name->value);
|
||||
render_more(out, "\t// %s\n", e->type_def->name->content);
|
||||
}
|
||||
|
||||
/* Render the operation */
|
||||
|
@ -1400,11 +1464,10 @@ static void render_element(FILE *out, struct element *e, struct element *tag)
|
|||
act = e->action ? "_ACT" : "";
|
||||
switch (e->compound) {
|
||||
case ANY:
|
||||
render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act);
|
||||
render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,",
|
||||
cond, act, skippable ? "_OR_SKIP" : "");
|
||||
if (e->name)
|
||||
render_more(out, "\t\t// %*.*s",
|
||||
(int)e->name->size, (int)e->name->size,
|
||||
e->name->value);
|
||||
render_more(out, "\t\t// %s", e->name->content);
|
||||
render_more(out, "\n");
|
||||
goto dont_render_tag;
|
||||
|
||||
|
@ -1435,15 +1498,15 @@ static void render_element(FILE *out, struct element *e, struct element *tag)
|
|||
break;
|
||||
}
|
||||
|
||||
if (e->name)
|
||||
render_more(out, "\t\t// %*.*s",
|
||||
(int)e->name->size, (int)e->name->size,
|
||||
e->name->value);
|
||||
x = tag ?: e;
|
||||
if (x->name)
|
||||
render_more(out, "\t\t// %s", x->name->content);
|
||||
render_more(out, "\n");
|
||||
|
||||
/* Render the tag */
|
||||
if (!tag)
|
||||
if (!tag || !(tag->flags & ELEMENT_TAG_SPECIFIED))
|
||||
tag = e;
|
||||
|
||||
if (tag->class == ASN1_UNIV &&
|
||||
tag->tag != 14 &&
|
||||
tag->tag != 15 &&
|
||||
|
@ -1465,7 +1528,8 @@ dont_render_tag:
|
|||
case TYPE_REF:
|
||||
render_element(out, e->type->type->element, tag);
|
||||
if (e->action)
|
||||
render_opcode(out, "ASN1_OP_ACT,\n");
|
||||
render_opcode(out, "ASN1_OP_%sACT,\n",
|
||||
skippable ? "MAYBE_" : "");
|
||||
break;
|
||||
|
||||
case SEQUENCE:
|
||||
|
@ -1474,10 +1538,8 @@ dont_render_tag:
|
|||
* skipability */
|
||||
render_opcode(out, "_jump_target(%u),", e->entry_index);
|
||||
if (e->type_def && e->type_def->name)
|
||||
render_more(out, "\t\t// --> %*.*s",
|
||||
(int)e->type_def->name->size,
|
||||
(int)e->type_def->name->size,
|
||||
e->type_def->name->value);
|
||||
render_more(out, "\t\t// --> %s",
|
||||
e->type_def->name->content);
|
||||
render_more(out, "\n");
|
||||
if (!(e->flags & ELEMENT_RENDERED)) {
|
||||
e->flags |= ELEMENT_RENDERED;
|
||||
|
@ -1502,10 +1564,8 @@ dont_render_tag:
|
|||
* skipability */
|
||||
render_opcode(out, "_jump_target(%u),", e->entry_index);
|
||||
if (e->type_def && e->type_def->name)
|
||||
render_more(out, "\t\t// --> %*.*s",
|
||||
(int)e->type_def->name->size,
|
||||
(int)e->type_def->name->size,
|
||||
e->type_def->name->value);
|
||||
render_more(out, "\t\t// --> %s",
|
||||
e->type_def->name->content);
|
||||
render_more(out, "\n");
|
||||
if (!(e->flags & ELEMENT_RENDERED)) {
|
||||
e->flags |= ELEMENT_RENDERED;
|
||||
|
@ -1539,7 +1599,7 @@ dont_render_tag:
|
|||
|
||||
case CHOICE:
|
||||
for (ec = e->children; ec; ec = ec->next)
|
||||
render_element(out, ec, NULL);
|
||||
render_element(out, ec, ec);
|
||||
if (!skippable)
|
||||
render_opcode(out, "ASN1_OP_COND_FAIL,\n");
|
||||
if (e->action)
|
||||
|
|
166
scripts/extract-cert.c
Normal file
166
scripts/extract-cert.c
Normal file
|
@ -0,0 +1,166 @@
|
|||
/* Extract X.509 certificate in DER form from PKCS#11 or PEM.
|
||||
*
|
||||
* Copyright © 2014 Red Hat, Inc. All Rights Reserved.
|
||||
* Copyright © 2015 Intel Corporation.
|
||||
*
|
||||
* Authors: David Howells <dhowells@redhat.com>
|
||||
* David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public Licence
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the Licence, or (at your option) any later version.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <err.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/engine.h>
|
||||
|
||||
#define PKEY_ID_PKCS7 2
|
||||
|
||||
static __attribute__((noreturn))
|
||||
void format(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: scripts/extract-cert <source> <dest>\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
static void display_openssl_errors(int l)
|
||||
{
|
||||
const char *file;
|
||||
char buf[120];
|
||||
int e, line;
|
||||
|
||||
if (ERR_peek_error() == 0)
|
||||
return;
|
||||
fprintf(stderr, "At main.c:%d:\n", l);
|
||||
|
||||
while ((e = ERR_get_error_line(&file, &line))) {
|
||||
ERR_error_string(e, buf);
|
||||
fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line);
|
||||
}
|
||||
}
|
||||
|
||||
static void drain_openssl_errors(void)
|
||||
{
|
||||
const char *file;
|
||||
int line;
|
||||
|
||||
if (ERR_peek_error() == 0)
|
||||
return;
|
||||
while (ERR_get_error_line(&file, &line)) {}
|
||||
}
|
||||
|
||||
#define ERR(cond, fmt, ...) \
|
||||
do { \
|
||||
bool __cond = (cond); \
|
||||
display_openssl_errors(__LINE__); \
|
||||
if (__cond) { \
|
||||
err(1, fmt, ## __VA_ARGS__); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
static const char *key_pass;
|
||||
static BIO *wb;
|
||||
static char *cert_dst;
|
||||
int kbuild_verbose;
|
||||
|
||||
static void write_cert(X509 *x509)
|
||||
{
|
||||
char buf[200];
|
||||
|
||||
if (!wb) {
|
||||
wb = BIO_new_file(cert_dst, "wb");
|
||||
ERR(!wb, "%s", cert_dst);
|
||||
}
|
||||
X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf));
|
||||
ERR(!i2d_X509_bio(wb, x509), cert_dst);
|
||||
if (kbuild_verbose)
|
||||
fprintf(stderr, "Extracted cert: %s\n", buf);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *cert_src;
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
ERR_load_crypto_strings();
|
||||
ERR_clear_error();
|
||||
|
||||
kbuild_verbose = atoi(getenv("KBUILD_VERBOSE")?:"0");
|
||||
|
||||
key_pass = getenv("KBUILD_SIGN_PIN");
|
||||
|
||||
if (argc != 3)
|
||||
format();
|
||||
|
||||
cert_src = argv[1];
|
||||
cert_dst = argv[2];
|
||||
|
||||
if (!cert_src[0]) {
|
||||
/* Invoked with no input; create empty file */
|
||||
FILE *f = fopen(cert_dst, "wb");
|
||||
ERR(!f, "%s", cert_dst);
|
||||
fclose(f);
|
||||
exit(0);
|
||||
} else if (!strncmp(cert_src, "pkcs11:", 7)) {
|
||||
ENGINE *e;
|
||||
struct {
|
||||
const char *cert_id;
|
||||
X509 *cert;
|
||||
} parms;
|
||||
|
||||
parms.cert_id = cert_src;
|
||||
parms.cert = NULL;
|
||||
|
||||
ENGINE_load_builtin_engines();
|
||||
drain_openssl_errors();
|
||||
e = ENGINE_by_id("pkcs11");
|
||||
ERR(!e, "Load PKCS#11 ENGINE");
|
||||
if (ENGINE_init(e))
|
||||
drain_openssl_errors();
|
||||
else
|
||||
ERR(1, "ENGINE_init");
|
||||
if (key_pass)
|
||||
ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN");
|
||||
ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1);
|
||||
ERR(!parms.cert, "Get X.509 from PKCS#11");
|
||||
write_cert(parms.cert);
|
||||
} else {
|
||||
BIO *b;
|
||||
X509 *x509;
|
||||
|
||||
b = BIO_new_file(cert_src, "rb");
|
||||
ERR(!b, "%s", cert_src);
|
||||
|
||||
while (1) {
|
||||
x509 = PEM_read_bio_X509(b, NULL, NULL, NULL);
|
||||
if (wb && !x509) {
|
||||
unsigned long err = ERR_peek_last_error();
|
||||
if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
|
||||
ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
|
||||
ERR_clear_error();
|
||||
break;
|
||||
}
|
||||
}
|
||||
ERR(!x509, "%s", cert_src);
|
||||
write_cert(x509);
|
||||
}
|
||||
}
|
||||
|
||||
BIO_free(wb);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -98,6 +98,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
/* types, roles, and allows */
|
||||
fprintf(fout, "type base_t;\n");
|
||||
fprintf(fout, "role base_r;\n");
|
||||
fprintf(fout, "role base_r types { base_t };\n");
|
||||
for (i = 0; secclass_map[i].name; i++)
|
||||
fprintf(fout, "allow base_t base_t:%s *;\n",
|
||||
|
|
|
@ -1,421 +0,0 @@
|
|||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Sign a module file using the given key.
|
||||
#
|
||||
|
||||
my $USAGE =
|
||||
"Usage: scripts/sign-file [-v] <hash algo> <key> <x509> <module> [<dest>]\n" .
|
||||
" scripts/sign-file [-v] -s <raw sig> <hash algo> <x509> <module> [<dest>]\n";
|
||||
|
||||
use strict;
|
||||
use FileHandle;
|
||||
use IPC::Open2;
|
||||
use Getopt::Std;
|
||||
|
||||
my %opts;
|
||||
getopts('vs:', \%opts) or die $USAGE;
|
||||
my $verbose = $opts{'v'};
|
||||
my $signature_file = $opts{'s'};
|
||||
|
||||
die $USAGE if ($#ARGV > 4);
|
||||
die $USAGE if (!$signature_file && $#ARGV < 3 || $signature_file && $#ARGV < 2);
|
||||
|
||||
my $dgst = shift @ARGV;
|
||||
my $private_key;
|
||||
if (!$signature_file) {
|
||||
$private_key = shift @ARGV;
|
||||
}
|
||||
my $x509 = shift @ARGV;
|
||||
my $module = shift @ARGV;
|
||||
my ($dest, $keep_orig);
|
||||
if (@ARGV) {
|
||||
$dest = $ARGV[0];
|
||||
$keep_orig = 1;
|
||||
} else {
|
||||
$dest = $module . "~";
|
||||
}
|
||||
|
||||
die "Can't read private key\n" if (!$signature_file && !-r $private_key);
|
||||
die "Can't read signature file\n" if ($signature_file && !-r $signature_file);
|
||||
die "Can't read X.509 certificate\n" unless (-r $x509);
|
||||
die "Can't read module\n" unless (-r $module);
|
||||
|
||||
#
|
||||
# Function to read the contents of a file into a variable.
|
||||
#
|
||||
sub read_file($)
|
||||
{
|
||||
my ($file) = @_;
|
||||
my $contents;
|
||||
my $len;
|
||||
|
||||
open(FD, "<$file") || die $file;
|
||||
binmode FD;
|
||||
my @st = stat(FD);
|
||||
die $file if (!@st);
|
||||
$len = read(FD, $contents, $st[7]) || die $file;
|
||||
close(FD) || die $file;
|
||||
die "$file: Wanted length ", $st[7], ", got ", $len, "\n"
|
||||
if ($len != $st[7]);
|
||||
return $contents;
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# First of all, we have to parse the X.509 certificate to find certain details
|
||||
# about it.
|
||||
#
|
||||
# We read the DER-encoded X509 certificate and parse it to extract the Subject
|
||||
# name and Subject Key Identifier. Theis provides the data we need to build
|
||||
# the certificate identifier.
|
||||
#
|
||||
# The signer's name part of the identifier is fabricated from the commonName,
|
||||
# the organizationName or the emailAddress components of the X.509 subject
|
||||
# name.
|
||||
#
|
||||
# The subject key ID is used to select which of that signer's certificates
|
||||
# we're intending to use to sign the module.
|
||||
#
|
||||
###############################################################################
|
||||
my $x509_certificate = read_file($x509);
|
||||
|
||||
my $UNIV = 0 << 6;
|
||||
my $APPL = 1 << 6;
|
||||
my $CONT = 2 << 6;
|
||||
my $PRIV = 3 << 6;
|
||||
|
||||
my $CONS = 0x20;
|
||||
|
||||
my $BOOLEAN = 0x01;
|
||||
my $INTEGER = 0x02;
|
||||
my $BIT_STRING = 0x03;
|
||||
my $OCTET_STRING = 0x04;
|
||||
my $NULL = 0x05;
|
||||
my $OBJ_ID = 0x06;
|
||||
my $UTF8String = 0x0c;
|
||||
my $SEQUENCE = 0x10;
|
||||
my $SET = 0x11;
|
||||
my $UTCTime = 0x17;
|
||||
my $GeneralizedTime = 0x18;
|
||||
|
||||
my %OIDs = (
|
||||
pack("CCC", 85, 4, 3) => "commonName",
|
||||
pack("CCC", 85, 4, 6) => "countryName",
|
||||
pack("CCC", 85, 4, 10) => "organizationName",
|
||||
pack("CCC", 85, 4, 11) => "organizationUnitName",
|
||||
pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption",
|
||||
pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption",
|
||||
pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress",
|
||||
pack("CCC", 85, 29, 35) => "authorityKeyIdentifier",
|
||||
pack("CCC", 85, 29, 14) => "subjectKeyIdentifier",
|
||||
pack("CCC", 85, 29, 19) => "basicConstraints"
|
||||
);
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Extract an ASN.1 element from a string and return information about it.
|
||||
#
|
||||
###############################################################################
|
||||
sub asn1_extract($$@)
|
||||
{
|
||||
my ($cursor, $expected_tag, $optional) = @_;
|
||||
|
||||
return [ -1 ]
|
||||
if ($cursor->[1] == 0 && $optional);
|
||||
|
||||
die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n"
|
||||
if ($cursor->[1] < 2);
|
||||
|
||||
my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2));
|
||||
|
||||
if ($expected_tag != -1 && $tag != $expected_tag) {
|
||||
return [ -1 ]
|
||||
if ($optional);
|
||||
die $x509, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag,
|
||||
" not ", $expected_tag, ")\n";
|
||||
}
|
||||
|
||||
$cursor->[0] += 2;
|
||||
$cursor->[1] -= 2;
|
||||
|
||||
die $x509, ": ", $cursor->[0], ": ASN.1 long tag\n"
|
||||
if (($tag & 0x1f) == 0x1f);
|
||||
die $x509, ": ", $cursor->[0], ": ASN.1 indefinite length\n"
|
||||
if ($len == 0x80);
|
||||
|
||||
if ($len > 0x80) {
|
||||
my $l = $len - 0x80;
|
||||
die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n"
|
||||
if ($cursor->[1] < $l);
|
||||
|
||||
if ($l == 0x1) {
|
||||
$len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1));
|
||||
} elsif ($l == 0x2) {
|
||||
$len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2));
|
||||
} elsif ($l == 0x3) {
|
||||
$len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16;
|
||||
$len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2));
|
||||
} elsif ($l == 0x4) {
|
||||
$len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4));
|
||||
} else {
|
||||
die $x509, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n";
|
||||
}
|
||||
|
||||
$cursor->[0] += $l;
|
||||
$cursor->[1] -= $l;
|
||||
}
|
||||
|
||||
die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n"
|
||||
if ($cursor->[1] < $len);
|
||||
|
||||
my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ];
|
||||
$cursor->[0] += $len;
|
||||
$cursor->[1] -= $len;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Retrieve the data referred to by a cursor
|
||||
#
|
||||
###############################################################################
|
||||
sub asn1_retrieve($)
|
||||
{
|
||||
my ($cursor) = @_;
|
||||
my ($offset, $len, $data) = @$cursor;
|
||||
return substr($$data, $offset, $len);
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Roughly parse the X.509 certificate
|
||||
#
|
||||
###############################################################################
|
||||
my $cursor = [ 0, length($x509_certificate), \$x509_certificate ];
|
||||
|
||||
my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE);
|
||||
my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE);
|
||||
my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1);
|
||||
my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER);
|
||||
my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
|
||||
my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
|
||||
my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
|
||||
my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
|
||||
my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
|
||||
my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1);
|
||||
my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1);
|
||||
my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1);
|
||||
|
||||
my $subject_key_id = ();
|
||||
my $authority_key_id = ();
|
||||
|
||||
#
|
||||
# Parse the extension list
|
||||
#
|
||||
if ($extension_list->[0] != -1) {
|
||||
my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE);
|
||||
|
||||
while ($extensions->[1]->[1] > 0) {
|
||||
my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE);
|
||||
my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID);
|
||||
my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1);
|
||||
my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING);
|
||||
|
||||
my $raw_oid = asn1_retrieve($x_oid->[1]);
|
||||
next if (!exists($OIDs{$raw_oid}));
|
||||
my $x_type = $OIDs{$raw_oid};
|
||||
|
||||
my $raw_value = asn1_retrieve($x_val->[1]);
|
||||
|
||||
if ($x_type eq "subjectKeyIdentifier") {
|
||||
my $vcursor = [ 0, length($raw_value), \$raw_value ];
|
||||
|
||||
$subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Determine what we're going to use as the signer's name. In order of
|
||||
# preference, take one of: commonName, organizationName or emailAddress.
|
||||
#
|
||||
###############################################################################
|
||||
my $org = "";
|
||||
my $cn = "";
|
||||
my $email = "";
|
||||
|
||||
while ($subject->[1]->[1] > 0) {
|
||||
my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET);
|
||||
my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE);
|
||||
my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID);
|
||||
my $n_val = asn1_extract($attr->[1], -1);
|
||||
|
||||
my $raw_oid = asn1_retrieve($n_oid->[1]);
|
||||
next if (!exists($OIDs{$raw_oid}));
|
||||
my $n_type = $OIDs{$raw_oid};
|
||||
|
||||
my $raw_value = asn1_retrieve($n_val->[1]);
|
||||
|
||||
if ($n_type eq "organizationName") {
|
||||
$org = $raw_value;
|
||||
} elsif ($n_type eq "commonName") {
|
||||
$cn = $raw_value;
|
||||
} elsif ($n_type eq "emailAddress") {
|
||||
$email = $raw_value;
|
||||
}
|
||||
}
|
||||
|
||||
my $signers_name = $email;
|
||||
|
||||
if ($org && $cn) {
|
||||
# Don't use the organizationName if the commonName repeats it
|
||||
if (length($org) <= length($cn) &&
|
||||
substr($cn, 0, length($org)) eq $org) {
|
||||
$signers_name = $cn;
|
||||
goto got_id_name;
|
||||
}
|
||||
|
||||
# Or a signifcant chunk of it
|
||||
if (length($org) >= 7 &&
|
||||
length($cn) >= 7 &&
|
||||
substr($cn, 0, 7) eq substr($org, 0, 7)) {
|
||||
$signers_name = $cn;
|
||||
goto got_id_name;
|
||||
}
|
||||
|
||||
$signers_name = $org . ": " . $cn;
|
||||
} elsif ($org) {
|
||||
$signers_name = $org;
|
||||
} elsif ($cn) {
|
||||
$signers_name = $cn;
|
||||
}
|
||||
|
||||
got_id_name:
|
||||
|
||||
die $x509, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n"
|
||||
if (!$subject_key_id);
|
||||
|
||||
my $key_identifier = asn1_retrieve($subject_key_id->[1]);
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Create and attach the module signature
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
#
|
||||
# Signature parameters
|
||||
#
|
||||
my $algo = 1; # Public-key crypto algorithm: RSA
|
||||
my $hash = 0; # Digest algorithm
|
||||
my $id_type = 1; # Identifier type: X.509
|
||||
|
||||
#
|
||||
# Digest the data
|
||||
#
|
||||
my $prologue;
|
||||
if ($dgst eq "sha1") {
|
||||
$prologue = pack("C*",
|
||||
0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
|
||||
0x2B, 0x0E, 0x03, 0x02, 0x1A,
|
||||
0x05, 0x00, 0x04, 0x14);
|
||||
$hash = 2;
|
||||
} elsif ($dgst eq "sha224") {
|
||||
$prologue = pack("C*",
|
||||
0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
|
||||
0x05, 0x00, 0x04, 0x1C);
|
||||
$hash = 7;
|
||||
} elsif ($dgst eq "sha256") {
|
||||
$prologue = pack("C*",
|
||||
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
|
||||
0x05, 0x00, 0x04, 0x20);
|
||||
$hash = 4;
|
||||
} elsif ($dgst eq "sha384") {
|
||||
$prologue = pack("C*",
|
||||
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
|
||||
0x05, 0x00, 0x04, 0x30);
|
||||
$hash = 5;
|
||||
} elsif ($dgst eq "sha512") {
|
||||
$prologue = pack("C*",
|
||||
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
|
||||
0x05, 0x00, 0x04, 0x40);
|
||||
$hash = 6;
|
||||
} else {
|
||||
die "Unknown hash algorithm: $dgst\n";
|
||||
}
|
||||
|
||||
my $signature;
|
||||
if ($signature_file) {
|
||||
$signature = read_file($signature_file);
|
||||
} else {
|
||||
#
|
||||
# Generate the digest and read from openssl's stdout
|
||||
#
|
||||
my $digest;
|
||||
$digest = readpipe("openssl dgst -$dgst -binary $module") || die "openssl dgst";
|
||||
|
||||
#
|
||||
# Generate the binary signature, which will be just the integer that
|
||||
# comprises the signature with no metadata attached.
|
||||
#
|
||||
my $pid;
|
||||
$pid = open2(*read_from, *write_to,
|
||||
"openssl rsautl -sign -inkey $private_key -keyform PEM") ||
|
||||
die "openssl rsautl";
|
||||
binmode write_to;
|
||||
print write_to $prologue . $digest || die "pipe to openssl rsautl";
|
||||
close(write_to) || die "pipe to openssl rsautl";
|
||||
|
||||
binmode read_from;
|
||||
read(read_from, $signature, 4096) || die "pipe from openssl rsautl";
|
||||
close(read_from) || die "pipe from openssl rsautl";
|
||||
waitpid($pid, 0) || die;
|
||||
die "openssl rsautl died: $?" if ($? >> 8);
|
||||
}
|
||||
$signature = pack("n", length($signature)) . $signature,
|
||||
|
||||
#
|
||||
# Build the signed binary
|
||||
#
|
||||
my $unsigned_module = read_file($module);
|
||||
|
||||
my $magic_number = "~Module signature appended~\n";
|
||||
|
||||
my $info = pack("CCCCCxxxN",
|
||||
$algo, $hash, $id_type,
|
||||
length($signers_name),
|
||||
length($key_identifier),
|
||||
length($signature));
|
||||
|
||||
if ($verbose) {
|
||||
print "Size of unsigned module: ", length($unsigned_module), "\n";
|
||||
print "Size of signer's name : ", length($signers_name), "\n";
|
||||
print "Size of key identifier : ", length($key_identifier), "\n";
|
||||
print "Size of signature : ", length($signature), "\n";
|
||||
print "Size of information : ", length($info), "\n";
|
||||
print "Size of magic number : ", length($magic_number), "\n";
|
||||
print "Signer's name : '", $signers_name, "'\n";
|
||||
print "Digest : $dgst\n";
|
||||
}
|
||||
|
||||
open(FD, ">$dest") || die $dest;
|
||||
binmode FD;
|
||||
print FD
|
||||
$unsigned_module,
|
||||
$signers_name,
|
||||
$key_identifier,
|
||||
$signature,
|
||||
$info,
|
||||
$magic_number
|
||||
;
|
||||
close FD || die $dest;
|
||||
|
||||
if (!$keep_orig) {
|
||||
rename($dest, $module) || die $module;
|
||||
}
|
260
scripts/sign-file.c
Executable file
260
scripts/sign-file.c
Executable file
|
@ -0,0 +1,260 @@
|
|||
/* Sign a module file using the given key.
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public Licence
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the Licence, or (at your option) any later version.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <err.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/cms.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/engine.h>
|
||||
|
||||
struct module_signature {
|
||||
uint8_t algo; /* Public-key crypto algorithm [0] */
|
||||
uint8_t hash; /* Digest algorithm [0] */
|
||||
uint8_t id_type; /* Key identifier type [PKEY_ID_PKCS7] */
|
||||
uint8_t signer_len; /* Length of signer's name [0] */
|
||||
uint8_t key_id_len; /* Length of key identifier [0] */
|
||||
uint8_t __pad[3];
|
||||
uint32_t sig_len; /* Length of signature data */
|
||||
};
|
||||
|
||||
#define PKEY_ID_PKCS7 2
|
||||
|
||||
static char magic_number[] = "~Module signature appended~\n";
|
||||
|
||||
static __attribute__((noreturn))
|
||||
void format(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: scripts/sign-file [-dp] <hash algo> <key> <x509> <module> [<dest>]\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
static void display_openssl_errors(int l)
|
||||
{
|
||||
const char *file;
|
||||
char buf[120];
|
||||
int e, line;
|
||||
|
||||
if (ERR_peek_error() == 0)
|
||||
return;
|
||||
fprintf(stderr, "At main.c:%d:\n", l);
|
||||
|
||||
while ((e = ERR_get_error_line(&file, &line))) {
|
||||
ERR_error_string(e, buf);
|
||||
fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line);
|
||||
}
|
||||
}
|
||||
|
||||
static void drain_openssl_errors(void)
|
||||
{
|
||||
const char *file;
|
||||
int line;
|
||||
|
||||
if (ERR_peek_error() == 0)
|
||||
return;
|
||||
while (ERR_get_error_line(&file, &line)) {}
|
||||
}
|
||||
|
||||
#define ERR(cond, fmt, ...) \
|
||||
do { \
|
||||
bool __cond = (cond); \
|
||||
display_openssl_errors(__LINE__); \
|
||||
if (__cond) { \
|
||||
err(1, fmt, ## __VA_ARGS__); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
static const char *key_pass;
|
||||
|
||||
static int pem_pw_cb(char *buf, int len, int w, void *v)
|
||||
{
|
||||
int pwlen;
|
||||
|
||||
if (!key_pass)
|
||||
return -1;
|
||||
|
||||
pwlen = strlen(key_pass);
|
||||
if (pwlen >= len)
|
||||
return -1;
|
||||
|
||||
strcpy(buf, key_pass);
|
||||
|
||||
/* If it's wrong, don't keep trying it. */
|
||||
key_pass = NULL;
|
||||
|
||||
return pwlen;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 };
|
||||
char *hash_algo = NULL;
|
||||
char *private_key_name, *x509_name, *module_name, *dest_name;
|
||||
bool save_cms = false, replace_orig;
|
||||
bool sign_only = false;
|
||||
unsigned char buf[4096];
|
||||
unsigned long module_size, cms_size;
|
||||
unsigned int use_keyid = 0, use_signed_attrs = CMS_NOATTR;
|
||||
const EVP_MD *digest_algo;
|
||||
EVP_PKEY *private_key;
|
||||
CMS_ContentInfo *cms;
|
||||
X509 *x509;
|
||||
BIO *b, *bd = NULL, *bm;
|
||||
int opt, n;
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
ERR_load_crypto_strings();
|
||||
ERR_clear_error();
|
||||
|
||||
key_pass = getenv("KBUILD_SIGN_PIN");
|
||||
|
||||
do {
|
||||
opt = getopt(argc, argv, "dpk");
|
||||
switch (opt) {
|
||||
case 'p': save_cms = true; break;
|
||||
case 'd': sign_only = true; save_cms = true; break;
|
||||
case 'k': use_keyid = CMS_USE_KEYID; break;
|
||||
case -1: break;
|
||||
default: format();
|
||||
}
|
||||
} while (opt != -1);
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (argc < 4 || argc > 5)
|
||||
format();
|
||||
|
||||
hash_algo = argv[0];
|
||||
private_key_name = argv[1];
|
||||
x509_name = argv[2];
|
||||
module_name = argv[3];
|
||||
if (argc == 5) {
|
||||
dest_name = argv[4];
|
||||
replace_orig = false;
|
||||
} else {
|
||||
ERR(asprintf(&dest_name, "%s.~signed~", module_name) < 0,
|
||||
"asprintf");
|
||||
replace_orig = true;
|
||||
}
|
||||
|
||||
/* Read the private key and the X.509 cert the PKCS#7 message
|
||||
* will point to.
|
||||
*/
|
||||
if (!strncmp(private_key_name, "pkcs11:", 7)) {
|
||||
ENGINE *e;
|
||||
|
||||
ENGINE_load_builtin_engines();
|
||||
drain_openssl_errors();
|
||||
e = ENGINE_by_id("pkcs11");
|
||||
ERR(!e, "Load PKCS#11 ENGINE");
|
||||
if (ENGINE_init(e))
|
||||
drain_openssl_errors();
|
||||
else
|
||||
ERR(1, "ENGINE_init");
|
||||
if (key_pass)
|
||||
ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN");
|
||||
private_key = ENGINE_load_private_key(e, private_key_name, NULL,
|
||||
NULL);
|
||||
ERR(!private_key, "%s", private_key_name);
|
||||
} else {
|
||||
b = BIO_new_file(private_key_name, "rb");
|
||||
ERR(!b, "%s", private_key_name);
|
||||
private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, NULL);
|
||||
ERR(!private_key, "%s", private_key_name);
|
||||
BIO_free(b);
|
||||
}
|
||||
|
||||
b = BIO_new_file(x509_name, "rb");
|
||||
ERR(!b, "%s", x509_name);
|
||||
x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */
|
||||
if (!x509) {
|
||||
ERR(BIO_reset(b) != 1, "%s", x509_name);
|
||||
x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); /* PEM encoded X.509 */
|
||||
if (x509)
|
||||
drain_openssl_errors();
|
||||
}
|
||||
BIO_free(b);
|
||||
ERR(!x509, "%s", x509_name);
|
||||
|
||||
/* Open the destination file now so that we can shovel the module data
|
||||
* across as we read it.
|
||||
*/
|
||||
if (!sign_only) {
|
||||
bd = BIO_new_file(dest_name, "wb");
|
||||
ERR(!bd, "%s", dest_name);
|
||||
}
|
||||
|
||||
/* Digest the module data. */
|
||||
OpenSSL_add_all_digests();
|
||||
display_openssl_errors(__LINE__);
|
||||
digest_algo = EVP_get_digestbyname(hash_algo);
|
||||
ERR(!digest_algo, "EVP_get_digestbyname");
|
||||
|
||||
bm = BIO_new_file(module_name, "rb");
|
||||
ERR(!bm, "%s", module_name);
|
||||
|
||||
/* Load the CMS message from the digest buffer. */
|
||||
cms = CMS_sign(NULL, NULL, NULL, NULL,
|
||||
CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | CMS_DETACHED | CMS_STREAM);
|
||||
ERR(!cms, "CMS_sign");
|
||||
|
||||
ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
|
||||
CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP |
|
||||
use_keyid | use_signed_attrs),
|
||||
"CMS_sign_add_signer");
|
||||
ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0,
|
||||
"CMS_final");
|
||||
|
||||
if (save_cms) {
|
||||
char *cms_name;
|
||||
|
||||
ERR(asprintf(&cms_name, "%s.p7s", module_name) < 0, "asprintf");
|
||||
b = BIO_new_file(cms_name, "wb");
|
||||
ERR(!b, "%s", cms_name);
|
||||
ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0, "%s", cms_name);
|
||||
BIO_free(b);
|
||||
}
|
||||
|
||||
if (sign_only)
|
||||
return 0;
|
||||
|
||||
/* Append the marker and the PKCS#7 message to the destination file */
|
||||
ERR(BIO_reset(bm) < 0, "%s", module_name);
|
||||
while ((n = BIO_read(bm, buf, sizeof(buf))),
|
||||
n > 0) {
|
||||
ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name);
|
||||
}
|
||||
ERR(n < 0, "%s", module_name);
|
||||
module_size = BIO_number_written(bd);
|
||||
|
||||
ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name);
|
||||
cms_size = BIO_number_written(bd) - module_size;
|
||||
sig_info.sig_len = htonl(cms_size);
|
||||
ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name);
|
||||
ERR(BIO_write(bd, magic_number, sizeof(magic_number) - 1) < 0, "%s", dest_name);
|
||||
|
||||
ERR(BIO_free(bd) < 0, "%s", dest_name);
|
||||
|
||||
/* Finally, if we're signing in place, replace the original. */
|
||||
if (replace_orig)
|
||||
ERR(rename(dest_name, module_name) < 0, "%s", dest_name);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue