1 /* Instantiate a public key crypto key from an X.509 Certificate
3 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
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"
27 * Set up the signature parameters in an X.509 certificate. This involves
28 * digesting the signed data and extracting the signature.
30 int x509_get_sig_params(struct x509_certificate
*cert
)
32 struct crypto_shash
*tfm
;
33 struct shash_desc
*desc
;
34 size_t digest_size
, desc_size
;
38 pr_devel("==>%s()\n", __func__
);
43 cert
->sig
.rsa
.s
= mpi_read_raw_data(cert
->raw_sig
, cert
->raw_sig_size
);
48 /* Allocate the hashing algorithm we're going to need and find out how
49 * big the hash operational data will be.
51 tfm
= crypto_alloc_shash(hash_algo_name
[cert
->sig
.pkey_hash_algo
], 0, 0);
53 return (PTR_ERR(tfm
) == -ENOENT
) ? -ENOPKG
: PTR_ERR(tfm
);
55 desc_size
= crypto_shash_descsize(tfm
) + sizeof(*desc
);
56 digest_size
= crypto_shash_digestsize(tfm
);
58 /* We allocate the hash operational data storage on the end of the
59 * digest storage space.
62 digest
= kzalloc(digest_size
+ desc_size
, GFP_KERNEL
);
66 cert
->sig
.digest
= digest
;
67 cert
->sig
.digest_size
= digest_size
;
69 desc
= digest
+ digest_size
;
71 desc
->flags
= CRYPTO_TFM_REQ_MAY_SLEEP
;
73 ret
= crypto_shash_init(desc
);
77 ret
= crypto_shash_finup(desc
, cert
->tbs
, cert
->tbs_size
, digest
);
79 crypto_free_shash(tfm
);
80 pr_devel("<==%s() = %d\n", __func__
, ret
);
83 EXPORT_SYMBOL_GPL(x509_get_sig_params
);
86 * Check the signature on a certificate using the provided public key
88 int x509_check_signature(const struct public_key
*pub
,
89 struct x509_certificate
*cert
)
93 pr_devel("==>%s()\n", __func__
);
95 ret
= x509_get_sig_params(cert
);
99 ret
= public_key_verify_signature(pub
, &cert
->sig
);
100 pr_debug("Cert Verification: %d\n", ret
);
103 EXPORT_SYMBOL_GPL(x509_check_signature
);
106 * Attempt to parse a data blob for a key as an X509 certificate.
108 static int x509_key_preparse(struct key_preparsed_payload
*prep
)
110 struct x509_certificate
*cert
;
115 cert
= x509_cert_parse(prep
->data
, prep
->datalen
);
117 return PTR_ERR(cert
);
119 pr_devel("Cert Issuer: %s\n", cert
->issuer
);
120 pr_devel("Cert Subject: %s\n", cert
->subject
);
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
]) {
129 goto error_free_cert
;
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
]);
145 if (!cert
->fingerprint
) {
146 pr_warn("Cert for '%s' must have a SubjKeyId extension\n",
149 goto error_free_cert
;
152 cert
->pub
->algo
= pkey_algo
[cert
->pub
->pkey_algo
];
153 cert
->pub
->id_type
= PKEY_ID_X509
;
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
);
160 goto error_free_cert
;
163 /* Propose a description */
164 sulen
= strlen(cert
->subject
);
165 srlen
= strlen(cert
->fingerprint
);
167 desc
= kmalloc(sulen
+ 2 + srlen
+ 1, GFP_KERNEL
);
169 goto error_free_cert
;
170 memcpy(desc
, cert
->subject
, sulen
);
172 desc
[sulen
+ 1] = ' ';
173 memcpy(desc
+ sulen
+ 2, cert
->fingerprint
, srlen
);
174 desc
[sulen
+ 2 + srlen
] = 0;
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;
184 /* We've finished with the certificate */
186 cert
->fingerprint
= NULL
;
191 x509_free_certificate(cert
);
195 static struct asymmetric_key_parser x509_key_parser
= {
196 .owner
= THIS_MODULE
,
198 .parse
= x509_key_preparse
,
204 static int __init
x509_key_init(void)
206 return register_asymmetric_key_parser(&x509_key_parser
);
209 static void __exit
x509_key_exit(void)
211 unregister_asymmetric_key_parser(&x509_key_parser
);
214 module_init(x509_key_init
);
215 module_exit(x509_key_exit
);
217 MODULE_DESCRIPTION("X.509 certificate parser");
218 MODULE_LICENSE("GPL");