1c26fd69fSDavid Howells /* Instantiate a public key crypto key from an X.509 Certificate 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/module.h> 14c26fd69fSDavid Howells #include <linux/kernel.h> 15c26fd69fSDavid Howells #include <linux/slab.h> 16c26fd69fSDavid Howells #include <linux/err.h> 17c26fd69fSDavid Howells #include <linux/mpi.h> 18c26fd69fSDavid Howells #include <linux/asn1_decoder.h> 19c26fd69fSDavid Howells #include <keys/asymmetric-subtype.h> 20c26fd69fSDavid Howells #include <keys/asymmetric-parser.h> 21c26fd69fSDavid Howells #include <crypto/hash.h> 22c26fd69fSDavid Howells #include "asymmetric_keys.h" 23c26fd69fSDavid Howells #include "public_key.h" 24c26fd69fSDavid Howells #include "x509_parser.h" 25c26fd69fSDavid Howells 26c26fd69fSDavid Howells /* 27*b426beb6SDavid Howells * Set up the signature parameters in an X.509 certificate. This involves 28*b426beb6SDavid Howells * digesting the signed data and extracting the signature. 29c26fd69fSDavid Howells */ 30*b426beb6SDavid Howells int x509_get_sig_params(struct x509_certificate *cert) 31c26fd69fSDavid Howells { 32c26fd69fSDavid Howells struct crypto_shash *tfm; 33c26fd69fSDavid Howells struct shash_desc *desc; 34c26fd69fSDavid Howells size_t digest_size, desc_size; 35*b426beb6SDavid Howells void *digest; 36c26fd69fSDavid Howells int ret; 37c26fd69fSDavid Howells 38c26fd69fSDavid Howells pr_devel("==>%s()\n", __func__); 39c26fd69fSDavid Howells 40*b426beb6SDavid Howells if (cert->sig.rsa.s) 41*b426beb6SDavid Howells return 0; 42*b426beb6SDavid Howells 43*b426beb6SDavid Howells cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size); 44*b426beb6SDavid Howells if (!cert->sig.rsa.s) 45*b426beb6SDavid Howells return -ENOMEM; 46*b426beb6SDavid Howells cert->sig.nr_mpi = 1; 47*b426beb6SDavid Howells 48c26fd69fSDavid Howells /* Allocate the hashing algorithm we're going to need and find out how 49c26fd69fSDavid Howells * big the hash operational data will be. 50c26fd69fSDavid Howells */ 51*b426beb6SDavid Howells tfm = crypto_alloc_shash(pkey_hash_algo_name[cert->sig.pkey_hash_algo], 0, 0); 52c26fd69fSDavid Howells if (IS_ERR(tfm)) 53c26fd69fSDavid Howells return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); 54c26fd69fSDavid Howells 55c26fd69fSDavid Howells desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); 56c26fd69fSDavid Howells digest_size = crypto_shash_digestsize(tfm); 57c26fd69fSDavid Howells 58*b426beb6SDavid Howells /* We allocate the hash operational data storage on the end of the 59*b426beb6SDavid Howells * digest storage space. 60c26fd69fSDavid Howells */ 61c26fd69fSDavid Howells ret = -ENOMEM; 62*b426beb6SDavid Howells digest = kzalloc(digest_size + desc_size, GFP_KERNEL); 63*b426beb6SDavid Howells if (!digest) 64*b426beb6SDavid Howells goto error; 65c26fd69fSDavid Howells 66*b426beb6SDavid Howells cert->sig.digest = digest; 67*b426beb6SDavid Howells cert->sig.digest_size = digest_size; 68c26fd69fSDavid Howells 69*b426beb6SDavid Howells desc = digest + digest_size; 70c26fd69fSDavid Howells desc->tfm = tfm; 71c26fd69fSDavid Howells desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; 72c26fd69fSDavid Howells 73c26fd69fSDavid Howells ret = crypto_shash_init(desc); 74c26fd69fSDavid Howells if (ret < 0) 75c26fd69fSDavid Howells goto error; 76*b426beb6SDavid Howells might_sleep(); 77*b426beb6SDavid Howells ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest); 78c26fd69fSDavid Howells error: 79c26fd69fSDavid Howells crypto_free_shash(tfm); 80c26fd69fSDavid Howells pr_devel("<==%s() = %d\n", __func__, ret); 81c26fd69fSDavid Howells return ret; 82c26fd69fSDavid Howells } 83*b426beb6SDavid Howells EXPORT_SYMBOL_GPL(x509_get_sig_params); 84*b426beb6SDavid Howells 85*b426beb6SDavid Howells /* 86*b426beb6SDavid Howells * Check the signature on a certificate using the provided public key 87*b426beb6SDavid Howells */ 88*b426beb6SDavid Howells int x509_check_signature(const struct public_key *pub, 89*b426beb6SDavid Howells struct x509_certificate *cert) 90*b426beb6SDavid Howells { 91*b426beb6SDavid Howells int ret; 92*b426beb6SDavid Howells 93*b426beb6SDavid Howells pr_devel("==>%s()\n", __func__); 94*b426beb6SDavid Howells 95*b426beb6SDavid Howells ret = x509_get_sig_params(cert); 96*b426beb6SDavid Howells if (ret < 0) 97*b426beb6SDavid Howells return ret; 98*b426beb6SDavid Howells 99*b426beb6SDavid Howells ret = public_key_verify_signature(pub, &cert->sig); 100*b426beb6SDavid Howells pr_debug("Cert Verification: %d\n", ret); 101*b426beb6SDavid Howells return ret; 102*b426beb6SDavid Howells } 103*b426beb6SDavid Howells EXPORT_SYMBOL_GPL(x509_check_signature); 104c26fd69fSDavid Howells 105c26fd69fSDavid Howells /* 106c26fd69fSDavid Howells * Attempt to parse a data blob for a key as an X509 certificate. 107c26fd69fSDavid Howells */ 108c26fd69fSDavid Howells static int x509_key_preparse(struct key_preparsed_payload *prep) 109c26fd69fSDavid Howells { 110c26fd69fSDavid Howells struct x509_certificate *cert; 111a5752d11SDavid Howells struct tm now; 112c26fd69fSDavid Howells size_t srlen, sulen; 113c26fd69fSDavid Howells char *desc = NULL; 114c26fd69fSDavid Howells int ret; 115c26fd69fSDavid Howells 116c26fd69fSDavid Howells cert = x509_cert_parse(prep->data, prep->datalen); 117c26fd69fSDavid Howells if (IS_ERR(cert)) 118c26fd69fSDavid Howells return PTR_ERR(cert); 119c26fd69fSDavid Howells 120c26fd69fSDavid Howells pr_devel("Cert Issuer: %s\n", cert->issuer); 121c26fd69fSDavid Howells pr_devel("Cert Subject: %s\n", cert->subject); 12267f7d60bSDavid Howells pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); 1232f1c4fefSDavid Howells pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", 124a5752d11SDavid Howells cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, 125a5752d11SDavid Howells cert->valid_from.tm_mday, cert->valid_from.tm_hour, 126a5752d11SDavid Howells cert->valid_from.tm_min, cert->valid_from.tm_sec); 1272f1c4fefSDavid Howells pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n", 128a5752d11SDavid Howells cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1, 129a5752d11SDavid Howells cert->valid_to.tm_mday, cert->valid_to.tm_hour, 130a5752d11SDavid Howells cert->valid_to.tm_min, cert->valid_to.tm_sec); 131c26fd69fSDavid Howells pr_devel("Cert Signature: %s + %s\n", 132*b426beb6SDavid Howells pkey_algo_name[cert->sig.pkey_algo], 133*b426beb6SDavid Howells pkey_hash_algo_name[cert->sig.pkey_hash_algo]); 134c26fd69fSDavid Howells 135c26fd69fSDavid Howells if (!cert->fingerprint || !cert->authority) { 136c26fd69fSDavid Howells pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n", 137c26fd69fSDavid Howells cert->subject); 138c26fd69fSDavid Howells ret = -EKEYREJECTED; 139c26fd69fSDavid Howells goto error_free_cert; 140c26fd69fSDavid Howells } 141c26fd69fSDavid Howells 142a5752d11SDavid Howells time_to_tm(CURRENT_TIME.tv_sec, 0, &now); 1432f1c4fefSDavid Howells pr_devel("Now: %04ld-%02d-%02d %02d:%02d:%02d\n", 144a5752d11SDavid Howells now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, 145a5752d11SDavid Howells now.tm_hour, now.tm_min, now.tm_sec); 146a5752d11SDavid Howells if (now.tm_year < cert->valid_from.tm_year || 147a5752d11SDavid Howells (now.tm_year == cert->valid_from.tm_year && 148a5752d11SDavid Howells (now.tm_mon < cert->valid_from.tm_mon || 149a5752d11SDavid Howells (now.tm_mon == cert->valid_from.tm_mon && 150a5752d11SDavid Howells (now.tm_mday < cert->valid_from.tm_mday || 151a5752d11SDavid Howells (now.tm_mday == cert->valid_from.tm_mday && 152a5752d11SDavid Howells (now.tm_hour < cert->valid_from.tm_hour || 153a5752d11SDavid Howells (now.tm_hour == cert->valid_from.tm_hour && 154a5752d11SDavid Howells (now.tm_min < cert->valid_from.tm_min || 155a5752d11SDavid Howells (now.tm_min == cert->valid_from.tm_min && 156a5752d11SDavid Howells (now.tm_sec < cert->valid_from.tm_sec 157a5752d11SDavid Howells ))))))))))) { 158c26fd69fSDavid Howells pr_warn("Cert %s is not yet valid\n", cert->fingerprint); 159c26fd69fSDavid Howells ret = -EKEYREJECTED; 160c26fd69fSDavid Howells goto error_free_cert; 161c26fd69fSDavid Howells } 162a5752d11SDavid Howells if (now.tm_year > cert->valid_to.tm_year || 163a5752d11SDavid Howells (now.tm_year == cert->valid_to.tm_year && 164a5752d11SDavid Howells (now.tm_mon > cert->valid_to.tm_mon || 165a5752d11SDavid Howells (now.tm_mon == cert->valid_to.tm_mon && 166a5752d11SDavid Howells (now.tm_mday > cert->valid_to.tm_mday || 167a5752d11SDavid Howells (now.tm_mday == cert->valid_to.tm_mday && 168a5752d11SDavid Howells (now.tm_hour > cert->valid_to.tm_hour || 169a5752d11SDavid Howells (now.tm_hour == cert->valid_to.tm_hour && 170a5752d11SDavid Howells (now.tm_min > cert->valid_to.tm_min || 171a5752d11SDavid Howells (now.tm_min == cert->valid_to.tm_min && 172a5752d11SDavid Howells (now.tm_sec > cert->valid_to.tm_sec 173a5752d11SDavid Howells ))))))))))) { 174c26fd69fSDavid Howells pr_warn("Cert %s has expired\n", cert->fingerprint); 175c26fd69fSDavid Howells ret = -EKEYEXPIRED; 176c26fd69fSDavid Howells goto error_free_cert; 177c26fd69fSDavid Howells } 178c26fd69fSDavid Howells 17967f7d60bSDavid Howells cert->pub->algo = pkey_algo[cert->pub->pkey_algo]; 180c26fd69fSDavid Howells cert->pub->id_type = PKEY_ID_X509; 181c26fd69fSDavid Howells 182c26fd69fSDavid Howells /* Check the signature on the key */ 183c26fd69fSDavid Howells if (strcmp(cert->fingerprint, cert->authority) == 0) { 184c26fd69fSDavid Howells ret = x509_check_signature(cert->pub, cert); 185c26fd69fSDavid Howells if (ret < 0) 186c26fd69fSDavid Howells goto error_free_cert; 187c26fd69fSDavid Howells } 188c26fd69fSDavid Howells 189c26fd69fSDavid Howells /* Propose a description */ 190c26fd69fSDavid Howells sulen = strlen(cert->subject); 191c26fd69fSDavid Howells srlen = strlen(cert->fingerprint); 192c26fd69fSDavid Howells ret = -ENOMEM; 193c26fd69fSDavid Howells desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL); 194c26fd69fSDavid Howells if (!desc) 195c26fd69fSDavid Howells goto error_free_cert; 196c26fd69fSDavid Howells memcpy(desc, cert->subject, sulen); 197c26fd69fSDavid Howells desc[sulen] = ':'; 198c26fd69fSDavid Howells desc[sulen + 1] = ' '; 199c26fd69fSDavid Howells memcpy(desc + sulen + 2, cert->fingerprint, srlen); 200c26fd69fSDavid Howells desc[sulen + 2 + srlen] = 0; 201c26fd69fSDavid Howells 202c26fd69fSDavid Howells /* We're pinning the module by being linked against it */ 203c26fd69fSDavid Howells __module_get(public_key_subtype.owner); 204c26fd69fSDavid Howells prep->type_data[0] = &public_key_subtype; 205c26fd69fSDavid Howells prep->type_data[1] = cert->fingerprint; 206c26fd69fSDavid Howells prep->payload = cert->pub; 207c26fd69fSDavid Howells prep->description = desc; 208c26fd69fSDavid Howells prep->quotalen = 100; 209c26fd69fSDavid Howells 210c26fd69fSDavid Howells /* We've finished with the certificate */ 211c26fd69fSDavid Howells cert->pub = NULL; 212c26fd69fSDavid Howells cert->fingerprint = NULL; 213c26fd69fSDavid Howells desc = NULL; 214c26fd69fSDavid Howells ret = 0; 215c26fd69fSDavid Howells 216c26fd69fSDavid Howells error_free_cert: 217c26fd69fSDavid Howells x509_free_certificate(cert); 218c26fd69fSDavid Howells return ret; 219c26fd69fSDavid Howells } 220c26fd69fSDavid Howells 221c26fd69fSDavid Howells static struct asymmetric_key_parser x509_key_parser = { 222c26fd69fSDavid Howells .owner = THIS_MODULE, 223c26fd69fSDavid Howells .name = "x509", 224c26fd69fSDavid Howells .parse = x509_key_preparse, 225c26fd69fSDavid Howells }; 226c26fd69fSDavid Howells 227c26fd69fSDavid Howells /* 228c26fd69fSDavid Howells * Module stuff 229c26fd69fSDavid Howells */ 230c26fd69fSDavid Howells static int __init x509_key_init(void) 231c26fd69fSDavid Howells { 232c26fd69fSDavid Howells return register_asymmetric_key_parser(&x509_key_parser); 233c26fd69fSDavid Howells } 234c26fd69fSDavid Howells 235c26fd69fSDavid Howells static void __exit x509_key_exit(void) 236c26fd69fSDavid Howells { 237c26fd69fSDavid Howells unregister_asymmetric_key_parser(&x509_key_parser); 238c26fd69fSDavid Howells } 239c26fd69fSDavid Howells 240c26fd69fSDavid Howells module_init(x509_key_init); 241c26fd69fSDavid Howells module_exit(x509_key_exit); 242