diff options
Diffstat (limited to 'crypto')
| -rw-r--r-- | crypto/Kconfig | 1 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/Makefile | 8 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/asymmetric_type.c | 11 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/mscode_parser.c | 9 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/pkcs7.asn1 | 22 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/pkcs7_key_type.c | 17 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/pkcs7_parser.c | 277 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/pkcs7_parser.h | 20 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/pkcs7_trust.c | 10 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/pkcs7_verify.c | 145 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/public_key.c | 1 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/verify_pefile.c | 7 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/x509_akid.asn1 | 35 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/x509_cert_parser.c | 231 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/x509_parser.h | 12 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 95 |
16 files changed, 738 insertions, 163 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig index b582ea7f78d3..48ee3e175dac 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig | |||
| @@ -1635,5 +1635,6 @@ config CRYPTO_HASH_INFO | |||
| 1635 | 1635 | ||
| 1636 | source "drivers/crypto/Kconfig" | 1636 | source "drivers/crypto/Kconfig" |
| 1637 | source crypto/asymmetric_keys/Kconfig | 1637 | source crypto/asymmetric_keys/Kconfig |
| 1638 | source certs/Kconfig | ||
| 1638 | 1639 | ||
| 1639 | endif # if CRYPTO | 1640 | endif # if CRYPTO |
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index e47fcd9ac5e8..cd1406f9b14a 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile | |||
| @@ -15,15 +15,21 @@ obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o | |||
| 15 | obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o | 15 | obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o |
| 16 | x509_key_parser-y := \ | 16 | x509_key_parser-y := \ |
| 17 | x509-asn1.o \ | 17 | x509-asn1.o \ |
| 18 | x509_akid-asn1.o \ | ||
| 18 | x509_rsakey-asn1.o \ | 19 | x509_rsakey-asn1.o \ |
| 19 | x509_cert_parser.o \ | 20 | x509_cert_parser.o \ |
| 20 | x509_public_key.o | 21 | x509_public_key.o |
| 21 | 22 | ||
| 22 | $(obj)/x509_cert_parser.o: $(obj)/x509-asn1.h $(obj)/x509_rsakey-asn1.h | 23 | $(obj)/x509_cert_parser.o: \ |
| 24 | $(obj)/x509-asn1.h \ | ||
| 25 | $(obj)/x509_akid-asn1.h \ | ||
| 26 | $(obj)/x509_rsakey-asn1.h | ||
| 23 | $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h | 27 | $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h |
| 28 | $(obj)/x509_akid-asn1.o: $(obj)/x509_akid-asn1.c $(obj)/x509_akid-asn1.h | ||
| 24 | $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h | 29 | $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h |
| 25 | 30 | ||
| 26 | clean-files += x509-asn1.c x509-asn1.h | 31 | clean-files += x509-asn1.c x509-asn1.h |
| 32 | clean-files += x509_akid-asn1.c x509_akid-asn1.h | ||
| 27 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h | 33 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h |
| 28 | 34 | ||
| 29 | # | 35 | # |
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index b0e4ed23d668..1916680ad81b 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | */ | 12 | */ |
| 13 | #include <keys/asymmetric-subtype.h> | 13 | #include <keys/asymmetric-subtype.h> |
| 14 | #include <keys/asymmetric-parser.h> | 14 | #include <keys/asymmetric-parser.h> |
| 15 | #include <crypto/public_key.h> | ||
| 15 | #include <linux/seq_file.h> | 16 | #include <linux/seq_file.h> |
| 16 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 17 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| @@ -20,6 +21,16 @@ | |||
| 20 | 21 | ||
| 21 | MODULE_LICENSE("GPL"); | 22 | MODULE_LICENSE("GPL"); |
| 22 | 23 | ||
| 24 | const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = { | ||
| 25 | [VERIFYING_MODULE_SIGNATURE] = "mod sig", | ||
| 26 | [VERIFYING_FIRMWARE_SIGNATURE] = "firmware sig", | ||
| 27 | [VERIFYING_KEXEC_PE_SIGNATURE] = "kexec PE sig", | ||
| 28 | [VERIFYING_KEY_SIGNATURE] = "key sig", | ||
| 29 | [VERIFYING_KEY_SELF_SIGNATURE] = "key self sig", | ||
| 30 | [VERIFYING_UNSPECIFIED_SIGNATURE] = "unspec sig", | ||
| 31 | }; | ||
| 32 | EXPORT_SYMBOL_GPL(key_being_used_for); | ||
| 33 | |||
| 23 | static LIST_HEAD(asymmetric_key_parsers); | 34 | static LIST_HEAD(asymmetric_key_parsers); |
| 24 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); | 35 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); |
| 25 | 36 | ||
diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c index 214a992123cd..adcef59eec0b 100644 --- a/crypto/asymmetric_keys/mscode_parser.c +++ b/crypto/asymmetric_keys/mscode_parser.c | |||
| @@ -97,6 +97,15 @@ int mscode_note_digest_algo(void *context, size_t hdrlen, | |||
| 97 | case OID_sha256: | 97 | case OID_sha256: |
| 98 | ctx->digest_algo = HASH_ALGO_SHA256; | 98 | ctx->digest_algo = HASH_ALGO_SHA256; |
| 99 | break; | 99 | break; |
| 100 | case OID_sha384: | ||
| 101 | ctx->digest_algo = HASH_ALGO_SHA384; | ||
| 102 | break; | ||
| 103 | case OID_sha512: | ||
| 104 | ctx->digest_algo = HASH_ALGO_SHA512; | ||
| 105 | break; | ||
| 106 | case OID_sha224: | ||
| 107 | ctx->digest_algo = HASH_ALGO_SHA224; | ||
| 108 | break; | ||
| 100 | 109 | ||
| 101 | case OID__NR: | 110 | case OID__NR: |
| 102 | sprint_oid(value, vlen, buffer, sizeof(buffer)); | 111 | sprint_oid(value, vlen, buffer, sizeof(buffer)); |
diff --git a/crypto/asymmetric_keys/pkcs7.asn1 b/crypto/asymmetric_keys/pkcs7.asn1 index a5a14ef28c86..1eca740b816a 100644 --- a/crypto/asymmetric_keys/pkcs7.asn1 +++ b/crypto/asymmetric_keys/pkcs7.asn1 | |||
| @@ -1,14 +1,14 @@ | |||
| 1 | PKCS7ContentInfo ::= SEQUENCE { | 1 | PKCS7ContentInfo ::= SEQUENCE { |
| 2 | contentType ContentType, | 2 | contentType ContentType ({ pkcs7_check_content_type }), |
| 3 | content [0] EXPLICIT SignedData OPTIONAL | 3 | content [0] EXPLICIT SignedData OPTIONAL |
| 4 | } | 4 | } |
| 5 | 5 | ||
| 6 | ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID }) | 6 | ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID }) |
| 7 | 7 | ||
| 8 | SignedData ::= SEQUENCE { | 8 | SignedData ::= SEQUENCE { |
| 9 | version INTEGER, | 9 | version INTEGER ({ pkcs7_note_signeddata_version }), |
| 10 | digestAlgorithms DigestAlgorithmIdentifiers, | 10 | digestAlgorithms DigestAlgorithmIdentifiers, |
| 11 | contentInfo ContentInfo, | 11 | contentInfo ContentInfo ({ pkcs7_note_content }), |
| 12 | certificates CHOICE { | 12 | certificates CHOICE { |
| 13 | certSet [0] IMPLICIT ExtendedCertificatesAndCertificates, | 13 | certSet [0] IMPLICIT ExtendedCertificatesAndCertificates, |
| 14 | certSequence [2] IMPLICIT Certificates | 14 | certSequence [2] IMPLICIT Certificates |
| @@ -21,7 +21,7 @@ SignedData ::= SEQUENCE { | |||
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | ContentInfo ::= SEQUENCE { | 23 | ContentInfo ::= SEQUENCE { |
| 24 | contentType ContentType, | 24 | contentType ContentType ({ pkcs7_note_OID }), |
| 25 | content [0] EXPLICIT Data OPTIONAL | 25 | content [0] EXPLICIT Data OPTIONAL |
| 26 | } | 26 | } |
| 27 | 27 | ||
| @@ -68,8 +68,8 @@ SignerInfos ::= CHOICE { | |||
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | SignerInfo ::= SEQUENCE { | 70 | SignerInfo ::= SEQUENCE { |
| 71 | version INTEGER, | 71 | version INTEGER ({ pkcs7_note_signerinfo_version }), |
| 72 | issuerAndSerialNumber IssuerAndSerialNumber, | 72 | sid SignerIdentifier, -- CMS variant, not PKCS#7 |
| 73 | digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }), | 73 | digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }), |
| 74 | authenticatedAttributes CHOICE { | 74 | authenticatedAttributes CHOICE { |
| 75 | aaSet [0] IMPLICIT SetOfAuthenticatedAttribute | 75 | aaSet [0] IMPLICIT SetOfAuthenticatedAttribute |
| @@ -88,6 +88,12 @@ SignerInfo ::= SEQUENCE { | |||
| 88 | } OPTIONAL | 88 | } OPTIONAL |
| 89 | } ({ pkcs7_note_signed_info }) | 89 | } ({ pkcs7_note_signed_info }) |
| 90 | 90 | ||
| 91 | SignerIdentifier ::= CHOICE { | ||
| 92 | -- RFC5652 sec 5.3 | ||
| 93 | issuerAndSerialNumber IssuerAndSerialNumber, | ||
| 94 | subjectKeyIdentifier [0] IMPLICIT SubjectKeyIdentifier | ||
| 95 | } | ||
| 96 | |||
| 91 | IssuerAndSerialNumber ::= SEQUENCE { | 97 | IssuerAndSerialNumber ::= SEQUENCE { |
| 92 | issuer Name ({ pkcs7_sig_note_issuer }), | 98 | issuer Name ({ pkcs7_sig_note_issuer }), |
| 93 | serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial }) | 99 | serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial }) |
| @@ -95,6 +101,8 @@ IssuerAndSerialNumber ::= SEQUENCE { | |||
| 95 | 101 | ||
| 96 | CertificateSerialNumber ::= INTEGER | 102 | CertificateSerialNumber ::= INTEGER |
| 97 | 103 | ||
| 104 | SubjectKeyIdentifier ::= OCTET STRING ({ pkcs7_sig_note_skid }) | ||
| 105 | |||
| 98 | SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute | 106 | SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute |
| 99 | 107 | ||
| 100 | AuthenticatedAttribute ::= SEQUENCE { | 108 | AuthenticatedAttribute ::= SEQUENCE { |
| @@ -103,7 +111,7 @@ AuthenticatedAttribute ::= SEQUENCE { | |||
| 103 | } | 111 | } |
| 104 | 112 | ||
| 105 | UnauthenticatedAttribute ::= SEQUENCE { | 113 | UnauthenticatedAttribute ::= SEQUENCE { |
| 106 | type OBJECT IDENTIFIER ({ pkcs7_note_OID }), | 114 | type OBJECT IDENTIFIER, |
| 107 | values SET OF ANY | 115 | values SET OF ANY |
| 108 | } | 116 | } |
| 109 | 117 | ||
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c index 3d13b042da73..e2d0edbbc71a 100644 --- a/crypto/asymmetric_keys/pkcs7_key_type.c +++ b/crypto/asymmetric_keys/pkcs7_key_type.c | |||
| @@ -14,16 +14,26 @@ | |||
| 14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
| 15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | #include <linux/key-type.h> | 16 | #include <linux/key-type.h> |
| 17 | #include <keys/asymmetric-type.h> | ||
| 17 | #include <crypto/pkcs7.h> | 18 | #include <crypto/pkcs7.h> |
| 18 | #include <keys/user-type.h> | 19 | #include <keys/user-type.h> |
| 19 | #include <keys/system_keyring.h> | 20 | #include <keys/system_keyring.h> |
| 20 | #include "pkcs7_parser.h" | 21 | #include "pkcs7_parser.h" |
| 21 | 22 | ||
| 23 | MODULE_LICENSE("GPL"); | ||
| 24 | MODULE_DESCRIPTION("PKCS#7 testing key type"); | ||
| 25 | |||
| 26 | static unsigned pkcs7_usage; | ||
| 27 | module_param_named(usage, pkcs7_usage, uint, S_IWUSR | S_IRUGO); | ||
| 28 | MODULE_PARM_DESC(pkcs7_usage, | ||
| 29 | "Usage to specify when verifying the PKCS#7 message"); | ||
| 30 | |||
| 22 | /* | 31 | /* |
| 23 | * Preparse a PKCS#7 wrapped and validated data blob. | 32 | * Preparse a PKCS#7 wrapped and validated data blob. |
| 24 | */ | 33 | */ |
| 25 | static int pkcs7_preparse(struct key_preparsed_payload *prep) | 34 | static int pkcs7_preparse(struct key_preparsed_payload *prep) |
| 26 | { | 35 | { |
| 36 | enum key_being_used_for usage = pkcs7_usage; | ||
| 27 | struct pkcs7_message *pkcs7; | 37 | struct pkcs7_message *pkcs7; |
| 28 | const void *data, *saved_prep_data; | 38 | const void *data, *saved_prep_data; |
| 29 | size_t datalen, saved_prep_datalen; | 39 | size_t datalen, saved_prep_datalen; |
| @@ -32,6 +42,11 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep) | |||
| 32 | 42 | ||
| 33 | kenter(""); | 43 | kenter(""); |
| 34 | 44 | ||
| 45 | if (usage >= NR__KEY_BEING_USED_FOR) { | ||
| 46 | pr_err("Invalid usage type %d\n", usage); | ||
| 47 | return -EINVAL; | ||
| 48 | } | ||
| 49 | |||
| 35 | saved_prep_data = prep->data; | 50 | saved_prep_data = prep->data; |
| 36 | saved_prep_datalen = prep->datalen; | 51 | saved_prep_datalen = prep->datalen; |
| 37 | pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); | 52 | pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); |
| @@ -40,7 +55,7 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep) | |||
| 40 | goto error; | 55 | goto error; |
| 41 | } | 56 | } |
| 42 | 57 | ||
| 43 | ret = pkcs7_verify(pkcs7); | 58 | ret = pkcs7_verify(pkcs7, usage); |
| 44 | if (ret < 0) | 59 | if (ret < 0) |
| 45 | goto error_free; | 60 | goto error_free; |
| 46 | 61 | ||
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index 3bd5a1e4c493..758acabf2d81 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c | |||
| @@ -33,6 +33,9 @@ struct pkcs7_parse_context { | |||
| 33 | unsigned raw_serial_size; | 33 | unsigned raw_serial_size; |
| 34 | unsigned raw_issuer_size; | 34 | unsigned raw_issuer_size; |
| 35 | const void *raw_issuer; | 35 | const void *raw_issuer; |
| 36 | const void *raw_skid; | ||
| 37 | unsigned raw_skid_size; | ||
| 38 | bool expect_skid; | ||
| 36 | }; | 39 | }; |
| 37 | 40 | ||
| 38 | /* | 41 | /* |
| @@ -78,6 +81,30 @@ void pkcs7_free_message(struct pkcs7_message *pkcs7) | |||
| 78 | } | 81 | } |
| 79 | EXPORT_SYMBOL_GPL(pkcs7_free_message); | 82 | EXPORT_SYMBOL_GPL(pkcs7_free_message); |
| 80 | 83 | ||
| 84 | /* | ||
| 85 | * Check authenticatedAttributes are provided or not provided consistently. | ||
| 86 | */ | ||
| 87 | static int pkcs7_check_authattrs(struct pkcs7_message *msg) | ||
| 88 | { | ||
| 89 | struct pkcs7_signed_info *sinfo; | ||
| 90 | bool want; | ||
| 91 | |||
| 92 | sinfo = msg->signed_infos; | ||
| 93 | if (sinfo->authattrs) { | ||
| 94 | want = true; | ||
| 95 | msg->have_authattrs = true; | ||
| 96 | } | ||
| 97 | |||
| 98 | for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next) | ||
| 99 | if (!!sinfo->authattrs != want) | ||
| 100 | goto inconsistent; | ||
| 101 | return 0; | ||
| 102 | |||
| 103 | inconsistent: | ||
| 104 | pr_warn("Inconsistently supplied authAttrs\n"); | ||
| 105 | return -EINVAL; | ||
| 106 | } | ||
| 107 | |||
| 81 | /** | 108 | /** |
| 82 | * pkcs7_parse_message - Parse a PKCS#7 message | 109 | * pkcs7_parse_message - Parse a PKCS#7 message |
| 83 | * @data: The raw binary ASN.1 encoded message to be parsed | 110 | * @data: The raw binary ASN.1 encoded message to be parsed |
| @@ -110,6 +137,10 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen) | |||
| 110 | goto out; | 137 | goto out; |
| 111 | } | 138 | } |
| 112 | 139 | ||
| 140 | ret = pkcs7_check_authattrs(ctx->msg); | ||
| 141 | if (ret < 0) | ||
| 142 | goto out; | ||
| 143 | |||
| 113 | msg = ctx->msg; | 144 | msg = ctx->msg; |
| 114 | ctx->msg = NULL; | 145 | ctx->msg = NULL; |
| 115 | 146 | ||
| @@ -198,6 +229,14 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen, | |||
| 198 | case OID_sha256: | 229 | case OID_sha256: |
| 199 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256; | 230 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256; |
| 200 | break; | 231 | break; |
| 232 | case OID_sha384: | ||
| 233 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA384; | ||
| 234 | break; | ||
| 235 | case OID_sha512: | ||
| 236 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA512; | ||
| 237 | break; | ||
| 238 | case OID_sha224: | ||
| 239 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA224; | ||
| 201 | default: | 240 | default: |
| 202 | printk("Unsupported digest algo: %u\n", ctx->last_oid); | 241 | printk("Unsupported digest algo: %u\n", ctx->last_oid); |
| 203 | return -ENOPKG; | 242 | return -ENOPKG; |
| @@ -226,6 +265,100 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, | |||
| 226 | } | 265 | } |
| 227 | 266 | ||
| 228 | /* | 267 | /* |
| 268 | * We only support signed data [RFC2315 sec 9]. | ||
| 269 | */ | ||
| 270 | int pkcs7_check_content_type(void *context, size_t hdrlen, | ||
| 271 | unsigned char tag, | ||
| 272 | const void *value, size_t vlen) | ||
| 273 | { | ||
| 274 | struct pkcs7_parse_context *ctx = context; | ||
| 275 | |||
| 276 | if (ctx->last_oid != OID_signed_data) { | ||
| 277 | pr_warn("Only support pkcs7_signedData type\n"); | ||
| 278 | return -EINVAL; | ||
| 279 | } | ||
| 280 | |||
| 281 | return 0; | ||
| 282 | } | ||
| 283 | |||
| 284 | /* | ||
| 285 | * Note the SignedData version | ||
| 286 | */ | ||
| 287 | int pkcs7_note_signeddata_version(void *context, size_t hdrlen, | ||
| 288 | unsigned char tag, | ||
| 289 | const void *value, size_t vlen) | ||
| 290 | { | ||
| 291 | struct pkcs7_parse_context *ctx = context; | ||
| 292 | unsigned version; | ||
| 293 | |||
| 294 | if (vlen != 1) | ||
| 295 | goto unsupported; | ||
| 296 | |||
| 297 | ctx->msg->version = version = *(const u8 *)value; | ||
| 298 | switch (version) { | ||
| 299 | case 1: | ||
| 300 | /* PKCS#7 SignedData [RFC2315 sec 9.1] | ||
| 301 | * CMS ver 1 SignedData [RFC5652 sec 5.1] | ||
| 302 | */ | ||
| 303 | break; | ||
| 304 | case 3: | ||
| 305 | /* CMS ver 3 SignedData [RFC2315 sec 5.1] */ | ||
| 306 | break; | ||
| 307 | default: | ||
| 308 | goto unsupported; | ||
| 309 | } | ||
| 310 | |||
| 311 | return 0; | ||
| 312 | |||
| 313 | unsupported: | ||
| 314 | pr_warn("Unsupported SignedData version\n"); | ||
| 315 | return -EINVAL; | ||
| 316 | } | ||
| 317 | |||
| 318 | /* | ||
| 319 | * Note the SignerInfo version | ||
| 320 | */ | ||
| 321 | int pkcs7_note_signerinfo_version(void *context, size_t hdrlen, | ||
| 322 | unsigned char tag, | ||
| 323 | const void *value, size_t vlen) | ||
| 324 | { | ||
| 325 | struct pkcs7_parse_context *ctx = context; | ||
| 326 | unsigned version; | ||
| 327 | |||
| 328 | if (vlen != 1) | ||
| 329 | goto unsupported; | ||
| 330 | |||
| 331 | version = *(const u8 *)value; | ||
| 332 | switch (version) { | ||
| 333 | case 1: | ||
| 334 | /* PKCS#7 SignerInfo [RFC2315 sec 9.2] | ||
| 335 | * CMS ver 1 SignerInfo [RFC5652 sec 5.3] | ||
| 336 | */ | ||
| 337 | if (ctx->msg->version != 1) | ||
| 338 | goto version_mismatch; | ||
| 339 | ctx->expect_skid = false; | ||
| 340 | break; | ||
| 341 | case 3: | ||
| 342 | /* CMS ver 3 SignerInfo [RFC2315 sec 5.3] */ | ||
| 343 | if (ctx->msg->version == 1) | ||
| 344 | goto version_mismatch; | ||
| 345 | ctx->expect_skid = true; | ||
| 346 | break; | ||
| 347 | default: | ||
| 348 | goto unsupported; | ||
| 349 | } | ||
| 350 | |||
| 351 | return 0; | ||
| 352 | |||
| 353 | unsupported: | ||
| 354 | pr_warn("Unsupported SignerInfo version\n"); | ||
| 355 | return -EINVAL; | ||
| 356 | version_mismatch: | ||
| 357 | pr_warn("SignedData-SignerInfo version mismatch\n"); | ||
| 358 | return -EBADMSG; | ||
| 359 | } | ||
| 360 | |||
| 361 | /* | ||
| 229 | * Extract a certificate and store it in the context. | 362 | * Extract a certificate and store it in the context. |
| 230 | */ | 363 | */ |
| 231 | int pkcs7_extract_cert(void *context, size_t hdrlen, | 364 | int pkcs7_extract_cert(void *context, size_t hdrlen, |
| @@ -284,6 +417,25 @@ int pkcs7_note_certificate_list(void *context, size_t hdrlen, | |||
| 284 | } | 417 | } |
| 285 | 418 | ||
| 286 | /* | 419 | /* |
| 420 | * Note the content type. | ||
| 421 | */ | ||
| 422 | int pkcs7_note_content(void *context, size_t hdrlen, | ||
| 423 | unsigned char tag, | ||
| 424 | const void *value, size_t vlen) | ||
| 425 | { | ||
| 426 | struct pkcs7_parse_context *ctx = context; | ||
| 427 | |||
| 428 | if (ctx->last_oid != OID_data && | ||
| 429 | ctx->last_oid != OID_msIndirectData) { | ||
| 430 | pr_warn("Unsupported data type %d\n", ctx->last_oid); | ||
| 431 | return -EINVAL; | ||
| 432 | } | ||
| 433 | |||
| 434 | ctx->msg->data_type = ctx->last_oid; | ||
| 435 | return 0; | ||
| 436 | } | ||
| 437 | |||
| 438 | /* | ||
| 287 | * Extract the data from the message and store that and its content type OID in | 439 | * Extract the data from the message and store that and its content type OID in |
| 288 | * the context. | 440 | * the context. |
| 289 | */ | 441 | */ |
| @@ -298,45 +450,119 @@ int pkcs7_note_data(void *context, size_t hdrlen, | |||
| 298 | ctx->msg->data = value; | 450 | ctx->msg->data = value; |
| 299 | ctx->msg->data_len = vlen; | 451 | ctx->msg->data_len = vlen; |
| 300 | ctx->msg->data_hdrlen = hdrlen; | 452 | ctx->msg->data_hdrlen = hdrlen; |
| 301 | ctx->msg->data_type = ctx->last_oid; | ||
| 302 | return 0; | 453 | return 0; |
| 303 | } | 454 | } |
| 304 | 455 | ||
| 305 | /* | 456 | /* |
| 306 | * Parse authenticated attributes | 457 | * Parse authenticated attributes. |
| 307 | */ | 458 | */ |
| 308 | int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, | 459 | int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, |
| 309 | unsigned char tag, | 460 | unsigned char tag, |
| 310 | const void *value, size_t vlen) | 461 | const void *value, size_t vlen) |
| 311 | { | 462 | { |
| 312 | struct pkcs7_parse_context *ctx = context; | 463 | struct pkcs7_parse_context *ctx = context; |
| 464 | struct pkcs7_signed_info *sinfo = ctx->sinfo; | ||
| 465 | enum OID content_type; | ||
| 313 | 466 | ||
| 314 | pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); | 467 | pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); |
| 315 | 468 | ||
| 316 | switch (ctx->last_oid) { | 469 | switch (ctx->last_oid) { |
| 470 | case OID_contentType: | ||
| 471 | if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set)) | ||
| 472 | goto repeated; | ||
| 473 | content_type = look_up_OID(value, vlen); | ||
| 474 | if (content_type != ctx->msg->data_type) { | ||
| 475 | pr_warn("Mismatch between global data type (%d) and sinfo %u (%d)\n", | ||
| 476 | ctx->msg->data_type, sinfo->index, | ||
| 477 | content_type); | ||
| 478 | return -EBADMSG; | ||
| 479 | } | ||
| 480 | return 0; | ||
| 481 | |||
| 482 | case OID_signingTime: | ||
| 483 | if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set)) | ||
| 484 | goto repeated; | ||
| 485 | /* Should we check that the signing time is consistent | ||
| 486 | * with the signer's X.509 cert? | ||
| 487 | */ | ||
| 488 | return x509_decode_time(&sinfo->signing_time, | ||
| 489 | hdrlen, tag, value, vlen); | ||
| 490 | |||
| 317 | case OID_messageDigest: | 491 | case OID_messageDigest: |
| 492 | if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set)) | ||
| 493 | goto repeated; | ||
| 318 | if (tag != ASN1_OTS) | 494 | if (tag != ASN1_OTS) |
| 319 | return -EBADMSG; | 495 | return -EBADMSG; |
| 320 | ctx->sinfo->msgdigest = value; | 496 | sinfo->msgdigest = value; |
| 321 | ctx->sinfo->msgdigest_len = vlen; | 497 | sinfo->msgdigest_len = vlen; |
| 498 | return 0; | ||
| 499 | |||
| 500 | case OID_smimeCapabilites: | ||
| 501 | if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set)) | ||
| 502 | goto repeated; | ||
| 503 | if (ctx->msg->data_type != OID_msIndirectData) { | ||
| 504 | pr_warn("S/MIME Caps only allowed with Authenticode\n"); | ||
| 505 | return -EKEYREJECTED; | ||
| 506 | } | ||
| 507 | return 0; | ||
| 508 | |||
| 509 | /* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE | ||
| 510 | * char URLs and cont[1] 8-bit char URLs. | ||
| 511 | * | ||
| 512 | * Microsoft StatementType seems to contain a list of OIDs that | ||
| 513 | * are also used as extendedKeyUsage types in X.509 certs. | ||
| 514 | */ | ||
| 515 | case OID_msSpOpusInfo: | ||
| 516 | if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) | ||
| 517 | goto repeated; | ||
| 518 | goto authenticode_check; | ||
| 519 | case OID_msStatementType: | ||
| 520 | if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set)) | ||
| 521 | goto repeated; | ||
| 522 | authenticode_check: | ||
| 523 | if (ctx->msg->data_type != OID_msIndirectData) { | ||
| 524 | pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n"); | ||
| 525 | return -EKEYREJECTED; | ||
| 526 | } | ||
| 527 | /* I'm not sure how to validate these */ | ||
| 322 | return 0; | 528 | return 0; |
| 323 | default: | 529 | default: |
| 324 | return 0; | 530 | return 0; |
| 325 | } | 531 | } |
| 532 | |||
| 533 | repeated: | ||
| 534 | /* We permit max one item per AuthenticatedAttribute and no repeats */ | ||
| 535 | pr_warn("Repeated/multivalue AuthAttrs not permitted\n"); | ||
| 536 | return -EKEYREJECTED; | ||
| 326 | } | 537 | } |
| 327 | 538 | ||
| 328 | /* | 539 | /* |
| 329 | * Note the set of auth attributes for digestion purposes [RFC2315 9.3] | 540 | * Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3] |
| 330 | */ | 541 | */ |
| 331 | int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, | 542 | int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, |
| 332 | unsigned char tag, | 543 | unsigned char tag, |
| 333 | const void *value, size_t vlen) | 544 | const void *value, size_t vlen) |
| 334 | { | 545 | { |
| 335 | struct pkcs7_parse_context *ctx = context; | 546 | struct pkcs7_parse_context *ctx = context; |
| 547 | struct pkcs7_signed_info *sinfo = ctx->sinfo; | ||
| 548 | |||
| 549 | if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) || | ||
| 550 | !test_bit(sinfo_has_message_digest, &sinfo->aa_set) || | ||
| 551 | (ctx->msg->data_type == OID_msIndirectData && | ||
| 552 | !test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))) { | ||
| 553 | pr_warn("Missing required AuthAttr\n"); | ||
| 554 | return -EBADMSG; | ||
| 555 | } | ||
| 556 | |||
| 557 | if (ctx->msg->data_type != OID_msIndirectData && | ||
| 558 | test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) { | ||
| 559 | pr_warn("Unexpected Authenticode AuthAttr\n"); | ||
| 560 | return -EBADMSG; | ||
| 561 | } | ||
| 336 | 562 | ||
| 337 | /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ | 563 | /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ |
| 338 | ctx->sinfo->authattrs = value - (hdrlen - 1); | 564 | sinfo->authattrs = value - (hdrlen - 1); |
| 339 | ctx->sinfo->authattrs_len = vlen + (hdrlen - 1); | 565 | sinfo->authattrs_len = vlen + (hdrlen - 1); |
| 340 | return 0; | 566 | return 0; |
| 341 | } | 567 | } |
| 342 | 568 | ||
| @@ -367,6 +593,22 @@ int pkcs7_sig_note_issuer(void *context, size_t hdrlen, | |||
| 367 | } | 593 | } |
| 368 | 594 | ||
| 369 | /* | 595 | /* |
| 596 | * Note the issuing cert's subjectKeyIdentifier | ||
| 597 | */ | ||
| 598 | int pkcs7_sig_note_skid(void *context, size_t hdrlen, | ||
| 599 | unsigned char tag, | ||
| 600 | const void *value, size_t vlen) | ||
| 601 | { | ||
| 602 | struct pkcs7_parse_context *ctx = context; | ||
| 603 | |||
| 604 | pr_devel("SKID: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); | ||
| 605 | |||
| 606 | ctx->raw_skid = value; | ||
| 607 | ctx->raw_skid_size = vlen; | ||
| 608 | return 0; | ||
| 609 | } | ||
| 610 | |||
| 611 | /* | ||
| 370 | * Note the signature data | 612 | * Note the signature data |
| 371 | */ | 613 | */ |
| 372 | int pkcs7_sig_note_signature(void *context, size_t hdrlen, | 614 | int pkcs7_sig_note_signature(void *context, size_t hdrlen, |
| @@ -398,14 +640,27 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen, | |||
| 398 | struct pkcs7_signed_info *sinfo = ctx->sinfo; | 640 | struct pkcs7_signed_info *sinfo = ctx->sinfo; |
| 399 | struct asymmetric_key_id *kid; | 641 | struct asymmetric_key_id *kid; |
| 400 | 642 | ||
| 643 | if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs) { | ||
| 644 | pr_warn("Authenticode requires AuthAttrs\n"); | ||
| 645 | return -EBADMSG; | ||
| 646 | } | ||
| 647 | |||
| 401 | /* Generate cert issuer + serial number key ID */ | 648 | /* Generate cert issuer + serial number key ID */ |
| 402 | kid = asymmetric_key_generate_id(ctx->raw_serial, | 649 | if (!ctx->expect_skid) { |
| 403 | ctx->raw_serial_size, | 650 | kid = asymmetric_key_generate_id(ctx->raw_serial, |
| 404 | ctx->raw_issuer, | 651 | ctx->raw_serial_size, |
| 405 | ctx->raw_issuer_size); | 652 | ctx->raw_issuer, |
| 653 | ctx->raw_issuer_size); | ||
| 654 | } else { | ||
| 655 | kid = asymmetric_key_generate_id(ctx->raw_skid, | ||
| 656 | ctx->raw_skid_size, | ||
| 657 | "", 0); | ||
| 658 | } | ||
| 406 | if (IS_ERR(kid)) | 659 | if (IS_ERR(kid)) |
| 407 | return PTR_ERR(kid); | 660 | return PTR_ERR(kid); |
| 408 | 661 | ||
| 662 | pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data); | ||
| 663 | |||
| 409 | sinfo->signing_cert_id = kid; | 664 | sinfo->signing_cert_id = kid; |
| 410 | sinfo->index = ++ctx->sinfo_index; | 665 | sinfo->index = ++ctx->sinfo_index; |
| 411 | *ctx->ppsinfo = sinfo; | 666 | *ctx->ppsinfo = sinfo; |
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h index efc7dc9b8f9c..a66b19ebcf47 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.h +++ b/crypto/asymmetric_keys/pkcs7_parser.h | |||
| @@ -21,9 +21,9 @@ | |||
| 21 | struct pkcs7_signed_info { | 21 | 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; | 25 | bool trusted; |
| 26 | bool unsupported_crypto; /* T if not usable due to missing crypto */ | 26 | bool unsupported_crypto; /* T if not usable due to missing crypto */ |
| 27 | 27 | ||
| 28 | /* Message digest - the digest of the Content Data (or NULL) */ | 28 | /* Message digest - the digest of the Content Data (or NULL) */ |
| 29 | const void *msgdigest; | 29 | const void *msgdigest; |
| @@ -32,8 +32,18 @@ struct pkcs7_signed_info { | |||
| 32 | /* Authenticated Attribute data (or NULL) */ | 32 | /* Authenticated Attribute data (or NULL) */ |
| 33 | unsigned authattrs_len; | 33 | unsigned authattrs_len; |
| 34 | const void *authattrs; | 34 | const void *authattrs; |
| 35 | unsigned long aa_set; | ||
| 36 | #define sinfo_has_content_type 0 | ||
| 37 | #define sinfo_has_signing_time 1 | ||
| 38 | #define sinfo_has_message_digest 2 | ||
| 39 | #define sinfo_has_smime_caps 3 | ||
| 40 | #define sinfo_has_ms_opus_info 4 | ||
| 41 | #define sinfo_has_ms_statement_type 5 | ||
| 42 | time64_t signing_time; | ||
| 35 | 43 | ||
| 36 | /* Issuing cert serial number and issuer's name */ | 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 | */ | ||
| 37 | struct asymmetric_key_id *signing_cert_id; | 47 | struct asymmetric_key_id *signing_cert_id; |
| 38 | 48 | ||
| 39 | /* Message signature. | 49 | /* Message signature. |
| @@ -50,6 +60,8 @@ struct pkcs7_message { | |||
| 50 | struct x509_certificate *certs; /* Certificate list */ | 60 | struct x509_certificate *certs; /* Certificate list */ |
| 51 | struct x509_certificate *crl; /* Revocation list */ | 61 | struct x509_certificate *crl; /* Revocation list */ |
| 52 | struct pkcs7_signed_info *signed_infos; | 62 | struct pkcs7_signed_info *signed_infos; |
| 63 | u8 version; /* Version of cert (1 -> PKCS#7 or CMS; 3 -> CMS) */ | ||
| 64 | bool have_authattrs; /* T if have authattrs */ | ||
| 53 | 65 | ||
| 54 | /* Content Data (or NULL) */ | 66 | /* Content Data (or NULL) */ |
| 55 | enum OID data_type; /* Type of Data */ | 67 | enum OID data_type; /* Type of Data */ |
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c index 1d29376072da..90d6d47965b0 100644 --- a/crypto/asymmetric_keys/pkcs7_trust.c +++ b/crypto/asymmetric_keys/pkcs7_trust.c | |||
| @@ -54,7 +54,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 54 | /* Look to see if this certificate is present in the trusted | 54 | /* Look to see if this certificate is present in the trusted |
| 55 | * keys. | 55 | * keys. |
| 56 | */ | 56 | */ |
| 57 | key = x509_request_asymmetric_key(trust_keyring, x509->id, | 57 | key = x509_request_asymmetric_key(trust_keyring, |
| 58 | x509->id, x509->skid, | ||
| 58 | false); | 59 | false); |
| 59 | if (!IS_ERR(key)) { | 60 | if (!IS_ERR(key)) { |
| 60 | /* One of the X.509 certificates in the PKCS#7 message | 61 | /* One of the X.509 certificates in the PKCS#7 message |
| @@ -85,8 +86,10 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 85 | /* No match - see if the root certificate has a signer amongst the | 86 | /* No match - see if the root certificate has a signer amongst the |
| 86 | * trusted keys. | 87 | * trusted keys. |
| 87 | */ | 88 | */ |
| 88 | if (last && last->authority) { | 89 | if (last && (last->akid_id || last->akid_skid)) { |
| 89 | key = x509_request_asymmetric_key(trust_keyring, last->authority, | 90 | key = x509_request_asymmetric_key(trust_keyring, |
| 91 | last->akid_id, | ||
| 92 | last->akid_skid, | ||
| 90 | false); | 93 | false); |
| 91 | if (!IS_ERR(key)) { | 94 | if (!IS_ERR(key)) { |
| 92 | x509 = last; | 95 | x509 = last; |
| @@ -103,6 +106,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 103 | */ | 106 | */ |
| 104 | key = x509_request_asymmetric_key(trust_keyring, | 107 | key = x509_request_asymmetric_key(trust_keyring, |
| 105 | sinfo->signing_cert_id, | 108 | sinfo->signing_cert_id, |
| 109 | NULL, | ||
| 106 | false); | 110 | false); |
| 107 | if (!IS_ERR(key)) { | 111 | if (!IS_ERR(key)) { |
| 108 | pr_devel("sinfo %u: Direct signer is key %x\n", | 112 | pr_devel("sinfo %u: Direct signer is key %x\n", |
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index cd455450b069..d20c0b4b880e 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c | |||
| @@ -70,9 +70,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, | |||
| 70 | * message digest attribute amongst them which corresponds to the | 70 | * message digest attribute amongst them which corresponds to the |
| 71 | * digest we just calculated. | 71 | * digest we just calculated. |
| 72 | */ | 72 | */ |
| 73 | if (sinfo->msgdigest) { | 73 | if (sinfo->authattrs) { |
| 74 | u8 tag; | 74 | u8 tag; |
| 75 | 75 | ||
| 76 | if (!sinfo->msgdigest) { | ||
| 77 | pr_warn("Sig %u: No messageDigest\n", sinfo->index); | ||
| 78 | ret = -EKEYREJECTED; | ||
| 79 | goto error; | ||
| 80 | } | ||
| 81 | |||
| 76 | if (sinfo->msgdigest_len != sinfo->sig.digest_size) { | 82 | if (sinfo->msgdigest_len != sinfo->sig.digest_size) { |
| 77 | pr_debug("Sig %u: Invalid digest size (%u)\n", | 83 | pr_debug("Sig %u: Invalid digest size (%u)\n", |
| 78 | sinfo->index, sinfo->msgdigest_len); | 84 | sinfo->index, sinfo->msgdigest_len); |
| @@ -170,6 +176,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 170 | struct pkcs7_signed_info *sinfo) | 176 | struct pkcs7_signed_info *sinfo) |
| 171 | { | 177 | { |
| 172 | struct x509_certificate *x509 = sinfo->signer, *p; | 178 | struct x509_certificate *x509 = sinfo->signer, *p; |
| 179 | struct asymmetric_key_id *auth; | ||
| 173 | int ret; | 180 | int ret; |
| 174 | 181 | ||
| 175 | kenter(""); | 182 | kenter(""); |
| @@ -187,11 +194,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 187 | goto maybe_missing_crypto_in_x509; | 194 | goto maybe_missing_crypto_in_x509; |
| 188 | 195 | ||
| 189 | pr_debug("- issuer %s\n", x509->issuer); | 196 | pr_debug("- issuer %s\n", x509->issuer); |
| 190 | if (x509->authority) | 197 | if (x509->akid_id) |
| 191 | pr_debug("- authkeyid %*phN\n", | 198 | pr_debug("- authkeyid.id %*phN\n", |
| 192 | x509->authority->len, x509->authority->data); | 199 | x509->akid_id->len, x509->akid_id->data); |
| 193 | 200 | if (x509->akid_skid) | |
| 194 | if (!x509->authority || | 201 | pr_debug("- authkeyid.skid %*phN\n", |
| 202 | x509->akid_skid->len, x509->akid_skid->data); | ||
| 203 | |||
| 204 | if ((!x509->akid_id && !x509->akid_skid) || | ||
| 195 | strcmp(x509->subject, x509->issuer) == 0) { | 205 | strcmp(x509->subject, x509->issuer) == 0) { |
| 196 | /* If there's no authority certificate specified, then | 206 | /* If there's no authority certificate specified, then |
| 197 | * the certificate must be self-signed and is the root | 207 | * the certificate must be self-signed and is the root |
| @@ -215,21 +225,42 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 215 | /* Look through the X.509 certificates in the PKCS#7 message's | 225 | /* Look through the X.509 certificates in the PKCS#7 message's |
| 216 | * list to see if the next one is there. | 226 | * list to see if the next one is there. |
| 217 | */ | 227 | */ |
| 218 | pr_debug("- want %*phN\n", | 228 | auth = x509->akid_id; |
| 219 | x509->authority->len, x509->authority->data); | 229 | if (auth) { |
| 220 | for (p = pkcs7->certs; p; p = p->next) { | 230 | pr_debug("- want %*phN\n", auth->len, auth->data); |
| 221 | if (!p->skid) | 231 | for (p = pkcs7->certs; p; p = p->next) { |
| 222 | continue; | 232 | pr_debug("- cmp [%u] %*phN\n", |
| 223 | pr_debug("- cmp [%u] %*phN\n", | 233 | p->index, p->id->len, p->id->data); |
| 224 | p->index, p->skid->len, p->skid->data); | 234 | if (asymmetric_key_id_same(p->id, auth)) |
| 225 | if (asymmetric_key_id_same(p->skid, x509->authority)) | 235 | goto found_issuer_check_skid; |
| 226 | goto found_issuer; | 236 | } |
| 237 | } else { | ||
| 238 | auth = x509->akid_skid; | ||
| 239 | pr_debug("- want %*phN\n", auth->len, auth->data); | ||
| 240 | for (p = pkcs7->certs; p; p = p->next) { | ||
| 241 | if (!p->skid) | ||
| 242 | continue; | ||
| 243 | pr_debug("- cmp [%u] %*phN\n", | ||
| 244 | p->index, p->skid->len, p->skid->data); | ||
| 245 | if (asymmetric_key_id_same(p->skid, auth)) | ||
| 246 | goto found_issuer; | ||
| 247 | } | ||
| 227 | } | 248 | } |
| 228 | 249 | ||
| 229 | /* We didn't find the root of this chain */ | 250 | /* We didn't find the root of this chain */ |
| 230 | pr_debug("- top\n"); | 251 | pr_debug("- top\n"); |
| 231 | return 0; | 252 | return 0; |
| 232 | 253 | ||
| 254 | found_issuer_check_skid: | ||
| 255 | /* We matched issuer + serialNumber, but if there's an | ||
| 256 | * authKeyId.keyId, that must match the CA subjKeyId also. | ||
| 257 | */ | ||
| 258 | if (x509->akid_skid && | ||
| 259 | !asymmetric_key_id_same(p->skid, x509->akid_skid)) { | ||
| 260 | pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n", | ||
| 261 | sinfo->index, x509->index, p->index); | ||
| 262 | return -EKEYREJECTED; | ||
| 263 | } | ||
| 233 | found_issuer: | 264 | found_issuer: |
| 234 | pr_debug("- subject %s\n", p->subject); | 265 | pr_debug("- subject %s\n", p->subject); |
| 235 | if (p->seen) { | 266 | if (p->seen) { |
| @@ -289,6 +320,18 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
| 289 | pr_devel("Using X.509[%u] for sig %u\n", | 320 | pr_devel("Using X.509[%u] for sig %u\n", |
| 290 | sinfo->signer->index, sinfo->index); | 321 | sinfo->signer->index, sinfo->index); |
| 291 | 322 | ||
| 323 | /* Check that the PKCS#7 signing time is valid according to the X.509 | ||
| 324 | * certificate. We can't, however, check against the system clock | ||
| 325 | * since that may not have been set yet and may be wrong. | ||
| 326 | */ | ||
| 327 | if (test_bit(sinfo_has_signing_time, &sinfo->aa_set)) { | ||
| 328 | if (sinfo->signing_time < sinfo->signer->valid_from || | ||
| 329 | sinfo->signing_time > sinfo->signer->valid_to) { | ||
| 330 | pr_warn("Message signed outside of X.509 validity window\n"); | ||
| 331 | return -EKEYREJECTED; | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 292 | /* Verify the PKCS#7 binary against the key */ | 335 | /* Verify the PKCS#7 binary against the key */ |
| 293 | ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); | 336 | ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); |
| 294 | if (ret < 0) | 337 | if (ret < 0) |
| @@ -303,6 +346,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
| 303 | /** | 346 | /** |
| 304 | * pkcs7_verify - Verify a PKCS#7 message | 347 | * pkcs7_verify - Verify a PKCS#7 message |
| 305 | * @pkcs7: The PKCS#7 message to be verified | 348 | * @pkcs7: The PKCS#7 message to be verified |
| 349 | * @usage: The use to which the key is being put | ||
| 306 | * | 350 | * |
| 307 | * Verify a PKCS#7 message is internally consistent - that is, the data digest | 351 | * Verify a PKCS#7 message is internally consistent - that is, the data digest |
| 308 | * matches the digest in the AuthAttrs and any signature in the message or one | 352 | * matches the digest in the AuthAttrs and any signature in the message or one |
| @@ -314,6 +358,9 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
| 314 | * | 358 | * |
| 315 | * Returns, in order of descending priority: | 359 | * Returns, in order of descending priority: |
| 316 | * | 360 | * |
| 361 | * (*) -EKEYREJECTED if a key was selected that had a usage restriction at | ||
| 362 | * odds with the specified usage, or: | ||
| 363 | * | ||
| 317 | * (*) -EKEYREJECTED if a signature failed to match for which we found an | 364 | * (*) -EKEYREJECTED if a signature failed to match for which we found an |
| 318 | * appropriate X.509 certificate, or: | 365 | * appropriate X.509 certificate, or: |
| 319 | * | 366 | * |
| @@ -325,7 +372,8 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
| 325 | * (*) 0 if all the signature chains that don't incur -ENOPKG can be verified | 372 | * (*) 0 if all the signature chains that don't incur -ENOPKG can be verified |
| 326 | * (note that a signature chain may be of zero length), or: | 373 | * (note that a signature chain may be of zero length), or: |
| 327 | */ | 374 | */ |
| 328 | int pkcs7_verify(struct pkcs7_message *pkcs7) | 375 | int pkcs7_verify(struct pkcs7_message *pkcs7, |
| 376 | enum key_being_used_for usage) | ||
| 329 | { | 377 | { |
| 330 | struct pkcs7_signed_info *sinfo; | 378 | struct pkcs7_signed_info *sinfo; |
| 331 | struct x509_certificate *x509; | 379 | struct x509_certificate *x509; |
| @@ -334,12 +382,48 @@ int pkcs7_verify(struct pkcs7_message *pkcs7) | |||
| 334 | 382 | ||
| 335 | kenter(""); | 383 | kenter(""); |
| 336 | 384 | ||
| 385 | switch (usage) { | ||
| 386 | case VERIFYING_MODULE_SIGNATURE: | ||
| 387 | if (pkcs7->data_type != OID_data) { | ||
| 388 | pr_warn("Invalid module sig (not pkcs7-data)\n"); | ||
| 389 | return -EKEYREJECTED; | ||
| 390 | } | ||
| 391 | if (pkcs7->have_authattrs) { | ||
| 392 | pr_warn("Invalid module sig (has authattrs)\n"); | ||
| 393 | return -EKEYREJECTED; | ||
| 394 | } | ||
| 395 | break; | ||
| 396 | case VERIFYING_FIRMWARE_SIGNATURE: | ||
| 397 | if (pkcs7->data_type != OID_data) { | ||
| 398 | pr_warn("Invalid firmware sig (not pkcs7-data)\n"); | ||
| 399 | return -EKEYREJECTED; | ||
| 400 | } | ||
| 401 | if (!pkcs7->have_authattrs) { | ||
| 402 | pr_warn("Invalid firmware sig (missing authattrs)\n"); | ||
| 403 | return -EKEYREJECTED; | ||
| 404 | } | ||
| 405 | break; | ||
| 406 | case VERIFYING_KEXEC_PE_SIGNATURE: | ||
| 407 | if (pkcs7->data_type != OID_msIndirectData) { | ||
| 408 | pr_warn("Invalid kexec sig (not Authenticode)\n"); | ||
| 409 | return -EKEYREJECTED; | ||
| 410 | } | ||
| 411 | /* Authattr presence checked in parser */ | ||
| 412 | break; | ||
| 413 | case VERIFYING_UNSPECIFIED_SIGNATURE: | ||
| 414 | if (pkcs7->data_type != OID_data) { | ||
| 415 | pr_warn("Invalid unspecified sig (not pkcs7-data)\n"); | ||
| 416 | return -EKEYREJECTED; | ||
| 417 | } | ||
| 418 | break; | ||
| 419 | default: | ||
| 420 | return -EINVAL; | ||
| 421 | } | ||
| 422 | |||
| 337 | for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { | 423 | for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { |
| 338 | ret = x509_get_sig_params(x509); | 424 | ret = x509_get_sig_params(x509); |
| 339 | if (ret < 0) | 425 | if (ret < 0) |
| 340 | return ret; | 426 | return ret; |
| 341 | pr_debug("X.509[%u] %*phN\n", | ||
| 342 | n, x509->authority->len, x509->authority->data); | ||
| 343 | } | 427 | } |
| 344 | 428 | ||
| 345 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | 429 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { |
| @@ -359,3 +443,28 @@ int pkcs7_verify(struct pkcs7_message *pkcs7) | |||
| 359 | return enopkg; | 443 | return enopkg; |
| 360 | } | 444 | } |
| 361 | EXPORT_SYMBOL_GPL(pkcs7_verify); | 445 | EXPORT_SYMBOL_GPL(pkcs7_verify); |
| 446 | |||
| 447 | /** | ||
| 448 | * pkcs7_supply_detached_data - Supply the data needed to verify a PKCS#7 message | ||
| 449 | * @pkcs7: The PKCS#7 message | ||
| 450 | * @data: The data to be verified | ||
| 451 | * @datalen: The amount of data | ||
| 452 | * | ||
| 453 | * Supply the detached data needed to verify a PKCS#7 message. Note that no | ||
| 454 | * attempt to retain/pin the data is made. That is left to the caller. The | ||
| 455 | * data will not be modified by pkcs7_verify() and will not be freed when the | ||
| 456 | * PKCS#7 message is freed. | ||
| 457 | * | ||
| 458 | * Returns -EINVAL if data is already supplied in the message, 0 otherwise. | ||
| 459 | */ | ||
| 460 | int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7, | ||
| 461 | const void *data, size_t datalen) | ||
| 462 | { | ||
| 463 | if (pkcs7->data) { | ||
| 464 | pr_debug("Data already supplied\n"); | ||
| 465 | return -EINVAL; | ||
| 466 | } | ||
| 467 | pkcs7->data = data; | ||
| 468 | pkcs7->data_len = datalen; | ||
| 469 | return 0; | ||
| 470 | } | ||
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index 2f6e4fb1a1ea..81efccbe22d5 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c | |||
| @@ -39,6 +39,7 @@ EXPORT_SYMBOL_GPL(pkey_algo); | |||
| 39 | const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = { | 39 | const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = { |
| 40 | [PKEY_ID_PGP] = "PGP", | 40 | [PKEY_ID_PGP] = "PGP", |
| 41 | [PKEY_ID_X509] = "X509", | 41 | [PKEY_ID_X509] = "X509", |
| 42 | [PKEY_ID_PKCS7] = "PKCS#7", | ||
| 42 | }; | 43 | }; |
| 43 | EXPORT_SYMBOL_GPL(pkey_id_type_name); | 44 | EXPORT_SYMBOL_GPL(pkey_id_type_name); |
| 44 | 45 | ||
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c index 2421f46184ce..897b734dabf9 100644 --- a/crypto/asymmetric_keys/verify_pefile.c +++ b/crypto/asymmetric_keys/verify_pefile.c | |||
| @@ -393,6 +393,7 @@ error_no_desc: | |||
| 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_keyring: Signing certificates to use as starting points |
| 396 | * @usage: The use to which the key is being put. | ||
| 396 | * @_trusted: Set to true if trustworth, false otherwise | 397 | * @_trusted: Set to true if trustworth, false otherwise |
| 397 | * | 398 | * |
| 398 | * Validate that the certificate chain inside the PKCS#7 message inside the PE | 399 | * Validate that the certificate chain inside the PKCS#7 message inside the PE |
| @@ -417,7 +418,9 @@ error_no_desc: | |||
| 417 | * May also return -ENOMEM. | 418 | * May also return -ENOMEM. |
| 418 | */ | 419 | */ |
| 419 | int verify_pefile_signature(const void *pebuf, unsigned pelen, | 420 | int verify_pefile_signature(const void *pebuf, unsigned pelen, |
| 420 | struct key *trusted_keyring, bool *_trusted) | 421 | struct key *trusted_keyring, |
| 422 | enum key_being_used_for usage, | ||
| 423 | bool *_trusted) | ||
| 421 | { | 424 | { |
| 422 | struct pkcs7_message *pkcs7; | 425 | struct pkcs7_message *pkcs7; |
| 423 | struct pefile_context ctx; | 426 | struct pefile_context ctx; |
| @@ -462,7 +465,7 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen, | |||
| 462 | if (ret < 0) | 465 | if (ret < 0) |
| 463 | goto error; | 466 | goto error; |
| 464 | 467 | ||
| 465 | ret = pkcs7_verify(pkcs7); | 468 | ret = pkcs7_verify(pkcs7, usage); |
| 466 | if (ret < 0) | 469 | if (ret < 0) |
| 467 | goto error; | 470 | goto error; |
| 468 | 471 | ||
diff --git a/crypto/asymmetric_keys/x509_akid.asn1 b/crypto/asymmetric_keys/x509_akid.asn1 new file mode 100644 index 000000000000..1a33231a75a8 --- /dev/null +++ b/crypto/asymmetric_keys/x509_akid.asn1 | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | -- X.509 AuthorityKeyIdentifier | ||
| 2 | -- rfc5280 section 4.2.1.1 | ||
| 3 | |||
| 4 | AuthorityKeyIdentifier ::= SEQUENCE { | ||
| 5 | keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL, | ||
| 6 | authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL, | ||
| 7 | authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL | ||
| 8 | } | ||
| 9 | |||
| 10 | KeyIdentifier ::= OCTET STRING ({ x509_akid_note_kid }) | ||
| 11 | |||
| 12 | CertificateSerialNumber ::= INTEGER ({ x509_akid_note_serial }) | ||
| 13 | |||
| 14 | GeneralNames ::= SEQUENCE OF GeneralName | ||
| 15 | |||
| 16 | GeneralName ::= CHOICE { | ||
| 17 | otherName [0] ANY, | ||
| 18 | rfc822Name [1] IA5String, | ||
| 19 | dNSName [2] IA5String, | ||
| 20 | x400Address [3] ANY, | ||
| 21 | directoryName [4] Name ({ x509_akid_note_name }), | ||
| 22 | ediPartyName [5] ANY, | ||
| 23 | uniformResourceIdentifier [6] IA5String, | ||
| 24 | iPAddress [7] OCTET STRING, | ||
| 25 | registeredID [8] OBJECT IDENTIFIER | ||
| 26 | } | ||
| 27 | |||
| 28 | Name ::= SEQUENCE OF RelativeDistinguishedName | ||
| 29 | |||
| 30 | RelativeDistinguishedName ::= SET OF AttributeValueAssertion | ||
| 31 | |||
| 32 | AttributeValueAssertion ::= SEQUENCE { | ||
| 33 | attributeType OBJECT IDENTIFIER ({ x509_note_OID }), | ||
| 34 | attributeValue ANY ({ x509_extract_name_segment }) | ||
| 35 | } | ||
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index a668d90302d3..af71878dc15b 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include "public_key.h" | 18 | #include "public_key.h" |
| 19 | #include "x509_parser.h" | 19 | #include "x509_parser.h" |
| 20 | #include "x509-asn1.h" | 20 | #include "x509-asn1.h" |
| 21 | #include "x509_akid-asn1.h" | ||
| 21 | #include "x509_rsakey-asn1.h" | 22 | #include "x509_rsakey-asn1.h" |
| 22 | 23 | ||
| 23 | struct x509_parse_context { | 24 | struct x509_parse_context { |
| @@ -35,6 +36,10 @@ struct x509_parse_context { | |||
| 35 | u16 o_offset; /* Offset of organizationName (O) */ | 36 | u16 o_offset; /* Offset of organizationName (O) */ |
| 36 | u16 cn_offset; /* Offset of commonName (CN) */ | 37 | u16 cn_offset; /* Offset of commonName (CN) */ |
| 37 | u16 email_offset; /* Offset of emailAddress */ | 38 | u16 email_offset; /* Offset of emailAddress */ |
| 39 | unsigned raw_akid_size; | ||
| 40 | const void *raw_akid; /* Raw authorityKeyId in ASN.1 */ | ||
| 41 | const void *akid_raw_issuer; /* Raw directoryName in authorityKeyId */ | ||
| 42 | unsigned akid_raw_issuer_size; | ||
| 38 | }; | 43 | }; |
| 39 | 44 | ||
| 40 | /* | 45 | /* |
| @@ -48,7 +53,8 @@ void x509_free_certificate(struct x509_certificate *cert) | |||
| 48 | kfree(cert->subject); | 53 | kfree(cert->subject); |
| 49 | kfree(cert->id); | 54 | kfree(cert->id); |
| 50 | kfree(cert->skid); | 55 | kfree(cert->skid); |
| 51 | kfree(cert->authority); | 56 | kfree(cert->akid_id); |
| 57 | kfree(cert->akid_skid); | ||
| 52 | kfree(cert->sig.digest); | 58 | kfree(cert->sig.digest); |
| 53 | mpi_free(cert->sig.rsa.s); | 59 | mpi_free(cert->sig.rsa.s); |
| 54 | kfree(cert); | 60 | kfree(cert); |
| @@ -85,6 +91,18 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) | |||
| 85 | if (ret < 0) | 91 | if (ret < 0) |
| 86 | goto error_decode; | 92 | goto error_decode; |
| 87 | 93 | ||
| 94 | /* Decode the AuthorityKeyIdentifier */ | ||
| 95 | if (ctx->raw_akid) { | ||
| 96 | pr_devel("AKID: %u %*phN\n", | ||
| 97 | ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid); | ||
| 98 | ret = asn1_ber_decoder(&x509_akid_decoder, ctx, | ||
| 99 | ctx->raw_akid, ctx->raw_akid_size); | ||
| 100 | if (ret < 0) { | ||
| 101 | pr_warn("Couldn't decode AuthKeyIdentifier\n"); | ||
| 102 | goto error_decode; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 88 | /* Decode the public key */ | 106 | /* Decode the public key */ |
| 89 | ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, | 107 | ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, |
| 90 | ctx->key, ctx->key_size); | 108 | ctx->key, ctx->key_size); |
| @@ -422,7 +440,6 @@ int x509_process_extension(void *context, size_t hdrlen, | |||
| 422 | struct x509_parse_context *ctx = context; | 440 | struct x509_parse_context *ctx = context; |
| 423 | struct asymmetric_key_id *kid; | 441 | struct asymmetric_key_id *kid; |
| 424 | const unsigned char *v = value; | 442 | const unsigned char *v = value; |
| 425 | int i; | ||
| 426 | 443 | ||
| 427 | pr_debug("Extension: %u\n", ctx->last_oid); | 444 | pr_debug("Extension: %u\n", ctx->last_oid); |
| 428 | 445 | ||
| @@ -437,9 +454,7 @@ int x509_process_extension(void *context, size_t hdrlen, | |||
| 437 | 454 | ||
| 438 | ctx->cert->raw_skid_size = vlen; | 455 | ctx->cert->raw_skid_size = vlen; |
| 439 | ctx->cert->raw_skid = v; | 456 | ctx->cert->raw_skid = v; |
| 440 | kid = asymmetric_key_generate_id(ctx->cert->raw_subject, | 457 | kid = asymmetric_key_generate_id(v, vlen, "", 0); |
| 441 | ctx->cert->raw_subject_size, | ||
| 442 | v, vlen); | ||
| 443 | if (IS_ERR(kid)) | 458 | if (IS_ERR(kid)) |
| 444 | return PTR_ERR(kid); | 459 | return PTR_ERR(kid); |
| 445 | ctx->cert->skid = kid; | 460 | ctx->cert->skid = kid; |
| @@ -449,117 +464,113 @@ int x509_process_extension(void *context, size_t hdrlen, | |||
| 449 | 464 | ||
| 450 | if (ctx->last_oid == OID_authorityKeyIdentifier) { | 465 | if (ctx->last_oid == OID_authorityKeyIdentifier) { |
| 451 | /* Get hold of the CA key fingerprint */ | 466 | /* Get hold of the CA key fingerprint */ |
| 452 | if (ctx->cert->authority || vlen < 5) | 467 | ctx->raw_akid = v; |
| 453 | return -EBADMSG; | 468 | ctx->raw_akid_size = vlen; |
| 454 | |||
| 455 | /* Authority Key Identifier must be a Constructed SEQUENCE */ | ||
| 456 | if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5))) | ||
| 457 | return -EBADMSG; | ||
| 458 | |||
| 459 | /* Authority Key Identifier is not indefinite length */ | ||
| 460 | if (unlikely(vlen == ASN1_INDEFINITE_LENGTH)) | ||
| 461 | return -EBADMSG; | ||
| 462 | |||
| 463 | if (vlen < ASN1_INDEFINITE_LENGTH) { | ||
| 464 | /* Short Form length */ | ||
| 465 | if (v[1] != vlen - 2 || | ||
| 466 | v[2] != SEQ_TAG_KEYID || | ||
| 467 | v[3] > vlen - 4) | ||
| 468 | return -EBADMSG; | ||
| 469 | |||
| 470 | vlen = v[3]; | ||
| 471 | v += 4; | ||
| 472 | } else { | ||
| 473 | /* Long Form length */ | ||
| 474 | size_t seq_len = 0; | ||
| 475 | size_t sub = v[1] - ASN1_INDEFINITE_LENGTH; | ||
| 476 | |||
| 477 | if (sub > 2) | ||
| 478 | return -EBADMSG; | ||
| 479 | |||
| 480 | /* calculate the length from subsequent octets */ | ||
| 481 | v += 2; | ||
| 482 | for (i = 0; i < sub; i++) { | ||
| 483 | seq_len <<= 8; | ||
| 484 | seq_len |= v[i]; | ||
| 485 | } | ||
| 486 | |||
| 487 | if (seq_len != vlen - 2 - sub || | ||
| 488 | v[sub] != SEQ_TAG_KEYID || | ||
| 489 | v[sub + 1] > vlen - 4 - sub) | ||
| 490 | return -EBADMSG; | ||
| 491 | |||
| 492 | vlen = v[sub + 1]; | ||
| 493 | v += (sub + 2); | ||
| 494 | } | ||
| 495 | |||
| 496 | kid = asymmetric_key_generate_id(ctx->cert->raw_issuer, | ||
| 497 | ctx->cert->raw_issuer_size, | ||
| 498 | v, vlen); | ||
| 499 | if (IS_ERR(kid)) | ||
| 500 | return PTR_ERR(kid); | ||
| 501 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | ||
| 502 | ctx->cert->authority = kid; | ||
| 503 | return 0; | 469 | return 0; |
| 504 | } | 470 | } |
| 505 | 471 | ||
| 506 | return 0; | 472 | return 0; |
| 507 | } | 473 | } |
| 508 | 474 | ||
| 509 | /* | 475 | /** |
| 510 | * Record a certificate time. | 476 | * x509_decode_time - Decode an X.509 time ASN.1 object |
| 477 | * @_t: The time to fill in | ||
| 478 | * @hdrlen: The length of the object header | ||
| 479 | * @tag: The object tag | ||
| 480 | * @value: The object value | ||
| 481 | * @vlen: The size of the object value | ||
| 482 | * | ||
| 483 | * Decode an ASN.1 universal time or generalised time field into a struct the | ||
| 484 | * kernel can handle and check it for validity. The time is decoded thus: | ||
| 485 | * | ||
| 486 | * [RFC5280 §4.1.2.5] | ||
| 487 | * CAs conforming to this profile MUST always encode certificate validity | ||
| 488 | * dates through the year 2049 as UTCTime; certificate validity dates in | ||
| 489 | * 2050 or later MUST be encoded as GeneralizedTime. Conforming | ||
| 490 | * applications MUST be able to process validity dates that are encoded in | ||
| 491 | * either UTCTime or GeneralizedTime. | ||
| 511 | */ | 492 | */ |
| 512 | static int x509_note_time(struct tm *tm, size_t hdrlen, | 493 | int x509_decode_time(time64_t *_t, size_t hdrlen, |
| 513 | unsigned char tag, | 494 | unsigned char tag, |
| 514 | const unsigned char *value, size_t vlen) | 495 | const unsigned char *value, size_t vlen) |
| 515 | { | 496 | { |
| 497 | static const unsigned char month_lengths[] = { 31, 29, 31, 30, 31, 30, | ||
| 498 | 31, 31, 30, 31, 30, 31 }; | ||
| 516 | const unsigned char *p = value; | 499 | const unsigned char *p = value; |
| 500 | unsigned year, mon, day, hour, min, sec, mon_len; | ||
| 517 | 501 | ||
| 518 | #define dec2bin(X) ((X) - '0') | 502 | #define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; }) |
| 519 | #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) | 503 | #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) |
| 520 | 504 | ||
| 521 | if (tag == ASN1_UNITIM) { | 505 | if (tag == ASN1_UNITIM) { |
| 522 | /* UTCTime: YYMMDDHHMMSSZ */ | 506 | /* UTCTime: YYMMDDHHMMSSZ */ |
| 523 | if (vlen != 13) | 507 | if (vlen != 13) |
| 524 | goto unsupported_time; | 508 | goto unsupported_time; |
| 525 | tm->tm_year = DD2bin(p); | 509 | year = DD2bin(p); |
| 526 | if (tm->tm_year >= 50) | 510 | if (year >= 50) |
| 527 | tm->tm_year += 1900; | 511 | year += 1900; |
| 528 | else | 512 | else |
| 529 | tm->tm_year += 2000; | 513 | year += 2000; |
| 530 | } else if (tag == ASN1_GENTIM) { | 514 | } else if (tag == ASN1_GENTIM) { |
| 531 | /* GenTime: YYYYMMDDHHMMSSZ */ | 515 | /* GenTime: YYYYMMDDHHMMSSZ */ |
| 532 | if (vlen != 15) | 516 | if (vlen != 15) |
| 533 | goto unsupported_time; | 517 | goto unsupported_time; |
| 534 | tm->tm_year = DD2bin(p) * 100 + DD2bin(p); | 518 | year = DD2bin(p) * 100 + DD2bin(p); |
| 519 | if (year >= 1950 && year <= 2049) | ||
| 520 | goto invalid_time; | ||
| 535 | } else { | 521 | } else { |
| 536 | goto unsupported_time; | 522 | goto unsupported_time; |
| 537 | } | 523 | } |
| 538 | 524 | ||
| 539 | tm->tm_year -= 1900; | 525 | mon = DD2bin(p); |
| 540 | tm->tm_mon = DD2bin(p) - 1; | 526 | day = DD2bin(p); |
| 541 | tm->tm_mday = DD2bin(p); | 527 | hour = DD2bin(p); |
| 542 | tm->tm_hour = DD2bin(p); | 528 | min = DD2bin(p); |
| 543 | tm->tm_min = DD2bin(p); | 529 | sec = DD2bin(p); |
| 544 | tm->tm_sec = DD2bin(p); | ||
| 545 | 530 | ||
| 546 | if (*p != 'Z') | 531 | if (*p != 'Z') |
| 547 | goto unsupported_time; | 532 | goto unsupported_time; |
| 548 | 533 | ||
| 534 | mon_len = month_lengths[mon]; | ||
| 535 | if (mon == 2) { | ||
| 536 | if (year % 4 == 0) { | ||
| 537 | mon_len = 29; | ||
| 538 | if (year % 100 == 0) { | ||
| 539 | year /= 100; | ||
| 540 | if (year % 4 != 0) | ||
| 541 | mon_len = 28; | ||
| 542 | } | ||
| 543 | } | ||
| 544 | } | ||
| 545 | |||
| 546 | if (year < 1970 || | ||
| 547 | mon < 1 || mon > 12 || | ||
| 548 | day < 1 || day > mon_len || | ||
| 549 | hour < 0 || hour > 23 || | ||
| 550 | min < 0 || min > 59 || | ||
| 551 | sec < 0 || sec > 59) | ||
| 552 | goto invalid_time; | ||
| 553 | |||
| 554 | *_t = mktime64(year, mon, day, hour, min, sec); | ||
| 549 | return 0; | 555 | return 0; |
| 550 | 556 | ||
| 551 | unsupported_time: | 557 | unsupported_time: |
| 552 | pr_debug("Got unsupported time [tag %02x]: '%*.*s'\n", | 558 | pr_debug("Got unsupported time [tag %02x]: '%*phN'\n", |
| 553 | tag, (int)vlen, (int)vlen, value); | 559 | tag, (int)vlen, value); |
| 560 | return -EBADMSG; | ||
| 561 | invalid_time: | ||
| 562 | pr_debug("Got invalid time [tag %02x]: '%*phN'\n", | ||
| 563 | tag, (int)vlen, value); | ||
| 554 | return -EBADMSG; | 564 | return -EBADMSG; |
| 555 | } | 565 | } |
| 566 | EXPORT_SYMBOL_GPL(x509_decode_time); | ||
| 556 | 567 | ||
| 557 | int x509_note_not_before(void *context, size_t hdrlen, | 568 | int x509_note_not_before(void *context, size_t hdrlen, |
| 558 | unsigned char tag, | 569 | unsigned char tag, |
| 559 | const void *value, size_t vlen) | 570 | const void *value, size_t vlen) |
| 560 | { | 571 | { |
| 561 | struct x509_parse_context *ctx = context; | 572 | struct x509_parse_context *ctx = context; |
| 562 | return x509_note_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); | 573 | return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); |
| 563 | } | 574 | } |
| 564 | 575 | ||
| 565 | int x509_note_not_after(void *context, size_t hdrlen, | 576 | int x509_note_not_after(void *context, size_t hdrlen, |
| @@ -567,5 +578,71 @@ int x509_note_not_after(void *context, size_t hdrlen, | |||
| 567 | const void *value, size_t vlen) | 578 | const void *value, size_t vlen) |
| 568 | { | 579 | { |
| 569 | struct x509_parse_context *ctx = context; | 580 | struct x509_parse_context *ctx = context; |
| 570 | return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); | 581 | return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); |
| 582 | } | ||
| 583 | |||
| 584 | /* | ||
| 585 | * Note a key identifier-based AuthorityKeyIdentifier | ||
| 586 | */ | ||
| 587 | int x509_akid_note_kid(void *context, size_t hdrlen, | ||
| 588 | unsigned char tag, | ||
| 589 | const void *value, size_t vlen) | ||
| 590 | { | ||
| 591 | struct x509_parse_context *ctx = context; | ||
| 592 | struct asymmetric_key_id *kid; | ||
| 593 | |||
| 594 | pr_debug("AKID: keyid: %*phN\n", (int)vlen, value); | ||
| 595 | |||
| 596 | if (ctx->cert->akid_skid) | ||
| 597 | return 0; | ||
| 598 | |||
| 599 | kid = asymmetric_key_generate_id(value, vlen, "", 0); | ||
| 600 | if (IS_ERR(kid)) | ||
| 601 | return PTR_ERR(kid); | ||
| 602 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | ||
| 603 | ctx->cert->akid_skid = kid; | ||
| 604 | return 0; | ||
| 605 | } | ||
| 606 | |||
| 607 | /* | ||
| 608 | * Note a directoryName in an AuthorityKeyIdentifier | ||
| 609 | */ | ||
| 610 | int x509_akid_note_name(void *context, size_t hdrlen, | ||
| 611 | unsigned char tag, | ||
| 612 | const void *value, size_t vlen) | ||
| 613 | { | ||
| 614 | struct x509_parse_context *ctx = context; | ||
| 615 | |||
| 616 | pr_debug("AKID: name: %*phN\n", (int)vlen, value); | ||
| 617 | |||
| 618 | ctx->akid_raw_issuer = value; | ||
| 619 | ctx->akid_raw_issuer_size = vlen; | ||
| 620 | return 0; | ||
| 621 | } | ||
| 622 | |||
| 623 | /* | ||
| 624 | * Note a serial number in an AuthorityKeyIdentifier | ||
| 625 | */ | ||
| 626 | int x509_akid_note_serial(void *context, size_t hdrlen, | ||
| 627 | unsigned char tag, | ||
| 628 | const void *value, size_t vlen) | ||
| 629 | { | ||
| 630 | struct x509_parse_context *ctx = context; | ||
| 631 | struct asymmetric_key_id *kid; | ||
| 632 | |||
| 633 | pr_debug("AKID: serial: %*phN\n", (int)vlen, value); | ||
| 634 | |||
| 635 | if (!ctx->akid_raw_issuer || ctx->cert->akid_id) | ||
| 636 | return 0; | ||
| 637 | |||
| 638 | kid = asymmetric_key_generate_id(value, | ||
| 639 | vlen, | ||
| 640 | ctx->akid_raw_issuer, | ||
| 641 | ctx->akid_raw_issuer_size); | ||
| 642 | if (IS_ERR(kid)) | ||
| 643 | return PTR_ERR(kid); | ||
| 644 | |||
| 645 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | ||
| 646 | ctx->cert->akid_id = kid; | ||
| 647 | return 0; | ||
| 571 | } | 648 | } |
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h index 3dfe6b5d6f0b..1de01eaec884 100644 --- a/crypto/asymmetric_keys/x509_parser.h +++ b/crypto/asymmetric_keys/x509_parser.h | |||
| @@ -19,11 +19,12 @@ struct x509_certificate { | |||
| 19 | struct public_key_signature sig; /* Signature parameters */ | 19 | struct public_key_signature sig; /* Signature parameters */ |
| 20 | char *issuer; /* Name of certificate issuer */ | 20 | char *issuer; /* Name of certificate issuer */ |
| 21 | char *subject; /* Name of certificate subject */ | 21 | char *subject; /* Name of certificate subject */ |
| 22 | struct asymmetric_key_id *id; /* Serial number + issuer */ | 22 | struct asymmetric_key_id *id; /* Issuer + Serial number */ |
| 23 | struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ | 23 | struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ |
| 24 | struct asymmetric_key_id *authority; /* Authority key identifier (optional) */ | 24 | struct asymmetric_key_id *akid_id; /* CA AuthKeyId matching ->id (optional) */ |
| 25 | struct tm valid_from; | 25 | struct asymmetric_key_id *akid_skid; /* CA AuthKeyId matching ->skid (optional) */ |
| 26 | struct tm valid_to; | 26 | time64_t valid_from; |
| 27 | time64_t valid_to; | ||
| 27 | const void *tbs; /* Signed data */ | 28 | const void *tbs; /* Signed data */ |
| 28 | unsigned tbs_size; /* Size of signed data */ | 29 | unsigned tbs_size; /* Size of signed data */ |
| 29 | unsigned raw_sig_size; /* Size of sigature */ | 30 | unsigned raw_sig_size; /* Size of sigature */ |
| @@ -48,6 +49,9 @@ struct x509_certificate { | |||
| 48 | */ | 49 | */ |
| 49 | extern void x509_free_certificate(struct x509_certificate *cert); | 50 | extern void x509_free_certificate(struct x509_certificate *cert); |
| 50 | extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); | 51 | extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); |
| 52 | extern int x509_decode_time(time64_t *_t, size_t hdrlen, | ||
| 53 | unsigned char tag, | ||
| 54 | const unsigned char *value, size_t vlen); | ||
| 51 | 55 | ||
| 52 | /* | 56 | /* |
| 53 | * x509_public_key.c | 57 | * x509_public_key.c |
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 24f17e6c5904..6d88dd15c98d 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
| @@ -65,23 +65,37 @@ __setup("ca_keys=", ca_keys_setup); | |||
| 65 | /** | 65 | /** |
| 66 | * x509_request_asymmetric_key - Request a key by X.509 certificate params. | 66 | * x509_request_asymmetric_key - Request a key by X.509 certificate params. |
| 67 | * @keyring: The keys to search. | 67 | * @keyring: The keys to search. |
| 68 | * @kid: The key ID. | 68 | * @id: The issuer & serialNumber to look for or NULL. |
| 69 | * @skid: The subjectKeyIdentifier to look for or NULL. | ||
| 69 | * @partial: Use partial match if true, exact if false. | 70 | * @partial: Use partial match if true, exact if false. |
| 70 | * | 71 | * |
| 71 | * Find a key in the given keyring by subject name and key ID. These might, | 72 | * Find a key in the given keyring by identifier. The preferred identifier is |
| 72 | * for instance, be the issuer name and the authority key ID of an X.509 | 73 | * the issuer + serialNumber and the fallback identifier is the |
| 73 | * certificate that needs to be verified. | 74 | * subjectKeyIdentifier. If both are given, the lookup is by the former, but |
| 75 | * the latter must also match. | ||
| 74 | */ | 76 | */ |
| 75 | struct key *x509_request_asymmetric_key(struct key *keyring, | 77 | struct key *x509_request_asymmetric_key(struct key *keyring, |
| 76 | const struct asymmetric_key_id *kid, | 78 | const struct asymmetric_key_id *id, |
| 79 | const struct asymmetric_key_id *skid, | ||
| 77 | bool partial) | 80 | bool partial) |
| 78 | { | 81 | { |
| 79 | key_ref_t key; | 82 | struct key *key; |
| 80 | char *id, *p; | 83 | key_ref_t ref; |
| 81 | 84 | const char *lookup; | |
| 85 | char *req, *p; | ||
| 86 | int len; | ||
| 87 | |||
| 88 | if (id) { | ||
| 89 | lookup = id->data; | ||
| 90 | len = id->len; | ||
| 91 | } else { | ||
| 92 | lookup = skid->data; | ||
| 93 | len = skid->len; | ||
| 94 | } | ||
| 95 | |||
| 82 | /* Construct an identifier "id:<keyid>". */ | 96 | /* Construct an identifier "id:<keyid>". */ |
| 83 | p = id = kmalloc(2 + 1 + kid->len * 2 + 1, GFP_KERNEL); | 97 | p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL); |
| 84 | if (!id) | 98 | if (!req) |
| 85 | return ERR_PTR(-ENOMEM); | 99 | return ERR_PTR(-ENOMEM); |
| 86 | 100 | ||
| 87 | if (partial) { | 101 | if (partial) { |
| @@ -92,32 +106,48 @@ struct key *x509_request_asymmetric_key(struct key *keyring, | |||
| 92 | *p++ = 'x'; | 106 | *p++ = 'x'; |
| 93 | } | 107 | } |
| 94 | *p++ = ':'; | 108 | *p++ = ':'; |
| 95 | p = bin2hex(p, kid->data, kid->len); | 109 | p = bin2hex(p, lookup, len); |
| 96 | *p = 0; | 110 | *p = 0; |
| 97 | 111 | ||
| 98 | pr_debug("Look up: \"%s\"\n", id); | 112 | pr_debug("Look up: \"%s\"\n", req); |
| 99 | 113 | ||
| 100 | key = keyring_search(make_key_ref(keyring, 1), | 114 | ref = keyring_search(make_key_ref(keyring, 1), |
| 101 | &key_type_asymmetric, id); | 115 | &key_type_asymmetric, req); |
| 102 | if (IS_ERR(key)) | 116 | if (IS_ERR(ref)) |
| 103 | pr_debug("Request for key '%s' err %ld\n", id, PTR_ERR(key)); | 117 | pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref)); |
| 104 | kfree(id); | 118 | kfree(req); |
| 105 | 119 | ||
| 106 | if (IS_ERR(key)) { | 120 | if (IS_ERR(ref)) { |
| 107 | switch (PTR_ERR(key)) { | 121 | switch (PTR_ERR(ref)) { |
| 108 | /* Hide some search errors */ | 122 | /* Hide some search errors */ |
| 109 | case -EACCES: | 123 | case -EACCES: |
| 110 | case -ENOTDIR: | 124 | case -ENOTDIR: |
| 111 | case -EAGAIN: | 125 | case -EAGAIN: |
| 112 | return ERR_PTR(-ENOKEY); | 126 | return ERR_PTR(-ENOKEY); |
| 113 | default: | 127 | default: |
| 114 | return ERR_CAST(key); | 128 | return ERR_CAST(ref); |
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | key = key_ref_to_ptr(ref); | ||
| 133 | if (id && skid) { | ||
| 134 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); | ||
| 135 | if (!kids->id[1]) { | ||
| 136 | pr_debug("issuer+serial match, but expected SKID missing\n"); | ||
| 137 | goto reject; | ||
| 138 | } | ||
| 139 | if (!asymmetric_key_id_same(skid, kids->id[1])) { | ||
| 140 | pr_debug("issuer+serial match, but SKID does not\n"); | ||
| 141 | goto reject; | ||
| 115 | } | 142 | } |
| 116 | } | 143 | } |
| 144 | |||
| 145 | pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key)); | ||
| 146 | return key; | ||
| 117 | 147 | ||
| 118 | pr_devel("<==%s() = 0 [%x]\n", __func__, | 148 | reject: |
| 119 | key_serial(key_ref_to_ptr(key))); | 149 | key_put(key); |
| 120 | return key_ref_to_ptr(key); | 150 | return ERR_PTR(-EKEYREJECTED); |
| 121 | } | 151 | } |
| 122 | EXPORT_SYMBOL_GPL(x509_request_asymmetric_key); | 152 | EXPORT_SYMBOL_GPL(x509_request_asymmetric_key); |
| 123 | 153 | ||
| @@ -227,10 +257,11 @@ static int x509_validate_trust(struct x509_certificate *cert, | |||
| 227 | if (!trust_keyring) | 257 | if (!trust_keyring) |
| 228 | return -EOPNOTSUPP; | 258 | return -EOPNOTSUPP; |
| 229 | 259 | ||
| 230 | if (ca_keyid && !asymmetric_key_id_partial(cert->authority, ca_keyid)) | 260 | if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid)) |
| 231 | return -EPERM; | 261 | return -EPERM; |
| 232 | 262 | ||
| 233 | key = x509_request_asymmetric_key(trust_keyring, cert->authority, | 263 | key = x509_request_asymmetric_key(trust_keyring, |
| 264 | cert->akid_id, cert->akid_skid, | ||
| 234 | false); | 265 | false); |
| 235 | if (!IS_ERR(key)) { | 266 | if (!IS_ERR(key)) { |
| 236 | if (!use_builtin_keys | 267 | if (!use_builtin_keys |
| @@ -271,14 +302,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
| 271 | } | 302 | } |
| 272 | 303 | ||
| 273 | pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); | 304 | pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); |
| 274 | pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", | 305 | pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); |
| 275 | cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, | ||
| 276 | cert->valid_from.tm_mday, cert->valid_from.tm_hour, | ||
| 277 | cert->valid_from.tm_min, cert->valid_from.tm_sec); | ||
| 278 | pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n", | ||
| 279 | cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1, | ||
| 280 | cert->valid_to.tm_mday, cert->valid_to.tm_hour, | ||
| 281 | cert->valid_to.tm_min, cert->valid_to.tm_sec); | ||
| 282 | pr_devel("Cert Signature: %s + %s\n", | 306 | pr_devel("Cert Signature: %s + %s\n", |
| 283 | pkey_algo_name[cert->sig.pkey_algo], | 307 | pkey_algo_name[cert->sig.pkey_algo], |
| 284 | hash_algo_name[cert->sig.pkey_hash_algo]); | 308 | hash_algo_name[cert->sig.pkey_hash_algo]); |
| @@ -287,8 +311,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
| 287 | cert->pub->id_type = PKEY_ID_X509; | 311 | cert->pub->id_type = PKEY_ID_X509; |
| 288 | 312 | ||
| 289 | /* Check the signature on the key if it appears to be self-signed */ | 313 | /* Check the signature on the key if it appears to be self-signed */ |
| 290 | if (!cert->authority || | 314 | if ((!cert->akid_skid && !cert->akid_id) || |
| 291 | asymmetric_key_id_same(cert->skid, cert->authority)) { | 315 | asymmetric_key_id_same(cert->skid, cert->akid_skid) || |
| 316 | asymmetric_key_id_same(cert->id, cert->akid_id)) { | ||
| 292 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ | 317 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ |
| 293 | if (ret < 0) | 318 | if (ret < 0) |
| 294 | goto error_free_cert; | 319 | goto error_free_cert; |
