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