1 /* Instantiate a public key crypto key from an X.509 Certificate 2 * 3 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public Licence 8 * as published by the Free Software Foundation; either version 9 * 2 of the Licence, or (at your option) any later version. 10 */ 11 12 #define pr_fmt(fmt) "X.509: "fmt 13 #include <linux/module.h> 14 #include <linux/kernel.h> 15 #include <linux/slab.h> 16 #include <linux/err.h> 17 #include <linux/mpi.h> 18 #include <linux/asn1_decoder.h> 19 #include <keys/asymmetric-subtype.h> 20 #include <keys/asymmetric-parser.h> 21 #include <crypto/hash.h> 22 #include "asymmetric_keys.h" 23 #include "public_key.h" 24 #include "x509_parser.h" 25 26 /* 27 * Set up the signature parameters in an X.509 certificate. This involves 28 * digesting the signed data and extracting the signature. 29 */ 30 int x509_get_sig_params(struct x509_certificate *cert) 31 { 32 struct crypto_shash *tfm; 33 struct shash_desc *desc; 34 size_t digest_size, desc_size; 35 void *digest; 36 int ret; 37 38 pr_devel("==>%s()\n", __func__); 39 40 if (cert->sig.rsa.s) 41 return 0; 42 43 cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size); 44 if (!cert->sig.rsa.s) 45 return -ENOMEM; 46 cert->sig.nr_mpi = 1; 47 48 /* Allocate the hashing algorithm we're going to need and find out how 49 * big the hash operational data will be. 50 */ 51 tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0); 52 if (IS_ERR(tfm)) 53 return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); 54 55 desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); 56 digest_size = crypto_shash_digestsize(tfm); 57 58 /* We allocate the hash operational data storage on the end of the 59 * digest storage space. 60 */ 61 ret = -ENOMEM; 62 digest = kzalloc(digest_size + desc_size, GFP_KERNEL); 63 if (!digest) 64 goto error; 65 66 cert->sig.digest = digest; 67 cert->sig.digest_size = digest_size; 68 69 desc = digest + digest_size; 70 desc->tfm = tfm; 71 desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; 72 73 ret = crypto_shash_init(desc); 74 if (ret < 0) 75 goto error; 76 might_sleep(); 77 ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest); 78 error: 79 crypto_free_shash(tfm); 80 pr_devel("<==%s() = %d\n", __func__, ret); 81 return ret; 82 } 83 EXPORT_SYMBOL_GPL(x509_get_sig_params); 84 85 /* 86 * Check the signature on a certificate using the provided public key 87 */ 88 int x509_check_signature(const struct public_key *pub, 89 struct x509_certificate *cert) 90 { 91 int ret; 92 93 pr_devel("==>%s()\n", __func__); 94 95 ret = x509_get_sig_params(cert); 96 if (ret < 0) 97 return ret; 98 99 ret = public_key_verify_signature(pub, &cert->sig); 100 pr_debug("Cert Verification: %d\n", ret); 101 return ret; 102 } 103 EXPORT_SYMBOL_GPL(x509_check_signature); 104 105 /* 106 * Attempt to parse a data blob for a key as an X509 certificate. 107 */ 108 static int x509_key_preparse(struct key_preparsed_payload *prep) 109 { 110 struct x509_certificate *cert; 111 size_t srlen, sulen; 112 char *desc = NULL; 113 int ret; 114 115 cert = x509_cert_parse(prep->data, prep->datalen); 116 if (IS_ERR(cert)) 117 return PTR_ERR(cert); 118 119 pr_devel("Cert Issuer: %s\n", cert->issuer); 120 pr_devel("Cert Subject: %s\n", cert->subject); 121 122 if (cert->pub->pkey_algo >= PKEY_ALGO__LAST || 123 cert->sig.pkey_algo >= PKEY_ALGO__LAST || 124 cert->sig.pkey_hash_algo >= PKEY_HASH__LAST || 125 !pkey_algo[cert->pub->pkey_algo] || 126 !pkey_algo[cert->sig.pkey_algo] || 127 !hash_algo_name[cert->sig.pkey_hash_algo]) { 128 ret = -ENOPKG; 129 goto error_free_cert; 130 } 131 132 pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); 133 pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", 134 cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, 135 cert->valid_from.tm_mday, cert->valid_from.tm_hour, 136 cert->valid_from.tm_min, cert->valid_from.tm_sec); 137 pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n", 138 cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1, 139 cert->valid_to.tm_mday, cert->valid_to.tm_hour, 140 cert->valid_to.tm_min, cert->valid_to.tm_sec); 141 pr_devel("Cert Signature: %s + %s\n", 142 pkey_algo_name[cert->sig.pkey_algo], 143 hash_algo_name[cert->sig.pkey_hash_algo]); 144 145 if (!cert->fingerprint) { 146 pr_warn("Cert for '%s' must have a SubjKeyId extension\n", 147 cert->subject); 148 ret = -EKEYREJECTED; 149 goto error_free_cert; 150 } 151 152 cert->pub->algo = pkey_algo[cert->pub->pkey_algo]; 153 cert->pub->id_type = PKEY_ID_X509; 154 155 /* Check the signature on the key if it appears to be self-signed */ 156 if (!cert->authority || 157 strcmp(cert->fingerprint, cert->authority) == 0) { 158 ret = x509_check_signature(cert->pub, cert); 159 if (ret < 0) 160 goto error_free_cert; 161 } 162 163 /* Propose a description */ 164 sulen = strlen(cert->subject); 165 srlen = strlen(cert->fingerprint); 166 ret = -ENOMEM; 167 desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL); 168 if (!desc) 169 goto error_free_cert; 170 memcpy(desc, cert->subject, sulen); 171 desc[sulen] = ':'; 172 desc[sulen + 1] = ' '; 173 memcpy(desc + sulen + 2, cert->fingerprint, srlen); 174 desc[sulen + 2 + srlen] = 0; 175 176 /* We're pinning the module by being linked against it */ 177 __module_get(public_key_subtype.owner); 178 prep->type_data[0] = &public_key_subtype; 179 prep->type_data[1] = cert->fingerprint; 180 prep->payload = cert->pub; 181 prep->description = desc; 182 prep->quotalen = 100; 183 184 /* We've finished with the certificate */ 185 cert->pub = NULL; 186 cert->fingerprint = NULL; 187 desc = NULL; 188 ret = 0; 189 190 error_free_cert: 191 x509_free_certificate(cert); 192 return ret; 193 } 194 195 static struct asymmetric_key_parser x509_key_parser = { 196 .owner = THIS_MODULE, 197 .name = "x509", 198 .parse = x509_key_preparse, 199 }; 200 201 /* 202 * Module stuff 203 */ 204 static int __init x509_key_init(void) 205 { 206 return register_asymmetric_key_parser(&x509_key_parser); 207 } 208 209 static void __exit x509_key_exit(void) 210 { 211 unregister_asymmetric_key_parser(&x509_key_parser); 212 } 213 214 module_init(x509_key_init); 215 module_exit(x509_key_exit); 216 217 MODULE_DESCRIPTION("X.509 certificate parser"); 218 MODULE_LICENSE("GPL"); 219