These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / crypto / asymmetric_keys / x509_cert_parser.c
index a668d90..021d39c 100644 (file)
@@ -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);
 
@@ -437,9 +454,7 @@ int x509_process_extension(void *context, size_t hdrlen,
 
                ctx->cert->raw_skid_size = vlen;
                ctx->cert->raw_skid = v;
-               kid = asymmetric_key_generate_id(ctx->cert->raw_subject,
-                                                ctx->cert->raw_subject_size,
-                                                v, vlen);
+               kid = asymmetric_key_generate_id(v, vlen, "", 0);
                if (IS_ERR(kid))
                        return PTR_ERR(kid);
                ctx->cert->skid = kid;
@@ -449,117 +464,115 @@ 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;
        }
 
        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, 29, 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) {
+                               year /= 100;
+                               if (year % 4 != 0)
+                                       mon_len = 28;
+                       }
+               }
+       }
+
+       if (day < 1 || day > mon_len ||
+           hour > 23 ||
+           min > 59 ||
+           sec > 59)
+               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,
@@ -567,5 +580,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->akid_skid)
+               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->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;
 }