diff options
48 files changed, 3025 insertions, 217 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 8b2ab548b6e4..90c12c591168 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -566,6 +566,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 566 | possible to determine what the correct size should be. | 566 | possible to determine what the correct size should be. |
| 567 | This option provides an override for these situations. | 567 | This option provides an override for these situations. |
| 568 | 568 | ||
| 569 | ca_keys= [KEYS] This parameter identifies a specific key(s) on | ||
| 570 | the system trusted keyring to be used for certificate | ||
| 571 | trust validation. | ||
| 572 | format: { id:<keyid> | builtin } | ||
| 573 | |||
| 569 | ccw_timeout_log [S390] | 574 | ccw_timeout_log [S390] |
| 570 | See Documentation/s390/CommonIO for details. | 575 | See Documentation/s390/CommonIO for details. |
| 571 | 576 | ||
diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt index a4c33f1a7c6d..8727c194ca16 100644 --- a/Documentation/security/keys.txt +++ b/Documentation/security/keys.txt | |||
| @@ -1150,20 +1150,24 @@ The structure has a number of fields, some of which are mandatory: | |||
| 1150 | const void *data; | 1150 | const void *data; |
| 1151 | size_t datalen; | 1151 | size_t datalen; |
| 1152 | size_t quotalen; | 1152 | size_t quotalen; |
| 1153 | time_t expiry; | ||
| 1153 | }; | 1154 | }; |
| 1154 | 1155 | ||
| 1155 | Before calling the method, the caller will fill in data and datalen with | 1156 | Before calling the method, the caller will fill in data and datalen with |
| 1156 | the payload blob parameters; quotalen will be filled in with the default | 1157 | the payload blob parameters; quotalen will be filled in with the default |
| 1157 | quota size from the key type and the rest will be cleared. | 1158 | quota size from the key type; expiry will be set to TIME_T_MAX and the |
| 1159 | rest will be cleared. | ||
| 1158 | 1160 | ||
| 1159 | If a description can be proposed from the payload contents, that should be | 1161 | If a description can be proposed from the payload contents, that should be |
| 1160 | attached as a string to the description field. This will be used for the | 1162 | attached as a string to the description field. This will be used for the |
| 1161 | key description if the caller of add_key() passes NULL or "". | 1163 | key description if the caller of add_key() passes NULL or "". |
| 1162 | 1164 | ||
| 1163 | The method can attach anything it likes to type_data[] and payload. These | 1165 | The method can attach anything it likes to type_data[] and payload. These |
| 1164 | are merely passed along to the instantiate() or update() operations. | 1166 | are merely passed along to the instantiate() or update() operations. If |
| 1167 | set, the expiry time will be applied to the key if it is instantiated from | ||
| 1168 | this data. | ||
| 1165 | 1169 | ||
| 1166 | The method should return 0 if success ful or a negative error code | 1170 | The method should return 0 if successful or a negative error code |
| 1167 | otherwise. | 1171 | otherwise. |
| 1168 | 1172 | ||
| 1169 | 1173 | ||
| @@ -1172,7 +1176,9 @@ The structure has a number of fields, some of which are mandatory: | |||
| 1172 | This method is only required if the preparse() method is provided, | 1176 | This method is only required if the preparse() method is provided, |
| 1173 | otherwise it is unused. It cleans up anything attached to the | 1177 | otherwise it is unused. It cleans up anything attached to the |
| 1174 | description, type_data and payload fields of the key_preparsed_payload | 1178 | description, type_data and payload fields of the key_preparsed_payload |
| 1175 | struct as filled in by the preparse() method. | 1179 | struct as filled in by the preparse() method. It will always be called |
| 1180 | after preparse() returns successfully, even if instantiate() or update() | ||
| 1181 | succeed. | ||
| 1176 | 1182 | ||
| 1177 | 1183 | ||
| 1178 | (*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep); | 1184 | (*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep); |
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index 03a6eb95ab50..4870f28403f5 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig | |||
| @@ -22,7 +22,6 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE | |||
| 22 | 22 | ||
| 23 | config PUBLIC_KEY_ALGO_RSA | 23 | config PUBLIC_KEY_ALGO_RSA |
| 24 | tristate "RSA public-key algorithm" | 24 | tristate "RSA public-key algorithm" |
| 25 | select MPILIB_EXTRA | ||
| 26 | select MPILIB | 25 | select MPILIB |
| 27 | help | 26 | help |
| 28 | This option enables support for the RSA algorithm (PKCS#1, RFC3447). | 27 | This option enables support for the RSA algorithm (PKCS#1, RFC3447). |
| @@ -33,8 +32,39 @@ config X509_CERTIFICATE_PARSER | |||
| 33 | select ASN1 | 32 | select ASN1 |
| 34 | select OID_REGISTRY | 33 | select OID_REGISTRY |
| 35 | help | 34 | help |
| 36 | This option procides support for parsing X.509 format blobs for key | 35 | This option provides support for parsing X.509 format blobs for key |
| 37 | data and provides the ability to instantiate a crypto key from a | 36 | data and provides the ability to instantiate a crypto key from a |
| 38 | public key packet found inside the certificate. | 37 | public key packet found inside the certificate. |
| 39 | 38 | ||
| 39 | config PKCS7_MESSAGE_PARSER | ||
| 40 | tristate "PKCS#7 message parser" | ||
| 41 | depends on X509_CERTIFICATE_PARSER | ||
| 42 | select ASN1 | ||
| 43 | select OID_REGISTRY | ||
| 44 | help | ||
| 45 | This option provides support for parsing PKCS#7 format messages for | ||
| 46 | signature data and provides the ability to verify the signature. | ||
| 47 | |||
| 48 | config PKCS7_TEST_KEY | ||
| 49 | tristate "PKCS#7 testing key type" | ||
| 50 | depends on PKCS7_MESSAGE_PARSER | ||
| 51 | select SYSTEM_TRUSTED_KEYRING | ||
| 52 | help | ||
| 53 | This option provides a type of key that can be loaded up from a | ||
| 54 | PKCS#7 message - provided the message is signed by a trusted key. If | ||
| 55 | it is, the PKCS#7 wrapper is discarded and reading the key returns | ||
| 56 | just the payload. If it isn't, adding the key will fail with an | ||
| 57 | error. | ||
| 58 | |||
| 59 | This is intended for testing the PKCS#7 parser. | ||
| 60 | |||
| 61 | config SIGNED_PE_FILE_VERIFICATION | ||
| 62 | bool "Support for PE file signature verification" | ||
| 63 | depends on PKCS7_MESSAGE_PARSER=y | ||
| 64 | select ASN1 | ||
| 65 | select OID_REGISTRY | ||
| 66 | help | ||
| 67 | This option provides support for verifying the signature(s) on a | ||
| 68 | signed PE binary. | ||
| 69 | |||
| 40 | endif # ASYMMETRIC_KEY_TYPE | 70 | endif # ASYMMETRIC_KEY_TYPE |
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index 0727204aab68..e47fcd9ac5e8 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile | |||
| @@ -25,3 +25,40 @@ $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h | |||
| 25 | 25 | ||
| 26 | clean-files += x509-asn1.c x509-asn1.h | 26 | clean-files += x509-asn1.c x509-asn1.h |
| 27 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h | 27 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h |
| 28 | |||
| 29 | # | ||
| 30 | # PKCS#7 message handling | ||
| 31 | # | ||
| 32 | obj-$(CONFIG_PKCS7_MESSAGE_PARSER) += pkcs7_message.o | ||
| 33 | pkcs7_message-y := \ | ||
| 34 | pkcs7-asn1.o \ | ||
| 35 | pkcs7_parser.o \ | ||
| 36 | pkcs7_trust.o \ | ||
| 37 | pkcs7_verify.o | ||
| 38 | |||
| 39 | $(obj)/pkcs7_parser.o: $(obj)/pkcs7-asn1.h | ||
| 40 | $(obj)/pkcs7-asn1.o: $(obj)/pkcs7-asn1.c $(obj)/pkcs7-asn1.h | ||
| 41 | |||
| 42 | clean-files += pkcs7-asn1.c pkcs7-asn1.h | ||
| 43 | |||
| 44 | # | ||
| 45 | # PKCS#7 parser testing key | ||
| 46 | # | ||
| 47 | obj-$(CONFIG_PKCS7_TEST_KEY) += pkcs7_test_key.o | ||
| 48 | pkcs7_test_key-y := \ | ||
| 49 | pkcs7_key_type.o | ||
| 50 | |||
| 51 | # | ||
| 52 | # Signed PE binary-wrapped key handling | ||
| 53 | # | ||
| 54 | obj-$(CONFIG_SIGNED_PE_FILE_VERIFICATION) += verify_signed_pefile.o | ||
| 55 | |||
| 56 | verify_signed_pefile-y := \ | ||
| 57 | verify_pefile.o \ | ||
| 58 | mscode_parser.o \ | ||
| 59 | mscode-asn1.o | ||
| 60 | |||
| 61 | $(obj)/mscode_parser.o: $(obj)/mscode-asn1.h $(obj)/mscode-asn1.h | ||
| 62 | $(obj)/mscode-asn1.o: $(obj)/mscode-asn1.c $(obj)/mscode-asn1.h | ||
| 63 | |||
| 64 | clean-files += mscode-asn1.c mscode-asn1.h | ||
diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h index 515b63430812..a63c551c6557 100644 --- a/crypto/asymmetric_keys/asymmetric_keys.h +++ b/crypto/asymmetric_keys/asymmetric_keys.h | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | * 2 of the Licence, or (at your option) any later version. | 9 | * 2 of the Licence, or (at your option) any later version. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | int asymmetric_keyid_match(const char *kid, const char *id); | ||
| 13 | |||
| 12 | static inline const char *asymmetric_key_id(const struct key *key) | 14 | static inline const char *asymmetric_key_id(const struct key *key) |
| 13 | { | 15 | { |
| 14 | return key->type_data.p[1]; | 16 | return key->type_data.p[1]; |
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index b77eb5304788..eb8cd46961a5 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c | |||
| @@ -23,6 +23,35 @@ static LIST_HEAD(asymmetric_key_parsers); | |||
| 23 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); | 23 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); |
| 24 | 24 | ||
| 25 | /* | 25 | /* |
| 26 | * Match asymmetric key id with partial match | ||
| 27 | * @id: key id to match in a form "id:<id>" | ||
| 28 | */ | ||
| 29 | int asymmetric_keyid_match(const char *kid, const char *id) | ||
| 30 | { | ||
| 31 | size_t idlen, kidlen; | ||
| 32 | |||
| 33 | if (!kid || !id) | ||
| 34 | return 0; | ||
| 35 | |||
| 36 | /* make it possible to use id as in the request: "id:<id>" */ | ||
| 37 | if (strncmp(id, "id:", 3) == 0) | ||
| 38 | id += 3; | ||
| 39 | |||
| 40 | /* Anything after here requires a partial match on the ID string */ | ||
| 41 | idlen = strlen(id); | ||
| 42 | kidlen = strlen(kid); | ||
| 43 | if (idlen > kidlen) | ||
| 44 | return 0; | ||
| 45 | |||
| 46 | kid += kidlen - idlen; | ||
| 47 | if (strcasecmp(id, kid) != 0) | ||
| 48 | return 0; | ||
| 49 | |||
| 50 | return 1; | ||
| 51 | } | ||
| 52 | EXPORT_SYMBOL_GPL(asymmetric_keyid_match); | ||
| 53 | |||
| 54 | /* | ||
| 26 | * Match asymmetric keys on (part of) their name | 55 | * Match asymmetric keys on (part of) their name |
| 27 | * We have some shorthand methods for matching keys. We allow: | 56 | * We have some shorthand methods for matching keys. We allow: |
| 28 | * | 57 | * |
| @@ -34,9 +63,8 @@ static int asymmetric_key_match(const struct key *key, const void *description) | |||
| 34 | { | 63 | { |
| 35 | const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); | 64 | const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); |
| 36 | const char *spec = description; | 65 | const char *spec = description; |
| 37 | const char *id, *kid; | 66 | const char *id; |
| 38 | ptrdiff_t speclen; | 67 | ptrdiff_t speclen; |
| 39 | size_t idlen, kidlen; | ||
| 40 | 68 | ||
| 41 | if (!subtype || !spec || !*spec) | 69 | if (!subtype || !spec || !*spec) |
| 42 | return 0; | 70 | return 0; |
| @@ -55,23 +83,8 @@ static int asymmetric_key_match(const struct key *key, const void *description) | |||
| 55 | speclen = id - spec; | 83 | speclen = id - spec; |
| 56 | id++; | 84 | id++; |
| 57 | 85 | ||
| 58 | /* Anything after here requires a partial match on the ID string */ | 86 | if (speclen == 2 && memcmp(spec, "id", 2) == 0) |
| 59 | kid = asymmetric_key_id(key); | 87 | return asymmetric_keyid_match(asymmetric_key_id(key), id); |
| 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 | 88 | ||
| 76 | if (speclen == subtype->name_len && | 89 | if (speclen == subtype->name_len && |
| 77 | memcmp(spec, subtype->name, speclen) == 0) | 90 | memcmp(spec, subtype->name, speclen) == 0) |
| @@ -156,7 +169,7 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) | |||
| 156 | pr_devel("==>%s()\n", __func__); | 169 | pr_devel("==>%s()\n", __func__); |
| 157 | 170 | ||
| 158 | if (subtype) { | 171 | if (subtype) { |
| 159 | subtype->destroy(prep->payload); | 172 | subtype->destroy(prep->payload[0]); |
| 160 | module_put(subtype->owner); | 173 | module_put(subtype->owner); |
| 161 | } | 174 | } |
| 162 | kfree(prep->type_data[1]); | 175 | kfree(prep->type_data[1]); |
| @@ -164,29 +177,6 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) | |||
| 164 | } | 177 | } |
| 165 | 178 | ||
| 166 | /* | 179 | /* |
| 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 | 180 | * dispose of the data dangling from the corpse of a asymmetric key |
| 191 | */ | 181 | */ |
| 192 | static void asymmetric_key_destroy(struct key *key) | 182 | static void asymmetric_key_destroy(struct key *key) |
| @@ -205,7 +195,7 @@ struct key_type key_type_asymmetric = { | |||
| 205 | .name = "asymmetric", | 195 | .name = "asymmetric", |
| 206 | .preparse = asymmetric_key_preparse, | 196 | .preparse = asymmetric_key_preparse, |
| 207 | .free_preparse = asymmetric_key_free_preparse, | 197 | .free_preparse = asymmetric_key_free_preparse, |
| 208 | .instantiate = asymmetric_key_instantiate, | 198 | .instantiate = generic_key_instantiate, |
| 209 | .match = asymmetric_key_match, | 199 | .match = asymmetric_key_match, |
| 210 | .destroy = asymmetric_key_destroy, | 200 | .destroy = asymmetric_key_destroy, |
| 211 | .describe = asymmetric_key_describe, | 201 | .describe = asymmetric_key_describe, |
diff --git a/crypto/asymmetric_keys/mscode.asn1 b/crypto/asymmetric_keys/mscode.asn1 new file mode 100644 index 000000000000..6d09ba48c41c --- /dev/null +++ b/crypto/asymmetric_keys/mscode.asn1 | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | --- Microsoft individual code signing data blob 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 | MSCode ::= SEQUENCE { | ||
| 13 | type SEQUENCE { | ||
| 14 | contentType ContentType, | ||
| 15 | parameters ANY | ||
| 16 | }, | ||
| 17 | content SEQUENCE { | ||
| 18 | digestAlgorithm DigestAlgorithmIdentifier, | ||
| 19 | digest OCTET STRING ({ mscode_note_digest }) | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | ContentType ::= OBJECT IDENTIFIER ({ mscode_note_content_type }) | ||
| 24 | |||
| 25 | DigestAlgorithmIdentifier ::= SEQUENCE { | ||
| 26 | algorithm OBJECT IDENTIFIER ({ mscode_note_digest_algo }), | ||
| 27 | parameters ANY OPTIONAL | ||
| 28 | } | ||
diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c new file mode 100644 index 000000000000..214a992123cd --- /dev/null +++ b/crypto/asymmetric_keys/mscode_parser.c | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | /* Parse a Microsoft Individual Code Signing blob | ||
| 2 | * | ||
| 3 | * Copyright (C) 2014 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) "MSCODE: "fmt | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include <linux/err.h> | ||
| 16 | #include <linux/oid_registry.h> | ||
| 17 | #include <crypto/pkcs7.h> | ||
| 18 | #include "verify_pefile.h" | ||
| 19 | #include "mscode-asn1.h" | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Parse a Microsoft Individual Code Signing blob | ||
| 23 | */ | ||
| 24 | int mscode_parse(struct pefile_context *ctx) | ||
| 25 | { | ||
| 26 | const void *content_data; | ||
| 27 | size_t data_len; | ||
| 28 | int ret; | ||
| 29 | |||
| 30 | ret = pkcs7_get_content_data(ctx->pkcs7, &content_data, &data_len, 1); | ||
| 31 | |||
| 32 | if (ret) { | ||
| 33 | pr_debug("PKCS#7 message does not contain data\n"); | ||
| 34 | return ret; | ||
| 35 | } | ||
| 36 | |||
| 37 | pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len), | ||
| 38 | content_data); | ||
| 39 | |||
| 40 | return asn1_ber_decoder(&mscode_decoder, ctx, content_data, data_len); | ||
| 41 | } | ||
| 42 | |||
| 43 | /* | ||
| 44 | * Check the content type OID | ||
| 45 | */ | ||
| 46 | int mscode_note_content_type(void *context, size_t hdrlen, | ||
| 47 | unsigned char tag, | ||
| 48 | const void *value, size_t vlen) | ||
| 49 | { | ||
| 50 | enum OID oid; | ||
| 51 | |||
| 52 | oid = look_up_OID(value, vlen); | ||
| 53 | if (oid == OID__NR) { | ||
| 54 | char buffer[50]; | ||
| 55 | |||
| 56 | sprint_oid(value, vlen, buffer, sizeof(buffer)); | ||
| 57 | pr_err("Unknown OID: %s\n", buffer); | ||
| 58 | return -EBADMSG; | ||
| 59 | } | ||
| 60 | |||
| 61 | /* | ||
| 62 | * pesign utility had a bug where it was putting | ||
| 63 | * OID_msIndividualSPKeyPurpose instead of OID_msPeImageDataObjId | ||
| 64 | * So allow both OIDs. | ||
| 65 | */ | ||
| 66 | if (oid != OID_msPeImageDataObjId && | ||
| 67 | oid != OID_msIndividualSPKeyPurpose) { | ||
| 68 | pr_err("Unexpected content type OID %u\n", oid); | ||
| 69 | return -EBADMSG; | ||
| 70 | } | ||
| 71 | |||
| 72 | return 0; | ||
| 73 | } | ||
| 74 | |||
| 75 | /* | ||
| 76 | * Note the digest algorithm OID | ||
| 77 | */ | ||
| 78 | int mscode_note_digest_algo(void *context, size_t hdrlen, | ||
| 79 | unsigned char tag, | ||
| 80 | const void *value, size_t vlen) | ||
| 81 | { | ||
| 82 | struct pefile_context *ctx = context; | ||
| 83 | char buffer[50]; | ||
| 84 | enum OID oid; | ||
| 85 | |||
| 86 | oid = look_up_OID(value, vlen); | ||
| 87 | switch (oid) { | ||
| 88 | case OID_md4: | ||
| 89 | ctx->digest_algo = HASH_ALGO_MD4; | ||
| 90 | break; | ||
| 91 | case OID_md5: | ||
| 92 | ctx->digest_algo = HASH_ALGO_MD5; | ||
| 93 | break; | ||
| 94 | case OID_sha1: | ||
| 95 | ctx->digest_algo = HASH_ALGO_SHA1; | ||
| 96 | break; | ||
| 97 | case OID_sha256: | ||
| 98 | ctx->digest_algo = HASH_ALGO_SHA256; | ||
| 99 | break; | ||
| 100 | |||
| 101 | case OID__NR: | ||
| 102 | sprint_oid(value, vlen, buffer, sizeof(buffer)); | ||
| 103 | pr_err("Unknown OID: %s\n", buffer); | ||
| 104 | return -EBADMSG; | ||
| 105 | |||
| 106 | default: | ||
| 107 | pr_err("Unsupported content type: %u\n", oid); | ||
| 108 | return -ENOPKG; | ||
| 109 | } | ||
| 110 | |||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | /* | ||
| 115 | * Note the digest we're guaranteeing with this certificate | ||
| 116 | */ | ||
| 117 | int mscode_note_digest(void *context, size_t hdrlen, | ||
| 118 | unsigned char tag, | ||
| 119 | const void *value, size_t vlen) | ||
| 120 | { | ||
| 121 | struct pefile_context *ctx = context; | ||
| 122 | |||
| 123 | ctx->digest = value; | ||
| 124 | ctx->digest_len = vlen; | ||
| 125 | return 0; | ||
| 126 | } | ||
diff --git a/crypto/asymmetric_keys/pkcs7.asn1 b/crypto/asymmetric_keys/pkcs7.asn1 new file mode 100644 index 000000000000..a5a14ef28c86 --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7.asn1 | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | PKCS7ContentInfo ::= SEQUENCE { | ||
| 2 | contentType ContentType, | ||
| 3 | content [0] EXPLICIT SignedData OPTIONAL | ||
| 4 | } | ||
| 5 | |||
| 6 | ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID }) | ||
| 7 | |||
| 8 | SignedData ::= SEQUENCE { | ||
| 9 | version INTEGER, | ||
| 10 | digestAlgorithms DigestAlgorithmIdentifiers, | ||
| 11 | contentInfo ContentInfo, | ||
| 12 | certificates CHOICE { | ||
| 13 | certSet [0] IMPLICIT ExtendedCertificatesAndCertificates, | ||
| 14 | certSequence [2] IMPLICIT Certificates | ||
| 15 | } OPTIONAL ({ pkcs7_note_certificate_list }), | ||
| 16 | crls CHOICE { | ||
| 17 | crlSet [1] IMPLICIT CertificateRevocationLists, | ||
| 18 | crlSequence [3] IMPLICIT CRLSequence | ||
| 19 | } OPTIONAL, | ||
| 20 | signerInfos SignerInfos | ||
| 21 | } | ||
| 22 | |||
| 23 | ContentInfo ::= SEQUENCE { | ||
| 24 | contentType ContentType, | ||
| 25 | content [0] EXPLICIT Data OPTIONAL | ||
| 26 | } | ||
| 27 | |||
| 28 | Data ::= ANY ({ pkcs7_note_data }) | ||
| 29 | |||
| 30 | DigestAlgorithmIdentifiers ::= CHOICE { | ||
| 31 | daSet SET OF DigestAlgorithmIdentifier, | ||
| 32 | daSequence SEQUENCE OF DigestAlgorithmIdentifier | ||
| 33 | } | ||
| 34 | |||
| 35 | DigestAlgorithmIdentifier ::= SEQUENCE { | ||
| 36 | algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }), | ||
| 37 | parameters ANY OPTIONAL | ||
| 38 | } | ||
| 39 | |||
| 40 | -- | ||
| 41 | -- Certificates and certificate lists | ||
| 42 | -- | ||
| 43 | ExtendedCertificatesAndCertificates ::= SET OF ExtendedCertificateOrCertificate | ||
| 44 | |||
| 45 | ExtendedCertificateOrCertificate ::= CHOICE { | ||
| 46 | certificate Certificate, -- X.509 | ||
| 47 | extendedCertificate [0] IMPLICIT ExtendedCertificate -- PKCS#6 | ||
| 48 | } | ||
| 49 | |||
| 50 | ExtendedCertificate ::= Certificate -- cheating | ||
| 51 | |||
| 52 | Certificates ::= SEQUENCE OF Certificate | ||
| 53 | |||
| 54 | CertificateRevocationLists ::= SET OF CertificateList | ||
| 55 | |||
| 56 | CertificateList ::= SEQUENCE OF Certificate -- This may be defined incorrectly | ||
| 57 | |||
| 58 | CRLSequence ::= SEQUENCE OF CertificateList | ||
| 59 | |||
| 60 | Certificate ::= ANY ({ pkcs7_extract_cert }) -- X.509 | ||
| 61 | |||
| 62 | -- | ||
| 63 | -- Signer information | ||
| 64 | -- | ||
| 65 | SignerInfos ::= CHOICE { | ||
| 66 | siSet SET OF SignerInfo, | ||
| 67 | siSequence SEQUENCE OF SignerInfo | ||
| 68 | } | ||
| 69 | |||
| 70 | SignerInfo ::= SEQUENCE { | ||
| 71 | version INTEGER, | ||
| 72 | issuerAndSerialNumber IssuerAndSerialNumber, | ||
| 73 | digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }), | ||
| 74 | authenticatedAttributes CHOICE { | ||
| 75 | aaSet [0] IMPLICIT SetOfAuthenticatedAttribute | ||
| 76 | ({ pkcs7_sig_note_set_of_authattrs }), | ||
| 77 | aaSequence [2] EXPLICIT SEQUENCE OF AuthenticatedAttribute | ||
| 78 | -- Explicit because easier to compute digest on | ||
| 79 | -- sequence of attributes and then reuse encoded | ||
| 80 | -- sequence in aaSequence. | ||
| 81 | } OPTIONAL, | ||
| 82 | digestEncryptionAlgorithm | ||
| 83 | DigestEncryptionAlgorithmIdentifier ({ pkcs7_sig_note_pkey_algo }), | ||
| 84 | encryptedDigest EncryptedDigest, | ||
| 85 | unauthenticatedAttributes CHOICE { | ||
| 86 | uaSet [1] IMPLICIT SET OF UnauthenticatedAttribute, | ||
| 87 | uaSequence [3] IMPLICIT SEQUENCE OF UnauthenticatedAttribute | ||
| 88 | } OPTIONAL | ||
| 89 | } ({ pkcs7_note_signed_info }) | ||
| 90 | |||
| 91 | IssuerAndSerialNumber ::= SEQUENCE { | ||
| 92 | issuer Name ({ pkcs7_sig_note_issuer }), | ||
| 93 | serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial }) | ||
| 94 | } | ||
| 95 | |||
| 96 | CertificateSerialNumber ::= INTEGER | ||
| 97 | |||
| 98 | SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute | ||
| 99 | |||
| 100 | AuthenticatedAttribute ::= SEQUENCE { | ||
| 101 | type OBJECT IDENTIFIER ({ pkcs7_note_OID }), | ||
| 102 | values SET OF ANY ({ pkcs7_sig_note_authenticated_attr }) | ||
| 103 | } | ||
| 104 | |||
| 105 | UnauthenticatedAttribute ::= SEQUENCE { | ||
| 106 | type OBJECT IDENTIFIER ({ pkcs7_note_OID }), | ||
| 107 | values SET OF ANY | ||
| 108 | } | ||
| 109 | |||
| 110 | DigestEncryptionAlgorithmIdentifier ::= SEQUENCE { | ||
| 111 | algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }), | ||
| 112 | parameters ANY OPTIONAL | ||
| 113 | } | ||
| 114 | |||
| 115 | EncryptedDigest ::= OCTET STRING ({ pkcs7_sig_note_signature }) | ||
| 116 | |||
| 117 | --- | ||
| 118 | --- X.500 Name | ||
| 119 | --- | ||
| 120 | Name ::= SEQUENCE OF RelativeDistinguishedName | ||
| 121 | |||
| 122 | RelativeDistinguishedName ::= SET OF AttributeValueAssertion | ||
| 123 | |||
| 124 | AttributeValueAssertion ::= SEQUENCE { | ||
| 125 | attributeType OBJECT IDENTIFIER ({ pkcs7_note_OID }), | ||
| 126 | attributeValue ANY | ||
| 127 | } | ||
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c new file mode 100644 index 000000000000..c2091f7bd15d --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7_key_type.c | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | /* Testing module to load key from trusted PKCS#7 message | ||
| 2 | * | ||
| 3 | * Copyright (C) 2014 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) "PKCS7key: "fmt | ||
| 13 | #include <linux/key.h> | ||
| 14 | #include <linux/key-type.h> | ||
| 15 | #include <crypto/pkcs7.h> | ||
| 16 | #include <keys/user-type.h> | ||
| 17 | #include <keys/system_keyring.h> | ||
| 18 | #include "pkcs7_parser.h" | ||
| 19 | |||
| 20 | /* | ||
| 21 | * Preparse a PKCS#7 wrapped and validated data blob. | ||
| 22 | */ | ||
| 23 | static int pkcs7_preparse(struct key_preparsed_payload *prep) | ||
| 24 | { | ||
| 25 | struct pkcs7_message *pkcs7; | ||
| 26 | const void *data, *saved_prep_data; | ||
| 27 | size_t datalen, saved_prep_datalen; | ||
| 28 | bool trusted; | ||
| 29 | int ret; | ||
| 30 | |||
| 31 | kenter(""); | ||
| 32 | |||
| 33 | saved_prep_data = prep->data; | ||
| 34 | saved_prep_datalen = prep->datalen; | ||
| 35 | pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); | ||
| 36 | if (IS_ERR(pkcs7)) { | ||
| 37 | ret = PTR_ERR(pkcs7); | ||
| 38 | goto error; | ||
| 39 | } | ||
| 40 | |||
| 41 | ret = pkcs7_verify(pkcs7); | ||
| 42 | if (ret < 0) | ||
| 43 | goto error_free; | ||
| 44 | |||
| 45 | ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); | ||
| 46 | if (ret < 0) | ||
| 47 | goto error_free; | ||
| 48 | if (!trusted) | ||
| 49 | pr_warn("PKCS#7 message doesn't chain back to a trusted key\n"); | ||
| 50 | |||
| 51 | ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false); | ||
| 52 | if (ret < 0) | ||
| 53 | goto error_free; | ||
| 54 | |||
| 55 | prep->data = data; | ||
| 56 | prep->datalen = datalen; | ||
| 57 | ret = user_preparse(prep); | ||
| 58 | prep->data = saved_prep_data; | ||
| 59 | prep->datalen = saved_prep_datalen; | ||
| 60 | |||
| 61 | error_free: | ||
| 62 | pkcs7_free_message(pkcs7); | ||
| 63 | error: | ||
| 64 | kleave(" = %d", ret); | ||
| 65 | return ret; | ||
| 66 | } | ||
| 67 | |||
| 68 | /* | ||
| 69 | * user defined keys take an arbitrary string as the description and an | ||
| 70 | * arbitrary blob of data as the payload | ||
| 71 | */ | ||
| 72 | struct key_type key_type_pkcs7 = { | ||
| 73 | .name = "pkcs7_test", | ||
| 74 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | ||
| 75 | .preparse = pkcs7_preparse, | ||
| 76 | .free_preparse = user_free_preparse, | ||
| 77 | .instantiate = generic_key_instantiate, | ||
| 78 | .match = user_match, | ||
| 79 | .revoke = user_revoke, | ||
| 80 | .destroy = user_destroy, | ||
| 81 | .describe = user_describe, | ||
| 82 | .read = user_read, | ||
| 83 | }; | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Module stuff | ||
| 87 | */ | ||
| 88 | static int __init pkcs7_key_init(void) | ||
| 89 | { | ||
| 90 | return register_key_type(&key_type_pkcs7); | ||
| 91 | } | ||
| 92 | |||
| 93 | static void __exit pkcs7_key_cleanup(void) | ||
| 94 | { | ||
| 95 | unregister_key_type(&key_type_pkcs7); | ||
| 96 | } | ||
| 97 | |||
| 98 | module_init(pkcs7_key_init); | ||
| 99 | module_exit(pkcs7_key_cleanup); | ||
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c new file mode 100644 index 000000000000..42e56aa7d277 --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7_parser.c | |||
| @@ -0,0 +1,396 @@ | |||
| 1 | /* PKCS#7 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) "PKCS7: "fmt | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/export.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/err.h> | ||
| 17 | #include <linux/oid_registry.h> | ||
| 18 | #include "public_key.h" | ||
| 19 | #include "pkcs7_parser.h" | ||
| 20 | #include "pkcs7-asn1.h" | ||
| 21 | |||
| 22 | struct pkcs7_parse_context { | ||
| 23 | struct pkcs7_message *msg; /* Message being constructed */ | ||
| 24 | struct pkcs7_signed_info *sinfo; /* SignedInfo being constructed */ | ||
| 25 | struct pkcs7_signed_info **ppsinfo; | ||
| 26 | struct x509_certificate *certs; /* Certificate cache */ | ||
| 27 | struct x509_certificate **ppcerts; | ||
| 28 | unsigned long data; /* Start of data */ | ||
| 29 | enum OID last_oid; /* Last OID encountered */ | ||
| 30 | unsigned x509_index; | ||
| 31 | unsigned sinfo_index; | ||
| 32 | }; | ||
| 33 | |||
| 34 | /** | ||
| 35 | * pkcs7_free_message - Free a PKCS#7 message | ||
| 36 | * @pkcs7: The PKCS#7 message to free | ||
| 37 | */ | ||
| 38 | void pkcs7_free_message(struct pkcs7_message *pkcs7) | ||
| 39 | { | ||
| 40 | struct x509_certificate *cert; | ||
| 41 | struct pkcs7_signed_info *sinfo; | ||
| 42 | |||
| 43 | if (pkcs7) { | ||
| 44 | while (pkcs7->certs) { | ||
| 45 | cert = pkcs7->certs; | ||
| 46 | pkcs7->certs = cert->next; | ||
| 47 | x509_free_certificate(cert); | ||
| 48 | } | ||
| 49 | while (pkcs7->crl) { | ||
| 50 | cert = pkcs7->crl; | ||
| 51 | pkcs7->crl = cert->next; | ||
| 52 | x509_free_certificate(cert); | ||
| 53 | } | ||
| 54 | while (pkcs7->signed_infos) { | ||
| 55 | sinfo = pkcs7->signed_infos; | ||
| 56 | pkcs7->signed_infos = sinfo->next; | ||
| 57 | mpi_free(sinfo->sig.mpi[0]); | ||
| 58 | kfree(sinfo->sig.digest); | ||
| 59 | kfree(sinfo); | ||
| 60 | } | ||
| 61 | kfree(pkcs7); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | EXPORT_SYMBOL_GPL(pkcs7_free_message); | ||
| 65 | |||
| 66 | /** | ||
| 67 | * pkcs7_parse_message - Parse a PKCS#7 message | ||
| 68 | * @data: The raw binary ASN.1 encoded message to be parsed | ||
| 69 | * @datalen: The size of the encoded message | ||
| 70 | */ | ||
| 71 | struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen) | ||
| 72 | { | ||
| 73 | struct pkcs7_parse_context *ctx; | ||
| 74 | struct pkcs7_message *msg; | ||
| 75 | long ret; | ||
| 76 | |||
| 77 | ret = -ENOMEM; | ||
| 78 | msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL); | ||
| 79 | if (!msg) | ||
| 80 | goto error_no_sig; | ||
| 81 | ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL); | ||
| 82 | if (!ctx) | ||
| 83 | goto error_no_ctx; | ||
| 84 | ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); | ||
| 85 | if (!ctx->sinfo) | ||
| 86 | goto error_no_sinfo; | ||
| 87 | |||
| 88 | ctx->msg = msg; | ||
| 89 | ctx->data = (unsigned long)data; | ||
| 90 | ctx->ppcerts = &ctx->certs; | ||
| 91 | ctx->ppsinfo = &ctx->msg->signed_infos; | ||
| 92 | |||
| 93 | /* Attempt to decode the signature */ | ||
| 94 | ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen); | ||
| 95 | if (ret < 0) | ||
| 96 | goto error_decode; | ||
| 97 | |||
| 98 | while (ctx->certs) { | ||
| 99 | struct x509_certificate *cert = ctx->certs; | ||
| 100 | ctx->certs = cert->next; | ||
| 101 | x509_free_certificate(cert); | ||
| 102 | } | ||
| 103 | mpi_free(ctx->sinfo->sig.mpi[0]); | ||
| 104 | kfree(ctx->sinfo->sig.digest); | ||
| 105 | kfree(ctx->sinfo); | ||
| 106 | kfree(ctx); | ||
| 107 | return msg; | ||
| 108 | |||
| 109 | error_decode: | ||
| 110 | mpi_free(ctx->sinfo->sig.mpi[0]); | ||
| 111 | kfree(ctx->sinfo->sig.digest); | ||
| 112 | kfree(ctx->sinfo); | ||
| 113 | error_no_sinfo: | ||
| 114 | kfree(ctx); | ||
| 115 | error_no_ctx: | ||
| 116 | pkcs7_free_message(msg); | ||
| 117 | error_no_sig: | ||
| 118 | return ERR_PTR(ret); | ||
| 119 | } | ||
| 120 | EXPORT_SYMBOL_GPL(pkcs7_parse_message); | ||
| 121 | |||
| 122 | /** | ||
| 123 | * pkcs7_get_content_data - Get access to the PKCS#7 content | ||
| 124 | * @pkcs7: The preparsed PKCS#7 message to access | ||
| 125 | * @_data: Place to return a pointer to the data | ||
| 126 | * @_data_len: Place to return the data length | ||
| 127 | * @want_wrapper: True if the ASN.1 object header should be included in the data | ||
| 128 | * | ||
| 129 | * Get access to the data content of the PKCS#7 message, including, optionally, | ||
| 130 | * the header of the ASN.1 object that contains it. Returns -ENODATA if the | ||
| 131 | * data object was missing from the message. | ||
| 132 | */ | ||
| 133 | int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, | ||
| 134 | const void **_data, size_t *_data_len, | ||
| 135 | bool want_wrapper) | ||
| 136 | { | ||
| 137 | size_t wrapper; | ||
| 138 | |||
| 139 | if (!pkcs7->data) | ||
| 140 | return -ENODATA; | ||
| 141 | |||
| 142 | wrapper = want_wrapper ? pkcs7->data_hdrlen : 0; | ||
| 143 | *_data = pkcs7->data - wrapper; | ||
| 144 | *_data_len = pkcs7->data_len + wrapper; | ||
| 145 | return 0; | ||
| 146 | } | ||
| 147 | EXPORT_SYMBOL_GPL(pkcs7_get_content_data); | ||
| 148 | |||
| 149 | /* | ||
| 150 | * Note an OID when we find one for later processing when we know how | ||
| 151 | * to interpret it. | ||
| 152 | */ | ||
| 153 | int pkcs7_note_OID(void *context, size_t hdrlen, | ||
| 154 | unsigned char tag, | ||
| 155 | const void *value, size_t vlen) | ||
| 156 | { | ||
| 157 | struct pkcs7_parse_context *ctx = context; | ||
| 158 | |||
| 159 | ctx->last_oid = look_up_OID(value, vlen); | ||
| 160 | if (ctx->last_oid == OID__NR) { | ||
| 161 | char buffer[50]; | ||
| 162 | sprint_oid(value, vlen, buffer, sizeof(buffer)); | ||
| 163 | printk("PKCS7: Unknown OID: [%lu] %s\n", | ||
| 164 | (unsigned long)value - ctx->data, buffer); | ||
| 165 | } | ||
| 166 | return 0; | ||
| 167 | } | ||
| 168 | |||
| 169 | /* | ||
| 170 | * Note the digest algorithm for the signature. | ||
| 171 | */ | ||
| 172 | int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen, | ||
| 173 | unsigned char tag, | ||
| 174 | const void *value, size_t vlen) | ||
| 175 | { | ||
| 176 | struct pkcs7_parse_context *ctx = context; | ||
| 177 | |||
| 178 | switch (ctx->last_oid) { | ||
| 179 | case OID_md4: | ||
| 180 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD4; | ||
| 181 | break; | ||
| 182 | case OID_md5: | ||
| 183 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD5; | ||
| 184 | break; | ||
| 185 | case OID_sha1: | ||
| 186 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA1; | ||
| 187 | break; | ||
| 188 | case OID_sha256: | ||
| 189 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256; | ||
| 190 | break; | ||
| 191 | default: | ||
| 192 | printk("Unsupported digest algo: %u\n", ctx->last_oid); | ||
| 193 | return -ENOPKG; | ||
| 194 | } | ||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | /* | ||
| 199 | * Note the public key algorithm for the signature. | ||
| 200 | */ | ||
| 201 | int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, | ||
| 202 | unsigned char tag, | ||
| 203 | const void *value, size_t vlen) | ||
| 204 | { | ||
| 205 | struct pkcs7_parse_context *ctx = context; | ||
| 206 | |||
| 207 | switch (ctx->last_oid) { | ||
| 208 | case OID_rsaEncryption: | ||
| 209 | ctx->sinfo->sig.pkey_algo = PKEY_ALGO_RSA; | ||
| 210 | break; | ||
| 211 | default: | ||
| 212 | printk("Unsupported pkey algo: %u\n", ctx->last_oid); | ||
| 213 | return -ENOPKG; | ||
| 214 | } | ||
| 215 | return 0; | ||
| 216 | } | ||
| 217 | |||
| 218 | /* | ||
| 219 | * Extract a certificate and store it in the context. | ||
| 220 | */ | ||
| 221 | int pkcs7_extract_cert(void *context, size_t hdrlen, | ||
| 222 | unsigned char tag, | ||
| 223 | const void *value, size_t vlen) | ||
| 224 | { | ||
| 225 | struct pkcs7_parse_context *ctx = context; | ||
| 226 | struct x509_certificate *x509; | ||
| 227 | |||
| 228 | if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ)) { | ||
| 229 | pr_debug("Cert began with tag %02x at %lu\n", | ||
| 230 | tag, (unsigned long)ctx - ctx->data); | ||
| 231 | return -EBADMSG; | ||
| 232 | } | ||
| 233 | |||
| 234 | /* We have to correct for the header so that the X.509 parser can start | ||
| 235 | * from the beginning. Note that since X.509 stipulates DER, there | ||
| 236 | * probably shouldn't be an EOC trailer - but it is in PKCS#7 (which | ||
| 237 | * stipulates BER). | ||
| 238 | */ | ||
| 239 | value -= hdrlen; | ||
| 240 | vlen += hdrlen; | ||
| 241 | |||
| 242 | if (((u8*)value)[1] == 0x80) | ||
| 243 | vlen += 2; /* Indefinite length - there should be an EOC */ | ||
| 244 | |||
| 245 | x509 = x509_cert_parse(value, vlen); | ||
| 246 | if (IS_ERR(x509)) | ||
| 247 | return PTR_ERR(x509); | ||
| 248 | |||
| 249 | pr_debug("Got cert for %s\n", x509->subject); | ||
| 250 | pr_debug("- fingerprint %s\n", x509->fingerprint); | ||
| 251 | |||
| 252 | x509->index = ++ctx->x509_index; | ||
| 253 | *ctx->ppcerts = x509; | ||
| 254 | ctx->ppcerts = &x509->next; | ||
| 255 | return 0; | ||
| 256 | } | ||
| 257 | |||
| 258 | /* | ||
| 259 | * Save the certificate list | ||
| 260 | */ | ||
| 261 | int pkcs7_note_certificate_list(void *context, size_t hdrlen, | ||
| 262 | unsigned char tag, | ||
| 263 | const void *value, size_t vlen) | ||
| 264 | { | ||
| 265 | struct pkcs7_parse_context *ctx = context; | ||
| 266 | |||
| 267 | pr_devel("Got cert list (%02x)\n", tag); | ||
| 268 | |||
| 269 | *ctx->ppcerts = ctx->msg->certs; | ||
| 270 | ctx->msg->certs = ctx->certs; | ||
| 271 | ctx->certs = NULL; | ||
| 272 | ctx->ppcerts = &ctx->certs; | ||
| 273 | return 0; | ||
| 274 | } | ||
| 275 | |||
| 276 | /* | ||
| 277 | * Extract the data from the message and store that and its content type OID in | ||
| 278 | * the context. | ||
| 279 | */ | ||
| 280 | int pkcs7_note_data(void *context, size_t hdrlen, | ||
| 281 | unsigned char tag, | ||
| 282 | const void *value, size_t vlen) | ||
| 283 | { | ||
| 284 | struct pkcs7_parse_context *ctx = context; | ||
| 285 | |||
| 286 | pr_debug("Got data\n"); | ||
| 287 | |||
| 288 | ctx->msg->data = value; | ||
| 289 | ctx->msg->data_len = vlen; | ||
| 290 | ctx->msg->data_hdrlen = hdrlen; | ||
| 291 | ctx->msg->data_type = ctx->last_oid; | ||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | |||
| 295 | /* | ||
| 296 | * Parse authenticated attributes | ||
| 297 | */ | ||
| 298 | int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, | ||
| 299 | unsigned char tag, | ||
| 300 | const void *value, size_t vlen) | ||
| 301 | { | ||
| 302 | struct pkcs7_parse_context *ctx = context; | ||
| 303 | |||
| 304 | pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); | ||
| 305 | |||
| 306 | switch (ctx->last_oid) { | ||
| 307 | case OID_messageDigest: | ||
| 308 | if (tag != ASN1_OTS) | ||
| 309 | return -EBADMSG; | ||
| 310 | ctx->sinfo->msgdigest = value; | ||
| 311 | ctx->sinfo->msgdigest_len = vlen; | ||
| 312 | return 0; | ||
| 313 | default: | ||
| 314 | return 0; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 318 | /* | ||
| 319 | * Note the set of auth attributes for digestion purposes [RFC2315 9.3] | ||
| 320 | */ | ||
| 321 | int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, | ||
| 322 | unsigned char tag, | ||
| 323 | const void *value, size_t vlen) | ||
| 324 | { | ||
| 325 | struct pkcs7_parse_context *ctx = context; | ||
| 326 | |||
| 327 | /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ | ||
| 328 | ctx->sinfo->authattrs = value - (hdrlen - 1); | ||
| 329 | ctx->sinfo->authattrs_len = vlen + (hdrlen - 1); | ||
| 330 | return 0; | ||
| 331 | } | ||
| 332 | |||
| 333 | /* | ||
| 334 | * Note the issuing certificate serial number | ||
| 335 | */ | ||
| 336 | int pkcs7_sig_note_serial(void *context, size_t hdrlen, | ||
| 337 | unsigned char tag, | ||
| 338 | const void *value, size_t vlen) | ||
| 339 | { | ||
| 340 | struct pkcs7_parse_context *ctx = context; | ||
| 341 | ctx->sinfo->raw_serial = value; | ||
| 342 | ctx->sinfo->raw_serial_size = vlen; | ||
| 343 | return 0; | ||
| 344 | } | ||
| 345 | |||
| 346 | /* | ||
| 347 | * Note the issuer's name | ||
| 348 | */ | ||
| 349 | int pkcs7_sig_note_issuer(void *context, size_t hdrlen, | ||
| 350 | unsigned char tag, | ||
| 351 | const void *value, size_t vlen) | ||
| 352 | { | ||
| 353 | struct pkcs7_parse_context *ctx = context; | ||
| 354 | ctx->sinfo->raw_issuer = value; | ||
| 355 | ctx->sinfo->raw_issuer_size = vlen; | ||
| 356 | return 0; | ||
| 357 | } | ||
| 358 | |||
| 359 | /* | ||
| 360 | * Note the signature data | ||
| 361 | */ | ||
| 362 | int pkcs7_sig_note_signature(void *context, size_t hdrlen, | ||
| 363 | unsigned char tag, | ||
| 364 | const void *value, size_t vlen) | ||
| 365 | { | ||
| 366 | struct pkcs7_parse_context *ctx = context; | ||
| 367 | MPI mpi; | ||
| 368 | |||
| 369 | BUG_ON(ctx->sinfo->sig.pkey_algo != PKEY_ALGO_RSA); | ||
| 370 | |||
| 371 | mpi = mpi_read_raw_data(value, vlen); | ||
| 372 | if (!mpi) | ||
| 373 | return -ENOMEM; | ||
| 374 | |||
| 375 | ctx->sinfo->sig.mpi[0] = mpi; | ||
| 376 | ctx->sinfo->sig.nr_mpi = 1; | ||
| 377 | return 0; | ||
| 378 | } | ||
| 379 | |||
| 380 | /* | ||
| 381 | * Note a signature information block | ||
| 382 | */ | ||
| 383 | int pkcs7_note_signed_info(void *context, size_t hdrlen, | ||
| 384 | unsigned char tag, | ||
| 385 | const void *value, size_t vlen) | ||
| 386 | { | ||
| 387 | struct pkcs7_parse_context *ctx = context; | ||
| 388 | |||
| 389 | ctx->sinfo->index = ++ctx->sinfo_index; | ||
| 390 | *ctx->ppsinfo = ctx->sinfo; | ||
| 391 | ctx->ppsinfo = &ctx->sinfo->next; | ||
| 392 | ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); | ||
| 393 | if (!ctx->sinfo) | ||
| 394 | return -ENOMEM; | ||
| 395 | return 0; | ||
| 396 | } | ||
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h new file mode 100644 index 000000000000..d25f4d15370f --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7_parser.h | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | /* PKCS#7 crypto data 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 <linux/oid_registry.h> | ||
| 13 | #include <crypto/pkcs7.h> | ||
| 14 | #include "x509_parser.h" | ||
| 15 | |||
| 16 | #define kenter(FMT, ...) \ | ||
| 17 | pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) | ||
| 18 | #define kleave(FMT, ...) \ | ||
| 19 | pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) | ||
| 20 | |||
| 21 | struct pkcs7_signed_info { | ||
| 22 | struct pkcs7_signed_info *next; | ||
| 23 | struct x509_certificate *signer; /* Signing certificate (in msg->certs) */ | ||
| 24 | unsigned index; | ||
| 25 | bool trusted; | ||
| 26 | |||
| 27 | /* Message digest - the digest of the Content Data (or NULL) */ | ||
| 28 | const void *msgdigest; | ||
| 29 | unsigned msgdigest_len; | ||
| 30 | |||
| 31 | /* Authenticated Attribute data (or NULL) */ | ||
| 32 | unsigned authattrs_len; | ||
| 33 | const void *authattrs; | ||
| 34 | |||
| 35 | /* Issuing cert serial number and issuer's name */ | ||
| 36 | const void *raw_serial; | ||
| 37 | unsigned raw_serial_size; | ||
| 38 | unsigned raw_issuer_size; | ||
| 39 | const void *raw_issuer; | ||
| 40 | |||
| 41 | /* Message signature. | ||
| 42 | * | ||
| 43 | * This contains the generated digest of _either_ the Content Data or | ||
| 44 | * the Authenticated Attributes [RFC2315 9.3]. If the latter, one of | ||
| 45 | * the attributes contains the digest of the the Content Data within | ||
| 46 | * it. | ||
| 47 | */ | ||
| 48 | struct public_key_signature sig; | ||
| 49 | }; | ||
| 50 | |||
| 51 | struct pkcs7_message { | ||
| 52 | struct x509_certificate *certs; /* Certificate list */ | ||
| 53 | struct x509_certificate *crl; /* Revocation list */ | ||
| 54 | struct pkcs7_signed_info *signed_infos; | ||
| 55 | |||
| 56 | /* Content Data (or NULL) */ | ||
| 57 | enum OID data_type; /* Type of Data */ | ||
| 58 | size_t data_len; /* Length of Data */ | ||
| 59 | size_t data_hdrlen; /* Length of Data ASN.1 header */ | ||
| 60 | const void *data; /* Content Data (or 0) */ | ||
| 61 | }; | ||
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c new file mode 100644 index 000000000000..b6b045131403 --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7_trust.c | |||
| @@ -0,0 +1,219 @@ | |||
| 1 | /* Validate the trust chain of a PKCS#7 message. | ||
| 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) "PKCS7: "fmt | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/export.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/err.h> | ||
| 17 | #include <linux/asn1.h> | ||
| 18 | #include <linux/key.h> | ||
| 19 | #include <keys/asymmetric-type.h> | ||
| 20 | #include "public_key.h" | ||
| 21 | #include "pkcs7_parser.h" | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Request an asymmetric key. | ||
| 25 | */ | ||
| 26 | static struct key *pkcs7_request_asymmetric_key( | ||
| 27 | struct key *keyring, | ||
| 28 | const char *signer, size_t signer_len, | ||
| 29 | const char *authority, size_t auth_len) | ||
| 30 | { | ||
| 31 | key_ref_t key; | ||
| 32 | char *id; | ||
| 33 | |||
| 34 | kenter(",%zu,,%zu", signer_len, auth_len); | ||
| 35 | |||
| 36 | /* Construct an identifier. */ | ||
| 37 | id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL); | ||
| 38 | if (!id) | ||
| 39 | return ERR_PTR(-ENOMEM); | ||
| 40 | |||
| 41 | memcpy(id, signer, signer_len); | ||
| 42 | id[signer_len + 0] = ':'; | ||
| 43 | id[signer_len + 1] = ' '; | ||
| 44 | memcpy(id + signer_len + 2, authority, auth_len); | ||
| 45 | id[signer_len + 2 + auth_len] = 0; | ||
| 46 | |||
| 47 | pr_debug("Look up: \"%s\"\n", id); | ||
| 48 | |||
| 49 | key = keyring_search(make_key_ref(keyring, 1), | ||
| 50 | &key_type_asymmetric, id); | ||
| 51 | if (IS_ERR(key)) | ||
| 52 | pr_debug("Request for module key '%s' err %ld\n", | ||
| 53 | id, PTR_ERR(key)); | ||
| 54 | kfree(id); | ||
| 55 | |||
| 56 | if (IS_ERR(key)) { | ||
| 57 | switch (PTR_ERR(key)) { | ||
| 58 | /* Hide some search errors */ | ||
| 59 | case -EACCES: | ||
| 60 | case -ENOTDIR: | ||
| 61 | case -EAGAIN: | ||
| 62 | return ERR_PTR(-ENOKEY); | ||
| 63 | default: | ||
| 64 | return ERR_CAST(key); | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key))); | ||
| 69 | return key_ref_to_ptr(key); | ||
| 70 | } | ||
| 71 | |||
| 72 | /** | ||
| 73 | * Check the trust on one PKCS#7 SignedInfo block. | ||
| 74 | */ | ||
| 75 | int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | ||
| 76 | struct pkcs7_signed_info *sinfo, | ||
| 77 | struct key *trust_keyring) | ||
| 78 | { | ||
| 79 | struct public_key_signature *sig = &sinfo->sig; | ||
| 80 | struct x509_certificate *x509, *last = NULL, *p; | ||
| 81 | struct key *key; | ||
| 82 | bool trusted; | ||
| 83 | int ret; | ||
| 84 | |||
| 85 | kenter(",%u,", sinfo->index); | ||
| 86 | |||
| 87 | for (x509 = sinfo->signer; x509; x509 = x509->signer) { | ||
| 88 | if (x509->seen) { | ||
| 89 | if (x509->verified) { | ||
| 90 | trusted = x509->trusted; | ||
| 91 | goto verified; | ||
| 92 | } | ||
| 93 | kleave(" = -ENOKEY [cached]"); | ||
| 94 | return -ENOKEY; | ||
| 95 | } | ||
| 96 | x509->seen = true; | ||
| 97 | |||
| 98 | /* Look to see if this certificate is present in the trusted | ||
| 99 | * keys. | ||
| 100 | */ | ||
| 101 | key = pkcs7_request_asymmetric_key( | ||
| 102 | trust_keyring, | ||
| 103 | x509->subject, strlen(x509->subject), | ||
| 104 | x509->fingerprint, strlen(x509->fingerprint)); | ||
| 105 | if (!IS_ERR(key)) | ||
| 106 | /* One of the X.509 certificates in the PKCS#7 message | ||
| 107 | * is apparently the same as one we already trust. | ||
| 108 | * Verify that the trusted variant can also validate | ||
| 109 | * the signature on the descendant. | ||
| 110 | */ | ||
| 111 | goto matched; | ||
| 112 | if (key == ERR_PTR(-ENOMEM)) | ||
| 113 | return -ENOMEM; | ||
| 114 | |||
| 115 | /* Self-signed certificates form roots of their own, and if we | ||
| 116 | * don't know them, then we can't accept them. | ||
| 117 | */ | ||
| 118 | if (x509->next == x509) { | ||
| 119 | kleave(" = -ENOKEY [unknown self-signed]"); | ||
| 120 | return -ENOKEY; | ||
| 121 | } | ||
| 122 | |||
| 123 | might_sleep(); | ||
| 124 | last = x509; | ||
| 125 | sig = &last->sig; | ||
| 126 | } | ||
| 127 | |||
| 128 | /* No match - see if the root certificate has a signer amongst the | ||
| 129 | * trusted keys. | ||
| 130 | */ | ||
| 131 | if (!last || !last->issuer || !last->authority) { | ||
| 132 | kleave(" = -ENOKEY [no backref]"); | ||
| 133 | return -ENOKEY; | ||
| 134 | } | ||
| 135 | |||
| 136 | key = pkcs7_request_asymmetric_key( | ||
| 137 | trust_keyring, | ||
| 138 | last->issuer, strlen(last->issuer), | ||
| 139 | last->authority, strlen(last->authority)); | ||
| 140 | if (IS_ERR(key)) | ||
| 141 | return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY; | ||
| 142 | x509 = last; | ||
| 143 | |||
| 144 | matched: | ||
| 145 | ret = verify_signature(key, sig); | ||
| 146 | trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags); | ||
| 147 | key_put(key); | ||
| 148 | if (ret < 0) { | ||
| 149 | if (ret == -ENOMEM) | ||
| 150 | return ret; | ||
| 151 | kleave(" = -EKEYREJECTED [verify %d]", ret); | ||
| 152 | return -EKEYREJECTED; | ||
| 153 | } | ||
| 154 | |||
| 155 | verified: | ||
| 156 | x509->verified = true; | ||
| 157 | for (p = sinfo->signer; p != x509; p = p->signer) { | ||
| 158 | p->verified = true; | ||
| 159 | p->trusted = trusted; | ||
| 160 | } | ||
| 161 | sinfo->trusted = trusted; | ||
| 162 | kleave(" = 0"); | ||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | |||
| 166 | /** | ||
| 167 | * pkcs7_validate_trust - Validate PKCS#7 trust chain | ||
| 168 | * @pkcs7: The PKCS#7 certificate to validate | ||
| 169 | * @trust_keyring: Signing certificates to use as starting points | ||
| 170 | * @_trusted: Set to true if trustworth, false otherwise | ||
| 171 | * | ||
| 172 | * Validate that the certificate chain inside the PKCS#7 message intersects | ||
| 173 | * keys we already know and trust. | ||
| 174 | * | ||
| 175 | * Returns, in order of descending priority: | ||
| 176 | * | ||
| 177 | * (*) -EKEYREJECTED if a signature failed to match for which we have a valid | ||
| 178 | * key, or: | ||
| 179 | * | ||
| 180 | * (*) 0 if at least one signature chain intersects with the keys in the trust | ||
| 181 | * keyring, or: | ||
| 182 | * | ||
| 183 | * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a | ||
| 184 | * chain. | ||
| 185 | * | ||
| 186 | * (*) -ENOKEY if we couldn't find a match for any of the signature chains in | ||
| 187 | * the message. | ||
| 188 | * | ||
| 189 | * May also return -ENOMEM. | ||
| 190 | */ | ||
| 191 | int pkcs7_validate_trust(struct pkcs7_message *pkcs7, | ||
| 192 | struct key *trust_keyring, | ||
| 193 | bool *_trusted) | ||
| 194 | { | ||
| 195 | struct pkcs7_signed_info *sinfo; | ||
| 196 | struct x509_certificate *p; | ||
| 197 | int cached_ret = 0, ret; | ||
| 198 | |||
| 199 | for (p = pkcs7->certs; p; p = p->next) | ||
| 200 | p->seen = false; | ||
| 201 | |||
| 202 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | ||
| 203 | ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring); | ||
| 204 | if (ret < 0) { | ||
| 205 | if (ret == -ENOPKG) { | ||
| 206 | cached_ret = -ENOPKG; | ||
| 207 | } else if (ret == -ENOKEY) { | ||
| 208 | if (cached_ret == 0) | ||
| 209 | cached_ret = -ENOKEY; | ||
| 210 | } else { | ||
| 211 | return ret; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | *_trusted |= sinfo->trusted; | ||
| 215 | } | ||
| 216 | |||
| 217 | return cached_ret; | ||
| 218 | } | ||
| 219 | EXPORT_SYMBOL_GPL(pkcs7_validate_trust); | ||
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c new file mode 100644 index 000000000000..51ff36f3a913 --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7_verify.c | |||
| @@ -0,0 +1,323 @@ | |||
| 1 | /* Verify the signature on a PKCS#7 message. | ||
| 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) "PKCS7: "fmt | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/export.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/err.h> | ||
| 17 | #include <linux/asn1.h> | ||
| 18 | #include <crypto/hash.h> | ||
| 19 | #include "public_key.h" | ||
| 20 | #include "pkcs7_parser.h" | ||
| 21 | |||
| 22 | /* | ||
| 23 | * Digest the relevant parts of the PKCS#7 data | ||
| 24 | */ | ||
| 25 | static int pkcs7_digest(struct pkcs7_message *pkcs7, | ||
| 26 | struct pkcs7_signed_info *sinfo) | ||
| 27 | { | ||
| 28 | struct crypto_shash *tfm; | ||
| 29 | struct shash_desc *desc; | ||
| 30 | size_t digest_size, desc_size; | ||
| 31 | void *digest; | ||
| 32 | int ret; | ||
| 33 | |||
| 34 | kenter(",%u,%u", sinfo->index, sinfo->sig.pkey_hash_algo); | ||
| 35 | |||
| 36 | if (sinfo->sig.pkey_hash_algo >= PKEY_HASH__LAST || | ||
| 37 | !hash_algo_name[sinfo->sig.pkey_hash_algo]) | ||
| 38 | return -ENOPKG; | ||
| 39 | |||
| 40 | /* Allocate the hashing algorithm we're going to need and find out how | ||
| 41 | * big the hash operational data will be. | ||
| 42 | */ | ||
| 43 | tfm = crypto_alloc_shash(hash_algo_name[sinfo->sig.pkey_hash_algo], | ||
| 44 | 0, 0); | ||
| 45 | if (IS_ERR(tfm)) | ||
| 46 | return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); | ||
| 47 | |||
| 48 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | ||
| 49 | sinfo->sig.digest_size = digest_size = crypto_shash_digestsize(tfm); | ||
| 50 | |||
| 51 | ret = -ENOMEM; | ||
| 52 | digest = kzalloc(digest_size + desc_size, GFP_KERNEL); | ||
| 53 | if (!digest) | ||
| 54 | goto error_no_desc; | ||
| 55 | |||
| 56 | desc = digest + digest_size; | ||
| 57 | desc->tfm = tfm; | ||
| 58 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
| 59 | |||
| 60 | /* Digest the message [RFC2315 9.3] */ | ||
| 61 | ret = crypto_shash_init(desc); | ||
| 62 | if (ret < 0) | ||
| 63 | goto error; | ||
| 64 | ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, digest); | ||
| 65 | if (ret < 0) | ||
| 66 | goto error; | ||
| 67 | pr_devel("MsgDigest = [%*ph]\n", 8, digest); | ||
| 68 | |||
| 69 | /* However, if there are authenticated attributes, there must be a | ||
| 70 | * message digest attribute amongst them which corresponds to the | ||
| 71 | * digest we just calculated. | ||
| 72 | */ | ||
| 73 | if (sinfo->msgdigest) { | ||
| 74 | u8 tag; | ||
| 75 | |||
| 76 | if (sinfo->msgdigest_len != sinfo->sig.digest_size) { | ||
| 77 | pr_debug("Sig %u: Invalid digest size (%u)\n", | ||
| 78 | sinfo->index, sinfo->msgdigest_len); | ||
| 79 | ret = -EBADMSG; | ||
| 80 | goto error; | ||
| 81 | } | ||
| 82 | |||
| 83 | if (memcmp(digest, sinfo->msgdigest, sinfo->msgdigest_len) != 0) { | ||
| 84 | pr_debug("Sig %u: Message digest doesn't match\n", | ||
| 85 | sinfo->index); | ||
| 86 | ret = -EKEYREJECTED; | ||
| 87 | goto error; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* We then calculate anew, using the authenticated attributes | ||
| 91 | * as the contents of the digest instead. Note that we need to | ||
| 92 | * convert the attributes from a CONT.0 into a SET before we | ||
| 93 | * hash it. | ||
| 94 | */ | ||
| 95 | memset(digest, 0, sinfo->sig.digest_size); | ||
| 96 | |||
| 97 | ret = crypto_shash_init(desc); | ||
| 98 | if (ret < 0) | ||
| 99 | goto error; | ||
| 100 | tag = ASN1_CONS_BIT | ASN1_SET; | ||
| 101 | ret = crypto_shash_update(desc, &tag, 1); | ||
| 102 | if (ret < 0) | ||
| 103 | goto error; | ||
| 104 | ret = crypto_shash_finup(desc, sinfo->authattrs, | ||
| 105 | sinfo->authattrs_len, digest); | ||
| 106 | if (ret < 0) | ||
| 107 | goto error; | ||
| 108 | pr_devel("AADigest = [%*ph]\n", 8, digest); | ||
| 109 | } | ||
| 110 | |||
| 111 | sinfo->sig.digest = digest; | ||
| 112 | digest = NULL; | ||
| 113 | |||
| 114 | error: | ||
| 115 | kfree(digest); | ||
| 116 | error_no_desc: | ||
| 117 | crypto_free_shash(tfm); | ||
| 118 | kleave(" = %d", ret); | ||
| 119 | return ret; | ||
| 120 | } | ||
| 121 | |||
| 122 | /* | ||
| 123 | * Find the key (X.509 certificate) to use to verify a PKCS#7 message. PKCS#7 | ||
| 124 | * uses the issuer's name and the issuing certificate serial number for | ||
| 125 | * matching purposes. These must match the certificate issuer's name (not | ||
| 126 | * subject's name) and the certificate serial number [RFC 2315 6.7]. | ||
| 127 | */ | ||
| 128 | static int pkcs7_find_key(struct pkcs7_message *pkcs7, | ||
| 129 | struct pkcs7_signed_info *sinfo) | ||
| 130 | { | ||
| 131 | struct x509_certificate *x509; | ||
| 132 | unsigned certix = 1; | ||
| 133 | |||
| 134 | kenter("%u,%u,%u", | ||
| 135 | sinfo->index, sinfo->raw_serial_size, sinfo->raw_issuer_size); | ||
| 136 | |||
| 137 | for (x509 = pkcs7->certs; x509; x509 = x509->next, certix++) { | ||
| 138 | /* I'm _assuming_ that the generator of the PKCS#7 message will | ||
| 139 | * encode the fields from the X.509 cert in the same way in the | ||
| 140 | * PKCS#7 message - but I can't be 100% sure of that. It's | ||
| 141 | * possible this will need element-by-element comparison. | ||
| 142 | */ | ||
| 143 | if (x509->raw_serial_size != sinfo->raw_serial_size || | ||
| 144 | memcmp(x509->raw_serial, sinfo->raw_serial, | ||
| 145 | sinfo->raw_serial_size) != 0) | ||
| 146 | continue; | ||
| 147 | pr_devel("Sig %u: Found cert serial match X.509[%u]\n", | ||
| 148 | sinfo->index, certix); | ||
| 149 | |||
| 150 | if (x509->raw_issuer_size != sinfo->raw_issuer_size || | ||
| 151 | memcmp(x509->raw_issuer, sinfo->raw_issuer, | ||
| 152 | sinfo->raw_issuer_size) != 0) { | ||
| 153 | pr_warn("Sig %u: X.509 subject and PKCS#7 issuer don't match\n", | ||
| 154 | sinfo->index); | ||
| 155 | continue; | ||
| 156 | } | ||
| 157 | |||
| 158 | if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) { | ||
| 159 | pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n", | ||
| 160 | sinfo->index); | ||
| 161 | continue; | ||
| 162 | } | ||
| 163 | |||
| 164 | sinfo->signer = x509; | ||
| 165 | return 0; | ||
| 166 | } | ||
| 167 | pr_warn("Sig %u: Issuing X.509 cert not found (#%*ph)\n", | ||
| 168 | sinfo->index, sinfo->raw_serial_size, sinfo->raw_serial); | ||
| 169 | return -ENOKEY; | ||
| 170 | } | ||
| 171 | |||
| 172 | /* | ||
| 173 | * Verify the internal certificate chain as best we can. | ||
| 174 | */ | ||
| 175 | static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | ||
| 176 | struct pkcs7_signed_info *sinfo) | ||
| 177 | { | ||
| 178 | struct x509_certificate *x509 = sinfo->signer, *p; | ||
| 179 | int ret; | ||
| 180 | |||
| 181 | kenter(""); | ||
| 182 | |||
| 183 | for (p = pkcs7->certs; p; p = p->next) | ||
| 184 | p->seen = false; | ||
| 185 | |||
| 186 | for (;;) { | ||
| 187 | pr_debug("verify %s: %s\n", x509->subject, x509->fingerprint); | ||
| 188 | x509->seen = true; | ||
| 189 | ret = x509_get_sig_params(x509); | ||
| 190 | if (ret < 0) | ||
| 191 | return ret; | ||
| 192 | |||
| 193 | if (x509->issuer) | ||
| 194 | pr_debug("- issuer %s\n", x509->issuer); | ||
| 195 | if (x509->authority) | ||
| 196 | pr_debug("- authkeyid %s\n", x509->authority); | ||
| 197 | |||
| 198 | if (!x509->authority || | ||
| 199 | (x509->subject && | ||
| 200 | strcmp(x509->subject, x509->issuer) == 0)) { | ||
| 201 | /* If there's no authority certificate specified, then | ||
| 202 | * the certificate must be self-signed and is the root | ||
| 203 | * of the chain. Likewise if the cert is its own | ||
| 204 | * authority. | ||
| 205 | */ | ||
| 206 | pr_debug("- no auth?\n"); | ||
| 207 | if (x509->raw_subject_size != x509->raw_issuer_size || | ||
| 208 | memcmp(x509->raw_subject, x509->raw_issuer, | ||
| 209 | x509->raw_issuer_size) != 0) | ||
| 210 | return 0; | ||
| 211 | |||
| 212 | ret = x509_check_signature(x509->pub, x509); | ||
| 213 | if (ret < 0) | ||
| 214 | return ret; | ||
| 215 | x509->signer = x509; | ||
| 216 | pr_debug("- self-signed\n"); | ||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | /* Look through the X.509 certificates in the PKCS#7 message's | ||
| 221 | * list to see if the next one is there. | ||
| 222 | */ | ||
| 223 | pr_debug("- want %s\n", x509->authority); | ||
| 224 | for (p = pkcs7->certs; p; p = p->next) { | ||
| 225 | pr_debug("- cmp [%u] %s\n", p->index, p->fingerprint); | ||
| 226 | if (p->raw_subject_size == x509->raw_issuer_size && | ||
| 227 | strcmp(p->fingerprint, x509->authority) == 0 && | ||
| 228 | memcmp(p->raw_subject, x509->raw_issuer, | ||
| 229 | x509->raw_issuer_size) == 0) | ||
| 230 | goto found_issuer; | ||
| 231 | } | ||
| 232 | |||
| 233 | /* We didn't find the root of this chain */ | ||
| 234 | pr_debug("- top\n"); | ||
| 235 | return 0; | ||
| 236 | |||
| 237 | found_issuer: | ||
| 238 | pr_debug("- issuer %s\n", p->subject); | ||
| 239 | if (p->seen) { | ||
| 240 | pr_warn("Sig %u: X.509 chain contains loop\n", | ||
| 241 | sinfo->index); | ||
| 242 | return 0; | ||
| 243 | } | ||
| 244 | ret = x509_check_signature(p->pub, x509); | ||
| 245 | if (ret < 0) | ||
| 246 | return ret; | ||
| 247 | x509->signer = p; | ||
| 248 | if (x509 == p) { | ||
| 249 | pr_debug("- self-signed\n"); | ||
| 250 | return 0; | ||
| 251 | } | ||
| 252 | x509 = p; | ||
| 253 | might_sleep(); | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | /* | ||
| 258 | * Verify one signed information block from a PKCS#7 message. | ||
| 259 | */ | ||
| 260 | static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | ||
| 261 | struct pkcs7_signed_info *sinfo) | ||
| 262 | { | ||
| 263 | int ret; | ||
| 264 | |||
| 265 | kenter(",%u", sinfo->index); | ||
| 266 | |||
| 267 | /* First of all, digest the data in the PKCS#7 message and the | ||
| 268 | * signed information block | ||
| 269 | */ | ||
| 270 | ret = pkcs7_digest(pkcs7, sinfo); | ||
| 271 | if (ret < 0) | ||
| 272 | return ret; | ||
| 273 | |||
| 274 | /* Find the key for the signature */ | ||
| 275 | ret = pkcs7_find_key(pkcs7, sinfo); | ||
| 276 | if (ret < 0) | ||
| 277 | return ret; | ||
| 278 | |||
| 279 | pr_devel("Using X.509[%u] for sig %u\n", | ||
| 280 | sinfo->signer->index, sinfo->index); | ||
| 281 | |||
| 282 | /* Verify the PKCS#7 binary against the key */ | ||
| 283 | ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); | ||
| 284 | if (ret < 0) | ||
| 285 | return ret; | ||
| 286 | |||
| 287 | pr_devel("Verified signature %u\n", sinfo->index); | ||
| 288 | |||
| 289 | /* Verify the internal certificate chain */ | ||
| 290 | return pkcs7_verify_sig_chain(pkcs7, sinfo); | ||
| 291 | } | ||
| 292 | |||
| 293 | /** | ||
| 294 | * pkcs7_verify - Verify a PKCS#7 message | ||
| 295 | * @pkcs7: The PKCS#7 message to be verified | ||
| 296 | */ | ||
| 297 | int pkcs7_verify(struct pkcs7_message *pkcs7) | ||
| 298 | { | ||
| 299 | struct pkcs7_signed_info *sinfo; | ||
| 300 | struct x509_certificate *x509; | ||
| 301 | int ret, n; | ||
| 302 | |||
| 303 | kenter(""); | ||
| 304 | |||
| 305 | for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { | ||
| 306 | ret = x509_get_sig_params(x509); | ||
| 307 | if (ret < 0) | ||
| 308 | return ret; | ||
| 309 | pr_debug("X.509[%u] %s\n", n, x509->authority); | ||
| 310 | } | ||
| 311 | |||
| 312 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | ||
| 313 | ret = pkcs7_verify_one(pkcs7, sinfo); | ||
| 314 | if (ret < 0) { | ||
| 315 | kleave(" = %d", ret); | ||
| 316 | return ret; | ||
| 317 | } | ||
| 318 | } | ||
| 319 | |||
| 320 | kleave(" = 0"); | ||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | EXPORT_SYMBOL_GPL(pkcs7_verify); | ||
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c new file mode 100644 index 000000000000..79175e6ea0b2 --- /dev/null +++ b/crypto/asymmetric_keys/verify_pefile.c | |||
| @@ -0,0 +1,457 @@ | |||
| 1 | /* Parse a signed PE binary | ||
| 2 | * | ||
| 3 | * Copyright (C) 2014 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) "PEFILE: "fmt | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/err.h> | ||
| 17 | #include <linux/pe.h> | ||
| 18 | #include <linux/asn1.h> | ||
| 19 | #include <crypto/pkcs7.h> | ||
| 20 | #include <crypto/hash.h> | ||
| 21 | #include "verify_pefile.h" | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Parse a PE binary. | ||
| 25 | */ | ||
| 26 | static int pefile_parse_binary(const void *pebuf, unsigned int pelen, | ||
| 27 | struct pefile_context *ctx) | ||
| 28 | { | ||
| 29 | const struct mz_hdr *mz = pebuf; | ||
| 30 | const struct pe_hdr *pe; | ||
| 31 | const struct pe32_opt_hdr *pe32; | ||
| 32 | const struct pe32plus_opt_hdr *pe64; | ||
| 33 | const struct data_directory *ddir; | ||
| 34 | const struct data_dirent *dde; | ||
| 35 | const struct section_header *secs, *sec; | ||
| 36 | size_t cursor, datalen = pelen; | ||
| 37 | |||
| 38 | kenter(""); | ||
| 39 | |||
| 40 | #define chkaddr(base, x, s) \ | ||
| 41 | do { \ | ||
| 42 | if ((x) < base || (s) >= datalen || (x) > datalen - (s)) \ | ||
| 43 | return -ELIBBAD; \ | ||
| 44 | } while (0) | ||
| 45 | |||
| 46 | chkaddr(0, 0, sizeof(*mz)); | ||
| 47 | if (mz->magic != MZ_MAGIC) | ||
| 48 | return -ELIBBAD; | ||
| 49 | cursor = sizeof(*mz); | ||
| 50 | |||
| 51 | chkaddr(cursor, mz->peaddr, sizeof(*pe)); | ||
| 52 | pe = pebuf + mz->peaddr; | ||
| 53 | if (pe->magic != PE_MAGIC) | ||
| 54 | return -ELIBBAD; | ||
| 55 | cursor = mz->peaddr + sizeof(*pe); | ||
| 56 | |||
| 57 | chkaddr(0, cursor, sizeof(pe32->magic)); | ||
| 58 | pe32 = pebuf + cursor; | ||
| 59 | pe64 = pebuf + cursor; | ||
| 60 | |||
| 61 | switch (pe32->magic) { | ||
| 62 | case PE_OPT_MAGIC_PE32: | ||
| 63 | chkaddr(0, cursor, sizeof(*pe32)); | ||
| 64 | ctx->image_checksum_offset = | ||
| 65 | (unsigned long)&pe32->csum - (unsigned long)pebuf; | ||
| 66 | ctx->header_size = pe32->header_size; | ||
| 67 | cursor += sizeof(*pe32); | ||
| 68 | ctx->n_data_dirents = pe32->data_dirs; | ||
| 69 | break; | ||
| 70 | |||
| 71 | case PE_OPT_MAGIC_PE32PLUS: | ||
| 72 | chkaddr(0, cursor, sizeof(*pe64)); | ||
| 73 | ctx->image_checksum_offset = | ||
| 74 | (unsigned long)&pe64->csum - (unsigned long)pebuf; | ||
| 75 | ctx->header_size = pe64->header_size; | ||
| 76 | cursor += sizeof(*pe64); | ||
| 77 | ctx->n_data_dirents = pe64->data_dirs; | ||
| 78 | break; | ||
| 79 | |||
| 80 | default: | ||
| 81 | pr_debug("Unknown PEOPT magic = %04hx\n", pe32->magic); | ||
| 82 | return -ELIBBAD; | ||
| 83 | } | ||
| 84 | |||
| 85 | pr_debug("checksum @ %x\n", ctx->image_checksum_offset); | ||
| 86 | pr_debug("header size = %x\n", ctx->header_size); | ||
| 87 | |||
| 88 | if (cursor >= ctx->header_size || ctx->header_size >= datalen) | ||
| 89 | return -ELIBBAD; | ||
| 90 | |||
| 91 | if (ctx->n_data_dirents > (ctx->header_size - cursor) / sizeof(*dde)) | ||
| 92 | return -ELIBBAD; | ||
| 93 | |||
| 94 | ddir = pebuf + cursor; | ||
| 95 | cursor += sizeof(*dde) * ctx->n_data_dirents; | ||
| 96 | |||
| 97 | ctx->cert_dirent_offset = | ||
| 98 | (unsigned long)&ddir->certs - (unsigned long)pebuf; | ||
| 99 | ctx->certs_size = ddir->certs.size; | ||
| 100 | |||
| 101 | if (!ddir->certs.virtual_address || !ddir->certs.size) { | ||
| 102 | pr_debug("Unsigned PE binary\n"); | ||
| 103 | return -EKEYREJECTED; | ||
| 104 | } | ||
| 105 | |||
| 106 | chkaddr(ctx->header_size, ddir->certs.virtual_address, | ||
| 107 | ddir->certs.size); | ||
| 108 | ctx->sig_offset = ddir->certs.virtual_address; | ||
| 109 | ctx->sig_len = ddir->certs.size; | ||
| 110 | pr_debug("cert = %x @%x [%*ph]\n", | ||
| 111 | ctx->sig_len, ctx->sig_offset, | ||
| 112 | ctx->sig_len, pebuf + ctx->sig_offset); | ||
| 113 | |||
| 114 | ctx->n_sections = pe->sections; | ||
| 115 | if (ctx->n_sections > (ctx->header_size - cursor) / sizeof(*sec)) | ||
| 116 | return -ELIBBAD; | ||
| 117 | ctx->secs = secs = pebuf + cursor; | ||
| 118 | |||
| 119 | return 0; | ||
| 120 | } | ||
| 121 | |||
| 122 | /* | ||
| 123 | * Check and strip the PE wrapper from around the signature and check that the | ||
| 124 | * remnant looks something like PKCS#7. | ||
| 125 | */ | ||
| 126 | static int pefile_strip_sig_wrapper(const void *pebuf, | ||
| 127 | struct pefile_context *ctx) | ||
| 128 | { | ||
| 129 | struct win_certificate wrapper; | ||
| 130 | const u8 *pkcs7; | ||
| 131 | |||
| 132 | if (ctx->sig_len < sizeof(wrapper)) { | ||
| 133 | pr_debug("Signature wrapper too short\n"); | ||
| 134 | return -ELIBBAD; | ||
| 135 | } | ||
| 136 | |||
| 137 | memcpy(&wrapper, pebuf + ctx->sig_offset, sizeof(wrapper)); | ||
| 138 | pr_debug("sig wrapper = { %x, %x, %x }\n", | ||
| 139 | wrapper.length, wrapper.revision, wrapper.cert_type); | ||
| 140 | |||
| 141 | /* Both pesign and sbsign round up the length of certificate table | ||
| 142 | * (in optional header data directories) to 8 byte alignment. | ||
| 143 | */ | ||
| 144 | if (round_up(wrapper.length, 8) != ctx->sig_len) { | ||
| 145 | pr_debug("Signature wrapper len wrong\n"); | ||
| 146 | return -ELIBBAD; | ||
| 147 | } | ||
| 148 | if (wrapper.revision != WIN_CERT_REVISION_2_0) { | ||
| 149 | pr_debug("Signature is not revision 2.0\n"); | ||
| 150 | return -ENOTSUPP; | ||
| 151 | } | ||
| 152 | if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) { | ||
| 153 | pr_debug("Signature certificate type is not PKCS\n"); | ||
| 154 | return -ENOTSUPP; | ||
| 155 | } | ||
| 156 | |||
| 157 | /* Looks like actual pkcs signature length is in wrapper->length. | ||
| 158 | * size obtained from data dir entries lists the total size of | ||
| 159 | * certificate table which is also aligned to octawrod boundary. | ||
| 160 | * | ||
| 161 | * So set signature length field appropriately. | ||
| 162 | */ | ||
| 163 | ctx->sig_len = wrapper.length; | ||
| 164 | ctx->sig_offset += sizeof(wrapper); | ||
| 165 | ctx->sig_len -= sizeof(wrapper); | ||
| 166 | if (ctx->sig_len == 0) { | ||
| 167 | pr_debug("Signature data missing\n"); | ||
| 168 | return -EKEYREJECTED; | ||
| 169 | } | ||
| 170 | |||
| 171 | /* What's left should a PKCS#7 cert */ | ||
| 172 | pkcs7 = pebuf + ctx->sig_offset; | ||
| 173 | if (pkcs7[0] == (ASN1_CONS_BIT | ASN1_SEQ)) { | ||
| 174 | if (pkcs7[1] == 0x82 && | ||
| 175 | pkcs7[2] == (((ctx->sig_len - 4) >> 8) & 0xff) && | ||
| 176 | pkcs7[3] == ((ctx->sig_len - 4) & 0xff)) | ||
| 177 | return 0; | ||
| 178 | if (pkcs7[1] == 0x80) | ||
| 179 | return 0; | ||
| 180 | if (pkcs7[1] > 0x82) | ||
| 181 | return -EMSGSIZE; | ||
| 182 | } | ||
| 183 | |||
| 184 | pr_debug("Signature data not PKCS#7\n"); | ||
| 185 | return -ELIBBAD; | ||
| 186 | } | ||
| 187 | |||
| 188 | /* | ||
| 189 | * Compare two sections for canonicalisation. | ||
| 190 | */ | ||
| 191 | static int pefile_compare_shdrs(const void *a, const void *b) | ||
| 192 | { | ||
| 193 | const struct section_header *shdra = a; | ||
| 194 | const struct section_header *shdrb = b; | ||
| 195 | int rc; | ||
| 196 | |||
| 197 | if (shdra->data_addr > shdrb->data_addr) | ||
| 198 | return 1; | ||
| 199 | if (shdrb->data_addr > shdra->data_addr) | ||
| 200 | return -1; | ||
| 201 | |||
| 202 | if (shdra->virtual_address > shdrb->virtual_address) | ||
| 203 | return 1; | ||
| 204 | if (shdrb->virtual_address > shdra->virtual_address) | ||
| 205 | return -1; | ||
| 206 | |||
| 207 | rc = strcmp(shdra->name, shdrb->name); | ||
| 208 | if (rc != 0) | ||
| 209 | return rc; | ||
| 210 | |||
| 211 | if (shdra->virtual_size > shdrb->virtual_size) | ||
| 212 | return 1; | ||
| 213 | if (shdrb->virtual_size > shdra->virtual_size) | ||
| 214 | return -1; | ||
| 215 | |||
| 216 | if (shdra->raw_data_size > shdrb->raw_data_size) | ||
| 217 | return 1; | ||
| 218 | if (shdrb->raw_data_size > shdra->raw_data_size) | ||
| 219 | return -1; | ||
| 220 | |||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | /* | ||
| 225 | * Load the contents of the PE binary into the digest, leaving out the image | ||
| 226 | * checksum and the certificate data block. | ||
| 227 | */ | ||
| 228 | static int pefile_digest_pe_contents(const void *pebuf, unsigned int pelen, | ||
| 229 | struct pefile_context *ctx, | ||
| 230 | struct shash_desc *desc) | ||
| 231 | { | ||
| 232 | unsigned *canon, tmp, loop, i, hashed_bytes; | ||
| 233 | int ret; | ||
| 234 | |||
| 235 | /* Digest the header and data directory, but leave out the image | ||
| 236 | * checksum and the data dirent for the signature. | ||
| 237 | */ | ||
| 238 | ret = crypto_shash_update(desc, pebuf, ctx->image_checksum_offset); | ||
| 239 | if (ret < 0) | ||
| 240 | return ret; | ||
| 241 | |||
| 242 | tmp = ctx->image_checksum_offset + sizeof(uint32_t); | ||
| 243 | ret = crypto_shash_update(desc, pebuf + tmp, | ||
| 244 | ctx->cert_dirent_offset - tmp); | ||
| 245 | if (ret < 0) | ||
| 246 | return ret; | ||
| 247 | |||
| 248 | tmp = ctx->cert_dirent_offset + sizeof(struct data_dirent); | ||
| 249 | ret = crypto_shash_update(desc, pebuf + tmp, ctx->header_size - tmp); | ||
| 250 | if (ret < 0) | ||
| 251 | return ret; | ||
| 252 | |||
| 253 | canon = kcalloc(ctx->n_sections, sizeof(unsigned), GFP_KERNEL); | ||
| 254 | if (!canon) | ||
| 255 | return -ENOMEM; | ||
| 256 | |||
| 257 | /* We have to canonicalise the section table, so we perform an | ||
| 258 | * insertion sort. | ||
| 259 | */ | ||
| 260 | canon[0] = 0; | ||
| 261 | for (loop = 1; loop < ctx->n_sections; loop++) { | ||
| 262 | for (i = 0; i < loop; i++) { | ||
| 263 | if (pefile_compare_shdrs(&ctx->secs[canon[i]], | ||
| 264 | &ctx->secs[loop]) > 0) { | ||
| 265 | memmove(&canon[i + 1], &canon[i], | ||
| 266 | (loop - i) * sizeof(canon[0])); | ||
| 267 | break; | ||
| 268 | } | ||
| 269 | } | ||
| 270 | canon[i] = loop; | ||
| 271 | } | ||
| 272 | |||
| 273 | hashed_bytes = ctx->header_size; | ||
| 274 | for (loop = 0; loop < ctx->n_sections; loop++) { | ||
| 275 | i = canon[loop]; | ||
| 276 | if (ctx->secs[i].raw_data_size == 0) | ||
| 277 | continue; | ||
| 278 | ret = crypto_shash_update(desc, | ||
| 279 | pebuf + ctx->secs[i].data_addr, | ||
| 280 | ctx->secs[i].raw_data_size); | ||
| 281 | if (ret < 0) { | ||
| 282 | kfree(canon); | ||
| 283 | return ret; | ||
| 284 | } | ||
| 285 | hashed_bytes += ctx->secs[i].raw_data_size; | ||
| 286 | } | ||
| 287 | kfree(canon); | ||
| 288 | |||
| 289 | if (pelen > hashed_bytes) { | ||
| 290 | tmp = hashed_bytes + ctx->certs_size; | ||
| 291 | ret = crypto_shash_update(desc, | ||
| 292 | pebuf + hashed_bytes, | ||
| 293 | pelen - tmp); | ||
| 294 | if (ret < 0) | ||
| 295 | return ret; | ||
| 296 | } | ||
| 297 | |||
| 298 | return 0; | ||
| 299 | } | ||
| 300 | |||
| 301 | /* | ||
| 302 | * Digest the contents of the PE binary, leaving out the image checksum and the | ||
| 303 | * certificate data block. | ||
| 304 | */ | ||
| 305 | static int pefile_digest_pe(const void *pebuf, unsigned int pelen, | ||
| 306 | struct pefile_context *ctx) | ||
| 307 | { | ||
| 308 | struct crypto_shash *tfm; | ||
| 309 | struct shash_desc *desc; | ||
| 310 | size_t digest_size, desc_size; | ||
| 311 | void *digest; | ||
| 312 | int ret; | ||
| 313 | |||
| 314 | kenter(",%u", ctx->digest_algo); | ||
| 315 | |||
| 316 | /* Allocate the hashing algorithm we're going to need and find out how | ||
| 317 | * big the hash operational data will be. | ||
| 318 | */ | ||
| 319 | tfm = crypto_alloc_shash(hash_algo_name[ctx->digest_algo], 0, 0); | ||
| 320 | if (IS_ERR(tfm)) | ||
| 321 | return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); | ||
| 322 | |||
| 323 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | ||
| 324 | digest_size = crypto_shash_digestsize(tfm); | ||
| 325 | |||
| 326 | if (digest_size != ctx->digest_len) { | ||
| 327 | pr_debug("Digest size mismatch (%zx != %x)\n", | ||
| 328 | digest_size, ctx->digest_len); | ||
| 329 | ret = -EBADMSG; | ||
| 330 | goto error_no_desc; | ||
| 331 | } | ||
| 332 | pr_debug("Digest: desc=%zu size=%zu\n", desc_size, digest_size); | ||
| 333 | |||
| 334 | ret = -ENOMEM; | ||
| 335 | desc = kzalloc(desc_size + digest_size, GFP_KERNEL); | ||
| 336 | if (!desc) | ||
| 337 | goto error_no_desc; | ||
| 338 | |||
| 339 | desc->tfm = tfm; | ||
| 340 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
| 341 | ret = crypto_shash_init(desc); | ||
| 342 | if (ret < 0) | ||
| 343 | goto error; | ||
| 344 | |||
| 345 | ret = pefile_digest_pe_contents(pebuf, pelen, ctx, desc); | ||
| 346 | if (ret < 0) | ||
| 347 | goto error; | ||
| 348 | |||
| 349 | digest = (void *)desc + desc_size; | ||
| 350 | ret = crypto_shash_final(desc, digest); | ||
| 351 | if (ret < 0) | ||
| 352 | goto error; | ||
| 353 | |||
| 354 | pr_debug("Digest calc = [%*ph]\n", ctx->digest_len, digest); | ||
| 355 | |||
| 356 | /* Check that the PE file digest matches that in the MSCODE part of the | ||
| 357 | * PKCS#7 certificate. | ||
| 358 | */ | ||
| 359 | if (memcmp(digest, ctx->digest, ctx->digest_len) != 0) { | ||
| 360 | pr_debug("Digest mismatch\n"); | ||
| 361 | ret = -EKEYREJECTED; | ||
| 362 | } else { | ||
| 363 | pr_debug("The digests match!\n"); | ||
| 364 | } | ||
| 365 | |||
| 366 | error: | ||
| 367 | kfree(desc); | ||
| 368 | error_no_desc: | ||
| 369 | crypto_free_shash(tfm); | ||
| 370 | kleave(" = %d", ret); | ||
| 371 | return ret; | ||
| 372 | } | ||
| 373 | |||
| 374 | /** | ||
| 375 | * verify_pefile_signature - Verify the signature on a PE binary image | ||
| 376 | * @pebuf: Buffer containing the PE binary image | ||
| 377 | * @pelen: Length of the binary image | ||
| 378 | * @trust_keyring: Signing certificates to use as starting points | ||
| 379 | * @_trusted: Set to true if trustworth, false otherwise | ||
| 380 | * | ||
| 381 | * Validate that the certificate chain inside the PKCS#7 message inside the PE | ||
| 382 | * binary image intersects keys we already know and trust. | ||
| 383 | * | ||
| 384 | * Returns, in order of descending priority: | ||
| 385 | * | ||
| 386 | * (*) -ELIBBAD if the image cannot be parsed, or: | ||
| 387 | * | ||
| 388 | * (*) -EKEYREJECTED if a signature failed to match for which we have a valid | ||
| 389 | * key, or: | ||
| 390 | * | ||
| 391 | * (*) 0 if at least one signature chain intersects with the keys in the trust | ||
| 392 | * keyring, or: | ||
| 393 | * | ||
| 394 | * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a | ||
| 395 | * chain. | ||
| 396 | * | ||
| 397 | * (*) -ENOKEY if we couldn't find a match for any of the signature chains in | ||
| 398 | * the message. | ||
| 399 | * | ||
| 400 | * May also return -ENOMEM. | ||
| 401 | */ | ||
| 402 | int verify_pefile_signature(const void *pebuf, unsigned pelen, | ||
| 403 | struct key *trusted_keyring, bool *_trusted) | ||
| 404 | { | ||
| 405 | struct pkcs7_message *pkcs7; | ||
| 406 | struct pefile_context ctx; | ||
| 407 | const void *data; | ||
| 408 | size_t datalen; | ||
| 409 | int ret; | ||
| 410 | |||
| 411 | kenter(""); | ||
| 412 | |||
| 413 | memset(&ctx, 0, sizeof(ctx)); | ||
| 414 | ret = pefile_parse_binary(pebuf, pelen, &ctx); | ||
| 415 | if (ret < 0) | ||
| 416 | return ret; | ||
| 417 | |||
| 418 | ret = pefile_strip_sig_wrapper(pebuf, &ctx); | ||
| 419 | if (ret < 0) | ||
| 420 | return ret; | ||
| 421 | |||
| 422 | pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len); | ||
| 423 | if (IS_ERR(pkcs7)) | ||
| 424 | return PTR_ERR(pkcs7); | ||
| 425 | ctx.pkcs7 = pkcs7; | ||
| 426 | |||
| 427 | ret = pkcs7_get_content_data(ctx.pkcs7, &data, &datalen, false); | ||
| 428 | if (ret < 0 || datalen == 0) { | ||
| 429 | pr_devel("PKCS#7 message does not contain data\n"); | ||
| 430 | ret = -EBADMSG; | ||
| 431 | goto error; | ||
| 432 | } | ||
| 433 | |||
| 434 | ret = mscode_parse(&ctx); | ||
| 435 | if (ret < 0) | ||
| 436 | goto error; | ||
| 437 | |||
| 438 | pr_debug("Digest: %u [%*ph]\n", | ||
| 439 | ctx.digest_len, ctx.digest_len, ctx.digest); | ||
| 440 | |||
| 441 | /* Generate the digest and check against the PKCS7 certificate | ||
| 442 | * contents. | ||
| 443 | */ | ||
| 444 | ret = pefile_digest_pe(pebuf, pelen, &ctx); | ||
| 445 | if (ret < 0) | ||
| 446 | goto error; | ||
| 447 | |||
| 448 | ret = pkcs7_verify(pkcs7); | ||
| 449 | if (ret < 0) | ||
| 450 | goto error; | ||
| 451 | |||
| 452 | ret = pkcs7_validate_trust(pkcs7, trusted_keyring, _trusted); | ||
| 453 | |||
| 454 | error: | ||
| 455 | pkcs7_free_message(ctx.pkcs7); | ||
| 456 | return ret; | ||
| 457 | } | ||
diff --git a/crypto/asymmetric_keys/verify_pefile.h b/crypto/asymmetric_keys/verify_pefile.h new file mode 100644 index 000000000000..55d5f7ebc45a --- /dev/null +++ b/crypto/asymmetric_keys/verify_pefile.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | /* PE Binary parser bits | ||
| 2 | * | ||
| 3 | * Copyright (C) 2014 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 <linux/verify_pefile.h> | ||
| 13 | #include <crypto/pkcs7.h> | ||
| 14 | #include <crypto/hash_info.h> | ||
| 15 | |||
| 16 | struct pefile_context { | ||
| 17 | unsigned header_size; | ||
| 18 | unsigned image_checksum_offset; | ||
| 19 | unsigned cert_dirent_offset; | ||
| 20 | unsigned n_data_dirents; | ||
| 21 | unsigned n_sections; | ||
| 22 | unsigned certs_size; | ||
| 23 | unsigned sig_offset; | ||
| 24 | unsigned sig_len; | ||
| 25 | const struct section_header *secs; | ||
| 26 | struct pkcs7_message *pkcs7; | ||
| 27 | |||
| 28 | /* PKCS#7 MS Individual Code Signing content */ | ||
| 29 | const void *digest; /* Digest */ | ||
| 30 | unsigned digest_len; /* Digest length */ | ||
| 31 | enum hash_algo digest_algo; /* Digest algorithm */ | ||
| 32 | }; | ||
| 33 | |||
| 34 | #define kenter(FMT, ...) \ | ||
| 35 | pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) | ||
| 36 | #define kleave(FMT, ...) \ | ||
| 37 | pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) | ||
| 38 | |||
| 39 | /* | ||
| 40 | * mscode_parser.c | ||
| 41 | */ | ||
| 42 | extern int mscode_parse(struct pefile_context *ctx); | ||
diff --git a/crypto/asymmetric_keys/x509.asn1 b/crypto/asymmetric_keys/x509.asn1 index bf32b3dff088..aae0cde414e2 100644 --- a/crypto/asymmetric_keys/x509.asn1 +++ b/crypto/asymmetric_keys/x509.asn1 | |||
| @@ -6,7 +6,7 @@ Certificate ::= SEQUENCE { | |||
| 6 | 6 | ||
| 7 | TBSCertificate ::= SEQUENCE { | 7 | TBSCertificate ::= SEQUENCE { |
| 8 | version [ 0 ] Version DEFAULT, | 8 | version [ 0 ] Version DEFAULT, |
| 9 | serialNumber CertificateSerialNumber, | 9 | serialNumber CertificateSerialNumber ({ x509_note_serial }), |
| 10 | signature AlgorithmIdentifier ({ x509_note_pkey_algo }), | 10 | signature AlgorithmIdentifier ({ x509_note_pkey_algo }), |
| 11 | issuer Name ({ x509_note_issuer }), | 11 | issuer Name ({ x509_note_issuer }), |
| 12 | validity Validity, | 12 | validity Validity, |
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 29893162497c..ac72348c186a 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | #define pr_fmt(fmt) "X.509: "fmt | 12 | #define pr_fmt(fmt) "X.509: "fmt |
| 13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 14 | #include <linux/export.h> | ||
| 14 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 15 | #include <linux/err.h> | 16 | #include <linux/err.h> |
| 16 | #include <linux/oid_registry.h> | 17 | #include <linux/oid_registry.h> |
| @@ -52,6 +53,7 @@ void x509_free_certificate(struct x509_certificate *cert) | |||
| 52 | kfree(cert); | 53 | kfree(cert); |
| 53 | } | 54 | } |
| 54 | } | 55 | } |
| 56 | EXPORT_SYMBOL_GPL(x509_free_certificate); | ||
| 55 | 57 | ||
| 56 | /* | 58 | /* |
| 57 | * Parse an X.509 certificate | 59 | * Parse an X.509 certificate |
| @@ -97,6 +99,7 @@ error_no_ctx: | |||
| 97 | error_no_cert: | 99 | error_no_cert: |
| 98 | return ERR_PTR(ret); | 100 | return ERR_PTR(ret); |
| 99 | } | 101 | } |
| 102 | EXPORT_SYMBOL_GPL(x509_cert_parse); | ||
| 100 | 103 | ||
| 101 | /* | 104 | /* |
| 102 | * Note an OID when we find one for later processing when we know how | 105 | * Note an OID when we find one for later processing when we know how |
| @@ -211,6 +214,19 @@ int x509_note_signature(void *context, size_t hdrlen, | |||
| 211 | } | 214 | } |
| 212 | 215 | ||
| 213 | /* | 216 | /* |
| 217 | * Note the certificate serial number | ||
| 218 | */ | ||
| 219 | int x509_note_serial(void *context, size_t hdrlen, | ||
| 220 | unsigned char tag, | ||
| 221 | const void *value, size_t vlen) | ||
| 222 | { | ||
| 223 | struct x509_parse_context *ctx = context; | ||
| 224 | ctx->cert->raw_serial = value; | ||
| 225 | ctx->cert->raw_serial_size = vlen; | ||
| 226 | return 0; | ||
| 227 | } | ||
| 228 | |||
| 229 | /* | ||
| 214 | * Note some of the name segments from which we'll fabricate a name. | 230 | * Note some of the name segments from which we'll fabricate a name. |
| 215 | */ | 231 | */ |
| 216 | int x509_extract_name_segment(void *context, size_t hdrlen, | 232 | int x509_extract_name_segment(void *context, size_t hdrlen, |
| @@ -322,6 +338,8 @@ int x509_note_issuer(void *context, size_t hdrlen, | |||
| 322 | const void *value, size_t vlen) | 338 | const void *value, size_t vlen) |
| 323 | { | 339 | { |
| 324 | struct x509_parse_context *ctx = context; | 340 | struct x509_parse_context *ctx = context; |
| 341 | ctx->cert->raw_issuer = value; | ||
| 342 | ctx->cert->raw_issuer_size = vlen; | ||
| 325 | return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen); | 343 | return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen); |
| 326 | } | 344 | } |
| 327 | 345 | ||
| @@ -330,6 +348,8 @@ int x509_note_subject(void *context, size_t hdrlen, | |||
| 330 | const void *value, size_t vlen) | 348 | const void *value, size_t vlen) |
| 331 | { | 349 | { |
| 332 | struct x509_parse_context *ctx = context; | 350 | struct x509_parse_context *ctx = context; |
| 351 | ctx->cert->raw_subject = value; | ||
| 352 | ctx->cert->raw_subject_size = vlen; | ||
| 333 | return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen); | 353 | return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen); |
| 334 | } | 354 | } |
| 335 | 355 | ||
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h index 87d9cc26f630..1b76f207c1f3 100644 --- a/crypto/asymmetric_keys/x509_parser.h +++ b/crypto/asymmetric_keys/x509_parser.h | |||
| @@ -14,7 +14,9 @@ | |||
| 14 | 14 | ||
| 15 | struct x509_certificate { | 15 | struct x509_certificate { |
| 16 | struct x509_certificate *next; | 16 | struct x509_certificate *next; |
| 17 | struct x509_certificate *signer; /* Certificate that signed this one */ | ||
| 17 | struct public_key *pub; /* Public key details */ | 18 | struct public_key *pub; /* Public key details */ |
| 19 | struct public_key_signature sig; /* Signature parameters */ | ||
| 18 | char *issuer; /* Name of certificate issuer */ | 20 | char *issuer; /* Name of certificate issuer */ |
| 19 | char *subject; /* Name of certificate subject */ | 21 | char *subject; /* Name of certificate subject */ |
| 20 | char *fingerprint; /* Key fingerprint as hex */ | 22 | char *fingerprint; /* Key fingerprint as hex */ |
| @@ -25,7 +27,16 @@ struct x509_certificate { | |||
| 25 | unsigned tbs_size; /* Size of signed data */ | 27 | unsigned tbs_size; /* Size of signed data */ |
| 26 | unsigned raw_sig_size; /* Size of sigature */ | 28 | unsigned raw_sig_size; /* Size of sigature */ |
| 27 | const void *raw_sig; /* Signature data */ | 29 | const void *raw_sig; /* Signature data */ |
| 28 | struct public_key_signature sig; /* Signature parameters */ | 30 | const void *raw_serial; /* Raw serial number in ASN.1 */ |
| 31 | unsigned raw_serial_size; | ||
| 32 | unsigned raw_issuer_size; | ||
| 33 | const void *raw_issuer; /* Raw issuer name in ASN.1 */ | ||
| 34 | const void *raw_subject; /* Raw subject name in ASN.1 */ | ||
| 35 | unsigned raw_subject_size; | ||
| 36 | unsigned index; | ||
| 37 | bool seen; /* Infinite recursion prevention */ | ||
| 38 | bool verified; | ||
| 39 | bool trusted; | ||
| 29 | }; | 40 | }; |
| 30 | 41 | ||
| 31 | /* | 42 | /* |
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 382ef0d2ff2e..a0f7cd196c9b 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
| @@ -18,11 +18,80 @@ | |||
| 18 | #include <linux/asn1_decoder.h> | 18 | #include <linux/asn1_decoder.h> |
| 19 | #include <keys/asymmetric-subtype.h> | 19 | #include <keys/asymmetric-subtype.h> |
| 20 | #include <keys/asymmetric-parser.h> | 20 | #include <keys/asymmetric-parser.h> |
| 21 | #include <keys/system_keyring.h> | ||
| 21 | #include <crypto/hash.h> | 22 | #include <crypto/hash.h> |
| 22 | #include "asymmetric_keys.h" | 23 | #include "asymmetric_keys.h" |
| 23 | #include "public_key.h" | 24 | #include "public_key.h" |
| 24 | #include "x509_parser.h" | 25 | #include "x509_parser.h" |
| 25 | 26 | ||
| 27 | static bool use_builtin_keys; | ||
| 28 | static char *ca_keyid; | ||
| 29 | |||
| 30 | #ifndef MODULE | ||
| 31 | static int __init ca_keys_setup(char *str) | ||
| 32 | { | ||
| 33 | if (!str) /* default system keyring */ | ||
| 34 | return 1; | ||
| 35 | |||
| 36 | if (strncmp(str, "id:", 3) == 0) | ||
| 37 | ca_keyid = str; /* owner key 'id:xxxxxx' */ | ||
| 38 | else if (strcmp(str, "builtin") == 0) | ||
| 39 | use_builtin_keys = true; | ||
| 40 | |||
| 41 | return 1; | ||
| 42 | } | ||
| 43 | __setup("ca_keys=", ca_keys_setup); | ||
| 44 | #endif | ||
| 45 | |||
| 46 | /* | ||
| 47 | * Find a key in the given keyring by issuer and authority. | ||
| 48 | */ | ||
| 49 | static struct key *x509_request_asymmetric_key(struct key *keyring, | ||
| 50 | const char *signer, | ||
| 51 | size_t signer_len, | ||
| 52 | const char *authority, | ||
| 53 | size_t auth_len) | ||
| 54 | { | ||
| 55 | key_ref_t key; | ||
| 56 | char *id; | ||
| 57 | |||
| 58 | /* Construct an identifier. */ | ||
| 59 | id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL); | ||
| 60 | if (!id) | ||
| 61 | return ERR_PTR(-ENOMEM); | ||
| 62 | |||
| 63 | memcpy(id, signer, signer_len); | ||
| 64 | id[signer_len + 0] = ':'; | ||
| 65 | id[signer_len + 1] = ' '; | ||
| 66 | memcpy(id + signer_len + 2, authority, auth_len); | ||
| 67 | id[signer_len + 2 + auth_len] = 0; | ||
| 68 | |||
| 69 | pr_debug("Look up: \"%s\"\n", id); | ||
| 70 | |||
| 71 | key = keyring_search(make_key_ref(keyring, 1), | ||
| 72 | &key_type_asymmetric, id); | ||
| 73 | if (IS_ERR(key)) | ||
| 74 | pr_debug("Request for module key '%s' err %ld\n", | ||
| 75 | id, PTR_ERR(key)); | ||
| 76 | kfree(id); | ||
| 77 | |||
| 78 | if (IS_ERR(key)) { | ||
| 79 | switch (PTR_ERR(key)) { | ||
| 80 | /* Hide some search errors */ | ||
| 81 | case -EACCES: | ||
| 82 | case -ENOTDIR: | ||
| 83 | case -EAGAIN: | ||
| 84 | return ERR_PTR(-ENOKEY); | ||
| 85 | default: | ||
| 86 | return ERR_CAST(key); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | pr_devel("<==%s() = 0 [%x]\n", __func__, | ||
| 91 | key_serial(key_ref_to_ptr(key))); | ||
| 92 | return key_ref_to_ptr(key); | ||
| 93 | } | ||
| 94 | |||
| 26 | /* | 95 | /* |
| 27 | * Set up the signature parameters in an X.509 certificate. This involves | 96 | * Set up the signature parameters in an X.509 certificate. This involves |
| 28 | * digesting the signed data and extracting the signature. | 97 | * digesting the signed data and extracting the signature. |
| @@ -103,6 +172,40 @@ int x509_check_signature(const struct public_key *pub, | |||
| 103 | EXPORT_SYMBOL_GPL(x509_check_signature); | 172 | EXPORT_SYMBOL_GPL(x509_check_signature); |
| 104 | 173 | ||
| 105 | /* | 174 | /* |
| 175 | * Check the new certificate against the ones in the trust keyring. If one of | ||
| 176 | * those is the signing key and validates the new certificate, then mark the | ||
| 177 | * new certificate as being trusted. | ||
| 178 | * | ||
| 179 | * Return 0 if the new certificate was successfully validated, 1 if we couldn't | ||
| 180 | * find a matching parent certificate in the trusted list and an error if there | ||
| 181 | * is a matching certificate but the signature check fails. | ||
| 182 | */ | ||
| 183 | static int x509_validate_trust(struct x509_certificate *cert, | ||
| 184 | struct key *trust_keyring) | ||
| 185 | { | ||
| 186 | struct key *key; | ||
| 187 | int ret = 1; | ||
| 188 | |||
| 189 | if (!trust_keyring) | ||
| 190 | return -EOPNOTSUPP; | ||
| 191 | |||
| 192 | if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid)) | ||
| 193 | return -EPERM; | ||
| 194 | |||
| 195 | key = x509_request_asymmetric_key(trust_keyring, | ||
| 196 | cert->issuer, strlen(cert->issuer), | ||
| 197 | cert->authority, | ||
| 198 | strlen(cert->authority)); | ||
| 199 | if (!IS_ERR(key)) { | ||
| 200 | if (!use_builtin_keys | ||
| 201 | || test_bit(KEY_FLAG_BUILTIN, &key->flags)) | ||
| 202 | ret = x509_check_signature(key->payload.data, cert); | ||
| 203 | key_put(key); | ||
| 204 | } | ||
| 205 | return ret; | ||
| 206 | } | ||
| 207 | |||
| 208 | /* | ||
| 106 | * Attempt to parse a data blob for a key as an X509 certificate. | 209 | * Attempt to parse a data blob for a key as an X509 certificate. |
| 107 | */ | 210 | */ |
| 108 | static int x509_key_preparse(struct key_preparsed_payload *prep) | 211 | static int x509_key_preparse(struct key_preparsed_payload *prep) |
| @@ -155,9 +258,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
| 155 | /* Check the signature on the key if it appears to be self-signed */ | 258 | /* Check the signature on the key if it appears to be self-signed */ |
| 156 | if (!cert->authority || | 259 | if (!cert->authority || |
| 157 | strcmp(cert->fingerprint, cert->authority) == 0) { | 260 | strcmp(cert->fingerprint, cert->authority) == 0) { |
| 158 | ret = x509_check_signature(cert->pub, cert); | 261 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ |
| 159 | if (ret < 0) | 262 | if (ret < 0) |
| 160 | goto error_free_cert; | 263 | goto error_free_cert; |
| 264 | } else if (!prep->trusted) { | ||
| 265 | ret = x509_validate_trust(cert, get_system_trusted_keyring()); | ||
| 266 | if (!ret) | ||
| 267 | prep->trusted = 1; | ||
| 161 | } | 268 | } |
| 162 | 269 | ||
| 163 | /* Propose a description */ | 270 | /* Propose a description */ |
| @@ -177,7 +284,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
| 177 | __module_get(public_key_subtype.owner); | 284 | __module_get(public_key_subtype.owner); |
| 178 | prep->type_data[0] = &public_key_subtype; | 285 | prep->type_data[0] = &public_key_subtype; |
| 179 | prep->type_data[1] = cert->fingerprint; | 286 | prep->type_data[1] = cert->fingerprint; |
| 180 | prep->payload = cert->pub; | 287 | prep->payload[0] = cert->pub; |
| 181 | prep->description = desc; | 288 | prep->description = desc; |
| 182 | prep->quotalen = 100; | 289 | prep->quotalen = 100; |
| 183 | 290 | ||
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 567983d2c0eb..7dd55b745c4d 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
| @@ -174,7 +174,9 @@ static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen) | |||
| 174 | 174 | ||
| 175 | static struct key_type key_type_id_resolver = { | 175 | static struct key_type key_type_id_resolver = { |
| 176 | .name = "id_resolver", | 176 | .name = "id_resolver", |
| 177 | .instantiate = user_instantiate, | 177 | .preparse = user_preparse, |
| 178 | .free_preparse = user_free_preparse, | ||
| 179 | .instantiate = generic_key_instantiate, | ||
| 178 | .match = user_match, | 180 | .match = user_match, |
| 179 | .revoke = user_revoke, | 181 | .revoke = user_revoke, |
| 180 | .destroy = user_destroy, | 182 | .destroy = user_destroy, |
| @@ -282,6 +284,8 @@ static struct key *nfs_idmap_request_key(const char *name, size_t namelen, | |||
| 282 | desc, "", 0, idmap); | 284 | desc, "", 0, idmap); |
| 283 | mutex_unlock(&idmap->idmap_mutex); | 285 | mutex_unlock(&idmap->idmap_mutex); |
| 284 | } | 286 | } |
| 287 | if (!IS_ERR(rkey)) | ||
| 288 | set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags); | ||
| 285 | 289 | ||
| 286 | kfree(desc); | 290 | kfree(desc); |
| 287 | return rkey; | 291 | return rkey; |
| @@ -394,7 +398,9 @@ static const struct rpc_pipe_ops idmap_upcall_ops = { | |||
| 394 | 398 | ||
| 395 | static struct key_type key_type_id_resolver_legacy = { | 399 | static struct key_type key_type_id_resolver_legacy = { |
| 396 | .name = "id_legacy", | 400 | .name = "id_legacy", |
| 397 | .instantiate = user_instantiate, | 401 | .preparse = user_preparse, |
| 402 | .free_preparse = user_free_preparse, | ||
| 403 | .instantiate = generic_key_instantiate, | ||
| 398 | .match = user_match, | 404 | .match = user_match, |
| 399 | .revoke = user_revoke, | 405 | .revoke = user_revoke, |
| 400 | .destroy = user_destroy, | 406 | .destroy = user_destroy, |
diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h new file mode 100644 index 000000000000..691c79172a26 --- /dev/null +++ b/include/crypto/pkcs7.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | /* PKCS#7 crypto data 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 | struct key; | ||
| 13 | struct pkcs7_message; | ||
| 14 | |||
| 15 | /* | ||
| 16 | * pkcs7_parser.c | ||
| 17 | */ | ||
| 18 | extern struct pkcs7_message *pkcs7_parse_message(const void *data, | ||
| 19 | size_t datalen); | ||
| 20 | extern void pkcs7_free_message(struct pkcs7_message *pkcs7); | ||
| 21 | |||
| 22 | extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, | ||
| 23 | const void **_data, size_t *_datalen, | ||
| 24 | bool want_wrapper); | ||
| 25 | |||
| 26 | /* | ||
| 27 | * pkcs7_trust.c | ||
| 28 | */ | ||
| 29 | extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7, | ||
| 30 | struct key *trust_keyring, | ||
| 31 | bool *_trusted); | ||
| 32 | |||
| 33 | /* | ||
| 34 | * pkcs7_verify.c | ||
| 35 | */ | ||
| 36 | extern int pkcs7_verify(struct pkcs7_message *pkcs7); | ||
diff --git a/include/keys/big_key-type.h b/include/keys/big_key-type.h index d69bc8af3292..e0970a578188 100644 --- a/include/keys/big_key-type.h +++ b/include/keys/big_key-type.h | |||
| @@ -16,7 +16,8 @@ | |||
| 16 | 16 | ||
| 17 | extern struct key_type key_type_big_key; | 17 | extern struct key_type key_type_big_key; |
| 18 | 18 | ||
| 19 | extern int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep); | 19 | extern int big_key_preparse(struct key_preparsed_payload *prep); |
| 20 | extern void big_key_free_preparse(struct key_preparsed_payload *prep); | ||
| 20 | extern void big_key_revoke(struct key *key); | 21 | extern void big_key_revoke(struct key *key); |
| 21 | extern void big_key_destroy(struct key *key); | 22 | extern void big_key_destroy(struct key *key); |
| 22 | extern void big_key_describe(const struct key *big_key, struct seq_file *m); | 23 | extern void big_key_describe(const struct key *big_key, struct seq_file *m); |
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h index 8dabc399bd1d..72665eb80692 100644 --- a/include/keys/system_keyring.h +++ b/include/keys/system_keyring.h | |||
| @@ -17,7 +17,15 @@ | |||
| 17 | #include <linux/key.h> | 17 | #include <linux/key.h> |
| 18 | 18 | ||
| 19 | extern struct key *system_trusted_keyring; | 19 | extern struct key *system_trusted_keyring; |
| 20 | 20 | static inline struct key *get_system_trusted_keyring(void) | |
| 21 | { | ||
| 22 | return system_trusted_keyring; | ||
| 23 | } | ||
| 24 | #else | ||
| 25 | static inline struct key *get_system_trusted_keyring(void) | ||
| 26 | { | ||
| 27 | return NULL; | ||
| 28 | } | ||
| 21 | #endif | 29 | #endif |
| 22 | 30 | ||
| 23 | #endif /* _KEYS_SYSTEM_KEYRING_H */ | 31 | #endif /* _KEYS_SYSTEM_KEYRING_H */ |
diff --git a/include/keys/user-type.h b/include/keys/user-type.h index 5e452c84f1e6..3ab1873a4bfa 100644 --- a/include/keys/user-type.h +++ b/include/keys/user-type.h | |||
| @@ -37,7 +37,8 @@ extern struct key_type key_type_logon; | |||
| 37 | 37 | ||
| 38 | struct key_preparsed_payload; | 38 | struct key_preparsed_payload; |
| 39 | 39 | ||
| 40 | extern int user_instantiate(struct key *key, struct key_preparsed_payload *prep); | 40 | extern int user_preparse(struct key_preparsed_payload *prep); |
| 41 | extern void user_free_preparse(struct key_preparsed_payload *prep); | ||
| 41 | extern int user_update(struct key *key, struct key_preparsed_payload *prep); | 42 | extern int user_update(struct key *key, struct key_preparsed_payload *prep); |
| 42 | extern int user_match(const struct key *key, const void *criterion); | 43 | extern int user_match(const struct key *key, const void *criterion); |
| 43 | extern void user_revoke(struct key *key); | 44 | extern void user_revoke(struct key *key); |
diff --git a/include/linux/key-type.h b/include/linux/key-type.h index a74c3a84dfdd..44792ee649de 100644 --- a/include/linux/key-type.h +++ b/include/linux/key-type.h | |||
| @@ -41,10 +41,11 @@ struct key_construction { | |||
| 41 | struct key_preparsed_payload { | 41 | struct key_preparsed_payload { |
| 42 | char *description; /* Proposed key description (or NULL) */ | 42 | char *description; /* Proposed key description (or NULL) */ |
| 43 | void *type_data[2]; /* Private key-type data */ | 43 | void *type_data[2]; /* Private key-type data */ |
| 44 | void *payload; /* Proposed payload */ | 44 | void *payload[2]; /* Proposed payload */ |
| 45 | const void *data; /* Raw data */ | 45 | const void *data; /* Raw data */ |
| 46 | size_t datalen; /* Raw datalen */ | 46 | size_t datalen; /* Raw datalen */ |
| 47 | size_t quotalen; /* Quota length for proposed payload */ | 47 | size_t quotalen; /* Quota length for proposed payload */ |
| 48 | time_t expiry; /* Expiry time of key */ | ||
| 48 | bool trusted; /* True if key is trusted */ | 49 | bool trusted; /* True if key is trusted */ |
| 49 | }; | 50 | }; |
| 50 | 51 | ||
| @@ -159,5 +160,7 @@ static inline int key_negate_and_link(struct key *key, | |||
| 159 | return key_reject_and_link(key, timeout, ENOKEY, keyring, instkey); | 160 | return key_reject_and_link(key, timeout, ENOKEY, keyring, instkey); |
| 160 | } | 161 | } |
| 161 | 162 | ||
| 163 | extern int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep); | ||
| 164 | |||
| 162 | #endif /* CONFIG_KEYS */ | 165 | #endif /* CONFIG_KEYS */ |
| 163 | #endif /* _LINUX_KEY_TYPE_H */ | 166 | #endif /* _LINUX_KEY_TYPE_H */ |
diff --git a/include/linux/key.h b/include/linux/key.h index 017b0826642f..e1d4715f3222 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
| @@ -170,6 +170,8 @@ struct key { | |||
| 170 | #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ | 170 | #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ |
| 171 | #define KEY_FLAG_TRUSTED 8 /* set if key is trusted */ | 171 | #define KEY_FLAG_TRUSTED 8 /* set if key is trusted */ |
| 172 | #define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */ | 172 | #define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */ |
| 173 | #define KEY_FLAG_BUILTIN 10 /* set if key is builtin */ | ||
| 174 | #define KEY_FLAG_ROOT_CAN_INVAL 11 /* set if key can be invalidated by root without permission */ | ||
| 173 | 175 | ||
| 174 | /* the key type and key description string | 176 | /* the key type and key description string |
| 175 | * - the desc is used to match a key against search criteria | 177 | * - the desc is used to match a key against search criteria |
diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h index 6926db724258..c2bbf672b84e 100644 --- a/include/linux/oid_registry.h +++ b/include/linux/oid_registry.h | |||
| @@ -52,9 +52,15 @@ enum OID { | |||
| 52 | OID_md4, /* 1.2.840.113549.2.4 */ | 52 | OID_md4, /* 1.2.840.113549.2.4 */ |
| 53 | OID_md5, /* 1.2.840.113549.2.5 */ | 53 | OID_md5, /* 1.2.840.113549.2.5 */ |
| 54 | 54 | ||
| 55 | OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ | 55 | /* Microsoft Authenticode & Software Publishing */ |
| 56 | OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */ | ||
| 57 | OID_msPeImageDataObjId, /* 1.3.6.1.4.1.311.2.1.15 */ | ||
| 58 | OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */ | ||
| 56 | OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */ | 59 | OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */ |
| 60 | |||
| 61 | OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ | ||
| 57 | OID_sha1, /* 1.3.14.3.2.26 */ | 62 | OID_sha1, /* 1.3.14.3.2.26 */ |
| 63 | OID_sha256, /* 2.16.840.1.101.3.4.2.1 */ | ||
| 58 | 64 | ||
| 59 | /* Distinguished Name attribute IDs [RFC 2256] */ | 65 | /* Distinguished Name attribute IDs [RFC 2256] */ |
| 60 | OID_commonName, /* 2.5.4.3 */ | 66 | OID_commonName, /* 2.5.4.3 */ |
diff --git a/include/linux/pe.h b/include/linux/pe.h new file mode 100644 index 000000000000..e170b95e763b --- /dev/null +++ b/include/linux/pe.h | |||
| @@ -0,0 +1,448 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2011 Red Hat, Inc. | ||
| 3 | * All rights reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; version 2 of the License. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | * | ||
| 17 | * Author(s): Peter Jones <pjones@redhat.com> | ||
| 18 | */ | ||
| 19 | #ifndef __LINUX_PE_H | ||
| 20 | #define __LINUX_PE_H | ||
| 21 | |||
| 22 | #include <linux/types.h> | ||
| 23 | |||
| 24 | #define MZ_MAGIC 0x5a4d /* "MZ" */ | ||
| 25 | |||
| 26 | struct mz_hdr { | ||
| 27 | uint16_t magic; /* MZ_MAGIC */ | ||
| 28 | uint16_t lbsize; /* size of last used block */ | ||
| 29 | uint16_t blocks; /* pages in file, 0x3 */ | ||
| 30 | uint16_t relocs; /* relocations */ | ||
| 31 | uint16_t hdrsize; /* header size in "paragraphs" */ | ||
| 32 | uint16_t min_extra_pps; /* .bss */ | ||
| 33 | uint16_t max_extra_pps; /* runtime limit for the arena size */ | ||
| 34 | uint16_t ss; /* relative stack segment */ | ||
| 35 | uint16_t sp; /* initial %sp register */ | ||
| 36 | uint16_t checksum; /* word checksum */ | ||
| 37 | uint16_t ip; /* initial %ip register */ | ||
| 38 | uint16_t cs; /* initial %cs relative to load segment */ | ||
| 39 | uint16_t reloc_table_offset; /* offset of the first relocation */ | ||
| 40 | uint16_t overlay_num; /* overlay number. set to 0. */ | ||
| 41 | uint16_t reserved0[4]; /* reserved */ | ||
| 42 | uint16_t oem_id; /* oem identifier */ | ||
| 43 | uint16_t oem_info; /* oem specific */ | ||
| 44 | uint16_t reserved1[10]; /* reserved */ | ||
| 45 | uint32_t peaddr; /* address of pe header */ | ||
| 46 | char message[64]; /* message to print */ | ||
| 47 | }; | ||
| 48 | |||
| 49 | struct mz_reloc { | ||
| 50 | uint16_t offset; | ||
| 51 | uint16_t segment; | ||
| 52 | }; | ||
| 53 | |||
| 54 | #define PE_MAGIC 0x00004550 /* "PE\0\0" */ | ||
| 55 | #define PE_OPT_MAGIC_PE32 0x010b | ||
| 56 | #define PE_OPT_MAGIC_PE32_ROM 0x0107 | ||
| 57 | #define PE_OPT_MAGIC_PE32PLUS 0x020b | ||
| 58 | |||
| 59 | /* machine type */ | ||
| 60 | #define IMAGE_FILE_MACHINE_UNKNOWN 0x0000 | ||
| 61 | #define IMAGE_FILE_MACHINE_AM33 0x01d3 | ||
| 62 | #define IMAGE_FILE_MACHINE_AMD64 0x8664 | ||
| 63 | #define IMAGE_FILE_MACHINE_ARM 0x01c0 | ||
| 64 | #define IMAGE_FILE_MACHINE_ARMV7 0x01c4 | ||
| 65 | #define IMAGE_FILE_MACHINE_EBC 0x0ebc | ||
| 66 | #define IMAGE_FILE_MACHINE_I386 0x014c | ||
| 67 | #define IMAGE_FILE_MACHINE_IA64 0x0200 | ||
| 68 | #define IMAGE_FILE_MACHINE_M32R 0x9041 | ||
| 69 | #define IMAGE_FILE_MACHINE_MIPS16 0x0266 | ||
| 70 | #define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 | ||
| 71 | #define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 | ||
| 72 | #define IMAGE_FILE_MACHINE_POWERPC 0x01f0 | ||
| 73 | #define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 | ||
| 74 | #define IMAGE_FILE_MACHINE_R4000 0x0166 | ||
| 75 | #define IMAGE_FILE_MACHINE_SH3 0x01a2 | ||
| 76 | #define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 | ||
| 77 | #define IMAGE_FILE_MACHINE_SH3E 0x01a4 | ||
| 78 | #define IMAGE_FILE_MACHINE_SH4 0x01a6 | ||
| 79 | #define IMAGE_FILE_MACHINE_SH5 0x01a8 | ||
| 80 | #define IMAGE_FILE_MACHINE_THUMB 0x01c2 | ||
| 81 | #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 | ||
| 82 | |||
| 83 | /* flags */ | ||
| 84 | #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 | ||
| 85 | #define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 | ||
| 86 | #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 | ||
| 87 | #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 | ||
| 88 | #define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010 | ||
| 89 | #define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 | ||
| 90 | #define IMAGE_FILE_16BIT_MACHINE 0x0040 | ||
| 91 | #define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 | ||
| 92 | #define IMAGE_FILE_32BIT_MACHINE 0x0100 | ||
| 93 | #define IMAGE_FILE_DEBUG_STRIPPED 0x0200 | ||
| 94 | #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 | ||
| 95 | #define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 | ||
| 96 | #define IMAGE_FILE_SYSTEM 0x1000 | ||
| 97 | #define IMAGE_FILE_DLL 0x2000 | ||
| 98 | #define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 | ||
| 99 | #define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 | ||
| 100 | |||
| 101 | struct pe_hdr { | ||
| 102 | uint32_t magic; /* PE magic */ | ||
| 103 | uint16_t machine; /* machine type */ | ||
| 104 | uint16_t sections; /* number of sections */ | ||
| 105 | uint32_t timestamp; /* time_t */ | ||
| 106 | uint32_t symbol_table; /* symbol table offset */ | ||
| 107 | uint32_t symbols; /* number of symbols */ | ||
| 108 | uint16_t opt_hdr_size; /* size of optional header */ | ||
| 109 | uint16_t flags; /* flags */ | ||
| 110 | }; | ||
| 111 | |||
| 112 | #define IMAGE_FILE_OPT_ROM_MAGIC 0x107 | ||
| 113 | #define IMAGE_FILE_OPT_PE32_MAGIC 0x10b | ||
| 114 | #define IMAGE_FILE_OPT_PE32_PLUS_MAGIC 0x20b | ||
| 115 | |||
| 116 | #define IMAGE_SUBSYSTEM_UNKNOWN 0 | ||
| 117 | #define IMAGE_SUBSYSTEM_NATIVE 1 | ||
| 118 | #define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 | ||
| 119 | #define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 | ||
| 120 | #define IMAGE_SUBSYSTEM_POSIX_CUI 7 | ||
| 121 | #define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 | ||
| 122 | #define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 | ||
| 123 | #define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 | ||
| 124 | #define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 | ||
| 125 | #define IMAGE_SUBSYSTEM_EFI_ROM_IMAGE 13 | ||
| 126 | #define IMAGE_SUBSYSTEM_XBOX 14 | ||
| 127 | |||
| 128 | #define IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE 0x0040 | ||
| 129 | #define IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY 0x0080 | ||
| 130 | #define IMAGE_DLL_CHARACTERISTICS_NX_COMPAT 0x0100 | ||
| 131 | #define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 | ||
| 132 | #define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 | ||
| 133 | #define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 | ||
| 134 | #define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 | ||
| 135 | #define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 | ||
| 136 | |||
| 137 | /* the fact that pe32 isn't padded where pe32+ is 64-bit means union won't | ||
| 138 | * work right. vomit. */ | ||
| 139 | struct pe32_opt_hdr { | ||
| 140 | /* "standard" header */ | ||
| 141 | uint16_t magic; /* file type */ | ||
| 142 | uint8_t ld_major; /* linker major version */ | ||
| 143 | uint8_t ld_minor; /* linker minor version */ | ||
| 144 | uint32_t text_size; /* size of text section(s) */ | ||
| 145 | uint32_t data_size; /* size of data section(s) */ | ||
| 146 | uint32_t bss_size; /* size of bss section(s) */ | ||
| 147 | uint32_t entry_point; /* file offset of entry point */ | ||
| 148 | uint32_t code_base; /* relative code addr in ram */ | ||
| 149 | uint32_t data_base; /* relative data addr in ram */ | ||
| 150 | /* "windows" header */ | ||
| 151 | uint32_t image_base; /* preferred load address */ | ||
| 152 | uint32_t section_align; /* alignment in bytes */ | ||
| 153 | uint32_t file_align; /* file alignment in bytes */ | ||
| 154 | uint16_t os_major; /* major OS version */ | ||
| 155 | uint16_t os_minor; /* minor OS version */ | ||
| 156 | uint16_t image_major; /* major image version */ | ||
| 157 | uint16_t image_minor; /* minor image version */ | ||
| 158 | uint16_t subsys_major; /* major subsystem version */ | ||
| 159 | uint16_t subsys_minor; /* minor subsystem version */ | ||
| 160 | uint32_t win32_version; /* reserved, must be 0 */ | ||
| 161 | uint32_t image_size; /* image size */ | ||
| 162 | uint32_t header_size; /* header size rounded up to | ||
| 163 | file_align */ | ||
| 164 | uint32_t csum; /* checksum */ | ||
| 165 | uint16_t subsys; /* subsystem */ | ||
| 166 | uint16_t dll_flags; /* more flags! */ | ||
| 167 | uint32_t stack_size_req;/* amt of stack requested */ | ||
| 168 | uint32_t stack_size; /* amt of stack required */ | ||
| 169 | uint32_t heap_size_req; /* amt of heap requested */ | ||
| 170 | uint32_t heap_size; /* amt of heap required */ | ||
| 171 | uint32_t loader_flags; /* reserved, must be 0 */ | ||
| 172 | uint32_t data_dirs; /* number of data dir entries */ | ||
| 173 | }; | ||
| 174 | |||
| 175 | struct pe32plus_opt_hdr { | ||
| 176 | uint16_t magic; /* file type */ | ||
| 177 | uint8_t ld_major; /* linker major version */ | ||
| 178 | uint8_t ld_minor; /* linker minor version */ | ||
| 179 | uint32_t text_size; /* size of text section(s) */ | ||
| 180 | uint32_t data_size; /* size of data section(s) */ | ||
| 181 | uint32_t bss_size; /* size of bss section(s) */ | ||
| 182 | uint32_t entry_point; /* file offset of entry point */ | ||
| 183 | uint32_t code_base; /* relative code addr in ram */ | ||
| 184 | /* "windows" header */ | ||
| 185 | uint64_t image_base; /* preferred load address */ | ||
| 186 | uint32_t section_align; /* alignment in bytes */ | ||
| 187 | uint32_t file_align; /* file alignment in bytes */ | ||
| 188 | uint16_t os_major; /* major OS version */ | ||
| 189 | uint16_t os_minor; /* minor OS version */ | ||
| 190 | uint16_t image_major; /* major image version */ | ||
| 191 | uint16_t image_minor; /* minor image version */ | ||
| 192 | uint16_t subsys_major; /* major subsystem version */ | ||
| 193 | uint16_t subsys_minor; /* minor subsystem version */ | ||
| 194 | uint32_t win32_version; /* reserved, must be 0 */ | ||
| 195 | uint32_t image_size; /* image size */ | ||
| 196 | uint32_t header_size; /* header size rounded up to | ||
| 197 | file_align */ | ||
| 198 | uint32_t csum; /* checksum */ | ||
| 199 | uint16_t subsys; /* subsystem */ | ||
| 200 | uint16_t dll_flags; /* more flags! */ | ||
| 201 | uint64_t stack_size_req;/* amt of stack requested */ | ||
| 202 | uint64_t stack_size; /* amt of stack required */ | ||
| 203 | uint64_t heap_size_req; /* amt of heap requested */ | ||
| 204 | uint64_t heap_size; /* amt of heap required */ | ||
| 205 | uint32_t loader_flags; /* reserved, must be 0 */ | ||
| 206 | uint32_t data_dirs; /* number of data dir entries */ | ||
| 207 | }; | ||
| 208 | |||
| 209 | struct data_dirent { | ||
| 210 | uint32_t virtual_address; /* relative to load address */ | ||
| 211 | uint32_t size; | ||
| 212 | }; | ||
| 213 | |||
| 214 | struct data_directory { | ||
| 215 | struct data_dirent exports; /* .edata */ | ||
| 216 | struct data_dirent imports; /* .idata */ | ||
| 217 | struct data_dirent resources; /* .rsrc */ | ||
| 218 | struct data_dirent exceptions; /* .pdata */ | ||
| 219 | struct data_dirent certs; /* certs */ | ||
| 220 | struct data_dirent base_relocations; /* .reloc */ | ||
| 221 | struct data_dirent debug; /* .debug */ | ||
| 222 | struct data_dirent arch; /* reservered */ | ||
| 223 | struct data_dirent global_ptr; /* global pointer reg. Size=0 */ | ||
| 224 | struct data_dirent tls; /* .tls */ | ||
| 225 | struct data_dirent load_config; /* load configuration structure */ | ||
| 226 | struct data_dirent bound_imports; /* no idea */ | ||
| 227 | struct data_dirent import_addrs; /* import address table */ | ||
| 228 | struct data_dirent delay_imports; /* delay-load import table */ | ||
| 229 | struct data_dirent clr_runtime_hdr; /* .cor (object only) */ | ||
| 230 | struct data_dirent reserved; | ||
| 231 | }; | ||
| 232 | |||
| 233 | struct section_header { | ||
| 234 | char name[8]; /* name or "/12\0" string tbl offset */ | ||
| 235 | uint32_t virtual_size; /* size of loaded section in ram */ | ||
| 236 | uint32_t virtual_address; /* relative virtual address */ | ||
| 237 | uint32_t raw_data_size; /* size of the section */ | ||
| 238 | uint32_t data_addr; /* file pointer to first page of sec */ | ||
| 239 | uint32_t relocs; /* file pointer to relocation entries */ | ||
| 240 | uint32_t line_numbers; /* line numbers! */ | ||
| 241 | uint16_t num_relocs; /* number of relocations */ | ||
| 242 | uint16_t num_lin_numbers; /* srsly. */ | ||
| 243 | uint32_t flags; | ||
| 244 | }; | ||
| 245 | |||
| 246 | /* they actually defined 0x00000000 as well, but I think we'll skip that one. */ | ||
| 247 | #define IMAGE_SCN_RESERVED_0 0x00000001 | ||
| 248 | #define IMAGE_SCN_RESERVED_1 0x00000002 | ||
| 249 | #define IMAGE_SCN_RESERVED_2 0x00000004 | ||
| 250 | #define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* don't pad - obsolete */ | ||
| 251 | #define IMAGE_SCN_RESERVED_3 0x00000010 | ||
| 252 | #define IMAGE_SCN_CNT_CODE 0x00000020 /* .text */ | ||
| 253 | #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* .data */ | ||
| 254 | #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* .bss */ | ||
| 255 | #define IMAGE_SCN_LNK_OTHER 0x00000100 /* reserved */ | ||
| 256 | #define IMAGE_SCN_LNK_INFO 0x00000200 /* .drectve comments */ | ||
| 257 | #define IMAGE_SCN_RESERVED_4 0x00000400 | ||
| 258 | #define IMAGE_SCN_LNK_REMOVE 0x00000800 /* .o only - scn to be rm'd*/ | ||
| 259 | #define IMAGE_SCN_LNK_COMDAT 0x00001000 /* .o only - COMDAT data */ | ||
| 260 | #define IMAGE_SCN_RESERVED_5 0x00002000 /* spec omits this */ | ||
| 261 | #define IMAGE_SCN_RESERVED_6 0x00004000 /* spec omits this */ | ||
| 262 | #define IMAGE_SCN_GPREL 0x00008000 /* global pointer referenced data */ | ||
| 263 | /* spec lists 0x20000 twice, I suspect they meant 0x10000 for one of them */ | ||
| 264 | #define IMAGE_SCN_MEM_PURGEABLE 0x00010000 /* reserved for "future" use */ | ||
| 265 | #define IMAGE_SCN_16BIT 0x00020000 /* reserved for "future" use */ | ||
| 266 | #define IMAGE_SCN_LOCKED 0x00040000 /* reserved for "future" use */ | ||
| 267 | #define IMAGE_SCN_PRELOAD 0x00080000 /* reserved for "future" use */ | ||
| 268 | /* and here they just stuck a 1-byte integer in the middle of a bitfield */ | ||
| 269 | #define IMAGE_SCN_ALIGN_1BYTES 0x00100000 /* it does what it says on the box */ | ||
| 270 | #define IMAGE_SCN_ALIGN_2BYTES 0x00200000 | ||
| 271 | #define IMAGE_SCN_ALIGN_4BYTES 0x00300000 | ||
| 272 | #define IMAGE_SCN_ALIGN_8BYTES 0x00400000 | ||
| 273 | #define IMAGE_SCN_ALIGN_16BYTES 0x00500000 | ||
| 274 | #define IMAGE_SCN_ALIGN_32BYTES 0x00600000 | ||
| 275 | #define IMAGE_SCN_ALIGN_64BYTES 0x00700000 | ||
| 276 | #define IMAGE_SCN_ALIGN_128BYTES 0x00800000 | ||
| 277 | #define IMAGE_SCN_ALIGN_256BYTES 0x00900000 | ||
| 278 | #define IMAGE_SCN_ALIGN_512BYTES 0x00a00000 | ||
| 279 | #define IMAGE_SCN_ALIGN_1024BYTES 0x00b00000 | ||
| 280 | #define IMAGE_SCN_ALIGN_2048BYTES 0x00c00000 | ||
| 281 | #define IMAGE_SCN_ALIGN_4096BYTES 0x00d00000 | ||
| 282 | #define IMAGE_SCN_ALIGN_8192BYTES 0x00e00000 | ||
| 283 | #define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* extended relocations */ | ||
| 284 | #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 /* scn can be discarded */ | ||
| 285 | #define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* cannot be cached */ | ||
| 286 | #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* not pageable */ | ||
| 287 | #define IMAGE_SCN_MEM_SHARED 0x10000000 /* can be shared */ | ||
| 288 | #define IMAGE_SCN_MEM_EXECUTE 0x20000000 /* can be executed as code */ | ||
| 289 | #define IMAGE_SCN_MEM_READ 0x40000000 /* readable */ | ||
| 290 | #define IMAGE_SCN_MEM_WRITE 0x80000000 /* writeable */ | ||
| 291 | |||
| 292 | enum x64_coff_reloc_type { | ||
| 293 | IMAGE_REL_AMD64_ABSOLUTE = 0, | ||
| 294 | IMAGE_REL_AMD64_ADDR64, | ||
| 295 | IMAGE_REL_AMD64_ADDR32, | ||
| 296 | IMAGE_REL_AMD64_ADDR32N, | ||
| 297 | IMAGE_REL_AMD64_REL32, | ||
| 298 | IMAGE_REL_AMD64_REL32_1, | ||
| 299 | IMAGE_REL_AMD64_REL32_2, | ||
| 300 | IMAGE_REL_AMD64_REL32_3, | ||
| 301 | IMAGE_REL_AMD64_REL32_4, | ||
| 302 | IMAGE_REL_AMD64_REL32_5, | ||
| 303 | IMAGE_REL_AMD64_SECTION, | ||
| 304 | IMAGE_REL_AMD64_SECREL, | ||
| 305 | IMAGE_REL_AMD64_SECREL7, | ||
| 306 | IMAGE_REL_AMD64_TOKEN, | ||
| 307 | IMAGE_REL_AMD64_SREL32, | ||
| 308 | IMAGE_REL_AMD64_PAIR, | ||
| 309 | IMAGE_REL_AMD64_SSPAN32, | ||
| 310 | }; | ||
| 311 | |||
| 312 | enum arm_coff_reloc_type { | ||
| 313 | IMAGE_REL_ARM_ABSOLUTE, | ||
| 314 | IMAGE_REL_ARM_ADDR32, | ||
| 315 | IMAGE_REL_ARM_ADDR32N, | ||
| 316 | IMAGE_REL_ARM_BRANCH2, | ||
| 317 | IMAGE_REL_ARM_BRANCH1, | ||
| 318 | IMAGE_REL_ARM_SECTION, | ||
| 319 | IMAGE_REL_ARM_SECREL, | ||
| 320 | }; | ||
| 321 | |||
| 322 | enum sh_coff_reloc_type { | ||
| 323 | IMAGE_REL_SH3_ABSOLUTE, | ||
| 324 | IMAGE_REL_SH3_DIRECT16, | ||
| 325 | IMAGE_REL_SH3_DIRECT32, | ||
| 326 | IMAGE_REL_SH3_DIRECT8, | ||
| 327 | IMAGE_REL_SH3_DIRECT8_WORD, | ||
| 328 | IMAGE_REL_SH3_DIRECT8_LONG, | ||
| 329 | IMAGE_REL_SH3_DIRECT4, | ||
| 330 | IMAGE_REL_SH3_DIRECT4_WORD, | ||
| 331 | IMAGE_REL_SH3_DIRECT4_LONG, | ||
| 332 | IMAGE_REL_SH3_PCREL8_WORD, | ||
| 333 | IMAGE_REL_SH3_PCREL8_LONG, | ||
| 334 | IMAGE_REL_SH3_PCREL12_WORD, | ||
| 335 | IMAGE_REL_SH3_STARTOF_SECTION, | ||
| 336 | IMAGE_REL_SH3_SIZEOF_SECTION, | ||
| 337 | IMAGE_REL_SH3_SECTION, | ||
| 338 | IMAGE_REL_SH3_SECREL, | ||
| 339 | IMAGE_REL_SH3_DIRECT32_NB, | ||
| 340 | IMAGE_REL_SH3_GPREL4_LONG, | ||
| 341 | IMAGE_REL_SH3_TOKEN, | ||
| 342 | IMAGE_REL_SHM_PCRELPT, | ||
| 343 | IMAGE_REL_SHM_REFLO, | ||
| 344 | IMAGE_REL_SHM_REFHALF, | ||
| 345 | IMAGE_REL_SHM_RELLO, | ||
| 346 | IMAGE_REL_SHM_RELHALF, | ||
| 347 | IMAGE_REL_SHM_PAIR, | ||
| 348 | IMAGE_REL_SHM_NOMODE, | ||
| 349 | }; | ||
| 350 | |||
| 351 | enum ppc_coff_reloc_type { | ||
| 352 | IMAGE_REL_PPC_ABSOLUTE, | ||
| 353 | IMAGE_REL_PPC_ADDR64, | ||
| 354 | IMAGE_REL_PPC_ADDR32, | ||
| 355 | IMAGE_REL_PPC_ADDR24, | ||
| 356 | IMAGE_REL_PPC_ADDR16, | ||
| 357 | IMAGE_REL_PPC_ADDR14, | ||
| 358 | IMAGE_REL_PPC_REL24, | ||
| 359 | IMAGE_REL_PPC_REL14, | ||
| 360 | IMAGE_REL_PPC_ADDR32N, | ||
| 361 | IMAGE_REL_PPC_SECREL, | ||
| 362 | IMAGE_REL_PPC_SECTION, | ||
| 363 | IMAGE_REL_PPC_SECREL16, | ||
| 364 | IMAGE_REL_PPC_REFHI, | ||
| 365 | IMAGE_REL_PPC_REFLO, | ||
| 366 | IMAGE_REL_PPC_PAIR, | ||
| 367 | IMAGE_REL_PPC_SECRELLO, | ||
| 368 | IMAGE_REL_PPC_GPREL, | ||
| 369 | IMAGE_REL_PPC_TOKEN, | ||
| 370 | }; | ||
| 371 | |||
| 372 | enum x86_coff_reloc_type { | ||
| 373 | IMAGE_REL_I386_ABSOLUTE, | ||
| 374 | IMAGE_REL_I386_DIR16, | ||
| 375 | IMAGE_REL_I386_REL16, | ||
| 376 | IMAGE_REL_I386_DIR32, | ||
| 377 | IMAGE_REL_I386_DIR32NB, | ||
| 378 | IMAGE_REL_I386_SEG12, | ||
| 379 | IMAGE_REL_I386_SECTION, | ||
| 380 | IMAGE_REL_I386_SECREL, | ||
| 381 | IMAGE_REL_I386_TOKEN, | ||
| 382 | IMAGE_REL_I386_SECREL7, | ||
| 383 | IMAGE_REL_I386_REL32, | ||
| 384 | }; | ||
| 385 | |||
| 386 | enum ia64_coff_reloc_type { | ||
| 387 | IMAGE_REL_IA64_ABSOLUTE, | ||
| 388 | IMAGE_REL_IA64_IMM14, | ||
| 389 | IMAGE_REL_IA64_IMM22, | ||
| 390 | IMAGE_REL_IA64_IMM64, | ||
| 391 | IMAGE_REL_IA64_DIR32, | ||
| 392 | IMAGE_REL_IA64_DIR64, | ||
| 393 | IMAGE_REL_IA64_PCREL21B, | ||
| 394 | IMAGE_REL_IA64_PCREL21M, | ||
| 395 | IMAGE_REL_IA64_PCREL21F, | ||
| 396 | IMAGE_REL_IA64_GPREL22, | ||
| 397 | IMAGE_REL_IA64_LTOFF22, | ||
| 398 | IMAGE_REL_IA64_SECTION, | ||
| 399 | IMAGE_REL_IA64_SECREL22, | ||
| 400 | IMAGE_REL_IA64_SECREL64I, | ||
| 401 | IMAGE_REL_IA64_SECREL32, | ||
| 402 | IMAGE_REL_IA64_DIR32NB, | ||
| 403 | IMAGE_REL_IA64_SREL14, | ||
| 404 | IMAGE_REL_IA64_SREL22, | ||
| 405 | IMAGE_REL_IA64_SREL32, | ||
| 406 | IMAGE_REL_IA64_UREL32, | ||
| 407 | IMAGE_REL_IA64_PCREL60X, | ||
| 408 | IMAGE_REL_IA64_PCREL60B, | ||
| 409 | IMAGE_REL_IA64_PCREL60F, | ||
| 410 | IMAGE_REL_IA64_PCREL60I, | ||
| 411 | IMAGE_REL_IA64_PCREL60M, | ||
| 412 | IMAGE_REL_IA64_IMMGPREL6, | ||
| 413 | IMAGE_REL_IA64_TOKEN, | ||
| 414 | IMAGE_REL_IA64_GPREL32, | ||
| 415 | IMAGE_REL_IA64_ADDEND, | ||
| 416 | }; | ||
| 417 | |||
| 418 | struct coff_reloc { | ||
| 419 | uint32_t virtual_address; | ||
| 420 | uint32_t symbol_table_index; | ||
| 421 | union { | ||
| 422 | enum x64_coff_reloc_type x64_type; | ||
| 423 | enum arm_coff_reloc_type arm_type; | ||
| 424 | enum sh_coff_reloc_type sh_type; | ||
| 425 | enum ppc_coff_reloc_type ppc_type; | ||
| 426 | enum x86_coff_reloc_type x86_type; | ||
| 427 | enum ia64_coff_reloc_type ia64_type; | ||
| 428 | uint16_t data; | ||
| 429 | }; | ||
| 430 | }; | ||
| 431 | |||
| 432 | /* | ||
| 433 | * Definitions for the contents of the certs data block | ||
| 434 | */ | ||
| 435 | #define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002 | ||
| 436 | #define WIN_CERT_TYPE_EFI_OKCS115 0x0EF0 | ||
| 437 | #define WIN_CERT_TYPE_EFI_GUID 0x0EF1 | ||
| 438 | |||
| 439 | #define WIN_CERT_REVISION_1_0 0x0100 | ||
| 440 | #define WIN_CERT_REVISION_2_0 0x0200 | ||
| 441 | |||
| 442 | struct win_certificate { | ||
| 443 | uint32_t length; | ||
| 444 | uint16_t revision; | ||
| 445 | uint16_t cert_type; | ||
| 446 | }; | ||
| 447 | |||
| 448 | #endif /* __LINUX_PE_H */ | ||
diff --git a/include/linux/verify_pefile.h b/include/linux/verify_pefile.h new file mode 100644 index 000000000000..ac34819214f9 --- /dev/null +++ b/include/linux/verify_pefile.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | /* Signed PE file verification | ||
| 2 | * | ||
| 3 | * Copyright (C) 2014 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 | #ifndef _LINUX_VERIFY_PEFILE_H | ||
| 13 | #define _LINUX_VERIFY_PEFILE_H | ||
| 14 | |||
| 15 | extern int verify_pefile_signature(const void *pebuf, unsigned pelen, | ||
| 16 | struct key *trusted_keyring, bool *_trusted); | ||
| 17 | |||
| 18 | #endif /* _LINUX_VERIFY_PEFILE_H */ | ||
diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c index 52ebc70263f4..875f64e8935b 100644 --- a/kernel/system_keyring.c +++ b/kernel/system_keyring.c | |||
| @@ -89,6 +89,7 @@ static __init int load_system_certificate_list(void) | |||
| 89 | pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", | 89 | pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", |
| 90 | PTR_ERR(key)); | 90 | PTR_ERR(key)); |
| 91 | } else { | 91 | } else { |
| 92 | set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags); | ||
| 92 | pr_notice("Loaded X.509 cert '%s'\n", | 93 | pr_notice("Loaded X.509 cert '%s'\n", |
| 93 | key_ref_to_ptr(key)->description); | 94 | key_ref_to_ptr(key)->description); |
| 94 | key_ref_put(key); | 95 | key_ref_put(key); |
diff --git a/lib/Kconfig b/lib/Kconfig index 334f7722a999..a8a775730c09 100644 --- a/lib/Kconfig +++ b/lib/Kconfig | |||
| @@ -451,7 +451,8 @@ config MPILIB | |||
| 451 | 451 | ||
| 452 | config SIGNATURE | 452 | config SIGNATURE |
| 453 | tristate | 453 | tristate |
| 454 | depends on KEYS && CRYPTO | 454 | depends on KEYS |
| 455 | select CRYPTO | ||
| 455 | select CRYPTO_SHA1 | 456 | select CRYPTO_SHA1 |
| 456 | select MPILIB | 457 | select MPILIB |
| 457 | help | 458 | help |
diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c index 6e7a236525b6..ffeba8f9dda9 100644 --- a/net/ceph/crypto.c +++ b/net/ceph/crypto.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <linux/key-type.h> | 8 | #include <linux/key-type.h> |
| 9 | 9 | ||
| 10 | #include <keys/ceph-type.h> | 10 | #include <keys/ceph-type.h> |
| 11 | #include <keys/user-type.h> | ||
| 11 | #include <linux/ceph/decode.h> | 12 | #include <linux/ceph/decode.h> |
| 12 | #include "crypto.h" | 13 | #include "crypto.h" |
| 13 | 14 | ||
| @@ -423,8 +424,7 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, | |||
| 423 | } | 424 | } |
| 424 | } | 425 | } |
| 425 | 426 | ||
| 426 | static int ceph_key_instantiate(struct key *key, | 427 | static int ceph_key_preparse(struct key_preparsed_payload *prep) |
| 427 | struct key_preparsed_payload *prep) | ||
| 428 | { | 428 | { |
| 429 | struct ceph_crypto_key *ckey; | 429 | struct ceph_crypto_key *ckey; |
| 430 | size_t datalen = prep->datalen; | 430 | size_t datalen = prep->datalen; |
| @@ -435,10 +435,6 @@ static int ceph_key_instantiate(struct key *key, | |||
| 435 | if (datalen <= 0 || datalen > 32767 || !prep->data) | 435 | if (datalen <= 0 || datalen > 32767 || !prep->data) |
| 436 | goto err; | 436 | goto err; |
| 437 | 437 | ||
| 438 | ret = key_payload_reserve(key, datalen); | ||
| 439 | if (ret < 0) | ||
| 440 | goto err; | ||
| 441 | |||
| 442 | ret = -ENOMEM; | 438 | ret = -ENOMEM; |
| 443 | ckey = kmalloc(sizeof(*ckey), GFP_KERNEL); | 439 | ckey = kmalloc(sizeof(*ckey), GFP_KERNEL); |
| 444 | if (!ckey) | 440 | if (!ckey) |
| @@ -450,7 +446,8 @@ static int ceph_key_instantiate(struct key *key, | |||
| 450 | if (ret < 0) | 446 | if (ret < 0) |
| 451 | goto err_ckey; | 447 | goto err_ckey; |
| 452 | 448 | ||
| 453 | key->payload.data = ckey; | 449 | prep->payload[0] = ckey; |
| 450 | prep->quotalen = datalen; | ||
| 454 | return 0; | 451 | return 0; |
| 455 | 452 | ||
| 456 | err_ckey: | 453 | err_ckey: |
| @@ -459,12 +456,15 @@ err: | |||
| 459 | return ret; | 456 | return ret; |
| 460 | } | 457 | } |
| 461 | 458 | ||
| 462 | static int ceph_key_match(const struct key *key, const void *description) | 459 | static void ceph_key_free_preparse(struct key_preparsed_payload *prep) |
| 463 | { | 460 | { |
| 464 | return strcmp(key->description, description) == 0; | 461 | struct ceph_crypto_key *ckey = prep->payload[0]; |
| 462 | ceph_crypto_key_destroy(ckey); | ||
| 463 | kfree(ckey); | ||
| 465 | } | 464 | } |
| 466 | 465 | ||
| 467 | static void ceph_key_destroy(struct key *key) { | 466 | static void ceph_key_destroy(struct key *key) |
| 467 | { | ||
| 468 | struct ceph_crypto_key *ckey = key->payload.data; | 468 | struct ceph_crypto_key *ckey = key->payload.data; |
| 469 | 469 | ||
| 470 | ceph_crypto_key_destroy(ckey); | 470 | ceph_crypto_key_destroy(ckey); |
| @@ -473,8 +473,10 @@ static void ceph_key_destroy(struct key *key) { | |||
| 473 | 473 | ||
| 474 | struct key_type key_type_ceph = { | 474 | struct key_type key_type_ceph = { |
| 475 | .name = "ceph", | 475 | .name = "ceph", |
| 476 | .instantiate = ceph_key_instantiate, | 476 | .preparse = ceph_key_preparse, |
| 477 | .match = ceph_key_match, | 477 | .free_preparse = ceph_key_free_preparse, |
| 478 | .instantiate = generic_key_instantiate, | ||
| 479 | .match = user_match, | ||
| 478 | .destroy = ceph_key_destroy, | 480 | .destroy = ceph_key_destroy, |
| 479 | }; | 481 | }; |
| 480 | 482 | ||
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index bf8584339048..f380b2c58178 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c | |||
| @@ -46,7 +46,7 @@ const struct cred *dns_resolver_cache; | |||
| 46 | #define DNS_ERRORNO_OPTION "dnserror" | 46 | #define DNS_ERRORNO_OPTION "dnserror" |
| 47 | 47 | ||
| 48 | /* | 48 | /* |
| 49 | * Instantiate a user defined key for dns_resolver. | 49 | * Preparse instantiation data for a dns_resolver key. |
| 50 | * | 50 | * |
| 51 | * The data must be a NUL-terminated string, with the NUL char accounted in | 51 | * The data must be a NUL-terminated string, with the NUL char accounted in |
| 52 | * datalen. | 52 | * datalen. |
| @@ -58,17 +58,15 @@ const struct cred *dns_resolver_cache; | |||
| 58 | * "ip1,ip2,...#foo=bar" | 58 | * "ip1,ip2,...#foo=bar" |
| 59 | */ | 59 | */ |
| 60 | static int | 60 | static int |
| 61 | dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | 61 | dns_resolver_preparse(struct key_preparsed_payload *prep) |
| 62 | { | 62 | { |
| 63 | struct user_key_payload *upayload; | 63 | struct user_key_payload *upayload; |
| 64 | unsigned long derrno; | 64 | unsigned long derrno; |
| 65 | int ret; | 65 | int ret; |
| 66 | size_t datalen = prep->datalen, result_len = 0; | 66 | int datalen = prep->datalen, result_len = 0; |
| 67 | const char *data = prep->data, *end, *opt; | 67 | const char *data = prep->data, *end, *opt; |
| 68 | 68 | ||
| 69 | kenter("%%%d,%s,'%*.*s',%zu", | 69 | kenter("'%*.*s',%u", datalen, datalen, data, datalen); |
| 70 | key->serial, key->description, | ||
| 71 | (int)datalen, (int)datalen, data, datalen); | ||
| 72 | 70 | ||
| 73 | if (datalen <= 1 || !data || data[datalen - 1] != '\0') | 71 | if (datalen <= 1 || !data || data[datalen - 1] != '\0') |
| 74 | return -EINVAL; | 72 | return -EINVAL; |
| @@ -95,8 +93,7 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
| 95 | opt_len = next_opt - opt; | 93 | opt_len = next_opt - opt; |
| 96 | if (!opt_len) { | 94 | if (!opt_len) { |
| 97 | printk(KERN_WARNING | 95 | printk(KERN_WARNING |
| 98 | "Empty option to dns_resolver key %d\n", | 96 | "Empty option to dns_resolver key\n"); |
| 99 | key->serial); | ||
| 100 | return -EINVAL; | 97 | return -EINVAL; |
| 101 | } | 98 | } |
| 102 | 99 | ||
| @@ -125,30 +122,28 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
| 125 | goto bad_option_value; | 122 | goto bad_option_value; |
| 126 | 123 | ||
| 127 | kdebug("dns error no. = %lu", derrno); | 124 | kdebug("dns error no. = %lu", derrno); |
| 128 | key->type_data.x[0] = -derrno; | 125 | prep->type_data[0] = ERR_PTR(-derrno); |
| 129 | continue; | 126 | continue; |
| 130 | } | 127 | } |
| 131 | 128 | ||
| 132 | bad_option_value: | 129 | bad_option_value: |
| 133 | printk(KERN_WARNING | 130 | printk(KERN_WARNING |
| 134 | "Option '%*.*s' to dns_resolver key %d:" | 131 | "Option '%*.*s' to dns_resolver key:" |
| 135 | " bad/missing value\n", | 132 | " bad/missing value\n", |
| 136 | opt_nlen, opt_nlen, opt, key->serial); | 133 | opt_nlen, opt_nlen, opt); |
| 137 | return -EINVAL; | 134 | return -EINVAL; |
| 138 | } while (opt = next_opt + 1, opt < end); | 135 | } while (opt = next_opt + 1, opt < end); |
| 139 | } | 136 | } |
| 140 | 137 | ||
| 141 | /* don't cache the result if we're caching an error saying there's no | 138 | /* don't cache the result if we're caching an error saying there's no |
| 142 | * result */ | 139 | * result */ |
| 143 | if (key->type_data.x[0]) { | 140 | if (prep->type_data[0]) { |
| 144 | kleave(" = 0 [h_error %ld]", key->type_data.x[0]); | 141 | kleave(" = 0 [h_error %ld]", PTR_ERR(prep->type_data[0])); |
| 145 | return 0; | 142 | return 0; |
| 146 | } | 143 | } |
| 147 | 144 | ||
| 148 | kdebug("store result"); | 145 | kdebug("store result"); |
| 149 | ret = key_payload_reserve(key, result_len); | 146 | prep->quotalen = result_len; |
| 150 | if (ret < 0) | ||
| 151 | return -EINVAL; | ||
| 152 | 147 | ||
| 153 | upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL); | 148 | upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL); |
| 154 | if (!upayload) { | 149 | if (!upayload) { |
| @@ -159,13 +154,23 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
| 159 | upayload->datalen = result_len; | 154 | upayload->datalen = result_len; |
| 160 | memcpy(upayload->data, data, result_len); | 155 | memcpy(upayload->data, data, result_len); |
| 161 | upayload->data[result_len] = '\0'; | 156 | upayload->data[result_len] = '\0'; |
| 162 | rcu_assign_pointer(key->payload.data, upayload); | ||
| 163 | 157 | ||
| 158 | prep->payload[0] = upayload; | ||
| 164 | kleave(" = 0"); | 159 | kleave(" = 0"); |
| 165 | return 0; | 160 | return 0; |
| 166 | } | 161 | } |
| 167 | 162 | ||
| 168 | /* | 163 | /* |
| 164 | * Clean up the preparse data | ||
| 165 | */ | ||
| 166 | static void dns_resolver_free_preparse(struct key_preparsed_payload *prep) | ||
| 167 | { | ||
| 168 | pr_devel("==>%s()\n", __func__); | ||
| 169 | |||
| 170 | kfree(prep->payload[0]); | ||
| 171 | } | ||
| 172 | |||
| 173 | /* | ||
| 169 | * The description is of the form "[<type>:]<domain_name>" | 174 | * The description is of the form "[<type>:]<domain_name>" |
| 170 | * | 175 | * |
| 171 | * The domain name may be a simple name or an absolute domain name (which | 176 | * The domain name may be a simple name or an absolute domain name (which |
| @@ -234,7 +239,9 @@ static long dns_resolver_read(const struct key *key, | |||
| 234 | 239 | ||
| 235 | struct key_type key_type_dns_resolver = { | 240 | struct key_type key_type_dns_resolver = { |
| 236 | .name = "dns_resolver", | 241 | .name = "dns_resolver", |
| 237 | .instantiate = dns_resolver_instantiate, | 242 | .preparse = dns_resolver_preparse, |
| 243 | .free_preparse = dns_resolver_free_preparse, | ||
| 244 | .instantiate = generic_key_instantiate, | ||
| 238 | .match = dns_resolver_match, | 245 | .match = dns_resolver_match, |
| 239 | .revoke = user_revoke, | 246 | .revoke = user_revoke, |
| 240 | .destroy = user_destroy, | 247 | .destroy = user_destroy, |
diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c index 9acec61f5433..9a32f55cf9b9 100644 --- a/net/dns_resolver/dns_query.c +++ b/net/dns_resolver/dns_query.c | |||
| @@ -129,6 +129,7 @@ int dns_query(const char *type, const char *name, size_t namelen, | |||
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | down_read(&rkey->sem); | 131 | down_read(&rkey->sem); |
| 132 | set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags); | ||
| 132 | rkey->perm |= KEY_USR_VIEW; | 133 | rkey->perm |= KEY_USR_VIEW; |
| 133 | 134 | ||
| 134 | ret = key_validate(rkey); | 135 | ret = key_validate(rkey); |
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c index 0ad080790a32..3907add75932 100644 --- a/net/rxrpc/ar-key.c +++ b/net/rxrpc/ar-key.c | |||
| @@ -26,8 +26,10 @@ | |||
| 26 | #include "ar-internal.h" | 26 | #include "ar-internal.h" |
| 27 | 27 | ||
| 28 | static int rxrpc_vet_description_s(const char *); | 28 | static int rxrpc_vet_description_s(const char *); |
| 29 | static int rxrpc_instantiate(struct key *, struct key_preparsed_payload *); | 29 | static int rxrpc_preparse(struct key_preparsed_payload *); |
| 30 | static int rxrpc_instantiate_s(struct key *, struct key_preparsed_payload *); | 30 | static int rxrpc_preparse_s(struct key_preparsed_payload *); |
| 31 | static void rxrpc_free_preparse(struct key_preparsed_payload *); | ||
| 32 | static void rxrpc_free_preparse_s(struct key_preparsed_payload *); | ||
| 31 | static void rxrpc_destroy(struct key *); | 33 | static void rxrpc_destroy(struct key *); |
| 32 | static void rxrpc_destroy_s(struct key *); | 34 | static void rxrpc_destroy_s(struct key *); |
| 33 | static void rxrpc_describe(const struct key *, struct seq_file *); | 35 | static void rxrpc_describe(const struct key *, struct seq_file *); |
| @@ -39,7 +41,9 @@ static long rxrpc_read(const struct key *, char __user *, size_t); | |||
| 39 | */ | 41 | */ |
| 40 | struct key_type key_type_rxrpc = { | 42 | struct key_type key_type_rxrpc = { |
| 41 | .name = "rxrpc", | 43 | .name = "rxrpc", |
| 42 | .instantiate = rxrpc_instantiate, | 44 | .preparse = rxrpc_preparse, |
| 45 | .free_preparse = rxrpc_free_preparse, | ||
| 46 | .instantiate = generic_key_instantiate, | ||
| 43 | .match = user_match, | 47 | .match = user_match, |
| 44 | .destroy = rxrpc_destroy, | 48 | .destroy = rxrpc_destroy, |
| 45 | .describe = rxrpc_describe, | 49 | .describe = rxrpc_describe, |
| @@ -54,7 +58,9 @@ EXPORT_SYMBOL(key_type_rxrpc); | |||
| 54 | struct key_type key_type_rxrpc_s = { | 58 | struct key_type key_type_rxrpc_s = { |
| 55 | .name = "rxrpc_s", | 59 | .name = "rxrpc_s", |
| 56 | .vet_description = rxrpc_vet_description_s, | 60 | .vet_description = rxrpc_vet_description_s, |
| 57 | .instantiate = rxrpc_instantiate_s, | 61 | .preparse = rxrpc_preparse_s, |
| 62 | .free_preparse = rxrpc_free_preparse_s, | ||
| 63 | .instantiate = generic_key_instantiate, | ||
| 58 | .match = user_match, | 64 | .match = user_match, |
| 59 | .destroy = rxrpc_destroy_s, | 65 | .destroy = rxrpc_destroy_s, |
| 60 | .describe = rxrpc_describe, | 66 | .describe = rxrpc_describe, |
| @@ -81,13 +87,13 @@ static int rxrpc_vet_description_s(const char *desc) | |||
| 81 | * parse an RxKAD type XDR format token | 87 | * parse an RxKAD type XDR format token |
| 82 | * - the caller guarantees we have at least 4 words | 88 | * - the caller guarantees we have at least 4 words |
| 83 | */ | 89 | */ |
| 84 | static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, | 90 | static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep, |
| 85 | unsigned int toklen) | 91 | size_t datalen, |
| 92 | const __be32 *xdr, unsigned int toklen) | ||
| 86 | { | 93 | { |
| 87 | struct rxrpc_key_token *token, **pptoken; | 94 | struct rxrpc_key_token *token, **pptoken; |
| 88 | size_t plen; | 95 | size_t plen; |
| 89 | u32 tktlen; | 96 | u32 tktlen; |
| 90 | int ret; | ||
| 91 | 97 | ||
| 92 | _enter(",{%x,%x,%x,%x},%u", | 98 | _enter(",{%x,%x,%x,%x},%u", |
| 93 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), | 99 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), |
| @@ -103,9 +109,7 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, | |||
| 103 | return -EKEYREJECTED; | 109 | return -EKEYREJECTED; |
| 104 | 110 | ||
| 105 | plen = sizeof(*token) + sizeof(*token->kad) + tktlen; | 111 | plen = sizeof(*token) + sizeof(*token->kad) + tktlen; |
| 106 | ret = key_payload_reserve(key, key->datalen + plen); | 112 | prep->quotalen = datalen + plen; |
| 107 | if (ret < 0) | ||
| 108 | return ret; | ||
| 109 | 113 | ||
| 110 | plen -= sizeof(*token); | 114 | plen -= sizeof(*token); |
| 111 | token = kzalloc(sizeof(*token), GFP_KERNEL); | 115 | token = kzalloc(sizeof(*token), GFP_KERNEL); |
| @@ -146,16 +150,16 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, | |||
| 146 | token->kad->ticket[6], token->kad->ticket[7]); | 150 | token->kad->ticket[6], token->kad->ticket[7]); |
| 147 | 151 | ||
| 148 | /* count the number of tokens attached */ | 152 | /* count the number of tokens attached */ |
| 149 | key->type_data.x[0]++; | 153 | prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1); |
| 150 | 154 | ||
| 151 | /* attach the data */ | 155 | /* attach the data */ |
| 152 | for (pptoken = (struct rxrpc_key_token **)&key->payload.data; | 156 | for (pptoken = (struct rxrpc_key_token **)&prep->payload[0]; |
| 153 | *pptoken; | 157 | *pptoken; |
| 154 | pptoken = &(*pptoken)->next) | 158 | pptoken = &(*pptoken)->next) |
| 155 | continue; | 159 | continue; |
| 156 | *pptoken = token; | 160 | *pptoken = token; |
| 157 | if (token->kad->expiry < key->expiry) | 161 | if (token->kad->expiry < prep->expiry) |
| 158 | key->expiry = token->kad->expiry; | 162 | prep->expiry = token->kad->expiry; |
| 159 | 163 | ||
| 160 | _leave(" = 0"); | 164 | _leave(" = 0"); |
| 161 | return 0; | 165 | return 0; |
| @@ -418,8 +422,9 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen, | |||
| 418 | * parse an RxK5 type XDR format token | 422 | * parse an RxK5 type XDR format token |
| 419 | * - the caller guarantees we have at least 4 words | 423 | * - the caller guarantees we have at least 4 words |
| 420 | */ | 424 | */ |
| 421 | static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, | 425 | static int rxrpc_preparse_xdr_rxk5(struct key_preparsed_payload *prep, |
| 422 | unsigned int toklen) | 426 | size_t datalen, |
| 427 | const __be32 *xdr, unsigned int toklen) | ||
| 423 | { | 428 | { |
| 424 | struct rxrpc_key_token *token, **pptoken; | 429 | struct rxrpc_key_token *token, **pptoken; |
| 425 | struct rxk5_key *rxk5; | 430 | struct rxk5_key *rxk5; |
| @@ -432,9 +437,7 @@ static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, | |||
| 432 | 437 | ||
| 433 | /* reserve some payload space for this subkey - the length of the token | 438 | /* reserve some payload space for this subkey - the length of the token |
| 434 | * is a reasonable approximation */ | 439 | * is a reasonable approximation */ |
| 435 | ret = key_payload_reserve(key, key->datalen + toklen); | 440 | prep->quotalen = datalen + toklen; |
| 436 | if (ret < 0) | ||
| 437 | return ret; | ||
| 438 | 441 | ||
| 439 | token = kzalloc(sizeof(*token), GFP_KERNEL); | 442 | token = kzalloc(sizeof(*token), GFP_KERNEL); |
| 440 | if (!token) | 443 | if (!token) |
| @@ -520,14 +523,14 @@ static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, | |||
| 520 | if (toklen != 0) | 523 | if (toklen != 0) |
| 521 | goto inval; | 524 | goto inval; |
| 522 | 525 | ||
| 523 | /* attach the payload to the key */ | 526 | /* attach the payload */ |
| 524 | for (pptoken = (struct rxrpc_key_token **)&key->payload.data; | 527 | for (pptoken = (struct rxrpc_key_token **)&prep->payload[0]; |
| 525 | *pptoken; | 528 | *pptoken; |
| 526 | pptoken = &(*pptoken)->next) | 529 | pptoken = &(*pptoken)->next) |
| 527 | continue; | 530 | continue; |
| 528 | *pptoken = token; | 531 | *pptoken = token; |
| 529 | if (token->kad->expiry < key->expiry) | 532 | if (token->kad->expiry < prep->expiry) |
| 530 | key->expiry = token->kad->expiry; | 533 | prep->expiry = token->kad->expiry; |
| 531 | 534 | ||
| 532 | _leave(" = 0"); | 535 | _leave(" = 0"); |
| 533 | return 0; | 536 | return 0; |
| @@ -545,16 +548,17 @@ error: | |||
| 545 | * attempt to parse the data as the XDR format | 548 | * attempt to parse the data as the XDR format |
| 546 | * - the caller guarantees we have more than 7 words | 549 | * - the caller guarantees we have more than 7 words |
| 547 | */ | 550 | */ |
| 548 | static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datalen) | 551 | static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep) |
| 549 | { | 552 | { |
| 550 | const __be32 *xdr = data, *token; | 553 | const __be32 *xdr = prep->data, *token; |
| 551 | const char *cp; | 554 | const char *cp; |
| 552 | unsigned int len, tmp, loop, ntoken, toklen, sec_ix; | 555 | unsigned int len, tmp, loop, ntoken, toklen, sec_ix; |
| 556 | size_t datalen = prep->datalen; | ||
| 553 | int ret; | 557 | int ret; |
| 554 | 558 | ||
| 555 | _enter(",{%x,%x,%x,%x},%zu", | 559 | _enter(",{%x,%x,%x,%x},%zu", |
| 556 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), | 560 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), |
| 557 | datalen); | 561 | prep->datalen); |
| 558 | 562 | ||
| 559 | if (datalen > AFSTOKEN_LENGTH_MAX) | 563 | if (datalen > AFSTOKEN_LENGTH_MAX) |
| 560 | goto not_xdr; | 564 | goto not_xdr; |
| @@ -635,13 +639,13 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal | |||
| 635 | 639 | ||
| 636 | switch (sec_ix) { | 640 | switch (sec_ix) { |
| 637 | case RXRPC_SECURITY_RXKAD: | 641 | case RXRPC_SECURITY_RXKAD: |
| 638 | ret = rxrpc_instantiate_xdr_rxkad(key, xdr, toklen); | 642 | ret = rxrpc_preparse_xdr_rxkad(prep, datalen, xdr, toklen); |
| 639 | if (ret != 0) | 643 | if (ret != 0) |
| 640 | goto error; | 644 | goto error; |
| 641 | break; | 645 | break; |
| 642 | 646 | ||
| 643 | case RXRPC_SECURITY_RXK5: | 647 | case RXRPC_SECURITY_RXK5: |
| 644 | ret = rxrpc_instantiate_xdr_rxk5(key, xdr, toklen); | 648 | ret = rxrpc_preparse_xdr_rxk5(prep, datalen, xdr, toklen); |
| 645 | if (ret != 0) | 649 | if (ret != 0) |
| 646 | goto error; | 650 | goto error; |
| 647 | break; | 651 | break; |
| @@ -665,8 +669,9 @@ error: | |||
| 665 | } | 669 | } |
| 666 | 670 | ||
| 667 | /* | 671 | /* |
| 668 | * instantiate an rxrpc defined key | 672 | * Preparse an rxrpc defined key. |
| 669 | * data should be of the form: | 673 | * |
| 674 | * Data should be of the form: | ||
| 670 | * OFFSET LEN CONTENT | 675 | * OFFSET LEN CONTENT |
| 671 | * 0 4 key interface version number | 676 | * 0 4 key interface version number |
| 672 | * 4 2 security index (type) | 677 | * 4 2 security index (type) |
| @@ -678,7 +683,7 @@ error: | |||
| 678 | * | 683 | * |
| 679 | * if no data is provided, then a no-security key is made | 684 | * if no data is provided, then a no-security key is made |
| 680 | */ | 685 | */ |
| 681 | static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep) | 686 | static int rxrpc_preparse(struct key_preparsed_payload *prep) |
| 682 | { | 687 | { |
| 683 | const struct rxrpc_key_data_v1 *v1; | 688 | const struct rxrpc_key_data_v1 *v1; |
| 684 | struct rxrpc_key_token *token, **pp; | 689 | struct rxrpc_key_token *token, **pp; |
| @@ -686,7 +691,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
| 686 | u32 kver; | 691 | u32 kver; |
| 687 | int ret; | 692 | int ret; |
| 688 | 693 | ||
| 689 | _enter("{%x},,%zu", key_serial(key), prep->datalen); | 694 | _enter("%zu", prep->datalen); |
| 690 | 695 | ||
| 691 | /* handle a no-security key */ | 696 | /* handle a no-security key */ |
| 692 | if (!prep->data && prep->datalen == 0) | 697 | if (!prep->data && prep->datalen == 0) |
| @@ -694,7 +699,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
| 694 | 699 | ||
| 695 | /* determine if the XDR payload format is being used */ | 700 | /* determine if the XDR payload format is being used */ |
| 696 | if (prep->datalen > 7 * 4) { | 701 | if (prep->datalen > 7 * 4) { |
| 697 | ret = rxrpc_instantiate_xdr(key, prep->data, prep->datalen); | 702 | ret = rxrpc_preparse_xdr(prep); |
| 698 | if (ret != -EPROTO) | 703 | if (ret != -EPROTO) |
| 699 | return ret; | 704 | return ret; |
| 700 | } | 705 | } |
| @@ -743,9 +748,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
| 743 | goto error; | 748 | goto error; |
| 744 | 749 | ||
| 745 | plen = sizeof(*token->kad) + v1->ticket_length; | 750 | plen = sizeof(*token->kad) + v1->ticket_length; |
| 746 | ret = key_payload_reserve(key, plen + sizeof(*token)); | 751 | prep->quotalen = plen + sizeof(*token); |
| 747 | if (ret < 0) | ||
| 748 | goto error; | ||
| 749 | 752 | ||
| 750 | ret = -ENOMEM; | 753 | ret = -ENOMEM; |
| 751 | token = kzalloc(sizeof(*token), GFP_KERNEL); | 754 | token = kzalloc(sizeof(*token), GFP_KERNEL); |
| @@ -762,15 +765,16 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
| 762 | memcpy(&token->kad->session_key, &v1->session_key, 8); | 765 | memcpy(&token->kad->session_key, &v1->session_key, 8); |
| 763 | memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length); | 766 | memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length); |
| 764 | 767 | ||
| 765 | /* attach the data */ | 768 | /* count the number of tokens attached */ |
| 766 | key->type_data.x[0]++; | 769 | prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1); |
| 767 | 770 | ||
| 768 | pp = (struct rxrpc_key_token **)&key->payload.data; | 771 | /* attach the data */ |
| 772 | pp = (struct rxrpc_key_token **)&prep->payload[0]; | ||
| 769 | while (*pp) | 773 | while (*pp) |
| 770 | pp = &(*pp)->next; | 774 | pp = &(*pp)->next; |
| 771 | *pp = token; | 775 | *pp = token; |
| 772 | if (token->kad->expiry < key->expiry) | 776 | if (token->kad->expiry < prep->expiry) |
| 773 | key->expiry = token->kad->expiry; | 777 | prep->expiry = token->kad->expiry; |
| 774 | token = NULL; | 778 | token = NULL; |
| 775 | ret = 0; | 779 | ret = 0; |
| 776 | 780 | ||
| @@ -781,20 +785,55 @@ error: | |||
| 781 | } | 785 | } |
| 782 | 786 | ||
| 783 | /* | 787 | /* |
| 784 | * instantiate a server secret key | 788 | * Free token list. |
| 785 | * data should be a pointer to the 8-byte secret key | ||
| 786 | */ | 789 | */ |
| 787 | static int rxrpc_instantiate_s(struct key *key, | 790 | static void rxrpc_free_token_list(struct rxrpc_key_token *token) |
| 788 | struct key_preparsed_payload *prep) | 791 | { |
| 792 | struct rxrpc_key_token *next; | ||
| 793 | |||
| 794 | for (; token; token = next) { | ||
| 795 | next = token->next; | ||
| 796 | switch (token->security_index) { | ||
| 797 | case RXRPC_SECURITY_RXKAD: | ||
| 798 | kfree(token->kad); | ||
| 799 | break; | ||
| 800 | case RXRPC_SECURITY_RXK5: | ||
| 801 | if (token->k5) | ||
| 802 | rxrpc_rxk5_free(token->k5); | ||
| 803 | break; | ||
| 804 | default: | ||
| 805 | printk(KERN_ERR "Unknown token type %x on rxrpc key\n", | ||
| 806 | token->security_index); | ||
| 807 | BUG(); | ||
| 808 | } | ||
| 809 | |||
| 810 | kfree(token); | ||
| 811 | } | ||
| 812 | } | ||
| 813 | |||
| 814 | /* | ||
| 815 | * Clean up preparse data. | ||
| 816 | */ | ||
| 817 | static void rxrpc_free_preparse(struct key_preparsed_payload *prep) | ||
| 818 | { | ||
| 819 | rxrpc_free_token_list(prep->payload[0]); | ||
| 820 | } | ||
| 821 | |||
| 822 | /* | ||
| 823 | * Preparse a server secret key. | ||
| 824 | * | ||
| 825 | * The data should be the 8-byte secret key. | ||
| 826 | */ | ||
| 827 | static int rxrpc_preparse_s(struct key_preparsed_payload *prep) | ||
| 789 | { | 828 | { |
| 790 | struct crypto_blkcipher *ci; | 829 | struct crypto_blkcipher *ci; |
| 791 | 830 | ||
| 792 | _enter("{%x},,%zu", key_serial(key), prep->datalen); | 831 | _enter("%zu", prep->datalen); |
| 793 | 832 | ||
| 794 | if (prep->datalen != 8) | 833 | if (prep->datalen != 8) |
| 795 | return -EINVAL; | 834 | return -EINVAL; |
| 796 | 835 | ||
| 797 | memcpy(&key->type_data, prep->data, 8); | 836 | memcpy(&prep->type_data, prep->data, 8); |
| 798 | 837 | ||
| 799 | ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC); | 838 | ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC); |
| 800 | if (IS_ERR(ci)) { | 839 | if (IS_ERR(ci)) { |
| @@ -805,36 +844,26 @@ static int rxrpc_instantiate_s(struct key *key, | |||
| 805 | if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0) | 844 | if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0) |
| 806 | BUG(); | 845 | BUG(); |
| 807 | 846 | ||
| 808 | key->payload.data = ci; | 847 | prep->payload[0] = ci; |
| 809 | _leave(" = 0"); | 848 | _leave(" = 0"); |
| 810 | return 0; | 849 | return 0; |
| 811 | } | 850 | } |
| 812 | 851 | ||
| 813 | /* | 852 | /* |
| 853 | * Clean up preparse data. | ||
| 854 | */ | ||
| 855 | static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep) | ||
| 856 | { | ||
| 857 | if (prep->payload[0]) | ||
| 858 | crypto_free_blkcipher(prep->payload[0]); | ||
| 859 | } | ||
| 860 | |||
| 861 | /* | ||
| 814 | * dispose of the data dangling from the corpse of a rxrpc key | 862 | * dispose of the data dangling from the corpse of a rxrpc key |
| 815 | */ | 863 | */ |
| 816 | static void rxrpc_destroy(struct key *key) | 864 | static void rxrpc_destroy(struct key *key) |
| 817 | { | 865 | { |
| 818 | struct rxrpc_key_token *token; | 866 | rxrpc_free_token_list(key->payload.data); |
| 819 | |||
| 820 | while ((token = key->payload.data)) { | ||
| 821 | key->payload.data = token->next; | ||
| 822 | switch (token->security_index) { | ||
| 823 | case RXRPC_SECURITY_RXKAD: | ||
| 824 | kfree(token->kad); | ||
| 825 | break; | ||
| 826 | case RXRPC_SECURITY_RXK5: | ||
| 827 | if (token->k5) | ||
| 828 | rxrpc_rxk5_free(token->k5); | ||
| 829 | break; | ||
| 830 | default: | ||
| 831 | printk(KERN_ERR "Unknown token type %x on rxrpc key\n", | ||
| 832 | token->security_index); | ||
| 833 | BUG(); | ||
| 834 | } | ||
| 835 | |||
| 836 | kfree(token); | ||
| 837 | } | ||
| 838 | } | 867 | } |
| 839 | 868 | ||
| 840 | /* | 869 | /* |
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index b4af4ebc5be2..8d4fbff8b87c 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c | |||
| @@ -13,7 +13,9 @@ | |||
| 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 14 | 14 | ||
| 15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
| 16 | #include <linux/sched.h> | ||
| 16 | #include <linux/rbtree.h> | 17 | #include <linux/rbtree.h> |
| 18 | #include <linux/cred.h> | ||
| 17 | #include <linux/key-type.h> | 19 | #include <linux/key-type.h> |
| 18 | #include <linux/digsig.h> | 20 | #include <linux/digsig.h> |
| 19 | 21 | ||
| @@ -24,7 +26,11 @@ static struct key *keyring[INTEGRITY_KEYRING_MAX]; | |||
| 24 | static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { | 26 | static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { |
| 25 | "_evm", | 27 | "_evm", |
| 26 | "_module", | 28 | "_module", |
| 29 | #ifndef CONFIG_IMA_TRUSTED_KEYRING | ||
| 27 | "_ima", | 30 | "_ima", |
| 31 | #else | ||
| 32 | ".ima", | ||
| 33 | #endif | ||
| 28 | }; | 34 | }; |
| 29 | 35 | ||
| 30 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | 36 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, |
| @@ -56,3 +62,25 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | |||
| 56 | 62 | ||
| 57 | return -EOPNOTSUPP; | 63 | return -EOPNOTSUPP; |
| 58 | } | 64 | } |
| 65 | |||
| 66 | int integrity_init_keyring(const unsigned int id) | ||
| 67 | { | ||
| 68 | const struct cred *cred = current_cred(); | ||
| 69 | int err = 0; | ||
| 70 | |||
| 71 | keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0), | ||
| 72 | KGIDT_INIT(0), cred, | ||
| 73 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | ||
| 74 | KEY_USR_VIEW | KEY_USR_READ | | ||
| 75 | KEY_USR_WRITE | KEY_USR_SEARCH), | ||
| 76 | KEY_ALLOC_NOT_IN_QUOTA, NULL); | ||
| 77 | if (!IS_ERR(keyring[id])) | ||
| 78 | set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags); | ||
| 79 | else { | ||
| 80 | err = PTR_ERR(keyring[id]); | ||
| 81 | pr_info("Can't allocate %s keyring (%d)\n", | ||
| 82 | keyring_name[id], err); | ||
| 83 | keyring[id] = NULL; | ||
| 84 | } | ||
| 85 | return err; | ||
| 86 | } | ||
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 81a27971d884..08758fbd496f 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
| @@ -123,3 +123,13 @@ config IMA_APPRAISE | |||
| 123 | For more information on integrity appraisal refer to: | 123 | For more information on integrity appraisal refer to: |
| 124 | <http://linux-ima.sourceforge.net> | 124 | <http://linux-ima.sourceforge.net> |
| 125 | If unsure, say N. | 125 | If unsure, say N. |
| 126 | |||
| 127 | config IMA_TRUSTED_KEYRING | ||
| 128 | bool "Require all keys on the .ima keyring be signed" | ||
| 129 | depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING | ||
| 130 | depends on INTEGRITY_ASYMMETRIC_KEYS | ||
| 131 | select KEYS_DEBUG_PROC_KEYS | ||
| 132 | default y | ||
| 133 | help | ||
| 134 | This option requires that all keys added to the .ima | ||
| 135 | keyring be signed by a key on the system trusted keyring. | ||
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index f79fa8be203c..c42056edfc97 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
| @@ -249,4 +249,16 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op, | |||
| 249 | return -EINVAL; | 249 | return -EINVAL; |
| 250 | } | 250 | } |
| 251 | #endif /* CONFIG_IMA_LSM_RULES */ | 251 | #endif /* CONFIG_IMA_LSM_RULES */ |
| 252 | |||
| 253 | #ifdef CONFIG_IMA_TRUSTED_KEYRING | ||
| 254 | static inline int ima_init_keyring(const unsigned int id) | ||
| 255 | { | ||
| 256 | return integrity_init_keyring(id); | ||
| 257 | } | ||
| 258 | #else | ||
| 259 | static inline int ima_init_keyring(const unsigned int id) | ||
| 260 | { | ||
| 261 | return 0; | ||
| 262 | } | ||
| 263 | #endif /* CONFIG_IMA_TRUSTED_KEYRING */ | ||
| 252 | #endif | 264 | #endif |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index f474c608fa11..0d696431209c 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -325,8 +325,14 @@ static int __init init_ima(void) | |||
| 325 | 325 | ||
| 326 | hash_setup(CONFIG_IMA_DEFAULT_HASH); | 326 | hash_setup(CONFIG_IMA_DEFAULT_HASH); |
| 327 | error = ima_init(); | 327 | error = ima_init(); |
| 328 | if (!error) | 328 | if (error) |
| 329 | ima_initialized = 1; | 329 | goto out; |
| 330 | |||
| 331 | error = ima_init_keyring(INTEGRITY_KEYRING_IMA); | ||
| 332 | if (error) | ||
| 333 | goto out; | ||
| 334 | ima_initialized = 1; | ||
| 335 | out: | ||
| 330 | return error; | 336 | return error; |
| 331 | } | 337 | } |
| 332 | 338 | ||
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 33c0a70f6b15..09c440d9aaee 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
| @@ -124,6 +124,7 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode); | |||
| 124 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | 124 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, |
| 125 | const char *digest, int digestlen); | 125 | const char *digest, int digestlen); |
| 126 | 126 | ||
| 127 | int integrity_init_keyring(const unsigned int id); | ||
| 127 | #else | 128 | #else |
| 128 | 129 | ||
| 129 | static inline int integrity_digsig_verify(const unsigned int id, | 130 | static inline int integrity_digsig_verify(const unsigned int id, |
| @@ -133,6 +134,10 @@ static inline int integrity_digsig_verify(const unsigned int id, | |||
| 133 | return -EOPNOTSUPP; | 134 | return -EOPNOTSUPP; |
| 134 | } | 135 | } |
| 135 | 136 | ||
| 137 | static inline int integrity_init_keyring(const unsigned int id) | ||
| 138 | { | ||
| 139 | return 0; | ||
| 140 | } | ||
| 136 | #endif /* CONFIG_INTEGRITY_SIGNATURE */ | 141 | #endif /* CONFIG_INTEGRITY_SIGNATURE */ |
| 137 | 142 | ||
| 138 | #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS | 143 | #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS |
diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 8137b27d641d..c2f91a0cf889 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c | |||
| @@ -34,7 +34,9 @@ MODULE_LICENSE("GPL"); | |||
| 34 | struct key_type key_type_big_key = { | 34 | struct key_type key_type_big_key = { |
| 35 | .name = "big_key", | 35 | .name = "big_key", |
| 36 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 36 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
| 37 | .instantiate = big_key_instantiate, | 37 | .preparse = big_key_preparse, |
| 38 | .free_preparse = big_key_free_preparse, | ||
| 39 | .instantiate = generic_key_instantiate, | ||
| 38 | .match = user_match, | 40 | .match = user_match, |
| 39 | .revoke = big_key_revoke, | 41 | .revoke = big_key_revoke, |
| 40 | .destroy = big_key_destroy, | 42 | .destroy = big_key_destroy, |
| @@ -43,11 +45,11 @@ struct key_type key_type_big_key = { | |||
| 43 | }; | 45 | }; |
| 44 | 46 | ||
| 45 | /* | 47 | /* |
| 46 | * Instantiate a big key | 48 | * Preparse a big key |
| 47 | */ | 49 | */ |
| 48 | int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | 50 | int big_key_preparse(struct key_preparsed_payload *prep) |
| 49 | { | 51 | { |
| 50 | struct path *path = (struct path *)&key->payload.data2; | 52 | struct path *path = (struct path *)&prep->payload; |
| 51 | struct file *file; | 53 | struct file *file; |
| 52 | ssize_t written; | 54 | ssize_t written; |
| 53 | size_t datalen = prep->datalen; | 55 | size_t datalen = prep->datalen; |
| @@ -58,11 +60,9 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
| 58 | goto error; | 60 | goto error; |
| 59 | 61 | ||
| 60 | /* Set an arbitrary quota */ | 62 | /* Set an arbitrary quota */ |
| 61 | ret = key_payload_reserve(key, 16); | 63 | prep->quotalen = 16; |
| 62 | if (ret < 0) | ||
| 63 | goto error; | ||
| 64 | 64 | ||
| 65 | key->type_data.x[1] = datalen; | 65 | prep->type_data[1] = (void *)(unsigned long)datalen; |
| 66 | 66 | ||
| 67 | if (datalen > BIG_KEY_FILE_THRESHOLD) { | 67 | if (datalen > BIG_KEY_FILE_THRESHOLD) { |
| 68 | /* Create a shmem file to store the data in. This will permit the data | 68 | /* Create a shmem file to store the data in. This will permit the data |
| @@ -73,7 +73,7 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
| 73 | file = shmem_kernel_file_setup("", datalen, 0); | 73 | file = shmem_kernel_file_setup("", datalen, 0); |
| 74 | if (IS_ERR(file)) { | 74 | if (IS_ERR(file)) { |
| 75 | ret = PTR_ERR(file); | 75 | ret = PTR_ERR(file); |
| 76 | goto err_quota; | 76 | goto error; |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | written = kernel_write(file, prep->data, prep->datalen, 0); | 79 | written = kernel_write(file, prep->data, prep->datalen, 0); |
| @@ -93,24 +93,33 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
| 93 | } else { | 93 | } else { |
| 94 | /* Just store the data in a buffer */ | 94 | /* Just store the data in a buffer */ |
| 95 | void *data = kmalloc(datalen, GFP_KERNEL); | 95 | void *data = kmalloc(datalen, GFP_KERNEL); |
| 96 | if (!data) { | 96 | if (!data) |
| 97 | ret = -ENOMEM; | 97 | return -ENOMEM; |
| 98 | goto err_quota; | ||
| 99 | } | ||
| 100 | 98 | ||
| 101 | key->payload.data = memcpy(data, prep->data, prep->datalen); | 99 | prep->payload[0] = memcpy(data, prep->data, prep->datalen); |
| 102 | } | 100 | } |
| 103 | return 0; | 101 | return 0; |
| 104 | 102 | ||
| 105 | err_fput: | 103 | err_fput: |
| 106 | fput(file); | 104 | fput(file); |
| 107 | err_quota: | ||
| 108 | key_payload_reserve(key, 0); | ||
| 109 | error: | 105 | error: |
| 110 | return ret; | 106 | return ret; |
| 111 | } | 107 | } |
| 112 | 108 | ||
| 113 | /* | 109 | /* |
| 110 | * Clear preparsement. | ||
| 111 | */ | ||
| 112 | void big_key_free_preparse(struct key_preparsed_payload *prep) | ||
| 113 | { | ||
| 114 | if (prep->datalen > BIG_KEY_FILE_THRESHOLD) { | ||
| 115 | struct path *path = (struct path *)&prep->payload; | ||
| 116 | path_put(path); | ||
| 117 | } else { | ||
| 118 | kfree(prep->payload[0]); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | /* | ||
| 114 | * dispose of the links from a revoked keyring | 123 | * dispose of the links from a revoked keyring |
| 115 | * - called with the key sem write-locked | 124 | * - called with the key sem write-locked |
| 116 | */ | 125 | */ |
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 5fe443d120af..d252c5704f8a 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c | |||
| @@ -811,7 +811,7 @@ static int encrypted_instantiate(struct key *key, | |||
| 811 | goto out; | 811 | goto out; |
| 812 | } | 812 | } |
| 813 | 813 | ||
| 814 | rcu_assign_keypointer(key, epayload); | 814 | prep->payload[0] = epayload; |
| 815 | out: | 815 | out: |
| 816 | kfree(datablob); | 816 | kfree(datablob); |
| 817 | return ret; | 817 | return ret; |
diff --git a/security/keys/key.c b/security/keys/key.c index 2048a110e7f1..b90a68c4e2c4 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
| @@ -437,6 +437,11 @@ static int __key_instantiate_and_link(struct key *key, | |||
| 437 | /* disable the authorisation key */ | 437 | /* disable the authorisation key */ |
| 438 | if (authkey) | 438 | if (authkey) |
| 439 | key_revoke(authkey); | 439 | key_revoke(authkey); |
| 440 | |||
| 441 | if (prep->expiry != TIME_T_MAX) { | ||
| 442 | key->expiry = prep->expiry; | ||
| 443 | key_schedule_gc(prep->expiry + key_gc_delay); | ||
| 444 | } | ||
| 440 | } | 445 | } |
| 441 | } | 446 | } |
| 442 | 447 | ||
| @@ -479,6 +484,7 @@ int key_instantiate_and_link(struct key *key, | |||
| 479 | prep.data = data; | 484 | prep.data = data; |
| 480 | prep.datalen = datalen; | 485 | prep.datalen = datalen; |
| 481 | prep.quotalen = key->type->def_datalen; | 486 | prep.quotalen = key->type->def_datalen; |
| 487 | prep.expiry = TIME_T_MAX; | ||
| 482 | if (key->type->preparse) { | 488 | if (key->type->preparse) { |
| 483 | ret = key->type->preparse(&prep); | 489 | ret = key->type->preparse(&prep); |
| 484 | if (ret < 0) | 490 | if (ret < 0) |
| @@ -488,7 +494,7 @@ int key_instantiate_and_link(struct key *key, | |||
| 488 | if (keyring) { | 494 | if (keyring) { |
| 489 | ret = __key_link_begin(keyring, &key->index_key, &edit); | 495 | ret = __key_link_begin(keyring, &key->index_key, &edit); |
| 490 | if (ret < 0) | 496 | if (ret < 0) |
| 491 | goto error_free_preparse; | 497 | goto error; |
| 492 | } | 498 | } |
| 493 | 499 | ||
| 494 | ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit); | 500 | ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit); |
| @@ -496,10 +502,9 @@ int key_instantiate_and_link(struct key *key, | |||
| 496 | if (keyring) | 502 | if (keyring) |
| 497 | __key_link_end(keyring, &key->index_key, edit); | 503 | __key_link_end(keyring, &key->index_key, edit); |
| 498 | 504 | ||
| 499 | error_free_preparse: | 505 | error: |
| 500 | if (key->type->preparse) | 506 | if (key->type->preparse) |
| 501 | key->type->free_preparse(&prep); | 507 | key->type->free_preparse(&prep); |
| 502 | error: | ||
| 503 | return ret; | 508 | return ret; |
| 504 | } | 509 | } |
| 505 | 510 | ||
| @@ -811,11 +816,12 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
| 811 | prep.datalen = plen; | 816 | prep.datalen = plen; |
| 812 | prep.quotalen = index_key.type->def_datalen; | 817 | prep.quotalen = index_key.type->def_datalen; |
| 813 | prep.trusted = flags & KEY_ALLOC_TRUSTED; | 818 | prep.trusted = flags & KEY_ALLOC_TRUSTED; |
| 819 | prep.expiry = TIME_T_MAX; | ||
| 814 | if (index_key.type->preparse) { | 820 | if (index_key.type->preparse) { |
| 815 | ret = index_key.type->preparse(&prep); | 821 | ret = index_key.type->preparse(&prep); |
| 816 | if (ret < 0) { | 822 | if (ret < 0) { |
| 817 | key_ref = ERR_PTR(ret); | 823 | key_ref = ERR_PTR(ret); |
| 818 | goto error_put_type; | 824 | goto error_free_prep; |
| 819 | } | 825 | } |
| 820 | if (!index_key.description) | 826 | if (!index_key.description) |
| 821 | index_key.description = prep.description; | 827 | index_key.description = prep.description; |
| @@ -941,6 +947,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) | |||
| 941 | prep.data = payload; | 947 | prep.data = payload; |
| 942 | prep.datalen = plen; | 948 | prep.datalen = plen; |
| 943 | prep.quotalen = key->type->def_datalen; | 949 | prep.quotalen = key->type->def_datalen; |
| 950 | prep.expiry = TIME_T_MAX; | ||
| 944 | if (key->type->preparse) { | 951 | if (key->type->preparse) { |
| 945 | ret = key->type->preparse(&prep); | 952 | ret = key->type->preparse(&prep); |
| 946 | if (ret < 0) | 953 | if (ret < 0) |
| @@ -956,9 +963,9 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) | |||
| 956 | 963 | ||
| 957 | up_write(&key->sem); | 964 | up_write(&key->sem); |
| 958 | 965 | ||
| 966 | error: | ||
| 959 | if (key->type->preparse) | 967 | if (key->type->preparse) |
| 960 | key->type->free_preparse(&prep); | 968 | key->type->free_preparse(&prep); |
| 961 | error: | ||
| 962 | return ret; | 969 | return ret; |
| 963 | } | 970 | } |
| 964 | EXPORT_SYMBOL(key_update); | 971 | EXPORT_SYMBOL(key_update); |
| @@ -1024,6 +1031,38 @@ void key_invalidate(struct key *key) | |||
| 1024 | EXPORT_SYMBOL(key_invalidate); | 1031 | EXPORT_SYMBOL(key_invalidate); |
| 1025 | 1032 | ||
| 1026 | /** | 1033 | /** |
| 1034 | * generic_key_instantiate - Simple instantiation of a key from preparsed data | ||
| 1035 | * @key: The key to be instantiated | ||
| 1036 | * @prep: The preparsed data to load. | ||
| 1037 | * | ||
| 1038 | * Instantiate a key from preparsed data. We assume we can just copy the data | ||
| 1039 | * in directly and clear the old pointers. | ||
| 1040 | * | ||
| 1041 | * This can be pointed to directly by the key type instantiate op pointer. | ||
| 1042 | */ | ||
| 1043 | int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | ||
| 1044 | { | ||
| 1045 | int ret; | ||
| 1046 | |||
| 1047 | pr_devel("==>%s()\n", __func__); | ||
| 1048 | |||
| 1049 | ret = key_payload_reserve(key, prep->quotalen); | ||
| 1050 | if (ret == 0) { | ||
| 1051 | key->type_data.p[0] = prep->type_data[0]; | ||
| 1052 | key->type_data.p[1] = prep->type_data[1]; | ||
| 1053 | rcu_assign_keypointer(key, prep->payload[0]); | ||
| 1054 | key->payload.data2[1] = prep->payload[1]; | ||
| 1055 | prep->type_data[0] = NULL; | ||
| 1056 | prep->type_data[1] = NULL; | ||
| 1057 | prep->payload[0] = NULL; | ||
| 1058 | prep->payload[1] = NULL; | ||
| 1059 | } | ||
| 1060 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
| 1061 | return ret; | ||
| 1062 | } | ||
| 1063 | EXPORT_SYMBOL(generic_key_instantiate); | ||
| 1064 | |||
| 1065 | /** | ||
| 1027 | * register_key_type - Register a type of key. | 1066 | * register_key_type - Register a type of key. |
| 1028 | * @ktype: The new key type. | 1067 | * @ktype: The new key type. |
| 1029 | * | 1068 | * |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index cd5bd0cef25d..e26f860e5f2e 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -37,8 +37,6 @@ static int key_get_type_from_user(char *type, | |||
| 37 | return ret; | 37 | return ret; |
| 38 | if (ret == 0 || ret >= len) | 38 | if (ret == 0 || ret >= len) |
| 39 | return -EINVAL; | 39 | return -EINVAL; |
| 40 | if (type[0] == '.') | ||
| 41 | return -EPERM; | ||
| 42 | type[len - 1] = '\0'; | 40 | type[len - 1] = '\0'; |
| 43 | return 0; | 41 | return 0; |
| 44 | } | 42 | } |
| @@ -86,6 +84,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, | |||
| 86 | if (!*description) { | 84 | if (!*description) { |
| 87 | kfree(description); | 85 | kfree(description); |
| 88 | description = NULL; | 86 | description = NULL; |
| 87 | } else if ((description[0] == '.') && | ||
| 88 | (strncmp(type, "keyring", 7) == 0)) { | ||
| 89 | ret = -EPERM; | ||
| 90 | goto error2; | ||
| 89 | } | 91 | } |
| 90 | } | 92 | } |
| 91 | 93 | ||
| @@ -404,12 +406,25 @@ long keyctl_invalidate_key(key_serial_t id) | |||
| 404 | key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); | 406 | key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); |
| 405 | if (IS_ERR(key_ref)) { | 407 | if (IS_ERR(key_ref)) { |
| 406 | ret = PTR_ERR(key_ref); | 408 | ret = PTR_ERR(key_ref); |
| 409 | |||
| 410 | /* Root is permitted to invalidate certain special keys */ | ||
| 411 | if (capable(CAP_SYS_ADMIN)) { | ||
| 412 | key_ref = lookup_user_key(id, 0, 0); | ||
| 413 | if (IS_ERR(key_ref)) | ||
| 414 | goto error; | ||
| 415 | if (test_bit(KEY_FLAG_ROOT_CAN_INVAL, | ||
| 416 | &key_ref_to_ptr(key_ref)->flags)) | ||
| 417 | goto invalidate; | ||
| 418 | goto error_put; | ||
| 419 | } | ||
| 420 | |||
| 407 | goto error; | 421 | goto error; |
| 408 | } | 422 | } |
| 409 | 423 | ||
| 424 | invalidate: | ||
| 410 | key_invalidate(key_ref_to_ptr(key_ref)); | 425 | key_invalidate(key_ref_to_ptr(key_ref)); |
| 411 | ret = 0; | 426 | ret = 0; |
| 412 | 427 | error_put: | |
| 413 | key_ref_put(key_ref); | 428 | key_ref_put(key_ref); |
| 414 | error: | 429 | error: |
| 415 | kleave(" = %ld", ret); | 430 | kleave(" = %ld", ret); |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 9cf2575f0d97..8314a7d2104d 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
| @@ -73,6 +73,8 @@ static inline unsigned keyring_hash(const char *desc) | |||
| 73 | * can be treated as ordinary keys in addition to having their own special | 73 | * can be treated as ordinary keys in addition to having their own special |
| 74 | * operations. | 74 | * operations. |
| 75 | */ | 75 | */ |
| 76 | static int keyring_preparse(struct key_preparsed_payload *prep); | ||
| 77 | static void keyring_free_preparse(struct key_preparsed_payload *prep); | ||
| 76 | static int keyring_instantiate(struct key *keyring, | 78 | static int keyring_instantiate(struct key *keyring, |
| 77 | struct key_preparsed_payload *prep); | 79 | struct key_preparsed_payload *prep); |
| 78 | static void keyring_revoke(struct key *keyring); | 80 | static void keyring_revoke(struct key *keyring); |
| @@ -84,6 +86,8 @@ static long keyring_read(const struct key *keyring, | |||
| 84 | struct key_type key_type_keyring = { | 86 | struct key_type key_type_keyring = { |
| 85 | .name = "keyring", | 87 | .name = "keyring", |
| 86 | .def_datalen = 0, | 88 | .def_datalen = 0, |
| 89 | .preparse = keyring_preparse, | ||
| 90 | .free_preparse = keyring_free_preparse, | ||
| 87 | .instantiate = keyring_instantiate, | 91 | .instantiate = keyring_instantiate, |
| 88 | .match = user_match, | 92 | .match = user_match, |
| 89 | .revoke = keyring_revoke, | 93 | .revoke = keyring_revoke, |
| @@ -123,6 +127,21 @@ static void keyring_publish_name(struct key *keyring) | |||
| 123 | } | 127 | } |
| 124 | 128 | ||
| 125 | /* | 129 | /* |
| 130 | * Preparse a keyring payload | ||
| 131 | */ | ||
| 132 | static int keyring_preparse(struct key_preparsed_payload *prep) | ||
| 133 | { | ||
| 134 | return prep->datalen != 0 ? -EINVAL : 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | /* | ||
| 138 | * Free a preparse of a user defined key payload | ||
| 139 | */ | ||
| 140 | static void keyring_free_preparse(struct key_preparsed_payload *prep) | ||
| 141 | { | ||
| 142 | } | ||
| 143 | |||
| 144 | /* | ||
| 126 | * Initialise a keyring. | 145 | * Initialise a keyring. |
| 127 | * | 146 | * |
| 128 | * Returns 0 on success, -EINVAL if given any data. | 147 | * Returns 0 on success, -EINVAL if given any data. |
| @@ -130,17 +149,10 @@ static void keyring_publish_name(struct key *keyring) | |||
| 130 | static int keyring_instantiate(struct key *keyring, | 149 | static int keyring_instantiate(struct key *keyring, |
| 131 | struct key_preparsed_payload *prep) | 150 | struct key_preparsed_payload *prep) |
| 132 | { | 151 | { |
| 133 | int ret; | 152 | assoc_array_init(&keyring->keys); |
| 134 | 153 | /* make the keyring available by name if it has one */ | |
| 135 | ret = -EINVAL; | 154 | keyring_publish_name(keyring); |
| 136 | if (prep->datalen == 0) { | 155 | return 0; |
| 137 | assoc_array_init(&keyring->keys); | ||
| 138 | /* make the keyring available by name if it has one */ | ||
| 139 | keyring_publish_name(keyring); | ||
| 140 | ret = 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | return ret; | ||
| 144 | } | 156 | } |
| 145 | 157 | ||
| 146 | /* | 158 | /* |
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 7495a93b4b90..842e6f410d50 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
| @@ -20,6 +20,8 @@ | |||
| 20 | #include "internal.h" | 20 | #include "internal.h" |
| 21 | #include <keys/user-type.h> | 21 | #include <keys/user-type.h> |
| 22 | 22 | ||
| 23 | static int request_key_auth_preparse(struct key_preparsed_payload *); | ||
| 24 | static void request_key_auth_free_preparse(struct key_preparsed_payload *); | ||
| 23 | static int request_key_auth_instantiate(struct key *, | 25 | static int request_key_auth_instantiate(struct key *, |
| 24 | struct key_preparsed_payload *); | 26 | struct key_preparsed_payload *); |
| 25 | static void request_key_auth_describe(const struct key *, struct seq_file *); | 27 | static void request_key_auth_describe(const struct key *, struct seq_file *); |
| @@ -33,6 +35,8 @@ static long request_key_auth_read(const struct key *, char __user *, size_t); | |||
| 33 | struct key_type key_type_request_key_auth = { | 35 | struct key_type key_type_request_key_auth = { |
| 34 | .name = ".request_key_auth", | 36 | .name = ".request_key_auth", |
| 35 | .def_datalen = sizeof(struct request_key_auth), | 37 | .def_datalen = sizeof(struct request_key_auth), |
| 38 | .preparse = request_key_auth_preparse, | ||
| 39 | .free_preparse = request_key_auth_free_preparse, | ||
| 36 | .instantiate = request_key_auth_instantiate, | 40 | .instantiate = request_key_auth_instantiate, |
| 37 | .describe = request_key_auth_describe, | 41 | .describe = request_key_auth_describe, |
| 38 | .revoke = request_key_auth_revoke, | 42 | .revoke = request_key_auth_revoke, |
| @@ -40,6 +44,15 @@ struct key_type key_type_request_key_auth = { | |||
| 40 | .read = request_key_auth_read, | 44 | .read = request_key_auth_read, |
| 41 | }; | 45 | }; |
| 42 | 46 | ||
| 47 | int request_key_auth_preparse(struct key_preparsed_payload *prep) | ||
| 48 | { | ||
| 49 | return 0; | ||
| 50 | } | ||
| 51 | |||
| 52 | void request_key_auth_free_preparse(struct key_preparsed_payload *prep) | ||
| 53 | { | ||
| 54 | } | ||
| 55 | |||
| 43 | /* | 56 | /* |
| 44 | * Instantiate a request-key authorisation key. | 57 | * Instantiate a request-key authorisation key. |
| 45 | */ | 58 | */ |
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index faa2caeb593f..eee340011f2b 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c | |||
| @@ -27,7 +27,9 @@ static int logon_vet_description(const char *desc); | |||
| 27 | struct key_type key_type_user = { | 27 | struct key_type key_type_user = { |
| 28 | .name = "user", | 28 | .name = "user", |
| 29 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 29 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
| 30 | .instantiate = user_instantiate, | 30 | .preparse = user_preparse, |
| 31 | .free_preparse = user_free_preparse, | ||
| 32 | .instantiate = generic_key_instantiate, | ||
| 31 | .update = user_update, | 33 | .update = user_update, |
| 32 | .match = user_match, | 34 | .match = user_match, |
| 33 | .revoke = user_revoke, | 35 | .revoke = user_revoke, |
| @@ -47,7 +49,9 @@ EXPORT_SYMBOL_GPL(key_type_user); | |||
| 47 | struct key_type key_type_logon = { | 49 | struct key_type key_type_logon = { |
| 48 | .name = "logon", | 50 | .name = "logon", |
| 49 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 51 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
| 50 | .instantiate = user_instantiate, | 52 | .preparse = user_preparse, |
| 53 | .free_preparse = user_free_preparse, | ||
| 54 | .instantiate = generic_key_instantiate, | ||
| 51 | .update = user_update, | 55 | .update = user_update, |
| 52 | .match = user_match, | 56 | .match = user_match, |
| 53 | .revoke = user_revoke, | 57 | .revoke = user_revoke, |
| @@ -58,38 +62,37 @@ struct key_type key_type_logon = { | |||
| 58 | EXPORT_SYMBOL_GPL(key_type_logon); | 62 | EXPORT_SYMBOL_GPL(key_type_logon); |
| 59 | 63 | ||
| 60 | /* | 64 | /* |
| 61 | * instantiate a user defined key | 65 | * Preparse a user defined key payload |
| 62 | */ | 66 | */ |
| 63 | int user_instantiate(struct key *key, struct key_preparsed_payload *prep) | 67 | int user_preparse(struct key_preparsed_payload *prep) |
| 64 | { | 68 | { |
| 65 | struct user_key_payload *upayload; | 69 | struct user_key_payload *upayload; |
| 66 | size_t datalen = prep->datalen; | 70 | size_t datalen = prep->datalen; |
| 67 | int ret; | ||
| 68 | 71 | ||
| 69 | ret = -EINVAL; | ||
| 70 | if (datalen <= 0 || datalen > 32767 || !prep->data) | 72 | if (datalen <= 0 || datalen > 32767 || !prep->data) |
| 71 | goto error; | 73 | return -EINVAL; |
| 72 | |||
| 73 | ret = key_payload_reserve(key, datalen); | ||
| 74 | if (ret < 0) | ||
| 75 | goto error; | ||
| 76 | 74 | ||
| 77 | ret = -ENOMEM; | ||
| 78 | upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); | 75 | upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); |
| 79 | if (!upayload) | 76 | if (!upayload) |
| 80 | goto error; | 77 | return -ENOMEM; |
| 81 | 78 | ||
| 82 | /* attach the data */ | 79 | /* attach the data */ |
| 80 | prep->quotalen = datalen; | ||
| 81 | prep->payload[0] = upayload; | ||
| 83 | upayload->datalen = datalen; | 82 | upayload->datalen = datalen; |
| 84 | memcpy(upayload->data, prep->data, datalen); | 83 | memcpy(upayload->data, prep->data, datalen); |
| 85 | rcu_assign_keypointer(key, upayload); | 84 | return 0; |
| 86 | ret = 0; | ||
| 87 | |||
| 88 | error: | ||
| 89 | return ret; | ||
| 90 | } | 85 | } |
| 86 | EXPORT_SYMBOL_GPL(user_preparse); | ||
| 91 | 87 | ||
| 92 | EXPORT_SYMBOL_GPL(user_instantiate); | 88 | /* |
| 89 | * Free a preparse of a user defined key payload | ||
| 90 | */ | ||
| 91 | void user_free_preparse(struct key_preparsed_payload *prep) | ||
| 92 | { | ||
| 93 | kfree(prep->payload[0]); | ||
| 94 | } | ||
| 95 | EXPORT_SYMBOL_GPL(user_free_preparse); | ||
| 93 | 96 | ||
| 94 | /* | 97 | /* |
| 95 | * update a user defined key | 98 | * update a user defined key |
