summaryrefslogtreecommitdiffstats
path: root/crypto/asymmetric_keys
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2016-04-06 11:13:34 -0400
committerDavid Howells <dhowells@redhat.com>2016-04-06 11:13:34 -0400
commit6c2dc5ae4ab719a61d19e8cef082226410b04ff8 (patch)
tree63f4974e873a7a3977a7411712875f6169763bed /crypto/asymmetric_keys
parent566a117a8b24e1ae2dfa817cf0c9eec092c783b5 (diff)
X.509: Extract signature digest and make self-signed cert checks earlier
Extract the signature digest for an X.509 certificate earlier, at the end of x509_cert_parse() rather than leaving it to the callers thereof since it has to be called anyway. Further, immediately after that, check the signature on self-signed certificates, also rather in the callers of x509_cert_parse(). We note in the x509_certificate struct the following bits of information: (1) Whether the signature is self-signed (even if we can't check the signature due to missing crypto). (2) Whether the key held in the certificate needs unsupported crypto to be used. We may get a PKCS#7 message with X.509 certs that we can't make use of - we just ignore them and give ENOPKG at the end it we couldn't verify anything if at least one of these unusable certs are in the chain of trust. (3) Whether the signature held in the certificate needs unsupported crypto to be checked. We can still use the key held in this certificate, even if we can't check the signature on it - if it is held in the system trusted keyring, for instance. We just can't add it to a ring of trusted keys or follow it further up the chain of trust. Making these checks earlier allows x509_check_signature() to be removed and replaced with direct calls to public_key_verify_signature(). Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'crypto/asymmetric_keys')
-rw-r--r--crypto/asymmetric_keys/pkcs7_verify.c38
-rw-r--r--crypto/asymmetric_keys/x509_cert_parser.c10
-rw-r--r--crypto/asymmetric_keys/x509_parser.h7
-rw-r--r--crypto/asymmetric_keys/x509_public_key.c126
4 files changed, 110 insertions, 71 deletions
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 1426f03e630b..44b746e9df1b 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -190,9 +190,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
190 x509->subject, 190 x509->subject,
191 x509->raw_serial_size, x509->raw_serial); 191 x509->raw_serial_size, x509->raw_serial);
192 x509->seen = true; 192 x509->seen = true;
193 ret = x509_get_sig_params(x509); 193 if (x509->unsupported_key)
194 if (ret < 0) 194 goto unsupported_crypto_in_x509;
195 goto maybe_missing_crypto_in_x509;
196 195
197 pr_debug("- issuer %s\n", x509->issuer); 196 pr_debug("- issuer %s\n", x509->issuer);
198 sig = x509->sig; 197 sig = x509->sig;
@@ -203,22 +202,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
203 pr_debug("- authkeyid.skid %*phN\n", 202 pr_debug("- authkeyid.skid %*phN\n",
204 sig->auth_ids[1]->len, sig->auth_ids[1]->data); 203 sig->auth_ids[1]->len, sig->auth_ids[1]->data);
205 204
206 if ((!x509->sig->auth_ids[0] && !x509->sig->auth_ids[1]) || 205 if (x509->self_signed) {
207 strcmp(x509->subject, x509->issuer) == 0) {
208 /* If there's no authority certificate specified, then 206 /* If there's no authority certificate specified, then
209 * the certificate must be self-signed and is the root 207 * the certificate must be self-signed and is the root
210 * of the chain. Likewise if the cert is its own 208 * of the chain. Likewise if the cert is its own
211 * authority. 209 * authority.
212 */ 210 */
213 pr_debug("- no auth?\n"); 211 if (x509->unsupported_sig)
214 if (x509->raw_subject_size != x509->raw_issuer_size || 212 goto unsupported_crypto_in_x509;
215 memcmp(x509->raw_subject, x509->raw_issuer,
216 x509->raw_issuer_size) != 0)
217 return 0;
218
219 ret = x509_check_signature(x509->pub, x509);
220 if (ret < 0)
221 goto maybe_missing_crypto_in_x509;
222 x509->signer = x509; 213 x509->signer = x509;
223 pr_debug("- self-signed\n"); 214 pr_debug("- self-signed\n");
224 return 0; 215 return 0;
@@ -270,7 +261,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
270 sinfo->index); 261 sinfo->index);
271 return 0; 262 return 0;
272 } 263 }
273 ret = x509_check_signature(p->pub, x509); 264 ret = public_key_verify_signature(p->pub, p->sig);
274 if (ret < 0) 265 if (ret < 0)
275 return ret; 266 return ret;
276 x509->signer = p; 267 x509->signer = p;
@@ -282,16 +273,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
282 might_sleep(); 273 might_sleep();
283 } 274 }
284 275
285maybe_missing_crypto_in_x509: 276unsupported_crypto_in_x509:
286 /* 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
287 * 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
288 * sinfo->missing_crypto as the signed info block may still be 279 * sinfo->unsupported_crypto as the signed info block may still be
289 * 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
290 * trusted copy of. 281 * trusted copy of.
291 */ 282 */
292 if (ret == -ENOPKG) 283 return 0;
293 return 0;
294 return ret;
295} 284}
296 285
297/* 286/*
@@ -378,9 +367,8 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
378 enum key_being_used_for usage) 367 enum key_being_used_for usage)
379{ 368{
380 struct pkcs7_signed_info *sinfo; 369 struct pkcs7_signed_info *sinfo;
381 struct x509_certificate *x509;
382 int enopkg = -ENOPKG; 370 int enopkg = -ENOPKG;
383 int ret, n; 371 int ret;
384 372
385 kenter(""); 373 kenter("");
386 374
@@ -422,12 +410,6 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
422 return -EINVAL; 410 return -EINVAL;
423 } 411 }
424 412
425 for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) {
426 ret = x509_get_sig_params(x509);
427 if (ret < 0)
428 return ret;
429 }
430
431 for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { 413 for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
432 ret = pkcs7_verify_one(pkcs7, sinfo); 414 ret = pkcs7_verify_one(pkcs7, sinfo);
433 if (ret < 0) { 415 if (ret < 0) {
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index a2fefa713614..865f46ea724f 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -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
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 26a4d83e4e6d..f24f4d808e7f 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -40,7 +40,9 @@ struct x509_certificate {
40 bool seen; /* Infinite recursion prevention */ 40 bool seen; /* Infinite recursion prevention */
41 bool verified; 41 bool verified;
42 bool trusted; 42 bool trusted;
43 bool unsupported_crypto; /* T if can't be verified due to missing crypto */ 43 bool self_signed; /* T if self-signed (check unsupported_sig too) */
44 bool unsupported_key; /* T if key uses unsupported crypto */
45 bool unsupported_sig; /* T if signature uses unsupported crypto */
44}; 46};
45 47
46/* 48/*
@@ -56,5 +58,4 @@ extern int x509_decode_time(time64_t *_t, size_t hdrlen,
56 * x509_public_key.c 58 * x509_public_key.c
57 */ 59 */
58extern int x509_get_sig_params(struct x509_certificate *cert); 60extern int x509_get_sig_params(struct x509_certificate *cert);
59extern int x509_check_signature(const struct public_key *pub, 61extern int x509_check_for_self_signed(struct x509_certificate *cert);
60 struct x509_certificate *cert);
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 4cd102de174c..752d8d5b48fa 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -161,10 +161,17 @@ int x509_get_sig_params(struct x509_certificate *cert)
161 161
162 pr_devel("==>%s()\n", __func__); 162 pr_devel("==>%s()\n", __func__);
163 163
164 if (cert->unsupported_crypto) 164 if (!cert->pub->pkey_algo)
165 return -ENOPKG; 165 cert->unsupported_key = true;
166 if (sig->s) 166
167 if (!sig->pkey_algo)
168 cert->unsupported_sig = true;
169
170 /* We check the hash if we can - even if we can't then verify it */
171 if (!sig->hash_algo) {
172 cert->unsupported_sig = true;
167 return 0; 173 return 0;
174 }
168 175
169 sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL); 176 sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL);
170 if (!sig->s) 177 if (!sig->s)
@@ -178,8 +185,8 @@ int x509_get_sig_params(struct x509_certificate *cert)
178 tfm = crypto_alloc_shash(sig->hash_algo, 0, 0); 185 tfm = crypto_alloc_shash(sig->hash_algo, 0, 0);
179 if (IS_ERR(tfm)) { 186 if (IS_ERR(tfm)) {
180 if (PTR_ERR(tfm) == -ENOENT) { 187 if (PTR_ERR(tfm) == -ENOENT) {
181 cert->unsupported_crypto = true; 188 cert->unsupported_sig = true;
182 return -ENOPKG; 189 return 0;
183 } 190 }
184 return PTR_ERR(tfm); 191 return PTR_ERR(tfm);
185 } 192 }
@@ -212,29 +219,53 @@ error:
212 pr_devel("<==%s() = %d\n", __func__, ret); 219 pr_devel("<==%s() = %d\n", __func__, ret);
213 return ret; 220 return ret;
214} 221}
215EXPORT_SYMBOL_GPL(x509_get_sig_params);
216 222
217/* 223/*
218 * Check the signature on a certificate using the provided public key 224 * Check for self-signedness in an X.509 cert and if found, check the signature
225 * immediately if we can.
219 */ 226 */
220int x509_check_signature(const struct public_key *pub, 227int x509_check_for_self_signed(struct x509_certificate *cert)
221 struct x509_certificate *cert)
222{ 228{
223 int ret; 229 int ret = 0;
224 230
225 pr_devel("==>%s()\n", __func__); 231 pr_devel("==>%s()\n", __func__);
226 232
227 ret = x509_get_sig_params(cert); 233 if (cert->sig->auth_ids[0] || cert->sig->auth_ids[1]) {
228 if (ret < 0) 234 /* If the AKID is present it may have one or two parts. If
229 return ret; 235 * both are supplied, both must match.
236 */
237 bool a = asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]);
238 bool b = asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0]);
239
240 if (!a && !b)
241 goto not_self_signed;
242
243 ret = -EKEYREJECTED;
244 if (((a && !b) || (b && !a)) &&
245 cert->sig->auth_ids[0] && cert->sig->auth_ids[1])
246 goto out;
247 }
248
249 ret = public_key_verify_signature(cert->pub, cert->sig);
250 if (ret < 0) {
251 if (ret == -ENOPKG) {
252 cert->unsupported_sig = true;
253 ret = 0;
254 }
255 goto out;
256 }
257
258 pr_devel("Cert Self-signature verified");
259 cert->self_signed = true;
230 260
231 ret = public_key_verify_signature(pub, cert->sig); 261out:
232 if (ret == -ENOPKG) 262 pr_devel("<==%s() = %d\n", __func__, ret);
233 cert->unsupported_crypto = true;
234 pr_debug("Cert Verification: %d\n", ret);
235 return ret; 263 return ret;
264
265not_self_signed:
266 pr_devel("<==%s() = 0 [not]\n", __func__);
267 return 0;
236} 268}
237EXPORT_SYMBOL_GPL(x509_check_signature);
238 269
239/* 270/*
240 * Check the new certificate against the ones in the trust keyring. If one of 271 * Check the new certificate against the ones in the trust keyring. If one of
@@ -252,22 +283,30 @@ static int x509_validate_trust(struct x509_certificate *cert,
252 struct key *key; 283 struct key *key;
253 int ret = 1; 284 int ret = 1;
254 285
286 if (!sig->auth_ids[0] && !sig->auth_ids[1])
287 return 1;
288
255 if (!trust_keyring) 289 if (!trust_keyring)
256 return -EOPNOTSUPP; 290 return -EOPNOTSUPP;
257
258 if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid)) 291 if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
259 return -EPERM; 292 return -EPERM;
293 if (cert->unsupported_sig)
294 return -ENOPKG;
260 295
261 key = x509_request_asymmetric_key(trust_keyring, 296 key = x509_request_asymmetric_key(trust_keyring,
262 sig->auth_ids[0], sig->auth_ids[1], 297 sig->auth_ids[0], sig->auth_ids[1],
263 false); 298 false);
264 if (!IS_ERR(key)) { 299 if (IS_ERR(key))
265 if (!use_builtin_keys 300 return PTR_ERR(key);
266 || test_bit(KEY_FLAG_BUILTIN, &key->flags)) 301
267 ret = x509_check_signature(key->payload.data[asym_crypto], 302 if (!use_builtin_keys ||
268 cert); 303 test_bit(KEY_FLAG_BUILTIN, &key->flags)) {
269 key_put(key); 304 ret = public_key_verify_signature(
305 key->payload.data[asym_crypto], cert->sig);
306 if (ret == -ENOPKG)
307 cert->unsupported_sig = true;
270 } 308 }
309 key_put(key);
271 return ret; 310 return ret;
272} 311}
273 312
@@ -290,34 +329,41 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
290 pr_devel("Cert Issuer: %s\n", cert->issuer); 329 pr_devel("Cert Issuer: %s\n", cert->issuer);
291 pr_devel("Cert Subject: %s\n", cert->subject); 330 pr_devel("Cert Subject: %s\n", cert->subject);
292 331
293 if (!cert->pub->pkey_algo || 332 if (cert->unsupported_key) {
294 !cert->sig->pkey_algo ||
295 !cert->sig->hash_algo) {
296 ret = -ENOPKG; 333 ret = -ENOPKG;
297 goto error_free_cert; 334 goto error_free_cert;
298 } 335 }
299 336
300 pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo); 337 pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo);
301 pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); 338 pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to);
302 pr_devel("Cert Signature: %s + %s\n",
303 cert->sig->pkey_algo,
304 cert->sig->hash_algo);
305 339
306 cert->pub->id_type = "X509"; 340 cert->pub->id_type = "X509";
307 341
308 /* Check the signature on the key if it appears to be self-signed */ 342 /* See if we can derive the trustability of this certificate.
309 if ((!cert->sig->auth_ids[0] && !cert->sig->auth_ids[1]) || 343 *
310 asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]) || 344 * When it comes to self-signed certificates, we cannot evaluate
311 asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0])) { 345 * trustedness except by the fact that we obtained it from a trusted
312 ret = x509_check_signature(cert->pub, cert); /* self-signed */ 346 * location. So we just rely on x509_validate_trust() failing in this
313 if (ret < 0) 347 * case.
314 goto error_free_cert; 348 *
315 } else if (!prep->trusted) { 349 * Note that there's a possibility of a self-signed cert matching a
350 * cert that we have (most likely a duplicate that we already trust) -
351 * in which case it will be marked trusted.
352 */
353 if (cert->unsupported_sig || cert->self_signed) {
354 public_key_signature_free(cert->sig);
355 cert->sig = NULL;
356 } else {
357 pr_devel("Cert Signature: %s + %s\n",
358 cert->sig->pkey_algo, cert->sig->hash_algo);
359
316 ret = x509_validate_trust(cert, get_system_trusted_keyring()); 360 ret = x509_validate_trust(cert, get_system_trusted_keyring());
317 if (ret) 361 if (ret)
318 ret = x509_validate_trust(cert, get_ima_mok_keyring()); 362 ret = x509_validate_trust(cert, get_ima_mok_keyring());
363 if (ret == -EKEYREJECTED)
364 goto error_free_cert;
319 if (!ret) 365 if (!ret)
320 prep->trusted = 1; 366 prep->trusted = true;
321 } 367 }
322 368
323 /* Propose a description */ 369 /* Propose a description */