[PATCH 3/3] x509: add CRL signature verification support
Timofei Novikov <[email protected]>
| Newsgroups | org.kernel.vger.linux-crypto,org.kernel.vger.keyrings |
|---|---|
| Message-ID | <[email protected]> |
Verify the digital signature of Certificate Revocation Lists (CRLs) before processing their entries. Extract signature parameters via x509_get_sig_params() and preserve the TBS data during parsing to enable signature verification with verify_signature(). Add the keyring parameter to x509_load_crl_list() to specify which keyring to use for CRL issuer lookup. If no keyring is provided, signature verification is skipped. Signed-off-by: Timofei Novikov <[email protected]> --- crypto/asymmetric_keys/x509_cert_parser.c | 11 ++++++++ crypto/asymmetric_keys/x509_crl.asn1 | 2 +- crypto/asymmetric_keys/x509_loader.c | 31 ++++++++++++++++++++++- crypto/asymmetric_keys/x509_parser.h | 2 +- include/keys/asymmetric-type.h | 3 ++- 5 files changed, 45 insertions(+), 4 deletions(-) diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 76b61f36c082..39ef4cf4b05d 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -907,14 +907,24 @@ struct x509_crl_context *x509_crl_parse(const void *data, size_t datalen) if (ret < 0) return ERR_PTR(ret); + /* + * Extract signature parameters (sig->s, sig->digest, etc.) + * This does what we previously tried to do manually. + */ + ret = x509_get_sig_params(cert); + if (ret < 0) + return ERR_PTR(ret); + /* Transfer parsed data to crl_context */ INIT_LIST_HEAD(&crl_ctx->revoked_list); crl_ctx->indirect_crl = ctx->indirect_crl; crl_ctx->raw_issuer = cert->raw_issuer; crl_ctx->raw_issuer_size = cert->raw_issuer_size; + crl_ctx->sig = cert->sig; list_splice(&ctx->revoked_list, &crl_ctx->revoked_list); /* Detach pointers from cert before auto-free */ + cert->sig = NULL; cert->raw_issuer = NULL; cert->raw_serial = NULL; @@ -930,6 +940,7 @@ void x509_crl_free(struct x509_crl_context *ctx) kfree(entry->serial); kfree(entry); } + public_key_signature_free(ctx->sig); kfree(ctx); } diff --git a/crypto/asymmetric_keys/x509_crl.asn1 b/crypto/asymmetric_keys/x509_crl.asn1 index 3ec8f5a32aca..910af624d828 100644 --- a/crypto/asymmetric_keys/x509_crl.asn1 +++ b/crypto/asymmetric_keys/x509_crl.asn1 @@ -16,7 +16,7 @@ TBSCertList ::= SEQUENCE { nextUpdate Time OPTIONAL ({ x509_note_not_after }) , revokedCertificates SEQUENCE OF RevokedCertificate OPTIONAL, crlExtensions [ 0 ] Extensions OPTIONAL - } + } ({ x509_note_tbs_certificate }) RevokedCertificate ::= SEQUENCE { userCertificate CertificateSerialNumber ({ crl_note_serial }), diff --git a/crypto/asymmetric_keys/x509_loader.c b/crypto/asymmetric_keys/x509_loader.c index 344e6bf31612..7c1a098b2ecb 100644 --- a/crypto/asymmetric_keys/x509_loader.c +++ b/crypto/asymmetric_keys/x509_loader.c @@ -6,6 +6,7 @@ #include <keys/system_keyring.h> #include <linux/slab.h> #include <crypto/sha2.h> +#include <crypto/public_key.h> #include "x509_parser.h" int x509_load_certificate_list(const u8 cert_list[], @@ -74,7 +75,30 @@ static const void *crl_entry_issuer(const struct x509_crl_context *crl, return crl->raw_issuer; } -int x509_load_crl_list(const u8 crl_list[], const unsigned long list_size) +static int x509_crl_verify_signature(struct x509_crl_context *crl_ctx, + const struct key *keyring) +{ + struct key *key; + int ret = -ENOKEY; + + if (!crl_ctx->raw_issuer || !crl_ctx->sig) + return -ENOKEY; + + key = find_asymmetric_key(keyring, + crl_ctx->sig->auth_ids[0], + crl_ctx->sig->auth_ids[1], + crl_ctx->sig->auth_ids[2], + false); + if (IS_ERR(key)) + return PTR_ERR(key); + + ret = verify_signature(key, crl_ctx->sig); + key_put(key); + return ret; +} + +int x509_load_crl_list(const u8 crl_list[], const unsigned long list_size, + const struct key *keyring) { const u8 *p = crl_list, *end = p + list_size; @@ -107,6 +131,11 @@ int x509_load_crl_list(const u8 crl_list[], const unsigned long list_size) pr_err("Problem parsing CRL (%ld)\n", PTR_ERR(crl_ctx)); goto next_crl; } + if (keyring && x509_crl_verify_signature(crl_ctx, keyring) < 0) { + pr_warn("CRL signature verification failed, skipping\n"); + x509_crl_free(crl_ctx); + goto next_crl; + } list_for_each_entry_safe(entry, tmp, &crl_ctx->revoked_list, list) { struct asymmetric_key_id *kid; const void *issuer; diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h index 13cc0bc3d7e2..7c48ccb1008c 100644 --- a/crypto/asymmetric_keys/x509_parser.h +++ b/crypto/asymmetric_keys/x509_parser.h @@ -49,9 +49,9 @@ struct x509_certificate { struct x509_crl_context { const void *raw_issuer; size_t raw_issuer_size; + struct public_key_signature *sig; struct list_head revoked_list; bool indirect_crl; - u8 crl_reason; }; struct x509_revoked_entry { diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h index 635644c8dcf1..db586a4c2981 100644 --- a/include/keys/asymmetric-type.h +++ b/include/keys/asymmetric-type.h @@ -87,7 +87,8 @@ extern struct key *find_asymmetric_key(struct key *keyring, int x509_load_certificate_list(const u8 cert_list[], const unsigned long list_size, const struct key *keyring); #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING -int x509_load_crl_list(const u8 crl_list[], const unsigned long list_size); +int x509_load_crl_list(const u8 crl_list[], const unsigned long list_size, + const struct key *keyring); #endif /* -- 2.43.0