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> 14c26fd69fSDavid Howells #include <linux/slab.h> 15c26fd69fSDavid Howells #include <linux/err.h> 16c26fd69fSDavid Howells #include <linux/oid_registry.h> 17c26fd69fSDavid Howells #include "public_key.h" 18c26fd69fSDavid Howells #include "x509_parser.h" 19c26fd69fSDavid Howells #include "x509-asn1.h" 20c26fd69fSDavid Howells #include "x509_rsakey-asn1.h" 21c26fd69fSDavid Howells 22c26fd69fSDavid Howells struct x509_parse_context { 23c26fd69fSDavid Howells struct x509_certificate *cert; /* Certificate being constructed */ 24c26fd69fSDavid Howells unsigned long data; /* Start of data */ 25c26fd69fSDavid Howells const void *cert_start; /* Start of cert content */ 26c26fd69fSDavid Howells const void *key; /* Key data */ 27c26fd69fSDavid Howells size_t key_size; /* Size of key data */ 28c26fd69fSDavid Howells enum OID last_oid; /* Last OID encountered */ 29c26fd69fSDavid Howells enum OID algo_oid; /* Algorithm OID */ 30c26fd69fSDavid Howells unsigned char nr_mpi; /* Number of MPIs stored */ 31c26fd69fSDavid Howells u8 o_size; /* Size of organizationName (O) */ 32c26fd69fSDavid Howells u8 cn_size; /* Size of commonName (CN) */ 33c26fd69fSDavid Howells u8 email_size; /* Size of emailAddress */ 34c26fd69fSDavid Howells u16 o_offset; /* Offset of organizationName (O) */ 35c26fd69fSDavid Howells u16 cn_offset; /* Offset of commonName (CN) */ 36c26fd69fSDavid Howells u16 email_offset; /* Offset of emailAddress */ 37c26fd69fSDavid Howells }; 38c26fd69fSDavid Howells 39c26fd69fSDavid Howells /* 40c26fd69fSDavid Howells * Free an X.509 certificate 41c26fd69fSDavid Howells */ 42c26fd69fSDavid Howells void x509_free_certificate(struct x509_certificate *cert) 43c26fd69fSDavid Howells { 44c26fd69fSDavid Howells if (cert) { 45c26fd69fSDavid Howells public_key_destroy(cert->pub); 46c26fd69fSDavid Howells kfree(cert->issuer); 47c26fd69fSDavid Howells kfree(cert->subject); 48c26fd69fSDavid Howells kfree(cert->fingerprint); 49c26fd69fSDavid Howells kfree(cert->authority); 50b426beb6SDavid Howells kfree(cert->sig.digest); 51b426beb6SDavid Howells mpi_free(cert->sig.rsa.s); 52c26fd69fSDavid Howells kfree(cert); 53c26fd69fSDavid Howells } 54c26fd69fSDavid Howells } 55c26fd69fSDavid Howells 56c26fd69fSDavid Howells /* 57c26fd69fSDavid Howells * Parse an X.509 certificate 58c26fd69fSDavid Howells */ 59c26fd69fSDavid Howells struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) 60c26fd69fSDavid Howells { 61c26fd69fSDavid Howells struct x509_certificate *cert; 62c26fd69fSDavid Howells struct x509_parse_context *ctx; 63c26fd69fSDavid Howells long ret; 64c26fd69fSDavid Howells 65c26fd69fSDavid Howells ret = -ENOMEM; 66c26fd69fSDavid Howells cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL); 67c26fd69fSDavid Howells if (!cert) 68c26fd69fSDavid Howells goto error_no_cert; 69c26fd69fSDavid Howells cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL); 70c26fd69fSDavid Howells if (!cert->pub) 71c26fd69fSDavid Howells goto error_no_ctx; 72c26fd69fSDavid Howells ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL); 73c26fd69fSDavid Howells if (!ctx) 74c26fd69fSDavid Howells goto error_no_ctx; 75c26fd69fSDavid Howells 76c26fd69fSDavid Howells ctx->cert = cert; 77c26fd69fSDavid Howells ctx->data = (unsigned long)data; 78c26fd69fSDavid Howells 79c26fd69fSDavid Howells /* Attempt to decode the certificate */ 80c26fd69fSDavid Howells ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen); 81c26fd69fSDavid Howells if (ret < 0) 82c26fd69fSDavid Howells goto error_decode; 83c26fd69fSDavid Howells 84c26fd69fSDavid Howells /* Decode the public key */ 85c26fd69fSDavid Howells ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, 86c26fd69fSDavid Howells ctx->key, ctx->key_size); 87c26fd69fSDavid Howells if (ret < 0) 88c26fd69fSDavid Howells goto error_decode; 89c26fd69fSDavid Howells 90c26fd69fSDavid Howells kfree(ctx); 91c26fd69fSDavid Howells return cert; 92c26fd69fSDavid Howells 93c26fd69fSDavid Howells error_decode: 94c26fd69fSDavid Howells kfree(ctx); 95c26fd69fSDavid Howells error_no_ctx: 96c26fd69fSDavid Howells x509_free_certificate(cert); 97c26fd69fSDavid Howells error_no_cert: 98c26fd69fSDavid Howells return ERR_PTR(ret); 99c26fd69fSDavid Howells } 100c26fd69fSDavid Howells 101c26fd69fSDavid Howells /* 102c26fd69fSDavid Howells * Note an OID when we find one for later processing when we know how 103c26fd69fSDavid Howells * to interpret it. 104c26fd69fSDavid Howells */ 105c26fd69fSDavid Howells int x509_note_OID(void *context, size_t hdrlen, 106c26fd69fSDavid Howells unsigned char tag, 107c26fd69fSDavid Howells const void *value, size_t vlen) 108c26fd69fSDavid Howells { 109c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 110c26fd69fSDavid Howells 111c26fd69fSDavid Howells ctx->last_oid = look_up_OID(value, vlen); 112c26fd69fSDavid Howells if (ctx->last_oid == OID__NR) { 113c26fd69fSDavid Howells char buffer[50]; 114c26fd69fSDavid Howells sprint_oid(value, vlen, buffer, sizeof(buffer)); 115cf75446eSRandy Dunlap pr_debug("Unknown OID: [%lu] %s\n", 116c26fd69fSDavid Howells (unsigned long)value - ctx->data, buffer); 117c26fd69fSDavid Howells } 118c26fd69fSDavid Howells return 0; 119c26fd69fSDavid Howells } 120c26fd69fSDavid Howells 121c26fd69fSDavid Howells /* 122c26fd69fSDavid Howells * Save the position of the TBS data so that we can check the signature over it 123c26fd69fSDavid Howells * later. 124c26fd69fSDavid Howells */ 125c26fd69fSDavid Howells int x509_note_tbs_certificate(void *context, size_t hdrlen, 126c26fd69fSDavid Howells unsigned char tag, 127c26fd69fSDavid Howells const void *value, size_t vlen) 128c26fd69fSDavid Howells { 129c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 130c26fd69fSDavid Howells 131c26fd69fSDavid Howells pr_debug("x509_note_tbs_certificate(,%zu,%02x,%ld,%zu)!\n", 132c26fd69fSDavid Howells hdrlen, tag, (unsigned long)value - ctx->data, vlen); 133c26fd69fSDavid Howells 134c26fd69fSDavid Howells ctx->cert->tbs = value - hdrlen; 135c26fd69fSDavid Howells ctx->cert->tbs_size = vlen + hdrlen; 136c26fd69fSDavid Howells return 0; 137c26fd69fSDavid Howells } 138c26fd69fSDavid Howells 139c26fd69fSDavid Howells /* 140c26fd69fSDavid Howells * Record the public key algorithm 141c26fd69fSDavid Howells */ 142c26fd69fSDavid Howells int x509_note_pkey_algo(void *context, size_t hdrlen, 143c26fd69fSDavid Howells unsigned char tag, 144c26fd69fSDavid Howells const void *value, size_t vlen) 145c26fd69fSDavid Howells { 146c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 147c26fd69fSDavid Howells 148c26fd69fSDavid Howells pr_debug("PubKey Algo: %u\n", ctx->last_oid); 149c26fd69fSDavid Howells 150c26fd69fSDavid Howells switch (ctx->last_oid) { 151c26fd69fSDavid Howells case OID_md2WithRSAEncryption: 152c26fd69fSDavid Howells case OID_md3WithRSAEncryption: 153c26fd69fSDavid Howells default: 154c26fd69fSDavid Howells return -ENOPKG; /* Unsupported combination */ 155c26fd69fSDavid Howells 156c26fd69fSDavid Howells case OID_md4WithRSAEncryption: 1573fe78ca2SDmitry Kasatkin ctx->cert->sig.pkey_hash_algo = HASH_ALGO_MD5; 158b426beb6SDavid Howells ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; 159c26fd69fSDavid Howells break; 160c26fd69fSDavid Howells 161c26fd69fSDavid Howells case OID_sha1WithRSAEncryption: 1623fe78ca2SDmitry Kasatkin ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA1; 163b426beb6SDavid Howells ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; 164c26fd69fSDavid Howells break; 165c26fd69fSDavid Howells 166c26fd69fSDavid Howells case OID_sha256WithRSAEncryption: 1673fe78ca2SDmitry Kasatkin ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA256; 168b426beb6SDavid Howells ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; 169c26fd69fSDavid Howells break; 170c26fd69fSDavid Howells 171c26fd69fSDavid Howells case OID_sha384WithRSAEncryption: 1723fe78ca2SDmitry Kasatkin ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA384; 173b426beb6SDavid Howells ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; 174c26fd69fSDavid Howells break; 175c26fd69fSDavid Howells 176c26fd69fSDavid Howells case OID_sha512WithRSAEncryption: 1773fe78ca2SDmitry Kasatkin ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA512; 178b426beb6SDavid Howells ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; 179c26fd69fSDavid Howells break; 180c26fd69fSDavid Howells 181c26fd69fSDavid Howells case OID_sha224WithRSAEncryption: 1823fe78ca2SDmitry Kasatkin ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA224; 183b426beb6SDavid Howells ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; 184c26fd69fSDavid Howells break; 185c26fd69fSDavid Howells } 186c26fd69fSDavid Howells 187c26fd69fSDavid Howells ctx->algo_oid = ctx->last_oid; 188c26fd69fSDavid Howells return 0; 189c26fd69fSDavid Howells } 190c26fd69fSDavid Howells 191c26fd69fSDavid Howells /* 192c26fd69fSDavid Howells * Note the whereabouts and type of the signature. 193c26fd69fSDavid Howells */ 194c26fd69fSDavid Howells int x509_note_signature(void *context, size_t hdrlen, 195c26fd69fSDavid Howells unsigned char tag, 196c26fd69fSDavid Howells const void *value, size_t vlen) 197c26fd69fSDavid Howells { 198c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 199c26fd69fSDavid Howells 200c26fd69fSDavid Howells pr_debug("Signature type: %u size %zu\n", ctx->last_oid, vlen); 201c26fd69fSDavid Howells 202c26fd69fSDavid Howells if (ctx->last_oid != ctx->algo_oid) { 203c26fd69fSDavid Howells pr_warn("Got cert with pkey (%u) and sig (%u) algorithm OIDs\n", 204c26fd69fSDavid Howells ctx->algo_oid, ctx->last_oid); 205c26fd69fSDavid Howells return -EINVAL; 206c26fd69fSDavid Howells } 207c26fd69fSDavid Howells 208b426beb6SDavid Howells ctx->cert->raw_sig = value; 209b426beb6SDavid Howells ctx->cert->raw_sig_size = vlen; 210c26fd69fSDavid Howells return 0; 211c26fd69fSDavid Howells } 212c26fd69fSDavid Howells 213c26fd69fSDavid Howells /* 214c26fd69fSDavid Howells * Note some of the name segments from which we'll fabricate a name. 215c26fd69fSDavid Howells */ 216c26fd69fSDavid Howells int x509_extract_name_segment(void *context, size_t hdrlen, 217c26fd69fSDavid Howells unsigned char tag, 218c26fd69fSDavid Howells const void *value, size_t vlen) 219c26fd69fSDavid Howells { 220c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 221c26fd69fSDavid Howells 222c26fd69fSDavid Howells switch (ctx->last_oid) { 223c26fd69fSDavid Howells case OID_commonName: 224c26fd69fSDavid Howells ctx->cn_size = vlen; 225c26fd69fSDavid Howells ctx->cn_offset = (unsigned long)value - ctx->data; 226c26fd69fSDavid Howells break; 227c26fd69fSDavid Howells case OID_organizationName: 228c26fd69fSDavid Howells ctx->o_size = vlen; 229c26fd69fSDavid Howells ctx->o_offset = (unsigned long)value - ctx->data; 230c26fd69fSDavid Howells break; 231c26fd69fSDavid Howells case OID_email_address: 232c26fd69fSDavid Howells ctx->email_size = vlen; 233c26fd69fSDavid Howells ctx->email_offset = (unsigned long)value - ctx->data; 234c26fd69fSDavid Howells break; 235c26fd69fSDavid Howells default: 236c26fd69fSDavid Howells break; 237c26fd69fSDavid Howells } 238c26fd69fSDavid Howells 239c26fd69fSDavid Howells return 0; 240c26fd69fSDavid Howells } 241c26fd69fSDavid Howells 242c26fd69fSDavid Howells /* 243c26fd69fSDavid Howells * Fabricate and save the issuer and subject names 244c26fd69fSDavid Howells */ 245c26fd69fSDavid Howells static int x509_fabricate_name(struct x509_parse_context *ctx, size_t hdrlen, 246c26fd69fSDavid Howells unsigned char tag, 247c26fd69fSDavid Howells char **_name, size_t vlen) 248c26fd69fSDavid Howells { 249c26fd69fSDavid Howells const void *name, *data = (const void *)ctx->data; 250c26fd69fSDavid Howells size_t namesize; 251c26fd69fSDavid Howells char *buffer; 252c26fd69fSDavid Howells 253c26fd69fSDavid Howells if (*_name) 254c26fd69fSDavid Howells return -EINVAL; 255c26fd69fSDavid Howells 256c26fd69fSDavid Howells /* Empty name string if no material */ 257c26fd69fSDavid Howells if (!ctx->cn_size && !ctx->o_size && !ctx->email_size) { 258c26fd69fSDavid Howells buffer = kmalloc(1, GFP_KERNEL); 259c26fd69fSDavid Howells if (!buffer) 260c26fd69fSDavid Howells return -ENOMEM; 261c26fd69fSDavid Howells buffer[0] = 0; 262c26fd69fSDavid Howells goto done; 263c26fd69fSDavid Howells } 264c26fd69fSDavid Howells 265c26fd69fSDavid Howells if (ctx->cn_size && ctx->o_size) { 266c26fd69fSDavid Howells /* Consider combining O and CN, but use only the CN if it is 267c26fd69fSDavid Howells * prefixed by the O, or a significant portion thereof. 268c26fd69fSDavid Howells */ 269c26fd69fSDavid Howells namesize = ctx->cn_size; 270c26fd69fSDavid Howells name = data + ctx->cn_offset; 271c26fd69fSDavid Howells if (ctx->cn_size >= ctx->o_size && 272c26fd69fSDavid Howells memcmp(data + ctx->cn_offset, data + ctx->o_offset, 273c26fd69fSDavid Howells ctx->o_size) == 0) 274c26fd69fSDavid Howells goto single_component; 275c26fd69fSDavid Howells if (ctx->cn_size >= 7 && 276c26fd69fSDavid Howells ctx->o_size >= 7 && 277c26fd69fSDavid Howells memcmp(data + ctx->cn_offset, data + ctx->o_offset, 7) == 0) 278c26fd69fSDavid Howells goto single_component; 279c26fd69fSDavid Howells 280c26fd69fSDavid Howells buffer = kmalloc(ctx->o_size + 2 + ctx->cn_size + 1, 281c26fd69fSDavid Howells GFP_KERNEL); 282c26fd69fSDavid Howells if (!buffer) 283c26fd69fSDavid Howells return -ENOMEM; 284c26fd69fSDavid Howells 285c26fd69fSDavid Howells memcpy(buffer, 286c26fd69fSDavid Howells data + ctx->o_offset, ctx->o_size); 287c26fd69fSDavid Howells buffer[ctx->o_size + 0] = ':'; 288c26fd69fSDavid Howells buffer[ctx->o_size + 1] = ' '; 289c26fd69fSDavid Howells memcpy(buffer + ctx->o_size + 2, 290c26fd69fSDavid Howells data + ctx->cn_offset, ctx->cn_size); 291c26fd69fSDavid Howells buffer[ctx->o_size + 2 + ctx->cn_size] = 0; 292c26fd69fSDavid Howells goto done; 293c26fd69fSDavid Howells 294c26fd69fSDavid Howells } else if (ctx->cn_size) { 295c26fd69fSDavid Howells namesize = ctx->cn_size; 296c26fd69fSDavid Howells name = data + ctx->cn_offset; 297c26fd69fSDavid Howells } else if (ctx->o_size) { 298c26fd69fSDavid Howells namesize = ctx->o_size; 299c26fd69fSDavid Howells name = data + ctx->o_offset; 300c26fd69fSDavid Howells } else { 301c26fd69fSDavid Howells namesize = ctx->email_size; 302c26fd69fSDavid Howells name = data + ctx->email_offset; 303c26fd69fSDavid Howells } 304c26fd69fSDavid Howells 305c26fd69fSDavid Howells single_component: 306c26fd69fSDavid Howells buffer = kmalloc(namesize + 1, GFP_KERNEL); 307c26fd69fSDavid Howells if (!buffer) 308c26fd69fSDavid Howells return -ENOMEM; 309c26fd69fSDavid Howells memcpy(buffer, name, namesize); 310c26fd69fSDavid Howells buffer[namesize] = 0; 311c26fd69fSDavid Howells 312c26fd69fSDavid Howells done: 313c26fd69fSDavid Howells *_name = buffer; 314c26fd69fSDavid Howells ctx->cn_size = 0; 315c26fd69fSDavid Howells ctx->o_size = 0; 316c26fd69fSDavid Howells ctx->email_size = 0; 317c26fd69fSDavid Howells return 0; 318c26fd69fSDavid Howells } 319c26fd69fSDavid Howells 320c26fd69fSDavid Howells int x509_note_issuer(void *context, size_t hdrlen, 321c26fd69fSDavid Howells unsigned char tag, 322c26fd69fSDavid Howells const void *value, size_t vlen) 323c26fd69fSDavid Howells { 324c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 325c26fd69fSDavid Howells return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen); 326c26fd69fSDavid Howells } 327c26fd69fSDavid Howells 328c26fd69fSDavid Howells int x509_note_subject(void *context, size_t hdrlen, 329c26fd69fSDavid Howells unsigned char tag, 330c26fd69fSDavid Howells const void *value, size_t vlen) 331c26fd69fSDavid Howells { 332c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 333c26fd69fSDavid Howells return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen); 334c26fd69fSDavid Howells } 335c26fd69fSDavid Howells 336c26fd69fSDavid Howells /* 337c26fd69fSDavid Howells * Extract the data for the public key algorithm 338c26fd69fSDavid Howells */ 339c26fd69fSDavid Howells int x509_extract_key_data(void *context, size_t hdrlen, 340c26fd69fSDavid Howells unsigned char tag, 341c26fd69fSDavid Howells const void *value, size_t vlen) 342c26fd69fSDavid Howells { 343c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 344c26fd69fSDavid Howells 345c26fd69fSDavid Howells if (ctx->last_oid != OID_rsaEncryption) 346c26fd69fSDavid Howells return -ENOPKG; 347c26fd69fSDavid Howells 34867f7d60bSDavid Howells ctx->cert->pub->pkey_algo = PKEY_ALGO_RSA; 34967f7d60bSDavid Howells 35067f7d60bSDavid Howells /* Discard the BIT STRING metadata */ 351c26fd69fSDavid Howells ctx->key = value + 1; 352c26fd69fSDavid Howells ctx->key_size = vlen - 1; 353c26fd69fSDavid Howells return 0; 354c26fd69fSDavid Howells } 355c26fd69fSDavid Howells 356c26fd69fSDavid Howells /* 357c26fd69fSDavid Howells * Extract a RSA public key value 358c26fd69fSDavid Howells */ 359c26fd69fSDavid Howells int rsa_extract_mpi(void *context, size_t hdrlen, 360c26fd69fSDavid Howells unsigned char tag, 361c26fd69fSDavid Howells const void *value, size_t vlen) 362c26fd69fSDavid Howells { 363c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 364c26fd69fSDavid Howells MPI mpi; 365c26fd69fSDavid Howells 366c26fd69fSDavid Howells if (ctx->nr_mpi >= ARRAY_SIZE(ctx->cert->pub->mpi)) { 367c26fd69fSDavid Howells pr_err("Too many public key MPIs in certificate\n"); 368c26fd69fSDavid Howells return -EBADMSG; 369c26fd69fSDavid Howells } 370c26fd69fSDavid Howells 371c26fd69fSDavid Howells mpi = mpi_read_raw_data(value, vlen); 372c26fd69fSDavid Howells if (!mpi) 373c26fd69fSDavid Howells return -ENOMEM; 374c26fd69fSDavid Howells 375c26fd69fSDavid Howells ctx->cert->pub->mpi[ctx->nr_mpi++] = mpi; 376c26fd69fSDavid Howells return 0; 377c26fd69fSDavid Howells } 378c26fd69fSDavid Howells 37904b00bdbSChun-Yi Lee /* The keyIdentifier in AuthorityKeyIdentifier SEQUENCE is tag(CONT,PRIM,0) */ 38004b00bdbSChun-Yi Lee #define SEQ_TAG_KEYID (ASN1_CONT << 6) 38104b00bdbSChun-Yi Lee 382c26fd69fSDavid Howells /* 383c26fd69fSDavid Howells * Process certificate extensions that are used to qualify the certificate. 384c26fd69fSDavid Howells */ 385c26fd69fSDavid Howells int x509_process_extension(void *context, size_t hdrlen, 386c26fd69fSDavid Howells unsigned char tag, 387c26fd69fSDavid Howells const void *value, size_t vlen) 388c26fd69fSDavid Howells { 389c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 390c26fd69fSDavid Howells const unsigned char *v = value; 391c26fd69fSDavid Howells char *f; 392c26fd69fSDavid Howells int i; 393c26fd69fSDavid Howells 394c26fd69fSDavid Howells pr_debug("Extension: %u\n", ctx->last_oid); 395c26fd69fSDavid Howells 396c26fd69fSDavid Howells if (ctx->last_oid == OID_subjectKeyIdentifier) { 397c26fd69fSDavid Howells /* Get hold of the key fingerprint */ 398c26fd69fSDavid Howells if (vlen < 3) 399c26fd69fSDavid Howells return -EBADMSG; 400c26fd69fSDavid Howells if (v[0] != ASN1_OTS || v[1] != vlen - 2) 401c26fd69fSDavid Howells return -EBADMSG; 402c26fd69fSDavid Howells v += 2; 403c26fd69fSDavid Howells vlen -= 2; 404c26fd69fSDavid Howells 405c26fd69fSDavid Howells f = kmalloc(vlen * 2 + 1, GFP_KERNEL); 406c26fd69fSDavid Howells if (!f) 407c26fd69fSDavid Howells return -ENOMEM; 408c26fd69fSDavid Howells for (i = 0; i < vlen; i++) 409c26fd69fSDavid Howells sprintf(f + i * 2, "%02x", v[i]); 410c26fd69fSDavid Howells pr_debug("fingerprint %s\n", f); 411c26fd69fSDavid Howells ctx->cert->fingerprint = f; 412c26fd69fSDavid Howells return 0; 413c26fd69fSDavid Howells } 414c26fd69fSDavid Howells 415c26fd69fSDavid Howells if (ctx->last_oid == OID_authorityKeyIdentifier) { 41604b00bdbSChun-Yi Lee size_t key_len; 41704b00bdbSChun-Yi Lee 418c26fd69fSDavid Howells /* Get hold of the CA key fingerprint */ 419c26fd69fSDavid Howells if (vlen < 5) 420c26fd69fSDavid Howells return -EBADMSG; 421c26fd69fSDavid Howells 42204b00bdbSChun-Yi Lee /* Authority Key Identifier must be a Constructed SEQUENCE */ 42304b00bdbSChun-Yi Lee if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5))) 42404b00bdbSChun-Yi Lee return -EBADMSG; 42504b00bdbSChun-Yi Lee 42604b00bdbSChun-Yi Lee /* Authority Key Identifier is not indefinite length */ 42704b00bdbSChun-Yi Lee if (unlikely(vlen == ASN1_INDEFINITE_LENGTH)) 42804b00bdbSChun-Yi Lee return -EBADMSG; 42904b00bdbSChun-Yi Lee 43004b00bdbSChun-Yi Lee if (vlen < ASN1_INDEFINITE_LENGTH) { 43104b00bdbSChun-Yi Lee /* Short Form length */ 43204b00bdbSChun-Yi Lee if (v[1] != vlen - 2 || 43304b00bdbSChun-Yi Lee v[2] != SEQ_TAG_KEYID || 43404b00bdbSChun-Yi Lee v[3] > vlen - 4) 43504b00bdbSChun-Yi Lee return -EBADMSG; 43604b00bdbSChun-Yi Lee 43704b00bdbSChun-Yi Lee key_len = v[3]; 43804b00bdbSChun-Yi Lee v += 4; 43904b00bdbSChun-Yi Lee } else { 44004b00bdbSChun-Yi Lee /* Long Form length */ 44104b00bdbSChun-Yi Lee size_t seq_len = 0; 44204b00bdbSChun-Yi Lee size_t sub = v[1] - ASN1_INDEFINITE_LENGTH; 44304b00bdbSChun-Yi Lee 44404b00bdbSChun-Yi Lee if (sub > 2) 44504b00bdbSChun-Yi Lee return -EBADMSG; 44604b00bdbSChun-Yi Lee 44704b00bdbSChun-Yi Lee /* calculate the length from subsequent octets */ 44804b00bdbSChun-Yi Lee v += 2; 44904b00bdbSChun-Yi Lee for (i = 0; i < sub; i++) { 45004b00bdbSChun-Yi Lee seq_len <<= 8; 45104b00bdbSChun-Yi Lee seq_len |= v[i]; 45204b00bdbSChun-Yi Lee } 45304b00bdbSChun-Yi Lee 45404b00bdbSChun-Yi Lee if (seq_len != vlen - 2 - sub || 45504b00bdbSChun-Yi Lee v[sub] != SEQ_TAG_KEYID || 45604b00bdbSChun-Yi Lee v[sub + 1] > vlen - 4 - sub) 45704b00bdbSChun-Yi Lee return -EBADMSG; 45804b00bdbSChun-Yi Lee 45904b00bdbSChun-Yi Lee key_len = v[sub + 1]; 46004b00bdbSChun-Yi Lee v += (sub + 2); 46104b00bdbSChun-Yi Lee } 46204b00bdbSChun-Yi Lee 46304b00bdbSChun-Yi Lee f = kmalloc(key_len * 2 + 1, GFP_KERNEL); 464c26fd69fSDavid Howells if (!f) 465c26fd69fSDavid Howells return -ENOMEM; 46604b00bdbSChun-Yi Lee for (i = 0; i < key_len; i++) 467c26fd69fSDavid Howells sprintf(f + i * 2, "%02x", v[i]); 468c26fd69fSDavid Howells pr_debug("authority %s\n", f); 469c26fd69fSDavid Howells ctx->cert->authority = f; 470c26fd69fSDavid Howells return 0; 471c26fd69fSDavid Howells } 472c26fd69fSDavid Howells 473c26fd69fSDavid Howells return 0; 474c26fd69fSDavid Howells } 475c26fd69fSDavid Howells 476c26fd69fSDavid Howells /* 477c26fd69fSDavid Howells * Record a certificate time. 478c26fd69fSDavid Howells */ 479a5752d11SDavid Howells static int x509_note_time(struct tm *tm, size_t hdrlen, 480c26fd69fSDavid Howells unsigned char tag, 481c26fd69fSDavid Howells const unsigned char *value, size_t vlen) 482c26fd69fSDavid Howells { 483c26fd69fSDavid Howells const unsigned char *p = value; 484c26fd69fSDavid Howells 485c26fd69fSDavid Howells #define dec2bin(X) ((X) - '0') 486c26fd69fSDavid Howells #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) 487c26fd69fSDavid Howells 488c26fd69fSDavid Howells if (tag == ASN1_UNITIM) { 489c26fd69fSDavid Howells /* UTCTime: YYMMDDHHMMSSZ */ 490c26fd69fSDavid Howells if (vlen != 13) 491c26fd69fSDavid Howells goto unsupported_time; 492a5752d11SDavid Howells tm->tm_year = DD2bin(p); 493a5752d11SDavid Howells if (tm->tm_year >= 50) 494a5752d11SDavid Howells tm->tm_year += 1900; 495c26fd69fSDavid Howells else 496a5752d11SDavid Howells tm->tm_year += 2000; 497c26fd69fSDavid Howells } else if (tag == ASN1_GENTIM) { 498c26fd69fSDavid Howells /* GenTime: YYYYMMDDHHMMSSZ */ 499c26fd69fSDavid Howells if (vlen != 15) 500c26fd69fSDavid Howells goto unsupported_time; 501a5752d11SDavid Howells tm->tm_year = DD2bin(p) * 100 + DD2bin(p); 502c26fd69fSDavid Howells } else { 503c26fd69fSDavid Howells goto unsupported_time; 504c26fd69fSDavid Howells } 505c26fd69fSDavid Howells 506a5752d11SDavid Howells tm->tm_year -= 1900; 507a5752d11SDavid Howells tm->tm_mon = DD2bin(p) - 1; 508a5752d11SDavid Howells tm->tm_mday = DD2bin(p); 509a5752d11SDavid Howells tm->tm_hour = DD2bin(p); 510a5752d11SDavid Howells tm->tm_min = DD2bin(p); 511a5752d11SDavid Howells tm->tm_sec = DD2bin(p); 512c26fd69fSDavid Howells 513c26fd69fSDavid Howells if (*p != 'Z') 514c26fd69fSDavid Howells goto unsupported_time; 515c26fd69fSDavid Howells 516c26fd69fSDavid Howells return 0; 517c26fd69fSDavid Howells 518c26fd69fSDavid Howells unsupported_time: 519c26fd69fSDavid Howells pr_debug("Got unsupported time [tag %02x]: '%*.*s'\n", 520c26fd69fSDavid Howells tag, (int)vlen, (int)vlen, value); 521c26fd69fSDavid Howells return -EBADMSG; 522c26fd69fSDavid Howells } 523c26fd69fSDavid Howells 524c26fd69fSDavid Howells int x509_note_not_before(void *context, size_t hdrlen, 525c26fd69fSDavid Howells unsigned char tag, 526c26fd69fSDavid Howells const void *value, size_t vlen) 527c26fd69fSDavid Howells { 528c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 529c26fd69fSDavid Howells return x509_note_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); 530c26fd69fSDavid Howells } 531c26fd69fSDavid Howells 532c26fd69fSDavid Howells int x509_note_not_after(void *context, size_t hdrlen, 533c26fd69fSDavid Howells unsigned char tag, 534c26fd69fSDavid Howells const void *value, size_t vlen) 535c26fd69fSDavid Howells { 536c26fd69fSDavid Howells struct x509_parse_context *ctx = context; 537c26fd69fSDavid Howells return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); 538c26fd69fSDavid Howells } 539