Branch data Line data Source code
1 : : /*
2 : : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License").
5 : : * You may not use this file except in compliance with the License.
6 : : * A copy of the License is located at
7 : : *
8 : : * http://aws.amazon.com/apache2.0
9 : : *
10 : : * or in the "license" file accompanying this file. This file is distributed
11 : : * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 : : * express or implied. See the License for the specific language governing
13 : : * permissions and limitations under the License.
14 : : */
15 : :
16 : : #include "crypto/s2n_pkey.h"
17 : :
18 : : #include <openssl/evp.h>
19 : :
20 : : #include "crypto/s2n_mldsa.h"
21 : : #include "crypto/s2n_openssl_evp.h"
22 : : #include "crypto/s2n_openssl_x509.h"
23 : : #include "crypto/s2n_pkey_evp.h"
24 : : #include "crypto/s2n_rsa_pss.h"
25 : : #include "error/s2n_errno.h"
26 : : #include "utils/s2n_mem.h"
27 : : #include "utils/s2n_result.h"
28 : : #include "utils/s2n_safety.h"
29 : :
30 : : #ifndef EVP_PKEY_RSA_PSS
31 : : #define EVP_PKEY_RSA_PSS EVP_PKEY_NONE
32 : : #endif
33 : :
34 : : int s2n_pkey_zero_init(struct s2n_pkey *pkey)
35 : 7096734 : {
36 : 7096734 : pkey->pkey = NULL;
37 : 7096734 : pkey->size = NULL;
38 : 7096734 : pkey->sign = NULL;
39 : 7096734 : pkey->verify = NULL;
40 : 7096734 : pkey->encrypt = NULL;
41 : 7096734 : pkey->decrypt = NULL;
42 : 7096734 : return 0;
43 : 7096734 : }
44 : :
45 : : S2N_RESULT s2n_pkey_setup_for_type(struct s2n_pkey *pkey, s2n_pkey_type pkey_type)
46 : 10786 : {
47 [ - + ]: 10786 : switch (pkey_type) {
48 [ + + ]: 8648 : case S2N_PKEY_TYPE_RSA:
49 [ + + ]: 10639 : case S2N_PKEY_TYPE_ECDSA:
50 [ + + ]: 10786 : case S2N_PKEY_TYPE_RSA_PSS:
51 [ - + ]: 10786 : case S2N_PKEY_TYPE_MLDSA:
52 : 10786 : return s2n_pkey_evp_init(pkey);
53 [ - + ]: 0 : case S2N_PKEY_TYPE_SENTINEL:
54 [ - + ]: 0 : case S2N_PKEY_TYPE_UNKNOWN:
55 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED);
56 : 10786 : }
57 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED);
58 : 0 : }
59 : :
60 : : int s2n_pkey_check_key_exists(const struct s2n_pkey *pkey)
61 : 1665 : {
62 [ # # ][ - + ]: 1665 : POSIX_ENSURE_REF(pkey);
63 [ + + ][ + - ]: 1665 : POSIX_ENSURE_REF(pkey->pkey);
64 : 1577 : return S2N_SUCCESS;
65 : 1665 : }
66 : :
67 : : S2N_RESULT s2n_pkey_size(const struct s2n_pkey *pkey, uint32_t *size_out)
68 : 7562 : {
69 [ - + ][ # # ]: 7562 : RESULT_ENSURE_REF(pkey);
70 [ - + ][ # # ]: 7562 : RESULT_ENSURE_REF(pkey->size);
71 [ - + ][ # # ]: 7562 : RESULT_ENSURE_REF(size_out);
72 : :
73 [ - + ]: 7562 : RESULT_GUARD(pkey->size(pkey, size_out));
74 : :
75 : 7562 : return S2N_RESULT_OK;
76 : 7562 : }
77 : :
78 : : int s2n_pkey_sign(const struct s2n_pkey *pkey, s2n_signature_algorithm sig_alg,
79 : : struct s2n_hash_state *digest, struct s2n_blob *signature)
80 : 4415 : {
81 [ # # ][ - + ]: 4415 : POSIX_ENSURE_REF(pkey->sign);
82 : :
83 : 4415 : return pkey->sign(pkey, sig_alg, digest, signature);
84 : 4415 : }
85 : :
86 : : int s2n_pkey_verify(const struct s2n_pkey *pkey, s2n_signature_algorithm sig_alg,
87 : : struct s2n_hash_state *digest, struct s2n_blob *signature)
88 : 3630 : {
89 [ - + ][ # # ]: 3630 : POSIX_ENSURE_REF(pkey);
90 [ - + ][ # # ]: 3630 : POSIX_ENSURE_REF(pkey->verify);
91 : :
92 : 3630 : return pkey->verify(pkey, sig_alg, digest, signature);
93 : 3630 : }
94 : :
95 : : int s2n_pkey_encrypt(const struct s2n_pkey *pkey, struct s2n_blob *in, struct s2n_blob *out)
96 : 247 : {
97 [ - + ][ # # ]: 247 : POSIX_ENSURE_REF(pkey->encrypt);
98 : :
99 : 247 : return pkey->encrypt(pkey, in, out);
100 : 247 : }
101 : :
102 : : int s2n_pkey_decrypt(const struct s2n_pkey *pkey, struct s2n_blob *in, struct s2n_blob *out)
103 : 1709 : {
104 [ - + ][ # # ]: 1709 : POSIX_ENSURE_REF(pkey->decrypt);
105 : :
106 : 1709 : return pkey->decrypt(pkey, in, out);
107 : 1709 : }
108 : :
109 : : int s2n_pkey_match(const struct s2n_pkey *pub_key, const struct s2n_pkey *priv_key)
110 : 585 : {
111 [ - + ][ # # ]: 585 : POSIX_ENSURE_REF(pub_key);
112 : :
113 : : /* Minimally, both keys must be of the same type */
114 : 585 : s2n_pkey_type priv_type = 0, pub_type = 0;
115 [ - + ]: 585 : POSIX_GUARD_RESULT(s2n_pkey_get_type(priv_key->pkey, &priv_type));
116 [ - + ]: 585 : POSIX_GUARD_RESULT(s2n_pkey_get_type(pub_key->pkey, &pub_type));
117 [ + - ][ + + ]: 585 : POSIX_ENSURE(priv_type == pub_type, S2N_ERR_KEY_MISMATCH);
118 : :
119 : : /* If both keys are of the same type, check that the public key
120 : : * can verify a test signature from the private key.
121 : : */
122 : :
123 : 561 : uint8_t input[] = "key check";
124 : 561 : DEFER_CLEANUP(struct s2n_blob signature = { 0 }, s2n_free);
125 : :
126 : : /* Choose one signature algorithm to test each type of pkey.
127 : : * For example, RSA certs can be used for either S2N_SIGNATURE_RSA (PKCS1)
128 : : * or S2N_SIGNATURE_RSA_PSS_RSAE, but we only test with S2N_SIGNATURE_RSA.
129 : : */
130 : 561 : s2n_signature_algorithm check_alg = S2N_SIGNATURE_ANONYMOUS;
131 : 561 : s2n_hash_algorithm hash_alg = S2N_HASH_SHA256;
132 : 561 : switch (priv_type) {
133 [ + + ]: 167 : case S2N_PKEY_TYPE_ECDSA:
134 : 167 : check_alg = S2N_SIGNATURE_ECDSA;
135 : 167 : break;
136 [ + + ]: 364 : case S2N_PKEY_TYPE_RSA:
137 : 364 : check_alg = S2N_SIGNATURE_RSA;
138 : 364 : break;
139 [ + + ]: 30 : case S2N_PKEY_TYPE_RSA_PSS:
140 : 30 : check_alg = S2N_SIGNATURE_RSA_PSS_PSS;
141 : 30 : break;
142 [ - + ]: 0 : case S2N_PKEY_TYPE_MLDSA:
143 : 0 : check_alg = S2N_SIGNATURE_MLDSA;
144 : 0 : hash_alg = S2N_HASH_SHAKE256_64;
145 : 0 : break;
146 [ - + ]: 0 : default:
147 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED);
148 : 561 : }
149 : :
150 : 561 : DEFER_CLEANUP(struct s2n_hash_state state_in = { 0 }, s2n_hash_free);
151 [ - + ]: 561 : POSIX_GUARD(s2n_hash_new(&state_in));
152 [ - + ]: 561 : POSIX_GUARD(s2n_hash_init(&state_in, hash_alg));
153 [ - + ]: 561 : POSIX_GUARD_RESULT(s2n_pkey_init_hash(pub_key, check_alg, &state_in));
154 [ - + ]: 561 : POSIX_GUARD(s2n_hash_update(&state_in, input, sizeof(input)));
155 : :
156 : 561 : DEFER_CLEANUP(struct s2n_hash_state state_out = { 0 }, s2n_hash_free);
157 [ - + ]: 561 : POSIX_GUARD(s2n_hash_new(&state_out));
158 [ - + ]: 561 : POSIX_GUARD(s2n_hash_copy(&state_out, &state_in));
159 : :
160 : 561 : uint32_t size = 0;
161 [ - + ]: 561 : POSIX_GUARD_RESULT(s2n_pkey_size(priv_key, &size));
162 [ - + ]: 561 : POSIX_GUARD(s2n_alloc(&signature, size));
163 : :
164 : : /* Note: The Libcrypto RSA EVP_PKEY will cache certain computations used for
165 : : * RSA signing.
166 : : *
167 : : * This means that the first RSA sign with an EVP_PKEY is ~300 us slower
168 : : * than subsequent sign operations. The effect is much smaller for ECDSA signatures.
169 : : *
170 : : * If this pkey_sign operation is moved out of config creation, then the
171 : : * 300 us penalty will be paid by the first handshake done on the config.
172 : : */
173 [ - + ]: 561 : POSIX_GUARD(s2n_pkey_sign(priv_key, check_alg, &state_in, &signature));
174 [ + + ][ + - ]: 561 : POSIX_ENSURE(s2n_pkey_verify(pub_key, check_alg, &state_out, &signature) == S2N_SUCCESS,
175 : 553 : S2N_ERR_KEY_MISMATCH);
176 : :
177 : 553 : return S2N_SUCCESS;
178 : 561 : }
179 : :
180 : : int s2n_pkey_free(struct s2n_pkey *key)
181 : 7099852 : {
182 [ - + ]: 7099852 : if (key == NULL) {
183 : 0 : return S2N_SUCCESS;
184 : 0 : }
185 [ + + ]: 7099852 : if (key->pkey != NULL) {
186 : 5750 : EVP_PKEY_free(key->pkey);
187 : 5750 : key->pkey = NULL;
188 : 5750 : }
189 : 7099852 : return S2N_SUCCESS;
190 : 7099852 : }
191 : :
192 : : S2N_RESULT s2n_asn1der_to_private_key(struct s2n_pkey *priv_key, struct s2n_blob *asn1der, int type_hint)
193 : 551 : {
194 : 551 : const unsigned char *key_to_parse = asn1der->data;
195 : :
196 : : /* We use "d2i_AutoPrivateKey" instead of "PEM_read_bio_PrivateKey" because
197 : : * s2n-tls prefers to perform its own custom PEM parsing. Historically,
198 : : * openssl's PEM parsing tended to ignore invalid certificates rather than
199 : : * error on them. We prefer to fail early rather than continue without
200 : : * the full and correct chain intended by the application.
201 : : */
202 : 551 : DEFER_CLEANUP(EVP_PKEY *evp_private_key = d2i_AutoPrivateKey(NULL, &key_to_parse, asn1der->size),
203 : 551 : EVP_PKEY_free_pointer);
204 : :
205 : : /* We have found cases where d2i_AutoPrivateKey fails to detect the type of
206 : : * the key. For example, openssl fails to identify an EC key without the
207 : : * optional publicKey field.
208 : : *
209 : : * If d2i_AutoPrivateKey fails, try once more with the type we parsed from the PEM.
210 : : */
211 [ - + ]: 551 : if (evp_private_key == NULL) {
212 : 0 : evp_private_key = d2i_PrivateKey(type_hint, NULL, &key_to_parse, asn1der->size);
213 : 0 : }
214 [ - + ][ # # ]: 551 : RESULT_ENSURE(evp_private_key, S2N_ERR_DECODE_PRIVATE_KEY);
215 : :
216 : : /* If key parsing is successful, d2i_AutoPrivateKey increments *key_to_parse to the byte following the parsed data */
217 : 551 : uint32_t parsed_len = key_to_parse - asn1der->data;
218 [ - + ][ # # ]: 551 : RESULT_ENSURE(parsed_len == asn1der->size, S2N_ERR_DECODE_PRIVATE_KEY);
219 : :
220 : : /* Initialize s2n_pkey according to key type */
221 : 551 : s2n_pkey_type type = 0;
222 [ - + ]: 551 : RESULT_GUARD(s2n_pkey_get_type(evp_private_key, &type));
223 [ - + ]: 551 : RESULT_GUARD(s2n_pkey_setup_for_type(priv_key, type));
224 : :
225 : 551 : priv_key->pkey = evp_private_key;
226 : 551 : ZERO_TO_DISABLE_DEFER_CLEANUP(evp_private_key);
227 : :
228 : 551 : return S2N_RESULT_OK;
229 : 551 : }
230 : :
231 : : S2N_RESULT s2n_asn1der_to_public_key_and_type(struct s2n_pkey *pub_key,
232 : : s2n_pkey_type *pkey_type_out, struct s2n_blob *asn1der)
233 : 115 : {
234 : 115 : DEFER_CLEANUP(X509 *cert = NULL, X509_free_pointer);
235 [ - + ]: 115 : RESULT_GUARD(s2n_openssl_x509_parse(asn1der, &cert));
236 [ - + ]: 115 : RESULT_GUARD(s2n_pkey_from_x509(cert, pub_key, pkey_type_out));
237 : :
238 : 115 : return S2N_RESULT_OK;
239 : 115 : }
240 : :
241 : : S2N_RESULT s2n_pkey_get_type(EVP_PKEY *evp_pkey, s2n_pkey_type *pkey_type)
242 : 12522 : {
243 [ - + ][ # # ]: 12522 : RESULT_ENSURE_REF(evp_pkey);
244 [ - + ][ # # ]: 12522 : RESULT_ENSURE_REF(pkey_type);
245 : 12522 : *pkey_type = S2N_PKEY_TYPE_UNKNOWN;
246 : :
247 : 12522 : int type = EVP_PKEY_base_id(evp_pkey);
248 : 12522 : switch (type) {
249 [ + + ]: 9865 : case EVP_PKEY_RSA:
250 : 9865 : *pkey_type = S2N_PKEY_TYPE_RSA;
251 : 9865 : break;
252 [ + + ]: 263 : case EVP_PKEY_RSA_PSS:
253 : 263 : *pkey_type = S2N_PKEY_TYPE_RSA_PSS;
254 : 263 : break;
255 [ + + ]: 2394 : case EVP_PKEY_EC:
256 : 2394 : *pkey_type = S2N_PKEY_TYPE_ECDSA;
257 : 2394 : break;
258 : : #if S2N_LIBCRYPTO_SUPPORTS_MLDSA
259 : : case EVP_PKEY_PQDSA:
260 : : *pkey_type = S2N_PKEY_TYPE_MLDSA;
261 : : break;
262 : : #endif
263 [ - + ]: 0 : default:
264 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_DECODE_CERTIFICATE);
265 : 12522 : }
266 : :
267 : 12522 : return S2N_RESULT_OK;
268 : 12522 : }
269 : :
270 : : S2N_RESULT s2n_pkey_from_x509(X509 *cert, struct s2n_pkey *pub_key_out,
271 : : s2n_pkey_type *pkey_type_out)
272 : 5199 : {
273 [ # # ][ - + ]: 5199 : RESULT_ENSURE_REF(cert);
274 [ - + ][ # # ]: 5199 : RESULT_ENSURE_REF(pub_key_out);
275 [ # # ][ - + ]: 5199 : RESULT_ENSURE_REF(pkey_type_out);
276 : :
277 : 5199 : DEFER_CLEANUP(EVP_PKEY *evp_public_key = X509_get_pubkey(cert), EVP_PKEY_free_pointer);
278 [ - + ][ # # ]: 5199 : RESULT_ENSURE(evp_public_key != NULL, S2N_ERR_DECODE_CERTIFICATE);
279 : :
280 [ - + ]: 5199 : RESULT_GUARD(s2n_pkey_get_type(evp_public_key, pkey_type_out));
281 [ - + ]: 5199 : RESULT_GUARD(s2n_pkey_setup_for_type(pub_key_out, *pkey_type_out));
282 : :
283 : 5199 : pub_key_out->pkey = evp_public_key;
284 : 5199 : ZERO_TO_DISABLE_DEFER_CLEANUP(evp_public_key);
285 : :
286 : 5199 : return S2N_RESULT_OK;
287 : 5199 : }
288 : :
289 : : S2N_RESULT s2n_pkey_init_hash(const struct s2n_pkey *pkey,
290 : : s2n_signature_algorithm sig_alg, struct s2n_hash_state *hash)
291 : 5603 : {
292 [ - + ]: 5603 : if (sig_alg == S2N_SIGNATURE_MLDSA) {
293 [ # # ]: 0 : RESULT_GUARD(s2n_mldsa_init_mu_hash(hash, pkey));
294 : 0 : }
295 : 5603 : return S2N_RESULT_OK;
296 : 5603 : }
|