1c26fd69fSDavid Howells /* X.509 certificate parser 2c26fd69fSDavid Howells * 3c26fd69fSDavid Howells * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. 4c26fd69fSDavid Howells * Written by David Howells (dhowells@redhat.com) 5c26fd69fSDavid Howells * 6c26fd69fSDavid Howells * This program is free software; you can redistribute it and/or 7c26fd69fSDavid Howells * modify it under the terms of the GNU General Public Licence 8c26fd69fSDavid Howells * as published by the Free Software Foundation; either version 9c26fd69fSDavid Howells * 2 of the Licence, or (at your option) any later version. 10c26fd69fSDavid Howells */ 11c26fd69fSDavid Howells 12c26fd69fSDavid Howells #define pr_fmt(fmt) "X.509: "fmt 13c26fd69fSDavid Howells #include <linux/kernel.h> 14ace0107aSDavid Howells #include <linux/export.h> 15c26fd69fSDavid Howells #include <linux/slab.h> 16c26fd69fSDavid Howells #include <linux/err.h> 17c26fd69fSDavid Howells #include <linux/oid_registry.h> 18db6c43bdSTadeusz Struk #include <crypto/public_key.h> 19c26fd69fSDavid Howells #include "x509_parser.h" 20c26fd69fSDavid Howells #include "x509-asn1.h" 21b92e6570SDavid Howells #include "x509_akid-asn1.h" 22c26fd69fSDavid Howells 23c26fd69fSDavid Howells struct x509_parse_context { 24c26fd69fSDavid Howells struct x509_certificate *cert; /* Certificate being constructed */ 25c26fd69fSDavid Howells unsigned long data; /* Start of data */ 26c26fd69fSDavid Howells const void *cert_start; /* Start of cert content */ 27c26fd69fSDavid Howells const void *key; /* Key data */ 28c26fd69fSDavid Howells size_t key_size; /* Size of key data */ 29c26fd69fSDavid Howells enum OID last_oid; /* Last OID encountered */ 30c26fd69fSDavid Howells enum OID algo_oid; /* Algorithm OID */ 31c26fd69fSDavid Howells unsigned char nr_mpi; /* Number of MPIs stored */ 32c26fd69fSDavid Howells u8 o_size; /* Size of organizationName (O) */ 33c26fd69fSDavid Howells u8 cn_size; /* Size of commonName (CN) */ 34c26fd69fSDavid Howells u8 email_size; /* Size of emailAddress */ 35c26fd69fSDavid Howells u16 o_offset; /* Offset of organizationName (O) */ 36c26fd69fSDavid Howells u16 cn_offset; /* Offset of commonName (CN) */ 37c26fd69fSDavid Howells u16 email_offset; /* Offset of emailAddress */ 38b92e6570SDavid Howells unsigned raw_akid_size; 39b92e6570SDavid Howells const void *raw_akid; /* Raw authorityKeyId in ASN.1 */ 40b92e6570SDavid Howells const void *akid_raw_issuer; /* Raw directoryName in authorityKeyId */ 41b92e6570SDavid Howells unsigned akid_raw_issuer_size; 42c26fd69fSDavid Howells }; 43c26fd69fSDavid Howells 44c26fd69fSDavid Howells /* 45c26fd69fSDavid Howells * Free an X.509 certificate 46c26fd69fSDavid Howells */ 47c26fd69fSDavid Howells void x509_free_certificate(struct x509_certificate *cert) 48c26fd69fSDavid Howells { 49c26fd69fSDavid Howells if (cert) { 503b764563SDavid Howells public_key_free(cert->pub); 5177d0910dSDavid Howells public_key_signature_free(cert->sig); 52c26fd69fSDavid Howells kfree(cert->issuer); 53c26fd69fSDavid Howells kfree(cert->subject); 5446963b77SDavid Howells kfree(cert->id); 5546963b77SDavid Howells kfree(cert->skid); 56c26fd69fSDavid Howells kfree(cert); 57c26fd69fSDavid Howells } 58c26fd69fSDavid Howells } 59ace0107aSDavid Howells EXPORT_SYMBOL_GPL(x509_free_certificate); 60c26fd69fSDavid Howells 61c26fd69fSDavid Howells /* 62c26fd69fSDavid Howells * Parse an X.509 certificate 63c26fd69fSDavid Howells */ 64c26fd69fSDavid Howells struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) 65c26fd69fSDavid Howells { 66c26fd69fSDavid Howells struct x509_certificate *cert; 67c26fd69fSDavid Howells struct x509_parse_context *ctx; 6846963b77SDavid Howells struct asymmetric_key_id *kid; 69c26fd69fSDavid Howells long ret; 70c26fd69fSDavid Howells 71c26fd69fSDavid Howells ret = -ENOMEM; 72c26fd69fSDavid Howells cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL); 73c26fd69fSDavid Howells if (!cert) 74c26fd69fSDavid Howells goto error_no_cert; 75c26fd69fSDavid Howells cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL); 76c26fd69fSDavid Howells if (!cert->pub) 77c26fd69fSDavid Howells goto error_no_ctx; 7877d0910dSDavid Howells cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL); 7977d0910dSDavid Howells if (!cert->sig) 8077d0910dSDavid Howells goto error_no_ctx; 81c26fd69fSDavid Howells ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL); 82c26fd69fSDavid Howells if (!ctx) 83c26fd69fSDavid Howells goto error_no_ctx; 84c26fd69fSDavid Howells 85c26fd69fSDavid Howells ctx->cert = cert; 86c26fd69fSDavid Howells ctx->data = (unsigned long)data; 87c26fd69fSDavid Howells 88c26fd69fSDavid Howells /* Attempt to decode the certificate */ 89c26fd69fSDavid Howells ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen); 90c26fd69fSDavid Howells if (ret < 0) 91c26fd69fSDavid Howells goto error_decode; 92c26fd69fSDavid Howells 93b92e6570SDavid Howells /* Decode the AuthorityKeyIdentifier */ 94b92e6570SDavid Howells if (ctx->raw_akid) { 95b92e6570SDavid Howells pr_devel("AKID: %u %*phN\n", 96b92e6570SDavid Howells ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid); 97b92e6570SDavid Howells ret = asn1_ber_decoder(&x509_akid_decoder, ctx, 98b92e6570SDavid Howells ctx->raw_akid, ctx->raw_akid_size); 99b92e6570SDavid Howells if (ret < 0) { 100b92e6570SDavid Howells pr_warn("Couldn't decode AuthKeyIdentifier\n"); 101b92e6570SDavid Howells goto error_decode; 102b92e6570SDavid Howells } 103b92e6570SDavid Howells } 104b92e6570SDavid Howells 105db6c43bdSTadeusz Struk cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL); 106db6c43bdSTadeusz Struk if (!cert->pub->key) 107c26fd69fSDavid Howells goto error_decode; 108c26fd69fSDavid Howells 109db6c43bdSTadeusz Struk cert->pub->keylen = ctx->key_size; 110db6c43bdSTadeusz Struk 11146963b77SDavid Howells /* Generate cert issuer + serial number key ID */ 11246963b77SDavid Howells kid = asymmetric_key_generate_id(cert->raw_serial, 11346963b77SDavid Howells cert->raw_serial_size, 11446963b77SDavid Howells cert->raw_issuer, 11546963b77SDavid Howells cert->raw_issuer_size); 11646963b77SDavid Howells if (IS_ERR(kid)) { 11746963b77SDavid Howells ret = PTR_ERR(kid); 11846963b77SDavid Howells goto error_decode; 11946963b77SDavid Howells } 12046963b77SDavid Howells cert->id = kid; 12146963b77SDavid Howells 122c26fd69fSDavid Howells kfree(ctx); 123c26fd69fSDavid Howells return cert; 124c26fd69fSDavid Howells 125c26fd69fSDavid Howells error_decode: 126db6c43bdSTadeusz Struk kfree(cert->pub->key); 127c26fd69fSDavid Howells kfree(ctx); 128c26fd69fSDavid Howells error_no_ctx: 129c26fd69fSDavid Howells x509_free_certificate(cert); 130c26fd69fSDavid Howells error_no_cert: 131c26fd69fSDavid Howells return ERR_PTR(ret); 132c26fd69fSDavid Howells } 133ace0107aSDavid Howells EXPORT_SYMBOL_GPL(x509_cert_parse); 134c26fd69fSDavid Howells 135c26fd69fSDavid Howells /* 136c26fd69fSDavid Howells * Note an OID when we find one for later processing when we know how 137c26fd69fSDavid Howells * to interpret it. 138c26fd69fSDavid Howells */ 139c26fd69fSDavid Howells int x509_note_OID(void *context, size_t hdrlen, 140c26fd69fSDavid Howells unsigned char tag, 141c26fd69fSDavid Howells const void *value, size_t vlen) 142c26fd69fSDavid Howells { 143c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 144c26fd69fSDavid Howells 145c26fd69fSDavid Howells ctx->last_oid = look_up_OID(value, vlen); 146c26fd69fSDavid Howells if (ctx->last_oid == OID__NR) { 147c26fd69fSDavid Howells char buffer[50]; 148c26fd69fSDavid Howells sprint_oid(value, vlen, buffer, sizeof(buffer)); 149cf75446eSRandy Dunlap pr_debug("Unknown OID: [%lu] %s\n", 150c26fd69fSDavid Howells (unsigned long)value - ctx->data, buffer); 151c26fd69fSDavid Howells } 152c26fd69fSDavid Howells return 0; 153c26fd69fSDavid Howells } 154c26fd69fSDavid Howells 155c26fd69fSDavid Howells /* 156c26fd69fSDavid Howells * Save the position of the TBS data so that we can check the signature over it 157c26fd69fSDavid Howells * later. 158c26fd69fSDavid Howells */ 159c26fd69fSDavid Howells int x509_note_tbs_certificate(void *context, size_t hdrlen, 160c26fd69fSDavid Howells unsigned char tag, 161c26fd69fSDavid Howells const void *value, size_t vlen) 162c26fd69fSDavid Howells { 163c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 164c26fd69fSDavid Howells 165c26fd69fSDavid Howells pr_debug("x509_note_tbs_certificate(,%zu,%02x,%ld,%zu)!\n", 166c26fd69fSDavid Howells hdrlen, tag, (unsigned long)value - ctx->data, vlen); 167c26fd69fSDavid Howells 168c26fd69fSDavid Howells ctx->cert->tbs = value - hdrlen; 169c26fd69fSDavid Howells ctx->cert->tbs_size = vlen + hdrlen; 170c26fd69fSDavid Howells return 0; 171c26fd69fSDavid Howells } 172c26fd69fSDavid Howells 173c26fd69fSDavid Howells /* 174c26fd69fSDavid Howells * Record the public key algorithm 175c26fd69fSDavid Howells */ 176c26fd69fSDavid Howells int x509_note_pkey_algo(void *context, size_t hdrlen, 177c26fd69fSDavid Howells unsigned char tag, 178c26fd69fSDavid Howells const void *value, size_t vlen) 179c26fd69fSDavid Howells { 180c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 181c26fd69fSDavid Howells 182c26fd69fSDavid Howells pr_debug("PubKey Algo: %u\n", ctx->last_oid); 183c26fd69fSDavid Howells 184c26fd69fSDavid Howells switch (ctx->last_oid) { 185c26fd69fSDavid Howells case OID_md2WithRSAEncryption: 186c26fd69fSDavid Howells case OID_md3WithRSAEncryption: 187c26fd69fSDavid Howells default: 188c26fd69fSDavid Howells return -ENOPKG; /* Unsupported combination */ 189c26fd69fSDavid Howells 190c26fd69fSDavid Howells case OID_md4WithRSAEncryption: 19177d0910dSDavid Howells ctx->cert->sig->hash_algo = "md4"; 19277d0910dSDavid Howells ctx->cert->sig->pkey_algo = "rsa"; 193c26fd69fSDavid Howells break; 194c26fd69fSDavid Howells 195c26fd69fSDavid Howells case OID_sha1WithRSAEncryption: 19677d0910dSDavid Howells ctx->cert->sig->hash_algo = "sha1"; 19777d0910dSDavid Howells ctx->cert->sig->pkey_algo = "rsa"; 198c26fd69fSDavid Howells break; 199c26fd69fSDavid Howells 200c26fd69fSDavid Howells case OID_sha256WithRSAEncryption: 20177d0910dSDavid Howells ctx->cert->sig->hash_algo = "sha256"; 20277d0910dSDavid Howells ctx->cert->sig->pkey_algo = "rsa"; 203c26fd69fSDavid Howells break; 204c26fd69fSDavid Howells 205c26fd69fSDavid Howells case OID_sha384WithRSAEncryption: 20677d0910dSDavid Howells ctx->cert->sig->hash_algo = "sha384"; 20777d0910dSDavid Howells ctx->cert->sig->pkey_algo = "rsa"; 208c26fd69fSDavid Howells break; 209c26fd69fSDavid Howells 210c26fd69fSDavid Howells case OID_sha512WithRSAEncryption: 21177d0910dSDavid Howells ctx->cert->sig->hash_algo = "sha512"; 21277d0910dSDavid Howells ctx->cert->sig->pkey_algo = "rsa"; 213c26fd69fSDavid Howells break; 214c26fd69fSDavid Howells 215c26fd69fSDavid Howells case OID_sha224WithRSAEncryption: 21677d0910dSDavid Howells ctx->cert->sig->hash_algo = "sha224"; 21777d0910dSDavid Howells ctx->cert->sig->pkey_algo = "rsa"; 218c26fd69fSDavid Howells break; 219c26fd69fSDavid Howells } 220c26fd69fSDavid Howells 221c26fd69fSDavid Howells ctx->algo_oid = ctx->last_oid; 222c26fd69fSDavid Howells return 0; 223c26fd69fSDavid Howells } 224c26fd69fSDavid Howells 225c26fd69fSDavid Howells /* 226c26fd69fSDavid Howells * Note the whereabouts and type of the signature. 227c26fd69fSDavid Howells */ 228c26fd69fSDavid Howells int x509_note_signature(void *context, size_t hdrlen, 229c26fd69fSDavid Howells unsigned char tag, 230c26fd69fSDavid Howells const void *value, size_t vlen) 231c26fd69fSDavid Howells { 232c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 233c26fd69fSDavid Howells 234c26fd69fSDavid Howells pr_debug("Signature type: %u size %zu\n", ctx->last_oid, vlen); 235c26fd69fSDavid Howells 236c26fd69fSDavid Howells if (ctx->last_oid != ctx->algo_oid) { 237c26fd69fSDavid Howells pr_warn("Got cert with pkey (%u) and sig (%u) algorithm OIDs\n", 238c26fd69fSDavid Howells ctx->algo_oid, ctx->last_oid); 239c26fd69fSDavid Howells return -EINVAL; 240c26fd69fSDavid Howells } 241c26fd69fSDavid Howells 242b426beb6SDavid Howells ctx->cert->raw_sig = value; 243b426beb6SDavid Howells ctx->cert->raw_sig_size = vlen; 244c26fd69fSDavid Howells return 0; 245c26fd69fSDavid Howells } 246c26fd69fSDavid Howells 247c26fd69fSDavid Howells /* 24884aabd46SDavid Howells * Note the certificate serial number 24984aabd46SDavid Howells */ 25084aabd46SDavid Howells int x509_note_serial(void *context, size_t hdrlen, 25184aabd46SDavid Howells unsigned char tag, 25284aabd46SDavid Howells const void *value, size_t vlen) 25384aabd46SDavid Howells { 25484aabd46SDavid Howells struct x509_parse_context *ctx = context; 25584aabd46SDavid Howells ctx->cert->raw_serial = value; 25684aabd46SDavid Howells ctx->cert->raw_serial_size = vlen; 25784aabd46SDavid Howells return 0; 25884aabd46SDavid Howells } 25984aabd46SDavid Howells 26084aabd46SDavid Howells /* 261c26fd69fSDavid Howells * Note some of the name segments from which we'll fabricate a name. 262c26fd69fSDavid Howells */ 263c26fd69fSDavid Howells int x509_extract_name_segment(void *context, size_t hdrlen, 264c26fd69fSDavid Howells unsigned char tag, 265c26fd69fSDavid Howells const void *value, size_t vlen) 266c26fd69fSDavid Howells { 267c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 268c26fd69fSDavid Howells 269c26fd69fSDavid Howells switch (ctx->last_oid) { 270c26fd69fSDavid Howells case OID_commonName: 271c26fd69fSDavid Howells ctx->cn_size = vlen; 272c26fd69fSDavid Howells ctx->cn_offset = (unsigned long)value - ctx->data; 273c26fd69fSDavid Howells break; 274c26fd69fSDavid Howells case OID_organizationName: 275c26fd69fSDavid Howells ctx->o_size = vlen; 276c26fd69fSDavid Howells ctx->o_offset = (unsigned long)value - ctx->data; 277c26fd69fSDavid Howells break; 278c26fd69fSDavid Howells case OID_email_address: 279c26fd69fSDavid Howells ctx->email_size = vlen; 280c26fd69fSDavid Howells ctx->email_offset = (unsigned long)value - ctx->data; 281c26fd69fSDavid Howells break; 282c26fd69fSDavid Howells default: 283c26fd69fSDavid Howells break; 284c26fd69fSDavid Howells } 285c26fd69fSDavid Howells 286c26fd69fSDavid Howells return 0; 287c26fd69fSDavid Howells } 288c26fd69fSDavid Howells 289c26fd69fSDavid Howells /* 290c26fd69fSDavid Howells * Fabricate and save the issuer and subject names 291c26fd69fSDavid Howells */ 292c26fd69fSDavid Howells static int x509_fabricate_name(struct x509_parse_context *ctx, size_t hdrlen, 293c26fd69fSDavid Howells unsigned char tag, 294c26fd69fSDavid Howells char **_name, size_t vlen) 295c26fd69fSDavid Howells { 296c26fd69fSDavid Howells const void *name, *data = (const void *)ctx->data; 297c26fd69fSDavid Howells size_t namesize; 298c26fd69fSDavid Howells char *buffer; 299c26fd69fSDavid Howells 300c26fd69fSDavid Howells if (*_name) 301c26fd69fSDavid Howells return -EINVAL; 302c26fd69fSDavid Howells 303c26fd69fSDavid Howells /* Empty name string if no material */ 304c26fd69fSDavid Howells if (!ctx->cn_size && !ctx->o_size && !ctx->email_size) { 305c26fd69fSDavid Howells buffer = kmalloc(1, GFP_KERNEL); 306c26fd69fSDavid Howells if (!buffer) 307c26fd69fSDavid Howells return -ENOMEM; 308c26fd69fSDavid Howells buffer[0] = 0; 309c26fd69fSDavid Howells goto done; 310c26fd69fSDavid Howells } 311c26fd69fSDavid Howells 312c26fd69fSDavid Howells if (ctx->cn_size && ctx->o_size) { 313c26fd69fSDavid Howells /* Consider combining O and CN, but use only the CN if it is 314c26fd69fSDavid Howells * prefixed by the O, or a significant portion thereof. 315c26fd69fSDavid Howells */ 316c26fd69fSDavid Howells namesize = ctx->cn_size; 317c26fd69fSDavid Howells name = data + ctx->cn_offset; 318c26fd69fSDavid Howells if (ctx->cn_size >= ctx->o_size && 319c26fd69fSDavid Howells memcmp(data + ctx->cn_offset, data + ctx->o_offset, 320c26fd69fSDavid Howells ctx->o_size) == 0) 321c26fd69fSDavid Howells goto single_component; 322c26fd69fSDavid Howells if (ctx->cn_size >= 7 && 323c26fd69fSDavid Howells ctx->o_size >= 7 && 324c26fd69fSDavid Howells memcmp(data + ctx->cn_offset, data + ctx->o_offset, 7) == 0) 325c26fd69fSDavid Howells goto single_component; 326c26fd69fSDavid Howells 327c26fd69fSDavid Howells buffer = kmalloc(ctx->o_size + 2 + ctx->cn_size + 1, 328c26fd69fSDavid Howells GFP_KERNEL); 329c26fd69fSDavid Howells if (!buffer) 330c26fd69fSDavid Howells return -ENOMEM; 331c26fd69fSDavid Howells 332c26fd69fSDavid Howells memcpy(buffer, 333c26fd69fSDavid Howells data + ctx->o_offset, ctx->o_size); 334c26fd69fSDavid Howells buffer[ctx->o_size + 0] = ':'; 335c26fd69fSDavid Howells buffer[ctx->o_size + 1] = ' '; 336c26fd69fSDavid Howells memcpy(buffer + ctx->o_size + 2, 337c26fd69fSDavid Howells data + ctx->cn_offset, ctx->cn_size); 338c26fd69fSDavid Howells buffer[ctx->o_size + 2 + ctx->cn_size] = 0; 339c26fd69fSDavid Howells goto done; 340c26fd69fSDavid Howells 341c26fd69fSDavid Howells } else if (ctx->cn_size) { 342c26fd69fSDavid Howells namesize = ctx->cn_size; 343c26fd69fSDavid Howells name = data + ctx->cn_offset; 344c26fd69fSDavid Howells } else if (ctx->o_size) { 345c26fd69fSDavid Howells namesize = ctx->o_size; 346c26fd69fSDavid Howells name = data + ctx->o_offset; 347c26fd69fSDavid Howells } else { 348c26fd69fSDavid Howells namesize = ctx->email_size; 349c26fd69fSDavid Howells name = data + ctx->email_offset; 350c26fd69fSDavid Howells } 351c26fd69fSDavid Howells 352c26fd69fSDavid Howells single_component: 353c26fd69fSDavid Howells buffer = kmalloc(namesize + 1, GFP_KERNEL); 354c26fd69fSDavid Howells if (!buffer) 355c26fd69fSDavid Howells return -ENOMEM; 356c26fd69fSDavid Howells memcpy(buffer, name, namesize); 357c26fd69fSDavid Howells buffer[namesize] = 0; 358c26fd69fSDavid Howells 359c26fd69fSDavid Howells done: 360c26fd69fSDavid Howells *_name = buffer; 361c26fd69fSDavid Howells ctx->cn_size = 0; 362c26fd69fSDavid Howells ctx->o_size = 0; 363c26fd69fSDavid Howells ctx->email_size = 0; 364c26fd69fSDavid Howells return 0; 365c26fd69fSDavid Howells } 366c26fd69fSDavid Howells 367c26fd69fSDavid Howells int x509_note_issuer(void *context, size_t hdrlen, 368c26fd69fSDavid Howells unsigned char tag, 369c26fd69fSDavid Howells const void *value, size_t vlen) 370c26fd69fSDavid Howells { 371c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 37284aabd46SDavid Howells ctx->cert->raw_issuer = value; 37384aabd46SDavid Howells ctx->cert->raw_issuer_size = vlen; 374c26fd69fSDavid Howells return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen); 375c26fd69fSDavid Howells } 376c26fd69fSDavid Howells 377c26fd69fSDavid Howells int x509_note_subject(void *context, size_t hdrlen, 378c26fd69fSDavid Howells unsigned char tag, 379c26fd69fSDavid Howells const void *value, size_t vlen) 380c26fd69fSDavid Howells { 381c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 38284aabd46SDavid Howells ctx->cert->raw_subject = value; 38384aabd46SDavid Howells ctx->cert->raw_subject_size = vlen; 384c26fd69fSDavid Howells return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen); 385c26fd69fSDavid Howells } 386c26fd69fSDavid Howells 387c26fd69fSDavid Howells /* 388c26fd69fSDavid Howells * Extract the data for the public key algorithm 389c26fd69fSDavid Howells */ 390c26fd69fSDavid Howells int x509_extract_key_data(void *context, size_t hdrlen, 391c26fd69fSDavid Howells unsigned char tag, 392c26fd69fSDavid Howells const void *value, size_t vlen) 393c26fd69fSDavid Howells { 394c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 395c26fd69fSDavid Howells 396c26fd69fSDavid Howells if (ctx->last_oid != OID_rsaEncryption) 397c26fd69fSDavid Howells return -ENOPKG; 398c26fd69fSDavid Howells 3994e8ae72aSDavid Howells ctx->cert->pub->pkey_algo = "rsa"; 40067f7d60bSDavid Howells 40167f7d60bSDavid Howells /* Discard the BIT STRING metadata */ 402c26fd69fSDavid Howells ctx->key = value + 1; 403c26fd69fSDavid Howells ctx->key_size = vlen - 1; 404c26fd69fSDavid Howells return 0; 405c26fd69fSDavid Howells } 406c26fd69fSDavid Howells 40704b00bdbSChun-Yi Lee /* The keyIdentifier in AuthorityKeyIdentifier SEQUENCE is tag(CONT,PRIM,0) */ 40804b00bdbSChun-Yi Lee #define SEQ_TAG_KEYID (ASN1_CONT << 6) 40904b00bdbSChun-Yi Lee 410c26fd69fSDavid Howells /* 411c26fd69fSDavid Howells * Process certificate extensions that are used to qualify the certificate. 412c26fd69fSDavid Howells */ 413c26fd69fSDavid Howells int x509_process_extension(void *context, size_t hdrlen, 414c26fd69fSDavid Howells unsigned char tag, 415c26fd69fSDavid Howells const void *value, size_t vlen) 416c26fd69fSDavid Howells { 417c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 41846963b77SDavid Howells struct asymmetric_key_id *kid; 419c26fd69fSDavid Howells const unsigned char *v = value; 420c26fd69fSDavid Howells 421c26fd69fSDavid Howells pr_debug("Extension: %u\n", ctx->last_oid); 422c26fd69fSDavid Howells 423c26fd69fSDavid Howells if (ctx->last_oid == OID_subjectKeyIdentifier) { 424c26fd69fSDavid Howells /* Get hold of the key fingerprint */ 42546963b77SDavid Howells if (ctx->cert->skid || vlen < 3) 426c26fd69fSDavid Howells return -EBADMSG; 427c26fd69fSDavid Howells if (v[0] != ASN1_OTS || v[1] != vlen - 2) 428c26fd69fSDavid Howells return -EBADMSG; 429c26fd69fSDavid Howells v += 2; 430c26fd69fSDavid Howells vlen -= 2; 431c26fd69fSDavid Howells 432dd2f6c44SDavid Howells ctx->cert->raw_skid_size = vlen; 433dd2f6c44SDavid Howells ctx->cert->raw_skid = v; 434a4c6e57fSDavid Howells kid = asymmetric_key_generate_id(v, vlen, "", 0); 43546963b77SDavid Howells if (IS_ERR(kid)) 43646963b77SDavid Howells return PTR_ERR(kid); 43746963b77SDavid Howells ctx->cert->skid = kid; 43846963b77SDavid Howells pr_debug("subjkeyid %*phN\n", kid->len, kid->data); 439c26fd69fSDavid Howells return 0; 440c26fd69fSDavid Howells } 441c26fd69fSDavid Howells 442c26fd69fSDavid Howells if (ctx->last_oid == OID_authorityKeyIdentifier) { 443c26fd69fSDavid Howells /* Get hold of the CA key fingerprint */ 444b92e6570SDavid Howells ctx->raw_akid = v; 445b92e6570SDavid Howells ctx->raw_akid_size = vlen; 446c26fd69fSDavid Howells return 0; 447c26fd69fSDavid Howells } 448c26fd69fSDavid Howells 449c26fd69fSDavid Howells return 0; 450c26fd69fSDavid Howells } 451c26fd69fSDavid Howells 452fd19a3d1SDavid Howells /** 453fd19a3d1SDavid Howells * x509_decode_time - Decode an X.509 time ASN.1 object 454fd19a3d1SDavid Howells * @_t: The time to fill in 455fd19a3d1SDavid Howells * @hdrlen: The length of the object header 456fd19a3d1SDavid Howells * @tag: The object tag 457fd19a3d1SDavid Howells * @value: The object value 458fd19a3d1SDavid Howells * @vlen: The size of the object value 459fd19a3d1SDavid Howells * 460fd19a3d1SDavid Howells * Decode an ASN.1 universal time or generalised time field into a struct the 461fd19a3d1SDavid Howells * kernel can handle and check it for validity. The time is decoded thus: 462fd19a3d1SDavid Howells * 463fd19a3d1SDavid Howells * [RFC5280 §4.1.2.5] 464fd19a3d1SDavid Howells * CAs conforming to this profile MUST always encode certificate validity 465fd19a3d1SDavid Howells * dates through the year 2049 as UTCTime; certificate validity dates in 466fd19a3d1SDavid Howells * 2050 or later MUST be encoded as GeneralizedTime. Conforming 467fd19a3d1SDavid Howells * applications MUST be able to process validity dates that are encoded in 468fd19a3d1SDavid Howells * either UTCTime or GeneralizedTime. 469c26fd69fSDavid Howells */ 470fd19a3d1SDavid Howells int x509_decode_time(time64_t *_t, size_t hdrlen, 471c26fd69fSDavid Howells unsigned char tag, 472c26fd69fSDavid Howells const unsigned char *value, size_t vlen) 473c26fd69fSDavid Howells { 474ac4cbedfSDavid Howells static const unsigned char month_lengths[] = { 31, 28, 31, 30, 31, 30, 475fd19a3d1SDavid Howells 31, 31, 30, 31, 30, 31 }; 476c26fd69fSDavid Howells const unsigned char *p = value; 477fd19a3d1SDavid Howells unsigned year, mon, day, hour, min, sec, mon_len; 478c26fd69fSDavid Howells 479fd19a3d1SDavid Howells #define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; }) 480c26fd69fSDavid Howells #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) 481c26fd69fSDavid Howells 482c26fd69fSDavid Howells if (tag == ASN1_UNITIM) { 483c26fd69fSDavid Howells /* UTCTime: YYMMDDHHMMSSZ */ 484c26fd69fSDavid Howells if (vlen != 13) 485c26fd69fSDavid Howells goto unsupported_time; 486fd19a3d1SDavid Howells year = DD2bin(p); 487fd19a3d1SDavid Howells if (year >= 50) 488fd19a3d1SDavid Howells year += 1900; 489c26fd69fSDavid Howells else 490fd19a3d1SDavid Howells year += 2000; 491c26fd69fSDavid Howells } else if (tag == ASN1_GENTIM) { 492c26fd69fSDavid Howells /* GenTime: YYYYMMDDHHMMSSZ */ 493c26fd69fSDavid Howells if (vlen != 15) 494c26fd69fSDavid Howells goto unsupported_time; 495fd19a3d1SDavid Howells year = DD2bin(p) * 100 + DD2bin(p); 496fd19a3d1SDavid Howells if (year >= 1950 && year <= 2049) 497fd19a3d1SDavid Howells goto invalid_time; 498c26fd69fSDavid Howells } else { 499c26fd69fSDavid Howells goto unsupported_time; 500c26fd69fSDavid Howells } 501c26fd69fSDavid Howells 502fd19a3d1SDavid Howells mon = DD2bin(p); 503fd19a3d1SDavid Howells day = DD2bin(p); 504fd19a3d1SDavid Howells hour = DD2bin(p); 505fd19a3d1SDavid Howells min = DD2bin(p); 506fd19a3d1SDavid Howells sec = DD2bin(p); 507c26fd69fSDavid Howells 508c26fd69fSDavid Howells if (*p != 'Z') 509c26fd69fSDavid Howells goto unsupported_time; 510c26fd69fSDavid Howells 511cc25b994SDavid Howells if (year < 1970 || 512cc25b994SDavid Howells mon < 1 || mon > 12) 513cc25b994SDavid Howells goto invalid_time; 514cc25b994SDavid Howells 515cc25b994SDavid Howells mon_len = month_lengths[mon - 1]; 516fd19a3d1SDavid Howells if (mon == 2) { 517fd19a3d1SDavid Howells if (year % 4 == 0) { 518fd19a3d1SDavid Howells mon_len = 29; 519fd19a3d1SDavid Howells if (year % 100 == 0) { 520fd19a3d1SDavid Howells mon_len = 28; 521ac4cbedfSDavid Howells if (year % 400 == 0) 522ac4cbedfSDavid Howells mon_len = 29; 523fd19a3d1SDavid Howells } 524fd19a3d1SDavid Howells } 525fd19a3d1SDavid Howells } 526fd19a3d1SDavid Howells 527cc25b994SDavid Howells if (day < 1 || day > mon_len || 5287650cb80SDavid Howells hour > 24 || /* ISO 8601 permits 24:00:00 as midnight tomorrow */ 5294dd17c9cSsudip min > 59 || 530da02559cSDavid Howells sec > 60) /* ISO 8601 permits leap seconds [X.680 46.3] */ 531fd19a3d1SDavid Howells goto invalid_time; 532fd19a3d1SDavid Howells 533fd19a3d1SDavid Howells *_t = mktime64(year, mon, day, hour, min, sec); 534c26fd69fSDavid Howells return 0; 535c26fd69fSDavid Howells 536c26fd69fSDavid Howells unsupported_time: 537fd19a3d1SDavid Howells pr_debug("Got unsupported time [tag %02x]: '%*phN'\n", 538fd19a3d1SDavid Howells tag, (int)vlen, value); 539fd19a3d1SDavid Howells return -EBADMSG; 540fd19a3d1SDavid Howells invalid_time: 541fd19a3d1SDavid Howells pr_debug("Got invalid time [tag %02x]: '%*phN'\n", 542fd19a3d1SDavid Howells tag, (int)vlen, value); 543c26fd69fSDavid Howells return -EBADMSG; 544c26fd69fSDavid Howells } 545fd19a3d1SDavid Howells EXPORT_SYMBOL_GPL(x509_decode_time); 546c26fd69fSDavid Howells 547c26fd69fSDavid Howells int x509_note_not_before(void *context, size_t hdrlen, 548c26fd69fSDavid Howells unsigned char tag, 549c26fd69fSDavid Howells const void *value, size_t vlen) 550c26fd69fSDavid Howells { 551c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 552fd19a3d1SDavid Howells return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); 553c26fd69fSDavid Howells } 554c26fd69fSDavid Howells 555c26fd69fSDavid Howells int x509_note_not_after(void *context, size_t hdrlen, 556c26fd69fSDavid Howells unsigned char tag, 557c26fd69fSDavid Howells const void *value, size_t vlen) 558c26fd69fSDavid Howells { 559c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 560fd19a3d1SDavid Howells return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); 561c26fd69fSDavid Howells } 562b92e6570SDavid Howells 563b92e6570SDavid Howells /* 564b92e6570SDavid Howells * Note a key identifier-based AuthorityKeyIdentifier 565b92e6570SDavid Howells */ 566b92e6570SDavid Howells int x509_akid_note_kid(void *context, size_t hdrlen, 567b92e6570SDavid Howells unsigned char tag, 568b92e6570SDavid Howells const void *value, size_t vlen) 569b92e6570SDavid Howells { 570b92e6570SDavid Howells struct x509_parse_context *ctx = context; 571b92e6570SDavid Howells struct asymmetric_key_id *kid; 572b92e6570SDavid Howells 573b92e6570SDavid Howells pr_debug("AKID: keyid: %*phN\n", (int)vlen, value); 574b92e6570SDavid Howells 57577d0910dSDavid Howells if (ctx->cert->sig->auth_ids[1]) 576b92e6570SDavid Howells return 0; 577b92e6570SDavid Howells 578a4c6e57fSDavid Howells kid = asymmetric_key_generate_id(value, vlen, "", 0); 579b92e6570SDavid Howells if (IS_ERR(kid)) 580b92e6570SDavid Howells return PTR_ERR(kid); 581b92e6570SDavid Howells pr_debug("authkeyid %*phN\n", kid->len, kid->data); 58277d0910dSDavid Howells ctx->cert->sig->auth_ids[1] = kid; 583b92e6570SDavid Howells return 0; 584b92e6570SDavid Howells } 585b92e6570SDavid Howells 586b92e6570SDavid Howells /* 587b92e6570SDavid Howells * Note a directoryName in an AuthorityKeyIdentifier 588b92e6570SDavid Howells */ 589b92e6570SDavid Howells int x509_akid_note_name(void *context, size_t hdrlen, 590b92e6570SDavid Howells unsigned char tag, 591b92e6570SDavid Howells const void *value, size_t vlen) 592b92e6570SDavid Howells { 593b92e6570SDavid Howells struct x509_parse_context *ctx = context; 594b92e6570SDavid Howells 595b92e6570SDavid Howells pr_debug("AKID: name: %*phN\n", (int)vlen, value); 596b92e6570SDavid Howells 597b92e6570SDavid Howells ctx->akid_raw_issuer = value; 598b92e6570SDavid Howells ctx->akid_raw_issuer_size = vlen; 599b92e6570SDavid Howells return 0; 600b92e6570SDavid Howells } 601b92e6570SDavid Howells 602b92e6570SDavid Howells /* 603b92e6570SDavid Howells * Note a serial number in an AuthorityKeyIdentifier 604b92e6570SDavid Howells */ 605b92e6570SDavid Howells int x509_akid_note_serial(void *context, size_t hdrlen, 606b92e6570SDavid Howells unsigned char tag, 607b92e6570SDavid Howells const void *value, size_t vlen) 608b92e6570SDavid Howells { 609b92e6570SDavid Howells struct x509_parse_context *ctx = context; 610b92e6570SDavid Howells struct asymmetric_key_id *kid; 611b92e6570SDavid Howells 612b92e6570SDavid Howells pr_debug("AKID: serial: %*phN\n", (int)vlen, value); 613b92e6570SDavid Howells 61477d0910dSDavid Howells if (!ctx->akid_raw_issuer || ctx->cert->sig->auth_ids[0]) 615b92e6570SDavid Howells return 0; 616b92e6570SDavid Howells 617b92e6570SDavid Howells kid = asymmetric_key_generate_id(value, 618b92e6570SDavid Howells vlen, 619b92e6570SDavid Howells ctx->akid_raw_issuer, 620b92e6570SDavid Howells ctx->akid_raw_issuer_size); 621b92e6570SDavid Howells if (IS_ERR(kid)) 622b92e6570SDavid Howells return PTR_ERR(kid); 623b92e6570SDavid Howells 624b92e6570SDavid Howells pr_debug("authkeyid %*phN\n", kid->len, kid->data); 62577d0910dSDavid Howells ctx->cert->sig->auth_ids[0] = kid; 626b92e6570SDavid Howells return 0; 627b92e6570SDavid Howells } 628