diff options
Diffstat (limited to 'crypto')
| -rw-r--r-- | crypto/asymmetric_keys/Kconfig | 7 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/Makefile | 5 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/asymmetric_keys.h | 2 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/asymmetric_type.c | 96 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/mscode_parser.c | 21 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/pkcs7_key_type.c | 72 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/pkcs7_parser.c | 58 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/pkcs7_parser.h | 11 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/pkcs7_trust.c | 43 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/pkcs7_verify.c | 107 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/public_key.c | 20 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/restrict.c | 108 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/signature.c | 18 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/verify_pefile.c | 40 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/verify_pefile.h | 5 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/x509_cert_parser.c | 52 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/x509_parser.h | 12 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 297 | ||||
| -rw-r--r-- | crypto/crypto_user.c | 1 |
19 files changed, 506 insertions, 469 deletions
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index 91a7e047a765..331f6baf2df8 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | menuconfig ASYMMETRIC_KEY_TYPE | 1 | menuconfig ASYMMETRIC_KEY_TYPE |
| 2 | tristate "Asymmetric (public-key cryptographic) key type" | 2 | bool "Asymmetric (public-key cryptographic) key type" |
| 3 | depends on KEYS | 3 | depends on KEYS |
| 4 | help | 4 | help |
| 5 | This option provides support for a key type that holds the data for | 5 | This option provides support for a key type that holds the data for |
| @@ -13,6 +13,7 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE | |||
| 13 | tristate "Asymmetric public-key crypto algorithm subtype" | 13 | tristate "Asymmetric public-key crypto algorithm subtype" |
| 14 | select MPILIB | 14 | select MPILIB |
| 15 | select CRYPTO_HASH_INFO | 15 | select CRYPTO_HASH_INFO |
| 16 | select CRYPTO_AKCIPHER | ||
| 16 | help | 17 | help |
| 17 | This option provides support for asymmetric public key type handling. | 18 | This option provides support for asymmetric public key type handling. |
| 18 | If signature generation and/or verification are to be used, | 19 | If signature generation and/or verification are to be used, |
| @@ -40,8 +41,7 @@ config PKCS7_MESSAGE_PARSER | |||
| 40 | 41 | ||
| 41 | config PKCS7_TEST_KEY | 42 | config PKCS7_TEST_KEY |
| 42 | tristate "PKCS#7 testing key type" | 43 | tristate "PKCS#7 testing key type" |
| 43 | depends on PKCS7_MESSAGE_PARSER | 44 | depends on SYSTEM_DATA_VERIFICATION |
| 44 | select SYSTEM_TRUSTED_KEYRING | ||
| 45 | help | 45 | help |
| 46 | This option provides a type of key that can be loaded up from a | 46 | This option provides a type of key that can be loaded up from a |
| 47 | PKCS#7 message - provided the message is signed by a trusted key. If | 47 | PKCS#7 message - provided the message is signed by a trusted key. If |
| @@ -54,6 +54,7 @@ config PKCS7_TEST_KEY | |||
| 54 | config SIGNED_PE_FILE_VERIFICATION | 54 | config SIGNED_PE_FILE_VERIFICATION |
| 55 | bool "Support for PE file signature verification" | 55 | bool "Support for PE file signature verification" |
| 56 | depends on PKCS7_MESSAGE_PARSER=y | 56 | depends on PKCS7_MESSAGE_PARSER=y |
| 57 | depends on SYSTEM_DATA_VERIFICATION | ||
| 57 | select ASN1 | 58 | select ASN1 |
| 58 | select OID_REGISTRY | 59 | select OID_REGISTRY |
| 59 | help | 60 | help |
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index f90486256f01..6516855bec18 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile | |||
| @@ -4,7 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o | 5 | obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o |
| 6 | 6 | ||
| 7 | asymmetric_keys-y := asymmetric_type.o signature.o | 7 | asymmetric_keys-y := \ |
| 8 | asymmetric_type.o \ | ||
| 9 | restrict.o \ | ||
| 10 | signature.o | ||
| 8 | 11 | ||
| 9 | obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o | 12 | obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o |
| 10 | 13 | ||
diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h index 1d450b580245..ca8e9ac34ce6 100644 --- a/crypto/asymmetric_keys/asymmetric_keys.h +++ b/crypto/asymmetric_keys/asymmetric_keys.h | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | * 2 of the Licence, or (at your option) any later version. | 9 | * 2 of the Licence, or (at your option) any later version. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <keys/asymmetric-type.h> | ||
| 13 | |||
| 12 | extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id); | 14 | extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id); |
| 13 | 15 | ||
| 14 | extern int __asymmetric_key_hex_to_key_id(const char *id, | 16 | extern int __asymmetric_key_hex_to_key_id(const char *id, |
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index 9f2165b27d52..6600181d5d01 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c | |||
| @@ -35,6 +35,95 @@ static LIST_HEAD(asymmetric_key_parsers); | |||
| 35 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); | 35 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); |
| 36 | 36 | ||
| 37 | /** | 37 | /** |
| 38 | * find_asymmetric_key - Find a key by ID. | ||
| 39 | * @keyring: The keys to search. | ||
| 40 | * @id_0: The first ID to look for or NULL. | ||
| 41 | * @id_1: The second ID to look for or NULL. | ||
| 42 | * @partial: Use partial match if true, exact if false. | ||
| 43 | * | ||
| 44 | * Find a key in the given keyring by identifier. The preferred identifier is | ||
| 45 | * the id_0 and the fallback identifier is the id_1. If both are given, the | ||
| 46 | * lookup is by the former, but the latter must also match. | ||
| 47 | */ | ||
| 48 | struct key *find_asymmetric_key(struct key *keyring, | ||
| 49 | const struct asymmetric_key_id *id_0, | ||
| 50 | const struct asymmetric_key_id *id_1, | ||
| 51 | bool partial) | ||
| 52 | { | ||
| 53 | struct key *key; | ||
| 54 | key_ref_t ref; | ||
| 55 | const char *lookup; | ||
| 56 | char *req, *p; | ||
| 57 | int len; | ||
| 58 | |||
| 59 | if (id_0) { | ||
| 60 | lookup = id_0->data; | ||
| 61 | len = id_0->len; | ||
| 62 | } else { | ||
| 63 | lookup = id_1->data; | ||
| 64 | len = id_1->len; | ||
| 65 | } | ||
| 66 | |||
| 67 | /* Construct an identifier "id:<keyid>". */ | ||
| 68 | p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL); | ||
| 69 | if (!req) | ||
| 70 | return ERR_PTR(-ENOMEM); | ||
| 71 | |||
| 72 | if (partial) { | ||
| 73 | *p++ = 'i'; | ||
| 74 | *p++ = 'd'; | ||
| 75 | } else { | ||
| 76 | *p++ = 'e'; | ||
| 77 | *p++ = 'x'; | ||
| 78 | } | ||
| 79 | *p++ = ':'; | ||
| 80 | p = bin2hex(p, lookup, len); | ||
| 81 | *p = 0; | ||
| 82 | |||
| 83 | pr_debug("Look up: \"%s\"\n", req); | ||
| 84 | |||
| 85 | ref = keyring_search(make_key_ref(keyring, 1), | ||
| 86 | &key_type_asymmetric, req); | ||
| 87 | if (IS_ERR(ref)) | ||
| 88 | pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref)); | ||
| 89 | kfree(req); | ||
| 90 | |||
| 91 | if (IS_ERR(ref)) { | ||
| 92 | switch (PTR_ERR(ref)) { | ||
| 93 | /* Hide some search errors */ | ||
| 94 | case -EACCES: | ||
| 95 | case -ENOTDIR: | ||
| 96 | case -EAGAIN: | ||
| 97 | return ERR_PTR(-ENOKEY); | ||
| 98 | default: | ||
| 99 | return ERR_CAST(ref); | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | key = key_ref_to_ptr(ref); | ||
| 104 | if (id_0 && id_1) { | ||
| 105 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); | ||
| 106 | |||
| 107 | if (!kids->id[0]) { | ||
| 108 | pr_debug("First ID matches, but second is missing\n"); | ||
| 109 | goto reject; | ||
| 110 | } | ||
| 111 | if (!asymmetric_key_id_same(id_1, kids->id[1])) { | ||
| 112 | pr_debug("First ID matches, but second does not\n"); | ||
| 113 | goto reject; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key)); | ||
| 118 | return key; | ||
| 119 | |||
| 120 | reject: | ||
| 121 | key_put(key); | ||
| 122 | return ERR_PTR(-EKEYREJECTED); | ||
| 123 | } | ||
| 124 | EXPORT_SYMBOL_GPL(find_asymmetric_key); | ||
| 125 | |||
| 126 | /** | ||
| 38 | * asymmetric_key_generate_id: Construct an asymmetric key ID | 127 | * asymmetric_key_generate_id: Construct an asymmetric key ID |
| 39 | * @val_1: First binary blob | 128 | * @val_1: First binary blob |
| 40 | * @len_1: Length of first binary blob | 129 | * @len_1: Length of first binary blob |
| @@ -331,7 +420,8 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) | |||
| 331 | pr_devel("==>%s()\n", __func__); | 420 | pr_devel("==>%s()\n", __func__); |
| 332 | 421 | ||
| 333 | if (subtype) { | 422 | if (subtype) { |
| 334 | subtype->destroy(prep->payload.data[asym_crypto]); | 423 | subtype->destroy(prep->payload.data[asym_crypto], |
| 424 | prep->payload.data[asym_auth]); | ||
| 335 | module_put(subtype->owner); | 425 | module_put(subtype->owner); |
| 336 | } | 426 | } |
| 337 | asymmetric_key_free_kids(kids); | 427 | asymmetric_key_free_kids(kids); |
| @@ -346,13 +436,15 @@ static void asymmetric_key_destroy(struct key *key) | |||
| 346 | struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); | 436 | struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); |
| 347 | struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids]; | 437 | struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids]; |
| 348 | void *data = key->payload.data[asym_crypto]; | 438 | void *data = key->payload.data[asym_crypto]; |
| 439 | void *auth = key->payload.data[asym_auth]; | ||
| 349 | 440 | ||
| 350 | key->payload.data[asym_crypto] = NULL; | 441 | key->payload.data[asym_crypto] = NULL; |
| 351 | key->payload.data[asym_subtype] = NULL; | 442 | key->payload.data[asym_subtype] = NULL; |
| 352 | key->payload.data[asym_key_ids] = NULL; | 443 | key->payload.data[asym_key_ids] = NULL; |
| 444 | key->payload.data[asym_auth] = NULL; | ||
| 353 | 445 | ||
| 354 | if (subtype) { | 446 | if (subtype) { |
| 355 | subtype->destroy(data); | 447 | subtype->destroy(data, auth); |
| 356 | module_put(subtype->owner); | 448 | module_put(subtype->owner); |
| 357 | } | 449 | } |
| 358 | 450 | ||
diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c index 3242cbfaeaa2..6a76d5c70ef6 100644 --- a/crypto/asymmetric_keys/mscode_parser.c +++ b/crypto/asymmetric_keys/mscode_parser.c | |||
| @@ -21,19 +21,13 @@ | |||
| 21 | /* | 21 | /* |
| 22 | * Parse a Microsoft Individual Code Signing blob | 22 | * Parse a Microsoft Individual Code Signing blob |
| 23 | */ | 23 | */ |
| 24 | int mscode_parse(struct pefile_context *ctx) | 24 | int mscode_parse(void *_ctx, const void *content_data, size_t data_len, |
| 25 | size_t asn1hdrlen) | ||
| 25 | { | 26 | { |
| 26 | const void *content_data; | 27 | struct pefile_context *ctx = _ctx; |
| 27 | size_t data_len; | ||
| 28 | int ret; | ||
| 29 | |||
| 30 | ret = pkcs7_get_content_data(ctx->pkcs7, &content_data, &data_len, 1); | ||
| 31 | |||
| 32 | if (ret) { | ||
| 33 | pr_debug("PKCS#7 message does not contain data\n"); | ||
| 34 | return ret; | ||
| 35 | } | ||
| 36 | 28 | ||
| 29 | content_data -= asn1hdrlen; | ||
| 30 | data_len += asn1hdrlen; | ||
| 37 | pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len), | 31 | pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len), |
| 38 | content_data); | 32 | content_data); |
| 39 | 33 | ||
| @@ -129,7 +123,6 @@ int mscode_note_digest(void *context, size_t hdrlen, | |||
| 129 | { | 123 | { |
| 130 | struct pefile_context *ctx = context; | 124 | struct pefile_context *ctx = context; |
| 131 | 125 | ||
| 132 | ctx->digest = value; | 126 | ctx->digest = kmemdup(value, vlen, GFP_KERNEL); |
| 133 | ctx->digest_len = vlen; | 127 | return ctx->digest ? 0 : -ENOMEM; |
| 134 | return 0; | ||
| 135 | } | 128 | } |
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c index e2d0edbbc71a..1063b644efcd 100644 --- a/crypto/asymmetric_keys/pkcs7_key_type.c +++ b/crypto/asymmetric_keys/pkcs7_key_type.c | |||
| @@ -13,12 +13,9 @@ | |||
| 13 | #include <linux/key.h> | 13 | #include <linux/key.h> |
| 14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
| 15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | #include <linux/verification.h> | ||
| 16 | #include <linux/key-type.h> | 17 | #include <linux/key-type.h> |
| 17 | #include <keys/asymmetric-type.h> | ||
| 18 | #include <crypto/pkcs7.h> | ||
| 19 | #include <keys/user-type.h> | 18 | #include <keys/user-type.h> |
| 20 | #include <keys/system_keyring.h> | ||
| 21 | #include "pkcs7_parser.h" | ||
| 22 | 19 | ||
| 23 | MODULE_LICENSE("GPL"); | 20 | MODULE_LICENSE("GPL"); |
| 24 | MODULE_DESCRIPTION("PKCS#7 testing key type"); | 21 | MODULE_DESCRIPTION("PKCS#7 testing key type"); |
| @@ -29,60 +26,47 @@ MODULE_PARM_DESC(pkcs7_usage, | |||
| 29 | "Usage to specify when verifying the PKCS#7 message"); | 26 | "Usage to specify when verifying the PKCS#7 message"); |
| 30 | 27 | ||
| 31 | /* | 28 | /* |
| 32 | * Preparse a PKCS#7 wrapped and validated data blob. | 29 | * Retrieve the PKCS#7 message content. |
| 33 | */ | 30 | */ |
| 34 | static int pkcs7_preparse(struct key_preparsed_payload *prep) | 31 | static int pkcs7_view_content(void *ctx, const void *data, size_t len, |
| 32 | size_t asn1hdrlen) | ||
| 35 | { | 33 | { |
| 36 | enum key_being_used_for usage = pkcs7_usage; | 34 | struct key_preparsed_payload *prep = ctx; |
| 37 | struct pkcs7_message *pkcs7; | 35 | const void *saved_prep_data; |
| 38 | const void *data, *saved_prep_data; | 36 | size_t saved_prep_datalen; |
| 39 | size_t datalen, saved_prep_datalen; | ||
| 40 | bool trusted; | ||
| 41 | int ret; | 37 | int ret; |
| 42 | 38 | ||
| 43 | kenter(""); | ||
| 44 | |||
| 45 | if (usage >= NR__KEY_BEING_USED_FOR) { | ||
| 46 | pr_err("Invalid usage type %d\n", usage); | ||
| 47 | return -EINVAL; | ||
| 48 | } | ||
| 49 | |||
| 50 | saved_prep_data = prep->data; | 39 | saved_prep_data = prep->data; |
| 51 | saved_prep_datalen = prep->datalen; | 40 | saved_prep_datalen = prep->datalen; |
| 52 | pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); | ||
| 53 | if (IS_ERR(pkcs7)) { | ||
| 54 | ret = PTR_ERR(pkcs7); | ||
| 55 | goto error; | ||
| 56 | } | ||
| 57 | |||
| 58 | ret = pkcs7_verify(pkcs7, usage); | ||
| 59 | if (ret < 0) | ||
| 60 | goto error_free; | ||
| 61 | |||
| 62 | ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); | ||
| 63 | if (ret < 0) | ||
| 64 | goto error_free; | ||
| 65 | if (!trusted) | ||
| 66 | pr_warn("PKCS#7 message doesn't chain back to a trusted key\n"); | ||
| 67 | |||
| 68 | ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false); | ||
| 69 | if (ret < 0) | ||
| 70 | goto error_free; | ||
| 71 | |||
| 72 | prep->data = data; | 41 | prep->data = data; |
| 73 | prep->datalen = datalen; | 42 | prep->datalen = len; |
| 43 | |||
| 74 | ret = user_preparse(prep); | 44 | ret = user_preparse(prep); |
| 45 | |||
| 75 | prep->data = saved_prep_data; | 46 | prep->data = saved_prep_data; |
| 76 | prep->datalen = saved_prep_datalen; | 47 | prep->datalen = saved_prep_datalen; |
| 77 | |||
| 78 | error_free: | ||
| 79 | pkcs7_free_message(pkcs7); | ||
| 80 | error: | ||
| 81 | kleave(" = %d", ret); | ||
| 82 | return ret; | 48 | return ret; |
| 83 | } | 49 | } |
| 84 | 50 | ||
| 85 | /* | 51 | /* |
| 52 | * Preparse a PKCS#7 wrapped and validated data blob. | ||
| 53 | */ | ||
| 54 | static int pkcs7_preparse(struct key_preparsed_payload *prep) | ||
| 55 | { | ||
| 56 | enum key_being_used_for usage = pkcs7_usage; | ||
| 57 | |||
| 58 | if (usage >= NR__KEY_BEING_USED_FOR) { | ||
| 59 | pr_err("Invalid usage type %d\n", usage); | ||
| 60 | return -EINVAL; | ||
| 61 | } | ||
| 62 | |||
| 63 | return verify_pkcs7_signature(NULL, 0, | ||
| 64 | prep->data, prep->datalen, | ||
| 65 | (void *)1UL, usage, | ||
| 66 | pkcs7_view_content, prep); | ||
| 67 | } | ||
| 68 | |||
| 69 | /* | ||
| 86 | * user defined keys take an arbitrary string as the description and an | 70 | * user defined keys take an arbitrary string as the description and an |
| 87 | * arbitrary blob of data as the payload | 71 | * arbitrary blob of data as the payload |
| 88 | */ | 72 | */ |
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index bdd0d753ce5d..af4cd8649117 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c | |||
| @@ -44,9 +44,7 @@ struct pkcs7_parse_context { | |||
| 44 | static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo) | 44 | static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo) |
| 45 | { | 45 | { |
| 46 | if (sinfo) { | 46 | if (sinfo) { |
| 47 | kfree(sinfo->sig.s); | 47 | public_key_signature_free(sinfo->sig); |
| 48 | kfree(sinfo->sig.digest); | ||
| 49 | kfree(sinfo->signing_cert_id); | ||
| 50 | kfree(sinfo); | 48 | kfree(sinfo); |
| 51 | } | 49 | } |
| 52 | } | 50 | } |
| @@ -125,6 +123,10 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen) | |||
| 125 | ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); | 123 | ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); |
| 126 | if (!ctx->sinfo) | 124 | if (!ctx->sinfo) |
| 127 | goto out_no_sinfo; | 125 | goto out_no_sinfo; |
| 126 | ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature), | ||
| 127 | GFP_KERNEL); | ||
| 128 | if (!ctx->sinfo->sig) | ||
| 129 | goto out_no_sig; | ||
| 128 | 130 | ||
| 129 | ctx->data = (unsigned long)data; | 131 | ctx->data = (unsigned long)data; |
| 130 | ctx->ppcerts = &ctx->certs; | 132 | ctx->ppcerts = &ctx->certs; |
| @@ -150,6 +152,7 @@ out: | |||
| 150 | ctx->certs = cert->next; | 152 | ctx->certs = cert->next; |
| 151 | x509_free_certificate(cert); | 153 | x509_free_certificate(cert); |
| 152 | } | 154 | } |
| 155 | out_no_sig: | ||
| 153 | pkcs7_free_signed_info(ctx->sinfo); | 156 | pkcs7_free_signed_info(ctx->sinfo); |
| 154 | out_no_sinfo: | 157 | out_no_sinfo: |
| 155 | pkcs7_free_message(ctx->msg); | 158 | pkcs7_free_message(ctx->msg); |
| @@ -165,24 +168,25 @@ EXPORT_SYMBOL_GPL(pkcs7_parse_message); | |||
| 165 | * @pkcs7: The preparsed PKCS#7 message to access | 168 | * @pkcs7: The preparsed PKCS#7 message to access |
| 166 | * @_data: Place to return a pointer to the data | 169 | * @_data: Place to return a pointer to the data |
| 167 | * @_data_len: Place to return the data length | 170 | * @_data_len: Place to return the data length |
| 168 | * @want_wrapper: True if the ASN.1 object header should be included in the data | 171 | * @_headerlen: Size of ASN.1 header not included in _data |
| 169 | * | 172 | * |
| 170 | * Get access to the data content of the PKCS#7 message, including, optionally, | 173 | * Get access to the data content of the PKCS#7 message. The size of the |
| 171 | * the header of the ASN.1 object that contains it. Returns -ENODATA if the | 174 | * header of the ASN.1 object that contains it is also provided and can be used |
| 172 | * data object was missing from the message. | 175 | * to adjust *_data and *_data_len to get the entire object. |
| 176 | * | ||
| 177 | * Returns -ENODATA if the data object was missing from the message. | ||
| 173 | */ | 178 | */ |
| 174 | int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, | 179 | int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, |
| 175 | const void **_data, size_t *_data_len, | 180 | const void **_data, size_t *_data_len, |
| 176 | bool want_wrapper) | 181 | size_t *_headerlen) |
| 177 | { | 182 | { |
| 178 | size_t wrapper; | ||
| 179 | |||
| 180 | if (!pkcs7->data) | 183 | if (!pkcs7->data) |
| 181 | return -ENODATA; | 184 | return -ENODATA; |
| 182 | 185 | ||
| 183 | wrapper = want_wrapper ? pkcs7->data_hdrlen : 0; | 186 | *_data = pkcs7->data; |
| 184 | *_data = pkcs7->data - wrapper; | 187 | *_data_len = pkcs7->data_len; |
| 185 | *_data_len = pkcs7->data_len + wrapper; | 188 | if (_headerlen) |
| 189 | *_headerlen = pkcs7->data_hdrlen; | ||
| 186 | return 0; | 190 | return 0; |
| 187 | } | 191 | } |
| 188 | EXPORT_SYMBOL_GPL(pkcs7_get_content_data); | 192 | EXPORT_SYMBOL_GPL(pkcs7_get_content_data); |
| @@ -218,25 +222,25 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen, | |||
| 218 | 222 | ||
| 219 | switch (ctx->last_oid) { | 223 | switch (ctx->last_oid) { |
| 220 | case OID_md4: | 224 | case OID_md4: |
| 221 | ctx->sinfo->sig.hash_algo = "md4"; | 225 | ctx->sinfo->sig->hash_algo = "md4"; |
| 222 | break; | 226 | break; |
| 223 | case OID_md5: | 227 | case OID_md5: |
| 224 | ctx->sinfo->sig.hash_algo = "md5"; | 228 | ctx->sinfo->sig->hash_algo = "md5"; |
| 225 | break; | 229 | break; |
| 226 | case OID_sha1: | 230 | case OID_sha1: |
| 227 | ctx->sinfo->sig.hash_algo = "sha1"; | 231 | ctx->sinfo->sig->hash_algo = "sha1"; |
| 228 | break; | 232 | break; |
| 229 | case OID_sha256: | 233 | case OID_sha256: |
| 230 | ctx->sinfo->sig.hash_algo = "sha256"; | 234 | ctx->sinfo->sig->hash_algo = "sha256"; |
| 231 | break; | 235 | break; |
| 232 | case OID_sha384: | 236 | case OID_sha384: |
| 233 | ctx->sinfo->sig.hash_algo = "sha384"; | 237 | ctx->sinfo->sig->hash_algo = "sha384"; |
| 234 | break; | 238 | break; |
| 235 | case OID_sha512: | 239 | case OID_sha512: |
| 236 | ctx->sinfo->sig.hash_algo = "sha512"; | 240 | ctx->sinfo->sig->hash_algo = "sha512"; |
| 237 | break; | 241 | break; |
| 238 | case OID_sha224: | 242 | case OID_sha224: |
| 239 | ctx->sinfo->sig.hash_algo = "sha224"; | 243 | ctx->sinfo->sig->hash_algo = "sha224"; |
| 240 | break; | 244 | break; |
| 241 | default: | 245 | default: |
| 242 | printk("Unsupported digest algo: %u\n", ctx->last_oid); | 246 | printk("Unsupported digest algo: %u\n", ctx->last_oid); |
| @@ -256,7 +260,7 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, | |||
| 256 | 260 | ||
| 257 | switch (ctx->last_oid) { | 261 | switch (ctx->last_oid) { |
| 258 | case OID_rsaEncryption: | 262 | case OID_rsaEncryption: |
| 259 | ctx->sinfo->sig.pkey_algo = "rsa"; | 263 | ctx->sinfo->sig->pkey_algo = "rsa"; |
| 260 | break; | 264 | break; |
| 261 | default: | 265 | default: |
| 262 | printk("Unsupported pkey algo: %u\n", ctx->last_oid); | 266 | printk("Unsupported pkey algo: %u\n", ctx->last_oid); |
| @@ -616,11 +620,11 @@ int pkcs7_sig_note_signature(void *context, size_t hdrlen, | |||
| 616 | { | 620 | { |
| 617 | struct pkcs7_parse_context *ctx = context; | 621 | struct pkcs7_parse_context *ctx = context; |
| 618 | 622 | ||
| 619 | ctx->sinfo->sig.s = kmemdup(value, vlen, GFP_KERNEL); | 623 | ctx->sinfo->sig->s = kmemdup(value, vlen, GFP_KERNEL); |
| 620 | if (!ctx->sinfo->sig.s) | 624 | if (!ctx->sinfo->sig->s) |
| 621 | return -ENOMEM; | 625 | return -ENOMEM; |
| 622 | 626 | ||
| 623 | ctx->sinfo->sig.s_size = vlen; | 627 | ctx->sinfo->sig->s_size = vlen; |
| 624 | return 0; | 628 | return 0; |
| 625 | } | 629 | } |
| 626 | 630 | ||
| @@ -656,12 +660,16 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen, | |||
| 656 | 660 | ||
| 657 | pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data); | 661 | pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data); |
| 658 | 662 | ||
| 659 | sinfo->signing_cert_id = kid; | 663 | sinfo->sig->auth_ids[0] = kid; |
| 660 | sinfo->index = ++ctx->sinfo_index; | 664 | sinfo->index = ++ctx->sinfo_index; |
| 661 | *ctx->ppsinfo = sinfo; | 665 | *ctx->ppsinfo = sinfo; |
| 662 | ctx->ppsinfo = &sinfo->next; | 666 | ctx->ppsinfo = &sinfo->next; |
| 663 | ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); | 667 | ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); |
| 664 | if (!ctx->sinfo) | 668 | if (!ctx->sinfo) |
| 665 | return -ENOMEM; | 669 | return -ENOMEM; |
| 670 | ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature), | ||
| 671 | GFP_KERNEL); | ||
| 672 | if (!ctx->sinfo->sig) | ||
| 673 | return -ENOMEM; | ||
| 666 | return 0; | 674 | return 0; |
| 667 | } | 675 | } |
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h index a66b19ebcf47..f4e81074f5e0 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.h +++ b/crypto/asymmetric_keys/pkcs7_parser.h | |||
| @@ -22,7 +22,6 @@ struct pkcs7_signed_info { | |||
| 22 | struct pkcs7_signed_info *next; | 22 | struct pkcs7_signed_info *next; |
| 23 | struct x509_certificate *signer; /* Signing certificate (in msg->certs) */ | 23 | struct x509_certificate *signer; /* Signing certificate (in msg->certs) */ |
| 24 | unsigned index; | 24 | unsigned index; |
| 25 | bool trusted; | ||
| 26 | bool unsupported_crypto; /* T if not usable due to missing crypto */ | 25 | bool unsupported_crypto; /* T if not usable due to missing crypto */ |
| 27 | 26 | ||
| 28 | /* Message digest - the digest of the Content Data (or NULL) */ | 27 | /* Message digest - the digest of the Content Data (or NULL) */ |
| @@ -41,19 +40,17 @@ struct pkcs7_signed_info { | |||
| 41 | #define sinfo_has_ms_statement_type 5 | 40 | #define sinfo_has_ms_statement_type 5 |
| 42 | time64_t signing_time; | 41 | time64_t signing_time; |
| 43 | 42 | ||
| 44 | /* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1] | ||
| 45 | * or issuing cert's SKID [CMS ver 3]. | ||
| 46 | */ | ||
| 47 | struct asymmetric_key_id *signing_cert_id; | ||
| 48 | |||
| 49 | /* Message signature. | 43 | /* Message signature. |
| 50 | * | 44 | * |
| 51 | * This contains the generated digest of _either_ the Content Data or | 45 | * This contains the generated digest of _either_ the Content Data or |
| 52 | * the Authenticated Attributes [RFC2315 9.3]. If the latter, one of | 46 | * the Authenticated Attributes [RFC2315 9.3]. If the latter, one of |
| 53 | * the attributes contains the digest of the the Content Data within | 47 | * the attributes contains the digest of the the Content Data within |
| 54 | * it. | 48 | * it. |
| 49 | * | ||
| 50 | * THis also contains the issuing cert serial number and issuer's name | ||
| 51 | * [PKCS#7 or CMS ver 1] or issuing cert's SKID [CMS ver 3]. | ||
| 55 | */ | 52 | */ |
| 56 | struct public_key_signature sig; | 53 | struct public_key_signature *sig; |
| 57 | }; | 54 | }; |
| 58 | 55 | ||
| 59 | struct pkcs7_message { | 56 | struct pkcs7_message { |
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c index 7d7a39b47c62..f6a009d88a33 100644 --- a/crypto/asymmetric_keys/pkcs7_trust.c +++ b/crypto/asymmetric_keys/pkcs7_trust.c | |||
| @@ -27,10 +27,9 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 27 | struct pkcs7_signed_info *sinfo, | 27 | struct pkcs7_signed_info *sinfo, |
| 28 | struct key *trust_keyring) | 28 | struct key *trust_keyring) |
| 29 | { | 29 | { |
| 30 | struct public_key_signature *sig = &sinfo->sig; | 30 | struct public_key_signature *sig = sinfo->sig; |
| 31 | struct x509_certificate *x509, *last = NULL, *p; | 31 | struct x509_certificate *x509, *last = NULL, *p; |
| 32 | struct key *key; | 32 | struct key *key; |
| 33 | bool trusted; | ||
| 34 | int ret; | 33 | int ret; |
| 35 | 34 | ||
| 36 | kenter(",%u,", sinfo->index); | 35 | kenter(",%u,", sinfo->index); |
| @@ -42,10 +41,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 42 | 41 | ||
| 43 | for (x509 = sinfo->signer; x509; x509 = x509->signer) { | 42 | for (x509 = sinfo->signer; x509; x509 = x509->signer) { |
| 44 | if (x509->seen) { | 43 | if (x509->seen) { |
| 45 | if (x509->verified) { | 44 | if (x509->verified) |
| 46 | trusted = x509->trusted; | ||
| 47 | goto verified; | 45 | goto verified; |
| 48 | } | ||
| 49 | kleave(" = -ENOKEY [cached]"); | 46 | kleave(" = -ENOKEY [cached]"); |
| 50 | return -ENOKEY; | 47 | return -ENOKEY; |
| 51 | } | 48 | } |
| @@ -54,9 +51,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 54 | /* Look to see if this certificate is present in the trusted | 51 | /* Look to see if this certificate is present in the trusted |
| 55 | * keys. | 52 | * keys. |
| 56 | */ | 53 | */ |
| 57 | key = x509_request_asymmetric_key(trust_keyring, | 54 | key = find_asymmetric_key(trust_keyring, |
| 58 | x509->id, x509->skid, | 55 | x509->id, x509->skid, false); |
| 59 | false); | ||
| 60 | if (!IS_ERR(key)) { | 56 | if (!IS_ERR(key)) { |
| 61 | /* One of the X.509 certificates in the PKCS#7 message | 57 | /* One of the X.509 certificates in the PKCS#7 message |
| 62 | * is apparently the same as one we already trust. | 58 | * is apparently the same as one we already trust. |
| @@ -80,17 +76,17 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 80 | 76 | ||
| 81 | might_sleep(); | 77 | might_sleep(); |
| 82 | last = x509; | 78 | last = x509; |
| 83 | sig = &last->sig; | 79 | sig = last->sig; |
| 84 | } | 80 | } |
| 85 | 81 | ||
| 86 | /* No match - see if the root certificate has a signer amongst the | 82 | /* No match - see if the root certificate has a signer amongst the |
| 87 | * trusted keys. | 83 | * trusted keys. |
| 88 | */ | 84 | */ |
| 89 | if (last && (last->akid_id || last->akid_skid)) { | 85 | if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) { |
| 90 | key = x509_request_asymmetric_key(trust_keyring, | 86 | key = find_asymmetric_key(trust_keyring, |
| 91 | last->akid_id, | 87 | last->sig->auth_ids[0], |
| 92 | last->akid_skid, | 88 | last->sig->auth_ids[1], |
| 93 | false); | 89 | false); |
| 94 | if (!IS_ERR(key)) { | 90 | if (!IS_ERR(key)) { |
| 95 | x509 = last; | 91 | x509 = last; |
| 96 | pr_devel("sinfo %u: Root cert %u signer is key %x\n", | 92 | pr_devel("sinfo %u: Root cert %u signer is key %x\n", |
| @@ -104,10 +100,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 104 | /* As a last resort, see if we have a trusted public key that matches | 100 | /* As a last resort, see if we have a trusted public key that matches |
| 105 | * the signed info directly. | 101 | * the signed info directly. |
| 106 | */ | 102 | */ |
| 107 | key = x509_request_asymmetric_key(trust_keyring, | 103 | key = find_asymmetric_key(trust_keyring, |
| 108 | sinfo->signing_cert_id, | 104 | sinfo->sig->auth_ids[0], NULL, false); |
| 109 | NULL, | ||
| 110 | false); | ||
| 111 | if (!IS_ERR(key)) { | 105 | if (!IS_ERR(key)) { |
| 112 | pr_devel("sinfo %u: Direct signer is key %x\n", | 106 | pr_devel("sinfo %u: Direct signer is key %x\n", |
| 113 | sinfo->index, key_serial(key)); | 107 | sinfo->index, key_serial(key)); |
| @@ -122,7 +116,6 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 122 | 116 | ||
| 123 | matched: | 117 | matched: |
| 124 | ret = verify_signature(key, sig); | 118 | ret = verify_signature(key, sig); |
| 125 | trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags); | ||
| 126 | key_put(key); | 119 | key_put(key); |
| 127 | if (ret < 0) { | 120 | if (ret < 0) { |
| 128 | if (ret == -ENOMEM) | 121 | if (ret == -ENOMEM) |
| @@ -134,12 +127,9 @@ matched: | |||
| 134 | verified: | 127 | verified: |
| 135 | if (x509) { | 128 | if (x509) { |
| 136 | x509->verified = true; | 129 | x509->verified = true; |
| 137 | for (p = sinfo->signer; p != x509; p = p->signer) { | 130 | for (p = sinfo->signer; p != x509; p = p->signer) |
| 138 | p->verified = true; | 131 | p->verified = true; |
| 139 | p->trusted = trusted; | ||
| 140 | } | ||
| 141 | } | 132 | } |
| 142 | sinfo->trusted = trusted; | ||
| 143 | kleave(" = 0"); | 133 | kleave(" = 0"); |
| 144 | return 0; | 134 | return 0; |
| 145 | } | 135 | } |
| @@ -148,7 +138,6 @@ verified: | |||
| 148 | * pkcs7_validate_trust - Validate PKCS#7 trust chain | 138 | * pkcs7_validate_trust - Validate PKCS#7 trust chain |
| 149 | * @pkcs7: The PKCS#7 certificate to validate | 139 | * @pkcs7: The PKCS#7 certificate to validate |
| 150 | * @trust_keyring: Signing certificates to use as starting points | 140 | * @trust_keyring: Signing certificates to use as starting points |
| 151 | * @_trusted: Set to true if trustworth, false otherwise | ||
| 152 | * | 141 | * |
| 153 | * Validate that the certificate chain inside the PKCS#7 message intersects | 142 | * Validate that the certificate chain inside the PKCS#7 message intersects |
| 154 | * keys we already know and trust. | 143 | * keys we already know and trust. |
| @@ -170,16 +159,13 @@ verified: | |||
| 170 | * May also return -ENOMEM. | 159 | * May also return -ENOMEM. |
| 171 | */ | 160 | */ |
| 172 | int pkcs7_validate_trust(struct pkcs7_message *pkcs7, | 161 | int pkcs7_validate_trust(struct pkcs7_message *pkcs7, |
| 173 | struct key *trust_keyring, | 162 | struct key *trust_keyring) |
| 174 | bool *_trusted) | ||
| 175 | { | 163 | { |
| 176 | struct pkcs7_signed_info *sinfo; | 164 | struct pkcs7_signed_info *sinfo; |
| 177 | struct x509_certificate *p; | 165 | struct x509_certificate *p; |
| 178 | int cached_ret = -ENOKEY; | 166 | int cached_ret = -ENOKEY; |
| 179 | int ret; | 167 | int ret; |
| 180 | 168 | ||
| 181 | *_trusted = false; | ||
| 182 | |||
| 183 | for (p = pkcs7->certs; p; p = p->next) | 169 | for (p = pkcs7->certs; p; p = p->next) |
| 184 | p->seen = false; | 170 | p->seen = false; |
| 185 | 171 | ||
| @@ -193,7 +179,6 @@ int pkcs7_validate_trust(struct pkcs7_message *pkcs7, | |||
| 193 | cached_ret = -ENOPKG; | 179 | cached_ret = -ENOPKG; |
| 194 | continue; | 180 | continue; |
| 195 | case 0: | 181 | case 0: |
| 196 | *_trusted |= sinfo->trusted; | ||
| 197 | cached_ret = 0; | 182 | cached_ret = 0; |
| 198 | continue; | 183 | continue; |
| 199 | default: | 184 | default: |
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index 50be2a15e531..44b746e9df1b 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c | |||
| @@ -25,34 +25,36 @@ | |||
| 25 | static int pkcs7_digest(struct pkcs7_message *pkcs7, | 25 | static int pkcs7_digest(struct pkcs7_message *pkcs7, |
| 26 | struct pkcs7_signed_info *sinfo) | 26 | struct pkcs7_signed_info *sinfo) |
| 27 | { | 27 | { |
| 28 | struct public_key_signature *sig = sinfo->sig; | ||
| 28 | struct crypto_shash *tfm; | 29 | struct crypto_shash *tfm; |
| 29 | struct shash_desc *desc; | 30 | struct shash_desc *desc; |
| 30 | size_t digest_size, desc_size; | 31 | size_t desc_size; |
| 31 | void *digest; | ||
| 32 | int ret; | 32 | int ret; |
| 33 | 33 | ||
| 34 | kenter(",%u,%s", sinfo->index, sinfo->sig.hash_algo); | 34 | kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo); |
| 35 | 35 | ||
| 36 | if (!sinfo->sig.hash_algo) | 36 | if (!sinfo->sig->hash_algo) |
| 37 | return -ENOPKG; | 37 | return -ENOPKG; |
| 38 | 38 | ||
| 39 | /* Allocate the hashing algorithm we're going to need and find out how | 39 | /* Allocate the hashing algorithm we're going to need and find out how |
| 40 | * big the hash operational data will be. | 40 | * big the hash operational data will be. |
| 41 | */ | 41 | */ |
| 42 | tfm = crypto_alloc_shash(sinfo->sig.hash_algo, 0, 0); | 42 | tfm = crypto_alloc_shash(sinfo->sig->hash_algo, 0, 0); |
| 43 | if (IS_ERR(tfm)) | 43 | if (IS_ERR(tfm)) |
| 44 | return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); | 44 | return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); |
| 45 | 45 | ||
| 46 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | 46 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); |
| 47 | sinfo->sig.digest_size = digest_size = crypto_shash_digestsize(tfm); | 47 | sig->digest_size = crypto_shash_digestsize(tfm); |
| 48 | 48 | ||
| 49 | ret = -ENOMEM; | 49 | ret = -ENOMEM; |
| 50 | digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size, | 50 | sig->digest = kmalloc(sig->digest_size, GFP_KERNEL); |
| 51 | GFP_KERNEL); | 51 | if (!sig->digest) |
| 52 | if (!digest) | 52 | goto error_no_desc; |
| 53 | |||
| 54 | desc = kzalloc(desc_size, GFP_KERNEL); | ||
| 55 | if (!desc) | ||
| 53 | goto error_no_desc; | 56 | goto error_no_desc; |
| 54 | 57 | ||
| 55 | desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc)); | ||
| 56 | desc->tfm = tfm; | 58 | desc->tfm = tfm; |
| 57 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | 59 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; |
| 58 | 60 | ||
| @@ -60,10 +62,11 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, | |||
| 60 | ret = crypto_shash_init(desc); | 62 | ret = crypto_shash_init(desc); |
| 61 | if (ret < 0) | 63 | if (ret < 0) |
| 62 | goto error; | 64 | goto error; |
| 63 | ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, digest); | 65 | ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, |
| 66 | sig->digest); | ||
| 64 | if (ret < 0) | 67 | if (ret < 0) |
| 65 | goto error; | 68 | goto error; |
| 66 | pr_devel("MsgDigest = [%*ph]\n", 8, digest); | 69 | pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest); |
| 67 | 70 | ||
| 68 | /* However, if there are authenticated attributes, there must be a | 71 | /* However, if there are authenticated attributes, there must be a |
| 69 | * message digest attribute amongst them which corresponds to the | 72 | * message digest attribute amongst them which corresponds to the |
| @@ -78,14 +81,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, | |||
| 78 | goto error; | 81 | goto error; |
| 79 | } | 82 | } |
| 80 | 83 | ||
| 81 | if (sinfo->msgdigest_len != sinfo->sig.digest_size) { | 84 | if (sinfo->msgdigest_len != sig->digest_size) { |
| 82 | pr_debug("Sig %u: Invalid digest size (%u)\n", | 85 | pr_debug("Sig %u: Invalid digest size (%u)\n", |
| 83 | sinfo->index, sinfo->msgdigest_len); | 86 | sinfo->index, sinfo->msgdigest_len); |
| 84 | ret = -EBADMSG; | 87 | ret = -EBADMSG; |
| 85 | goto error; | 88 | goto error; |
| 86 | } | 89 | } |
| 87 | 90 | ||
| 88 | if (memcmp(digest, sinfo->msgdigest, sinfo->msgdigest_len) != 0) { | 91 | if (memcmp(sig->digest, sinfo->msgdigest, |
| 92 | sinfo->msgdigest_len) != 0) { | ||
| 89 | pr_debug("Sig %u: Message digest doesn't match\n", | 93 | pr_debug("Sig %u: Message digest doesn't match\n", |
| 90 | sinfo->index); | 94 | sinfo->index); |
| 91 | ret = -EKEYREJECTED; | 95 | ret = -EKEYREJECTED; |
| @@ -97,7 +101,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, | |||
| 97 | * convert the attributes from a CONT.0 into a SET before we | 101 | * convert the attributes from a CONT.0 into a SET before we |
| 98 | * hash it. | 102 | * hash it. |
| 99 | */ | 103 | */ |
| 100 | memset(digest, 0, sinfo->sig.digest_size); | 104 | memset(sig->digest, 0, sig->digest_size); |
| 101 | 105 | ||
| 102 | ret = crypto_shash_init(desc); | 106 | ret = crypto_shash_init(desc); |
| 103 | if (ret < 0) | 107 | if (ret < 0) |
| @@ -107,17 +111,14 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, | |||
| 107 | if (ret < 0) | 111 | if (ret < 0) |
| 108 | goto error; | 112 | goto error; |
| 109 | ret = crypto_shash_finup(desc, sinfo->authattrs, | 113 | ret = crypto_shash_finup(desc, sinfo->authattrs, |
| 110 | sinfo->authattrs_len, digest); | 114 | sinfo->authattrs_len, sig->digest); |
| 111 | if (ret < 0) | 115 | if (ret < 0) |
| 112 | goto error; | 116 | goto error; |
| 113 | pr_devel("AADigest = [%*ph]\n", 8, digest); | 117 | pr_devel("AADigest = [%*ph]\n", 8, sig->digest); |
| 114 | } | 118 | } |
| 115 | 119 | ||
| 116 | sinfo->sig.digest = digest; | ||
| 117 | digest = NULL; | ||
| 118 | |||
| 119 | error: | 120 | error: |
| 120 | kfree(digest); | 121 | kfree(desc); |
| 121 | error_no_desc: | 122 | error_no_desc: |
| 122 | crypto_free_shash(tfm); | 123 | crypto_free_shash(tfm); |
| 123 | kleave(" = %d", ret); | 124 | kleave(" = %d", ret); |
| @@ -144,12 +145,12 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7, | |||
| 144 | * PKCS#7 message - but I can't be 100% sure of that. It's | 145 | * PKCS#7 message - but I can't be 100% sure of that. It's |
| 145 | * possible this will need element-by-element comparison. | 146 | * possible this will need element-by-element comparison. |
| 146 | */ | 147 | */ |
| 147 | if (!asymmetric_key_id_same(x509->id, sinfo->signing_cert_id)) | 148 | if (!asymmetric_key_id_same(x509->id, sinfo->sig->auth_ids[0])) |
| 148 | continue; | 149 | continue; |
| 149 | pr_devel("Sig %u: Found cert serial match X.509[%u]\n", | 150 | pr_devel("Sig %u: Found cert serial match X.509[%u]\n", |
| 150 | sinfo->index, certix); | 151 | sinfo->index, certix); |
| 151 | 152 | ||
| 152 | if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) { | 153 | if (x509->pub->pkey_algo != sinfo->sig->pkey_algo) { |
| 153 | pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n", | 154 | pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n", |
| 154 | sinfo->index); | 155 | sinfo->index); |
| 155 | continue; | 156 | continue; |
| @@ -164,7 +165,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7, | |||
| 164 | */ | 165 | */ |
| 165 | pr_debug("Sig %u: Issuing X.509 cert not found (#%*phN)\n", | 166 | pr_debug("Sig %u: Issuing X.509 cert not found (#%*phN)\n", |
| 166 | sinfo->index, | 167 | sinfo->index, |
| 167 | sinfo->signing_cert_id->len, sinfo->signing_cert_id->data); | 168 | sinfo->sig->auth_ids[0]->len, sinfo->sig->auth_ids[0]->data); |
| 168 | return 0; | 169 | return 0; |
| 169 | } | 170 | } |
| 170 | 171 | ||
| @@ -174,6 +175,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7, | |||
| 174 | static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | 175 | static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, |
| 175 | struct pkcs7_signed_info *sinfo) | 176 | struct pkcs7_signed_info *sinfo) |
| 176 | { | 177 | { |
| 178 | struct public_key_signature *sig; | ||
| 177 | struct x509_certificate *x509 = sinfo->signer, *p; | 179 | struct x509_certificate *x509 = sinfo->signer, *p; |
| 178 | struct asymmetric_key_id *auth; | 180 | struct asymmetric_key_id *auth; |
| 179 | int ret; | 181 | int ret; |
| @@ -188,34 +190,26 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 188 | x509->subject, | 190 | x509->subject, |
| 189 | x509->raw_serial_size, x509->raw_serial); | 191 | x509->raw_serial_size, x509->raw_serial); |
| 190 | x509->seen = true; | 192 | x509->seen = true; |
| 191 | ret = x509_get_sig_params(x509); | 193 | if (x509->unsupported_key) |
| 192 | if (ret < 0) | 194 | goto unsupported_crypto_in_x509; |
| 193 | goto maybe_missing_crypto_in_x509; | ||
| 194 | 195 | ||
| 195 | pr_debug("- issuer %s\n", x509->issuer); | 196 | pr_debug("- issuer %s\n", x509->issuer); |
| 196 | if (x509->akid_id) | 197 | sig = x509->sig; |
| 198 | if (sig->auth_ids[0]) | ||
| 197 | pr_debug("- authkeyid.id %*phN\n", | 199 | pr_debug("- authkeyid.id %*phN\n", |
| 198 | x509->akid_id->len, x509->akid_id->data); | 200 | sig->auth_ids[0]->len, sig->auth_ids[0]->data); |
| 199 | if (x509->akid_skid) | 201 | if (sig->auth_ids[1]) |
| 200 | pr_debug("- authkeyid.skid %*phN\n", | 202 | pr_debug("- authkeyid.skid %*phN\n", |
| 201 | x509->akid_skid->len, x509->akid_skid->data); | 203 | sig->auth_ids[1]->len, sig->auth_ids[1]->data); |
| 202 | 204 | ||
| 203 | if ((!x509->akid_id && !x509->akid_skid) || | 205 | if (x509->self_signed) { |
| 204 | strcmp(x509->subject, x509->issuer) == 0) { | ||
| 205 | /* If there's no authority certificate specified, then | 206 | /* If there's no authority certificate specified, then |
| 206 | * the certificate must be self-signed and is the root | 207 | * the certificate must be self-signed and is the root |
| 207 | * of the chain. Likewise if the cert is its own | 208 | * of the chain. Likewise if the cert is its own |
| 208 | * authority. | 209 | * authority. |
| 209 | */ | 210 | */ |
| 210 | pr_debug("- no auth?\n"); | 211 | if (x509->unsupported_sig) |
| 211 | if (x509->raw_subject_size != x509->raw_issuer_size || | 212 | goto unsupported_crypto_in_x509; |
| 212 | memcmp(x509->raw_subject, x509->raw_issuer, | ||
| 213 | x509->raw_issuer_size) != 0) | ||
| 214 | return 0; | ||
| 215 | |||
| 216 | ret = x509_check_signature(x509->pub, x509); | ||
| 217 | if (ret < 0) | ||
| 218 | goto maybe_missing_crypto_in_x509; | ||
| 219 | x509->signer = x509; | 213 | x509->signer = x509; |
| 220 | pr_debug("- self-signed\n"); | 214 | pr_debug("- self-signed\n"); |
| 221 | return 0; | 215 | return 0; |
| @@ -224,7 +218,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 224 | /* Look through the X.509 certificates in the PKCS#7 message's | 218 | /* Look through the X.509 certificates in the PKCS#7 message's |
| 225 | * list to see if the next one is there. | 219 | * list to see if the next one is there. |
| 226 | */ | 220 | */ |
| 227 | auth = x509->akid_id; | 221 | auth = sig->auth_ids[0]; |
| 228 | if (auth) { | 222 | if (auth) { |
| 229 | pr_debug("- want %*phN\n", auth->len, auth->data); | 223 | pr_debug("- want %*phN\n", auth->len, auth->data); |
| 230 | for (p = pkcs7->certs; p; p = p->next) { | 224 | for (p = pkcs7->certs; p; p = p->next) { |
| @@ -234,7 +228,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 234 | goto found_issuer_check_skid; | 228 | goto found_issuer_check_skid; |
| 235 | } | 229 | } |
| 236 | } else { | 230 | } else { |
| 237 | auth = x509->akid_skid; | 231 | auth = sig->auth_ids[1]; |
| 238 | pr_debug("- want %*phN\n", auth->len, auth->data); | 232 | pr_debug("- want %*phN\n", auth->len, auth->data); |
| 239 | for (p = pkcs7->certs; p; p = p->next) { | 233 | for (p = pkcs7->certs; p; p = p->next) { |
| 240 | if (!p->skid) | 234 | if (!p->skid) |
| @@ -254,8 +248,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 254 | /* We matched issuer + serialNumber, but if there's an | 248 | /* We matched issuer + serialNumber, but if there's an |
| 255 | * authKeyId.keyId, that must match the CA subjKeyId also. | 249 | * authKeyId.keyId, that must match the CA subjKeyId also. |
| 256 | */ | 250 | */ |
| 257 | if (x509->akid_skid && | 251 | if (sig->auth_ids[1] && |
| 258 | !asymmetric_key_id_same(p->skid, x509->akid_skid)) { | 252 | !asymmetric_key_id_same(p->skid, sig->auth_ids[1])) { |
| 259 | pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n", | 253 | pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n", |
| 260 | sinfo->index, x509->index, p->index); | 254 | sinfo->index, x509->index, p->index); |
| 261 | return -EKEYREJECTED; | 255 | return -EKEYREJECTED; |
| @@ -267,7 +261,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 267 | sinfo->index); | 261 | sinfo->index); |
| 268 | return 0; | 262 | return 0; |
| 269 | } | 263 | } |
| 270 | ret = x509_check_signature(p->pub, x509); | 264 | ret = public_key_verify_signature(p->pub, p->sig); |
| 271 | if (ret < 0) | 265 | if (ret < 0) |
| 272 | return ret; | 266 | return ret; |
| 273 | x509->signer = p; | 267 | x509->signer = p; |
| @@ -279,16 +273,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 279 | might_sleep(); | 273 | might_sleep(); |
| 280 | } | 274 | } |
| 281 | 275 | ||
| 282 | maybe_missing_crypto_in_x509: | 276 | unsupported_crypto_in_x509: |
| 283 | /* Just prune the certificate chain at this point if we lack some | 277 | /* Just prune the certificate chain at this point if we lack some |
| 284 | * crypto module to go further. Note, however, we don't want to set | 278 | * crypto module to go further. Note, however, we don't want to set |
| 285 | * sinfo->missing_crypto as the signed info block may still be | 279 | * sinfo->unsupported_crypto as the signed info block may still be |
| 286 | * validatable against an X.509 cert lower in the chain that we have a | 280 | * validatable against an X.509 cert lower in the chain that we have a |
| 287 | * trusted copy of. | 281 | * trusted copy of. |
| 288 | */ | 282 | */ |
| 289 | if (ret == -ENOPKG) | 283 | return 0; |
| 290 | return 0; | ||
| 291 | return ret; | ||
| 292 | } | 284 | } |
| 293 | 285 | ||
| 294 | /* | 286 | /* |
| @@ -332,7 +324,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
| 332 | } | 324 | } |
| 333 | 325 | ||
| 334 | /* Verify the PKCS#7 binary against the key */ | 326 | /* Verify the PKCS#7 binary against the key */ |
| 335 | ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); | 327 | ret = public_key_verify_signature(sinfo->signer->pub, sinfo->sig); |
| 336 | if (ret < 0) | 328 | if (ret < 0) |
| 337 | return ret; | 329 | return ret; |
| 338 | 330 | ||
| @@ -375,9 +367,8 @@ int pkcs7_verify(struct pkcs7_message *pkcs7, | |||
| 375 | enum key_being_used_for usage) | 367 | enum key_being_used_for usage) |
| 376 | { | 368 | { |
| 377 | struct pkcs7_signed_info *sinfo; | 369 | struct pkcs7_signed_info *sinfo; |
| 378 | struct x509_certificate *x509; | ||
| 379 | int enopkg = -ENOPKG; | 370 | int enopkg = -ENOPKG; |
| 380 | int ret, n; | 371 | int ret; |
| 381 | 372 | ||
| 382 | kenter(""); | 373 | kenter(""); |
| 383 | 374 | ||
| @@ -419,12 +410,6 @@ int pkcs7_verify(struct pkcs7_message *pkcs7, | |||
| 419 | return -EINVAL; | 410 | return -EINVAL; |
| 420 | } | 411 | } |
| 421 | 412 | ||
| 422 | for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { | ||
| 423 | ret = x509_get_sig_params(x509); | ||
| 424 | if (ret < 0) | ||
| 425 | return ret; | ||
| 426 | } | ||
| 427 | |||
| 428 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | 413 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { |
| 429 | ret = pkcs7_verify_one(pkcs7, sinfo); | 414 | ret = pkcs7_verify_one(pkcs7, sinfo); |
| 430 | if (ret < 0) { | 415 | if (ret < 0) { |
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index 0f8b264b3961..fd76b5fc3b3a 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c | |||
| @@ -39,15 +39,23 @@ static void public_key_describe(const struct key *asymmetric_key, | |||
| 39 | /* | 39 | /* |
| 40 | * Destroy a public key algorithm key. | 40 | * Destroy a public key algorithm key. |
| 41 | */ | 41 | */ |
| 42 | void public_key_destroy(void *payload) | 42 | void public_key_free(struct public_key *key) |
| 43 | { | 43 | { |
| 44 | struct public_key *key = payload; | 44 | if (key) { |
| 45 | |||
| 46 | if (key) | ||
| 47 | kfree(key->key); | 45 | kfree(key->key); |
| 48 | kfree(key); | 46 | kfree(key); |
| 47 | } | ||
| 48 | } | ||
| 49 | EXPORT_SYMBOL_GPL(public_key_free); | ||
| 50 | |||
| 51 | /* | ||
| 52 | * Destroy a public key algorithm key. | ||
| 53 | */ | ||
| 54 | static void public_key_destroy(void *payload0, void *payload3) | ||
| 55 | { | ||
| 56 | public_key_free(payload0); | ||
| 57 | public_key_signature_free(payload3); | ||
| 49 | } | 58 | } |
| 50 | EXPORT_SYMBOL_GPL(public_key_destroy); | ||
| 51 | 59 | ||
| 52 | struct public_key_completion { | 60 | struct public_key_completion { |
| 53 | struct completion completion; | 61 | struct completion completion; |
diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c new file mode 100644 index 000000000000..ac4bddf669de --- /dev/null +++ b/crypto/asymmetric_keys/restrict.c | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | /* Instantiate a public key crypto key from an X.509 Certificate | ||
| 2 | * | ||
| 3 | * Copyright (C) 2012, 2016 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 | |||
| 12 | #define pr_fmt(fmt) "ASYM: "fmt | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/err.h> | ||
| 16 | #include <crypto/public_key.h> | ||
| 17 | #include "asymmetric_keys.h" | ||
| 18 | |||
| 19 | static bool use_builtin_keys; | ||
| 20 | static struct asymmetric_key_id *ca_keyid; | ||
| 21 | |||
| 22 | #ifndef MODULE | ||
| 23 | static struct { | ||
| 24 | struct asymmetric_key_id id; | ||
| 25 | unsigned char data[10]; | ||
| 26 | } cakey; | ||
| 27 | |||
| 28 | static int __init ca_keys_setup(char *str) | ||
| 29 | { | ||
| 30 | if (!str) /* default system keyring */ | ||
| 31 | return 1; | ||
| 32 | |||
| 33 | if (strncmp(str, "id:", 3) == 0) { | ||
| 34 | struct asymmetric_key_id *p = &cakey.id; | ||
| 35 | size_t hexlen = (strlen(str) - 3) / 2; | ||
| 36 | int ret; | ||
| 37 | |||
| 38 | if (hexlen == 0 || hexlen > sizeof(cakey.data)) { | ||
| 39 | pr_err("Missing or invalid ca_keys id\n"); | ||
| 40 | return 1; | ||
| 41 | } | ||
| 42 | |||
| 43 | ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen); | ||
| 44 | if (ret < 0) | ||
| 45 | pr_err("Unparsable ca_keys id hex string\n"); | ||
| 46 | else | ||
| 47 | ca_keyid = p; /* owner key 'id:xxxxxx' */ | ||
| 48 | } else if (strcmp(str, "builtin") == 0) { | ||
| 49 | use_builtin_keys = true; | ||
| 50 | } | ||
| 51 | |||
| 52 | return 1; | ||
| 53 | } | ||
| 54 | __setup("ca_keys=", ca_keys_setup); | ||
| 55 | #endif | ||
| 56 | |||
| 57 | /** | ||
| 58 | * restrict_link_by_signature - Restrict additions to a ring of public keys | ||
| 59 | * @trust_keyring: A ring of keys that can be used to vouch for the new cert. | ||
| 60 | * @type: The type of key being added. | ||
| 61 | * @payload: The payload of the new key. | ||
| 62 | * | ||
| 63 | * Check the new certificate against the ones in the trust keyring. If one of | ||
| 64 | * those is the signing key and validates the new certificate, then mark the | ||
| 65 | * new certificate as being trusted. | ||
| 66 | * | ||
| 67 | * Returns 0 if the new certificate was accepted, -ENOKEY if we couldn't find a | ||
| 68 | * matching parent certificate in the trusted list, -EKEYREJECTED if the | ||
| 69 | * signature check fails or the key is blacklisted and some other error if | ||
| 70 | * there is a matching certificate but the signature check cannot be performed. | ||
| 71 | */ | ||
| 72 | int restrict_link_by_signature(struct key *trust_keyring, | ||
| 73 | const struct key_type *type, | ||
| 74 | const union key_payload *payload) | ||
| 75 | { | ||
| 76 | const struct public_key_signature *sig; | ||
| 77 | struct key *key; | ||
| 78 | int ret; | ||
| 79 | |||
| 80 | pr_devel("==>%s()\n", __func__); | ||
| 81 | |||
| 82 | if (!trust_keyring) | ||
| 83 | return -ENOKEY; | ||
| 84 | |||
| 85 | if (type != &key_type_asymmetric) | ||
| 86 | return -EOPNOTSUPP; | ||
| 87 | |||
| 88 | sig = payload->data[asym_auth]; | ||
| 89 | if (!sig->auth_ids[0] && !sig->auth_ids[1]) | ||
| 90 | return 0; | ||
| 91 | |||
| 92 | if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid)) | ||
| 93 | return -EPERM; | ||
| 94 | |||
| 95 | /* See if we have a key that signed this one. */ | ||
| 96 | key = find_asymmetric_key(trust_keyring, | ||
| 97 | sig->auth_ids[0], sig->auth_ids[1], | ||
| 98 | false); | ||
| 99 | if (IS_ERR(key)) | ||
| 100 | return -ENOKEY; | ||
| 101 | |||
| 102 | if (use_builtin_keys && !test_bit(KEY_FLAG_BUILTIN, &key->flags)) | ||
| 103 | ret = -ENOKEY; | ||
| 104 | else | ||
| 105 | ret = verify_signature(key, sig); | ||
| 106 | key_put(key); | ||
| 107 | return ret; | ||
| 108 | } | ||
diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c index 004d5fc8e56b..11b7ba170904 100644 --- a/crypto/asymmetric_keys/signature.c +++ b/crypto/asymmetric_keys/signature.c | |||
| @@ -15,9 +15,27 @@ | |||
| 15 | #include <keys/asymmetric-subtype.h> | 15 | #include <keys/asymmetric-subtype.h> |
| 16 | #include <linux/export.h> | 16 | #include <linux/export.h> |
| 17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
| 18 | #include <linux/slab.h> | ||
| 18 | #include <crypto/public_key.h> | 19 | #include <crypto/public_key.h> |
| 19 | #include "asymmetric_keys.h" | 20 | #include "asymmetric_keys.h" |
| 20 | 21 | ||
| 22 | /* | ||
| 23 | * Destroy a public key signature. | ||
| 24 | */ | ||
| 25 | void public_key_signature_free(struct public_key_signature *sig) | ||
| 26 | { | ||
| 27 | int i; | ||
| 28 | |||
| 29 | if (sig) { | ||
| 30 | for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++) | ||
| 31 | kfree(sig->auth_ids[i]); | ||
| 32 | kfree(sig->s); | ||
| 33 | kfree(sig->digest); | ||
| 34 | kfree(sig); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | EXPORT_SYMBOL_GPL(public_key_signature_free); | ||
| 38 | |||
| 21 | /** | 39 | /** |
| 22 | * verify_signature - Initiate the use of an asymmetric key to verify a signature | 40 | * verify_signature - Initiate the use of an asymmetric key to verify a signature |
| 23 | * @key: The asymmetric key to verify against | 41 | * @key: The asymmetric key to verify against |
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c index 7e8c2338ae25..672a94c2c3ff 100644 --- a/crypto/asymmetric_keys/verify_pefile.c +++ b/crypto/asymmetric_keys/verify_pefile.c | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
| 17 | #include <linux/pe.h> | 17 | #include <linux/pe.h> |
| 18 | #include <linux/asn1.h> | 18 | #include <linux/asn1.h> |
| 19 | #include <crypto/pkcs7.h> | 19 | #include <linux/verification.h> |
| 20 | #include <crypto/hash.h> | 20 | #include <crypto/hash.h> |
| 21 | #include "verify_pefile.h" | 21 | #include "verify_pefile.h" |
| 22 | 22 | ||
| @@ -392,9 +392,8 @@ error_no_desc: | |||
| 392 | * verify_pefile_signature - Verify the signature on a PE binary image | 392 | * verify_pefile_signature - Verify the signature on a PE binary image |
| 393 | * @pebuf: Buffer containing the PE binary image | 393 | * @pebuf: Buffer containing the PE binary image |
| 394 | * @pelen: Length of the binary image | 394 | * @pelen: Length of the binary image |
| 395 | * @trust_keyring: Signing certificates to use as starting points | 395 | * @trust_keys: Signing certificate(s) to use as starting points |
| 396 | * @usage: The use to which the key is being put. | 396 | * @usage: The use to which the key is being put. |
| 397 | * @_trusted: Set to true if trustworth, false otherwise | ||
| 398 | * | 397 | * |
| 399 | * Validate that the certificate chain inside the PKCS#7 message inside the PE | 398 | * Validate that the certificate chain inside the PKCS#7 message inside the PE |
| 400 | * binary image intersects keys we already know and trust. | 399 | * binary image intersects keys we already know and trust. |
| @@ -418,14 +417,10 @@ error_no_desc: | |||
| 418 | * May also return -ENOMEM. | 417 | * May also return -ENOMEM. |
| 419 | */ | 418 | */ |
| 420 | int verify_pefile_signature(const void *pebuf, unsigned pelen, | 419 | int verify_pefile_signature(const void *pebuf, unsigned pelen, |
| 421 | struct key *trusted_keyring, | 420 | struct key *trusted_keys, |
| 422 | enum key_being_used_for usage, | 421 | enum key_being_used_for usage) |
| 423 | bool *_trusted) | ||
| 424 | { | 422 | { |
| 425 | struct pkcs7_message *pkcs7; | ||
| 426 | struct pefile_context ctx; | 423 | struct pefile_context ctx; |
| 427 | const void *data; | ||
| 428 | size_t datalen; | ||
| 429 | int ret; | 424 | int ret; |
| 430 | 425 | ||
| 431 | kenter(""); | 426 | kenter(""); |
| @@ -439,19 +434,10 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen, | |||
| 439 | if (ret < 0) | 434 | if (ret < 0) |
| 440 | return ret; | 435 | return ret; |
| 441 | 436 | ||
| 442 | pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len); | 437 | ret = verify_pkcs7_signature(NULL, 0, |
| 443 | if (IS_ERR(pkcs7)) | 438 | pebuf + ctx.sig_offset, ctx.sig_len, |
| 444 | return PTR_ERR(pkcs7); | 439 | trusted_keys, usage, |
| 445 | ctx.pkcs7 = pkcs7; | 440 | mscode_parse, &ctx); |
| 446 | |||
| 447 | ret = pkcs7_get_content_data(ctx.pkcs7, &data, &datalen, false); | ||
| 448 | if (ret < 0 || datalen == 0) { | ||
| 449 | pr_devel("PKCS#7 message does not contain data\n"); | ||
| 450 | ret = -EBADMSG; | ||
| 451 | goto error; | ||
| 452 | } | ||
| 453 | |||
| 454 | ret = mscode_parse(&ctx); | ||
| 455 | if (ret < 0) | 441 | if (ret < 0) |
| 456 | goto error; | 442 | goto error; |
| 457 | 443 | ||
| @@ -462,16 +448,8 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen, | |||
| 462 | * contents. | 448 | * contents. |
| 463 | */ | 449 | */ |
| 464 | ret = pefile_digest_pe(pebuf, pelen, &ctx); | 450 | ret = pefile_digest_pe(pebuf, pelen, &ctx); |
| 465 | if (ret < 0) | ||
| 466 | goto error; | ||
| 467 | |||
| 468 | ret = pkcs7_verify(pkcs7, usage); | ||
| 469 | if (ret < 0) | ||
| 470 | goto error; | ||
| 471 | |||
| 472 | ret = pkcs7_validate_trust(pkcs7, trusted_keyring, _trusted); | ||
| 473 | 451 | ||
| 474 | error: | 452 | error: |
| 475 | pkcs7_free_message(ctx.pkcs7); | 453 | kfree(ctx.digest); |
| 476 | return ret; | 454 | return ret; |
| 477 | } | 455 | } |
diff --git a/crypto/asymmetric_keys/verify_pefile.h b/crypto/asymmetric_keys/verify_pefile.h index a133eb81a492..cd4d20930728 100644 --- a/crypto/asymmetric_keys/verify_pefile.h +++ b/crypto/asymmetric_keys/verify_pefile.h | |||
| @@ -9,7 +9,6 @@ | |||
| 9 | * 2 of the Licence, or (at your option) any later version. | 9 | * 2 of the Licence, or (at your option) any later version. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/verify_pefile.h> | ||
| 13 | #include <crypto/pkcs7.h> | 12 | #include <crypto/pkcs7.h> |
| 14 | #include <crypto/hash_info.h> | 13 | #include <crypto/hash_info.h> |
| 15 | 14 | ||
| @@ -23,7 +22,6 @@ struct pefile_context { | |||
| 23 | unsigned sig_offset; | 22 | unsigned sig_offset; |
| 24 | unsigned sig_len; | 23 | unsigned sig_len; |
| 25 | const struct section_header *secs; | 24 | const struct section_header *secs; |
| 26 | struct pkcs7_message *pkcs7; | ||
| 27 | 25 | ||
| 28 | /* PKCS#7 MS Individual Code Signing content */ | 26 | /* PKCS#7 MS Individual Code Signing content */ |
| 29 | const void *digest; /* Digest */ | 27 | const void *digest; /* Digest */ |
| @@ -39,4 +37,5 @@ struct pefile_context { | |||
| 39 | /* | 37 | /* |
| 40 | * mscode_parser.c | 38 | * mscode_parser.c |
| 41 | */ | 39 | */ |
| 42 | extern int mscode_parse(struct pefile_context *ctx); | 40 | extern int mscode_parse(void *_ctx, const void *content_data, size_t data_len, |
| 41 | size_t asn1hdrlen); | ||
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 4a29bac70060..865f46ea724f 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c | |||
| @@ -47,15 +47,12 @@ struct x509_parse_context { | |||
| 47 | void x509_free_certificate(struct x509_certificate *cert) | 47 | void x509_free_certificate(struct x509_certificate *cert) |
| 48 | { | 48 | { |
| 49 | if (cert) { | 49 | if (cert) { |
| 50 | public_key_destroy(cert->pub); | 50 | public_key_free(cert->pub); |
| 51 | public_key_signature_free(cert->sig); | ||
| 51 | kfree(cert->issuer); | 52 | kfree(cert->issuer); |
| 52 | kfree(cert->subject); | 53 | kfree(cert->subject); |
| 53 | kfree(cert->id); | 54 | kfree(cert->id); |
| 54 | kfree(cert->skid); | 55 | kfree(cert->skid); |
| 55 | kfree(cert->akid_id); | ||
| 56 | kfree(cert->akid_skid); | ||
| 57 | kfree(cert->sig.digest); | ||
| 58 | kfree(cert->sig.s); | ||
| 59 | kfree(cert); | 56 | kfree(cert); |
| 60 | } | 57 | } |
| 61 | } | 58 | } |
| @@ -78,6 +75,9 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) | |||
| 78 | cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL); | 75 | cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL); |
| 79 | if (!cert->pub) | 76 | if (!cert->pub) |
| 80 | goto error_no_ctx; | 77 | goto error_no_ctx; |
| 78 | cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL); | ||
| 79 | if (!cert->sig) | ||
| 80 | goto error_no_ctx; | ||
| 81 | ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL); | 81 | ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL); |
| 82 | if (!ctx) | 82 | if (!ctx) |
| 83 | goto error_no_ctx; | 83 | goto error_no_ctx; |
| @@ -108,6 +108,11 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) | |||
| 108 | 108 | ||
| 109 | cert->pub->keylen = ctx->key_size; | 109 | cert->pub->keylen = ctx->key_size; |
| 110 | 110 | ||
| 111 | /* Grab the signature bits */ | ||
| 112 | ret = x509_get_sig_params(cert); | ||
| 113 | if (ret < 0) | ||
| 114 | goto error_decode; | ||
| 115 | |||
| 111 | /* Generate cert issuer + serial number key ID */ | 116 | /* Generate cert issuer + serial number key ID */ |
| 112 | kid = asymmetric_key_generate_id(cert->raw_serial, | 117 | kid = asymmetric_key_generate_id(cert->raw_serial, |
| 113 | cert->raw_serial_size, | 118 | cert->raw_serial_size, |
| @@ -119,6 +124,11 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) | |||
| 119 | } | 124 | } |
| 120 | cert->id = kid; | 125 | cert->id = kid; |
| 121 | 126 | ||
| 127 | /* Detect self-signed certificates */ | ||
| 128 | ret = x509_check_for_self_signed(cert); | ||
| 129 | if (ret < 0) | ||
| 130 | goto error_decode; | ||
| 131 | |||
| 122 | kfree(ctx); | 132 | kfree(ctx); |
| 123 | return cert; | 133 | return cert; |
| 124 | 134 | ||
| @@ -188,33 +198,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen, | |||
| 188 | return -ENOPKG; /* Unsupported combination */ | 198 | return -ENOPKG; /* Unsupported combination */ |
| 189 | 199 | ||
| 190 | case OID_md4WithRSAEncryption: | 200 | case OID_md4WithRSAEncryption: |
| 191 | ctx->cert->sig.hash_algo = "md4"; | 201 | ctx->cert->sig->hash_algo = "md4"; |
| 192 | ctx->cert->sig.pkey_algo = "rsa"; | 202 | ctx->cert->sig->pkey_algo = "rsa"; |
| 193 | break; | 203 | break; |
| 194 | 204 | ||
| 195 | case OID_sha1WithRSAEncryption: | 205 | case OID_sha1WithRSAEncryption: |
| 196 | ctx->cert->sig.hash_algo = "sha1"; | 206 | ctx->cert->sig->hash_algo = "sha1"; |
| 197 | ctx->cert->sig.pkey_algo = "rsa"; | 207 | ctx->cert->sig->pkey_algo = "rsa"; |
| 198 | break; | 208 | break; |
| 199 | 209 | ||
| 200 | case OID_sha256WithRSAEncryption: | 210 | case OID_sha256WithRSAEncryption: |
| 201 | ctx->cert->sig.hash_algo = "sha256"; | 211 | ctx->cert->sig->hash_algo = "sha256"; |
| 202 | ctx->cert->sig.pkey_algo = "rsa"; | 212 | ctx->cert->sig->pkey_algo = "rsa"; |
| 203 | break; | 213 | break; |
| 204 | 214 | ||
| 205 | case OID_sha384WithRSAEncryption: | 215 | case OID_sha384WithRSAEncryption: |
| 206 | ctx->cert->sig.hash_algo = "sha384"; | 216 | ctx->cert->sig->hash_algo = "sha384"; |
| 207 | ctx->cert->sig.pkey_algo = "rsa"; | 217 | ctx->cert->sig->pkey_algo = "rsa"; |
| 208 | break; | 218 | break; |
| 209 | 219 | ||
| 210 | case OID_sha512WithRSAEncryption: | 220 | case OID_sha512WithRSAEncryption: |
| 211 | ctx->cert->sig.hash_algo = "sha512"; | 221 | ctx->cert->sig->hash_algo = "sha512"; |
| 212 | ctx->cert->sig.pkey_algo = "rsa"; | 222 | ctx->cert->sig->pkey_algo = "rsa"; |
| 213 | break; | 223 | break; |
| 214 | 224 | ||
| 215 | case OID_sha224WithRSAEncryption: | 225 | case OID_sha224WithRSAEncryption: |
| 216 | ctx->cert->sig.hash_algo = "sha224"; | 226 | ctx->cert->sig->hash_algo = "sha224"; |
| 217 | ctx->cert->sig.pkey_algo = "rsa"; | 227 | ctx->cert->sig->pkey_algo = "rsa"; |
| 218 | break; | 228 | break; |
| 219 | } | 229 | } |
| 220 | 230 | ||
| @@ -572,14 +582,14 @@ int x509_akid_note_kid(void *context, size_t hdrlen, | |||
| 572 | 582 | ||
| 573 | pr_debug("AKID: keyid: %*phN\n", (int)vlen, value); | 583 | pr_debug("AKID: keyid: %*phN\n", (int)vlen, value); |
| 574 | 584 | ||
| 575 | if (ctx->cert->akid_skid) | 585 | if (ctx->cert->sig->auth_ids[1]) |
| 576 | return 0; | 586 | return 0; |
| 577 | 587 | ||
| 578 | kid = asymmetric_key_generate_id(value, vlen, "", 0); | 588 | kid = asymmetric_key_generate_id(value, vlen, "", 0); |
| 579 | if (IS_ERR(kid)) | 589 | if (IS_ERR(kid)) |
| 580 | return PTR_ERR(kid); | 590 | return PTR_ERR(kid); |
| 581 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | 591 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); |
| 582 | ctx->cert->akid_skid = kid; | 592 | ctx->cert->sig->auth_ids[1] = kid; |
| 583 | return 0; | 593 | return 0; |
| 584 | } | 594 | } |
| 585 | 595 | ||
| @@ -611,7 +621,7 @@ int x509_akid_note_serial(void *context, size_t hdrlen, | |||
| 611 | 621 | ||
| 612 | pr_debug("AKID: serial: %*phN\n", (int)vlen, value); | 622 | pr_debug("AKID: serial: %*phN\n", (int)vlen, value); |
| 613 | 623 | ||
| 614 | if (!ctx->akid_raw_issuer || ctx->cert->akid_id) | 624 | if (!ctx->akid_raw_issuer || ctx->cert->sig->auth_ids[0]) |
| 615 | return 0; | 625 | return 0; |
| 616 | 626 | ||
| 617 | kid = asymmetric_key_generate_id(value, | 627 | kid = asymmetric_key_generate_id(value, |
| @@ -622,6 +632,6 @@ int x509_akid_note_serial(void *context, size_t hdrlen, | |||
| 622 | return PTR_ERR(kid); | 632 | return PTR_ERR(kid); |
| 623 | 633 | ||
| 624 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | 634 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); |
| 625 | ctx->cert->akid_id = kid; | 635 | ctx->cert->sig->auth_ids[0] = kid; |
| 626 | return 0; | 636 | return 0; |
| 627 | } | 637 | } |
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h index dbeed6018e63..05eef1c68881 100644 --- a/crypto/asymmetric_keys/x509_parser.h +++ b/crypto/asymmetric_keys/x509_parser.h | |||
| @@ -17,13 +17,11 @@ struct x509_certificate { | |||
| 17 | struct x509_certificate *next; | 17 | struct x509_certificate *next; |
| 18 | struct x509_certificate *signer; /* Certificate that signed this one */ | 18 | struct x509_certificate *signer; /* Certificate that signed this one */ |
| 19 | struct public_key *pub; /* Public key details */ | 19 | struct public_key *pub; /* Public key details */ |
| 20 | struct public_key_signature sig; /* Signature parameters */ | 20 | struct public_key_signature *sig; /* Signature parameters */ |
| 21 | char *issuer; /* Name of certificate issuer */ | 21 | char *issuer; /* Name of certificate issuer */ |
| 22 | char *subject; /* Name of certificate subject */ | 22 | char *subject; /* Name of certificate subject */ |
| 23 | struct asymmetric_key_id *id; /* Issuer + Serial number */ | 23 | struct asymmetric_key_id *id; /* Issuer + Serial number */ |
| 24 | struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ | 24 | struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ |
| 25 | struct asymmetric_key_id *akid_id; /* CA AuthKeyId matching ->id (optional) */ | ||
| 26 | struct asymmetric_key_id *akid_skid; /* CA AuthKeyId matching ->skid (optional) */ | ||
| 27 | time64_t valid_from; | 25 | time64_t valid_from; |
| 28 | time64_t valid_to; | 26 | time64_t valid_to; |
| 29 | const void *tbs; /* Signed data */ | 27 | const void *tbs; /* Signed data */ |
| @@ -41,8 +39,9 @@ struct x509_certificate { | |||
| 41 | unsigned index; | 39 | unsigned index; |
| 42 | bool seen; /* Infinite recursion prevention */ | 40 | bool seen; /* Infinite recursion prevention */ |
| 43 | bool verified; | 41 | bool verified; |
| 44 | bool trusted; | 42 | bool self_signed; /* T if self-signed (check unsupported_sig too) */ |
| 45 | bool unsupported_crypto; /* T if can't be verified due to missing crypto */ | 43 | bool unsupported_key; /* T if key uses unsupported crypto */ |
| 44 | bool unsupported_sig; /* T if signature uses unsupported crypto */ | ||
| 46 | }; | 45 | }; |
| 47 | 46 | ||
| 48 | /* | 47 | /* |
| @@ -58,5 +57,4 @@ extern int x509_decode_time(time64_t *_t, size_t hdrlen, | |||
| 58 | * x509_public_key.c | 57 | * x509_public_key.c |
| 59 | */ | 58 | */ |
| 60 | extern int x509_get_sig_params(struct x509_certificate *cert); | 59 | extern int x509_get_sig_params(struct x509_certificate *cert); |
| 61 | extern int x509_check_signature(const struct public_key *pub, | 60 | extern int x509_check_for_self_signed(struct x509_certificate *cert); |
| 62 | struct x509_certificate *cert); | ||
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 733c046aacc6..fb732296cd36 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
| @@ -20,256 +20,133 @@ | |||
| 20 | #include "asymmetric_keys.h" | 20 | #include "asymmetric_keys.h" |
| 21 | #include "x509_parser.h" | 21 | #include "x509_parser.h" |
| 22 | 22 | ||
| 23 | static bool use_builtin_keys; | ||
| 24 | static struct asymmetric_key_id *ca_keyid; | ||
| 25 | |||
| 26 | #ifndef MODULE | ||
| 27 | static struct { | ||
| 28 | struct asymmetric_key_id id; | ||
| 29 | unsigned char data[10]; | ||
| 30 | } cakey; | ||
| 31 | |||
| 32 | static int __init ca_keys_setup(char *str) | ||
| 33 | { | ||
| 34 | if (!str) /* default system keyring */ | ||
| 35 | return 1; | ||
| 36 | |||
| 37 | if (strncmp(str, "id:", 3) == 0) { | ||
| 38 | struct asymmetric_key_id *p = &cakey.id; | ||
| 39 | size_t hexlen = (strlen(str) - 3) / 2; | ||
| 40 | int ret; | ||
| 41 | |||
| 42 | if (hexlen == 0 || hexlen > sizeof(cakey.data)) { | ||
| 43 | pr_err("Missing or invalid ca_keys id\n"); | ||
| 44 | return 1; | ||
| 45 | } | ||
| 46 | |||
| 47 | ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen); | ||
| 48 | if (ret < 0) | ||
| 49 | pr_err("Unparsable ca_keys id hex string\n"); | ||
| 50 | else | ||
| 51 | ca_keyid = p; /* owner key 'id:xxxxxx' */ | ||
| 52 | } else if (strcmp(str, "builtin") == 0) { | ||
| 53 | use_builtin_keys = true; | ||
| 54 | } | ||
| 55 | |||
| 56 | return 1; | ||
| 57 | } | ||
| 58 | __setup("ca_keys=", ca_keys_setup); | ||
| 59 | #endif | ||
| 60 | |||
| 61 | /** | ||
| 62 | * x509_request_asymmetric_key - Request a key by X.509 certificate params. | ||
| 63 | * @keyring: The keys to search. | ||
| 64 | * @id: The issuer & serialNumber to look for or NULL. | ||
| 65 | * @skid: The subjectKeyIdentifier to look for or NULL. | ||
| 66 | * @partial: Use partial match if true, exact if false. | ||
| 67 | * | ||
| 68 | * Find a key in the given keyring by identifier. The preferred identifier is | ||
| 69 | * the issuer + serialNumber and the fallback identifier is the | ||
| 70 | * subjectKeyIdentifier. If both are given, the lookup is by the former, but | ||
| 71 | * the latter must also match. | ||
| 72 | */ | ||
| 73 | struct key *x509_request_asymmetric_key(struct key *keyring, | ||
| 74 | const struct asymmetric_key_id *id, | ||
| 75 | const struct asymmetric_key_id *skid, | ||
| 76 | bool partial) | ||
| 77 | { | ||
| 78 | struct key *key; | ||
| 79 | key_ref_t ref; | ||
| 80 | const char *lookup; | ||
| 81 | char *req, *p; | ||
| 82 | int len; | ||
| 83 | |||
| 84 | if (id) { | ||
| 85 | lookup = id->data; | ||
| 86 | len = id->len; | ||
| 87 | } else { | ||
| 88 | lookup = skid->data; | ||
| 89 | len = skid->len; | ||
| 90 | } | ||
| 91 | |||
| 92 | /* Construct an identifier "id:<keyid>". */ | ||
| 93 | p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL); | ||
| 94 | if (!req) | ||
| 95 | return ERR_PTR(-ENOMEM); | ||
| 96 | |||
| 97 | if (partial) { | ||
| 98 | *p++ = 'i'; | ||
| 99 | *p++ = 'd'; | ||
| 100 | } else { | ||
| 101 | *p++ = 'e'; | ||
| 102 | *p++ = 'x'; | ||
| 103 | } | ||
| 104 | *p++ = ':'; | ||
| 105 | p = bin2hex(p, lookup, len); | ||
| 106 | *p = 0; | ||
| 107 | |||
| 108 | pr_debug("Look up: \"%s\"\n", req); | ||
| 109 | |||
| 110 | ref = keyring_search(make_key_ref(keyring, 1), | ||
| 111 | &key_type_asymmetric, req); | ||
| 112 | if (IS_ERR(ref)) | ||
| 113 | pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref)); | ||
| 114 | kfree(req); | ||
| 115 | |||
| 116 | if (IS_ERR(ref)) { | ||
| 117 | switch (PTR_ERR(ref)) { | ||
| 118 | /* Hide some search errors */ | ||
| 119 | case -EACCES: | ||
| 120 | case -ENOTDIR: | ||
| 121 | case -EAGAIN: | ||
| 122 | return ERR_PTR(-ENOKEY); | ||
| 123 | default: | ||
| 124 | return ERR_CAST(ref); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | key = key_ref_to_ptr(ref); | ||
| 129 | if (id && skid) { | ||
| 130 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); | ||
| 131 | if (!kids->id[1]) { | ||
| 132 | pr_debug("issuer+serial match, but expected SKID missing\n"); | ||
| 133 | goto reject; | ||
| 134 | } | ||
| 135 | if (!asymmetric_key_id_same(skid, kids->id[1])) { | ||
| 136 | pr_debug("issuer+serial match, but SKID does not\n"); | ||
| 137 | goto reject; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key)); | ||
| 142 | return key; | ||
| 143 | |||
| 144 | reject: | ||
| 145 | key_put(key); | ||
| 146 | return ERR_PTR(-EKEYREJECTED); | ||
| 147 | } | ||
| 148 | EXPORT_SYMBOL_GPL(x509_request_asymmetric_key); | ||
| 149 | |||
| 150 | /* | 23 | /* |
| 151 | * Set up the signature parameters in an X.509 certificate. This involves | 24 | * Set up the signature parameters in an X.509 certificate. This involves |
| 152 | * digesting the signed data and extracting the signature. | 25 | * digesting the signed data and extracting the signature. |
| 153 | */ | 26 | */ |
| 154 | int x509_get_sig_params(struct x509_certificate *cert) | 27 | int x509_get_sig_params(struct x509_certificate *cert) |
| 155 | { | 28 | { |
| 29 | struct public_key_signature *sig = cert->sig; | ||
| 156 | struct crypto_shash *tfm; | 30 | struct crypto_shash *tfm; |
| 157 | struct shash_desc *desc; | 31 | struct shash_desc *desc; |
| 158 | size_t digest_size, desc_size; | 32 | size_t desc_size; |
| 159 | void *digest; | ||
| 160 | int ret; | 33 | int ret; |
| 161 | 34 | ||
| 162 | pr_devel("==>%s()\n", __func__); | 35 | pr_devel("==>%s()\n", __func__); |
| 163 | 36 | ||
| 164 | if (cert->unsupported_crypto) | 37 | if (!cert->pub->pkey_algo) |
| 165 | return -ENOPKG; | 38 | cert->unsupported_key = true; |
| 166 | if (cert->sig.s) | 39 | |
| 40 | if (!sig->pkey_algo) | ||
| 41 | cert->unsupported_sig = true; | ||
| 42 | |||
| 43 | /* We check the hash if we can - even if we can't then verify it */ | ||
| 44 | if (!sig->hash_algo) { | ||
| 45 | cert->unsupported_sig = true; | ||
| 167 | return 0; | 46 | return 0; |
| 47 | } | ||
| 168 | 48 | ||
| 169 | cert->sig.s = kmemdup(cert->raw_sig, cert->raw_sig_size, | 49 | sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL); |
| 170 | GFP_KERNEL); | 50 | if (!sig->s) |
| 171 | if (!cert->sig.s) | ||
| 172 | return -ENOMEM; | 51 | return -ENOMEM; |
| 173 | 52 | ||
| 174 | cert->sig.s_size = cert->raw_sig_size; | 53 | sig->s_size = cert->raw_sig_size; |
| 175 | 54 | ||
| 176 | /* Allocate the hashing algorithm we're going to need and find out how | 55 | /* Allocate the hashing algorithm we're going to need and find out how |
| 177 | * big the hash operational data will be. | 56 | * big the hash operational data will be. |
| 178 | */ | 57 | */ |
| 179 | tfm = crypto_alloc_shash(cert->sig.hash_algo, 0, 0); | 58 | tfm = crypto_alloc_shash(sig->hash_algo, 0, 0); |
| 180 | if (IS_ERR(tfm)) { | 59 | if (IS_ERR(tfm)) { |
| 181 | if (PTR_ERR(tfm) == -ENOENT) { | 60 | if (PTR_ERR(tfm) == -ENOENT) { |
| 182 | cert->unsupported_crypto = true; | 61 | cert->unsupported_sig = true; |
| 183 | return -ENOPKG; | 62 | return 0; |
| 184 | } | 63 | } |
| 185 | return PTR_ERR(tfm); | 64 | return PTR_ERR(tfm); |
| 186 | } | 65 | } |
| 187 | 66 | ||
| 188 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | 67 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); |
| 189 | digest_size = crypto_shash_digestsize(tfm); | 68 | sig->digest_size = crypto_shash_digestsize(tfm); |
| 190 | 69 | ||
| 191 | /* We allocate the hash operational data storage on the end of the | ||
| 192 | * digest storage space. | ||
| 193 | */ | ||
| 194 | ret = -ENOMEM; | 70 | ret = -ENOMEM; |
| 195 | digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size, | 71 | sig->digest = kmalloc(sig->digest_size, GFP_KERNEL); |
| 196 | GFP_KERNEL); | 72 | if (!sig->digest) |
| 197 | if (!digest) | ||
| 198 | goto error; | 73 | goto error; |
| 199 | 74 | ||
| 200 | cert->sig.digest = digest; | 75 | desc = kzalloc(desc_size, GFP_KERNEL); |
| 201 | cert->sig.digest_size = digest_size; | 76 | if (!desc) |
| 77 | goto error; | ||
| 202 | 78 | ||
| 203 | desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc)); | ||
| 204 | desc->tfm = tfm; | 79 | desc->tfm = tfm; |
| 205 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | 80 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; |
| 206 | 81 | ||
| 207 | ret = crypto_shash_init(desc); | 82 | ret = crypto_shash_init(desc); |
| 208 | if (ret < 0) | 83 | if (ret < 0) |
| 209 | goto error; | 84 | goto error_2; |
| 210 | might_sleep(); | 85 | might_sleep(); |
| 211 | ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest); | 86 | ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest); |
| 87 | |||
| 88 | error_2: | ||
| 89 | kfree(desc); | ||
| 212 | error: | 90 | error: |
| 213 | crypto_free_shash(tfm); | 91 | crypto_free_shash(tfm); |
| 214 | pr_devel("<==%s() = %d\n", __func__, ret); | 92 | pr_devel("<==%s() = %d\n", __func__, ret); |
| 215 | return ret; | 93 | return ret; |
| 216 | } | 94 | } |
| 217 | EXPORT_SYMBOL_GPL(x509_get_sig_params); | ||
| 218 | 95 | ||
| 219 | /* | 96 | /* |
| 220 | * Check the signature on a certificate using the provided public key | 97 | * Check for self-signedness in an X.509 cert and if found, check the signature |
| 98 | * immediately if we can. | ||
| 221 | */ | 99 | */ |
| 222 | int x509_check_signature(const struct public_key *pub, | 100 | int x509_check_for_self_signed(struct x509_certificate *cert) |
| 223 | struct x509_certificate *cert) | ||
| 224 | { | 101 | { |
| 225 | int ret; | 102 | int ret = 0; |
| 226 | 103 | ||
| 227 | pr_devel("==>%s()\n", __func__); | 104 | pr_devel("==>%s()\n", __func__); |
| 228 | 105 | ||
| 229 | ret = x509_get_sig_params(cert); | 106 | if (cert->raw_subject_size != cert->raw_issuer_size || |
| 230 | if (ret < 0) | 107 | memcmp(cert->raw_subject, cert->raw_issuer, |
| 231 | return ret; | 108 | cert->raw_issuer_size) != 0) |
| 109 | goto not_self_signed; | ||
| 110 | |||
| 111 | if (cert->sig->auth_ids[0] || cert->sig->auth_ids[1]) { | ||
| 112 | /* If the AKID is present it may have one or two parts. If | ||
| 113 | * both are supplied, both must match. | ||
| 114 | */ | ||
| 115 | bool a = asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]); | ||
| 116 | bool b = asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0]); | ||
| 117 | |||
| 118 | if (!a && !b) | ||
| 119 | goto not_self_signed; | ||
| 120 | |||
| 121 | ret = -EKEYREJECTED; | ||
| 122 | if (((a && !b) || (b && !a)) && | ||
| 123 | cert->sig->auth_ids[0] && cert->sig->auth_ids[1]) | ||
| 124 | goto out; | ||
| 125 | } | ||
| 232 | 126 | ||
| 233 | ret = public_key_verify_signature(pub, &cert->sig); | 127 | ret = -EKEYREJECTED; |
| 234 | if (ret == -ENOPKG) | 128 | if (cert->pub->pkey_algo != cert->sig->pkey_algo) |
| 235 | cert->unsupported_crypto = true; | 129 | goto out; |
| 236 | pr_debug("Cert Verification: %d\n", ret); | ||
| 237 | return ret; | ||
| 238 | } | ||
| 239 | EXPORT_SYMBOL_GPL(x509_check_signature); | ||
| 240 | 130 | ||
| 241 | /* | 131 | ret = public_key_verify_signature(cert->pub, cert->sig); |
| 242 | * Check the new certificate against the ones in the trust keyring. If one of | 132 | if (ret < 0) { |
| 243 | * those is the signing key and validates the new certificate, then mark the | 133 | if (ret == -ENOPKG) { |
| 244 | * new certificate as being trusted. | 134 | cert->unsupported_sig = true; |
| 245 | * | 135 | ret = 0; |
| 246 | * Return 0 if the new certificate was successfully validated, 1 if we couldn't | 136 | } |
| 247 | * find a matching parent certificate in the trusted list and an error if there | 137 | goto out; |
| 248 | * is a matching certificate but the signature check fails. | ||
| 249 | */ | ||
| 250 | static int x509_validate_trust(struct x509_certificate *cert, | ||
| 251 | struct key *trust_keyring) | ||
| 252 | { | ||
| 253 | struct key *key; | ||
| 254 | int ret = 1; | ||
| 255 | |||
| 256 | if (!trust_keyring) | ||
| 257 | return -EOPNOTSUPP; | ||
| 258 | |||
| 259 | if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid)) | ||
| 260 | return -EPERM; | ||
| 261 | |||
| 262 | key = x509_request_asymmetric_key(trust_keyring, | ||
| 263 | cert->akid_id, cert->akid_skid, | ||
| 264 | false); | ||
| 265 | if (!IS_ERR(key)) { | ||
| 266 | if (!use_builtin_keys | ||
| 267 | || test_bit(KEY_FLAG_BUILTIN, &key->flags)) | ||
| 268 | ret = x509_check_signature(key->payload.data[asym_crypto], | ||
| 269 | cert); | ||
| 270 | key_put(key); | ||
| 271 | } | 138 | } |
| 139 | |||
| 140 | pr_devel("Cert Self-signature verified"); | ||
| 141 | cert->self_signed = true; | ||
| 142 | |||
| 143 | out: | ||
| 144 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
| 272 | return ret; | 145 | return ret; |
| 146 | |||
| 147 | not_self_signed: | ||
| 148 | pr_devel("<==%s() = 0 [not]\n", __func__); | ||
| 149 | return 0; | ||
| 273 | } | 150 | } |
| 274 | 151 | ||
| 275 | /* | 152 | /* |
| @@ -291,34 +168,22 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
| 291 | pr_devel("Cert Issuer: %s\n", cert->issuer); | 168 | pr_devel("Cert Issuer: %s\n", cert->issuer); |
| 292 | pr_devel("Cert Subject: %s\n", cert->subject); | 169 | pr_devel("Cert Subject: %s\n", cert->subject); |
| 293 | 170 | ||
| 294 | if (!cert->pub->pkey_algo || | 171 | if (cert->unsupported_key) { |
| 295 | !cert->sig.pkey_algo || | ||
| 296 | !cert->sig.hash_algo) { | ||
| 297 | ret = -ENOPKG; | 172 | ret = -ENOPKG; |
| 298 | goto error_free_cert; | 173 | goto error_free_cert; |
| 299 | } | 174 | } |
| 300 | 175 | ||
| 301 | pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo); | 176 | pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo); |
| 302 | pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); | 177 | pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); |
| 303 | pr_devel("Cert Signature: %s + %s\n", | ||
| 304 | cert->sig.pkey_algo, | ||
| 305 | cert->sig.hash_algo); | ||
| 306 | 178 | ||
| 307 | cert->pub->id_type = "X509"; | 179 | cert->pub->id_type = "X509"; |
| 308 | 180 | ||
| 309 | /* Check the signature on the key if it appears to be self-signed */ | 181 | if (cert->unsupported_sig) { |
| 310 | if ((!cert->akid_skid && !cert->akid_id) || | 182 | public_key_signature_free(cert->sig); |
| 311 | asymmetric_key_id_same(cert->skid, cert->akid_skid) || | 183 | cert->sig = NULL; |
| 312 | asymmetric_key_id_same(cert->id, cert->akid_id)) { | 184 | } else { |
| 313 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ | 185 | pr_devel("Cert Signature: %s + %s\n", |
| 314 | if (ret < 0) | 186 | cert->sig->pkey_algo, cert->sig->hash_algo); |
| 315 | goto error_free_cert; | ||
| 316 | } else if (!prep->trusted) { | ||
| 317 | ret = x509_validate_trust(cert, get_system_trusted_keyring()); | ||
| 318 | if (ret) | ||
| 319 | ret = x509_validate_trust(cert, get_ima_mok_keyring()); | ||
| 320 | if (!ret) | ||
| 321 | prep->trusted = 1; | ||
| 322 | } | 187 | } |
| 323 | 188 | ||
| 324 | /* Propose a description */ | 189 | /* Propose a description */ |
| @@ -353,6 +218,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
| 353 | prep->payload.data[asym_subtype] = &public_key_subtype; | 218 | prep->payload.data[asym_subtype] = &public_key_subtype; |
| 354 | prep->payload.data[asym_key_ids] = kids; | 219 | prep->payload.data[asym_key_ids] = kids; |
| 355 | prep->payload.data[asym_crypto] = cert->pub; | 220 | prep->payload.data[asym_crypto] = cert->pub; |
| 221 | prep->payload.data[asym_auth] = cert->sig; | ||
| 356 | prep->description = desc; | 222 | prep->description = desc; |
| 357 | prep->quotalen = 100; | 223 | prep->quotalen = 100; |
| 358 | 224 | ||
| @@ -360,6 +226,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
| 360 | cert->pub = NULL; | 226 | cert->pub = NULL; |
| 361 | cert->id = NULL; | 227 | cert->id = NULL; |
| 362 | cert->skid = NULL; | 228 | cert->skid = NULL; |
| 229 | cert->sig = NULL; | ||
| 363 | desc = NULL; | 230 | desc = NULL; |
| 364 | ret = 0; | 231 | ret = 0; |
| 365 | 232 | ||
diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index 43fe85f20d57..7097a3395b25 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user.c | |||
| @@ -455,6 +455,7 @@ static const int crypto_msg_min[CRYPTO_NR_MSGTYPES] = { | |||
| 455 | [CRYPTO_MSG_NEWALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg), | 455 | [CRYPTO_MSG_NEWALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg), |
| 456 | [CRYPTO_MSG_DELALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg), | 456 | [CRYPTO_MSG_DELALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg), |
| 457 | [CRYPTO_MSG_UPDATEALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg), | 457 | [CRYPTO_MSG_UPDATEALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg), |
| 458 | [CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg), | ||
| 458 | [CRYPTO_MSG_DELRNG - CRYPTO_MSG_BASE] = 0, | 459 | [CRYPTO_MSG_DELRNG - CRYPTO_MSG_BASE] = 0, |
| 459 | }; | 460 | }; |
| 460 | 461 | ||
