diff options
Diffstat (limited to 'crypto/asymmetric_keys/x509_public_key.c')
| -rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 157 |
1 files changed, 68 insertions, 89 deletions
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 06007f0e880c..382ef0d2ff2e 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
| @@ -23,82 +23,84 @@ | |||
| 23 | #include "public_key.h" | 23 | #include "public_key.h" |
| 24 | #include "x509_parser.h" | 24 | #include "x509_parser.h" |
| 25 | 25 | ||
| 26 | static const | ||
| 27 | struct public_key_algorithm *x509_public_key_algorithms[PKEY_ALGO__LAST] = { | ||
| 28 | [PKEY_ALGO_DSA] = NULL, | ||
| 29 | #if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \ | ||
| 30 | defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE) | ||
| 31 | [PKEY_ALGO_RSA] = &RSA_public_key_algorithm, | ||
| 32 | #endif | ||
| 33 | }; | ||
| 34 | |||
| 35 | /* | 26 | /* |
| 36 | * Check the signature on a certificate using the provided public key | 27 | * Set up the signature parameters in an X.509 certificate. This involves |
| 28 | * digesting the signed data and extracting the signature. | ||
| 37 | */ | 29 | */ |
| 38 | static int x509_check_signature(const struct public_key *pub, | 30 | int x509_get_sig_params(struct x509_certificate *cert) |
| 39 | const struct x509_certificate *cert) | ||
| 40 | { | 31 | { |
| 41 | struct public_key_signature *sig; | ||
| 42 | struct crypto_shash *tfm; | 32 | struct crypto_shash *tfm; |
| 43 | struct shash_desc *desc; | 33 | struct shash_desc *desc; |
| 44 | size_t digest_size, desc_size; | 34 | size_t digest_size, desc_size; |
| 35 | void *digest; | ||
| 45 | int ret; | 36 | int ret; |
| 46 | 37 | ||
| 47 | pr_devel("==>%s()\n", __func__); | 38 | pr_devel("==>%s()\n", __func__); |
| 48 | 39 | ||
| 40 | if (cert->sig.rsa.s) | ||
| 41 | return 0; | ||
| 42 | |||
| 43 | cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size); | ||
| 44 | if (!cert->sig.rsa.s) | ||
| 45 | return -ENOMEM; | ||
| 46 | cert->sig.nr_mpi = 1; | ||
| 47 | |||
| 49 | /* Allocate the hashing algorithm we're going to need and find out how | 48 | /* Allocate the hashing algorithm we're going to need and find out how |
| 50 | * big the hash operational data will be. | 49 | * big the hash operational data will be. |
| 51 | */ | 50 | */ |
| 52 | tfm = crypto_alloc_shash(pkey_hash_algo[cert->sig_hash_algo], 0, 0); | 51 | tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0); |
| 53 | if (IS_ERR(tfm)) | 52 | if (IS_ERR(tfm)) |
| 54 | return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); | 53 | return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); |
| 55 | 54 | ||
| 56 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | 55 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); |
| 57 | digest_size = crypto_shash_digestsize(tfm); | 56 | digest_size = crypto_shash_digestsize(tfm); |
| 58 | 57 | ||
| 59 | /* We allocate the hash operational data storage on the end of our | 58 | /* We allocate the hash operational data storage on the end of the |
| 60 | * context data. | 59 | * digest storage space. |
| 61 | */ | 60 | */ |
| 62 | ret = -ENOMEM; | 61 | ret = -ENOMEM; |
| 63 | sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL); | 62 | digest = kzalloc(digest_size + desc_size, GFP_KERNEL); |
| 64 | if (!sig) | 63 | if (!digest) |
| 65 | goto error_no_sig; | 64 | goto error; |
| 66 | 65 | ||
| 67 | sig->pkey_hash_algo = cert->sig_hash_algo; | 66 | cert->sig.digest = digest; |
| 68 | sig->digest = (u8 *)sig + sizeof(*sig) + desc_size; | 67 | cert->sig.digest_size = digest_size; |
| 69 | sig->digest_size = digest_size; | ||
| 70 | 68 | ||
| 71 | desc = (void *)sig + sizeof(*sig); | 69 | desc = digest + digest_size; |
| 72 | desc->tfm = tfm; | 70 | desc->tfm = tfm; |
| 73 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | 71 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; |
| 74 | 72 | ||
| 75 | ret = crypto_shash_init(desc); | 73 | ret = crypto_shash_init(desc); |
| 76 | if (ret < 0) | 74 | if (ret < 0) |
| 77 | goto error; | 75 | goto error; |
| 76 | might_sleep(); | ||
| 77 | ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest); | ||
| 78 | error: | ||
| 79 | crypto_free_shash(tfm); | ||
| 80 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
| 81 | return ret; | ||
| 82 | } | ||
| 83 | EXPORT_SYMBOL_GPL(x509_get_sig_params); | ||
| 78 | 84 | ||
| 79 | ret = -ENOMEM; | 85 | /* |
| 80 | sig->rsa.s = mpi_read_raw_data(cert->sig, cert->sig_size); | 86 | * Check the signature on a certificate using the provided public key |
| 81 | if (!sig->rsa.s) | 87 | */ |
| 82 | goto error; | 88 | int x509_check_signature(const struct public_key *pub, |
| 89 | struct x509_certificate *cert) | ||
| 90 | { | ||
| 91 | int ret; | ||
| 83 | 92 | ||
| 84 | ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest); | 93 | pr_devel("==>%s()\n", __func__); |
| 85 | if (ret < 0) | ||
| 86 | goto error_mpi; | ||
| 87 | 94 | ||
| 88 | ret = pub->algo->verify_signature(pub, sig); | 95 | ret = x509_get_sig_params(cert); |
| 96 | if (ret < 0) | ||
| 97 | return ret; | ||
| 89 | 98 | ||
| 99 | ret = public_key_verify_signature(pub, &cert->sig); | ||
| 90 | pr_debug("Cert Verification: %d\n", ret); | 100 | pr_debug("Cert Verification: %d\n", ret); |
| 91 | |||
| 92 | error_mpi: | ||
| 93 | mpi_free(sig->rsa.s); | ||
| 94 | error: | ||
| 95 | kfree(sig); | ||
| 96 | error_no_sig: | ||
| 97 | crypto_free_shash(tfm); | ||
| 98 | |||
| 99 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
| 100 | return ret; | 101 | return ret; |
| 101 | } | 102 | } |
| 103 | EXPORT_SYMBOL_GPL(x509_check_signature); | ||
| 102 | 104 | ||
| 103 | /* | 105 | /* |
| 104 | * Attempt to parse a data blob for a key as an X509 certificate. | 106 | * Attempt to parse a data blob for a key as an X509 certificate. |
| @@ -106,7 +108,6 @@ error_no_sig: | |||
| 106 | static int x509_key_preparse(struct key_preparsed_payload *prep) | 108 | static int x509_key_preparse(struct key_preparsed_payload *prep) |
| 107 | { | 109 | { |
| 108 | struct x509_certificate *cert; | 110 | struct x509_certificate *cert; |
| 109 | struct tm now; | ||
| 110 | size_t srlen, sulen; | 111 | size_t srlen, sulen; |
| 111 | char *desc = NULL; | 112 | char *desc = NULL; |
| 112 | int ret; | 113 | int ret; |
| @@ -117,7 +118,18 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
| 117 | 118 | ||
| 118 | pr_devel("Cert Issuer: %s\n", cert->issuer); | 119 | pr_devel("Cert Issuer: %s\n", cert->issuer); |
| 119 | pr_devel("Cert Subject: %s\n", cert->subject); | 120 | pr_devel("Cert Subject: %s\n", cert->subject); |
| 120 | pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]); | 121 | |
| 122 | if (cert->pub->pkey_algo >= PKEY_ALGO__LAST || | ||
| 123 | cert->sig.pkey_algo >= PKEY_ALGO__LAST || | ||
| 124 | cert->sig.pkey_hash_algo >= PKEY_HASH__LAST || | ||
| 125 | !pkey_algo[cert->pub->pkey_algo] || | ||
| 126 | !pkey_algo[cert->sig.pkey_algo] || | ||
| 127 | !hash_algo_name[cert->sig.pkey_hash_algo]) { | ||
| 128 | ret = -ENOPKG; | ||
| 129 | goto error_free_cert; | ||
| 130 | } | ||
| 131 | |||
| 132 | pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); | ||
| 121 | pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", | 133 | pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", |
| 122 | cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, | 134 | cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, |
| 123 | cert->valid_from.tm_mday, cert->valid_from.tm_hour, | 135 | cert->valid_from.tm_mday, cert->valid_from.tm_hour, |
| @@ -127,58 +139,22 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
| 127 | cert->valid_to.tm_mday, cert->valid_to.tm_hour, | 139 | cert->valid_to.tm_mday, cert->valid_to.tm_hour, |
| 128 | cert->valid_to.tm_min, cert->valid_to.tm_sec); | 140 | cert->valid_to.tm_min, cert->valid_to.tm_sec); |
| 129 | pr_devel("Cert Signature: %s + %s\n", | 141 | pr_devel("Cert Signature: %s + %s\n", |
| 130 | pkey_algo[cert->sig_pkey_algo], | 142 | pkey_algo_name[cert->sig.pkey_algo], |
| 131 | pkey_hash_algo[cert->sig_hash_algo]); | 143 | hash_algo_name[cert->sig.pkey_hash_algo]); |
| 132 | 144 | ||
| 133 | if (!cert->fingerprint || !cert->authority) { | 145 | if (!cert->fingerprint) { |
| 134 | pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n", | 146 | pr_warn("Cert for '%s' must have a SubjKeyId extension\n", |
| 135 | cert->subject); | 147 | cert->subject); |
| 136 | ret = -EKEYREJECTED; | 148 | ret = -EKEYREJECTED; |
| 137 | goto error_free_cert; | 149 | goto error_free_cert; |
| 138 | } | 150 | } |
| 139 | 151 | ||
| 140 | time_to_tm(CURRENT_TIME.tv_sec, 0, &now); | 152 | cert->pub->algo = pkey_algo[cert->pub->pkey_algo]; |
| 141 | pr_devel("Now: %04ld-%02d-%02d %02d:%02d:%02d\n", | ||
| 142 | now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, | ||
| 143 | now.tm_hour, now.tm_min, now.tm_sec); | ||
| 144 | if (now.tm_year < cert->valid_from.tm_year || | ||
| 145 | (now.tm_year == cert->valid_from.tm_year && | ||
| 146 | (now.tm_mon < cert->valid_from.tm_mon || | ||
| 147 | (now.tm_mon == cert->valid_from.tm_mon && | ||
| 148 | (now.tm_mday < cert->valid_from.tm_mday || | ||
| 149 | (now.tm_mday == cert->valid_from.tm_mday && | ||
| 150 | (now.tm_hour < cert->valid_from.tm_hour || | ||
| 151 | (now.tm_hour == cert->valid_from.tm_hour && | ||
| 152 | (now.tm_min < cert->valid_from.tm_min || | ||
| 153 | (now.tm_min == cert->valid_from.tm_min && | ||
| 154 | (now.tm_sec < cert->valid_from.tm_sec | ||
| 155 | ))))))))))) { | ||
| 156 | pr_warn("Cert %s is not yet valid\n", cert->fingerprint); | ||
| 157 | ret = -EKEYREJECTED; | ||
| 158 | goto error_free_cert; | ||
| 159 | } | ||
| 160 | if (now.tm_year > cert->valid_to.tm_year || | ||
| 161 | (now.tm_year == cert->valid_to.tm_year && | ||
| 162 | (now.tm_mon > cert->valid_to.tm_mon || | ||
| 163 | (now.tm_mon == cert->valid_to.tm_mon && | ||
| 164 | (now.tm_mday > cert->valid_to.tm_mday || | ||
| 165 | (now.tm_mday == cert->valid_to.tm_mday && | ||
| 166 | (now.tm_hour > cert->valid_to.tm_hour || | ||
| 167 | (now.tm_hour == cert->valid_to.tm_hour && | ||
| 168 | (now.tm_min > cert->valid_to.tm_min || | ||
| 169 | (now.tm_min == cert->valid_to.tm_min && | ||
| 170 | (now.tm_sec > cert->valid_to.tm_sec | ||
| 171 | ))))))))))) { | ||
| 172 | pr_warn("Cert %s has expired\n", cert->fingerprint); | ||
| 173 | ret = -EKEYEXPIRED; | ||
| 174 | goto error_free_cert; | ||
| 175 | } | ||
| 176 | |||
| 177 | cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo]; | ||
| 178 | cert->pub->id_type = PKEY_ID_X509; | 153 | cert->pub->id_type = PKEY_ID_X509; |
| 179 | 154 | ||
| 180 | /* Check the signature on the key */ | 155 | /* Check the signature on the key if it appears to be self-signed */ |
| 181 | if (strcmp(cert->fingerprint, cert->authority) == 0) { | 156 | if (!cert->authority || |
| 157 | strcmp(cert->fingerprint, cert->authority) == 0) { | ||
| 182 | ret = x509_check_signature(cert->pub, cert); | 158 | ret = x509_check_signature(cert->pub, cert); |
| 183 | if (ret < 0) | 159 | if (ret < 0) |
| 184 | goto error_free_cert; | 160 | goto error_free_cert; |
| @@ -237,3 +213,6 @@ static void __exit x509_key_exit(void) | |||
| 237 | 213 | ||
| 238 | module_init(x509_key_init); | 214 | module_init(x509_key_init); |
| 239 | module_exit(x509_key_exit); | 215 | module_exit(x509_key_exit); |
| 216 | |||
| 217 | MODULE_DESCRIPTION("X.509 certificate parser"); | ||
| 218 | MODULE_LICENSE("GPL"); | ||
