diff options
Diffstat (limited to 'security/keys/encrypted.c')
-rw-r--r-- | security/keys/encrypted.c | 141 |
1 files changed, 101 insertions, 40 deletions
diff --git a/security/keys/encrypted.c b/security/keys/encrypted.c index f36a105de791..89981c987ba7 100644 --- a/security/keys/encrypted.c +++ b/security/keys/encrypted.c | |||
@@ -1,8 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 IBM Corporation | 2 | * Copyright (C) 2010 IBM Corporation |
3 | * Copyright (C) 2010 Politecnico di Torino, Italy | ||
4 | * TORSEC group -- http://security.polito.it | ||
3 | * | 5 | * |
4 | * Author: | 6 | * Authors: |
5 | * Mimi Zohar <zohar@us.ibm.com> | 7 | * Mimi Zohar <zohar@us.ibm.com> |
8 | * Roberto Sassu <roberto.sassu@polito.it> | ||
6 | * | 9 | * |
7 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -37,6 +40,7 @@ static const char KEY_USER_PREFIX[] = "user:"; | |||
37 | static const char hash_alg[] = "sha256"; | 40 | static const char hash_alg[] = "sha256"; |
38 | static const char hmac_alg[] = "hmac(sha256)"; | 41 | static const char hmac_alg[] = "hmac(sha256)"; |
39 | static const char blkcipher_alg[] = "cbc(aes)"; | 42 | static const char blkcipher_alg[] = "cbc(aes)"; |
43 | static const char key_format_default[] = "default"; | ||
40 | static unsigned int ivsize; | 44 | static unsigned int ivsize; |
41 | static int blksize; | 45 | static int blksize; |
42 | 46 | ||
@@ -58,6 +62,15 @@ enum { | |||
58 | Opt_err = -1, Opt_new, Opt_load, Opt_update | 62 | Opt_err = -1, Opt_new, Opt_load, Opt_update |
59 | }; | 63 | }; |
60 | 64 | ||
65 | enum { | ||
66 | Opt_error = -1, Opt_default | ||
67 | }; | ||
68 | |||
69 | static const match_table_t key_format_tokens = { | ||
70 | {Opt_default, "default"}, | ||
71 | {Opt_error, NULL} | ||
72 | }; | ||
73 | |||
61 | static const match_table_t key_tokens = { | 74 | static const match_table_t key_tokens = { |
62 | {Opt_new, "new"}, | 75 | {Opt_new, "new"}, |
63 | {Opt_load, "load"}, | 76 | {Opt_load, "load"}, |
@@ -118,8 +131,9 @@ out: | |||
118 | * datablob_parse - parse the keyctl data | 131 | * datablob_parse - parse the keyctl data |
119 | * | 132 | * |
120 | * datablob format: | 133 | * datablob format: |
121 | * new <master-key name> <decrypted data length> | 134 | * new [<format>] <master-key name> <decrypted data length> |
122 | * load <master-key name> <decrypted data length> <encrypted iv + data> | 135 | * load [<format>] <master-key name> <decrypted data length> |
136 | * <encrypted iv + data> | ||
123 | * update <new-master-key name> | 137 | * update <new-master-key name> |
124 | * | 138 | * |
125 | * Tokenizes a copy of the keyctl data, returning a pointer to each token, | 139 | * Tokenizes a copy of the keyctl data, returning a pointer to each token, |
@@ -127,13 +141,15 @@ out: | |||
127 | * | 141 | * |
128 | * On success returns 0, otherwise -EINVAL. | 142 | * On success returns 0, otherwise -EINVAL. |
129 | */ | 143 | */ |
130 | static int datablob_parse(char *datablob, char **master_desc, | 144 | static int datablob_parse(char *datablob, const char **format, |
131 | char **decrypted_datalen, char **hex_encoded_iv) | 145 | char **master_desc, char **decrypted_datalen, |
146 | char **hex_encoded_iv) | ||
132 | { | 147 | { |
133 | substring_t args[MAX_OPT_ARGS]; | 148 | substring_t args[MAX_OPT_ARGS]; |
134 | int ret = -EINVAL; | 149 | int ret = -EINVAL; |
135 | int key_cmd; | 150 | int key_cmd; |
136 | char *keyword; | 151 | int key_format; |
152 | char *p, *keyword; | ||
137 | 153 | ||
138 | keyword = strsep(&datablob, " \t"); | 154 | keyword = strsep(&datablob, " \t"); |
139 | if (!keyword) { | 155 | if (!keyword) { |
@@ -142,7 +158,24 @@ static int datablob_parse(char *datablob, char **master_desc, | |||
142 | } | 158 | } |
143 | key_cmd = match_token(keyword, key_tokens, args); | 159 | key_cmd = match_token(keyword, key_tokens, args); |
144 | 160 | ||
145 | *master_desc = strsep(&datablob, " \t"); | 161 | /* Get optional format: default */ |
162 | p = strsep(&datablob, " \t"); | ||
163 | if (!p) { | ||
164 | pr_err("encrypted_key: insufficient parameters specified\n"); | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | key_format = match_token(p, key_format_tokens, args); | ||
169 | switch (key_format) { | ||
170 | case Opt_default: | ||
171 | *format = p; | ||
172 | *master_desc = strsep(&datablob, " \t"); | ||
173 | break; | ||
174 | case Opt_error: | ||
175 | *master_desc = p; | ||
176 | break; | ||
177 | } | ||
178 | |||
146 | if (!*master_desc) { | 179 | if (!*master_desc) { |
147 | pr_info("encrypted_key: master key parameter is missing\n"); | 180 | pr_info("encrypted_key: master key parameter is missing\n"); |
148 | goto out; | 181 | goto out; |
@@ -220,8 +253,8 @@ static char *datablob_format(struct encrypted_key_payload *epayload, | |||
220 | ascii_buf[asciiblob_len] = '\0'; | 253 | ascii_buf[asciiblob_len] = '\0'; |
221 | 254 | ||
222 | /* copy datablob master_desc and datalen strings */ | 255 | /* copy datablob master_desc and datalen strings */ |
223 | len = sprintf(ascii_buf, "%s %s ", epayload->master_desc, | 256 | len = sprintf(ascii_buf, "%s %s %s ", epayload->format, |
224 | epayload->datalen); | 257 | epayload->master_desc, epayload->datalen); |
225 | 258 | ||
226 | /* convert the hex encoded iv, encrypted-data and HMAC to ascii */ | 259 | /* convert the hex encoded iv, encrypted-data and HMAC to ascii */ |
227 | bufp = &ascii_buf[len]; | 260 | bufp = &ascii_buf[len]; |
@@ -464,9 +497,9 @@ static int datablob_hmac_append(struct encrypted_key_payload *epayload, | |||
464 | if (ret < 0) | 497 | if (ret < 0) |
465 | goto out; | 498 | goto out; |
466 | 499 | ||
467 | digest = epayload->master_desc + epayload->datablob_len; | 500 | digest = epayload->format + epayload->datablob_len; |
468 | ret = calc_hmac(digest, derived_key, sizeof derived_key, | 501 | ret = calc_hmac(digest, derived_key, sizeof derived_key, |
469 | epayload->master_desc, epayload->datablob_len); | 502 | epayload->format, epayload->datablob_len); |
470 | if (!ret) | 503 | if (!ret) |
471 | dump_hmac(NULL, digest, HASH_SIZE); | 504 | dump_hmac(NULL, digest, HASH_SIZE); |
472 | out: | 505 | out: |
@@ -475,26 +508,35 @@ out: | |||
475 | 508 | ||
476 | /* verify HMAC before decrypting encrypted key */ | 509 | /* verify HMAC before decrypting encrypted key */ |
477 | static int datablob_hmac_verify(struct encrypted_key_payload *epayload, | 510 | static int datablob_hmac_verify(struct encrypted_key_payload *epayload, |
478 | const u8 *master_key, size_t master_keylen) | 511 | const u8 *format, const u8 *master_key, |
512 | size_t master_keylen) | ||
479 | { | 513 | { |
480 | u8 derived_key[HASH_SIZE]; | 514 | u8 derived_key[HASH_SIZE]; |
481 | u8 digest[HASH_SIZE]; | 515 | u8 digest[HASH_SIZE]; |
482 | int ret; | 516 | int ret; |
517 | char *p; | ||
518 | unsigned short len; | ||
483 | 519 | ||
484 | ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen); | 520 | ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen); |
485 | if (ret < 0) | 521 | if (ret < 0) |
486 | goto out; | 522 | goto out; |
487 | 523 | ||
488 | ret = calc_hmac(digest, derived_key, sizeof derived_key, | 524 | len = epayload->datablob_len; |
489 | epayload->master_desc, epayload->datablob_len); | 525 | if (!format) { |
526 | p = epayload->master_desc; | ||
527 | len -= strlen(epayload->format) + 1; | ||
528 | } else | ||
529 | p = epayload->format; | ||
530 | |||
531 | ret = calc_hmac(digest, derived_key, sizeof derived_key, p, len); | ||
490 | if (ret < 0) | 532 | if (ret < 0) |
491 | goto out; | 533 | goto out; |
492 | ret = memcmp(digest, epayload->master_desc + epayload->datablob_len, | 534 | ret = memcmp(digest, epayload->format + epayload->datablob_len, |
493 | sizeof digest); | 535 | sizeof digest); |
494 | if (ret) { | 536 | if (ret) { |
495 | ret = -EINVAL; | 537 | ret = -EINVAL; |
496 | dump_hmac("datablob", | 538 | dump_hmac("datablob", |
497 | epayload->master_desc + epayload->datablob_len, | 539 | epayload->format + epayload->datablob_len, |
498 | HASH_SIZE); | 540 | HASH_SIZE); |
499 | dump_hmac("calc", digest, HASH_SIZE); | 541 | dump_hmac("calc", digest, HASH_SIZE); |
500 | } | 542 | } |
@@ -539,13 +581,16 @@ out: | |||
539 | 581 | ||
540 | /* Allocate memory for decrypted key and datablob. */ | 582 | /* Allocate memory for decrypted key and datablob. */ |
541 | static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, | 583 | static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, |
584 | const char *format, | ||
542 | const char *master_desc, | 585 | const char *master_desc, |
543 | const char *datalen) | 586 | const char *datalen) |
544 | { | 587 | { |
545 | struct encrypted_key_payload *epayload = NULL; | 588 | struct encrypted_key_payload *epayload = NULL; |
546 | unsigned short datablob_len; | 589 | unsigned short datablob_len; |
547 | unsigned short decrypted_datalen; | 590 | unsigned short decrypted_datalen; |
591 | unsigned short payload_datalen; | ||
548 | unsigned int encrypted_datalen; | 592 | unsigned int encrypted_datalen; |
593 | unsigned int format_len; | ||
549 | long dlen; | 594 | long dlen; |
550 | int ret; | 595 | int ret; |
551 | 596 | ||
@@ -553,29 +598,32 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, | |||
553 | if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE) | 598 | if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE) |
554 | return ERR_PTR(-EINVAL); | 599 | return ERR_PTR(-EINVAL); |
555 | 600 | ||
601 | format_len = (!format) ? strlen(key_format_default) : strlen(format); | ||
556 | decrypted_datalen = dlen; | 602 | decrypted_datalen = dlen; |
603 | payload_datalen = decrypted_datalen; | ||
557 | encrypted_datalen = roundup(decrypted_datalen, blksize); | 604 | encrypted_datalen = roundup(decrypted_datalen, blksize); |
558 | 605 | ||
559 | datablob_len = strlen(master_desc) + 1 + strlen(datalen) + 1 | 606 | datablob_len = format_len + 1 + strlen(master_desc) + 1 |
560 | + ivsize + 1 + encrypted_datalen; | 607 | + strlen(datalen) + 1 + ivsize + 1 + encrypted_datalen; |
561 | 608 | ||
562 | ret = key_payload_reserve(key, decrypted_datalen + datablob_len | 609 | ret = key_payload_reserve(key, payload_datalen + datablob_len |
563 | + HASH_SIZE + 1); | 610 | + HASH_SIZE + 1); |
564 | if (ret < 0) | 611 | if (ret < 0) |
565 | return ERR_PTR(ret); | 612 | return ERR_PTR(ret); |
566 | 613 | ||
567 | epayload = kzalloc(sizeof(*epayload) + decrypted_datalen + | 614 | epayload = kzalloc(sizeof(*epayload) + payload_datalen + |
568 | datablob_len + HASH_SIZE + 1, GFP_KERNEL); | 615 | datablob_len + HASH_SIZE + 1, GFP_KERNEL); |
569 | if (!epayload) | 616 | if (!epayload) |
570 | return ERR_PTR(-ENOMEM); | 617 | return ERR_PTR(-ENOMEM); |
571 | 618 | ||
619 | epayload->payload_datalen = payload_datalen; | ||
572 | epayload->decrypted_datalen = decrypted_datalen; | 620 | epayload->decrypted_datalen = decrypted_datalen; |
573 | epayload->datablob_len = datablob_len; | 621 | epayload->datablob_len = datablob_len; |
574 | return epayload; | 622 | return epayload; |
575 | } | 623 | } |
576 | 624 | ||
577 | static int encrypted_key_decrypt(struct encrypted_key_payload *epayload, | 625 | static int encrypted_key_decrypt(struct encrypted_key_payload *epayload, |
578 | const char *hex_encoded_iv) | 626 | const char *format, const char *hex_encoded_iv) |
579 | { | 627 | { |
580 | struct key *mkey; | 628 | struct key *mkey; |
581 | u8 derived_key[HASH_SIZE]; | 629 | u8 derived_key[HASH_SIZE]; |
@@ -596,14 +644,14 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload, | |||
596 | hex2bin(epayload->iv, hex_encoded_iv, ivsize); | 644 | hex2bin(epayload->iv, hex_encoded_iv, ivsize); |
597 | hex2bin(epayload->encrypted_data, hex_encoded_data, encrypted_datalen); | 645 | hex2bin(epayload->encrypted_data, hex_encoded_data, encrypted_datalen); |
598 | 646 | ||
599 | hmac = epayload->master_desc + epayload->datablob_len; | 647 | hmac = epayload->format + epayload->datablob_len; |
600 | hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2), HASH_SIZE); | 648 | hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2), HASH_SIZE); |
601 | 649 | ||
602 | mkey = request_master_key(epayload, &master_key, &master_keylen); | 650 | mkey = request_master_key(epayload, &master_key, &master_keylen); |
603 | if (IS_ERR(mkey)) | 651 | if (IS_ERR(mkey)) |
604 | return PTR_ERR(mkey); | 652 | return PTR_ERR(mkey); |
605 | 653 | ||
606 | ret = datablob_hmac_verify(epayload, master_key, master_keylen); | 654 | ret = datablob_hmac_verify(epayload, format, master_key, master_keylen); |
607 | if (ret < 0) { | 655 | if (ret < 0) { |
608 | pr_err("encrypted_key: bad hmac (%d)\n", ret); | 656 | pr_err("encrypted_key: bad hmac (%d)\n", ret); |
609 | goto out; | 657 | goto out; |
@@ -623,14 +671,23 @@ out: | |||
623 | } | 671 | } |
624 | 672 | ||
625 | static void __ekey_init(struct encrypted_key_payload *epayload, | 673 | static void __ekey_init(struct encrypted_key_payload *epayload, |
626 | const char *master_desc, const char *datalen) | 674 | const char *format, const char *master_desc, |
675 | const char *datalen) | ||
627 | { | 676 | { |
628 | epayload->master_desc = epayload->decrypted_data | 677 | unsigned int format_len; |
629 | + epayload->decrypted_datalen; | 678 | |
679 | format_len = (!format) ? strlen(key_format_default) : strlen(format); | ||
680 | epayload->format = epayload->payload_data + epayload->payload_datalen; | ||
681 | epayload->master_desc = epayload->format + format_len + 1; | ||
630 | epayload->datalen = epayload->master_desc + strlen(master_desc) + 1; | 682 | epayload->datalen = epayload->master_desc + strlen(master_desc) + 1; |
631 | epayload->iv = epayload->datalen + strlen(datalen) + 1; | 683 | epayload->iv = epayload->datalen + strlen(datalen) + 1; |
632 | epayload->encrypted_data = epayload->iv + ivsize + 1; | 684 | epayload->encrypted_data = epayload->iv + ivsize + 1; |
685 | epayload->decrypted_data = epayload->payload_data; | ||
633 | 686 | ||
687 | if (!format) | ||
688 | memcpy(epayload->format, key_format_default, format_len); | ||
689 | else | ||
690 | memcpy(epayload->format, format, format_len); | ||
634 | memcpy(epayload->master_desc, master_desc, strlen(master_desc)); | 691 | memcpy(epayload->master_desc, master_desc, strlen(master_desc)); |
635 | memcpy(epayload->datalen, datalen, strlen(datalen)); | 692 | memcpy(epayload->datalen, datalen, strlen(datalen)); |
636 | } | 693 | } |
@@ -642,19 +699,19 @@ static void __ekey_init(struct encrypted_key_payload *epayload, | |||
642 | * itself. For an old key, decrypt the hex encoded data. | 699 | * itself. For an old key, decrypt the hex encoded data. |
643 | */ | 700 | */ |
644 | static int encrypted_init(struct encrypted_key_payload *epayload, | 701 | static int encrypted_init(struct encrypted_key_payload *epayload, |
645 | const char *master_desc, const char *datalen, | 702 | const char *format, const char *master_desc, |
646 | const char *hex_encoded_iv) | 703 | const char *datalen, const char *hex_encoded_iv) |
647 | { | 704 | { |
648 | int ret = 0; | 705 | int ret = 0; |
649 | 706 | ||
650 | __ekey_init(epayload, master_desc, datalen); | 707 | __ekey_init(epayload, format, master_desc, datalen); |
651 | if (!hex_encoded_iv) { | 708 | if (!hex_encoded_iv) { |
652 | get_random_bytes(epayload->iv, ivsize); | 709 | get_random_bytes(epayload->iv, ivsize); |
653 | 710 | ||
654 | get_random_bytes(epayload->decrypted_data, | 711 | get_random_bytes(epayload->decrypted_data, |
655 | epayload->decrypted_datalen); | 712 | epayload->decrypted_datalen); |
656 | } else | 713 | } else |
657 | ret = encrypted_key_decrypt(epayload, hex_encoded_iv); | 714 | ret = encrypted_key_decrypt(epayload, format, hex_encoded_iv); |
658 | return ret; | 715 | return ret; |
659 | } | 716 | } |
660 | 717 | ||
@@ -671,6 +728,7 @@ static int encrypted_instantiate(struct key *key, const void *data, | |||
671 | { | 728 | { |
672 | struct encrypted_key_payload *epayload = NULL; | 729 | struct encrypted_key_payload *epayload = NULL; |
673 | char *datablob = NULL; | 730 | char *datablob = NULL; |
731 | const char *format = NULL; | ||
674 | char *master_desc = NULL; | 732 | char *master_desc = NULL; |
675 | char *decrypted_datalen = NULL; | 733 | char *decrypted_datalen = NULL; |
676 | char *hex_encoded_iv = NULL; | 734 | char *hex_encoded_iv = NULL; |
@@ -684,17 +742,18 @@ static int encrypted_instantiate(struct key *key, const void *data, | |||
684 | return -ENOMEM; | 742 | return -ENOMEM; |
685 | datablob[datalen] = 0; | 743 | datablob[datalen] = 0; |
686 | memcpy(datablob, data, datalen); | 744 | memcpy(datablob, data, datalen); |
687 | ret = datablob_parse(datablob, &master_desc, &decrypted_datalen, | 745 | ret = datablob_parse(datablob, &format, &master_desc, |
688 | &hex_encoded_iv); | 746 | &decrypted_datalen, &hex_encoded_iv); |
689 | if (ret < 0) | 747 | if (ret < 0) |
690 | goto out; | 748 | goto out; |
691 | 749 | ||
692 | epayload = encrypted_key_alloc(key, master_desc, decrypted_datalen); | 750 | epayload = encrypted_key_alloc(key, format, master_desc, |
751 | decrypted_datalen); | ||
693 | if (IS_ERR(epayload)) { | 752 | if (IS_ERR(epayload)) { |
694 | ret = PTR_ERR(epayload); | 753 | ret = PTR_ERR(epayload); |
695 | goto out; | 754 | goto out; |
696 | } | 755 | } |
697 | ret = encrypted_init(epayload, master_desc, decrypted_datalen, | 756 | ret = encrypted_init(epayload, format, master_desc, decrypted_datalen, |
698 | hex_encoded_iv); | 757 | hex_encoded_iv); |
699 | if (ret < 0) { | 758 | if (ret < 0) { |
700 | kfree(epayload); | 759 | kfree(epayload); |
@@ -731,6 +790,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen) | |||
731 | struct encrypted_key_payload *new_epayload; | 790 | struct encrypted_key_payload *new_epayload; |
732 | char *buf; | 791 | char *buf; |
733 | char *new_master_desc = NULL; | 792 | char *new_master_desc = NULL; |
793 | const char *format = NULL; | ||
734 | int ret = 0; | 794 | int ret = 0; |
735 | 795 | ||
736 | if (datalen <= 0 || datalen > 32767 || !data) | 796 | if (datalen <= 0 || datalen > 32767 || !data) |
@@ -742,7 +802,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen) | |||
742 | 802 | ||
743 | buf[datalen] = 0; | 803 | buf[datalen] = 0; |
744 | memcpy(buf, data, datalen); | 804 | memcpy(buf, data, datalen); |
745 | ret = datablob_parse(buf, &new_master_desc, NULL, NULL); | 805 | ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL); |
746 | if (ret < 0) | 806 | if (ret < 0) |
747 | goto out; | 807 | goto out; |
748 | 808 | ||
@@ -750,18 +810,19 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen) | |||
750 | if (ret < 0) | 810 | if (ret < 0) |
751 | goto out; | 811 | goto out; |
752 | 812 | ||
753 | new_epayload = encrypted_key_alloc(key, new_master_desc, | 813 | new_epayload = encrypted_key_alloc(key, epayload->format, |
754 | epayload->datalen); | 814 | new_master_desc, epayload->datalen); |
755 | if (IS_ERR(new_epayload)) { | 815 | if (IS_ERR(new_epayload)) { |
756 | ret = PTR_ERR(new_epayload); | 816 | ret = PTR_ERR(new_epayload); |
757 | goto out; | 817 | goto out; |
758 | } | 818 | } |
759 | 819 | ||
760 | __ekey_init(new_epayload, new_master_desc, epayload->datalen); | 820 | __ekey_init(new_epayload, epayload->format, new_master_desc, |
821 | epayload->datalen); | ||
761 | 822 | ||
762 | memcpy(new_epayload->iv, epayload->iv, ivsize); | 823 | memcpy(new_epayload->iv, epayload->iv, ivsize); |
763 | memcpy(new_epayload->decrypted_data, epayload->decrypted_data, | 824 | memcpy(new_epayload->payload_data, epayload->payload_data, |
764 | epayload->decrypted_datalen); | 825 | epayload->payload_datalen); |
765 | 826 | ||
766 | rcu_assign_pointer(key->payload.data, new_epayload); | 827 | rcu_assign_pointer(key->payload.data, new_epayload); |
767 | call_rcu(&epayload->rcu, encrypted_rcu_free); | 828 | call_rcu(&epayload->rcu, encrypted_rcu_free); |