Messages in this thread | | | Date | Thu, 04 Dec 2014 14:14:44 +0200 | From | Dmitry Kasatkin <> | Subject | Re: [PATCH 1/5] X.509: Extract both parts of the AuthorityKeyIdentifier [ver #2] |
| |
On 26/11/14 16:17, David Howells wrote: > Extract both parts of the AuthorityKeyIdentifier, not just the keyIdentifier, > as the second part can be used to match X.509 certificates by issuer and > serialNumber. > > Signed-off-by: David Howells <dhowells@redhat.com> > --- > > crypto/asymmetric_keys/Makefile | 8 +- > crypto/asymmetric_keys/pkcs7_trust.c | 4 - > crypto/asymmetric_keys/pkcs7_verify.c | 12 +- > crypto/asymmetric_keys/x509_akid.asn1 | 35 +++++++ > crypto/asymmetric_keys/x509_cert_parser.c | 142 ++++++++++++++++++----------- > crypto/asymmetric_keys/x509_parser.h | 5 + > crypto/asymmetric_keys/x509_public_key.c | 8 +- > 7 files changed, 145 insertions(+), 69 deletions(-) > create mode 100644 crypto/asymmetric_keys/x509_akid.asn1 > > 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 > obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o > x509_key_parser-y := \ > x509-asn1.o \ > + x509_akid-asn1.o \ > x509_rsakey-asn1.o \ > x509_cert_parser.o \ > x509_public_key.o > > -$(obj)/x509_cert_parser.o: $(obj)/x509-asn1.h $(obj)/x509_rsakey-asn1.h > +$(obj)/x509_cert_parser.o: \ > + $(obj)/x509-asn1.h \ > + $(obj)/x509_akid-asn1.h \ > + $(obj)/x509_rsakey-asn1.h > $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h > +$(obj)/x509_akid-asn1.o: $(obj)/x509_akid-asn1.c $(obj)/x509_akid-asn1.h > $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h > > clean-files += x509-asn1.c x509-asn1.h > +clean-files += x509_akid-asn1.c x509_akid-asn1.h > clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h > > # > diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c > index 1d29376072da..f802cf118053 100644 > --- a/crypto/asymmetric_keys/pkcs7_trust.c > +++ b/crypto/asymmetric_keys/pkcs7_trust.c > @@ -85,8 +85,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, > /* No match - see if the root certificate has a signer amongst the > * trusted keys. > */ > - if (last && last->authority) { > - key = x509_request_asymmetric_key(trust_keyring, last->authority, > + if (last && last->auth_skid) { > + key = x509_request_asymmetric_key(trust_keyring, last->auth_skid, > false); > if (!IS_ERR(key)) { > x509 = last; > diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c > index cd455450b069..5e956c5b9071 100644 > --- a/crypto/asymmetric_keys/pkcs7_verify.c > +++ b/crypto/asymmetric_keys/pkcs7_verify.c > @@ -187,11 +187,11 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, > goto maybe_missing_crypto_in_x509; > > pr_debug("- issuer %s\n", x509->issuer); > - if (x509->authority) > + if (x509->auth_skid) > pr_debug("- authkeyid %*phN\n", > - x509->authority->len, x509->authority->data); > + x509->auth_skid->len, x509->auth_skid->data); > > - if (!x509->authority || > + if (!x509->auth_skid || > strcmp(x509->subject, x509->issuer) == 0) { > /* If there's no authority certificate specified, then > * the certificate must be self-signed and is the root > @@ -216,13 +216,13 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, > * list to see if the next one is there. > */ > pr_debug("- want %*phN\n", > - x509->authority->len, x509->authority->data); > + x509->auth_skid->len, x509->auth_skid->data); > for (p = pkcs7->certs; p; p = p->next) { > if (!p->skid) > continue; > pr_debug("- cmp [%u] %*phN\n", > p->index, p->skid->len, p->skid->data); > - if (asymmetric_key_id_same(p->skid, x509->authority)) > + if (asymmetric_key_id_same(p->skid, x509->auth_skid)) > goto found_issuer; > } > > @@ -338,8 +338,6 @@ int pkcs7_verify(struct pkcs7_message *pkcs7) > ret = x509_get_sig_params(x509); > if (ret < 0) > return ret; > - pr_debug("X.509[%u] %*phN\n", > - n, x509->authority->len, x509->authority->data); > } > > for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { > 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 @@ > +-- X.509 AuthorityKeyIdentifier > +-- rfc5280 section 4.2.1.1 > + > +AuthorityKeyIdentifier ::= SEQUENCE { > + keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL, > + authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL, > + authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL > + } > + > +KeyIdentifier ::= OCTET STRING ({ x509_akid_note_kid }) > + > +CertificateSerialNumber ::= INTEGER ({ x509_akid_note_serial }) > + > +GeneralNames ::= SEQUENCE OF GeneralName > + > +GeneralName ::= CHOICE { > + otherName [0] ANY, > + rfc822Name [1] IA5String, > + dNSName [2] IA5String, > + x400Address [3] ANY, > + directoryName [4] Name ({ x509_akid_note_name }), > + ediPartyName [5] ANY, > + uniformResourceIdentifier [6] IA5String, > + iPAddress [7] OCTET STRING, > + registeredID [8] OBJECT IDENTIFIER > + } > + > +Name ::= SEQUENCE OF RelativeDistinguishedName > + > +RelativeDistinguishedName ::= SET OF AttributeValueAssertion > + > +AttributeValueAssertion ::= SEQUENCE { > + attributeType OBJECT IDENTIFIER ({ x509_note_OID }), > + attributeValue ANY ({ x509_extract_name_segment }) > + } > diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c > index a668d90302d3..e9d6586fdf89 100644 > --- a/crypto/asymmetric_keys/x509_cert_parser.c > +++ b/crypto/asymmetric_keys/x509_cert_parser.c > @@ -18,6 +18,7 @@ > #include "public_key.h" > #include "x509_parser.h" > #include "x509-asn1.h" > +#include "x509_akid-asn1.h" > #include "x509_rsakey-asn1.h" > > struct x509_parse_context { > @@ -35,6 +36,10 @@ struct x509_parse_context { > u16 o_offset; /* Offset of organizationName (O) */ > u16 cn_offset; /* Offset of commonName (CN) */ > u16 email_offset; /* Offset of emailAddress */ > + unsigned raw_akid_size; > + const void *raw_akid; /* Raw authorityKeyId in ASN.1 */ > + const void *akid_raw_issuer; /* Raw directoryName in authorityKeyId */ > + unsigned akid_raw_issuer_size; > }; > > /* > @@ -48,7 +53,8 @@ void x509_free_certificate(struct x509_certificate *cert) > kfree(cert->subject); > kfree(cert->id); > kfree(cert->skid); > - kfree(cert->authority); > + kfree(cert->auth_id); > + kfree(cert->auth_skid); > kfree(cert->sig.digest); > mpi_free(cert->sig.rsa.s); > kfree(cert); > @@ -85,6 +91,18 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) > if (ret < 0) > goto error_decode; > > + /* Decode the AuthorityKeyIdentifier */ > + if (ctx->raw_akid) { > + pr_devel("AKID: %u %*phN\n", > + ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid); > + ret = asn1_ber_decoder(&x509_akid_decoder, ctx, > + ctx->raw_akid, ctx->raw_akid_size); > + if (ret < 0) { > + pr_warn("Couldn't decode AuthKeyIdentifier\n"); > + goto error_decode; > + } > + } > + > /* Decode the public key */ > ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, > ctx->key, ctx->key_size); > @@ -422,7 +440,6 @@ int x509_process_extension(void *context, size_t hdrlen, > struct x509_parse_context *ctx = context; > struct asymmetric_key_id *kid; > const unsigned char *v = value; > - int i; > > pr_debug("Extension: %u\n", ctx->last_oid); > > @@ -449,57 +466,8 @@ int x509_process_extension(void *context, size_t hdrlen, > > if (ctx->last_oid == OID_authorityKeyIdentifier) { > /* Get hold of the CA key fingerprint */ > - if (ctx->cert->authority || vlen < 5) > - return -EBADMSG; > - > - /* Authority Key Identifier must be a Constructed SEQUENCE */ > - if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5))) > - return -EBADMSG; > - > - /* Authority Key Identifier is not indefinite length */ > - if (unlikely(vlen == ASN1_INDEFINITE_LENGTH)) > - return -EBADMSG; > - > - if (vlen < ASN1_INDEFINITE_LENGTH) { > - /* Short Form length */ > - if (v[1] != vlen - 2 || > - v[2] != SEQ_TAG_KEYID || > - v[3] > vlen - 4) > - return -EBADMSG; > - > - vlen = v[3]; > - v += 4; > - } else { > - /* Long Form length */ > - size_t seq_len = 0; > - size_t sub = v[1] - ASN1_INDEFINITE_LENGTH; > - > - if (sub > 2) > - return -EBADMSG; > - > - /* calculate the length from subsequent octets */ > - v += 2; > - for (i = 0; i < sub; i++) { > - seq_len <<= 8; > - seq_len |= v[i]; > - } > - > - if (seq_len != vlen - 2 - sub || > - v[sub] != SEQ_TAG_KEYID || > - v[sub + 1] > vlen - 4 - sub) > - return -EBADMSG; > - > - vlen = v[sub + 1]; > - v += (sub + 2); > - } > - > - kid = asymmetric_key_generate_id(ctx->cert->raw_issuer, > - ctx->cert->raw_issuer_size, > - v, vlen); > - if (IS_ERR(kid)) > - return PTR_ERR(kid); > - pr_debug("authkeyid %*phN\n", kid->len, kid->data); > - ctx->cert->authority = kid; > + ctx->raw_akid = v; > + ctx->raw_akid_size = vlen; > return 0; > } > > @@ -569,3 +537,71 @@ int x509_note_not_after(void *context, size_t hdrlen, > struct x509_parse_context *ctx = context; > return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); > } > + > +/* > + * Note a key identifier-based AuthorityKeyIdentifier > + */ > +int x509_akid_note_kid(void *context, size_t hdrlen, > + unsigned char tag, > + const void *value, size_t vlen) > +{ > + struct x509_parse_context *ctx = context; > + struct asymmetric_key_id *kid; > + > + pr_debug("AKID: keyid: %*phN\n", (int)vlen, value); > + > + if (ctx->cert->auth_skid) > + return 0; > + > + kid = asymmetric_key_generate_id(ctx->cert->raw_issuer, > + ctx->cert->raw_issuer_size, > + value, vlen); > + if (IS_ERR(kid)) > + return PTR_ERR(kid); > + pr_debug("authkeyid %*phN\n", kid->len, kid->data); > + ctx->cert->auth_skid = kid; > + return 0; > +} > + > +/* > + * Note a directoryName in an AuthorityKeyIdentifier > + */ > +int x509_akid_note_name(void *context, size_t hdrlen, > + unsigned char tag, > + const void *value, size_t vlen) > +{ > + struct x509_parse_context *ctx = context; > + > + pr_debug("AKID: name: %*phN\n", (int)vlen, value); > + > + ctx->akid_raw_issuer = value; > + ctx->akid_raw_issuer_size = vlen; > + return 0; > +} > + > +/* > + * Note a serial number in an AuthorityKeyIdentifier > + */ > +int x509_akid_note_serial(void *context, size_t hdrlen, > + unsigned char tag, > + const void *value, size_t vlen) > +{ > + struct x509_parse_context *ctx = context; > + struct asymmetric_key_id *kid; > + > + pr_debug("AKID: serial: %*phN\n", (int)vlen, value); > + > + if (!ctx->akid_raw_issuer || ctx->cert->auth_id) > + return 0; > + > + kid = asymmetric_key_generate_id(value, > + vlen, > + ctx->akid_raw_issuer, > + ctx->akid_raw_issuer_size); > + if (IS_ERR(kid)) > + return PTR_ERR(kid); > + > + pr_debug("authkeyid %*phN\n", kid->len, kid->data); > + ctx->cert->auth_id = kid; > + return 0; > +} > diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h > index 3dfe6b5d6f0b..c4d16ddbc2cb 100644 > --- a/crypto/asymmetric_keys/x509_parser.h > +++ b/crypto/asymmetric_keys/x509_parser.h > @@ -19,9 +19,10 @@ struct x509_certificate { > struct public_key_signature sig; /* Signature parameters */ > char *issuer; /* Name of certificate issuer */ > char *subject; /* Name of certificate subject */ > - struct asymmetric_key_id *id; /* Serial number + issuer */ > + struct asymmetric_key_id *id; /* Issuer + Serial number */ > struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ > - struct asymmetric_key_id *authority; /* Authority key identifier (optional) */ > + struct asymmetric_key_id *auth_id; /* CA AuthKeyId matching ->id (optional) */ > + struct asymmetric_key_id *auth_skid; /* CA AuthKeyId matching ->skid (optional) */
Hi David,
Why do you call it "auth_skid", not just akid in similar way as 'skid'? Why it is "auth & skid"?
- Dmitry
> struct tm valid_from; > struct tm valid_to; > const void *tbs; /* Signed data */ > diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c > index a6c42031628e..a3d9ba999da5 100644 > --- a/crypto/asymmetric_keys/x509_public_key.c > +++ b/crypto/asymmetric_keys/x509_public_key.c > @@ -214,10 +214,10 @@ static int x509_validate_trust(struct x509_certificate *cert, > if (!trust_keyring) > return -EOPNOTSUPP; > > - if (ca_keyid && !asymmetric_key_id_partial(cert->authority, ca_keyid)) > + if (ca_keyid && !asymmetric_key_id_partial(cert->auth_skid, ca_keyid)) > return -EPERM; > > - key = x509_request_asymmetric_key(trust_keyring, cert->authority, > + key = x509_request_asymmetric_key(trust_keyring, cert->auth_skid, > false); > if (!IS_ERR(key)) { > if (!use_builtin_keys > @@ -274,8 +274,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) > cert->pub->id_type = PKEY_ID_X509; > > /* Check the signature on the key if it appears to be self-signed */ > - if (!cert->authority || > - asymmetric_key_id_same(cert->skid, cert->authority)) { > + if (!cert->auth_skid || > + asymmetric_key_id_same(cert->skid, cert->auth_skid)) { > ret = x509_check_signature(cert->pub, cert); /* self-signed */ > if (ret < 0) > goto error_free_cert; > >
| |