diff options
Diffstat (limited to 'crypto/asymmetric_keys/x509_cert_parser.c')
| -rw-r--r-- | crypto/asymmetric_keys/x509_cert_parser.c | 630 |
1 files changed, 456 insertions, 174 deletions
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index facbf26bc6bb..b37cae914987 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -1,39 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* X.509 certificate parser * * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. */ #define pr_fmt(fmt) "X.509: "fmt #include <linux/kernel.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/oid_registry.h> -#include "public_key.h" +#include <crypto/public_key.h> #include "x509_parser.h" -#include "x509-asn1.h" -#include "x509_rsakey-asn1.h" +#include "x509.asn1.h" +#include "x509_akid.asn1.h" struct x509_parse_context { struct x509_certificate *cert; /* Certificate being constructed */ unsigned long data; /* Start of data */ - const void *cert_start; /* Start of cert content */ const void *key; /* Key data */ size_t key_size; /* Size of key data */ + const void *params; /* Key parameters */ + size_t params_size; /* Size of key parameters */ + enum OID key_algo; /* Algorithm used by the cert's key */ enum OID last_oid; /* Last OID encountered */ - enum OID algo_oid; /* Algorithm OID */ - unsigned char nr_mpi; /* Number of MPIs stored */ + enum OID sig_algo; /* Algorithm used to sign the cert */ u8 o_size; /* Size of organizationName (O) */ u8 cn_size; /* Size of commonName (CN) */ u8 email_size; /* Size of emailAddress */ 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; }; /* @@ -42,34 +44,39 @@ struct x509_parse_context { void x509_free_certificate(struct x509_certificate *cert) { if (cert) { - public_key_destroy(cert->pub); + public_key_free(cert->pub); + public_key_signature_free(cert->sig); kfree(cert->issuer); kfree(cert->subject); - kfree(cert->fingerprint); - kfree(cert->authority); + kfree(cert->id); + kfree(cert->skid); kfree(cert); } } +EXPORT_SYMBOL_GPL(x509_free_certificate); /* * Parse an X.509 certificate */ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) { - struct x509_certificate *cert; - struct x509_parse_context *ctx; + struct x509_certificate *cert __free(x509_free_certificate) = NULL; + struct x509_parse_context *ctx __free(kfree) = NULL; + struct asymmetric_key_id *kid; long ret; - ret = -ENOMEM; cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL); if (!cert) - goto error_no_cert; + return ERR_PTR(-ENOMEM); cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL); if (!cert->pub) - goto error_no_ctx; + return ERR_PTR(-ENOMEM); + cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL); + if (!cert->sig) + return ERR_PTR(-ENOMEM); ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL); if (!ctx) - goto error_no_ctx; + return ERR_PTR(-ENOMEM); ctx->cert = cert; ctx->data = (unsigned long)data; @@ -77,24 +84,55 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) /* Attempt to decode the certificate */ ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen); if (ret < 0) - goto error_decode; + return ERR_PTR(ret); + + /* 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"); + return ERR_PTR(ret); + } + } - /* Decode the public key */ - ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, - ctx->key, ctx->key_size); - if (ret < 0) - goto error_decode; + cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL); + if (!cert->pub->key) + return ERR_PTR(-ENOMEM); + + cert->pub->keylen = ctx->key_size; - kfree(ctx); - return cert; + cert->pub->params = kmemdup(ctx->params, ctx->params_size, GFP_KERNEL); + if (!cert->pub->params) + return ERR_PTR(-ENOMEM); -error_decode: - kfree(ctx); -error_no_ctx: - x509_free_certificate(cert); -error_no_cert: - return ERR_PTR(ret); + cert->pub->paramlen = ctx->params_size; + cert->pub->algo = ctx->key_algo; + + /* Grab the signature bits */ + ret = x509_get_sig_params(cert); + if (ret < 0) + return ERR_PTR(ret); + + /* Generate cert issuer + serial number key ID */ + kid = asymmetric_key_generate_id(cert->raw_serial, + cert->raw_serial_size, + cert->raw_issuer, + cert->raw_issuer_size); + if (IS_ERR(kid)) + return ERR_CAST(kid); + cert->id = kid; + + /* Detect self-signed certificates */ + ret = x509_check_for_self_signed(cert); + if (ret < 0) + return ERR_PTR(ret); + + return_ptr(cert); } +EXPORT_SYMBOL_GPL(x509_cert_parse); /* * Note an OID when we find one for later processing when we know how @@ -135,54 +173,106 @@ int x509_note_tbs_certificate(void *context, size_t hdrlen, } /* - * Record the public key algorithm + * Record the algorithm that was used to sign this certificate. */ -int x509_note_pkey_algo(void *context, size_t hdrlen, - unsigned char tag, - const void *value, size_t vlen) +int x509_note_sig_algo(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) { struct x509_parse_context *ctx = context; pr_debug("PubKey Algo: %u\n", ctx->last_oid); switch (ctx->last_oid) { - case OID_md2WithRSAEncryption: - case OID_md3WithRSAEncryption: default: return -ENOPKG; /* Unsupported combination */ - case OID_md4WithRSAEncryption: - ctx->cert->sig_hash_algo = PKEY_HASH_MD5; - ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; - break; - case OID_sha1WithRSAEncryption: - ctx->cert->sig_hash_algo = PKEY_HASH_SHA1; - ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; - break; + ctx->cert->sig->hash_algo = "sha1"; + goto rsa_pkcs1; case OID_sha256WithRSAEncryption: - ctx->cert->sig_hash_algo = PKEY_HASH_SHA256; - ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; - break; + ctx->cert->sig->hash_algo = "sha256"; + goto rsa_pkcs1; case OID_sha384WithRSAEncryption: - ctx->cert->sig_hash_algo = PKEY_HASH_SHA384; - ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; - break; + ctx->cert->sig->hash_algo = "sha384"; + goto rsa_pkcs1; case OID_sha512WithRSAEncryption: - ctx->cert->sig_hash_algo = PKEY_HASH_SHA512; - ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; - break; + ctx->cert->sig->hash_algo = "sha512"; + goto rsa_pkcs1; case OID_sha224WithRSAEncryption: - ctx->cert->sig_hash_algo = PKEY_HASH_SHA224; - ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; - break; + ctx->cert->sig->hash_algo = "sha224"; + goto rsa_pkcs1; + + case OID_id_ecdsa_with_sha1: + ctx->cert->sig->hash_algo = "sha1"; + goto ecdsa; + + case OID_id_rsassa_pkcs1_v1_5_with_sha3_256: + ctx->cert->sig->hash_algo = "sha3-256"; + goto rsa_pkcs1; + + case OID_id_rsassa_pkcs1_v1_5_with_sha3_384: + ctx->cert->sig->hash_algo = "sha3-384"; + goto rsa_pkcs1; + + case OID_id_rsassa_pkcs1_v1_5_with_sha3_512: + ctx->cert->sig->hash_algo = "sha3-512"; + goto rsa_pkcs1; + + case OID_id_ecdsa_with_sha224: + ctx->cert->sig->hash_algo = "sha224"; + goto ecdsa; + + case OID_id_ecdsa_with_sha256: + ctx->cert->sig->hash_algo = "sha256"; + goto ecdsa; + + case OID_id_ecdsa_with_sha384: + ctx->cert->sig->hash_algo = "sha384"; + goto ecdsa; + + case OID_id_ecdsa_with_sha512: + ctx->cert->sig->hash_algo = "sha512"; + goto ecdsa; + + case OID_id_ecdsa_with_sha3_256: + ctx->cert->sig->hash_algo = "sha3-256"; + goto ecdsa; + + case OID_id_ecdsa_with_sha3_384: + ctx->cert->sig->hash_algo = "sha3-384"; + goto ecdsa; + + case OID_id_ecdsa_with_sha3_512: + ctx->cert->sig->hash_algo = "sha3-512"; + goto ecdsa; + + case OID_gost2012Signature256: + ctx->cert->sig->hash_algo = "streebog256"; + goto ecrdsa; + + case OID_gost2012Signature512: + ctx->cert->sig->hash_algo = "streebog512"; + goto ecrdsa; } - ctx->algo_oid = ctx->last_oid; +rsa_pkcs1: + ctx->cert->sig->pkey_algo = "rsa"; + ctx->cert->sig->encoding = "pkcs1"; + ctx->sig_algo = ctx->last_oid; + return 0; +ecrdsa: + ctx->cert->sig->pkey_algo = "ecrdsa"; + ctx->cert->sig->encoding = "raw"; + ctx->sig_algo = ctx->last_oid; + return 0; +ecdsa: + ctx->cert->sig->pkey_algo = "ecdsa"; + ctx->cert->sig->encoding = "x962"; + ctx->sig_algo = ctx->last_oid; return 0; } @@ -195,16 +285,45 @@ int x509_note_signature(void *context, size_t hdrlen, { struct x509_parse_context *ctx = context; - pr_debug("Signature type: %u size %zu\n", ctx->last_oid, vlen); + pr_debug("Signature: alg=%u, size=%zu\n", ctx->last_oid, vlen); - if (ctx->last_oid != ctx->algo_oid) { - pr_warn("Got cert with pkey (%u) and sig (%u) algorithm OIDs\n", - ctx->algo_oid, ctx->last_oid); + /* + * In X.509 certificates, the signature's algorithm is stored in two + * places: inside the TBSCertificate (the data that is signed), and + * alongside the signature. These *must* match. + */ + if (ctx->last_oid != ctx->sig_algo) { + pr_warn("signatureAlgorithm (%u) differs from tbsCertificate.signature (%u)\n", + ctx->last_oid, ctx->sig_algo); return -EINVAL; } - ctx->cert->sig = value; - ctx->cert->sig_size = vlen; + if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 || + strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0 || + strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0) { + /* Discard the BIT STRING metadata */ + if (vlen < 1 || *(const u8 *)value != 0) + return -EBADMSG; + + value++; + vlen--; + } + + ctx->cert->raw_sig = value; + ctx->cert->raw_sig_size = vlen; + return 0; +} + +/* + * Note the certificate serial number + */ +int x509_note_serial(void *context, size_t hdrlen, + unsigned char tag, + const void *value, size_t vlen) +{ + struct x509_parse_context *ctx = context; + ctx->cert->raw_serial = value; + ctx->cert->raw_serial_size = vlen; return 0; } @@ -253,10 +372,9 @@ static int x509_fabricate_name(struct x509_parse_context *ctx, size_t hdrlen, /* Empty name string if no material */ if (!ctx->cn_size && !ctx->o_size && !ctx->email_size) { - buffer = kmalloc(1, GFP_KERNEL); + buffer = kzalloc(1, GFP_KERNEL); if (!buffer) return -ENOMEM; - buffer[0] = 0; goto done; } @@ -320,6 +438,18 @@ int x509_note_issuer(void *context, size_t hdrlen, const void *value, size_t vlen) { struct x509_parse_context *ctx = context; + struct asymmetric_key_id *kid; + + ctx->cert->raw_issuer = value; + ctx->cert->raw_issuer_size = vlen; + + if (!ctx->cert->sig->auth_ids[2]) { + kid = asymmetric_key_generate_id(value, vlen, "", 0); + if (IS_ERR(kid)) + return PTR_ERR(kid); + ctx->cert->sig->auth_ids[2] = kid; + } + return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen); } @@ -328,48 +458,81 @@ int x509_note_subject(void *context, size_t hdrlen, const void *value, size_t vlen) { struct x509_parse_context *ctx = context; + ctx->cert->raw_subject = value; + ctx->cert->raw_subject_size = vlen; return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen); } /* - * Extract the data for the public key algorithm + * Extract the parameters for the public key */ -int x509_extract_key_data(void *context, size_t hdrlen, - unsigned char tag, - const void *value, size_t vlen) +int x509_note_params(void *context, size_t hdrlen, + unsigned char tag, + const void *value, size_t vlen) { struct x509_parse_context *ctx = context; - if (ctx->last_oid != OID_rsaEncryption) - return -ENOPKG; - - /* There seems to be an extraneous 0 byte on the front of the data */ - ctx->cert->pkey_algo = PKEY_ALGO_RSA; - ctx->key = value + 1; - ctx->key_size = vlen - 1; + /* + * AlgorithmIdentifier is used three times in the x509, we should skip + * first and ignore third, using second one which is after subject and + * before subjectPublicKey. + */ + if (!ctx->cert->raw_subject || ctx->key) + return 0; + ctx->params = value - hdrlen; + ctx->params_size = vlen + hdrlen; return 0; } /* - * Extract a RSA public key value + * Extract the data for the public key algorithm */ -int rsa_extract_mpi(void *context, size_t hdrlen, - unsigned char tag, - const void *value, size_t vlen) +int x509_extract_key_data(void *context, size_t hdrlen, + unsigned char tag, + const void *value, size_t vlen) { struct x509_parse_context *ctx = context; - MPI mpi; + enum OID oid; - if (ctx->nr_mpi >= ARRAY_SIZE(ctx->cert->pub->mpi)) { - pr_err("Too many public key MPIs in certificate\n"); - return -EBADMSG; - } + ctx->key_algo = ctx->last_oid; + switch (ctx->last_oid) { + case OID_rsaEncryption: + ctx->cert->pub->pkey_algo = "rsa"; + break; + case OID_gost2012PKey256: + case OID_gost2012PKey512: + ctx->cert->pub->pkey_algo = "ecrdsa"; + break; + case OID_id_ecPublicKey: + if (parse_OID(ctx->params, ctx->params_size, &oid) != 0) + return -EBADMSG; - mpi = mpi_read_raw_data(value, vlen); - if (!mpi) - return -ENOMEM; + switch (oid) { + case OID_id_prime192v1: + ctx->cert->pub->pkey_algo = "ecdsa-nist-p192"; + break; + case OID_id_prime256v1: + ctx->cert->pub->pkey_algo = "ecdsa-nist-p256"; + break; + case OID_id_ansip384r1: + ctx->cert->pub->pkey_algo = "ecdsa-nist-p384"; + break; + case OID_id_ansip521r1: + ctx->cert->pub->pkey_algo = "ecdsa-nist-p521"; + break; + default: + return -ENOPKG; + } + break; + default: + return -ENOPKG; + } - ctx->cert->pub->mpi[ctx->nr_mpi++] = mpi; + /* Discard the BIT STRING metadata */ + if (vlen < 1 || *(const u8 *)value != 0) + return -EBADMSG; + ctx->key = value + 1; + ctx->key_size = vlen - 1; return 0; } @@ -384,146 +547,199 @@ int x509_process_extension(void *context, size_t hdrlen, const void *value, size_t vlen) { struct x509_parse_context *ctx = context; + struct asymmetric_key_id *kid; const unsigned char *v = value; - char *f; - int i; pr_debug("Extension: %u\n", ctx->last_oid); if (ctx->last_oid == OID_subjectKeyIdentifier) { /* Get hold of the key fingerprint */ - if (vlen < 3) + if (ctx->cert->skid || vlen < 3) return -EBADMSG; if (v[0] != ASN1_OTS || v[1] != vlen - 2) return -EBADMSG; v += 2; vlen -= 2; - f = kmalloc(vlen * 2 + 1, GFP_KERNEL); - if (!f) - return -ENOMEM; - for (i = 0; i < vlen; i++) - sprintf(f + i * 2, "%02x", v[i]); - pr_debug("fingerprint %s\n", f); - ctx->cert->fingerprint = f; + ctx->cert->raw_skid_size = vlen; + ctx->cert->raw_skid = v; + kid = asymmetric_key_generate_id(v, vlen, "", 0); + if (IS_ERR(kid)) + return PTR_ERR(kid); + ctx->cert->skid = kid; + pr_debug("subjkeyid %*phN\n", kid->len, kid->data); return 0; } - if (ctx->last_oid == OID_authorityKeyIdentifier) { - size_t key_len; - - /* Get hold of the CA key fingerprint */ - if (vlen < 5) + if (ctx->last_oid == OID_keyUsage) { + /* + * Get hold of the keyUsage bit string + * v[1] is the encoding size + * (Expect either 0x02 or 0x03, making it 1 or 2 bytes) + * v[2] is the number of unused bits in the bit string + * (If >= 3 keyCertSign is missing when v[1] = 0x02) + * v[3] and possibly v[4] contain the bit string + * + * From RFC 5280 4.2.1.3: + * 0x04 is where keyCertSign lands in this bit string + * 0x80 is where digitalSignature lands in this bit string + */ + if (v[0] != ASN1_BTS) return -EBADMSG; - - /* Authority Key Identifier must be a Constructed SEQUENCE */ - if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5))) + if (vlen < 4) return -EBADMSG; - - /* Authority Key Identifier is not indefinite length */ - if (unlikely(vlen == ASN1_INDEFINITE_LENGTH)) + if (v[2] >= 8) return -EBADMSG; + if (v[3] & 0x80) + ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_DIGITALSIG; + if (v[1] == 0x02 && v[2] <= 2 && (v[3] & 0x04)) + ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_KEYCERTSIGN; + else if (vlen > 4 && v[1] == 0x03 && (v[3] & 0x04)) + ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_KEYCERTSIGN; + return 0; + } - if (vlen < ASN1_INDEFINITE_LENGTH) { - /* Short Form length */ - if (v[1] != vlen - 2 || - v[2] != SEQ_TAG_KEYID || - v[3] > vlen - 4) - return -EBADMSG; - - key_len = 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; - - key_len = v[sub + 1]; - v += (sub + 2); - } + if (ctx->last_oid == OID_authorityKeyIdentifier) { + /* Get hold of the CA key fingerprint */ + ctx->raw_akid = v; + ctx->raw_akid_size = vlen; + return 0; + } - f = kmalloc(key_len * 2 + 1, GFP_KERNEL); - if (!f) - return -ENOMEM; - for (i = 0; i < key_len; i++) - sprintf(f + i * 2, "%02x", v[i]); - pr_debug("authority %s\n", f); - ctx->cert->authority = f; + if (ctx->last_oid == OID_basicConstraints) { + /* + * Get hold of the basicConstraints + * v[1] is the encoding size + * (Expect 0x00 for empty SEQUENCE with CA:FALSE, or + * 0x03 or greater for non-empty SEQUENCE) + * v[2] is the encoding type + * (Expect an ASN1_BOOL for the CA) + * v[3] is the length of the ASN1_BOOL + * (Expect 1 for a single byte boolean) + * v[4] is the contents of the ASN1_BOOL + * (Expect 0xFF if the CA is TRUE) + * vlen should match the entire extension size + */ + if (v[0] != (ASN1_CONS_BIT | ASN1_SEQ)) + return -EBADMSG; + if (vlen < 2) + return -EBADMSG; + if (v[1] != vlen - 2) + return -EBADMSG; + /* Empty SEQUENCE means CA:FALSE (default value omitted per DER) */ + if (v[1] == 0) + return 0; + if (vlen >= 5 && v[2] == ASN1_BOOL && v[3] == 1 && v[4] == 0xFF) + ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_CA; + else + return -EBADMSG; return 0; } return 0; } -/* - * Record a certificate time. +/** + * x509_decode_time - Decode an X.509 time ASN.1 object + * @_t: The time to fill in + * @hdrlen: The length of the object header + * @tag: The object tag + * @value: The object value + * @vlen: The size of the object value + * + * Decode an ASN.1 universal time or generalised time field into a struct the + * kernel can handle and check it for validity. The time is decoded thus: + * + * [RFC5280 ยง4.1.2.5] + * CAs conforming to this profile MUST always encode certificate validity + * dates through the year 2049 as UTCTime; certificate validity dates in + * 2050 or later MUST be encoded as GeneralizedTime. Conforming + * applications MUST be able to process validity dates that are encoded in + * either UTCTime or GeneralizedTime. */ -static int x509_note_time(struct tm *tm, size_t hdrlen, - unsigned char tag, - const unsigned char *value, size_t vlen) +int x509_decode_time(time64_t *_t, size_t hdrlen, + unsigned char tag, + const unsigned char *value, size_t vlen) { + static const unsigned char month_lengths[] = { 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31 }; const unsigned char *p = value; + unsigned year, mon, day, hour, min, sec, mon_len; -#define dec2bin(X) ((X) - '0') +#define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; }) #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) if (tag == ASN1_UNITIM) { /* UTCTime: YYMMDDHHMMSSZ */ if (vlen != 13) goto unsupported_time; - tm->tm_year = DD2bin(p); - if (tm->tm_year >= 50) - tm->tm_year += 1900; + year = DD2bin(p); + if (year >= 50) + year += 1900; else - tm->tm_year += 2000; + year += 2000; } else if (tag == ASN1_GENTIM) { /* GenTime: YYYYMMDDHHMMSSZ */ if (vlen != 15) goto unsupported_time; - tm->tm_year = DD2bin(p) * 100 + DD2bin(p); + year = DD2bin(p) * 100 + DD2bin(p); + if (year >= 1950 && year <= 2049) + goto invalid_time; } else { goto unsupported_time; } - tm->tm_year -= 1900; - tm->tm_mon = DD2bin(p) - 1; - tm->tm_mday = DD2bin(p); - tm->tm_hour = DD2bin(p); - tm->tm_min = DD2bin(p); - tm->tm_sec = DD2bin(p); + mon = DD2bin(p); + day = DD2bin(p); + hour = DD2bin(p); + min = DD2bin(p); + sec = DD2bin(p); if (*p != 'Z') goto unsupported_time; + if (year < 1970 || + mon < 1 || mon > 12) + goto invalid_time; + + mon_len = month_lengths[mon - 1]; + if (mon == 2) { + if (year % 4 == 0) { + mon_len = 29; + if (year % 100 == 0) { + mon_len = 28; + if (year % 400 == 0) + mon_len = 29; + } + } + } + + if (day < 1 || day > mon_len || + hour > 24 || /* ISO 8601 permits 24:00:00 as midnight tomorrow */ + min > 59 || + sec > 60) /* ISO 8601 permits leap seconds [X.680 46.3] */ + goto invalid_time; + + *_t = mktime64(year, mon, day, hour, min, sec); return 0; unsupported_time: - pr_debug("Got unsupported time [tag %02x]: '%*.*s'\n", - tag, (int)vlen, (int)vlen, value); + pr_debug("Got unsupported time [tag %02x]: '%*phN'\n", + tag, (int)vlen, value); + return -EBADMSG; +invalid_time: + pr_debug("Got invalid time [tag %02x]: '%*phN'\n", + tag, (int)vlen, value); return -EBADMSG; } +EXPORT_SYMBOL_GPL(x509_decode_time); int x509_note_not_before(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen) { struct x509_parse_context *ctx = context; - return x509_note_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); + return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); } int x509_note_not_after(void *context, size_t hdrlen, @@ -531,5 +747,71 @@ int x509_note_not_after(void *context, size_t hdrlen, const void *value, size_t vlen) { struct x509_parse_context *ctx = context; - return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); + return x509_decode_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->sig->auth_ids[1]) + return 0; + + kid = asymmetric_key_generate_id(value, vlen, "", 0); + if (IS_ERR(kid)) + return PTR_ERR(kid); + pr_debug("authkeyid %*phN\n", kid->len, kid->data); + ctx->cert->sig->auth_ids[1] = 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->sig->auth_ids[0]) + 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->sig->auth_ids[0] = kid; + return 0; } |
