X.509: Extract both parts of the AuthorityKeyIdentifier
[ Upstream commit b92e6570a9
]
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>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
wifi-calibration
parent
d836abef23
commit
3ccbbbf7b5
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 })
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue