Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b92e6570 authored by David Howells's avatar David Howells
Browse files

X.509: Extract both parts of the AuthorityKeyIdentifier



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: default avatarDavid Howells <dhowells@redhat.com>
Tested-by: default avatarVivek Goyal <vgoyal@redhat.com>
parent c05cae9a
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -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

#
+2 −2
Original line number Diff line number Diff line
@@ -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;
+5 −7
Original line number Diff line number Diff line
@@ -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
@@ -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;
		}

@@ -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) {
+35 −0
Original line number Diff line number Diff line
-- 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 })
	}
+89 −53
Original line number Diff line number Diff line
@@ -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->akid_id);
		kfree(cert->akid_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->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;
}
Loading