Skip to content

Commit

Permalink
X.509: Extract both parts of the AuthorityKeyIdentifier
Browse files Browse the repository at this point in the history
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>
Tested-by: Vivek Goyal <vgoyal@redhat.com>
  • Loading branch information
dhowells committed Aug 7, 2015
1 parent c05cae9 commit b92e657
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 69 deletions.
8 changes: 7 additions & 1 deletion crypto/asymmetric_keys/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

#
Expand Down
4 changes: 2 additions & 2 deletions crypto/asymmetric_keys/pkcs7_trust.c
Original file line number Diff line number Diff line change
Expand Up @@ -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->akid_skid) {
key = x509_request_asymmetric_key(trust_keyring, last->akid_skid,
false);
if (!IS_ERR(key)) {
x509 = last;
Expand Down
12 changes: 5 additions & 7 deletions crypto/asymmetric_keys/pkcs7_verify.c
Original file line number Diff line number Diff line change
Expand Up @@ -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->akid_skid)
pr_debug("- authkeyid %*phN\n",
x509->authority->len, x509->authority->data);
x509->akid_skid->len, x509->akid_skid->data);

if (!x509->authority ||
if (!x509->akid_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
Expand All @@ -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->akid_skid->len, x509->akid_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->akid_skid))
goto found_issuer;
}

Expand Down Expand Up @@ -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) {
Expand Down
35 changes: 35 additions & 0 deletions crypto/asymmetric_keys/x509_akid.asn1
Original file line number Diff line number Diff line change
@@ -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 })
}
142 changes: 89 additions & 53 deletions crypto/asymmetric_keys/x509_cert_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
};

/*
Expand All @@ -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->akid_id);
kfree(cert->akid_skid);
kfree(cert->sig.digest);
mpi_free(cert->sig.rsa.s);
kfree(cert);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand All @@ -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;
}

Expand Down Expand Up @@ -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->akid_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->akid_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->akid_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->akid_id = kid;
return 0;
}
5 changes: 3 additions & 2 deletions crypto/asymmetric_keys/x509_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *akid_id; /* CA AuthKeyId matching ->id (optional) */
struct asymmetric_key_id *akid_skid; /* CA AuthKeyId matching ->skid (optional) */
struct tm valid_from;
struct tm valid_to;
const void *tbs; /* Signed data */
Expand Down
8 changes: 4 additions & 4 deletions crypto/asymmetric_keys/x509_public_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,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->akid_skid, ca_keyid))
return -EPERM;

key = x509_request_asymmetric_key(trust_keyring, cert->authority,
key = x509_request_asymmetric_key(trust_keyring, cert->akid_skid,
false);
if (!IS_ERR(key)) {
if (!use_builtin_keys
Expand Down Expand Up @@ -287,8 +287,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->akid_skid ||
asymmetric_key_id_same(cert->skid, cert->akid_skid)) {
ret = x509_check_signature(cert->pub, cert); /* self-signed */
if (ret < 0)
goto error_free_cert;
Expand Down

0 comments on commit b92e657

Please sign in to comment.