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> 18c26fd69fSDavid Howells #include "public_key.h" 19c26fd69fSDavid Howells #include "x509_parser.h" 20c26fd69fSDavid Howells #include "x509-asn1.h" 21b92e6570SDavid Howells #include "x509_akid-asn1.h" 22c26fd69fSDavid Howells #include "x509_rsakey-asn1.h" 23c26fd69fSDavid Howells 24c26fd69fSDavid Howells struct x509_parse_context { 25c26fd69fSDavid Howells struct x509_certificate *cert; /* Certificate being constructed */ 26c26fd69fSDavid Howells unsigned long data; /* Start of data */ 27c26fd69fSDavid Howells const void *cert_start; /* Start of cert content */ 28c26fd69fSDavid Howells const void *key; /* Key data */ 29c26fd69fSDavid Howells size_t key_size; /* Size of key data */ 30c26fd69fSDavid Howells enum OID last_oid; /* Last OID encountered */ 31c26fd69fSDavid Howells enum OID algo_oid; /* Algorithm OID */ 32c26fd69fSDavid Howells unsigned char nr_mpi; /* Number of MPIs stored */ 33c26fd69fSDavid Howells u8 o_size; /* Size of organizationName (O) */ 34c26fd69fSDavid Howells u8 cn_size; /* Size of commonName (CN) */ 35c26fd69fSDavid Howells u8 email_size; /* Size of emailAddress */ 36c26fd69fSDavid Howells u16 o_offset; /* Offset of organizationName (O) */ 37c26fd69fSDavid Howells u16 cn_offset; /* Offset of commonName (CN) */ 38c26fd69fSDavid Howells u16 email_offset; /* Offset of emailAddress */ 39b92e6570SDavid Howells unsigned raw_akid_size; 40b92e6570SDavid Howells const void *raw_akid; /* Raw authorityKeyId in ASN.1 */ 41b92e6570SDavid Howells const void *akid_raw_issuer; /* Raw directoryName in authorityKeyId */ 42b92e6570SDavid Howells unsigned akid_raw_issuer_size; 43c26fd69fSDavid Howells }; 44c26fd69fSDavid Howells 45c26fd69fSDavid Howells /* 46c26fd69fSDavid Howells * Free an X.509 certificate 47c26fd69fSDavid Howells */ 48c26fd69fSDavid Howells void x509_free_certificate(struct x509_certificate *cert) 49c26fd69fSDavid Howells { 50c26fd69fSDavid Howells if (cert) { 51c26fd69fSDavid Howells public_key_destroy(cert->pub); 52c26fd69fSDavid Howells kfree(cert->issuer); 53c26fd69fSDavid Howells kfree(cert->subject); 5446963b77SDavid Howells kfree(cert->id); 5546963b77SDavid Howells kfree(cert->skid); 56b92e6570SDavid Howells kfree(cert->akid_id); 57b92e6570SDavid Howells kfree(cert->akid_skid); 58b426beb6SDavid Howells kfree(cert->sig.digest); 59b426beb6SDavid Howells mpi_free(cert->sig.rsa.s); 60c26fd69fSDavid Howells kfree(cert); 61c26fd69fSDavid Howells } 62c26fd69fSDavid Howells } 63ace0107aSDavid Howells EXPORT_SYMBOL_GPL(x509_free_certificate); 64c26fd69fSDavid Howells 65c26fd69fSDavid Howells /* 66c26fd69fSDavid Howells * Parse an X.509 certificate 67c26fd69fSDavid Howells */ 68c26fd69fSDavid Howells struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) 69c26fd69fSDavid Howells { 70c26fd69fSDavid Howells struct x509_certificate *cert; 71c26fd69fSDavid Howells struct x509_parse_context *ctx; 7246963b77SDavid Howells struct asymmetric_key_id *kid; 73c26fd69fSDavid Howells long ret; 74c26fd69fSDavid Howells 75c26fd69fSDavid Howells ret = -ENOMEM; 76c26fd69fSDavid Howells cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL); 77c26fd69fSDavid Howells if (!cert) 78c26fd69fSDavid Howells goto error_no_cert; 79c26fd69fSDavid Howells cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL); 80c26fd69fSDavid Howells if (!cert->pub) 81c26fd69fSDavid Howells goto error_no_ctx; 82c26fd69fSDavid Howells ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL); 83c26fd69fSDavid Howells if (!ctx) 84c26fd69fSDavid Howells goto error_no_ctx; 85c26fd69fSDavid Howells 86c26fd69fSDavid Howells ctx->cert = cert; 87c26fd69fSDavid Howells ctx->data = (unsigned long)data; 88c26fd69fSDavid Howells 89c26fd69fSDavid Howells /* Attempt to decode the certificate */ 90c26fd69fSDavid Howells ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen); 91c26fd69fSDavid Howells if (ret < 0) 92c26fd69fSDavid Howells goto error_decode; 93c26fd69fSDavid Howells 94b92e6570SDavid Howells /* Decode the AuthorityKeyIdentifier */ 95b92e6570SDavid Howells if (ctx->raw_akid) { 96b92e6570SDavid Howells pr_devel("AKID: %u %*phN\n", 97b92e6570SDavid Howells ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid); 98b92e6570SDavid Howells ret = asn1_ber_decoder(&x509_akid_decoder, ctx, 99b92e6570SDavid Howells ctx->raw_akid, ctx->raw_akid_size); 100b92e6570SDavid Howells if (ret < 0) { 101b92e6570SDavid Howells pr_warn("Couldn't decode AuthKeyIdentifier\n"); 102b92e6570SDavid Howells goto error_decode; 103b92e6570SDavid Howells } 104b92e6570SDavid Howells } 105b92e6570SDavid Howells 106c26fd69fSDavid Howells /* Decode the public key */ 107c26fd69fSDavid Howells ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, 108c26fd69fSDavid Howells ctx->key, ctx->key_size); 109c26fd69fSDavid Howells if (ret < 0) 110c26fd69fSDavid Howells goto error_decode; 111c26fd69fSDavid Howells 11246963b77SDavid Howells /* Generate cert issuer + serial number key ID */ 11346963b77SDavid Howells kid = asymmetric_key_generate_id(cert->raw_serial, 11446963b77SDavid Howells cert->raw_serial_size, 11546963b77SDavid Howells cert->raw_issuer, 11646963b77SDavid Howells cert->raw_issuer_size); 11746963b77SDavid Howells if (IS_ERR(kid)) { 11846963b77SDavid Howells ret = PTR_ERR(kid); 11946963b77SDavid Howells goto error_decode; 12046963b77SDavid Howells } 12146963b77SDavid Howells cert->id = kid; 12246963b77SDavid Howells 123c26fd69fSDavid Howells kfree(ctx); 124c26fd69fSDavid Howells return cert; 125c26fd69fSDavid Howells 126c26fd69fSDavid Howells error_decode: 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: 1913fe78ca2SDmitry Kasatkin ctx->cert->sig.pkey_hash_algo = HASH_ALGO_MD5; 192b426beb6SDavid Howells ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; 193c26fd69fSDavid Howells break; 194c26fd69fSDavid Howells 195c26fd69fSDavid Howells case OID_sha1WithRSAEncryption: 1963fe78ca2SDmitry Kasatkin ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA1; 197b426beb6SDavid Howells ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; 198c26fd69fSDavid Howells break; 199c26fd69fSDavid Howells 200c26fd69fSDavid Howells case OID_sha256WithRSAEncryption: 2013fe78ca2SDmitry Kasatkin ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA256; 202b426beb6SDavid Howells ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; 203c26fd69fSDavid Howells break; 204c26fd69fSDavid Howells 205c26fd69fSDavid Howells case OID_sha384WithRSAEncryption: 2063fe78ca2SDmitry Kasatkin ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA384; 207b426beb6SDavid Howells ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; 208c26fd69fSDavid Howells break; 209c26fd69fSDavid Howells 210c26fd69fSDavid Howells case OID_sha512WithRSAEncryption: 2113fe78ca2SDmitry Kasatkin ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA512; 212b426beb6SDavid Howells ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; 213c26fd69fSDavid Howells break; 214c26fd69fSDavid Howells 215c26fd69fSDavid Howells case OID_sha224WithRSAEncryption: 2163fe78ca2SDmitry Kasatkin ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA224; 217b426beb6SDavid Howells ctx->cert->sig.pkey_algo = 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 39967f7d60bSDavid Howells ctx->cert->pub->pkey_algo = 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 407c26fd69fSDavid Howells /* 408c26fd69fSDavid Howells * Extract a RSA public key value 409c26fd69fSDavid Howells */ 410c26fd69fSDavid Howells int rsa_extract_mpi(void *context, size_t hdrlen, 411c26fd69fSDavid Howells unsigned char tag, 412c26fd69fSDavid Howells const void *value, size_t vlen) 413c26fd69fSDavid Howells { 414c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 415c26fd69fSDavid Howells MPI mpi; 416c26fd69fSDavid Howells 417c26fd69fSDavid Howells if (ctx->nr_mpi >= ARRAY_SIZE(ctx->cert->pub->mpi)) { 418c26fd69fSDavid Howells pr_err("Too many public key MPIs in certificate\n"); 419c26fd69fSDavid Howells return -EBADMSG; 420c26fd69fSDavid Howells } 421c26fd69fSDavid Howells 422c26fd69fSDavid Howells mpi = mpi_read_raw_data(value, vlen); 423c26fd69fSDavid Howells if (!mpi) 424c26fd69fSDavid Howells return -ENOMEM; 425c26fd69fSDavid Howells 426c26fd69fSDavid Howells ctx->cert->pub->mpi[ctx->nr_mpi++] = mpi; 427c26fd69fSDavid Howells return 0; 428c26fd69fSDavid Howells } 429c26fd69fSDavid Howells 43004b00bdbSChun-Yi Lee /* The keyIdentifier in AuthorityKeyIdentifier SEQUENCE is tag(CONT,PRIM,0) */ 43104b00bdbSChun-Yi Lee #define SEQ_TAG_KEYID (ASN1_CONT << 6) 43204b00bdbSChun-Yi Lee 433c26fd69fSDavid Howells /* 434c26fd69fSDavid Howells * Process certificate extensions that are used to qualify the certificate. 435c26fd69fSDavid Howells */ 436c26fd69fSDavid Howells int x509_process_extension(void *context, size_t hdrlen, 437c26fd69fSDavid Howells unsigned char tag, 438c26fd69fSDavid Howells const void *value, size_t vlen) 439c26fd69fSDavid Howells { 440c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 44146963b77SDavid Howells struct asymmetric_key_id *kid; 442c26fd69fSDavid Howells const unsigned char *v = value; 443c26fd69fSDavid Howells 444c26fd69fSDavid Howells pr_debug("Extension: %u\n", ctx->last_oid); 445c26fd69fSDavid Howells 446c26fd69fSDavid Howells if (ctx->last_oid == OID_subjectKeyIdentifier) { 447c26fd69fSDavid Howells /* Get hold of the key fingerprint */ 44846963b77SDavid Howells if (ctx->cert->skid || vlen < 3) 449c26fd69fSDavid Howells return -EBADMSG; 450c26fd69fSDavid Howells if (v[0] != ASN1_OTS || v[1] != vlen - 2) 451c26fd69fSDavid Howells return -EBADMSG; 452c26fd69fSDavid Howells v += 2; 453c26fd69fSDavid Howells vlen -= 2; 454c26fd69fSDavid Howells 455dd2f6c44SDavid Howells ctx->cert->raw_skid_size = vlen; 456dd2f6c44SDavid Howells ctx->cert->raw_skid = v; 457a4c6e57fSDavid Howells kid = asymmetric_key_generate_id(v, vlen, "", 0); 45846963b77SDavid Howells if (IS_ERR(kid)) 45946963b77SDavid Howells return PTR_ERR(kid); 46046963b77SDavid Howells ctx->cert->skid = kid; 46146963b77SDavid Howells pr_debug("subjkeyid %*phN\n", kid->len, kid->data); 462c26fd69fSDavid Howells return 0; 463c26fd69fSDavid Howells } 464c26fd69fSDavid Howells 465c26fd69fSDavid Howells if (ctx->last_oid == OID_authorityKeyIdentifier) { 466c26fd69fSDavid Howells /* Get hold of the CA key fingerprint */ 467b92e6570SDavid Howells ctx->raw_akid = v; 468b92e6570SDavid Howells ctx->raw_akid_size = vlen; 469c26fd69fSDavid Howells return 0; 470c26fd69fSDavid Howells } 471c26fd69fSDavid Howells 472c26fd69fSDavid Howells return 0; 473c26fd69fSDavid Howells } 474c26fd69fSDavid Howells 475fd19a3d1SDavid Howells /** 476fd19a3d1SDavid Howells * x509_decode_time - Decode an X.509 time ASN.1 object 477fd19a3d1SDavid Howells * @_t: The time to fill in 478fd19a3d1SDavid Howells * @hdrlen: The length of the object header 479fd19a3d1SDavid Howells * @tag: The object tag 480fd19a3d1SDavid Howells * @value: The object value 481fd19a3d1SDavid Howells * @vlen: The size of the object value 482fd19a3d1SDavid Howells * 483fd19a3d1SDavid Howells * Decode an ASN.1 universal time or generalised time field into a struct the 484fd19a3d1SDavid Howells * kernel can handle and check it for validity. The time is decoded thus: 485fd19a3d1SDavid Howells * 486fd19a3d1SDavid Howells * [RFC5280 §4.1.2.5] 487fd19a3d1SDavid Howells * CAs conforming to this profile MUST always encode certificate validity 488fd19a3d1SDavid Howells * dates through the year 2049 as UTCTime; certificate validity dates in 489fd19a3d1SDavid Howells * 2050 or later MUST be encoded as GeneralizedTime. Conforming 490fd19a3d1SDavid Howells * applications MUST be able to process validity dates that are encoded in 491fd19a3d1SDavid Howells * either UTCTime or GeneralizedTime. 492c26fd69fSDavid Howells */ 493fd19a3d1SDavid Howells int x509_decode_time(time64_t *_t, size_t hdrlen, 494c26fd69fSDavid Howells unsigned char tag, 495c26fd69fSDavid Howells const unsigned char *value, size_t vlen) 496c26fd69fSDavid Howells { 497fd19a3d1SDavid Howells static const unsigned char month_lengths[] = { 31, 29, 31, 30, 31, 30, 498fd19a3d1SDavid Howells 31, 31, 30, 31, 30, 31 }; 499c26fd69fSDavid Howells const unsigned char *p = value; 500fd19a3d1SDavid Howells unsigned year, mon, day, hour, min, sec, mon_len; 501c26fd69fSDavid Howells 502fd19a3d1SDavid Howells #define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; }) 503c26fd69fSDavid Howells #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) 504c26fd69fSDavid Howells 505c26fd69fSDavid Howells if (tag == ASN1_UNITIM) { 506c26fd69fSDavid Howells /* UTCTime: YYMMDDHHMMSSZ */ 507c26fd69fSDavid Howells if (vlen != 13) 508c26fd69fSDavid Howells goto unsupported_time; 509fd19a3d1SDavid Howells year = DD2bin(p); 510fd19a3d1SDavid Howells if (year >= 50) 511fd19a3d1SDavid Howells year += 1900; 512c26fd69fSDavid Howells else 513fd19a3d1SDavid Howells year += 2000; 514c26fd69fSDavid Howells } else if (tag == ASN1_GENTIM) { 515c26fd69fSDavid Howells /* GenTime: YYYYMMDDHHMMSSZ */ 516c26fd69fSDavid Howells if (vlen != 15) 517c26fd69fSDavid Howells goto unsupported_time; 518fd19a3d1SDavid Howells year = DD2bin(p) * 100 + DD2bin(p); 519fd19a3d1SDavid Howells if (year >= 1950 && year <= 2049) 520fd19a3d1SDavid Howells goto invalid_time; 521c26fd69fSDavid Howells } else { 522c26fd69fSDavid Howells goto unsupported_time; 523c26fd69fSDavid Howells } 524c26fd69fSDavid Howells 525fd19a3d1SDavid Howells mon = DD2bin(p); 526fd19a3d1SDavid Howells day = DD2bin(p); 527fd19a3d1SDavid Howells hour = DD2bin(p); 528fd19a3d1SDavid Howells min = DD2bin(p); 529fd19a3d1SDavid Howells sec = DD2bin(p); 530c26fd69fSDavid Howells 531c26fd69fSDavid Howells if (*p != 'Z') 532c26fd69fSDavid Howells goto unsupported_time; 533c26fd69fSDavid Howells 534cc25b994SDavid Howells if (year < 1970 || 535cc25b994SDavid Howells mon < 1 || mon > 12) 536cc25b994SDavid Howells goto invalid_time; 537cc25b994SDavid Howells 538cc25b994SDavid Howells mon_len = month_lengths[mon - 1]; 539fd19a3d1SDavid Howells if (mon == 2) { 540fd19a3d1SDavid Howells if (year % 4 == 0) { 541fd19a3d1SDavid Howells mon_len = 29; 542fd19a3d1SDavid Howells if (year % 100 == 0) { 543fd19a3d1SDavid Howells year /= 100; 544fd19a3d1SDavid Howells if (year % 4 != 0) 545fd19a3d1SDavid Howells mon_len = 28; 546fd19a3d1SDavid Howells } 547fd19a3d1SDavid Howells } 548fd19a3d1SDavid Howells } 549fd19a3d1SDavid Howells 550cc25b994SDavid Howells if (day < 1 || day > mon_len || 5514dd17c9cSsudip hour > 23 || 5524dd17c9cSsudip min > 59 || 5534dd17c9cSsudip sec > 59) 554fd19a3d1SDavid Howells goto invalid_time; 555fd19a3d1SDavid Howells 556fd19a3d1SDavid Howells *_t = mktime64(year, mon, day, hour, min, sec); 557c26fd69fSDavid Howells return 0; 558c26fd69fSDavid Howells 559c26fd69fSDavid Howells unsupported_time: 560fd19a3d1SDavid Howells pr_debug("Got unsupported time [tag %02x]: '%*phN'\n", 561fd19a3d1SDavid Howells tag, (int)vlen, value); 562fd19a3d1SDavid Howells return -EBADMSG; 563fd19a3d1SDavid Howells invalid_time: 564fd19a3d1SDavid Howells pr_debug("Got invalid time [tag %02x]: '%*phN'\n", 565fd19a3d1SDavid Howells tag, (int)vlen, value); 566c26fd69fSDavid Howells return -EBADMSG; 567c26fd69fSDavid Howells } 568fd19a3d1SDavid Howells EXPORT_SYMBOL_GPL(x509_decode_time); 569c26fd69fSDavid Howells 570c26fd69fSDavid Howells int x509_note_not_before(void *context, size_t hdrlen, 571c26fd69fSDavid Howells unsigned char tag, 572c26fd69fSDavid Howells const void *value, size_t vlen) 573c26fd69fSDavid Howells { 574c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 575fd19a3d1SDavid Howells return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); 576c26fd69fSDavid Howells } 577c26fd69fSDavid Howells 578c26fd69fSDavid Howells int x509_note_not_after(void *context, size_t hdrlen, 579c26fd69fSDavid Howells unsigned char tag, 580c26fd69fSDavid Howells const void *value, size_t vlen) 581c26fd69fSDavid Howells { 582c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 583fd19a3d1SDavid Howells return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); 584c26fd69fSDavid Howells } 585b92e6570SDavid Howells 586b92e6570SDavid Howells /* 587b92e6570SDavid Howells * Note a key identifier-based AuthorityKeyIdentifier 588b92e6570SDavid Howells */ 589b92e6570SDavid Howells int x509_akid_note_kid(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 struct asymmetric_key_id *kid; 595b92e6570SDavid Howells 596b92e6570SDavid Howells pr_debug("AKID: keyid: %*phN\n", (int)vlen, value); 597b92e6570SDavid Howells 598b92e6570SDavid Howells if (ctx->cert->akid_skid) 599b92e6570SDavid Howells return 0; 600b92e6570SDavid Howells 601a4c6e57fSDavid Howells kid = asymmetric_key_generate_id(value, vlen, "", 0); 602b92e6570SDavid Howells if (IS_ERR(kid)) 603b92e6570SDavid Howells return PTR_ERR(kid); 604b92e6570SDavid Howells pr_debug("authkeyid %*phN\n", kid->len, kid->data); 605b92e6570SDavid Howells ctx->cert->akid_skid = kid; 606b92e6570SDavid Howells return 0; 607b92e6570SDavid Howells } 608b92e6570SDavid Howells 609b92e6570SDavid Howells /* 610b92e6570SDavid Howells * Note a directoryName in an AuthorityKeyIdentifier 611b92e6570SDavid Howells */ 612b92e6570SDavid Howells int x509_akid_note_name(void *context, size_t hdrlen, 613b92e6570SDavid Howells unsigned char tag, 614b92e6570SDavid Howells const void *value, size_t vlen) 615b92e6570SDavid Howells { 616b92e6570SDavid Howells struct x509_parse_context *ctx = context; 617b92e6570SDavid Howells 618b92e6570SDavid Howells pr_debug("AKID: name: %*phN\n", (int)vlen, value); 619b92e6570SDavid Howells 620b92e6570SDavid Howells ctx->akid_raw_issuer = value; 621b92e6570SDavid Howells ctx->akid_raw_issuer_size = vlen; 622b92e6570SDavid Howells return 0; 623b92e6570SDavid Howells } 624b92e6570SDavid Howells 625b92e6570SDavid Howells /* 626b92e6570SDavid Howells * Note a serial number in an AuthorityKeyIdentifier 627b92e6570SDavid Howells */ 628b92e6570SDavid Howells int x509_akid_note_serial(void *context, size_t hdrlen, 629b92e6570SDavid Howells unsigned char tag, 630b92e6570SDavid Howells const void *value, size_t vlen) 631b92e6570SDavid Howells { 632b92e6570SDavid Howells struct x509_parse_context *ctx = context; 633b92e6570SDavid Howells struct asymmetric_key_id *kid; 634b92e6570SDavid Howells 635b92e6570SDavid Howells pr_debug("AKID: serial: %*phN\n", (int)vlen, value); 636b92e6570SDavid Howells 637b92e6570SDavid Howells if (!ctx->akid_raw_issuer || ctx->cert->akid_id) 638b92e6570SDavid Howells return 0; 639b92e6570SDavid Howells 640b92e6570SDavid Howells kid = asymmetric_key_generate_id(value, 641b92e6570SDavid Howells vlen, 642b92e6570SDavid Howells ctx->akid_raw_issuer, 643b92e6570SDavid Howells ctx->akid_raw_issuer_size); 644b92e6570SDavid Howells if (IS_ERR(kid)) 645b92e6570SDavid Howells return PTR_ERR(kid); 646b92e6570SDavid Howells 647b92e6570SDavid Howells pr_debug("authkeyid %*phN\n", kid->len, kid->data); 648b92e6570SDavid Howells ctx->cert->akid_id = kid; 649b92e6570SDavid Howells return 0; 650b92e6570SDavid Howells } 651