diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-14 16:39:34 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-14 16:39:34 -0400 |
| commit | d25282d1c9b9bc4cda7f9d3c0205108e99aa7a9d (patch) | |
| tree | f414482d768b015a609924293b779b4ad0b8f764 /crypto | |
| parent | b6eea87fc6850d3531a64a27d2323a4498cd4e43 (diff) | |
| parent | dbadc17683e6c673a69b236c0f041b931cc55c42 (diff) | |
Merge branch 'modules-next' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux
Pull module signing support from Rusty Russell:
"module signing is the highlight, but it's an all-over David Howells frenzy..."
Hmm "Magrathea: Glacier signing key". Somebody has been reading too much HHGTTG.
* 'modules-next' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux: (37 commits)
X.509: Fix indefinite length element skip error handling
X.509: Convert some printk calls to pr_devel
asymmetric keys: fix printk format warning
MODSIGN: Fix 32-bit overflow in X.509 certificate validity date checking
MODSIGN: Make mrproper should remove generated files.
MODSIGN: Use utf8 strings in signer's name in autogenerated X.509 certs
MODSIGN: Use the same digest for the autogen key sig as for the module sig
MODSIGN: Sign modules during the build process
MODSIGN: Provide a script for generating a key ID from an X.509 cert
MODSIGN: Implement module signature checking
MODSIGN: Provide module signing public keys to the kernel
MODSIGN: Automatically generate module signing keys if missing
MODSIGN: Provide Kconfig options
MODSIGN: Provide gitignore and make clean rules for extra files
MODSIGN: Add FIPS policy
module: signature checking hook
X.509: Add a crypto key parser for binary (DER) X.509 certificates
MPILIB: Provide a function to read raw data into an MPI
X.509: Add an ASN.1 decoder
X.509: Add simple ASN.1 grammar compiler
...
Diffstat (limited to 'crypto')
| -rw-r--r-- | crypto/Kconfig | 1 | ||||
| -rw-r--r-- | crypto/Makefile | 1 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/.gitignore | 1 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/Kconfig | 38 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/Makefile | 27 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/asymmetric_keys.h | 15 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/asymmetric_type.c | 274 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/public_key.c | 108 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/public_key.h | 30 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/rsa.c | 277 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/signature.c | 49 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/x509.asn1 | 60 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/x509_cert_parser.c | 496 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/x509_parser.h | 36 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 239 | ||||
| -rw-r--r-- | crypto/asymmetric_keys/x509_rsakey.asn1 | 4 |
16 files changed, 1656 insertions, 0 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig index 50402dc0ea35..6563366bae80 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig | |||
| @@ -1216,5 +1216,6 @@ config CRYPTO_USER_API_SKCIPHER | |||
| 1216 | key cipher algorithms. | 1216 | key cipher algorithms. |
| 1217 | 1217 | ||
| 1218 | source "drivers/crypto/Kconfig" | 1218 | source "drivers/crypto/Kconfig" |
| 1219 | source crypto/asymmetric_keys/Kconfig | ||
| 1219 | 1220 | ||
| 1220 | endif # if CRYPTO | 1221 | endif # if CRYPTO |
diff --git a/crypto/Makefile b/crypto/Makefile index a301ad2b258c..8cf61ffe3513 100644 --- a/crypto/Makefile +++ b/crypto/Makefile | |||
| @@ -97,3 +97,4 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o | |||
| 97 | # | 97 | # |
| 98 | obj-$(CONFIG_XOR_BLOCKS) += xor.o | 98 | obj-$(CONFIG_XOR_BLOCKS) += xor.o |
| 99 | obj-$(CONFIG_ASYNC_CORE) += async_tx/ | 99 | obj-$(CONFIG_ASYNC_CORE) += async_tx/ |
| 100 | obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/ | ||
diff --git a/crypto/asymmetric_keys/.gitignore b/crypto/asymmetric_keys/.gitignore new file mode 100644 index 000000000000..ee328374dba8 --- /dev/null +++ b/crypto/asymmetric_keys/.gitignore | |||
| @@ -0,0 +1 @@ | |||
| *-asn1.[ch] | |||
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig new file mode 100644 index 000000000000..6d2c2ea12559 --- /dev/null +++ b/crypto/asymmetric_keys/Kconfig | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | menuconfig ASYMMETRIC_KEY_TYPE | ||
| 2 | tristate "Asymmetric (public-key cryptographic) key type" | ||
| 3 | depends on KEYS | ||
| 4 | help | ||
| 5 | This option provides support for a key type that holds the data for | ||
| 6 | the asymmetric keys used for public key cryptographic operations such | ||
| 7 | as encryption, decryption, signature generation and signature | ||
| 8 | verification. | ||
| 9 | |||
| 10 | if ASYMMETRIC_KEY_TYPE | ||
| 11 | |||
| 12 | config ASYMMETRIC_PUBLIC_KEY_SUBTYPE | ||
| 13 | tristate "Asymmetric public-key crypto algorithm subtype" | ||
| 14 | select MPILIB | ||
| 15 | help | ||
| 16 | This option provides support for asymmetric public key type handling. | ||
| 17 | If signature generation and/or verification are to be used, | ||
| 18 | appropriate hash algorithms (such as SHA-1) must be available. | ||
| 19 | ENOPKG will be reported if the requisite algorithm is unavailable. | ||
| 20 | |||
| 21 | config PUBLIC_KEY_ALGO_RSA | ||
| 22 | tristate "RSA public-key algorithm" | ||
| 23 | depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE | ||
| 24 | select MPILIB_EXTRA | ||
| 25 | help | ||
| 26 | This option enables support for the RSA algorithm (PKCS#1, RFC3447). | ||
| 27 | |||
| 28 | config X509_CERTIFICATE_PARSER | ||
| 29 | tristate "X.509 certificate parser" | ||
| 30 | depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE | ||
| 31 | select ASN1 | ||
| 32 | select OID_REGISTRY | ||
| 33 | help | ||
| 34 | This option procides support for parsing X.509 format blobs for key | ||
| 35 | data and provides the ability to instantiate a crypto key from a | ||
| 36 | public key packet found inside the certificate. | ||
| 37 | |||
| 38 | endif # ASYMMETRIC_KEY_TYPE | ||
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile new file mode 100644 index 000000000000..0727204aab68 --- /dev/null +++ b/crypto/asymmetric_keys/Makefile | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | # | ||
| 2 | # Makefile for asymmetric cryptographic keys | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o | ||
| 6 | |||
| 7 | asymmetric_keys-y := asymmetric_type.o signature.o | ||
| 8 | |||
| 9 | obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o | ||
| 10 | obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o | ||
| 11 | |||
| 12 | # | ||
| 13 | # X.509 Certificate handling | ||
| 14 | # | ||
| 15 | obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o | ||
| 16 | x509_key_parser-y := \ | ||
| 17 | x509-asn1.o \ | ||
| 18 | x509_rsakey-asn1.o \ | ||
| 19 | x509_cert_parser.o \ | ||
| 20 | x509_public_key.o | ||
| 21 | |||
| 22 | $(obj)/x509_cert_parser.o: $(obj)/x509-asn1.h $(obj)/x509_rsakey-asn1.h | ||
| 23 | $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h | ||
| 24 | $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h | ||
| 25 | |||
| 26 | clean-files += x509-asn1.c x509-asn1.h | ||
| 27 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h | ||
diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h new file mode 100644 index 000000000000..515b63430812 --- /dev/null +++ b/crypto/asymmetric_keys/asymmetric_keys.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | /* Internal definitions for asymmetric key type | ||
| 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 | static inline const char *asymmetric_key_id(const struct key *key) | ||
| 13 | { | ||
| 14 | return key->type_data.p[1]; | ||
| 15 | } | ||
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c new file mode 100644 index 000000000000..cf807654d221 --- /dev/null +++ b/crypto/asymmetric_keys/asymmetric_type.c | |||
| @@ -0,0 +1,274 @@ | |||
| 1 | /* Asymmetric public-key cryptography key type | ||
| 2 | * | ||
| 3 | * See Documentation/security/asymmetric-keys.txt | ||
| 4 | * | ||
| 5 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
| 6 | * Written by David Howells (dhowells@redhat.com) | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public Licence | ||
| 10 | * as published by the Free Software Foundation; either version | ||
| 11 | * 2 of the Licence, or (at your option) any later version. | ||
| 12 | */ | ||
| 13 | #include <keys/asymmetric-subtype.h> | ||
| 14 | #include <keys/asymmetric-parser.h> | ||
| 15 | #include <linux/seq_file.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/slab.h> | ||
| 18 | #include "asymmetric_keys.h" | ||
| 19 | |||
| 20 | MODULE_LICENSE("GPL"); | ||
| 21 | |||
| 22 | static LIST_HEAD(asymmetric_key_parsers); | ||
| 23 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); | ||
| 24 | |||
| 25 | /* | ||
| 26 | * Match asymmetric keys on (part of) their name | ||
| 27 | * We have some shorthand methods for matching keys. We allow: | ||
| 28 | * | ||
| 29 | * "<desc>" - request a key by description | ||
| 30 | * "id:<id>" - request a key matching the ID | ||
| 31 | * "<subtype>:<id>" - request a key of a subtype | ||
| 32 | */ | ||
| 33 | static int asymmetric_key_match(const struct key *key, const void *description) | ||
| 34 | { | ||
| 35 | const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); | ||
| 36 | const char *spec = description; | ||
| 37 | const char *id, *kid; | ||
| 38 | ptrdiff_t speclen; | ||
| 39 | size_t idlen, kidlen; | ||
| 40 | |||
| 41 | if (!subtype || !spec || !*spec) | ||
| 42 | return 0; | ||
| 43 | |||
| 44 | /* See if the full key description matches as is */ | ||
| 45 | if (key->description && strcmp(key->description, description) == 0) | ||
| 46 | return 1; | ||
| 47 | |||
| 48 | /* All tests from here on break the criterion description into a | ||
| 49 | * specifier, a colon and then an identifier. | ||
| 50 | */ | ||
| 51 | id = strchr(spec, ':'); | ||
| 52 | if (!id) | ||
| 53 | return 0; | ||
| 54 | |||
| 55 | speclen = id - spec; | ||
| 56 | id++; | ||
| 57 | |||
| 58 | /* Anything after here requires a partial match on the ID string */ | ||
| 59 | kid = asymmetric_key_id(key); | ||
| 60 | if (!kid) | ||
| 61 | return 0; | ||
| 62 | |||
| 63 | idlen = strlen(id); | ||
| 64 | kidlen = strlen(kid); | ||
| 65 | if (idlen > kidlen) | ||
| 66 | return 0; | ||
| 67 | |||
| 68 | kid += kidlen - idlen; | ||
| 69 | if (strcasecmp(id, kid) != 0) | ||
| 70 | return 0; | ||
| 71 | |||
| 72 | if (speclen == 2 && | ||
| 73 | memcmp(spec, "id", 2) == 0) | ||
| 74 | return 1; | ||
| 75 | |||
| 76 | if (speclen == subtype->name_len && | ||
| 77 | memcmp(spec, subtype->name, speclen) == 0) | ||
| 78 | return 1; | ||
| 79 | |||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | /* | ||
| 84 | * Describe the asymmetric key | ||
| 85 | */ | ||
| 86 | static void asymmetric_key_describe(const struct key *key, struct seq_file *m) | ||
| 87 | { | ||
| 88 | const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); | ||
| 89 | const char *kid = asymmetric_key_id(key); | ||
| 90 | size_t n; | ||
| 91 | |||
| 92 | seq_puts(m, key->description); | ||
| 93 | |||
| 94 | if (subtype) { | ||
| 95 | seq_puts(m, ": "); | ||
| 96 | subtype->describe(key, m); | ||
| 97 | |||
| 98 | if (kid) { | ||
| 99 | seq_putc(m, ' '); | ||
| 100 | n = strlen(kid); | ||
| 101 | if (n <= 8) | ||
| 102 | seq_puts(m, kid); | ||
| 103 | else | ||
| 104 | seq_puts(m, kid + n - 8); | ||
| 105 | } | ||
| 106 | |||
| 107 | seq_puts(m, " ["); | ||
| 108 | /* put something here to indicate the key's capabilities */ | ||
| 109 | seq_putc(m, ']'); | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | /* | ||
| 114 | * Preparse a asymmetric payload to get format the contents appropriately for the | ||
| 115 | * internal payload to cut down on the number of scans of the data performed. | ||
| 116 | * | ||
| 117 | * We also generate a proposed description from the contents of the key that | ||
| 118 | * can be used to name the key if the user doesn't want to provide one. | ||
| 119 | */ | ||
| 120 | static int asymmetric_key_preparse(struct key_preparsed_payload *prep) | ||
| 121 | { | ||
| 122 | struct asymmetric_key_parser *parser; | ||
| 123 | int ret; | ||
| 124 | |||
| 125 | pr_devel("==>%s()\n", __func__); | ||
| 126 | |||
| 127 | if (prep->datalen == 0) | ||
| 128 | return -EINVAL; | ||
| 129 | |||
| 130 | down_read(&asymmetric_key_parsers_sem); | ||
| 131 | |||
| 132 | ret = -EBADMSG; | ||
| 133 | list_for_each_entry(parser, &asymmetric_key_parsers, link) { | ||
| 134 | pr_debug("Trying parser '%s'\n", parser->name); | ||
| 135 | |||
| 136 | ret = parser->parse(prep); | ||
| 137 | if (ret != -EBADMSG) { | ||
| 138 | pr_debug("Parser recognised the format (ret %d)\n", | ||
| 139 | ret); | ||
| 140 | break; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | up_read(&asymmetric_key_parsers_sem); | ||
| 145 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
| 146 | return ret; | ||
| 147 | } | ||
| 148 | |||
| 149 | /* | ||
| 150 | * Clean up the preparse data | ||
| 151 | */ | ||
| 152 | static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) | ||
| 153 | { | ||
| 154 | struct asymmetric_key_subtype *subtype = prep->type_data[0]; | ||
| 155 | |||
| 156 | pr_devel("==>%s()\n", __func__); | ||
| 157 | |||
| 158 | if (subtype) { | ||
| 159 | subtype->destroy(prep->payload); | ||
| 160 | module_put(subtype->owner); | ||
| 161 | } | ||
| 162 | kfree(prep->type_data[1]); | ||
| 163 | kfree(prep->description); | ||
| 164 | } | ||
| 165 | |||
| 166 | /* | ||
| 167 | * Instantiate a asymmetric_key defined key. The key was preparsed, so we just | ||
| 168 | * have to transfer the data here. | ||
| 169 | */ | ||
| 170 | static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | ||
| 171 | { | ||
| 172 | int ret; | ||
| 173 | |||
| 174 | pr_devel("==>%s()\n", __func__); | ||
| 175 | |||
| 176 | ret = key_payload_reserve(key, prep->quotalen); | ||
| 177 | if (ret == 0) { | ||
| 178 | key->type_data.p[0] = prep->type_data[0]; | ||
| 179 | key->type_data.p[1] = prep->type_data[1]; | ||
| 180 | key->payload.data = prep->payload; | ||
| 181 | prep->type_data[0] = NULL; | ||
| 182 | prep->type_data[1] = NULL; | ||
| 183 | prep->payload = NULL; | ||
| 184 | } | ||
| 185 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
| 186 | return ret; | ||
| 187 | } | ||
| 188 | |||
| 189 | /* | ||
| 190 | * dispose of the data dangling from the corpse of a asymmetric key | ||
| 191 | */ | ||
| 192 | static void asymmetric_key_destroy(struct key *key) | ||
| 193 | { | ||
| 194 | struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); | ||
| 195 | if (subtype) { | ||
| 196 | subtype->destroy(key->payload.data); | ||
| 197 | module_put(subtype->owner); | ||
| 198 | key->type_data.p[0] = NULL; | ||
| 199 | } | ||
| 200 | kfree(key->type_data.p[1]); | ||
| 201 | key->type_data.p[1] = NULL; | ||
| 202 | } | ||
| 203 | |||
| 204 | struct key_type key_type_asymmetric = { | ||
| 205 | .name = "asymmetric", | ||
| 206 | .preparse = asymmetric_key_preparse, | ||
| 207 | .free_preparse = asymmetric_key_free_preparse, | ||
| 208 | .instantiate = asymmetric_key_instantiate, | ||
| 209 | .match = asymmetric_key_match, | ||
| 210 | .destroy = asymmetric_key_destroy, | ||
| 211 | .describe = asymmetric_key_describe, | ||
| 212 | }; | ||
| 213 | EXPORT_SYMBOL_GPL(key_type_asymmetric); | ||
| 214 | |||
| 215 | /** | ||
| 216 | * register_asymmetric_key_parser - Register a asymmetric key blob parser | ||
| 217 | * @parser: The parser to register | ||
| 218 | */ | ||
| 219 | int register_asymmetric_key_parser(struct asymmetric_key_parser *parser) | ||
| 220 | { | ||
| 221 | struct asymmetric_key_parser *cursor; | ||
| 222 | int ret; | ||
| 223 | |||
| 224 | down_write(&asymmetric_key_parsers_sem); | ||
| 225 | |||
| 226 | list_for_each_entry(cursor, &asymmetric_key_parsers, link) { | ||
| 227 | if (strcmp(cursor->name, parser->name) == 0) { | ||
| 228 | pr_err("Asymmetric key parser '%s' already registered\n", | ||
| 229 | parser->name); | ||
| 230 | ret = -EEXIST; | ||
| 231 | goto out; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | list_add_tail(&parser->link, &asymmetric_key_parsers); | ||
| 236 | |||
| 237 | pr_notice("Asymmetric key parser '%s' registered\n", parser->name); | ||
| 238 | ret = 0; | ||
| 239 | |||
| 240 | out: | ||
| 241 | up_write(&asymmetric_key_parsers_sem); | ||
| 242 | return ret; | ||
| 243 | } | ||
| 244 | EXPORT_SYMBOL_GPL(register_asymmetric_key_parser); | ||
| 245 | |||
| 246 | /** | ||
| 247 | * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser | ||
| 248 | * @parser: The parser to unregister | ||
| 249 | */ | ||
| 250 | void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser) | ||
| 251 | { | ||
| 252 | down_write(&asymmetric_key_parsers_sem); | ||
| 253 | list_del(&parser->link); | ||
| 254 | up_write(&asymmetric_key_parsers_sem); | ||
| 255 | |||
| 256 | pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name); | ||
| 257 | } | ||
| 258 | EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser); | ||
| 259 | |||
| 260 | /* | ||
| 261 | * Module stuff | ||
| 262 | */ | ||
| 263 | static int __init asymmetric_key_init(void) | ||
| 264 | { | ||
| 265 | return register_key_type(&key_type_asymmetric); | ||
| 266 | } | ||
| 267 | |||
| 268 | static void __exit asymmetric_key_cleanup(void) | ||
| 269 | { | ||
| 270 | unregister_key_type(&key_type_asymmetric); | ||
| 271 | } | ||
| 272 | |||
| 273 | module_init(asymmetric_key_init); | ||
| 274 | module_exit(asymmetric_key_cleanup); | ||
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c new file mode 100644 index 000000000000..cb2e29180a87 --- /dev/null +++ b/crypto/asymmetric_keys/public_key.c | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | /* In-software asymmetric public-key crypto subtype | ||
| 2 | * | ||
| 3 | * See Documentation/crypto/asymmetric-keys.txt | ||
| 4 | * | ||
| 5 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
| 6 | * Written by David Howells (dhowells@redhat.com) | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public Licence | ||
| 10 | * as published by the Free Software Foundation; either version | ||
| 11 | * 2 of the Licence, or (at your option) any later version. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #define pr_fmt(fmt) "PKEY: "fmt | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/export.h> | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <linux/seq_file.h> | ||
| 20 | #include <keys/asymmetric-subtype.h> | ||
| 21 | #include "public_key.h" | ||
| 22 | |||
| 23 | MODULE_LICENSE("GPL"); | ||
| 24 | |||
| 25 | const char *const pkey_algo[PKEY_ALGO__LAST] = { | ||
| 26 | [PKEY_ALGO_DSA] = "DSA", | ||
| 27 | [PKEY_ALGO_RSA] = "RSA", | ||
| 28 | }; | ||
| 29 | EXPORT_SYMBOL_GPL(pkey_algo); | ||
| 30 | |||
| 31 | const char *const pkey_hash_algo[PKEY_HASH__LAST] = { | ||
| 32 | [PKEY_HASH_MD4] = "md4", | ||
| 33 | [PKEY_HASH_MD5] = "md5", | ||
| 34 | [PKEY_HASH_SHA1] = "sha1", | ||
| 35 | [PKEY_HASH_RIPE_MD_160] = "rmd160", | ||
| 36 | [PKEY_HASH_SHA256] = "sha256", | ||
| 37 | [PKEY_HASH_SHA384] = "sha384", | ||
| 38 | [PKEY_HASH_SHA512] = "sha512", | ||
| 39 | [PKEY_HASH_SHA224] = "sha224", | ||
| 40 | }; | ||
| 41 | EXPORT_SYMBOL_GPL(pkey_hash_algo); | ||
| 42 | |||
| 43 | const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = { | ||
| 44 | [PKEY_ID_PGP] = "PGP", | ||
| 45 | [PKEY_ID_X509] = "X509", | ||
| 46 | }; | ||
| 47 | EXPORT_SYMBOL_GPL(pkey_id_type); | ||
| 48 | |||
| 49 | /* | ||
| 50 | * Provide a part of a description of the key for /proc/keys. | ||
| 51 | */ | ||
| 52 | static void public_key_describe(const struct key *asymmetric_key, | ||
| 53 | struct seq_file *m) | ||
| 54 | { | ||
| 55 | struct public_key *key = asymmetric_key->payload.data; | ||
| 56 | |||
| 57 | if (key) | ||
| 58 | seq_printf(m, "%s.%s", | ||
| 59 | pkey_id_type[key->id_type], key->algo->name); | ||
| 60 | } | ||
| 61 | |||
| 62 | /* | ||
| 63 | * Destroy a public key algorithm key. | ||
| 64 | */ | ||
| 65 | void public_key_destroy(void *payload) | ||
| 66 | { | ||
| 67 | struct public_key *key = payload; | ||
| 68 | int i; | ||
| 69 | |||
| 70 | if (key) { | ||
| 71 | for (i = 0; i < ARRAY_SIZE(key->mpi); i++) | ||
| 72 | mpi_free(key->mpi[i]); | ||
| 73 | kfree(key); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | EXPORT_SYMBOL_GPL(public_key_destroy); | ||
| 77 | |||
| 78 | /* | ||
| 79 | * Verify a signature using a public key. | ||
| 80 | */ | ||
| 81 | static int public_key_verify_signature(const struct key *key, | ||
| 82 | const struct public_key_signature *sig) | ||
| 83 | { | ||
| 84 | const struct public_key *pk = key->payload.data; | ||
| 85 | |||
| 86 | if (!pk->algo->verify_signature) | ||
| 87 | return -ENOTSUPP; | ||
| 88 | |||
| 89 | if (sig->nr_mpi != pk->algo->n_sig_mpi) { | ||
| 90 | pr_debug("Signature has %u MPI not %u\n", | ||
| 91 | sig->nr_mpi, pk->algo->n_sig_mpi); | ||
| 92 | return -EINVAL; | ||
| 93 | } | ||
| 94 | |||
| 95 | return pk->algo->verify_signature(pk, sig); | ||
| 96 | } | ||
| 97 | |||
| 98 | /* | ||
| 99 | * Public key algorithm asymmetric key subtype | ||
| 100 | */ | ||
| 101 | struct asymmetric_key_subtype public_key_subtype = { | ||
| 102 | .owner = THIS_MODULE, | ||
| 103 | .name = "public_key", | ||
| 104 | .describe = public_key_describe, | ||
| 105 | .destroy = public_key_destroy, | ||
| 106 | .verify_signature = public_key_verify_signature, | ||
| 107 | }; | ||
| 108 | EXPORT_SYMBOL_GPL(public_key_subtype); | ||
diff --git a/crypto/asymmetric_keys/public_key.h b/crypto/asymmetric_keys/public_key.h new file mode 100644 index 000000000000..5e5e35626899 --- /dev/null +++ b/crypto/asymmetric_keys/public_key.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* Public key algorithm internals | ||
| 2 | * | ||
| 3 | * See Documentation/crypto/asymmetric-keys.txt | ||
| 4 | * | ||
| 5 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
| 6 | * Written by David Howells (dhowells@redhat.com) | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public Licence | ||
| 10 | * as published by the Free Software Foundation; either version | ||
| 11 | * 2 of the Licence, or (at your option) any later version. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <crypto/public_key.h> | ||
| 15 | |||
| 16 | extern struct asymmetric_key_subtype public_key_subtype; | ||
| 17 | |||
| 18 | /* | ||
| 19 | * Public key algorithm definition. | ||
| 20 | */ | ||
| 21 | struct public_key_algorithm { | ||
| 22 | const char *name; | ||
| 23 | u8 n_pub_mpi; /* Number of MPIs in public key */ | ||
| 24 | u8 n_sec_mpi; /* Number of MPIs in secret key */ | ||
| 25 | u8 n_sig_mpi; /* Number of MPIs in a signature */ | ||
| 26 | int (*verify_signature)(const struct public_key *key, | ||
| 27 | const struct public_key_signature *sig); | ||
| 28 | }; | ||
| 29 | |||
| 30 | extern const struct public_key_algorithm RSA_public_key_algorithm; | ||
diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c new file mode 100644 index 000000000000..4a6a0696f8a3 --- /dev/null +++ b/crypto/asymmetric_keys/rsa.c | |||
| @@ -0,0 +1,277 @@ | |||
| 1 | /* RSA asymmetric public-key algorithm [RFC3447] | ||
| 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) "RSA: "fmt | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include "public_key.h" | ||
| 17 | |||
| 18 | MODULE_LICENSE("GPL"); | ||
| 19 | MODULE_DESCRIPTION("RSA Public Key Algorithm"); | ||
| 20 | |||
| 21 | #define kenter(FMT, ...) \ | ||
| 22 | pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) | ||
| 23 | #define kleave(FMT, ...) \ | ||
| 24 | pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) | ||
| 25 | |||
| 26 | /* | ||
| 27 | * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2]. | ||
| 28 | */ | ||
| 29 | static const u8 RSA_digest_info_MD5[] = { | ||
| 30 | 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, | ||
| 31 | 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */ | ||
| 32 | 0x05, 0x00, 0x04, 0x10 | ||
| 33 | }; | ||
| 34 | |||
| 35 | static const u8 RSA_digest_info_SHA1[] = { | ||
| 36 | 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, | ||
| 37 | 0x2B, 0x0E, 0x03, 0x02, 0x1A, | ||
| 38 | 0x05, 0x00, 0x04, 0x14 | ||
| 39 | }; | ||
| 40 | |||
| 41 | static const u8 RSA_digest_info_RIPE_MD_160[] = { | ||
| 42 | 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, | ||
| 43 | 0x2B, 0x24, 0x03, 0x02, 0x01, | ||
| 44 | 0x05, 0x00, 0x04, 0x14 | ||
| 45 | }; | ||
| 46 | |||
| 47 | static const u8 RSA_digest_info_SHA224[] = { | ||
| 48 | 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, | ||
| 49 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, | ||
| 50 | 0x05, 0x00, 0x04, 0x1C | ||
| 51 | }; | ||
| 52 | |||
| 53 | static const u8 RSA_digest_info_SHA256[] = { | ||
| 54 | 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, | ||
| 55 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, | ||
| 56 | 0x05, 0x00, 0x04, 0x20 | ||
| 57 | }; | ||
| 58 | |||
| 59 | static const u8 RSA_digest_info_SHA384[] = { | ||
| 60 | 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, | ||
| 61 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, | ||
| 62 | 0x05, 0x00, 0x04, 0x30 | ||
| 63 | }; | ||
| 64 | |||
| 65 | static const u8 RSA_digest_info_SHA512[] = { | ||
| 66 | 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, | ||
| 67 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, | ||
| 68 | 0x05, 0x00, 0x04, 0x40 | ||
| 69 | }; | ||
| 70 | |||
| 71 | static const struct { | ||
| 72 | const u8 *data; | ||
| 73 | size_t size; | ||
| 74 | } RSA_ASN1_templates[PKEY_HASH__LAST] = { | ||
| 75 | #define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) } | ||
| 76 | [PKEY_HASH_MD5] = _(MD5), | ||
| 77 | [PKEY_HASH_SHA1] = _(SHA1), | ||
| 78 | [PKEY_HASH_RIPE_MD_160] = _(RIPE_MD_160), | ||
| 79 | [PKEY_HASH_SHA256] = _(SHA256), | ||
| 80 | [PKEY_HASH_SHA384] = _(SHA384), | ||
| 81 | [PKEY_HASH_SHA512] = _(SHA512), | ||
| 82 | [PKEY_HASH_SHA224] = _(SHA224), | ||
| 83 | #undef _ | ||
| 84 | }; | ||
| 85 | |||
| 86 | /* | ||
| 87 | * RSAVP1() function [RFC3447 sec 5.2.2] | ||
| 88 | */ | ||
| 89 | static int RSAVP1(const struct public_key *key, MPI s, MPI *_m) | ||
| 90 | { | ||
| 91 | MPI m; | ||
| 92 | int ret; | ||
| 93 | |||
| 94 | /* (1) Validate 0 <= s < n */ | ||
| 95 | if (mpi_cmp_ui(s, 0) < 0) { | ||
| 96 | kleave(" = -EBADMSG [s < 0]"); | ||
| 97 | return -EBADMSG; | ||
| 98 | } | ||
| 99 | if (mpi_cmp(s, key->rsa.n) >= 0) { | ||
| 100 | kleave(" = -EBADMSG [s >= n]"); | ||
| 101 | return -EBADMSG; | ||
| 102 | } | ||
| 103 | |||
| 104 | m = mpi_alloc(0); | ||
| 105 | if (!m) | ||
| 106 | return -ENOMEM; | ||
| 107 | |||
| 108 | /* (2) m = s^e mod n */ | ||
| 109 | ret = mpi_powm(m, s, key->rsa.e, key->rsa.n); | ||
| 110 | if (ret < 0) { | ||
| 111 | mpi_free(m); | ||
| 112 | return ret; | ||
| 113 | } | ||
| 114 | |||
| 115 | *_m = m; | ||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | /* | ||
| 120 | * Integer to Octet String conversion [RFC3447 sec 4.1] | ||
| 121 | */ | ||
| 122 | static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X) | ||
| 123 | { | ||
| 124 | unsigned X_size, x_size; | ||
| 125 | int X_sign; | ||
| 126 | u8 *X; | ||
| 127 | |||
| 128 | /* Make sure the string is the right length. The number should begin | ||
| 129 | * with { 0x00, 0x01, ... } so we have to account for 15 leading zero | ||
| 130 | * bits not being reported by MPI. | ||
| 131 | */ | ||
| 132 | x_size = mpi_get_nbits(x); | ||
| 133 | pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8); | ||
| 134 | if (x_size != xLen * 8 - 15) | ||
| 135 | return -ERANGE; | ||
| 136 | |||
| 137 | X = mpi_get_buffer(x, &X_size, &X_sign); | ||
| 138 | if (!X) | ||
| 139 | return -ENOMEM; | ||
| 140 | if (X_sign < 0) { | ||
| 141 | kfree(X); | ||
| 142 | return -EBADMSG; | ||
| 143 | } | ||
| 144 | if (X_size != xLen - 1) { | ||
| 145 | kfree(X); | ||
| 146 | return -EBADMSG; | ||
| 147 | } | ||
| 148 | |||
| 149 | *_X = X; | ||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | /* | ||
| 154 | * Perform the RSA signature verification. | ||
| 155 | * @H: Value of hash of data and metadata | ||
| 156 | * @EM: The computed signature value | ||
| 157 | * @k: The size of EM (EM[0] is an invalid location but should hold 0x00) | ||
| 158 | * @hash_size: The size of H | ||
| 159 | * @asn1_template: The DigestInfo ASN.1 template | ||
| 160 | * @asn1_size: Size of asm1_template[] | ||
| 161 | */ | ||
| 162 | static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size, | ||
| 163 | const u8 *asn1_template, size_t asn1_size) | ||
| 164 | { | ||
| 165 | unsigned PS_end, T_offset, i; | ||
| 166 | |||
| 167 | kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size); | ||
| 168 | |||
| 169 | if (k < 2 + 1 + asn1_size + hash_size) | ||
| 170 | return -EBADMSG; | ||
| 171 | |||
| 172 | /* Decode the EMSA-PKCS1-v1_5 */ | ||
| 173 | if (EM[1] != 0x01) { | ||
| 174 | kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]); | ||
| 175 | return -EBADMSG; | ||
| 176 | } | ||
| 177 | |||
| 178 | T_offset = k - (asn1_size + hash_size); | ||
| 179 | PS_end = T_offset - 1; | ||
| 180 | if (EM[PS_end] != 0x00) { | ||
| 181 | kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]); | ||
| 182 | return -EBADMSG; | ||
| 183 | } | ||
| 184 | |||
| 185 | for (i = 2; i < PS_end; i++) { | ||
| 186 | if (EM[i] != 0xff) { | ||
| 187 | kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]); | ||
| 188 | return -EBADMSG; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | if (memcmp(asn1_template, EM + T_offset, asn1_size) != 0) { | ||
| 193 | kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]"); | ||
| 194 | return -EBADMSG; | ||
| 195 | } | ||
| 196 | |||
| 197 | if (memcmp(H, EM + T_offset + asn1_size, hash_size) != 0) { | ||
| 198 | kleave(" = -EKEYREJECTED [EM[T] hash mismatch]"); | ||
| 199 | return -EKEYREJECTED; | ||
| 200 | } | ||
| 201 | |||
| 202 | kleave(" = 0"); | ||
| 203 | return 0; | ||
| 204 | } | ||
| 205 | |||
| 206 | /* | ||
| 207 | * Perform the verification step [RFC3447 sec 8.2.2]. | ||
| 208 | */ | ||
| 209 | static int RSA_verify_signature(const struct public_key *key, | ||
| 210 | const struct public_key_signature *sig) | ||
| 211 | { | ||
| 212 | size_t tsize; | ||
| 213 | int ret; | ||
| 214 | |||
| 215 | /* Variables as per RFC3447 sec 8.2.2 */ | ||
| 216 | const u8 *H = sig->digest; | ||
| 217 | u8 *EM = NULL; | ||
| 218 | MPI m = NULL; | ||
| 219 | size_t k; | ||
| 220 | |||
| 221 | kenter(""); | ||
| 222 | |||
| 223 | if (!RSA_ASN1_templates[sig->pkey_hash_algo].data) | ||
| 224 | return -ENOTSUPP; | ||
| 225 | |||
| 226 | /* (1) Check the signature size against the public key modulus size */ | ||
| 227 | k = mpi_get_nbits(key->rsa.n); | ||
| 228 | tsize = mpi_get_nbits(sig->rsa.s); | ||
| 229 | |||
| 230 | /* According to RFC 4880 sec 3.2, length of MPI is computed starting | ||
| 231 | * from most significant bit. So the RFC 3447 sec 8.2.2 size check | ||
| 232 | * must be relaxed to conform with shorter signatures - so we fail here | ||
| 233 | * only if signature length is longer than modulus size. | ||
| 234 | */ | ||
| 235 | pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize); | ||
| 236 | if (k < tsize) { | ||
| 237 | ret = -EBADMSG; | ||
| 238 | goto error; | ||
| 239 | } | ||
| 240 | |||
| 241 | /* Round up and convert to octets */ | ||
| 242 | k = (k + 7) / 8; | ||
| 243 | |||
| 244 | /* (2b) Apply the RSAVP1 verification primitive to the public key */ | ||
| 245 | ret = RSAVP1(key, sig->rsa.s, &m); | ||
| 246 | if (ret < 0) | ||
| 247 | goto error; | ||
| 248 | |||
| 249 | /* (2c) Convert the message representative (m) to an encoded message | ||
| 250 | * (EM) of length k octets. | ||
| 251 | * | ||
| 252 | * NOTE! The leading zero byte is suppressed by MPI, so we pass a | ||
| 253 | * pointer to the _preceding_ byte to RSA_verify()! | ||
| 254 | */ | ||
| 255 | ret = RSA_I2OSP(m, k, &EM); | ||
| 256 | if (ret < 0) | ||
| 257 | goto error; | ||
| 258 | |||
| 259 | ret = RSA_verify(H, EM - 1, k, sig->digest_size, | ||
| 260 | RSA_ASN1_templates[sig->pkey_hash_algo].data, | ||
| 261 | RSA_ASN1_templates[sig->pkey_hash_algo].size); | ||
| 262 | |||
| 263 | error: | ||
| 264 | kfree(EM); | ||
| 265 | mpi_free(m); | ||
| 266 | kleave(" = %d", ret); | ||
| 267 | return ret; | ||
| 268 | } | ||
| 269 | |||
| 270 | const struct public_key_algorithm RSA_public_key_algorithm = { | ||
| 271 | .name = "RSA", | ||
| 272 | .n_pub_mpi = 2, | ||
| 273 | .n_sec_mpi = 3, | ||
| 274 | .n_sig_mpi = 1, | ||
| 275 | .verify_signature = RSA_verify_signature, | ||
| 276 | }; | ||
| 277 | EXPORT_SYMBOL_GPL(RSA_public_key_algorithm); | ||
diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c new file mode 100644 index 000000000000..50b3f880b4ff --- /dev/null +++ b/crypto/asymmetric_keys/signature.c | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* Signature verification with an asymmetric key | ||
| 2 | * | ||
| 3 | * See Documentation/security/asymmetric-keys.txt | ||
| 4 | * | ||
| 5 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
| 6 | * Written by David Howells (dhowells@redhat.com) | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public Licence | ||
| 10 | * as published by the Free Software Foundation; either version | ||
| 11 | * 2 of the Licence, or (at your option) any later version. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <keys/asymmetric-subtype.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/err.h> | ||
| 17 | #include <crypto/public_key.h> | ||
| 18 | #include "asymmetric_keys.h" | ||
| 19 | |||
| 20 | /** | ||
| 21 | * verify_signature - Initiate the use of an asymmetric key to verify a signature | ||
| 22 | * @key: The asymmetric key to verify against | ||
| 23 | * @sig: The signature to check | ||
| 24 | * | ||
| 25 | * Returns 0 if successful or else an error. | ||
| 26 | */ | ||
| 27 | int verify_signature(const struct key *key, | ||
| 28 | const struct public_key_signature *sig) | ||
| 29 | { | ||
| 30 | const struct asymmetric_key_subtype *subtype; | ||
| 31 | int ret; | ||
| 32 | |||
| 33 | pr_devel("==>%s()\n", __func__); | ||
| 34 | |||
| 35 | if (key->type != &key_type_asymmetric) | ||
| 36 | return -EINVAL; | ||
| 37 | subtype = asymmetric_key_subtype(key); | ||
| 38 | if (!subtype || | ||
| 39 | !key->payload.data) | ||
| 40 | return -EINVAL; | ||
| 41 | if (!subtype->verify_signature) | ||
| 42 | return -ENOTSUPP; | ||
| 43 | |||
| 44 | ret = subtype->verify_signature(key, sig); | ||
| 45 | |||
| 46 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
| 47 | return ret; | ||
| 48 | } | ||
| 49 | EXPORT_SYMBOL_GPL(verify_signature); | ||
diff --git a/crypto/asymmetric_keys/x509.asn1 b/crypto/asymmetric_keys/x509.asn1 new file mode 100644 index 000000000000..bf32b3dff088 --- /dev/null +++ b/crypto/asymmetric_keys/x509.asn1 | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | Certificate ::= SEQUENCE { | ||
| 2 | tbsCertificate TBSCertificate ({ x509_note_tbs_certificate }), | ||
| 3 | signatureAlgorithm AlgorithmIdentifier, | ||
| 4 | signature BIT STRING ({ x509_note_signature }) | ||
| 5 | } | ||
| 6 | |||
| 7 | TBSCertificate ::= SEQUENCE { | ||
| 8 | version [ 0 ] Version DEFAULT, | ||
| 9 | serialNumber CertificateSerialNumber, | ||
| 10 | signature AlgorithmIdentifier ({ x509_note_pkey_algo }), | ||
| 11 | issuer Name ({ x509_note_issuer }), | ||
| 12 | validity Validity, | ||
| 13 | subject Name ({ x509_note_subject }), | ||
| 14 | subjectPublicKeyInfo SubjectPublicKeyInfo, | ||
| 15 | issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL, | ||
| 16 | subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL, | ||
| 17 | extensions [ 3 ] Extensions OPTIONAL | ||
| 18 | } | ||
| 19 | |||
| 20 | Version ::= INTEGER | ||
| 21 | CertificateSerialNumber ::= INTEGER | ||
| 22 | |||
| 23 | AlgorithmIdentifier ::= SEQUENCE { | ||
| 24 | algorithm OBJECT IDENTIFIER ({ x509_note_OID }), | ||
| 25 | parameters ANY OPTIONAL | ||
| 26 | } | ||
| 27 | |||
| 28 | Name ::= SEQUENCE OF RelativeDistinguishedName | ||
| 29 | |||
| 30 | RelativeDistinguishedName ::= SET OF AttributeValueAssertion | ||
| 31 | |||
| 32 | AttributeValueAssertion ::= SEQUENCE { | ||
| 33 | attributeType OBJECT IDENTIFIER ({ x509_note_OID }), | ||
| 34 | attributeValue ANY ({ x509_extract_name_segment }) | ||
| 35 | } | ||
| 36 | |||
| 37 | Validity ::= SEQUENCE { | ||
| 38 | notBefore Time ({ x509_note_not_before }), | ||
| 39 | notAfter Time ({ x509_note_not_after }) | ||
| 40 | } | ||
| 41 | |||
| 42 | Time ::= CHOICE { | ||
| 43 | utcTime UTCTime, | ||
| 44 | generalTime GeneralizedTime | ||
| 45 | } | ||
| 46 | |||
| 47 | SubjectPublicKeyInfo ::= SEQUENCE { | ||
| 48 | algorithm AlgorithmIdentifier, | ||
| 49 | subjectPublicKey BIT STRING ({ x509_extract_key_data }) | ||
| 50 | } | ||
| 51 | |||
| 52 | UniqueIdentifier ::= BIT STRING | ||
| 53 | |||
| 54 | Extensions ::= SEQUENCE OF Extension | ||
| 55 | |||
| 56 | Extension ::= SEQUENCE { | ||
| 57 | extnid OBJECT IDENTIFIER ({ x509_note_OID }), | ||
| 58 | critical BOOLEAN DEFAULT, | ||
| 59 | extnValue OCTET STRING ({ x509_process_extension }) | ||
| 60 | } | ||
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c new file mode 100644 index 000000000000..7fabc4c01993 --- /dev/null +++ b/crypto/asymmetric_keys/x509_cert_parser.c | |||
| @@ -0,0 +1,496 @@ | |||
| 1 | /* X.509 certificate parser | ||
| 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/kernel.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include <linux/err.h> | ||
| 16 | #include <linux/oid_registry.h> | ||
| 17 | #include "public_key.h" | ||
| 18 | #include "x509_parser.h" | ||
| 19 | #include "x509-asn1.h" | ||
| 20 | #include "x509_rsakey-asn1.h" | ||
| 21 | |||
| 22 | struct x509_parse_context { | ||
| 23 | struct x509_certificate *cert; /* Certificate being constructed */ | ||
| 24 | unsigned long data; /* Start of data */ | ||
| 25 | const void *cert_start; /* Start of cert content */ | ||
| 26 | const void *key; /* Key data */ | ||
| 27 | size_t key_size; /* Size of key data */ | ||
| 28 | enum OID last_oid; /* Last OID encountered */ | ||
| 29 | enum OID algo_oid; /* Algorithm OID */ | ||
| 30 | unsigned char nr_mpi; /* Number of MPIs stored */ | ||
| 31 | u8 o_size; /* Size of organizationName (O) */ | ||
| 32 | u8 cn_size; /* Size of commonName (CN) */ | ||
| 33 | u8 email_size; /* Size of emailAddress */ | ||
| 34 | u16 o_offset; /* Offset of organizationName (O) */ | ||
| 35 | u16 cn_offset; /* Offset of commonName (CN) */ | ||
| 36 | u16 email_offset; /* Offset of emailAddress */ | ||
| 37 | }; | ||
| 38 | |||
| 39 | /* | ||
| 40 | * Free an X.509 certificate | ||
| 41 | */ | ||
| 42 | void x509_free_certificate(struct x509_certificate *cert) | ||
| 43 | { | ||
| 44 | if (cert) { | ||
| 45 | public_key_destroy(cert->pub); | ||
| 46 | kfree(cert->issuer); | ||
| 47 | kfree(cert->subject); | ||
| 48 | kfree(cert->fingerprint); | ||
| 49 | kfree(cert->authority); | ||
| 50 | kfree(cert); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | /* | ||
| 55 | * Parse an X.509 certificate | ||
| 56 | */ | ||
| 57 | struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) | ||
| 58 | { | ||
| 59 | struct x509_certificate *cert; | ||
| 60 | struct x509_parse_context *ctx; | ||
| 61 | long ret; | ||
| 62 | |||
| 63 | ret = -ENOMEM; | ||
| 64 | cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL); | ||
| 65 | if (!cert) | ||
| 66 | goto error_no_cert; | ||
| 67 | cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL); | ||
| 68 | if (!cert->pub) | ||
| 69 | goto error_no_ctx; | ||
| 70 | ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL); | ||
| 71 | if (!ctx) | ||
| 72 | goto error_no_ctx; | ||
| 73 | |||
| 74 | ctx->cert = cert; | ||
| 75 | ctx->data = (unsigned long)data; | ||
| 76 | |||
| 77 | /* Attempt to decode the certificate */ | ||
| 78 | ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen); | ||
| 79 | if (ret < 0) | ||
| 80 | goto error_decode; | ||
| 81 | |||
| 82 | /* Decode the public key */ | ||
| 83 | ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, | ||
| 84 | ctx->key, ctx->key_size); | ||
| 85 | if (ret < 0) | ||
| 86 | goto error_decode; | ||
| 87 | |||
| 88 | kfree(ctx); | ||
| 89 | return cert; | ||
| 90 | |||
| 91 | error_decode: | ||
| 92 | kfree(ctx); | ||
| 93 | error_no_ctx: | ||
| 94 | x509_free_certificate(cert); | ||
| 95 | error_no_cert: | ||
| 96 | return ERR_PTR(ret); | ||
| 97 | } | ||
| 98 | |||
| 99 | /* | ||
| 100 | * Note an OID when we find one for later processing when we know how | ||
| 101 | * to interpret it. | ||
| 102 | */ | ||
| 103 | int x509_note_OID(void *context, size_t hdrlen, | ||
| 104 | unsigned char tag, | ||
| 105 | const void *value, size_t vlen) | ||
| 106 | { | ||
| 107 | struct x509_parse_context *ctx = context; | ||
| 108 | |||
| 109 | ctx->last_oid = look_up_OID(value, vlen); | ||
| 110 | if (ctx->last_oid == OID__NR) { | ||
| 111 | char buffer[50]; | ||
| 112 | sprint_oid(value, vlen, buffer, sizeof(buffer)); | ||
| 113 | pr_debug("Unknown OID: [%lu] %s\n", | ||
| 114 | (unsigned long)value - ctx->data, buffer); | ||
| 115 | } | ||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | /* | ||
| 120 | * Save the position of the TBS data so that we can check the signature over it | ||
| 121 | * later. | ||
| 122 | */ | ||
| 123 | int x509_note_tbs_certificate(void *context, size_t hdrlen, | ||
| 124 | unsigned char tag, | ||
| 125 | const void *value, size_t vlen) | ||
| 126 | { | ||
| 127 | struct x509_parse_context *ctx = context; | ||
| 128 | |||
| 129 | pr_debug("x509_note_tbs_certificate(,%zu,%02x,%ld,%zu)!\n", | ||
| 130 | hdrlen, tag, (unsigned long)value - ctx->data, vlen); | ||
| 131 | |||
| 132 | ctx->cert->tbs = value - hdrlen; | ||
| 133 | ctx->cert->tbs_size = vlen + hdrlen; | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | /* | ||
| 138 | * Record the public key algorithm | ||
| 139 | */ | ||
| 140 | int x509_note_pkey_algo(void *context, size_t hdrlen, | ||
| 141 | unsigned char tag, | ||
| 142 | const void *value, size_t vlen) | ||
| 143 | { | ||
| 144 | struct x509_parse_context *ctx = context; | ||
| 145 | |||
| 146 | pr_debug("PubKey Algo: %u\n", ctx->last_oid); | ||
| 147 | |||
| 148 | switch (ctx->last_oid) { | ||
| 149 | case OID_md2WithRSAEncryption: | ||
| 150 | case OID_md3WithRSAEncryption: | ||
| 151 | default: | ||
| 152 | return -ENOPKG; /* Unsupported combination */ | ||
| 153 | |||
| 154 | case OID_md4WithRSAEncryption: | ||
| 155 | ctx->cert->sig_hash_algo = PKEY_HASH_MD5; | ||
| 156 | ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; | ||
| 157 | break; | ||
| 158 | |||
| 159 | case OID_sha1WithRSAEncryption: | ||
| 160 | ctx->cert->sig_hash_algo = PKEY_HASH_SHA1; | ||
| 161 | ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; | ||
| 162 | break; | ||
| 163 | |||
| 164 | case OID_sha256WithRSAEncryption: | ||
| 165 | ctx->cert->sig_hash_algo = PKEY_HASH_SHA256; | ||
| 166 | ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; | ||
| 167 | break; | ||
| 168 | |||
| 169 | case OID_sha384WithRSAEncryption: | ||
| 170 | ctx->cert->sig_hash_algo = PKEY_HASH_SHA384; | ||
| 171 | ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; | ||
| 172 | break; | ||
| 173 | |||
| 174 | case OID_sha512WithRSAEncryption: | ||
| 175 | ctx->cert->sig_hash_algo = PKEY_HASH_SHA512; | ||
| 176 | ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; | ||
| 177 | break; | ||
| 178 | |||
| 179 | case OID_sha224WithRSAEncryption: | ||
| 180 | ctx->cert->sig_hash_algo = PKEY_HASH_SHA224; | ||
| 181 | ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; | ||
| 182 | break; | ||
| 183 | } | ||
| 184 | |||
| 185 | ctx->algo_oid = ctx->last_oid; | ||
| 186 | return 0; | ||
| 187 | } | ||
| 188 | |||
| 189 | /* | ||
| 190 | * Note the whereabouts and type of the signature. | ||
| 191 | */ | ||
| 192 | int x509_note_signature(void *context, size_t hdrlen, | ||
| 193 | unsigned char tag, | ||
| 194 | const void *value, size_t vlen) | ||
| 195 | { | ||
| 196 | struct x509_parse_context *ctx = context; | ||
| 197 | |||
| 198 | pr_debug("Signature type: %u size %zu\n", ctx->last_oid, vlen); | ||
| 199 | |||
| 200 | if (ctx->last_oid != ctx->algo_oid) { | ||
| 201 | pr_warn("Got cert with pkey (%u) and sig (%u) algorithm OIDs\n", | ||
| 202 | ctx->algo_oid, ctx->last_oid); | ||
| 203 | return -EINVAL; | ||
| 204 | } | ||
| 205 | |||
| 206 | ctx->cert->sig = value; | ||
| 207 | ctx->cert->sig_size = vlen; | ||
| 208 | return 0; | ||
| 209 | } | ||
| 210 | |||
| 211 | /* | ||
| 212 | * Note some of the name segments from which we'll fabricate a name. | ||
| 213 | */ | ||
| 214 | int x509_extract_name_segment(void *context, size_t hdrlen, | ||
| 215 | unsigned char tag, | ||
| 216 | const void *value, size_t vlen) | ||
| 217 | { | ||
| 218 | struct x509_parse_context *ctx = context; | ||
| 219 | |||
| 220 | switch (ctx->last_oid) { | ||
| 221 | case OID_commonName: | ||
| 222 | ctx->cn_size = vlen; | ||
| 223 | ctx->cn_offset = (unsigned long)value - ctx->data; | ||
| 224 | break; | ||
| 225 | case OID_organizationName: | ||
| 226 | ctx->o_size = vlen; | ||
| 227 | ctx->o_offset = (unsigned long)value - ctx->data; | ||
| 228 | break; | ||
| 229 | case OID_email_address: | ||
| 230 | ctx->email_size = vlen; | ||
| 231 | ctx->email_offset = (unsigned long)value - ctx->data; | ||
| 232 | break; | ||
| 233 | default: | ||
| 234 | break; | ||
| 235 | } | ||
| 236 | |||
| 237 | return 0; | ||
| 238 | } | ||
| 239 | |||
| 240 | /* | ||
| 241 | * Fabricate and save the issuer and subject names | ||
| 242 | */ | ||
| 243 | static int x509_fabricate_name(struct x509_parse_context *ctx, size_t hdrlen, | ||
| 244 | unsigned char tag, | ||
| 245 | char **_name, size_t vlen) | ||
| 246 | { | ||
| 247 | const void *name, *data = (const void *)ctx->data; | ||
| 248 | size_t namesize; | ||
| 249 | char *buffer; | ||
| 250 | |||
| 251 | if (*_name) | ||
| 252 | return -EINVAL; | ||
| 253 | |||
| 254 | /* Empty name string if no material */ | ||
| 255 | if (!ctx->cn_size && !ctx->o_size && !ctx->email_size) { | ||
| 256 | buffer = kmalloc(1, GFP_KERNEL); | ||
| 257 | if (!buffer) | ||
| 258 | return -ENOMEM; | ||
| 259 | buffer[0] = 0; | ||
| 260 | goto done; | ||
| 261 | } | ||
| 262 | |||
| 263 | if (ctx->cn_size && ctx->o_size) { | ||
| 264 | /* Consider combining O and CN, but use only the CN if it is | ||
| 265 | * prefixed by the O, or a significant portion thereof. | ||
| 266 | */ | ||
| 267 | namesize = ctx->cn_size; | ||
| 268 | name = data + ctx->cn_offset; | ||
| 269 | if (ctx->cn_size >= ctx->o_size && | ||
| 270 | memcmp(data + ctx->cn_offset, data + ctx->o_offset, | ||
| 271 | ctx->o_size) == 0) | ||
| 272 | goto single_component; | ||
| 273 | if (ctx->cn_size >= 7 && | ||
| 274 | ctx->o_size >= 7 && | ||
| 275 | memcmp(data + ctx->cn_offset, data + ctx->o_offset, 7) == 0) | ||
| 276 | goto single_component; | ||
| 277 | |||
| 278 | buffer = kmalloc(ctx->o_size + 2 + ctx->cn_size + 1, | ||
| 279 | GFP_KERNEL); | ||
| 280 | if (!buffer) | ||
| 281 | return -ENOMEM; | ||
| 282 | |||
| 283 | memcpy(buffer, | ||
| 284 | data + ctx->o_offset, ctx->o_size); | ||
| 285 | buffer[ctx->o_size + 0] = ':'; | ||
| 286 | buffer[ctx->o_size + 1] = ' '; | ||
| 287 | memcpy(buffer + ctx->o_size + 2, | ||
| 288 | data + ctx->cn_offset, ctx->cn_size); | ||
| 289 | buffer[ctx->o_size + 2 + ctx->cn_size] = 0; | ||
| 290 | goto done; | ||
| 291 | |||
| 292 | } else if (ctx->cn_size) { | ||
| 293 | namesize = ctx->cn_size; | ||
| 294 | name = data + ctx->cn_offset; | ||
| 295 | } else if (ctx->o_size) { | ||
| 296 | namesize = ctx->o_size; | ||
| 297 | name = data + ctx->o_offset; | ||
| 298 | } else { | ||
| 299 | namesize = ctx->email_size; | ||
| 300 | name = data + ctx->email_offset; | ||
| 301 | } | ||
| 302 | |||
| 303 | single_component: | ||
| 304 | buffer = kmalloc(namesize + 1, GFP_KERNEL); | ||
| 305 | if (!buffer) | ||
| 306 | return -ENOMEM; | ||
| 307 | memcpy(buffer, name, namesize); | ||
| 308 | buffer[namesize] = 0; | ||
| 309 | |||
| 310 | done: | ||
| 311 | *_name = buffer; | ||
| 312 | ctx->cn_size = 0; | ||
| 313 | ctx->o_size = 0; | ||
| 314 | ctx->email_size = 0; | ||
| 315 | return 0; | ||
| 316 | } | ||
| 317 | |||
| 318 | int x509_note_issuer(void *context, size_t hdrlen, | ||
| 319 | unsigned char tag, | ||
| 320 | const void *value, size_t vlen) | ||
| 321 | { | ||
| 322 | struct x509_parse_context *ctx = context; | ||
| 323 | return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen); | ||
| 324 | } | ||
| 325 | |||
| 326 | int x509_note_subject(void *context, size_t hdrlen, | ||
| 327 | unsigned char tag, | ||
| 328 | const void *value, size_t vlen) | ||
| 329 | { | ||
| 330 | struct x509_parse_context *ctx = context; | ||
| 331 | return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen); | ||
| 332 | } | ||
| 333 | |||
| 334 | /* | ||
| 335 | * Extract the data for the public key algorithm | ||
| 336 | */ | ||
| 337 | int x509_extract_key_data(void *context, size_t hdrlen, | ||
| 338 | unsigned char tag, | ||
| 339 | const void *value, size_t vlen) | ||
| 340 | { | ||
| 341 | struct x509_parse_context *ctx = context; | ||
| 342 | |||
| 343 | if (ctx->last_oid != OID_rsaEncryption) | ||
| 344 | return -ENOPKG; | ||
| 345 | |||
| 346 | /* There seems to be an extraneous 0 byte on the front of the data */ | ||
| 347 | ctx->cert->pkey_algo = PKEY_ALGO_RSA; | ||
| 348 | ctx->key = value + 1; | ||
| 349 | ctx->key_size = vlen - 1; | ||
| 350 | return 0; | ||
| 351 | } | ||
| 352 | |||
| 353 | /* | ||
| 354 | * Extract a RSA public key value | ||
| 355 | */ | ||
| 356 | int rsa_extract_mpi(void *context, size_t hdrlen, | ||
| 357 | unsigned char tag, | ||
| 358 | const void *value, size_t vlen) | ||
| 359 | { | ||
| 360 | struct x509_parse_context *ctx = context; | ||
| 361 | MPI mpi; | ||
| 362 | |||
| 363 | if (ctx->nr_mpi >= ARRAY_SIZE(ctx->cert->pub->mpi)) { | ||
| 364 | pr_err("Too many public key MPIs in certificate\n"); | ||
| 365 | return -EBADMSG; | ||
| 366 | } | ||
| 367 | |||
| 368 | mpi = mpi_read_raw_data(value, vlen); | ||
| 369 | if (!mpi) | ||
| 370 | return -ENOMEM; | ||
| 371 | |||
| 372 | ctx->cert->pub->mpi[ctx->nr_mpi++] = mpi; | ||
| 373 | return 0; | ||
| 374 | } | ||
| 375 | |||
| 376 | /* | ||
| 377 | * Process certificate extensions that are used to qualify the certificate. | ||
| 378 | */ | ||
| 379 | int x509_process_extension(void *context, size_t hdrlen, | ||
| 380 | unsigned char tag, | ||
| 381 | const void *value, size_t vlen) | ||
| 382 | { | ||
| 383 | struct x509_parse_context *ctx = context; | ||
| 384 | const unsigned char *v = value; | ||
| 385 | char *f; | ||
| 386 | int i; | ||
| 387 | |||
| 388 | pr_debug("Extension: %u\n", ctx->last_oid); | ||
| 389 | |||
| 390 | if (ctx->last_oid == OID_subjectKeyIdentifier) { | ||
| 391 | /* Get hold of the key fingerprint */ | ||
| 392 | if (vlen < 3) | ||
| 393 | return -EBADMSG; | ||
| 394 | if (v[0] != ASN1_OTS || v[1] != vlen - 2) | ||
| 395 | return -EBADMSG; | ||
| 396 | v += 2; | ||
| 397 | vlen -= 2; | ||
| 398 | |||
| 399 | f = kmalloc(vlen * 2 + 1, GFP_KERNEL); | ||
| 400 | if (!f) | ||
| 401 | return -ENOMEM; | ||
| 402 | for (i = 0; i < vlen; i++) | ||
| 403 | sprintf(f + i * 2, "%02x", v[i]); | ||
| 404 | pr_debug("fingerprint %s\n", f); | ||
| 405 | ctx->cert->fingerprint = f; | ||
| 406 | return 0; | ||
| 407 | } | ||
| 408 | |||
| 409 | if (ctx->last_oid == OID_authorityKeyIdentifier) { | ||
| 410 | /* Get hold of the CA key fingerprint */ | ||
| 411 | if (vlen < 5) | ||
| 412 | return -EBADMSG; | ||
| 413 | if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5)) || | ||
| 414 | v[1] != vlen - 2 || | ||
| 415 | v[2] != (ASN1_CONT << 6) || | ||
| 416 | v[3] != vlen - 4) | ||
| 417 | return -EBADMSG; | ||
| 418 | v += 4; | ||
| 419 | vlen -= 4; | ||
| 420 | |||
| 421 | f = kmalloc(vlen * 2 + 1, GFP_KERNEL); | ||
| 422 | if (!f) | ||
| 423 | return -ENOMEM; | ||
| 424 | for (i = 0; i < vlen; i++) | ||
| 425 | sprintf(f + i * 2, "%02x", v[i]); | ||
| 426 | pr_debug("authority %s\n", f); | ||
| 427 | ctx->cert->authority = f; | ||
| 428 | return 0; | ||
| 429 | } | ||
| 430 | |||
| 431 | return 0; | ||
| 432 | } | ||
| 433 | |||
| 434 | /* | ||
| 435 | * Record a certificate time. | ||
| 436 | */ | ||
| 437 | static int x509_note_time(struct tm *tm, size_t hdrlen, | ||
| 438 | unsigned char tag, | ||
| 439 | const unsigned char *value, size_t vlen) | ||
| 440 | { | ||
| 441 | const unsigned char *p = value; | ||
| 442 | |||
| 443 | #define dec2bin(X) ((X) - '0') | ||
| 444 | #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) | ||
| 445 | |||
| 446 | if (tag == ASN1_UNITIM) { | ||
| 447 | /* UTCTime: YYMMDDHHMMSSZ */ | ||
| 448 | if (vlen != 13) | ||
| 449 | goto unsupported_time; | ||
| 450 | tm->tm_year = DD2bin(p); | ||
| 451 | if (tm->tm_year >= 50) | ||
| 452 | tm->tm_year += 1900; | ||
| 453 | else | ||
| 454 | tm->tm_year += 2000; | ||
| 455 | } else if (tag == ASN1_GENTIM) { | ||
| 456 | /* GenTime: YYYYMMDDHHMMSSZ */ | ||
| 457 | if (vlen != 15) | ||
| 458 | goto unsupported_time; | ||
| 459 | tm->tm_year = DD2bin(p) * 100 + DD2bin(p); | ||
| 460 | } else { | ||
| 461 | goto unsupported_time; | ||
| 462 | } | ||
| 463 | |||
| 464 | tm->tm_year -= 1900; | ||
| 465 | tm->tm_mon = DD2bin(p) - 1; | ||
| 466 | tm->tm_mday = DD2bin(p); | ||
| 467 | tm->tm_hour = DD2bin(p); | ||
| 468 | tm->tm_min = DD2bin(p); | ||
| 469 | tm->tm_sec = DD2bin(p); | ||
| 470 | |||
| 471 | if (*p != 'Z') | ||
| 472 | goto unsupported_time; | ||
| 473 | |||
| 474 | return 0; | ||
| 475 | |||
| 476 | unsupported_time: | ||
| 477 | pr_debug("Got unsupported time [tag %02x]: '%*.*s'\n", | ||
| 478 | tag, (int)vlen, (int)vlen, value); | ||
| 479 | return -EBADMSG; | ||
| 480 | } | ||
| 481 | |||
| 482 | int x509_note_not_before(void *context, size_t hdrlen, | ||
| 483 | unsigned char tag, | ||
| 484 | const void *value, size_t vlen) | ||
| 485 | { | ||
| 486 | struct x509_parse_context *ctx = context; | ||
| 487 | return x509_note_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); | ||
| 488 | } | ||
| 489 | |||
| 490 | int x509_note_not_after(void *context, size_t hdrlen, | ||
| 491 | unsigned char tag, | ||
| 492 | const void *value, size_t vlen) | ||
| 493 | { | ||
| 494 | struct x509_parse_context *ctx = context; | ||
| 495 | return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); | ||
| 496 | } | ||
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h new file mode 100644 index 000000000000..f86dc5fcc4ad --- /dev/null +++ b/crypto/asymmetric_keys/x509_parser.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | /* X.509 certificate parser internal definitions | ||
| 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 | #include <crypto/public_key.h> | ||
| 13 | |||
| 14 | struct x509_certificate { | ||
| 15 | struct x509_certificate *next; | ||
| 16 | struct public_key *pub; /* Public key details */ | ||
| 17 | char *issuer; /* Name of certificate issuer */ | ||
| 18 | char *subject; /* Name of certificate subject */ | ||
| 19 | char *fingerprint; /* Key fingerprint as hex */ | ||
| 20 | char *authority; /* Authority key fingerprint as hex */ | ||
| 21 | struct tm valid_from; | ||
| 22 | struct tm valid_to; | ||
| 23 | enum pkey_algo pkey_algo : 8; /* Public key algorithm */ | ||
| 24 | enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */ | ||
| 25 | enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */ | ||
| 26 | const void *tbs; /* Signed data */ | ||
| 27 | size_t tbs_size; /* Size of signed data */ | ||
| 28 | const void *sig; /* Signature data */ | ||
| 29 | size_t sig_size; /* Size of sigature */ | ||
| 30 | }; | ||
| 31 | |||
| 32 | /* | ||
| 33 | * x509_cert_parser.c | ||
| 34 | */ | ||
| 35 | extern void x509_free_certificate(struct x509_certificate *cert); | ||
| 36 | extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); | ||
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c new file mode 100644 index 000000000000..06007f0e880c --- /dev/null +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
| @@ -0,0 +1,239 @@ | |||
| 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 | static const | ||
| 27 | struct public_key_algorithm *x509_public_key_algorithms[PKEY_ALGO__LAST] = { | ||
| 28 | [PKEY_ALGO_DSA] = NULL, | ||
| 29 | #if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \ | ||
| 30 | defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE) | ||
| 31 | [PKEY_ALGO_RSA] = &RSA_public_key_algorithm, | ||
| 32 | #endif | ||
| 33 | }; | ||
| 34 | |||
| 35 | /* | ||
| 36 | * Check the signature on a certificate using the provided public key | ||
| 37 | */ | ||
| 38 | static int x509_check_signature(const struct public_key *pub, | ||
| 39 | const struct x509_certificate *cert) | ||
| 40 | { | ||
| 41 | struct public_key_signature *sig; | ||
| 42 | struct crypto_shash *tfm; | ||
| 43 | struct shash_desc *desc; | ||
| 44 | size_t digest_size, desc_size; | ||
| 45 | int ret; | ||
| 46 | |||
| 47 | pr_devel("==>%s()\n", __func__); | ||
| 48 | |||
| 49 | /* Allocate the hashing algorithm we're going to need and find out how | ||
| 50 | * big the hash operational data will be. | ||
| 51 | */ | ||
| 52 | tfm = crypto_alloc_shash(pkey_hash_algo[cert->sig_hash_algo], 0, 0); | ||
| 53 | if (IS_ERR(tfm)) | ||
| 54 | return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); | ||
| 55 | |||
| 56 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | ||
| 57 | digest_size = crypto_shash_digestsize(tfm); | ||
| 58 | |||
| 59 | /* We allocate the hash operational data storage on the end of our | ||
| 60 | * context data. | ||
| 61 | */ | ||
| 62 | ret = -ENOMEM; | ||
| 63 | sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL); | ||
| 64 | if (!sig) | ||
| 65 | goto error_no_sig; | ||
| 66 | |||
| 67 | sig->pkey_hash_algo = cert->sig_hash_algo; | ||
| 68 | sig->digest = (u8 *)sig + sizeof(*sig) + desc_size; | ||
| 69 | sig->digest_size = digest_size; | ||
| 70 | |||
| 71 | desc = (void *)sig + sizeof(*sig); | ||
| 72 | desc->tfm = tfm; | ||
| 73 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
| 74 | |||
| 75 | ret = crypto_shash_init(desc); | ||
| 76 | if (ret < 0) | ||
| 77 | goto error; | ||
| 78 | |||
| 79 | ret = -ENOMEM; | ||
| 80 | sig->rsa.s = mpi_read_raw_data(cert->sig, cert->sig_size); | ||
| 81 | if (!sig->rsa.s) | ||
| 82 | goto error; | ||
| 83 | |||
| 84 | ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest); | ||
| 85 | if (ret < 0) | ||
| 86 | goto error_mpi; | ||
| 87 | |||
| 88 | ret = pub->algo->verify_signature(pub, sig); | ||
| 89 | |||
| 90 | pr_debug("Cert Verification: %d\n", ret); | ||
| 91 | |||
| 92 | error_mpi: | ||
| 93 | mpi_free(sig->rsa.s); | ||
| 94 | error: | ||
| 95 | kfree(sig); | ||
| 96 | error_no_sig: | ||
| 97 | crypto_free_shash(tfm); | ||
| 98 | |||
| 99 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
| 100 | return ret; | ||
| 101 | } | ||
| 102 | |||
| 103 | /* | ||
| 104 | * Attempt to parse a data blob for a key as an X509 certificate. | ||
| 105 | */ | ||
| 106 | static int x509_key_preparse(struct key_preparsed_payload *prep) | ||
| 107 | { | ||
| 108 | struct x509_certificate *cert; | ||
| 109 | struct tm now; | ||
| 110 | size_t srlen, sulen; | ||
| 111 | char *desc = NULL; | ||
| 112 | int ret; | ||
| 113 | |||
| 114 | cert = x509_cert_parse(prep->data, prep->datalen); | ||
| 115 | if (IS_ERR(cert)) | ||
| 116 | return PTR_ERR(cert); | ||
| 117 | |||
| 118 | pr_devel("Cert Issuer: %s\n", cert->issuer); | ||
| 119 | pr_devel("Cert Subject: %s\n", cert->subject); | ||
| 120 | pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]); | ||
| 121 | pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", | ||
| 122 | cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, | ||
| 123 | cert->valid_from.tm_mday, cert->valid_from.tm_hour, | ||
| 124 | cert->valid_from.tm_min, cert->valid_from.tm_sec); | ||
| 125 | pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n", | ||
| 126 | cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1, | ||
| 127 | cert->valid_to.tm_mday, cert->valid_to.tm_hour, | ||
| 128 | cert->valid_to.tm_min, cert->valid_to.tm_sec); | ||
| 129 | pr_devel("Cert Signature: %s + %s\n", | ||
| 130 | pkey_algo[cert->sig_pkey_algo], | ||
| 131 | pkey_hash_algo[cert->sig_hash_algo]); | ||
| 132 | |||
| 133 | if (!cert->fingerprint || !cert->authority) { | ||
| 134 | pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n", | ||
| 135 | cert->subject); | ||
| 136 | ret = -EKEYREJECTED; | ||
| 137 | goto error_free_cert; | ||
| 138 | } | ||
| 139 | |||
| 140 | time_to_tm(CURRENT_TIME.tv_sec, 0, &now); | ||
| 141 | pr_devel("Now: %04ld-%02d-%02d %02d:%02d:%02d\n", | ||
| 142 | now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, | ||
| 143 | now.tm_hour, now.tm_min, now.tm_sec); | ||
| 144 | if (now.tm_year < cert->valid_from.tm_year || | ||
| 145 | (now.tm_year == cert->valid_from.tm_year && | ||
| 146 | (now.tm_mon < cert->valid_from.tm_mon || | ||
| 147 | (now.tm_mon == cert->valid_from.tm_mon && | ||
| 148 | (now.tm_mday < cert->valid_from.tm_mday || | ||
| 149 | (now.tm_mday == cert->valid_from.tm_mday && | ||
| 150 | (now.tm_hour < cert->valid_from.tm_hour || | ||
| 151 | (now.tm_hour == cert->valid_from.tm_hour && | ||
| 152 | (now.tm_min < cert->valid_from.tm_min || | ||
| 153 | (now.tm_min == cert->valid_from.tm_min && | ||
| 154 | (now.tm_sec < cert->valid_from.tm_sec | ||
| 155 | ))))))))))) { | ||
| 156 | pr_warn("Cert %s is not yet valid\n", cert->fingerprint); | ||
| 157 | ret = -EKEYREJECTED; | ||
| 158 | goto error_free_cert; | ||
| 159 | } | ||
| 160 | if (now.tm_year > cert->valid_to.tm_year || | ||
| 161 | (now.tm_year == cert->valid_to.tm_year && | ||
| 162 | (now.tm_mon > cert->valid_to.tm_mon || | ||
| 163 | (now.tm_mon == cert->valid_to.tm_mon && | ||
| 164 | (now.tm_mday > cert->valid_to.tm_mday || | ||
| 165 | (now.tm_mday == cert->valid_to.tm_mday && | ||
| 166 | (now.tm_hour > cert->valid_to.tm_hour || | ||
| 167 | (now.tm_hour == cert->valid_to.tm_hour && | ||
| 168 | (now.tm_min > cert->valid_to.tm_min || | ||
| 169 | (now.tm_min == cert->valid_to.tm_min && | ||
| 170 | (now.tm_sec > cert->valid_to.tm_sec | ||
| 171 | ))))))))))) { | ||
| 172 | pr_warn("Cert %s has expired\n", cert->fingerprint); | ||
| 173 | ret = -EKEYEXPIRED; | ||
| 174 | goto error_free_cert; | ||
| 175 | } | ||
| 176 | |||
| 177 | cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo]; | ||
| 178 | cert->pub->id_type = PKEY_ID_X509; | ||
| 179 | |||
| 180 | /* Check the signature on the key */ | ||
| 181 | if (strcmp(cert->fingerprint, cert->authority) == 0) { | ||
| 182 | ret = x509_check_signature(cert->pub, cert); | ||
| 183 | if (ret < 0) | ||
| 184 | goto error_free_cert; | ||
| 185 | } | ||
| 186 | |||
| 187 | /* Propose a description */ | ||
| 188 | sulen = strlen(cert->subject); | ||
| 189 | srlen = strlen(cert->fingerprint); | ||
| 190 | ret = -ENOMEM; | ||
| 191 | desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL); | ||
| 192 | if (!desc) | ||
| 193 | goto error_free_cert; | ||
| 194 | memcpy(desc, cert->subject, sulen); | ||
| 195 | desc[sulen] = ':'; | ||
| 196 | desc[sulen + 1] = ' '; | ||
| 197 | memcpy(desc + sulen + 2, cert->fingerprint, srlen); | ||
| 198 | desc[sulen + 2 + srlen] = 0; | ||
| 199 | |||
| 200 | /* We're pinning the module by being linked against it */ | ||
| 201 | __module_get(public_key_subtype.owner); | ||
| 202 | prep->type_data[0] = &public_key_subtype; | ||
| 203 | prep->type_data[1] = cert->fingerprint; | ||
| 204 | prep->payload = cert->pub; | ||
| 205 | prep->description = desc; | ||
| 206 | prep->quotalen = 100; | ||
| 207 | |||
| 208 | /* We've finished with the certificate */ | ||
| 209 | cert->pub = NULL; | ||
| 210 | cert->fingerprint = NULL; | ||
| 211 | desc = NULL; | ||
| 212 | ret = 0; | ||
| 213 | |||
| 214 | error_free_cert: | ||
| 215 | x509_free_certificate(cert); | ||
| 216 | return ret; | ||
| 217 | } | ||
| 218 | |||
| 219 | static struct asymmetric_key_parser x509_key_parser = { | ||
| 220 | .owner = THIS_MODULE, | ||
| 221 | .name = "x509", | ||
| 222 | .parse = x509_key_preparse, | ||
| 223 | }; | ||
| 224 | |||
| 225 | /* | ||
| 226 | * Module stuff | ||
| 227 | */ | ||
| 228 | static int __init x509_key_init(void) | ||
| 229 | { | ||
| 230 | return register_asymmetric_key_parser(&x509_key_parser); | ||
| 231 | } | ||
| 232 | |||
| 233 | static void __exit x509_key_exit(void) | ||
| 234 | { | ||
| 235 | unregister_asymmetric_key_parser(&x509_key_parser); | ||
| 236 | } | ||
| 237 | |||
| 238 | module_init(x509_key_init); | ||
| 239 | module_exit(x509_key_exit); | ||
diff --git a/crypto/asymmetric_keys/x509_rsakey.asn1 b/crypto/asymmetric_keys/x509_rsakey.asn1 new file mode 100644 index 000000000000..4ec7cc6532c1 --- /dev/null +++ b/crypto/asymmetric_keys/x509_rsakey.asn1 | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | RSAPublicKey ::= SEQUENCE { | ||
| 2 | modulus INTEGER ({ rsa_extract_mpi }), -- n | ||
| 3 | publicExponent INTEGER ({ rsa_extract_mpi }) -- e | ||
| 4 | } | ||
