diff options
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_parser.h | 1 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_trust.c | 29 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_verify.c | 46 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_parser.h | 1 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 13 |
5 files changed, 74 insertions, 16 deletions
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h index 91949f92bc72..efc7dc9b8f9c 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.h +++ b/crypto/asymmetric_keys/pkcs7_parser.h | |||
@@ -23,6 +23,7 @@ struct pkcs7_signed_info { | |||
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 | 27 | ||
27 | /* Message digest - the digest of the Content Data (or NULL) */ | 28 | /* Message digest - the digest of the Content Data (or NULL) */ |
28 | const void *msgdigest; | 29 | const void *msgdigest; |
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c index 09197e50fa82..8bd474e5e706 100644 --- a/crypto/asymmetric_keys/pkcs7_trust.c +++ b/crypto/asymmetric_keys/pkcs7_trust.c | |||
@@ -35,6 +35,11 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
35 | 35 | ||
36 | kenter(",%u,", sinfo->index); | 36 | kenter(",%u,", sinfo->index); |
37 | 37 | ||
38 | if (sinfo->unsupported_crypto) { | ||
39 | kleave(" = -ENOPKG [cached]"); | ||
40 | return -ENOPKG; | ||
41 | } | ||
42 | |||
38 | for (x509 = sinfo->signer; x509; x509 = x509->signer) { | 43 | for (x509 = sinfo->signer; x509; x509 = x509->signer) { |
39 | if (x509->seen) { | 44 | if (x509->seen) { |
40 | if (x509->verified) { | 45 | if (x509->verified) { |
@@ -139,24 +144,28 @@ int pkcs7_validate_trust(struct pkcs7_message *pkcs7, | |||
139 | { | 144 | { |
140 | struct pkcs7_signed_info *sinfo; | 145 | struct pkcs7_signed_info *sinfo; |
141 | struct x509_certificate *p; | 146 | struct x509_certificate *p; |
142 | int cached_ret = 0, ret; | 147 | int cached_ret = -ENOKEY; |
148 | int ret; | ||
143 | 149 | ||
144 | for (p = pkcs7->certs; p; p = p->next) | 150 | for (p = pkcs7->certs; p; p = p->next) |
145 | p->seen = false; | 151 | p->seen = false; |
146 | 152 | ||
147 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | 153 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { |
148 | ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring); | 154 | ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring); |
149 | if (ret < 0) { | 155 | switch (ret) { |
150 | if (ret == -ENOPKG) { | 156 | case -ENOKEY: |
157 | continue; | ||
158 | case -ENOPKG: | ||
159 | if (cached_ret == -ENOKEY) | ||
151 | cached_ret = -ENOPKG; | 160 | cached_ret = -ENOPKG; |
152 | } else if (ret == -ENOKEY) { | 161 | continue; |
153 | if (cached_ret == 0) | 162 | case 0: |
154 | cached_ret = -ENOKEY; | 163 | *_trusted |= sinfo->trusted; |
155 | } else { | 164 | cached_ret = 0; |
156 | return ret; | 165 | continue; |
157 | } | 166 | default: |
167 | return ret; | ||
158 | } | 168 | } |
159 | *_trusted |= sinfo->trusted; | ||
160 | } | 169 | } |
161 | 170 | ||
162 | return cached_ret; | 171 | return cached_ret; |
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index 57e90fa17f2b..bd264052f751 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c | |||
@@ -181,7 +181,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
181 | x509->seen = true; | 181 | x509->seen = true; |
182 | ret = x509_get_sig_params(x509); | 182 | ret = x509_get_sig_params(x509); |
183 | if (ret < 0) | 183 | if (ret < 0) |
184 | return ret; | 184 | goto maybe_missing_crypto_in_x509; |
185 | 185 | ||
186 | pr_debug("- issuer %s\n", x509->issuer); | 186 | pr_debug("- issuer %s\n", x509->issuer); |
187 | if (x509->authority) | 187 | if (x509->authority) |
@@ -203,7 +203,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
203 | 203 | ||
204 | ret = x509_check_signature(x509->pub, x509); | 204 | ret = x509_check_signature(x509->pub, x509); |
205 | if (ret < 0) | 205 | if (ret < 0) |
206 | return ret; | 206 | goto maybe_missing_crypto_in_x509; |
207 | x509->signer = x509; | 207 | x509->signer = x509; |
208 | pr_debug("- self-signed\n"); | 208 | pr_debug("- self-signed\n"); |
209 | return 0; | 209 | return 0; |
@@ -245,6 +245,17 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
245 | x509 = p; | 245 | x509 = p; |
246 | might_sleep(); | 246 | might_sleep(); |
247 | } | 247 | } |
248 | |||
249 | maybe_missing_crypto_in_x509: | ||
250 | /* Just prune the certificate chain at this point if we lack some | ||
251 | * crypto module to go further. Note, however, we don't want to set | ||
252 | * sinfo->missing_crypto as the signed info block may still be | ||
253 | * validatable against an X.509 cert lower in the chain that we have a | ||
254 | * trusted copy of. | ||
255 | */ | ||
256 | if (ret == -ENOPKG) | ||
257 | return 0; | ||
258 | return ret; | ||
248 | } | 259 | } |
249 | 260 | ||
250 | /* | 261 | /* |
@@ -286,11 +297,33 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
286 | /** | 297 | /** |
287 | * pkcs7_verify - Verify a PKCS#7 message | 298 | * pkcs7_verify - Verify a PKCS#7 message |
288 | * @pkcs7: The PKCS#7 message to be verified | 299 | * @pkcs7: The PKCS#7 message to be verified |
300 | * | ||
301 | * Verify a PKCS#7 message is internally consistent - that is, the data digest | ||
302 | * matches the digest in the AuthAttrs and any signature in the message or one | ||
303 | * of the X.509 certificates it carries that matches another X.509 cert in the | ||
304 | * message can be verified. | ||
305 | * | ||
306 | * This does not look to match the contents of the PKCS#7 message against any | ||
307 | * external public keys. | ||
308 | * | ||
309 | * Returns, in order of descending priority: | ||
310 | * | ||
311 | * (*) -EKEYREJECTED if a signature failed to match for which we found an | ||
312 | * appropriate X.509 certificate, or: | ||
313 | * | ||
314 | * (*) -EBADMSG if some part of the message was invalid, or: | ||
315 | * | ||
316 | * (*) -ENOPKG if none of the signature chains are verifiable because suitable | ||
317 | * crypto modules couldn't be found, or: | ||
318 | * | ||
319 | * (*) 0 if all the signature chains that don't incur -ENOPKG can be verified | ||
320 | * (note that a signature chain may be of zero length), or: | ||
289 | */ | 321 | */ |
290 | int pkcs7_verify(struct pkcs7_message *pkcs7) | 322 | int pkcs7_verify(struct pkcs7_message *pkcs7) |
291 | { | 323 | { |
292 | struct pkcs7_signed_info *sinfo; | 324 | struct pkcs7_signed_info *sinfo; |
293 | struct x509_certificate *x509; | 325 | struct x509_certificate *x509; |
326 | int enopkg = -ENOPKG; | ||
294 | int ret, n; | 327 | int ret, n; |
295 | 328 | ||
296 | kenter(""); | 329 | kenter(""); |
@@ -306,12 +339,17 @@ int pkcs7_verify(struct pkcs7_message *pkcs7) | |||
306 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | 339 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { |
307 | ret = pkcs7_verify_one(pkcs7, sinfo); | 340 | ret = pkcs7_verify_one(pkcs7, sinfo); |
308 | if (ret < 0) { | 341 | if (ret < 0) { |
342 | if (ret == -ENOPKG) { | ||
343 | sinfo->unsupported_crypto = true; | ||
344 | continue; | ||
345 | } | ||
309 | kleave(" = %d", ret); | 346 | kleave(" = %d", ret); |
310 | return ret; | 347 | return ret; |
311 | } | 348 | } |
349 | enopkg = 0; | ||
312 | } | 350 | } |
313 | 351 | ||
314 | kleave(" = 0"); | 352 | kleave(" = %d", enopkg); |
315 | return 0; | 353 | return enopkg; |
316 | } | 354 | } |
317 | EXPORT_SYMBOL_GPL(pkcs7_verify); | 355 | EXPORT_SYMBOL_GPL(pkcs7_verify); |
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h index 0e8d59b010fb..4e1a384901ed 100644 --- a/crypto/asymmetric_keys/x509_parser.h +++ b/crypto/asymmetric_keys/x509_parser.h | |||
@@ -38,6 +38,7 @@ struct x509_certificate { | |||
38 | bool seen; /* Infinite recursion prevention */ | 38 | bool seen; /* Infinite recursion prevention */ |
39 | bool verified; | 39 | bool verified; |
40 | bool trusted; | 40 | bool trusted; |
41 | bool unsupported_crypto; /* T if can't be verified due to missing crypto */ | ||
41 | }; | 42 | }; |
42 | 43 | ||
43 | /* | 44 | /* |
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index c60905c3f4d2..1d9a4c555376 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
@@ -115,6 +115,8 @@ int x509_get_sig_params(struct x509_certificate *cert) | |||
115 | 115 | ||
116 | pr_devel("==>%s()\n", __func__); | 116 | pr_devel("==>%s()\n", __func__); |
117 | 117 | ||
118 | if (cert->unsupported_crypto) | ||
119 | return -ENOPKG; | ||
118 | if (cert->sig.rsa.s) | 120 | if (cert->sig.rsa.s) |
119 | return 0; | 121 | return 0; |
120 | 122 | ||
@@ -127,8 +129,13 @@ int x509_get_sig_params(struct x509_certificate *cert) | |||
127 | * big the hash operational data will be. | 129 | * big the hash operational data will be. |
128 | */ | 130 | */ |
129 | tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0); | 131 | tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0); |
130 | if (IS_ERR(tfm)) | 132 | if (IS_ERR(tfm)) { |
131 | return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); | 133 | if (PTR_ERR(tfm) == -ENOENT) { |
134 | cert->unsupported_crypto = true; | ||
135 | return -ENOPKG; | ||
136 | } | ||
137 | return PTR_ERR(tfm); | ||
138 | } | ||
132 | 139 | ||
133 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | 140 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); |
134 | digest_size = crypto_shash_digestsize(tfm); | 141 | digest_size = crypto_shash_digestsize(tfm); |
@@ -175,6 +182,8 @@ int x509_check_signature(const struct public_key *pub, | |||
175 | return ret; | 182 | return ret; |
176 | 183 | ||
177 | ret = public_key_verify_signature(pub, &cert->sig); | 184 | ret = public_key_verify_signature(pub, &cert->sig); |
185 | if (ret == -ENOPKG) | ||
186 | cert->unsupported_crypto = true; | ||
178 | pr_debug("Cert Verification: %d\n", ret); | 187 | pr_debug("Cert Verification: %d\n", ret); |
179 | return ret; | 188 | return ret; |
180 | } | 189 | } |