Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later 2 : : /* Instantiate a public key crypto key from an X.509 Certificate 3 : : * 4 : : * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. 5 : : * Written by David Howells (dhowells@redhat.com) 6 : : */ 7 : : 8 : : #define pr_fmt(fmt) "X.509: "fmt 9 : : #include <linux/module.h> 10 : : #include <linux/kernel.h> 11 : : #include <linux/slab.h> 12 : : #include <keys/asymmetric-subtype.h> 13 : : #include <keys/asymmetric-parser.h> 14 : : #include <keys/system_keyring.h> 15 : : #include <crypto/hash.h> 16 : : #include "asymmetric_keys.h" 17 : : #include "x509_parser.h" 18 : : 19 : : /* 20 : : * Set up the signature parameters in an X.509 certificate. This involves 21 : : * digesting the signed data and extracting the signature. 22 : : */ 23 : 3 : int x509_get_sig_params(struct x509_certificate *cert) 24 : : { 25 : 3 : struct public_key_signature *sig = cert->sig; 26 : : struct crypto_shash *tfm; 27 : : struct shash_desc *desc; 28 : : size_t desc_size; 29 : : int ret; 30 : : 31 : : pr_devel("==>%s()\n", __func__); 32 : : 33 : 3 : if (!cert->pub->pkey_algo) 34 : 0 : cert->unsupported_key = true; 35 : : 36 : 3 : if (!sig->pkey_algo) 37 : 0 : cert->unsupported_sig = true; 38 : : 39 : : /* We check the hash if we can - even if we can't then verify it */ 40 : 3 : if (!sig->hash_algo) { 41 : 0 : cert->unsupported_sig = true; 42 : 0 : return 0; 43 : : } 44 : : 45 : 3 : sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL); 46 : 3 : if (!sig->s) 47 : : return -ENOMEM; 48 : : 49 : 3 : sig->s_size = cert->raw_sig_size; 50 : : 51 : : /* Allocate the hashing algorithm we're going to need and find out how 52 : : * big the hash operational data will be. 53 : : */ 54 : 3 : tfm = crypto_alloc_shash(sig->hash_algo, 0, 0); 55 : 3 : if (IS_ERR(tfm)) { 56 : 0 : if (PTR_ERR(tfm) == -ENOENT) { 57 : 0 : cert->unsupported_sig = true; 58 : 0 : return 0; 59 : : } 60 : : return PTR_ERR(tfm); 61 : : } 62 : : 63 : 3 : desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); 64 : 3 : sig->digest_size = crypto_shash_digestsize(tfm); 65 : : 66 : : ret = -ENOMEM; 67 : 3 : sig->digest = kmalloc(sig->digest_size, GFP_KERNEL); 68 : 3 : if (!sig->digest) 69 : : goto error; 70 : : 71 : 3 : desc = kzalloc(desc_size, GFP_KERNEL); 72 : 3 : if (!desc) 73 : : goto error; 74 : : 75 : 3 : desc->tfm = tfm; 76 : : 77 : 3 : ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size, sig->digest); 78 : 3 : if (ret < 0) 79 : : goto error_2; 80 : : 81 : : ret = is_hash_blacklisted(sig->digest, sig->digest_size, "tbs"); 82 : : if (ret == -EKEYREJECTED) { 83 : : pr_err("Cert %*phN is blacklisted\n", 84 : : sig->digest_size, sig->digest); 85 : : cert->blacklisted = true; 86 : : ret = 0; 87 : : } 88 : : 89 : : error_2: 90 : 3 : kfree(desc); 91 : : error: 92 : : crypto_free_shash(tfm); 93 : : pr_devel("<==%s() = %d\n", __func__, ret); 94 : 3 : return ret; 95 : : } 96 : : 97 : : /* 98 : : * Check for self-signedness in an X.509 cert and if found, check the signature 99 : : * immediately if we can. 100 : : */ 101 : 3 : int x509_check_for_self_signed(struct x509_certificate *cert) 102 : : { 103 : : int ret = 0; 104 : : 105 : : pr_devel("==>%s()\n", __func__); 106 : : 107 : 3 : if (cert->raw_subject_size != cert->raw_issuer_size || 108 : 3 : memcmp(cert->raw_subject, cert->raw_issuer, 109 : : cert->raw_issuer_size) != 0) 110 : : goto not_self_signed; 111 : : 112 : 3 : if (cert->sig->auth_ids[0] || cert->sig->auth_ids[1]) { 113 : : /* If the AKID is present it may have one or two parts. If 114 : : * both are supplied, both must match. 115 : : */ 116 : 0 : bool a = asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]); 117 : 0 : bool b = asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0]); 118 : : 119 : 0 : if (!a && !b) 120 : : goto not_self_signed; 121 : : 122 : : ret = -EKEYREJECTED; 123 : 0 : if (((a && !b) || (b && !a)) && 124 : 0 : cert->sig->auth_ids[0] && cert->sig->auth_ids[1]) 125 : : goto out; 126 : : } 127 : : 128 : : ret = -EKEYREJECTED; 129 : 3 : if (strcmp(cert->pub->pkey_algo, cert->sig->pkey_algo) != 0) 130 : : goto out; 131 : : 132 : 3 : ret = public_key_verify_signature(cert->pub, cert->sig); 133 : 3 : if (ret < 0) { 134 : 0 : if (ret == -ENOPKG) { 135 : 0 : cert->unsupported_sig = true; 136 : : ret = 0; 137 : : } 138 : : goto out; 139 : : } 140 : : 141 : : pr_devel("Cert Self-signature verified"); 142 : 3 : cert->self_signed = true; 143 : : 144 : : out: 145 : : pr_devel("<==%s() = %d\n", __func__, ret); 146 : 3 : return ret; 147 : : 148 : : not_self_signed: 149 : : pr_devel("<==%s() = 0 [not]\n", __func__); 150 : : return 0; 151 : : } 152 : : 153 : : /* 154 : : * Attempt to parse a data blob for a key as an X509 certificate. 155 : : */ 156 : 3 : static int x509_key_preparse(struct key_preparsed_payload *prep) 157 : : { 158 : : struct asymmetric_key_ids *kids; 159 : : struct x509_certificate *cert; 160 : : const char *q; 161 : : size_t srlen, sulen; 162 : : char *desc = NULL, *p; 163 : : int ret; 164 : : 165 : 3 : cert = x509_cert_parse(prep->data, prep->datalen); 166 : 3 : if (IS_ERR(cert)) 167 : 0 : return PTR_ERR(cert); 168 : : 169 : : pr_devel("Cert Issuer: %s\n", cert->issuer); 170 : : pr_devel("Cert Subject: %s\n", cert->subject); 171 : : 172 : 3 : if (cert->unsupported_key) { 173 : : ret = -ENOPKG; 174 : : goto error_free_cert; 175 : : } 176 : : 177 : : pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo); 178 : : pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); 179 : : 180 : 3 : cert->pub->id_type = "X509"; 181 : : 182 : 3 : if (cert->unsupported_sig) { 183 : 0 : public_key_signature_free(cert->sig); 184 : 0 : cert->sig = NULL; 185 : : } else { 186 : : pr_devel("Cert Signature: %s + %s\n", 187 : : cert->sig->pkey_algo, cert->sig->hash_algo); 188 : : } 189 : : 190 : : /* Don't permit addition of blacklisted keys */ 191 : : ret = -EKEYREJECTED; 192 : 3 : if (cert->blacklisted) 193 : : goto error_free_cert; 194 : : 195 : : /* Propose a description */ 196 : 3 : sulen = strlen(cert->subject); 197 : 3 : if (cert->raw_skid) { 198 : 0 : srlen = cert->raw_skid_size; 199 : : q = cert->raw_skid; 200 : : } else { 201 : 3 : srlen = cert->raw_serial_size; 202 : 3 : q = cert->raw_serial; 203 : : } 204 : : 205 : : ret = -ENOMEM; 206 : 3 : desc = kmalloc(sulen + 2 + srlen * 2 + 1, GFP_KERNEL); 207 : 3 : if (!desc) 208 : : goto error_free_cert; 209 : 3 : p = memcpy(desc, cert->subject, sulen); 210 : 3 : p += sulen; 211 : 3 : *p++ = ':'; 212 : 3 : *p++ = ' '; 213 : 3 : p = bin2hex(p, q, srlen); 214 : 3 : *p = 0; 215 : : 216 : : kids = kmalloc(sizeof(struct asymmetric_key_ids), GFP_KERNEL); 217 : 3 : if (!kids) 218 : : goto error_free_desc; 219 : 3 : kids->id[0] = cert->id; 220 : 3 : kids->id[1] = cert->skid; 221 : : 222 : : /* We're pinning the module by being linked against it */ 223 : 3 : __module_get(public_key_subtype.owner); 224 : 3 : prep->payload.data[asym_subtype] = &public_key_subtype; 225 : 3 : prep->payload.data[asym_key_ids] = kids; 226 : 3 : prep->payload.data[asym_crypto] = cert->pub; 227 : 3 : prep->payload.data[asym_auth] = cert->sig; 228 : 3 : prep->description = desc; 229 : 3 : prep->quotalen = 100; 230 : : 231 : : /* We've finished with the certificate */ 232 : 3 : cert->pub = NULL; 233 : 3 : cert->id = NULL; 234 : 3 : cert->skid = NULL; 235 : 3 : cert->sig = NULL; 236 : : desc = NULL; 237 : : ret = 0; 238 : : 239 : : error_free_desc: 240 : 3 : kfree(desc); 241 : : error_free_cert: 242 : 3 : x509_free_certificate(cert); 243 : 3 : return ret; 244 : : } 245 : : 246 : : static struct asymmetric_key_parser x509_key_parser = { 247 : : .owner = THIS_MODULE, 248 : : .name = "x509", 249 : : .parse = x509_key_preparse, 250 : : }; 251 : : 252 : : /* 253 : : * Module stuff 254 : : */ 255 : 3 : static int __init x509_key_init(void) 256 : : { 257 : 3 : return register_asymmetric_key_parser(&x509_key_parser); 258 : : } 259 : : 260 : 0 : static void __exit x509_key_exit(void) 261 : : { 262 : 0 : unregister_asymmetric_key_parser(&x509_key_parser); 263 : 0 : } 264 : : 265 : : module_init(x509_key_init); 266 : : module_exit(x509_key_exit); 267 : : 268 : : MODULE_DESCRIPTION("X.509 certificate parser"); 269 : : MODULE_AUTHOR("Red Hat, Inc."); 270 : : MODULE_LICENSE("GPL");