diff options
| author | James Morris <james.l.morris@oracle.com> | 2015-08-13 22:08:39 -0400 |
|---|---|---|
| committer | James Morris <james.l.morris@oracle.com> | 2015-08-13 22:08:39 -0400 |
| commit | e4fc02f24c223ee8d668bf2d39bb8a2dbd61b40e (patch) | |
| tree | 8ad26407ec8b8898f6ff5f396ff628919a56c624 /scripts | |
| parent | aa62efff65ba572814511efa68cb158fe9e960c4 (diff) | |
| parent | e9a5e8cc55286941503f36c5b7485a5aa923b3f1 (diff) | |
Merge tag 'modsign-pkcs7-20150812-3' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs into next
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/Makefile | 4 | ||||
| -rw-r--r-- | scripts/Makefile.modinst | 2 | ||||
| -rw-r--r-- | scripts/asn1_compiler.c | 229 | ||||
| -rw-r--r-- | scripts/extract-cert.c | 166 | ||||
| -rwxr-xr-x | scripts/sign-file | 421 | ||||
| -rwxr-xr-x | scripts/sign-file.c | 260 |
6 files changed, 573 insertions, 509 deletions
diff --git a/scripts/Makefile b/scripts/Makefile index 2016a64497ab..1b2661712d44 100644 --- a/scripts/Makefile +++ b/scripts/Makefile | |||
| @@ -16,9 +16,13 @@ hostprogs-$(CONFIG_VT) += conmakehash | |||
| 16 | hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount | 16 | hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount |
| 17 | hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable | 17 | hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable |
| 18 | hostprogs-$(CONFIG_ASN1) += asn1_compiler | 18 | hostprogs-$(CONFIG_ASN1) += asn1_compiler |
| 19 | hostprogs-$(CONFIG_MODULE_SIG) += sign-file | ||
| 20 | hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert | ||
| 19 | 21 | ||
| 20 | HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include | 22 | HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include |
| 21 | HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include | 23 | HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include |
| 24 | HOSTLOADLIBES_sign-file = -lcrypto | ||
| 25 | HOSTLOADLIBES_extract-cert = -lcrypto | ||
| 22 | 26 | ||
| 23 | always := $(hostprogs-y) $(hostprogs-m) | 27 | always := $(hostprogs-y) $(hostprogs-m) |
| 24 | 28 | ||
diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index e48a4e9d8868..07650eeaaf06 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst | |||
| @@ -22,7 +22,7 @@ quiet_cmd_modules_install = INSTALL $@ | |||
| 22 | mkdir -p $(2) ; \ | 22 | mkdir -p $(2) ; \ |
| 23 | cp $@ $(2) ; \ | 23 | cp $@ $(2) ; \ |
| 24 | $(mod_strip_cmd) $(2)/$(notdir $@) ; \ | 24 | $(mod_strip_cmd) $(2)/$(notdir $@) ; \ |
| 25 | $(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) ; \ | 25 | $(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) && \ |
| 26 | $(mod_compress_cmd) $(2)/$(notdir $@) | 26 | $(mod_compress_cmd) $(2)/$(notdir $@) |
| 27 | 27 | ||
| 28 | # Modules built outside the kernel source tree go into extra by default | 28 | # Modules built outside the kernel source tree go into extra by default |
diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c index 1c75e22b6385..e000f44e37b8 100644 --- a/scripts/asn1_compiler.c +++ b/scripts/asn1_compiler.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <stdio.h> | 13 | #include <stdio.h> |
| 14 | #include <stdlib.h> | 14 | #include <stdlib.h> |
| 15 | #include <stdint.h> | 15 | #include <stdint.h> |
| 16 | #include <stdbool.h> | ||
| 16 | #include <string.h> | 17 | #include <string.h> |
| 17 | #include <ctype.h> | 18 | #include <ctype.h> |
| 18 | #include <unistd.h> | 19 | #include <unistd.h> |
| @@ -293,8 +294,8 @@ static const char *const directives[NR__DIRECTIVES] = { | |||
| 293 | 294 | ||
| 294 | struct action { | 295 | struct action { |
| 295 | struct action *next; | 296 | struct action *next; |
| 297 | char *name; | ||
| 296 | unsigned char index; | 298 | unsigned char index; |
| 297 | char name[]; | ||
| 298 | }; | 299 | }; |
| 299 | 300 | ||
| 300 | static struct action *action_list; | 301 | static struct action *action_list; |
| @@ -305,15 +306,17 @@ struct token { | |||
| 305 | enum token_type token_type : 8; | 306 | enum token_type token_type : 8; |
| 306 | unsigned char size; | 307 | unsigned char size; |
| 307 | struct action *action; | 308 | struct action *action; |
| 308 | const char *value; | 309 | char *content; |
| 309 | struct type *type; | 310 | struct type *type; |
| 310 | }; | 311 | }; |
| 311 | 312 | ||
| 312 | static struct token *token_list; | 313 | static struct token *token_list; |
| 313 | static unsigned nr_tokens; | 314 | static unsigned nr_tokens; |
| 314 | static _Bool verbose; | 315 | static bool verbose_opt; |
| 316 | static bool debug_opt; | ||
| 315 | 317 | ||
| 316 | #define debug(fmt, ...) do { if (verbose) printf(fmt, ## __VA_ARGS__); } while (0) | 318 | #define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0) |
| 319 | #define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0) | ||
| 317 | 320 | ||
| 318 | static int directive_compare(const void *_key, const void *_pdir) | 321 | static int directive_compare(const void *_key, const void *_pdir) |
| 319 | { | 322 | { |
| @@ -325,11 +328,9 @@ static int directive_compare(const void *_key, const void *_pdir) | |||
| 325 | dlen = strlen(dir); | 328 | dlen = strlen(dir); |
| 326 | clen = (dlen < token->size) ? dlen : token->size; | 329 | clen = (dlen < token->size) ? dlen : token->size; |
| 327 | 330 | ||
| 328 | //debug("cmp(%*.*s,%s) = ", | 331 | //debug("cmp(%s,%s) = ", token->content, dir); |
| 329 | // (int)token->size, (int)token->size, token->value, | ||
| 330 | // dir); | ||
| 331 | 332 | ||
| 332 | val = memcmp(token->value, dir, clen); | 333 | val = memcmp(token->content, dir, clen); |
| 333 | if (val != 0) { | 334 | if (val != 0) { |
| 334 | //debug("%d [cmp]\n", val); | 335 | //debug("%d [cmp]\n", val); |
| 335 | return val; | 336 | return val; |
| @@ -349,7 +350,7 @@ static int directive_compare(const void *_key, const void *_pdir) | |||
| 349 | static void tokenise(char *buffer, char *end) | 350 | static void tokenise(char *buffer, char *end) |
| 350 | { | 351 | { |
| 351 | struct token *tokens; | 352 | struct token *tokens; |
| 352 | char *line, *nl, *p, *q; | 353 | char *line, *nl, *start, *p, *q; |
| 353 | unsigned tix, lineno; | 354 | unsigned tix, lineno; |
| 354 | 355 | ||
| 355 | /* Assume we're going to have half as many tokens as we have | 356 | /* Assume we're going to have half as many tokens as we have |
| @@ -408,11 +409,11 @@ static void tokenise(char *buffer, char *end) | |||
| 408 | break; | 409 | break; |
| 409 | 410 | ||
| 410 | tokens[tix].line = lineno; | 411 | tokens[tix].line = lineno; |
| 411 | tokens[tix].value = p; | 412 | start = p; |
| 412 | 413 | ||
| 413 | /* Handle string tokens */ | 414 | /* Handle string tokens */ |
| 414 | if (isalpha(*p)) { | 415 | if (isalpha(*p)) { |
| 415 | const char **dir; | 416 | const char **dir, *start = p; |
| 416 | 417 | ||
| 417 | /* Can be a directive, type name or element | 418 | /* Can be a directive, type name or element |
| 418 | * name. Find the end of the name. | 419 | * name. Find the end of the name. |
| @@ -423,10 +424,18 @@ static void tokenise(char *buffer, char *end) | |||
| 423 | tokens[tix].size = q - p; | 424 | tokens[tix].size = q - p; |
| 424 | p = q; | 425 | p = q; |
| 425 | 426 | ||
| 427 | tokens[tix].content = malloc(tokens[tix].size + 1); | ||
| 428 | if (!tokens[tix].content) { | ||
| 429 | perror(NULL); | ||
| 430 | exit(1); | ||
| 431 | } | ||
| 432 | memcpy(tokens[tix].content, start, tokens[tix].size); | ||
| 433 | tokens[tix].content[tokens[tix].size] = 0; | ||
| 434 | |||
| 426 | /* If it begins with a lowercase letter then | 435 | /* If it begins with a lowercase letter then |
| 427 | * it's an element name | 436 | * it's an element name |
| 428 | */ | 437 | */ |
| 429 | if (islower(tokens[tix].value[0])) { | 438 | if (islower(tokens[tix].content[0])) { |
| 430 | tokens[tix++].token_type = TOKEN_ELEMENT_NAME; | 439 | tokens[tix++].token_type = TOKEN_ELEMENT_NAME; |
| 431 | continue; | 440 | continue; |
| 432 | } | 441 | } |
| @@ -455,6 +464,13 @@ static void tokenise(char *buffer, char *end) | |||
| 455 | q++; | 464 | q++; |
| 456 | tokens[tix].size = q - p; | 465 | tokens[tix].size = q - p; |
| 457 | p = q; | 466 | p = q; |
| 467 | tokens[tix].content = malloc(tokens[tix].size + 1); | ||
| 468 | if (!tokens[tix].content) { | ||
| 469 | perror(NULL); | ||
| 470 | exit(1); | ||
| 471 | } | ||
| 472 | memcpy(tokens[tix].content, start, tokens[tix].size); | ||
| 473 | tokens[tix].content[tokens[tix].size] = 0; | ||
| 458 | tokens[tix++].token_type = TOKEN_NUMBER; | 474 | tokens[tix++].token_type = TOKEN_NUMBER; |
| 459 | continue; | 475 | continue; |
| 460 | } | 476 | } |
| @@ -463,6 +479,7 @@ static void tokenise(char *buffer, char *end) | |||
| 463 | if (memcmp(p, "::=", 3) == 0) { | 479 | if (memcmp(p, "::=", 3) == 0) { |
| 464 | p += 3; | 480 | p += 3; |
| 465 | tokens[tix].size = 3; | 481 | tokens[tix].size = 3; |
| 482 | tokens[tix].content = "::="; | ||
| 466 | tokens[tix++].token_type = TOKEN_ASSIGNMENT; | 483 | tokens[tix++].token_type = TOKEN_ASSIGNMENT; |
| 467 | continue; | 484 | continue; |
| 468 | } | 485 | } |
| @@ -472,12 +489,14 @@ static void tokenise(char *buffer, char *end) | |||
| 472 | if (memcmp(p, "({", 2) == 0) { | 489 | if (memcmp(p, "({", 2) == 0) { |
| 473 | p += 2; | 490 | p += 2; |
| 474 | tokens[tix].size = 2; | 491 | tokens[tix].size = 2; |
| 492 | tokens[tix].content = "({"; | ||
| 475 | tokens[tix++].token_type = TOKEN_OPEN_ACTION; | 493 | tokens[tix++].token_type = TOKEN_OPEN_ACTION; |
| 476 | continue; | 494 | continue; |
| 477 | } | 495 | } |
| 478 | if (memcmp(p, "})", 2) == 0) { | 496 | if (memcmp(p, "})", 2) == 0) { |
| 479 | p += 2; | 497 | p += 2; |
| 480 | tokens[tix].size = 2; | 498 | tokens[tix].size = 2; |
| 499 | tokens[tix].content = "})"; | ||
| 481 | tokens[tix++].token_type = TOKEN_CLOSE_ACTION; | 500 | tokens[tix++].token_type = TOKEN_CLOSE_ACTION; |
| 482 | continue; | 501 | continue; |
| 483 | } | 502 | } |
| @@ -488,22 +507,27 @@ static void tokenise(char *buffer, char *end) | |||
| 488 | switch (*p) { | 507 | switch (*p) { |
| 489 | case '{': | 508 | case '{': |
| 490 | p += 1; | 509 | p += 1; |
| 510 | tokens[tix].content = "{"; | ||
| 491 | tokens[tix++].token_type = TOKEN_OPEN_CURLY; | 511 | tokens[tix++].token_type = TOKEN_OPEN_CURLY; |
| 492 | continue; | 512 | continue; |
| 493 | case '}': | 513 | case '}': |
| 494 | p += 1; | 514 | p += 1; |
| 515 | tokens[tix].content = "}"; | ||
| 495 | tokens[tix++].token_type = TOKEN_CLOSE_CURLY; | 516 | tokens[tix++].token_type = TOKEN_CLOSE_CURLY; |
| 496 | continue; | 517 | continue; |
| 497 | case '[': | 518 | case '[': |
| 498 | p += 1; | 519 | p += 1; |
| 520 | tokens[tix].content = "["; | ||
| 499 | tokens[tix++].token_type = TOKEN_OPEN_SQUARE; | 521 | tokens[tix++].token_type = TOKEN_OPEN_SQUARE; |
| 500 | continue; | 522 | continue; |
| 501 | case ']': | 523 | case ']': |
| 502 | p += 1; | 524 | p += 1; |
| 525 | tokens[tix].content = "]"; | ||
| 503 | tokens[tix++].token_type = TOKEN_CLOSE_SQUARE; | 526 | tokens[tix++].token_type = TOKEN_CLOSE_SQUARE; |
| 504 | continue; | 527 | continue; |
| 505 | case ',': | 528 | case ',': |
| 506 | p += 1; | 529 | p += 1; |
| 530 | tokens[tix].content = ","; | ||
| 507 | tokens[tix++].token_type = TOKEN_COMMA; | 531 | tokens[tix++].token_type = TOKEN_COMMA; |
| 508 | continue; | 532 | continue; |
| 509 | default: | 533 | default: |
| @@ -518,22 +542,20 @@ static void tokenise(char *buffer, char *end) | |||
| 518 | } | 542 | } |
| 519 | 543 | ||
| 520 | nr_tokens = tix; | 544 | nr_tokens = tix; |
| 521 | debug("Extracted %u tokens\n", nr_tokens); | 545 | verbose("Extracted %u tokens\n", nr_tokens); |
| 522 | 546 | ||
| 523 | #if 0 | 547 | #if 0 |
| 524 | { | 548 | { |
| 525 | int n; | 549 | int n; |
| 526 | for (n = 0; n < nr_tokens; n++) | 550 | for (n = 0; n < nr_tokens; n++) |
| 527 | debug("Token %3u: '%*.*s'\n", | 551 | debug("Token %3u: '%s'\n", n, token_list[n].content); |
| 528 | n, | ||
| 529 | (int)token_list[n].size, (int)token_list[n].size, | ||
| 530 | token_list[n].value); | ||
| 531 | } | 552 | } |
| 532 | #endif | 553 | #endif |
| 533 | } | 554 | } |
| 534 | 555 | ||
| 535 | static void build_type_list(void); | 556 | static void build_type_list(void); |
| 536 | static void parse(void); | 557 | static void parse(void); |
| 558 | static void dump_elements(void); | ||
| 537 | static void render(FILE *out, FILE *hdr); | 559 | static void render(FILE *out, FILE *hdr); |
| 538 | 560 | ||
| 539 | /* | 561 | /* |
| @@ -548,16 +570,27 @@ int main(int argc, char **argv) | |||
| 548 | char *kbuild_verbose; | 570 | char *kbuild_verbose; |
| 549 | int fd; | 571 | int fd; |
| 550 | 572 | ||
| 573 | kbuild_verbose = getenv("KBUILD_VERBOSE"); | ||
| 574 | if (kbuild_verbose) | ||
| 575 | verbose_opt = atoi(kbuild_verbose); | ||
| 576 | |||
| 577 | while (argc > 4) { | ||
| 578 | if (strcmp(argv[1], "-v") == 0) | ||
| 579 | verbose_opt = true; | ||
| 580 | else if (strcmp(argv[1], "-d") == 0) | ||
| 581 | debug_opt = true; | ||
| 582 | else | ||
| 583 | break; | ||
| 584 | memmove(&argv[1], &argv[2], (argc - 2) * sizeof(char *)); | ||
| 585 | argc--; | ||
| 586 | } | ||
| 587 | |||
| 551 | if (argc != 4) { | 588 | if (argc != 4) { |
| 552 | fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n", | 589 | fprintf(stderr, "Format: %s [-v] [-d] <grammar-file> <c-file> <hdr-file>\n", |
| 553 | argv[0]); | 590 | argv[0]); |
| 554 | exit(2); | 591 | exit(2); |
| 555 | } | 592 | } |
| 556 | 593 | ||
| 557 | kbuild_verbose = getenv("KBUILD_VERBOSE"); | ||
| 558 | if (kbuild_verbose) | ||
| 559 | verbose = atoi(kbuild_verbose); | ||
| 560 | |||
| 561 | filename = argv[1]; | 594 | filename = argv[1]; |
| 562 | outputname = argv[2]; | 595 | outputname = argv[2]; |
| 563 | headername = argv[3]; | 596 | headername = argv[3]; |
| @@ -608,6 +641,7 @@ int main(int argc, char **argv) | |||
| 608 | tokenise(buffer, buffer + readlen); | 641 | tokenise(buffer, buffer + readlen); |
| 609 | build_type_list(); | 642 | build_type_list(); |
| 610 | parse(); | 643 | parse(); |
| 644 | dump_elements(); | ||
| 611 | 645 | ||
| 612 | out = fopen(outputname, "w"); | 646 | out = fopen(outputname, "w"); |
| 613 | if (!out) { | 647 | if (!out) { |
| @@ -693,7 +727,7 @@ static int type_index_compare(const void *_a, const void *_b) | |||
| 693 | if ((*a)->name->size != (*b)->name->size) | 727 | if ((*a)->name->size != (*b)->name->size) |
| 694 | return (*a)->name->size - (*b)->name->size; | 728 | return (*a)->name->size - (*b)->name->size; |
| 695 | else | 729 | else |
| 696 | return memcmp((*a)->name->value, (*b)->name->value, | 730 | return memcmp((*a)->name->content, (*b)->name->content, |
| 697 | (*a)->name->size); | 731 | (*a)->name->size); |
| 698 | } | 732 | } |
| 699 | 733 | ||
| @@ -706,7 +740,7 @@ static int type_finder(const void *_key, const void *_ti) | |||
| 706 | if (token->size != type->name->size) | 740 | if (token->size != type->name->size) |
| 707 | return token->size - type->name->size; | 741 | return token->size - type->name->size; |
| 708 | else | 742 | else |
| 709 | return memcmp(token->value, type->name->value, | 743 | return memcmp(token->content, type->name->content, |
| 710 | token->size); | 744 | token->size); |
| 711 | } | 745 | } |
| 712 | 746 | ||
| @@ -756,14 +790,11 @@ static void build_type_list(void) | |||
| 756 | 790 | ||
| 757 | qsort(type_index, nr, sizeof(type_index[0]), type_index_compare); | 791 | qsort(type_index, nr, sizeof(type_index[0]), type_index_compare); |
| 758 | 792 | ||
| 759 | debug("Extracted %u types\n", nr_types); | 793 | verbose("Extracted %u types\n", nr_types); |
| 760 | #if 0 | 794 | #if 0 |
| 761 | for (n = 0; n < nr_types; n++) { | 795 | for (n = 0; n < nr_types; n++) { |
| 762 | struct type *type = type_index[n]; | 796 | struct type *type = type_index[n]; |
| 763 | debug("- %*.*s\n", | 797 | debug("- %*.*s\n", type->name->content); |
| 764 | (int)type->name->size, | ||
| 765 | (int)type->name->size, | ||
| 766 | type->name->value); | ||
| 767 | } | 798 | } |
| 768 | #endif | 799 | #endif |
| 769 | } | 800 | } |
| @@ -793,15 +824,14 @@ static void parse(void) | |||
| 793 | type->element->type_def = type; | 824 | type->element->type_def = type; |
| 794 | 825 | ||
| 795 | if (cursor != type[1].name) { | 826 | if (cursor != type[1].name) { |
| 796 | fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n", | 827 | fprintf(stderr, "%s:%d: Parse error at token '%s'\n", |
| 797 | filename, cursor->line, | 828 | filename, cursor->line, cursor->content); |
| 798 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 799 | exit(1); | 829 | exit(1); |
| 800 | } | 830 | } |
| 801 | 831 | ||
| 802 | } while (type++, !(type->flags & TYPE_STOP_MARKER)); | 832 | } while (type++, !(type->flags & TYPE_STOP_MARKER)); |
| 803 | 833 | ||
| 804 | debug("Extracted %u actions\n", nr_actions); | 834 | verbose("Extracted %u actions\n", nr_actions); |
| 805 | } | 835 | } |
| 806 | 836 | ||
| 807 | static struct element *element_list; | 837 | static struct element *element_list; |
| @@ -862,34 +892,31 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
| 862 | cursor++; | 892 | cursor++; |
| 863 | break; | 893 | break; |
| 864 | default: | 894 | default: |
| 865 | fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n", | 895 | fprintf(stderr, "%s:%d: Unrecognised tag class token '%s'\n", |
| 866 | filename, cursor->line, | 896 | filename, cursor->line, cursor->content); |
| 867 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 868 | exit(1); | 897 | exit(1); |
| 869 | } | 898 | } |
| 870 | 899 | ||
| 871 | if (cursor >= end) | 900 | if (cursor >= end) |
| 872 | goto overrun_error; | 901 | goto overrun_error; |
| 873 | if (cursor->token_type != TOKEN_NUMBER) { | 902 | if (cursor->token_type != TOKEN_NUMBER) { |
| 874 | fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n", | 903 | fprintf(stderr, "%s:%d: Missing tag number '%s'\n", |
| 875 | filename, cursor->line, | 904 | filename, cursor->line, cursor->content); |
| 876 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 877 | exit(1); | 905 | exit(1); |
| 878 | } | 906 | } |
| 879 | 907 | ||
| 880 | element->tag &= ~0x1f; | 908 | element->tag &= ~0x1f; |
| 881 | element->tag |= strtoul(cursor->value, &p, 10); | 909 | element->tag |= strtoul(cursor->content, &p, 10); |
| 882 | element->flags |= ELEMENT_TAG_SPECIFIED; | 910 | element->flags |= ELEMENT_TAG_SPECIFIED; |
| 883 | if (p - cursor->value != cursor->size) | 911 | if (p - cursor->content != cursor->size) |
| 884 | abort(); | 912 | abort(); |
| 885 | cursor++; | 913 | cursor++; |
| 886 | 914 | ||
| 887 | if (cursor >= end) | 915 | if (cursor >= end) |
| 888 | goto overrun_error; | 916 | goto overrun_error; |
| 889 | if (cursor->token_type != TOKEN_CLOSE_SQUARE) { | 917 | if (cursor->token_type != TOKEN_CLOSE_SQUARE) { |
| 890 | fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n", | 918 | fprintf(stderr, "%s:%d: Missing closing square bracket '%s'\n", |
| 891 | filename, cursor->line, | 919 | filename, cursor->line, cursor->content); |
| 892 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 893 | exit(1); | 920 | exit(1); |
| 894 | } | 921 | } |
| 895 | cursor++; | 922 | cursor++; |
| @@ -989,9 +1016,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
| 989 | ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]), | 1016 | ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]), |
| 990 | type_finder); | 1017 | type_finder); |
| 991 | if (!ref) { | 1018 | if (!ref) { |
| 992 | fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n", | 1019 | fprintf(stderr, "%s:%d: Type '%s' undefined\n", |
| 993 | filename, cursor->line, | 1020 | filename, cursor->line, cursor->content); |
| 994 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 995 | exit(1); | 1021 | exit(1); |
| 996 | } | 1022 | } |
| 997 | cursor->type = *ref; | 1023 | cursor->type = *ref; |
| @@ -1040,9 +1066,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
| 1040 | break; | 1066 | break; |
| 1041 | 1067 | ||
| 1042 | default: | 1068 | default: |
| 1043 | fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n", | 1069 | fprintf(stderr, "%s:%d: Token '%s' does not introduce a type\n", |
| 1044 | filename, cursor->line, | 1070 | filename, cursor->line, cursor->content); |
| 1045 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1046 | exit(1); | 1071 | exit(1); |
| 1047 | } | 1072 | } |
| 1048 | 1073 | ||
| @@ -1059,20 +1084,18 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
| 1059 | if (cursor >= end) | 1084 | if (cursor >= end) |
| 1060 | goto overrun_error; | 1085 | goto overrun_error; |
| 1061 | if (cursor->token_type != TOKEN_ELEMENT_NAME) { | 1086 | if (cursor->token_type != TOKEN_ELEMENT_NAME) { |
| 1062 | fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n", | 1087 | fprintf(stderr, "%s:%d: Token '%s' is not an action function name\n", |
| 1063 | filename, cursor->line, | 1088 | filename, cursor->line, cursor->content); |
| 1064 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1065 | exit(1); | 1089 | exit(1); |
| 1066 | } | 1090 | } |
| 1067 | 1091 | ||
| 1068 | action = malloc(sizeof(struct action) + cursor->size + 1); | 1092 | action = malloc(sizeof(struct action)); |
| 1069 | if (!action) { | 1093 | if (!action) { |
| 1070 | perror(NULL); | 1094 | perror(NULL); |
| 1071 | exit(1); | 1095 | exit(1); |
| 1072 | } | 1096 | } |
| 1073 | action->index = 0; | 1097 | action->index = 0; |
| 1074 | memcpy(action->name, cursor->value, cursor->size); | 1098 | action->name = cursor->content; |
| 1075 | action->name[cursor->size] = 0; | ||
| 1076 | 1099 | ||
| 1077 | for (ppaction = &action_list; | 1100 | for (ppaction = &action_list; |
| 1078 | *ppaction; | 1101 | *ppaction; |
| @@ -1102,9 +1125,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
| 1102 | if (cursor >= end) | 1125 | if (cursor >= end) |
| 1103 | goto overrun_error; | 1126 | goto overrun_error; |
| 1104 | if (cursor->token_type != TOKEN_CLOSE_ACTION) { | 1127 | if (cursor->token_type != TOKEN_CLOSE_ACTION) { |
| 1105 | fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n", | 1128 | fprintf(stderr, "%s:%d: Missing close action, got '%s'\n", |
| 1106 | filename, cursor->line, | 1129 | filename, cursor->line, cursor->content); |
| 1107 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1108 | exit(1); | 1130 | exit(1); |
| 1109 | } | 1131 | } |
| 1110 | cursor++; | 1132 | cursor++; |
| @@ -1114,9 +1136,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
| 1114 | return top; | 1136 | return top; |
| 1115 | 1137 | ||
| 1116 | parse_error: | 1138 | parse_error: |
| 1117 | fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n", | 1139 | fprintf(stderr, "%s:%d: Unexpected token '%s'\n", |
| 1118 | filename, cursor->line, | 1140 | filename, cursor->line, cursor->content); |
| 1119 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1120 | exit(1); | 1141 | exit(1); |
| 1121 | 1142 | ||
| 1122 | overrun_error: | 1143 | overrun_error: |
| @@ -1134,9 +1155,8 @@ static struct element *parse_compound(struct token **_cursor, struct token *end, | |||
| 1134 | struct token *cursor = *_cursor, *name; | 1155 | struct token *cursor = *_cursor, *name; |
| 1135 | 1156 | ||
| 1136 | if (cursor->token_type != TOKEN_OPEN_CURLY) { | 1157 | if (cursor->token_type != TOKEN_OPEN_CURLY) { |
| 1137 | fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n", | 1158 | fprintf(stderr, "%s:%d: Expected compound to start with brace not '%s'\n", |
| 1138 | filename, cursor->line, | 1159 | filename, cursor->line, cursor->content); |
| 1139 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1140 | exit(1); | 1160 | exit(1); |
| 1141 | } | 1161 | } |
| 1142 | cursor++; | 1162 | cursor++; |
| @@ -1177,9 +1197,8 @@ static struct element *parse_compound(struct token **_cursor, struct token *end, | |||
| 1177 | children->flags &= ~ELEMENT_CONDITIONAL; | 1197 | children->flags &= ~ELEMENT_CONDITIONAL; |
| 1178 | 1198 | ||
| 1179 | if (cursor->token_type != TOKEN_CLOSE_CURLY) { | 1199 | if (cursor->token_type != TOKEN_CLOSE_CURLY) { |
| 1180 | fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n", | 1200 | fprintf(stderr, "%s:%d: Expected compound closure, got '%s'\n", |
| 1181 | filename, cursor->line, | 1201 | filename, cursor->line, cursor->content); |
| 1182 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1183 | exit(1); | 1202 | exit(1); |
| 1184 | } | 1203 | } |
| 1185 | cursor++; | 1204 | cursor++; |
| @@ -1192,6 +1211,52 @@ overrun_error: | |||
| 1192 | exit(1); | 1211 | exit(1); |
| 1193 | } | 1212 | } |
| 1194 | 1213 | ||
| 1214 | static void dump_element(const struct element *e, int level) | ||
| 1215 | { | ||
| 1216 | const struct element *c; | ||
| 1217 | const struct type *t = e->type_def; | ||
| 1218 | const char *name = e->name ? e->name->content : "."; | ||
| 1219 | const char *tname = t && t->name ? t->name->content : "."; | ||
| 1220 | char tag[32]; | ||
| 1221 | |||
| 1222 | if (e->class == 0 && e->method == 0 && e->tag == 0) | ||
| 1223 | strcpy(tag, "<...>"); | ||
| 1224 | else if (e->class == ASN1_UNIV) | ||
| 1225 | sprintf(tag, "%s %s %s", | ||
| 1226 | asn1_classes[e->class], | ||
| 1227 | asn1_methods[e->method], | ||
| 1228 | asn1_universal_tags[e->tag]); | ||
| 1229 | else | ||
| 1230 | sprintf(tag, "%s %s %u", | ||
| 1231 | asn1_classes[e->class], | ||
| 1232 | asn1_methods[e->method], | ||
| 1233 | e->tag); | ||
| 1234 | |||
| 1235 | printf("%c%c%c%c%c %c %*s[*] \e[33m%s\e[m %s %s \e[35m%s\e[m\n", | ||
| 1236 | e->flags & ELEMENT_IMPLICIT ? 'I' : '-', | ||
| 1237 | e->flags & ELEMENT_EXPLICIT ? 'E' : '-', | ||
| 1238 | e->flags & ELEMENT_TAG_SPECIFIED ? 'T' : '-', | ||
| 1239 | e->flags & ELEMENT_SKIPPABLE ? 'S' : '-', | ||
| 1240 | e->flags & ELEMENT_CONDITIONAL ? 'C' : '-', | ||
| 1241 | "-tTqQcaro"[e->compound], | ||
| 1242 | level, "", | ||
| 1243 | tag, | ||
| 1244 | tname, | ||
| 1245 | name, | ||
| 1246 | e->action ? e->action->name : ""); | ||
| 1247 | if (e->compound == TYPE_REF) | ||
| 1248 | dump_element(e->type->type->element, level + 3); | ||
| 1249 | else | ||
| 1250 | for (c = e->children; c; c = c->next) | ||
| 1251 | dump_element(c, level + 3); | ||
| 1252 | } | ||
| 1253 | |||
| 1254 | static void dump_elements(void) | ||
| 1255 | { | ||
| 1256 | if (debug_opt) | ||
| 1257 | dump_element(type_list[0].element, 0); | ||
| 1258 | } | ||
| 1259 | |||
| 1195 | static void render_element(FILE *out, struct element *e, struct element *tag); | 1260 | static void render_element(FILE *out, struct element *e, struct element *tag); |
| 1196 | static void render_out_of_line_list(FILE *out); | 1261 | static void render_out_of_line_list(FILE *out); |
| 1197 | 1262 | ||
| @@ -1293,7 +1358,7 @@ static void render(FILE *out, FILE *hdr) | |||
| 1293 | } | 1358 | } |
| 1294 | 1359 | ||
| 1295 | /* We do two passes - the first one calculates all the offsets */ | 1360 | /* We do two passes - the first one calculates all the offsets */ |
| 1296 | debug("Pass 1\n"); | 1361 | verbose("Pass 1\n"); |
| 1297 | nr_entries = 0; | 1362 | nr_entries = 0; |
| 1298 | root = &type_list[0]; | 1363 | root = &type_list[0]; |
| 1299 | render_element(NULL, root->element, NULL); | 1364 | render_element(NULL, root->element, NULL); |
| @@ -1304,7 +1369,7 @@ static void render(FILE *out, FILE *hdr) | |||
| 1304 | e->flags &= ~ELEMENT_RENDERED; | 1369 | e->flags &= ~ELEMENT_RENDERED; |
| 1305 | 1370 | ||
| 1306 | /* And then we actually render */ | 1371 | /* And then we actually render */ |
| 1307 | debug("Pass 2\n"); | 1372 | verbose("Pass 2\n"); |
| 1308 | fprintf(out, "\n"); | 1373 | fprintf(out, "\n"); |
| 1309 | fprintf(out, "static const unsigned char %s_machine[] = {\n", | 1374 | fprintf(out, "static const unsigned char %s_machine[] = {\n", |
| 1310 | grammar_name); | 1375 | grammar_name); |
| @@ -1390,9 +1455,7 @@ static void render_element(FILE *out, struct element *e, struct element *tag) | |||
| 1390 | outofline = 1; | 1455 | outofline = 1; |
| 1391 | 1456 | ||
| 1392 | if (e->type_def && out) { | 1457 | if (e->type_def && out) { |
| 1393 | render_more(out, "\t// %*.*s\n", | 1458 | render_more(out, "\t// %s\n", e->type_def->name->content); |
| 1394 | (int)e->type_def->name->size, (int)e->type_def->name->size, | ||
| 1395 | e->type_def->name->value); | ||
| 1396 | } | 1459 | } |
| 1397 | 1460 | ||
| 1398 | /* Render the operation */ | 1461 | /* Render the operation */ |
| @@ -1404,9 +1467,7 @@ static void render_element(FILE *out, struct element *e, struct element *tag) | |||
| 1404 | render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,", | 1467 | render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,", |
| 1405 | cond, act, skippable ? "_OR_SKIP" : ""); | 1468 | cond, act, skippable ? "_OR_SKIP" : ""); |
| 1406 | if (e->name) | 1469 | if (e->name) |
| 1407 | render_more(out, "\t\t// %*.*s", | 1470 | render_more(out, "\t\t// %s", e->name->content); |
| 1408 | (int)e->name->size, (int)e->name->size, | ||
| 1409 | e->name->value); | ||
| 1410 | render_more(out, "\n"); | 1471 | render_more(out, "\n"); |
| 1411 | goto dont_render_tag; | 1472 | goto dont_render_tag; |
| 1412 | 1473 | ||
| @@ -1439,9 +1500,7 @@ static void render_element(FILE *out, struct element *e, struct element *tag) | |||
| 1439 | 1500 | ||
| 1440 | x = tag ?: e; | 1501 | x = tag ?: e; |
| 1441 | if (x->name) | 1502 | if (x->name) |
| 1442 | render_more(out, "\t\t// %*.*s", | 1503 | render_more(out, "\t\t// %s", x->name->content); |
| 1443 | (int)x->name->size, (int)x->name->size, | ||
| 1444 | x->name->value); | ||
| 1445 | render_more(out, "\n"); | 1504 | render_more(out, "\n"); |
| 1446 | 1505 | ||
| 1447 | /* Render the tag */ | 1506 | /* Render the tag */ |
| @@ -1479,10 +1538,8 @@ dont_render_tag: | |||
| 1479 | * skipability */ | 1538 | * skipability */ |
| 1480 | render_opcode(out, "_jump_target(%u),", e->entry_index); | 1539 | render_opcode(out, "_jump_target(%u),", e->entry_index); |
| 1481 | if (e->type_def && e->type_def->name) | 1540 | if (e->type_def && e->type_def->name) |
| 1482 | render_more(out, "\t\t// --> %*.*s", | 1541 | render_more(out, "\t\t// --> %s", |
| 1483 | (int)e->type_def->name->size, | 1542 | e->type_def->name->content); |
| 1484 | (int)e->type_def->name->size, | ||
| 1485 | e->type_def->name->value); | ||
| 1486 | render_more(out, "\n"); | 1543 | render_more(out, "\n"); |
| 1487 | if (!(e->flags & ELEMENT_RENDERED)) { | 1544 | if (!(e->flags & ELEMENT_RENDERED)) { |
| 1488 | e->flags |= ELEMENT_RENDERED; | 1545 | e->flags |= ELEMENT_RENDERED; |
| @@ -1507,10 +1564,8 @@ dont_render_tag: | |||
| 1507 | * skipability */ | 1564 | * skipability */ |
| 1508 | render_opcode(out, "_jump_target(%u),", e->entry_index); | 1565 | render_opcode(out, "_jump_target(%u),", e->entry_index); |
| 1509 | if (e->type_def && e->type_def->name) | 1566 | if (e->type_def && e->type_def->name) |
| 1510 | render_more(out, "\t\t// --> %*.*s", | 1567 | render_more(out, "\t\t// --> %s", |
| 1511 | (int)e->type_def->name->size, | 1568 | e->type_def->name->content); |
| 1512 | (int)e->type_def->name->size, | ||
| 1513 | e->type_def->name->value); | ||
| 1514 | render_more(out, "\n"); | 1569 | render_more(out, "\n"); |
| 1515 | if (!(e->flags & ELEMENT_RENDERED)) { | 1570 | if (!(e->flags & ELEMENT_RENDERED)) { |
| 1516 | e->flags |= ELEMENT_RENDERED; | 1571 | e->flags |= ELEMENT_RENDERED; |
diff --git a/scripts/extract-cert.c b/scripts/extract-cert.c new file mode 100644 index 000000000000..fd0db015c65c --- /dev/null +++ b/scripts/extract-cert.c | |||
| @@ -0,0 +1,166 @@ | |||
| 1 | /* Extract X.509 certificate in DER form from PKCS#11 or PEM. | ||
| 2 | * | ||
| 3 | * Copyright © 2014 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Copyright © 2015 Intel Corporation. | ||
| 5 | * | ||
| 6 | * Authors: David Howells <dhowells@redhat.com> | ||
| 7 | * David Woodhouse <dwmw2@infradead.org> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public Licence | ||
| 11 | * as published by the Free Software Foundation; either version | ||
| 12 | * 2 of the Licence, or (at your option) any later version. | ||
| 13 | */ | ||
| 14 | #define _GNU_SOURCE | ||
| 15 | #include <stdio.h> | ||
| 16 | #include <stdlib.h> | ||
| 17 | #include <stdint.h> | ||
| 18 | #include <stdbool.h> | ||
| 19 | #include <string.h> | ||
| 20 | #include <getopt.h> | ||
| 21 | #include <err.h> | ||
| 22 | #include <arpa/inet.h> | ||
| 23 | #include <openssl/bio.h> | ||
| 24 | #include <openssl/evp.h> | ||
| 25 | #include <openssl/pem.h> | ||
| 26 | #include <openssl/pkcs7.h> | ||
| 27 | #include <openssl/err.h> | ||
| 28 | #include <openssl/engine.h> | ||
| 29 | |||
| 30 | #define PKEY_ID_PKCS7 2 | ||
| 31 | |||
| 32 | static __attribute__((noreturn)) | ||
| 33 | void format(void) | ||
| 34 | { | ||
| 35 | fprintf(stderr, | ||
| 36 | "Usage: scripts/extract-cert <source> <dest>\n"); | ||
| 37 | exit(2); | ||
| 38 | } | ||
| 39 | |||
| 40 | static void display_openssl_errors(int l) | ||
| 41 | { | ||
| 42 | const char *file; | ||
| 43 | char buf[120]; | ||
| 44 | int e, line; | ||
| 45 | |||
| 46 | if (ERR_peek_error() == 0) | ||
| 47 | return; | ||
| 48 | fprintf(stderr, "At main.c:%d:\n", l); | ||
| 49 | |||
| 50 | while ((e = ERR_get_error_line(&file, &line))) { | ||
| 51 | ERR_error_string(e, buf); | ||
| 52 | fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | static void drain_openssl_errors(void) | ||
| 57 | { | ||
| 58 | const char *file; | ||
| 59 | int line; | ||
| 60 | |||
| 61 | if (ERR_peek_error() == 0) | ||
| 62 | return; | ||
| 63 | while (ERR_get_error_line(&file, &line)) {} | ||
| 64 | } | ||
| 65 | |||
| 66 | #define ERR(cond, fmt, ...) \ | ||
| 67 | do { \ | ||
| 68 | bool __cond = (cond); \ | ||
| 69 | display_openssl_errors(__LINE__); \ | ||
| 70 | if (__cond) { \ | ||
| 71 | err(1, fmt, ## __VA_ARGS__); \ | ||
| 72 | } \ | ||
| 73 | } while(0) | ||
| 74 | |||
| 75 | static const char *key_pass; | ||
| 76 | static BIO *wb; | ||
| 77 | static char *cert_dst; | ||
| 78 | int kbuild_verbose; | ||
| 79 | |||
| 80 | static void write_cert(X509 *x509) | ||
| 81 | { | ||
| 82 | char buf[200]; | ||
| 83 | |||
| 84 | if (!wb) { | ||
| 85 | wb = BIO_new_file(cert_dst, "wb"); | ||
| 86 | ERR(!wb, "%s", cert_dst); | ||
| 87 | } | ||
| 88 | X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf)); | ||
| 89 | ERR(!i2d_X509_bio(wb, x509), cert_dst); | ||
| 90 | if (kbuild_verbose) | ||
| 91 | fprintf(stderr, "Extracted cert: %s\n", buf); | ||
| 92 | } | ||
| 93 | |||
| 94 | int main(int argc, char **argv) | ||
| 95 | { | ||
| 96 | char *cert_src; | ||
| 97 | |||
| 98 | OpenSSL_add_all_algorithms(); | ||
| 99 | ERR_load_crypto_strings(); | ||
| 100 | ERR_clear_error(); | ||
| 101 | |||
| 102 | kbuild_verbose = atoi(getenv("KBUILD_VERBOSE")?:"0"); | ||
| 103 | |||
| 104 | key_pass = getenv("KBUILD_SIGN_PIN"); | ||
| 105 | |||
| 106 | if (argc != 3) | ||
| 107 | format(); | ||
| 108 | |||
| 109 | cert_src = argv[1]; | ||
| 110 | cert_dst = argv[2]; | ||
| 111 | |||
| 112 | if (!cert_src[0]) { | ||
| 113 | /* Invoked with no input; create empty file */ | ||
| 114 | FILE *f = fopen(cert_dst, "wb"); | ||
| 115 | ERR(!f, "%s", cert_dst); | ||
| 116 | fclose(f); | ||
| 117 | exit(0); | ||
| 118 | } else if (!strncmp(cert_src, "pkcs11:", 7)) { | ||
| 119 | ENGINE *e; | ||
| 120 | struct { | ||
| 121 | const char *cert_id; | ||
| 122 | X509 *cert; | ||
| 123 | } parms; | ||
| 124 | |||
| 125 | parms.cert_id = cert_src; | ||
| 126 | parms.cert = NULL; | ||
| 127 | |||
| 128 | ENGINE_load_builtin_engines(); | ||
| 129 | drain_openssl_errors(); | ||
| 130 | e = ENGINE_by_id("pkcs11"); | ||
| 131 | ERR(!e, "Load PKCS#11 ENGINE"); | ||
| 132 | if (ENGINE_init(e)) | ||
| 133 | drain_openssl_errors(); | ||
| 134 | else | ||
| 135 | ERR(1, "ENGINE_init"); | ||
| 136 | if (key_pass) | ||
| 137 | ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); | ||
| 138 | ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1); | ||
| 139 | ERR(!parms.cert, "Get X.509 from PKCS#11"); | ||
| 140 | write_cert(parms.cert); | ||
| 141 | } else { | ||
| 142 | BIO *b; | ||
| 143 | X509 *x509; | ||
| 144 | |||
| 145 | b = BIO_new_file(cert_src, "rb"); | ||
| 146 | ERR(!b, "%s", cert_src); | ||
| 147 | |||
| 148 | while (1) { | ||
| 149 | x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); | ||
| 150 | if (wb && !x509) { | ||
| 151 | unsigned long err = ERR_peek_last_error(); | ||
| 152 | if (ERR_GET_LIB(err) == ERR_LIB_PEM && | ||
| 153 | ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { | ||
| 154 | ERR_clear_error(); | ||
| 155 | break; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | ERR(!x509, "%s", cert_src); | ||
| 159 | write_cert(x509); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | BIO_free(wb); | ||
| 164 | |||
| 165 | return 0; | ||
| 166 | } | ||
diff --git a/scripts/sign-file b/scripts/sign-file deleted file mode 100755 index 3906ee1e2f76..000000000000 --- a/scripts/sign-file +++ /dev/null | |||
| @@ -1,421 +0,0 @@ | |||
| 1 | #!/usr/bin/perl -w | ||
| 2 | # | ||
| 3 | # Sign a module file using the given key. | ||
| 4 | # | ||
| 5 | |||
| 6 | my $USAGE = | ||
| 7 | "Usage: scripts/sign-file [-v] <hash algo> <key> <x509> <module> [<dest>]\n" . | ||
| 8 | " scripts/sign-file [-v] -s <raw sig> <hash algo> <x509> <module> [<dest>]\n"; | ||
| 9 | |||
| 10 | use strict; | ||
| 11 | use FileHandle; | ||
| 12 | use IPC::Open2; | ||
| 13 | use Getopt::Std; | ||
| 14 | |||
| 15 | my %opts; | ||
| 16 | getopts('vs:', \%opts) or die $USAGE; | ||
| 17 | my $verbose = $opts{'v'}; | ||
| 18 | my $signature_file = $opts{'s'}; | ||
| 19 | |||
| 20 | die $USAGE if ($#ARGV > 4); | ||
| 21 | die $USAGE if (!$signature_file && $#ARGV < 3 || $signature_file && $#ARGV < 2); | ||
| 22 | |||
| 23 | my $dgst = shift @ARGV; | ||
| 24 | my $private_key; | ||
| 25 | if (!$signature_file) { | ||
| 26 | $private_key = shift @ARGV; | ||
| 27 | } | ||
| 28 | my $x509 = shift @ARGV; | ||
| 29 | my $module = shift @ARGV; | ||
| 30 | my ($dest, $keep_orig); | ||
| 31 | if (@ARGV) { | ||
| 32 | $dest = $ARGV[0]; | ||
| 33 | $keep_orig = 1; | ||
| 34 | } else { | ||
| 35 | $dest = $module . "~"; | ||
| 36 | } | ||
| 37 | |||
| 38 | die "Can't read private key\n" if (!$signature_file && !-r $private_key); | ||
| 39 | die "Can't read signature file\n" if ($signature_file && !-r $signature_file); | ||
| 40 | die "Can't read X.509 certificate\n" unless (-r $x509); | ||
| 41 | die "Can't read module\n" unless (-r $module); | ||
| 42 | |||
| 43 | # | ||
| 44 | # Function to read the contents of a file into a variable. | ||
| 45 | # | ||
| 46 | sub read_file($) | ||
| 47 | { | ||
| 48 | my ($file) = @_; | ||
| 49 | my $contents; | ||
| 50 | my $len; | ||
| 51 | |||
| 52 | open(FD, "<$file") || die $file; | ||
| 53 | binmode FD; | ||
| 54 | my @st = stat(FD); | ||
| 55 | die $file if (!@st); | ||
| 56 | $len = read(FD, $contents, $st[7]) || die $file; | ||
| 57 | close(FD) || die $file; | ||
| 58 | die "$file: Wanted length ", $st[7], ", got ", $len, "\n" | ||
| 59 | if ($len != $st[7]); | ||
| 60 | return $contents; | ||
| 61 | } | ||
| 62 | |||
| 63 | ############################################################################### | ||
| 64 | # | ||
| 65 | # First of all, we have to parse the X.509 certificate to find certain details | ||
| 66 | # about it. | ||
| 67 | # | ||
| 68 | # We read the DER-encoded X509 certificate and parse it to extract the Subject | ||
| 69 | # name and Subject Key Identifier. Theis provides the data we need to build | ||
| 70 | # the certificate identifier. | ||
| 71 | # | ||
| 72 | # The signer's name part of the identifier is fabricated from the commonName, | ||
| 73 | # the organizationName or the emailAddress components of the X.509 subject | ||
| 74 | # name. | ||
| 75 | # | ||
| 76 | # The subject key ID is used to select which of that signer's certificates | ||
| 77 | # we're intending to use to sign the module. | ||
| 78 | # | ||
| 79 | ############################################################################### | ||
| 80 | my $x509_certificate = read_file($x509); | ||
| 81 | |||
| 82 | my $UNIV = 0 << 6; | ||
| 83 | my $APPL = 1 << 6; | ||
| 84 | my $CONT = 2 << 6; | ||
| 85 | my $PRIV = 3 << 6; | ||
| 86 | |||
| 87 | my $CONS = 0x20; | ||
| 88 | |||
| 89 | my $BOOLEAN = 0x01; | ||
| 90 | my $INTEGER = 0x02; | ||
| 91 | my $BIT_STRING = 0x03; | ||
| 92 | my $OCTET_STRING = 0x04; | ||
| 93 | my $NULL = 0x05; | ||
| 94 | my $OBJ_ID = 0x06; | ||
| 95 | my $UTF8String = 0x0c; | ||
| 96 | my $SEQUENCE = 0x10; | ||
| 97 | my $SET = 0x11; | ||
| 98 | my $UTCTime = 0x17; | ||
| 99 | my $GeneralizedTime = 0x18; | ||
| 100 | |||
| 101 | my %OIDs = ( | ||
| 102 | pack("CCC", 85, 4, 3) => "commonName", | ||
| 103 | pack("CCC", 85, 4, 6) => "countryName", | ||
| 104 | pack("CCC", 85, 4, 10) => "organizationName", | ||
| 105 | pack("CCC", 85, 4, 11) => "organizationUnitName", | ||
| 106 | pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption", | ||
| 107 | pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption", | ||
| 108 | pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress", | ||
| 109 | pack("CCC", 85, 29, 35) => "authorityKeyIdentifier", | ||
| 110 | pack("CCC", 85, 29, 14) => "subjectKeyIdentifier", | ||
| 111 | pack("CCC", 85, 29, 19) => "basicConstraints" | ||
| 112 | ); | ||
| 113 | |||
| 114 | ############################################################################### | ||
| 115 | # | ||
| 116 | # Extract an ASN.1 element from a string and return information about it. | ||
| 117 | # | ||
| 118 | ############################################################################### | ||
| 119 | sub asn1_extract($$@) | ||
| 120 | { | ||
| 121 | my ($cursor, $expected_tag, $optional) = @_; | ||
| 122 | |||
| 123 | return [ -1 ] | ||
| 124 | if ($cursor->[1] == 0 && $optional); | ||
| 125 | |||
| 126 | die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n" | ||
| 127 | if ($cursor->[1] < 2); | ||
| 128 | |||
| 129 | my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2)); | ||
| 130 | |||
| 131 | if ($expected_tag != -1 && $tag != $expected_tag) { | ||
| 132 | return [ -1 ] | ||
| 133 | if ($optional); | ||
| 134 | die $x509, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag, | ||
| 135 | " not ", $expected_tag, ")\n"; | ||
| 136 | } | ||
| 137 | |||
| 138 | $cursor->[0] += 2; | ||
| 139 | $cursor->[1] -= 2; | ||
| 140 | |||
| 141 | die $x509, ": ", $cursor->[0], ": ASN.1 long tag\n" | ||
| 142 | if (($tag & 0x1f) == 0x1f); | ||
| 143 | die $x509, ": ", $cursor->[0], ": ASN.1 indefinite length\n" | ||
| 144 | if ($len == 0x80); | ||
| 145 | |||
| 146 | if ($len > 0x80) { | ||
| 147 | my $l = $len - 0x80; | ||
| 148 | die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n" | ||
| 149 | if ($cursor->[1] < $l); | ||
| 150 | |||
| 151 | if ($l == 0x1) { | ||
| 152 | $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)); | ||
| 153 | } elsif ($l == 0x2) { | ||
| 154 | $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2)); | ||
| 155 | } elsif ($l == 0x3) { | ||
| 156 | $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16; | ||
| 157 | $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2)); | ||
| 158 | } elsif ($l == 0x4) { | ||
| 159 | $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4)); | ||
| 160 | } else { | ||
| 161 | die $x509, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n"; | ||
| 162 | } | ||
| 163 | |||
| 164 | $cursor->[0] += $l; | ||
| 165 | $cursor->[1] -= $l; | ||
| 166 | } | ||
| 167 | |||
| 168 | die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n" | ||
| 169 | if ($cursor->[1] < $len); | ||
| 170 | |||
| 171 | my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ]; | ||
| 172 | $cursor->[0] += $len; | ||
| 173 | $cursor->[1] -= $len; | ||
| 174 | |||
| 175 | return $ret; | ||
| 176 | } | ||
| 177 | |||
| 178 | ############################################################################### | ||
| 179 | # | ||
| 180 | # Retrieve the data referred to by a cursor | ||
| 181 | # | ||
| 182 | ############################################################################### | ||
| 183 | sub asn1_retrieve($) | ||
| 184 | { | ||
| 185 | my ($cursor) = @_; | ||
| 186 | my ($offset, $len, $data) = @$cursor; | ||
| 187 | return substr($$data, $offset, $len); | ||
| 188 | } | ||
| 189 | |||
| 190 | ############################################################################### | ||
| 191 | # | ||
| 192 | # Roughly parse the X.509 certificate | ||
| 193 | # | ||
| 194 | ############################################################################### | ||
| 195 | my $cursor = [ 0, length($x509_certificate), \$x509_certificate ]; | ||
| 196 | |||
| 197 | my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE); | ||
| 198 | my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 199 | my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1); | ||
| 200 | my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER); | ||
| 201 | my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 202 | my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 203 | my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 204 | my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 205 | my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 206 | my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1); | ||
| 207 | my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1); | ||
| 208 | my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1); | ||
| 209 | |||
| 210 | my $subject_key_id = (); | ||
| 211 | my $authority_key_id = (); | ||
| 212 | |||
| 213 | # | ||
| 214 | # Parse the extension list | ||
| 215 | # | ||
| 216 | if ($extension_list->[0] != -1) { | ||
| 217 | my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 218 | |||
| 219 | while ($extensions->[1]->[1] > 0) { | ||
| 220 | my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 221 | my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID); | ||
| 222 | my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1); | ||
| 223 | my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING); | ||
| 224 | |||
| 225 | my $raw_oid = asn1_retrieve($x_oid->[1]); | ||
| 226 | next if (!exists($OIDs{$raw_oid})); | ||
| 227 | my $x_type = $OIDs{$raw_oid}; | ||
| 228 | |||
| 229 | my $raw_value = asn1_retrieve($x_val->[1]); | ||
| 230 | |||
| 231 | if ($x_type eq "subjectKeyIdentifier") { | ||
| 232 | my $vcursor = [ 0, length($raw_value), \$raw_value ]; | ||
| 233 | |||
| 234 | $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING); | ||
| 235 | } | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 | ############################################################################### | ||
| 240 | # | ||
| 241 | # Determine what we're going to use as the signer's name. In order of | ||
| 242 | # preference, take one of: commonName, organizationName or emailAddress. | ||
| 243 | # | ||
| 244 | ############################################################################### | ||
| 245 | my $org = ""; | ||
| 246 | my $cn = ""; | ||
| 247 | my $email = ""; | ||
| 248 | |||
| 249 | while ($subject->[1]->[1] > 0) { | ||
| 250 | my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET); | ||
| 251 | my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 252 | my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID); | ||
| 253 | my $n_val = asn1_extract($attr->[1], -1); | ||
| 254 | |||
| 255 | my $raw_oid = asn1_retrieve($n_oid->[1]); | ||
| 256 | next if (!exists($OIDs{$raw_oid})); | ||
| 257 | my $n_type = $OIDs{$raw_oid}; | ||
| 258 | |||
| 259 | my $raw_value = asn1_retrieve($n_val->[1]); | ||
| 260 | |||
| 261 | if ($n_type eq "organizationName") { | ||
| 262 | $org = $raw_value; | ||
| 263 | } elsif ($n_type eq "commonName") { | ||
| 264 | $cn = $raw_value; | ||
| 265 | } elsif ($n_type eq "emailAddress") { | ||
| 266 | $email = $raw_value; | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | my $signers_name = $email; | ||
| 271 | |||
| 272 | if ($org && $cn) { | ||
| 273 | # Don't use the organizationName if the commonName repeats it | ||
| 274 | if (length($org) <= length($cn) && | ||
| 275 | substr($cn, 0, length($org)) eq $org) { | ||
| 276 | $signers_name = $cn; | ||
| 277 | goto got_id_name; | ||
| 278 | } | ||
| 279 | |||
| 280 | # Or a signifcant chunk of it | ||
| 281 | if (length($org) >= 7 && | ||
| 282 | length($cn) >= 7 && | ||
| 283 | substr($cn, 0, 7) eq substr($org, 0, 7)) { | ||
| 284 | $signers_name = $cn; | ||
| 285 | goto got_id_name; | ||
| 286 | } | ||
| 287 | |||
| 288 | $signers_name = $org . ": " . $cn; | ||
| 289 | } elsif ($org) { | ||
| 290 | $signers_name = $org; | ||
| 291 | } elsif ($cn) { | ||
| 292 | $signers_name = $cn; | ||
| 293 | } | ||
| 294 | |||
| 295 | got_id_name: | ||
| 296 | |||
| 297 | die $x509, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n" | ||
| 298 | if (!$subject_key_id); | ||
| 299 | |||
| 300 | my $key_identifier = asn1_retrieve($subject_key_id->[1]); | ||
| 301 | |||
| 302 | ############################################################################### | ||
| 303 | # | ||
| 304 | # Create and attach the module signature | ||
| 305 | # | ||
| 306 | ############################################################################### | ||
| 307 | |||
| 308 | # | ||
| 309 | # Signature parameters | ||
| 310 | # | ||
| 311 | my $algo = 1; # Public-key crypto algorithm: RSA | ||
| 312 | my $hash = 0; # Digest algorithm | ||
| 313 | my $id_type = 1; # Identifier type: X.509 | ||
| 314 | |||
| 315 | # | ||
| 316 | # Digest the data | ||
| 317 | # | ||
| 318 | my $prologue; | ||
| 319 | if ($dgst eq "sha1") { | ||
| 320 | $prologue = pack("C*", | ||
| 321 | 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, | ||
| 322 | 0x2B, 0x0E, 0x03, 0x02, 0x1A, | ||
| 323 | 0x05, 0x00, 0x04, 0x14); | ||
| 324 | $hash = 2; | ||
| 325 | } elsif ($dgst eq "sha224") { | ||
| 326 | $prologue = pack("C*", | ||
| 327 | 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, | ||
| 328 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, | ||
| 329 | 0x05, 0x00, 0x04, 0x1C); | ||
| 330 | $hash = 7; | ||
| 331 | } elsif ($dgst eq "sha256") { | ||
| 332 | $prologue = pack("C*", | ||
| 333 | 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, | ||
| 334 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, | ||
| 335 | 0x05, 0x00, 0x04, 0x20); | ||
| 336 | $hash = 4; | ||
| 337 | } elsif ($dgst eq "sha384") { | ||
| 338 | $prologue = pack("C*", | ||
| 339 | 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, | ||
| 340 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, | ||
| 341 | 0x05, 0x00, 0x04, 0x30); | ||
| 342 | $hash = 5; | ||
| 343 | } elsif ($dgst eq "sha512") { | ||
| 344 | $prologue = pack("C*", | ||
| 345 | 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, | ||
| 346 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, | ||
| 347 | 0x05, 0x00, 0x04, 0x40); | ||
| 348 | $hash = 6; | ||
| 349 | } else { | ||
| 350 | die "Unknown hash algorithm: $dgst\n"; | ||
| 351 | } | ||
| 352 | |||
| 353 | my $signature; | ||
| 354 | if ($signature_file) { | ||
| 355 | $signature = read_file($signature_file); | ||
| 356 | } else { | ||
| 357 | # | ||
| 358 | # Generate the digest and read from openssl's stdout | ||
| 359 | # | ||
| 360 | my $digest; | ||
| 361 | $digest = readpipe("openssl dgst -$dgst -binary $module") || die "openssl dgst"; | ||
| 362 | |||
| 363 | # | ||
| 364 | # Generate the binary signature, which will be just the integer that | ||
| 365 | # comprises the signature with no metadata attached. | ||
| 366 | # | ||
| 367 | my $pid; | ||
| 368 | $pid = open2(*read_from, *write_to, | ||
| 369 | "openssl rsautl -sign -inkey $private_key -keyform PEM") || | ||
| 370 | die "openssl rsautl"; | ||
| 371 | binmode write_to; | ||
| 372 | print write_to $prologue . $digest || die "pipe to openssl rsautl"; | ||
| 373 | close(write_to) || die "pipe to openssl rsautl"; | ||
| 374 | |||
| 375 | binmode read_from; | ||
| 376 | read(read_from, $signature, 4096) || die "pipe from openssl rsautl"; | ||
| 377 | close(read_from) || die "pipe from openssl rsautl"; | ||
| 378 | waitpid($pid, 0) || die; | ||
| 379 | die "openssl rsautl died: $?" if ($? >> 8); | ||
| 380 | } | ||
| 381 | $signature = pack("n", length($signature)) . $signature, | ||
| 382 | |||
| 383 | # | ||
| 384 | # Build the signed binary | ||
| 385 | # | ||
| 386 | my $unsigned_module = read_file($module); | ||
| 387 | |||
| 388 | my $magic_number = "~Module signature appended~\n"; | ||
| 389 | |||
| 390 | my $info = pack("CCCCCxxxN", | ||
| 391 | $algo, $hash, $id_type, | ||
| 392 | length($signers_name), | ||
| 393 | length($key_identifier), | ||
| 394 | length($signature)); | ||
| 395 | |||
| 396 | if ($verbose) { | ||
| 397 | print "Size of unsigned module: ", length($unsigned_module), "\n"; | ||
| 398 | print "Size of signer's name : ", length($signers_name), "\n"; | ||
| 399 | print "Size of key identifier : ", length($key_identifier), "\n"; | ||
| 400 | print "Size of signature : ", length($signature), "\n"; | ||
| 401 | print "Size of information : ", length($info), "\n"; | ||
| 402 | print "Size of magic number : ", length($magic_number), "\n"; | ||
| 403 | print "Signer's name : '", $signers_name, "'\n"; | ||
| 404 | print "Digest : $dgst\n"; | ||
| 405 | } | ||
| 406 | |||
| 407 | open(FD, ">$dest") || die $dest; | ||
| 408 | binmode FD; | ||
| 409 | print FD | ||
| 410 | $unsigned_module, | ||
| 411 | $signers_name, | ||
| 412 | $key_identifier, | ||
| 413 | $signature, | ||
| 414 | $info, | ||
| 415 | $magic_number | ||
| 416 | ; | ||
| 417 | close FD || die $dest; | ||
| 418 | |||
| 419 | if (!$keep_orig) { | ||
| 420 | rename($dest, $module) || die $module; | ||
| 421 | } | ||
diff --git a/scripts/sign-file.c b/scripts/sign-file.c new file mode 100755 index 000000000000..058bba3103e2 --- /dev/null +++ b/scripts/sign-file.c | |||
| @@ -0,0 +1,260 @@ | |||
| 1 | /* Sign a module file using the given key. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | #define _GNU_SOURCE | ||
| 12 | #include <stdio.h> | ||
| 13 | #include <stdlib.h> | ||
| 14 | #include <stdint.h> | ||
| 15 | #include <stdbool.h> | ||
| 16 | #include <string.h> | ||
| 17 | #include <getopt.h> | ||
| 18 | #include <err.h> | ||
| 19 | #include <arpa/inet.h> | ||
| 20 | #include <openssl/bio.h> | ||
| 21 | #include <openssl/evp.h> | ||
| 22 | #include <openssl/pem.h> | ||
| 23 | #include <openssl/cms.h> | ||
| 24 | #include <openssl/err.h> | ||
| 25 | #include <openssl/engine.h> | ||
| 26 | |||
| 27 | struct module_signature { | ||
| 28 | uint8_t algo; /* Public-key crypto algorithm [0] */ | ||
| 29 | uint8_t hash; /* Digest algorithm [0] */ | ||
| 30 | uint8_t id_type; /* Key identifier type [PKEY_ID_PKCS7] */ | ||
| 31 | uint8_t signer_len; /* Length of signer's name [0] */ | ||
| 32 | uint8_t key_id_len; /* Length of key identifier [0] */ | ||
| 33 | uint8_t __pad[3]; | ||
| 34 | uint32_t sig_len; /* Length of signature data */ | ||
| 35 | }; | ||
| 36 | |||
| 37 | #define PKEY_ID_PKCS7 2 | ||
| 38 | |||
| 39 | static char magic_number[] = "~Module signature appended~\n"; | ||
| 40 | |||
| 41 | static __attribute__((noreturn)) | ||
| 42 | void format(void) | ||
| 43 | { | ||
| 44 | fprintf(stderr, | ||
| 45 | "Usage: scripts/sign-file [-dp] <hash algo> <key> <x509> <module> [<dest>]\n"); | ||
| 46 | exit(2); | ||
| 47 | } | ||
| 48 | |||
| 49 | static void display_openssl_errors(int l) | ||
| 50 | { | ||
| 51 | const char *file; | ||
| 52 | char buf[120]; | ||
| 53 | int e, line; | ||
| 54 | |||
| 55 | if (ERR_peek_error() == 0) | ||
| 56 | return; | ||
| 57 | fprintf(stderr, "At main.c:%d:\n", l); | ||
| 58 | |||
| 59 | while ((e = ERR_get_error_line(&file, &line))) { | ||
| 60 | ERR_error_string(e, buf); | ||
| 61 | fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | static void drain_openssl_errors(void) | ||
| 66 | { | ||
| 67 | const char *file; | ||
| 68 | int line; | ||
| 69 | |||
| 70 | if (ERR_peek_error() == 0) | ||
| 71 | return; | ||
| 72 | while (ERR_get_error_line(&file, &line)) {} | ||
| 73 | } | ||
| 74 | |||
| 75 | #define ERR(cond, fmt, ...) \ | ||
| 76 | do { \ | ||
| 77 | bool __cond = (cond); \ | ||
| 78 | display_openssl_errors(__LINE__); \ | ||
| 79 | if (__cond) { \ | ||
| 80 | err(1, fmt, ## __VA_ARGS__); \ | ||
| 81 | } \ | ||
| 82 | } while(0) | ||
| 83 | |||
| 84 | static const char *key_pass; | ||
| 85 | |||
| 86 | static int pem_pw_cb(char *buf, int len, int w, void *v) | ||
| 87 | { | ||
| 88 | int pwlen; | ||
| 89 | |||
| 90 | if (!key_pass) | ||
| 91 | return -1; | ||
| 92 | |||
| 93 | pwlen = strlen(key_pass); | ||
| 94 | if (pwlen >= len) | ||
| 95 | return -1; | ||
| 96 | |||
| 97 | strcpy(buf, key_pass); | ||
| 98 | |||
| 99 | /* If it's wrong, don't keep trying it. */ | ||
| 100 | key_pass = NULL; | ||
| 101 | |||
| 102 | return pwlen; | ||
| 103 | } | ||
| 104 | |||
| 105 | int main(int argc, char **argv) | ||
| 106 | { | ||
| 107 | struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 }; | ||
| 108 | char *hash_algo = NULL; | ||
| 109 | char *private_key_name, *x509_name, *module_name, *dest_name; | ||
| 110 | bool save_cms = false, replace_orig; | ||
| 111 | bool sign_only = false; | ||
| 112 | unsigned char buf[4096]; | ||
| 113 | unsigned long module_size, cms_size; | ||
| 114 | unsigned int use_keyid = 0, use_signed_attrs = CMS_NOATTR; | ||
| 115 | const EVP_MD *digest_algo; | ||
| 116 | EVP_PKEY *private_key; | ||
| 117 | CMS_ContentInfo *cms; | ||
| 118 | X509 *x509; | ||
| 119 | BIO *b, *bd = NULL, *bm; | ||
| 120 | int opt, n; | ||
| 121 | |||
| 122 | OpenSSL_add_all_algorithms(); | ||
| 123 | ERR_load_crypto_strings(); | ||
| 124 | ERR_clear_error(); | ||
| 125 | |||
| 126 | key_pass = getenv("KBUILD_SIGN_PIN"); | ||
| 127 | |||
| 128 | do { | ||
| 129 | opt = getopt(argc, argv, "dpk"); | ||
| 130 | switch (opt) { | ||
| 131 | case 'p': save_cms = true; break; | ||
| 132 | case 'd': sign_only = true; save_cms = true; break; | ||
| 133 | case 'k': use_keyid = CMS_USE_KEYID; break; | ||
| 134 | case -1: break; | ||
| 135 | default: format(); | ||
| 136 | } | ||
| 137 | } while (opt != -1); | ||
| 138 | |||
| 139 | argc -= optind; | ||
| 140 | argv += optind; | ||
| 141 | if (argc < 4 || argc > 5) | ||
| 142 | format(); | ||
| 143 | |||
| 144 | hash_algo = argv[0]; | ||
| 145 | private_key_name = argv[1]; | ||
| 146 | x509_name = argv[2]; | ||
| 147 | module_name = argv[3]; | ||
| 148 | if (argc == 5) { | ||
| 149 | dest_name = argv[4]; | ||
| 150 | replace_orig = false; | ||
| 151 | } else { | ||
| 152 | ERR(asprintf(&dest_name, "%s.~signed~", module_name) < 0, | ||
| 153 | "asprintf"); | ||
| 154 | replace_orig = true; | ||
| 155 | } | ||
| 156 | |||
| 157 | /* Read the private key and the X.509 cert the PKCS#7 message | ||
| 158 | * will point to. | ||
| 159 | */ | ||
| 160 | if (!strncmp(private_key_name, "pkcs11:", 7)) { | ||
| 161 | ENGINE *e; | ||
| 162 | |||
| 163 | ENGINE_load_builtin_engines(); | ||
| 164 | drain_openssl_errors(); | ||
| 165 | e = ENGINE_by_id("pkcs11"); | ||
| 166 | ERR(!e, "Load PKCS#11 ENGINE"); | ||
| 167 | if (ENGINE_init(e)) | ||
| 168 | drain_openssl_errors(); | ||
| 169 | else | ||
| 170 | ERR(1, "ENGINE_init"); | ||
| 171 | if (key_pass) | ||
| 172 | ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); | ||
| 173 | private_key = ENGINE_load_private_key(e, private_key_name, NULL, | ||
| 174 | NULL); | ||
| 175 | ERR(!private_key, "%s", private_key_name); | ||
| 176 | } else { | ||
| 177 | b = BIO_new_file(private_key_name, "rb"); | ||
| 178 | ERR(!b, "%s", private_key_name); | ||
| 179 | private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, NULL); | ||
| 180 | ERR(!private_key, "%s", private_key_name); | ||
| 181 | BIO_free(b); | ||
| 182 | } | ||
| 183 | |||
| 184 | b = BIO_new_file(x509_name, "rb"); | ||
| 185 | ERR(!b, "%s", x509_name); | ||
| 186 | x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */ | ||
| 187 | if (!x509) { | ||
| 188 | ERR(BIO_reset(b) != 1, "%s", x509_name); | ||
| 189 | x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); /* PEM encoded X.509 */ | ||
| 190 | if (x509) | ||
| 191 | drain_openssl_errors(); | ||
| 192 | } | ||
| 193 | BIO_free(b); | ||
| 194 | ERR(!x509, "%s", x509_name); | ||
| 195 | |||
| 196 | /* Open the destination file now so that we can shovel the module data | ||
| 197 | * across as we read it. | ||
| 198 | */ | ||
| 199 | if (!sign_only) { | ||
| 200 | bd = BIO_new_file(dest_name, "wb"); | ||
| 201 | ERR(!bd, "%s", dest_name); | ||
| 202 | } | ||
| 203 | |||
| 204 | /* Digest the module data. */ | ||
| 205 | OpenSSL_add_all_digests(); | ||
| 206 | display_openssl_errors(__LINE__); | ||
| 207 | digest_algo = EVP_get_digestbyname(hash_algo); | ||
| 208 | ERR(!digest_algo, "EVP_get_digestbyname"); | ||
| 209 | |||
| 210 | bm = BIO_new_file(module_name, "rb"); | ||
| 211 | ERR(!bm, "%s", module_name); | ||
| 212 | |||
| 213 | /* Load the CMS message from the digest buffer. */ | ||
| 214 | cms = CMS_sign(NULL, NULL, NULL, NULL, | ||
| 215 | CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | CMS_DETACHED | CMS_STREAM); | ||
| 216 | ERR(!cms, "CMS_sign"); | ||
| 217 | |||
| 218 | ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, | ||
| 219 | CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP | | ||
| 220 | use_keyid | use_signed_attrs), | ||
| 221 | "CMS_sign_add_signer"); | ||
| 222 | ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0, | ||
| 223 | "CMS_final"); | ||
| 224 | |||
| 225 | if (save_cms) { | ||
| 226 | char *cms_name; | ||
| 227 | |||
| 228 | ERR(asprintf(&cms_name, "%s.p7s", module_name) < 0, "asprintf"); | ||
| 229 | b = BIO_new_file(cms_name, "wb"); | ||
| 230 | ERR(!b, "%s", cms_name); | ||
| 231 | ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0, "%s", cms_name); | ||
| 232 | BIO_free(b); | ||
| 233 | } | ||
| 234 | |||
| 235 | if (sign_only) | ||
| 236 | return 0; | ||
| 237 | |||
| 238 | /* Append the marker and the PKCS#7 message to the destination file */ | ||
| 239 | ERR(BIO_reset(bm) < 0, "%s", module_name); | ||
| 240 | while ((n = BIO_read(bm, buf, sizeof(buf))), | ||
| 241 | n > 0) { | ||
| 242 | ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name); | ||
| 243 | } | ||
| 244 | ERR(n < 0, "%s", module_name); | ||
| 245 | module_size = BIO_number_written(bd); | ||
| 246 | |||
| 247 | ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name); | ||
| 248 | cms_size = BIO_number_written(bd) - module_size; | ||
| 249 | sig_info.sig_len = htonl(cms_size); | ||
| 250 | ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name); | ||
| 251 | ERR(BIO_write(bd, magic_number, sizeof(magic_number) - 1) < 0, "%s", dest_name); | ||
| 252 | |||
| 253 | ERR(BIO_free(bd) < 0, "%s", dest_name); | ||
| 254 | |||
| 255 | /* Finally, if we're signing in place, replace the original. */ | ||
| 256 | if (replace_orig) | ||
| 257 | ERR(rename(dest_name, module_name) < 0, "%s", dest_name); | ||
| 258 | |||
| 259 | return 0; | ||
| 260 | } | ||
