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 : : #include "tls/s2n_async_pkey.h"
16 : :
17 : : #include "api/s2n.h"
18 : : #include "crypto/s2n_hash.h"
19 : : #include "crypto/s2n_signature.h"
20 : : #include "error/s2n_errno.h"
21 : : #include "tls/s2n_async_offload.h"
22 : : #include "tls/s2n_connection.h"
23 : : #include "tls/s2n_handshake.h"
24 : : #include "utils/s2n_blob.h"
25 : : #include "utils/s2n_mem.h"
26 : : #include "utils/s2n_result.h"
27 : : #include "utils/s2n_safety.h"
28 : :
29 : : struct s2n_async_pkey_decrypt_data {
30 : : s2n_async_pkey_decrypt_complete on_complete;
31 : : struct s2n_blob encrypted;
32 : : struct s2n_blob decrypted;
33 : : unsigned rsa_failed : 1;
34 : : };
35 : :
36 : : struct s2n_async_pkey_sign_data {
37 : : s2n_async_pkey_sign_complete on_complete;
38 : : struct s2n_hash_state digest;
39 : : s2n_signature_algorithm sig_alg;
40 : : struct s2n_blob signature;
41 : : };
42 : :
43 : : struct s2n_async_pkey_op {
44 : : s2n_async_pkey_op_type type;
45 : : struct s2n_connection *conn;
46 : : s2n_async_pkey_validation_mode validation_mode;
47 : : unsigned complete : 1;
48 : : unsigned applied : 1;
49 : : union {
50 : : struct s2n_async_pkey_decrypt_data decrypt;
51 : : struct s2n_async_pkey_sign_data sign;
52 : : } op;
53 : : };
54 : :
55 : : struct s2n_async_pkey_op_actions {
56 : : S2N_RESULT (*perform)(struct s2n_async_pkey_op *op, s2n_cert_private_key *pkey);
57 : : S2N_RESULT (*apply)(struct s2n_async_pkey_op *op, struct s2n_connection *conn);
58 : : S2N_RESULT (*get_input_size)(struct s2n_async_pkey_op *op, uint32_t *data_len);
59 : : S2N_RESULT (*get_input)(struct s2n_async_pkey_op *op, uint8_t *data, uint32_t data_len);
60 : : S2N_RESULT (*set_output)(struct s2n_async_pkey_op *op, const uint8_t *data, uint32_t data_len);
61 : : S2N_RESULT (*free)(struct s2n_async_pkey_op *op);
62 : : };
63 : :
64 : : static S2N_RESULT s2n_async_get_actions(s2n_async_pkey_op_type type, const struct s2n_async_pkey_op_actions **actions);
65 : :
66 : : static S2N_RESULT s2n_async_pkey_op_allocate(struct s2n_async_pkey_op **op);
67 : :
68 : : static S2N_RESULT s2n_async_pkey_sign_async(struct s2n_connection *conn, s2n_signature_algorithm sig_alg,
69 : : struct s2n_hash_state *digest, s2n_async_pkey_sign_complete on_complete);
70 : : static S2N_RESULT s2n_async_pkey_sign_sync(struct s2n_connection *conn, s2n_signature_algorithm sig_alg,
71 : : struct s2n_hash_state *digest, s2n_async_pkey_sign_complete on_complete);
72 : :
73 : : static S2N_RESULT s2n_async_pkey_decrypt_async(struct s2n_connection *conn, struct s2n_blob *encrypted,
74 : : struct s2n_blob *init_decrypted,
75 : : s2n_async_pkey_decrypt_complete on_complete);
76 : : static S2N_RESULT s2n_async_pkey_decrypt_sync(struct s2n_connection *conn, struct s2n_blob *encrypted,
77 : : struct s2n_blob *init_decrypted,
78 : : s2n_async_pkey_decrypt_complete on_complete);
79 : :
80 : : static S2N_RESULT s2n_async_pkey_decrypt_perform(struct s2n_async_pkey_op *op, s2n_cert_private_key *pkey);
81 : : static S2N_RESULT s2n_async_pkey_decrypt_apply(struct s2n_async_pkey_op *op, struct s2n_connection *conn);
82 : : static S2N_RESULT s2n_async_pkey_get_input_size_decrypt(struct s2n_async_pkey_op *op, uint32_t *data_len);
83 : : static S2N_RESULT s2n_async_pkey_get_input_decrypt(struct s2n_async_pkey_op *op, uint8_t *data, uint32_t data_len);
84 : : static S2N_RESULT s2n_async_pkey_op_set_output_decrypt(struct s2n_async_pkey_op *op, const uint8_t *data, uint32_t data_len);
85 : : static S2N_RESULT s2n_async_pkey_decrypt_free(struct s2n_async_pkey_op *op);
86 : :
87 : : static S2N_RESULT s2n_async_pkey_sign_perform(struct s2n_async_pkey_op *op, s2n_cert_private_key *pkey);
88 : : static S2N_RESULT s2n_async_pkey_sign_apply(struct s2n_async_pkey_op *op, struct s2n_connection *conn);
89 : : static S2N_RESULT s2n_async_pkey_get_input_size_sign(struct s2n_async_pkey_op *op, uint32_t *data_len);
90 : : static S2N_RESULT s2n_async_pkey_get_input_sign(struct s2n_async_pkey_op *op, uint8_t *data, uint32_t data_len);
91 : : static S2N_RESULT s2n_async_pkey_op_set_output_sign(struct s2n_async_pkey_op *op, const uint8_t *data, uint32_t data_len);
92 : : static S2N_RESULT s2n_async_pkey_sign_free(struct s2n_async_pkey_op *op);
93 : :
94 : : static const struct s2n_async_pkey_op_actions s2n_async_pkey_decrypt_op = {
95 : : .perform = &s2n_async_pkey_decrypt_perform,
96 : : .apply = &s2n_async_pkey_decrypt_apply,
97 : : .get_input_size = &s2n_async_pkey_get_input_size_decrypt,
98 : : .get_input = &s2n_async_pkey_get_input_decrypt,
99 : : .set_output = &s2n_async_pkey_op_set_output_decrypt,
100 : : .free = &s2n_async_pkey_decrypt_free
101 : : };
102 : :
103 : : static const struct s2n_async_pkey_op_actions s2n_async_pkey_sign_op = {
104 : : .perform = &s2n_async_pkey_sign_perform,
105 : : .apply = &s2n_async_pkey_sign_apply,
106 : : .get_input_size = &s2n_async_pkey_get_input_size_sign,
107 : : .get_input = &s2n_async_pkey_get_input_sign,
108 : : .set_output = &s2n_async_pkey_op_set_output_sign,
109 : : .free = &s2n_async_pkey_sign_free
110 : : };
111 : :
112 : : DEFINE_POINTER_CLEANUP_FUNC(struct s2n_async_pkey_op *, s2n_async_pkey_op_free);
113 : :
114 : : static S2N_RESULT s2n_async_get_actions(s2n_async_pkey_op_type type, const struct s2n_async_pkey_op_actions **actions)
115 : 3591 : {
116 [ # # ][ - + ]: 3591 : RESULT_ENSURE_REF(actions);
117 : :
118 [ - + ]: 3591 : switch (type) {
119 [ + + ]: 3328 : case S2N_ASYNC_DECRYPT:
120 : 3328 : *actions = &s2n_async_pkey_decrypt_op;
121 : 3328 : return S2N_RESULT_OK;
122 [ + + ]: 263 : case S2N_ASYNC_SIGN:
123 : 263 : *actions = &s2n_async_pkey_sign_op;
124 : 263 : return S2N_RESULT_OK;
125 : : /* No default for compiler warnings */
126 : 3591 : }
127 : :
128 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_SAFETY);
129 : 0 : }
130 : :
131 : : static S2N_RESULT s2n_async_pkey_op_allocate(struct s2n_async_pkey_op **op)
132 : 915 : {
133 [ # # ][ - + ]: 915 : RESULT_ENSURE_REF(op);
134 [ # # ][ - + ]: 915 : RESULT_ENSURE(*op == NULL, S2N_ERR_SAFETY);
135 : :
136 : : /* allocate memory */
137 : 915 : DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free);
138 [ - + ]: 915 : RESULT_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_async_pkey_op)));
139 [ - + ]: 915 : RESULT_GUARD_POSIX(s2n_blob_zero(&mem));
140 : :
141 : 915 : *op = (void *) mem.data;
142 : 915 : ZERO_TO_DISABLE_DEFER_CLEANUP(mem);
143 : 915 : return S2N_RESULT_OK;
144 : 915 : }
145 : :
146 : : S2N_RESULT s2n_async_pkey_decrypt(struct s2n_connection *conn, struct s2n_blob *encrypted,
147 : : struct s2n_blob *init_decrypted, s2n_async_pkey_decrypt_complete on_complete)
148 : 1455 : {
149 [ # # ][ - + ]: 1455 : RESULT_ENSURE_REF(conn);
150 [ - + ][ # # ]: 1455 : RESULT_ENSURE_REF(encrypted);
151 [ - + ][ # # ]: 1455 : RESULT_ENSURE_REF(init_decrypted);
152 [ # # ][ - + ]: 1455 : RESULT_ENSURE_REF(on_complete);
153 : :
154 [ + + ]: 1455 : if (conn->config->async_pkey_cb) {
155 [ + + ]: 840 : RESULT_GUARD(s2n_async_pkey_decrypt_async(conn, encrypted, init_decrypted, on_complete));
156 : 840 : } else {
157 [ - + ]: 615 : RESULT_GUARD(s2n_async_pkey_decrypt_sync(conn, encrypted, init_decrypted, on_complete));
158 : 615 : }
159 : :
160 : 1420 : return S2N_RESULT_OK;
161 : 1455 : }
162 : :
163 : : S2N_RESULT s2n_async_cb_execute(struct s2n_connection *conn, struct s2n_async_pkey_op **owned_op)
164 : 915 : {
165 [ # # ][ - + ]: 915 : RESULT_ENSURE_REF(conn);
166 [ - + ][ # # ]: 915 : RESULT_ENSURE_REF(owned_op);
167 [ - + ][ # # ]: 915 : RESULT_ENSURE(conn->handshake.async_state == S2N_ASYNC_NOT_INVOKED, S2N_ERR_ASYNC_MORE_THAN_ONE);
168 : :
169 : : /* The callback now owns the operation, meaning we can't free it.
170 : : * Wipe our version and pass a copy to the callback.
171 : : */
172 : 915 : struct s2n_async_pkey_op *unowned_op = *owned_op;
173 : 915 : ZERO_TO_DISABLE_DEFER_CLEANUP(*owned_op);
174 : :
175 : 915 : conn->handshake.async_state = S2N_ASYNC_INVOKED;
176 [ + + ][ + - ]: 915 : RESULT_ENSURE(conn->config->async_pkey_cb(conn, unowned_op) == S2N_SUCCESS, S2N_ERR_ASYNC_CALLBACK_FAILED);
177 : :
178 : : /*
179 : : * If the callback already completed the operation, continue.
180 : : * Otherwise, we need to block s2n_negotiate and wait for the operation to complete.
181 : : */
182 [ + + ]: 914 : if (conn->handshake.async_state == S2N_ASYNC_COMPLETE) {
183 : 806 : return S2N_RESULT_OK;
184 : 806 : }
185 [ + - ]: 108 : RESULT_BAIL(S2N_ERR_ASYNC_BLOCKED);
186 : 108 : }
187 : :
188 : : S2N_RESULT s2n_async_pkey_decrypt_async(struct s2n_connection *conn, struct s2n_blob *encrypted,
189 : : struct s2n_blob *init_decrypted, s2n_async_pkey_decrypt_complete on_complete)
190 : 840 : {
191 [ - + ][ # # ]: 840 : RESULT_ENSURE_REF(conn);
192 [ # # ][ - + ]: 840 : RESULT_ENSURE_REF(encrypted);
193 [ - + ][ # # ]: 840 : RESULT_ENSURE_REF(init_decrypted);
194 [ - + ][ # # ]: 840 : RESULT_ENSURE_REF(on_complete);
195 : :
196 : 840 : DEFER_CLEANUP(struct s2n_async_pkey_op *op = NULL, s2n_async_pkey_op_free_pointer);
197 [ - + ]: 840 : RESULT_GUARD(s2n_async_pkey_op_allocate(&op));
198 : :
199 : 840 : op->type = S2N_ASYNC_DECRYPT;
200 : 840 : op->conn = conn;
201 : 840 : op->validation_mode = conn->config->async_pkey_validation_mode;
202 : :
203 : 840 : struct s2n_async_pkey_decrypt_data *decrypt = &op->op.decrypt;
204 : 840 : decrypt->on_complete = on_complete;
205 : :
206 [ - + ]: 840 : RESULT_GUARD_POSIX(s2n_dup(encrypted, &decrypt->encrypted));
207 [ - + ]: 840 : RESULT_GUARD_POSIX(s2n_dup(init_decrypted, &decrypt->decrypted));
208 : :
209 [ + + ]: 840 : RESULT_GUARD(s2n_async_cb_execute(conn, &op));
210 : 805 : return S2N_RESULT_OK;
211 : 840 : }
212 : :
213 : : S2N_RESULT s2n_async_pkey_decrypt_sync(struct s2n_connection *conn, struct s2n_blob *encrypted,
214 : : struct s2n_blob *init_decrypted, s2n_async_pkey_decrypt_complete on_complete)
215 : 615 : {
216 [ # # ][ - + ]: 615 : RESULT_ENSURE_REF(conn);
217 [ - + ][ # # ]: 615 : RESULT_ENSURE_REF(encrypted);
218 [ - + ][ # # ]: 615 : RESULT_ENSURE_REF(init_decrypted);
219 [ - + ][ # # ]: 615 : RESULT_ENSURE_REF(on_complete);
220 : :
221 : 615 : const struct s2n_pkey *pkey = conn->handshake_params.our_chain_and_key->private_key;
222 : :
223 : 615 : bool rsa_failed = s2n_pkey_decrypt(pkey, encrypted, init_decrypted) != S2N_SUCCESS;
224 [ - + ]: 615 : RESULT_GUARD_POSIX(on_complete(conn, rsa_failed, init_decrypted));
225 : :
226 : 615 : return S2N_RESULT_OK;
227 : 615 : }
228 : :
229 : : S2N_RESULT s2n_async_pkey_sign(struct s2n_connection *conn, s2n_signature_algorithm sig_alg,
230 : : struct s2n_hash_state *digest, s2n_async_pkey_sign_complete on_complete)
231 : 4416 : {
232 [ # # ][ - + ]: 4416 : RESULT_ENSURE_REF(conn);
233 [ # # ][ - + ]: 4416 : RESULT_ENSURE_REF(digest);
234 [ - + ][ # # ]: 4416 : RESULT_ENSURE_REF(on_complete);
235 : :
236 [ + + ]: 4416 : if (conn->config->async_pkey_cb) {
237 [ + + ]: 75 : RESULT_GUARD(s2n_async_pkey_sign_async(conn, sig_alg, digest, on_complete));
238 : 4341 : } else {
239 [ + + ]: 4341 : RESULT_GUARD(s2n_async_pkey_sign_sync(conn, sig_alg, digest, on_complete));
240 : 4341 : }
241 : :
242 : 4341 : return S2N_RESULT_OK;
243 : 4416 : }
244 : :
245 : : S2N_RESULT s2n_async_pkey_sign_async(struct s2n_connection *conn, s2n_signature_algorithm sig_alg,
246 : : struct s2n_hash_state *digest, s2n_async_pkey_sign_complete on_complete)
247 : 75 : {
248 [ # # ][ - + ]: 75 : RESULT_ENSURE_REF(conn);
249 [ - + ][ # # ]: 75 : RESULT_ENSURE_REF(digest);
250 [ # # ][ - + ]: 75 : RESULT_ENSURE_REF(on_complete);
251 : :
252 : 75 : DEFER_CLEANUP(struct s2n_async_pkey_op *op = NULL, s2n_async_pkey_op_free_pointer);
253 [ - + ]: 75 : RESULT_GUARD(s2n_async_pkey_op_allocate(&op));
254 : :
255 : 75 : op->type = S2N_ASYNC_SIGN;
256 : 75 : op->conn = conn;
257 : 75 : op->validation_mode = conn->config->async_pkey_validation_mode;
258 [ + + ]: 75 : if (conn->config->verify_after_sign) {
259 : 33 : op->validation_mode = S2N_ASYNC_PKEY_VALIDATION_STRICT;
260 : 33 : }
261 : :
262 : 75 : struct s2n_async_pkey_sign_data *sign = &op->op.sign;
263 : 75 : sign->on_complete = on_complete;
264 : 75 : sign->sig_alg = sig_alg;
265 : :
266 [ - + ]: 75 : RESULT_GUARD_POSIX(s2n_hash_new(&sign->digest));
267 [ - + ]: 75 : RESULT_GUARD_POSIX(s2n_hash_copy(&sign->digest, digest));
268 : :
269 [ + + ]: 75 : RESULT_GUARD(s2n_async_cb_execute(conn, &op));
270 : 1 : return S2N_RESULT_OK;
271 : 75 : }
272 : :
273 : : S2N_RESULT s2n_async_pkey_sign_sync(struct s2n_connection *conn, s2n_signature_algorithm sig_alg,
274 : : struct s2n_hash_state *digest, s2n_async_pkey_sign_complete on_complete)
275 : 4341 : {
276 [ # # ][ - + ]: 4341 : RESULT_ENSURE_REF(conn);
277 [ - + ][ # # ]: 4341 : RESULT_ENSURE_REF(digest);
278 [ # # ][ - + ]: 4341 : RESULT_ENSURE_REF(on_complete);
279 : :
280 : 4341 : const struct s2n_pkey *pkey = conn->handshake_params.our_chain_and_key->private_key;
281 : 4341 : DEFER_CLEANUP(struct s2n_blob signed_content = { 0 }, s2n_free);
282 : :
283 : 4341 : uint32_t maximum_signature_length = 0;
284 [ - + ]: 4341 : RESULT_GUARD(s2n_pkey_size(pkey, &maximum_signature_length));
285 [ - + ]: 4341 : RESULT_GUARD_POSIX(s2n_alloc(&signed_content, maximum_signature_length));
286 : :
287 [ # # ][ - + ]: 4341 : RESULT_ENSURE_REF(conn->config);
288 [ + + ]: 4341 : if (conn->config->verify_after_sign) {
289 : 33 : DEFER_CLEANUP(struct s2n_hash_state digest_for_verify = { 0 }, s2n_hash_free);
290 [ - + ]: 33 : RESULT_GUARD_POSIX(s2n_hash_new(&digest_for_verify));
291 [ - + ]: 33 : RESULT_GUARD_POSIX(s2n_hash_copy(&digest_for_verify, digest));
292 [ - + ]: 33 : RESULT_GUARD_POSIX(s2n_pkey_sign(pkey, sig_alg, digest, &signed_content));
293 [ + + ]: 33 : RESULT_GUARD(s2n_async_pkey_verify_signature(conn, sig_alg, &digest_for_verify, &signed_content));
294 : 4308 : } else {
295 [ - + ]: 4308 : RESULT_GUARD_POSIX(s2n_pkey_sign(pkey, sig_alg, digest, &signed_content));
296 : 4308 : }
297 : :
298 [ - + ]: 4340 : RESULT_GUARD_POSIX(on_complete(conn, &signed_content));
299 : :
300 : 4340 : return S2N_RESULT_OK;
301 : 4340 : }
302 : :
303 : : int s2n_async_pkey_op_perform(struct s2n_async_pkey_op *op, s2n_cert_private_key *key)
304 : 562 : {
305 [ - + ][ # # ]: 562 : POSIX_ENSURE_REF(op);
306 [ - + ][ # # ]: 562 : POSIX_ENSURE_REF(key);
307 [ + + ][ + - ]: 562 : POSIX_ENSURE(!op->complete, S2N_ERR_ASYNC_ALREADY_PERFORMED);
308 : :
309 : 490 : const struct s2n_async_pkey_op_actions *actions = NULL;
310 [ - + ]: 490 : POSIX_GUARD_RESULT(s2n_async_get_actions(op->type, &actions));
311 [ - + ][ # # ]: 490 : POSIX_ENSURE_REF(actions);
312 : :
313 [ - + ]: 490 : POSIX_GUARD_RESULT(actions->perform(op, key));
314 : :
315 : 490 : op->complete = true;
316 : :
317 : 490 : return S2N_SUCCESS;
318 : 490 : }
319 : :
320 : : int s2n_async_pkey_op_apply(struct s2n_async_pkey_op *op, struct s2n_connection *conn)
321 : 1134 : {
322 [ - + ][ # # ]: 1134 : POSIX_ENSURE_REF(op);
323 [ - + ][ # # ]: 1134 : POSIX_ENSURE_REF(conn);
324 [ + - ][ + + ]: 1134 : POSIX_ENSURE(op->complete, S2N_ERR_ASYNC_NOT_PERFORMED);
325 [ + + ][ + - ]: 1061 : POSIX_ENSURE(!op->applied, S2N_ERR_ASYNC_ALREADY_APPLIED);
326 : : /* We could have just used op->conn and removed a conn argument, but we want caller
327 : : * to be explicit about connection it wants to resume. Plus this gives more
328 : : * protections in cases if caller frees connection object and then tries to resume
329 : : * the connection. */
330 [ + + ][ + - ]: 989 : POSIX_ENSURE(op->conn == conn, S2N_ERR_ASYNC_WRONG_CONNECTION);
331 [ + + ][ + - ]: 917 : POSIX_ENSURE(conn->handshake.async_state == S2N_ASYNC_INVOKED, S2N_ERR_ASYNC_WRONG_CONNECTION);
332 : : /* s2n_async_pkey_op_apply mutates conn->handshake state that s2n_send/s2n_recv also
333 : : * access. Calling it concurrently with those methods on the same connection is undefined
334 : : * behavior. We do NOT check negotiate_in_use here because the synchronous async_pkey
335 : : * pattern legitimately invokes apply() from inside the async_pkey callback, which runs
336 : : * on the s2n_negotiate call stack (see s2n_async_pkey_sign / _decrypt). */
337 [ + + ][ + - ]: 915 : POSIX_ENSURE(!conn->send_in_use, S2N_ERR_REENTRANCY);
338 [ + - ][ + + ]: 914 : POSIX_ENSURE(!conn->recv_in_use, S2N_ERR_REENTRANCY);
339 : :
340 : 913 : const struct s2n_async_pkey_op_actions *actions = NULL;
341 [ - + ]: 913 : POSIX_GUARD_RESULT(s2n_async_get_actions(op->type, &actions));
342 [ - + ][ # # ]: 913 : POSIX_ENSURE_REF(actions);
343 : :
344 [ + + ]: 913 : POSIX_GUARD_RESULT(actions->apply(op, conn));
345 : :
346 : 910 : op->applied = true;
347 : 910 : conn->handshake.async_state = S2N_ASYNC_COMPLETE;
348 : :
349 : : /* Free up the decrypt/sign structs to avoid storing secrets for too long */
350 [ - + ]: 910 : POSIX_GUARD_RESULT(actions->free(op));
351 : :
352 : 910 : return S2N_SUCCESS;
353 : 910 : }
354 : :
355 : : int s2n_async_pkey_op_free(struct s2n_async_pkey_op *op)
356 : 915 : {
357 [ - + ][ # # ]: 915 : POSIX_ENSURE_REF(op);
358 : 915 : const struct s2n_async_pkey_op_actions *actions = NULL;
359 [ - + ]: 915 : POSIX_GUARD_RESULT(s2n_async_get_actions(op->type, &actions));
360 [ - + ][ # # ]: 915 : POSIX_ENSURE_REF(actions);
361 : :
362 : : /* If applied the decrypt/sign structs were released in apply call */
363 [ + + ]: 915 : if (!op->applied) {
364 [ - + ]: 5 : POSIX_GUARD_RESULT(actions->free(op));
365 : 5 : }
366 : :
367 [ - + ]: 915 : POSIX_GUARD(s2n_free_object((uint8_t **) &op, sizeof(struct s2n_async_pkey_op)));
368 : :
369 : 915 : return S2N_SUCCESS;
370 : 915 : }
371 : :
372 : : S2N_RESULT s2n_async_pkey_decrypt_perform(struct s2n_async_pkey_op *op, s2n_cert_private_key *pkey)
373 : 434 : {
374 [ - + ][ # # ]: 434 : RESULT_ENSURE_REF(op);
375 [ - + ][ # # ]: 434 : RESULT_ENSURE_REF(pkey);
376 : :
377 : 434 : struct s2n_async_pkey_decrypt_data *decrypt = &op->op.decrypt;
378 : :
379 : 434 : decrypt->rsa_failed = s2n_pkey_decrypt(pkey, &decrypt->encrypted, &decrypt->decrypted) != S2N_SUCCESS;
380 : :
381 : 434 : return S2N_RESULT_OK;
382 : 434 : }
383 : :
384 : : S2N_RESULT s2n_async_pkey_decrypt_apply(struct s2n_async_pkey_op *op, struct s2n_connection *conn)
385 : 838 : {
386 [ # # ][ - + ]: 838 : RESULT_ENSURE_REF(op);
387 [ - + ][ # # ]: 838 : RESULT_ENSURE_REF(conn);
388 : :
389 : 838 : struct s2n_async_pkey_decrypt_data *decrypt = &op->op.decrypt;
390 : :
391 [ - + ]: 838 : RESULT_GUARD_POSIX(decrypt->on_complete(conn, decrypt->rsa_failed, &decrypt->decrypted));
392 : :
393 : 838 : return S2N_RESULT_OK;
394 : 838 : }
395 : :
396 : : S2N_RESULT s2n_async_pkey_decrypt_free(struct s2n_async_pkey_op *op)
397 : 840 : {
398 [ # # ][ - + ]: 840 : RESULT_ENSURE_REF(op);
399 : :
400 : 840 : struct s2n_async_pkey_decrypt_data *decrypt = &op->op.decrypt;
401 : :
402 [ - + ]: 840 : RESULT_GUARD_POSIX(s2n_blob_zero(&decrypt->decrypted));
403 [ - + ]: 840 : RESULT_GUARD_POSIX(s2n_blob_zero(&decrypt->encrypted));
404 [ - + ]: 840 : RESULT_GUARD_POSIX(s2n_free(&decrypt->decrypted));
405 [ - + ]: 840 : RESULT_GUARD_POSIX(s2n_free(&decrypt->encrypted));
406 : :
407 : 840 : return S2N_RESULT_OK;
408 : 840 : }
409 : :
410 : : S2N_RESULT s2n_async_pkey_sign_perform(struct s2n_async_pkey_op *op, s2n_cert_private_key *pkey)
411 : 56 : {
412 [ - + ][ # # ]: 56 : RESULT_ENSURE_REF(op);
413 [ - + ][ # # ]: 56 : RESULT_ENSURE_REF(op->conn);
414 [ - + ][ # # ]: 56 : RESULT_ENSURE_REF(op->conn->config);
415 [ - + ][ # # ]: 56 : RESULT_ENSURE_REF(pkey);
416 : :
417 : 56 : struct s2n_async_pkey_sign_data *sign = &op->op.sign;
418 : :
419 : 56 : uint32_t maximum_signature_length = 0;
420 [ - + ]: 56 : RESULT_GUARD(s2n_pkey_size(pkey, &maximum_signature_length));
421 [ - + ]: 56 : RESULT_GUARD_POSIX(s2n_alloc(&sign->signature, maximum_signature_length));
422 : :
423 : : /* If validation mode is S2N_ASYNC_PKEY_VALIDATION_STRICT
424 : : * then use local hash copy to sign the signature */
425 [ + + ]: 56 : if (op->validation_mode == S2N_ASYNC_PKEY_VALIDATION_STRICT) {
426 : 36 : DEFER_CLEANUP(struct s2n_hash_state hash_state_copy = { 0 }, s2n_hash_free);
427 [ - + ]: 36 : RESULT_GUARD_POSIX(s2n_hash_new(&hash_state_copy));
428 [ - + ]: 36 : RESULT_GUARD_POSIX(s2n_hash_copy(&hash_state_copy, &sign->digest));
429 : :
430 [ - + ]: 36 : RESULT_GUARD_POSIX(s2n_pkey_sign(pkey, sign->sig_alg, &hash_state_copy, &sign->signature));
431 : 36 : } else {
432 [ - + ]: 20 : RESULT_GUARD_POSIX(s2n_pkey_sign(pkey, sign->sig_alg, &sign->digest, &sign->signature));
433 : 20 : }
434 : :
435 : 56 : return S2N_RESULT_OK;
436 : 56 : }
437 : :
438 : : S2N_RESULT s2n_async_pkey_sign_apply(struct s2n_async_pkey_op *op, struct s2n_connection *conn)
439 : 75 : {
440 [ - + ][ # # ]: 75 : RESULT_ENSURE_REF(op);
441 [ - + ][ # # ]: 75 : RESULT_ENSURE_REF(conn);
442 : :
443 : 75 : struct s2n_async_pkey_sign_data *sign = &op->op.sign;
444 : :
445 : : /* Perform signature validation only if validation feature is opt in */
446 [ + + ]: 75 : if (op->validation_mode == S2N_ASYNC_PKEY_VALIDATION_STRICT) {
447 [ + + ]: 36 : RESULT_GUARD(s2n_async_pkey_verify_signature(conn, sign->sig_alg, &sign->digest, &sign->signature));
448 : 36 : }
449 : :
450 [ - + ]: 72 : RESULT_GUARD_POSIX(sign->on_complete(conn, &sign->signature));
451 : :
452 : 72 : return S2N_RESULT_OK;
453 : 72 : }
454 : :
455 : : S2N_RESULT s2n_async_pkey_verify_signature(struct s2n_connection *conn, s2n_signature_algorithm sig_alg,
456 : : struct s2n_hash_state *digest, struct s2n_blob *signature)
457 : 69 : {
458 [ # # ][ - + ]: 69 : RESULT_ENSURE_REF(conn);
459 [ # # ][ - + ]: 69 : RESULT_ENSURE_REF(conn->handshake_params.our_chain_and_key);
460 [ - + ][ # # ]: 69 : RESULT_ENSURE_REF(digest);
461 [ # # ][ - + ]: 69 : RESULT_ENSURE_REF(signature);
462 : :
463 : : /* Parse public key for the cert */
464 : 69 : DEFER_CLEANUP(struct s2n_pkey public_key = { 0 }, s2n_pkey_free);
465 : 69 : s2n_pkey_type pkey_type = S2N_PKEY_TYPE_UNKNOWN;
466 [ - + ]: 69 : RESULT_GUARD(s2n_asn1der_to_public_key_and_type(&public_key, &pkey_type,
467 : 69 : &conn->handshake_params.our_chain_and_key->cert_chain->head->raw));
468 [ + - ][ + + ]: 69 : RESULT_ENSURE(s2n_pkey_verify(&public_key, sig_alg, digest, signature) == S2N_SUCCESS, S2N_ERR_VERIFY_SIGNATURE);
469 : :
470 : 65 : return S2N_RESULT_OK;
471 : 69 : }
472 : :
473 : : S2N_RESULT s2n_async_pkey_sign_free(struct s2n_async_pkey_op *op)
474 : 75 : {
475 [ # # ][ - + ]: 75 : RESULT_ENSURE_REF(op);
476 : :
477 : 75 : struct s2n_async_pkey_sign_data *sign = &op->op.sign;
478 : :
479 [ - + ]: 75 : RESULT_GUARD_POSIX(s2n_hash_free(&sign->digest));
480 [ - + ]: 75 : RESULT_GUARD_POSIX(s2n_free(&sign->signature));
481 : :
482 : 75 : return S2N_RESULT_OK;
483 : 75 : }
484 : :
485 : : int s2n_async_pkey_op_set_validation_mode(struct s2n_async_pkey_op *op, s2n_async_pkey_validation_mode mode)
486 : 3 : {
487 [ # # ][ - + ]: 3 : POSIX_ENSURE_REF(op);
488 : :
489 [ - + ]: 3 : switch (mode) {
490 [ + - ]: 3 : case S2N_ASYNC_PKEY_VALIDATION_FAST:
491 [ - + ]: 3 : case S2N_ASYNC_PKEY_VALIDATION_STRICT:
492 : 3 : op->validation_mode = mode;
493 : 3 : return S2N_SUCCESS;
494 : 3 : }
495 : :
496 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_INVALID_ARGUMENT);
497 : 0 : }
498 : :
499 : : int s2n_async_pkey_op_get_op_type(struct s2n_async_pkey_op *op, s2n_async_pkey_op_type *type)
500 : 830 : {
501 [ - + ][ # # ]: 830 : POSIX_ENSURE_REF(op);
502 [ + + ][ + - ]: 830 : POSIX_ENSURE_REF(type);
503 : :
504 : 829 : *type = op->type;
505 : :
506 : 829 : return S2N_SUCCESS;
507 : 830 : }
508 : :
509 : : int s2n_async_pkey_op_get_input_size(struct s2n_async_pkey_op *op, uint32_t *data_len)
510 : 424 : {
511 [ - + ][ # # ]: 424 : POSIX_ENSURE_REF(op);
512 [ + + ][ + - ]: 424 : POSIX_ENSURE_REF(data_len);
513 : :
514 : 423 : const struct s2n_async_pkey_op_actions *actions = NULL;
515 [ - + ]: 423 : POSIX_GUARD_RESULT(s2n_async_get_actions(op->type, &actions));
516 [ - + ][ # # ]: 423 : POSIX_ENSURE_REF(actions);
517 : :
518 [ - + ]: 423 : POSIX_GUARD_RESULT(actions->get_input_size(op, data_len));
519 : :
520 : 423 : return S2N_SUCCESS;
521 : 423 : }
522 : :
523 : : static S2N_RESULT s2n_async_pkey_get_input_size_decrypt(struct s2n_async_pkey_op *op, uint32_t *data_len)
524 : 405 : {
525 [ # # ][ - + ]: 405 : RESULT_ENSURE_REF(op);
526 [ - + ][ # # ]: 405 : RESULT_ENSURE_REF(data_len);
527 : :
528 : 405 : struct s2n_async_pkey_decrypt_data *decrypt = &op->op.decrypt;
529 : 405 : struct s2n_blob *in = &decrypt->encrypted;
530 : :
531 : 405 : *data_len = in->size;
532 : 405 : return S2N_RESULT_OK;
533 : 405 : }
534 : :
535 : : static S2N_RESULT s2n_async_pkey_get_input_size_sign(struct s2n_async_pkey_op *op, uint32_t *data_len)
536 : 18 : {
537 [ - + ][ # # ]: 18 : RESULT_ENSURE_REF(op);
538 [ # # ][ - + ]: 18 : RESULT_ENSURE_REF(data_len);
539 : :
540 : 18 : struct s2n_async_pkey_sign_data *sign = &op->op.sign;
541 : 18 : struct s2n_hash_state *digest = &sign->digest;
542 : :
543 : 18 : uint8_t digest_length = 0;
544 [ - + ]: 18 : RESULT_GUARD_POSIX(s2n_hash_digest_size(digest->alg, &digest_length));
545 : :
546 : 18 : *data_len = digest_length;
547 : :
548 : 18 : return S2N_RESULT_OK;
549 : 18 : }
550 : :
551 : : int s2n_async_pkey_op_get_input(struct s2n_async_pkey_op *op, uint8_t *data, uint32_t data_len)
552 : 429 : {
553 [ - + ][ # # ]: 429 : POSIX_ENSURE_REF(op);
554 [ + - ][ + + ]: 429 : POSIX_ENSURE_REF(data);
555 : :
556 : 428 : const struct s2n_async_pkey_op_actions *actions = NULL;
557 [ - + ]: 428 : POSIX_GUARD_RESULT(s2n_async_get_actions(op->type, &actions));
558 [ - + ][ # # ]: 428 : POSIX_ENSURE_REF(actions);
559 : :
560 [ + + ]: 428 : POSIX_GUARD_RESULT(actions->get_input(op, data, data_len));
561 : :
562 : 427 : return S2N_SUCCESS;
563 : 428 : }
564 : :
565 : : static S2N_RESULT s2n_async_pkey_get_input_decrypt(struct s2n_async_pkey_op *op, uint8_t *data, uint32_t data_len)
566 : 406 : {
567 [ # # ][ - + ]: 406 : RESULT_ENSURE_REF(op);
568 [ # # ][ - + ]: 406 : RESULT_ENSURE_REF(data);
569 : :
570 : 406 : struct s2n_async_pkey_decrypt_data *decrypt = &op->op.decrypt;
571 : 406 : struct s2n_blob *in = &decrypt->encrypted;
572 : :
573 [ # # ][ - + ]: 406 : RESULT_ENSURE_LTE(in->size, data_len);
574 : :
575 [ # # ][ - + ]: 406 : RESULT_CHECKED_MEMCPY(data, in->data, in->size);
[ + - ]
576 : :
577 : 406 : return S2N_RESULT_OK;
578 : 406 : }
579 : :
580 : : static S2N_RESULT s2n_async_pkey_get_input_sign(struct s2n_async_pkey_op *op, uint8_t *data, uint32_t data_len)
581 : 22 : {
582 [ - + ][ # # ]: 22 : RESULT_ENSURE_REF(op);
583 [ # # ][ - + ]: 22 : RESULT_ENSURE_REF(data);
584 : :
585 : 22 : struct s2n_async_pkey_sign_data *sign = &op->op.sign;
586 : :
587 : 22 : DEFER_CLEANUP(struct s2n_hash_state digest_copy = { 0 }, s2n_hash_free);
588 [ - + ]: 22 : RESULT_GUARD_POSIX(s2n_hash_new(&digest_copy));
589 [ - + ]: 22 : RESULT_GUARD_POSIX(s2n_hash_copy(&digest_copy, &sign->digest));
590 : :
591 : 22 : uint8_t digest_length = 0;
592 : :
593 [ - + ]: 22 : RESULT_GUARD_POSIX(s2n_hash_digest_size(digest_copy.alg, &digest_length));
594 : :
595 [ + + ][ + - ]: 22 : RESULT_ENSURE_LTE(digest_length, data_len);
596 [ - + ]: 21 : RESULT_GUARD_POSIX(s2n_hash_digest(&digest_copy, data, digest_length));
597 : :
598 : 21 : return S2N_RESULT_OK;
599 : 21 : }
600 : :
601 : : int s2n_async_pkey_op_set_output(struct s2n_async_pkey_op *op, const uint8_t *data, uint32_t data_len)
602 : 423 : {
603 [ # # ][ - + ]: 423 : POSIX_ENSURE_REF(op);
604 [ + + ][ + - ]: 423 : POSIX_ENSURE_REF(data);
605 : :
606 : 422 : const struct s2n_async_pkey_op_actions *actions = NULL;
607 [ - + ]: 422 : POSIX_GUARD_RESULT(s2n_async_get_actions(op->type, &actions));
608 [ # # ][ - + ]: 422 : POSIX_ENSURE_REF(actions);
609 : :
610 [ - + ]: 422 : POSIX_GUARD_RESULT(actions->set_output(op, data, data_len));
611 : 422 : op->complete = true;
612 : :
613 : 422 : return S2N_SUCCESS;
614 : 422 : }
615 : :
616 : : static S2N_RESULT s2n_async_pkey_op_set_output_decrypt(struct s2n_async_pkey_op *op, const uint8_t *data, uint32_t data_len)
617 : 405 : {
618 [ - + ][ # # ]: 405 : RESULT_ENSURE_REF(op);
619 [ # # ][ - + ]: 405 : RESULT_ENSURE_REF(data);
620 : :
621 : 405 : struct s2n_async_pkey_decrypt_data *decrypt = &op->op.decrypt;
622 : 405 : struct s2n_blob *out = &decrypt->decrypted;
623 : :
624 [ - + ]: 405 : RESULT_GUARD_POSIX(s2n_realloc(out, data_len));
625 [ # # ][ - + ]: 405 : RESULT_CHECKED_MEMCPY(out->data, data, data_len);
[ + - ]
626 : :
627 : 405 : return S2N_RESULT_OK;
628 : 405 : }
629 : :
630 : : static S2N_RESULT s2n_async_pkey_op_set_output_sign(struct s2n_async_pkey_op *op, const uint8_t *data, uint32_t data_len)
631 : 17 : {
632 [ # # ][ - + ]: 17 : RESULT_ENSURE_REF(op);
633 [ # # ][ - + ]: 17 : RESULT_ENSURE_REF(data);
634 : :
635 : 17 : struct s2n_async_pkey_sign_data *sign = &op->op.sign;
636 : 17 : struct s2n_blob *sigcopy = &sign->signature;
637 : :
638 [ - + ]: 17 : RESULT_GUARD_POSIX(s2n_realloc(sigcopy, data_len));
639 [ - + ][ # # ]: 17 : RESULT_CHECKED_MEMCPY(sigcopy->data, data, data_len);
[ + - ]
640 : :
641 : 17 : return S2N_RESULT_OK;
642 : 17 : }
643 : :
644 : : S2N_RESULT s2n_async_pkey_op_copy_hash_state_for_testing(struct s2n_async_pkey_op *op,
645 : : struct s2n_hash_state *copy)
646 : 26 : {
647 [ # # ][ - + ]: 26 : RESULT_ENSURE_REF(op);
648 [ # # ][ - + ]: 26 : RESULT_ENSURE_EQ(op->type, S2N_ASYNC_SIGN);
649 [ - + ]: 26 : RESULT_GUARD_POSIX(s2n_hash_copy(copy, &op->op.sign.digest));
650 : 26 : return S2N_RESULT_OK;
651 : 26 : }
652 : :
653 : : static S2N_RESULT s2n_async_pkey_verify_data_free(struct s2n_async_offload_op *op)
654 : 13 : {
655 [ # # ][ - + ]: 13 : RESULT_ENSURE_REF(op);
656 [ # # ][ - + ]: 13 : RESULT_ENSURE_EQ(op->type, S2N_ASYNC_OFFLOAD_PKEY_VERIFY);
657 : :
658 : 13 : struct s2n_async_pkey_verify_data *verify = &op->op_data.async_pkey_verify;
659 [ - + ]: 13 : RESULT_GUARD_POSIX(s2n_hash_free(&verify->digest));
660 [ - + ]: 13 : RESULT_GUARD_POSIX(s2n_free(&verify->signature));
661 : :
662 : 13 : return S2N_RESULT_OK;
663 : 13 : }
664 : :
665 : : static S2N_RESULT s2n_async_pkey_verify_perform(struct s2n_async_offload_op *op)
666 : 13 : {
667 [ - + ][ # # ]: 13 : RESULT_ENSURE_REF(op);
668 [ # # ][ - + ]: 13 : RESULT_ENSURE_REF(op->conn);
669 [ - + ][ # # ]: 13 : RESULT_ENSURE_EQ(op->type, S2N_ASYNC_OFFLOAD_PKEY_VERIFY);
670 : :
671 : 13 : struct s2n_pkey *pub_key = NULL;
672 [ + + ]: 13 : if (op->conn->mode == S2N_CLIENT) {
673 : 8 : pub_key = &op->conn->handshake_params.server_public_key;
674 : 8 : } else {
675 : 5 : pub_key = &op->conn->handshake_params.client_public_key;
676 : 5 : }
677 : :
678 : 13 : struct s2n_async_pkey_verify_data *verify = &op->op_data.async_pkey_verify;
679 [ - + ][ # # ]: 13 : RESULT_ENSURE(s2n_pkey_verify(pub_key, verify->sig_alg, &verify->digest, &verify->signature) == S2N_SUCCESS,
680 : 13 : S2N_ERR_VERIFY_SIGNATURE);
681 : :
682 : 13 : return S2N_RESULT_OK;
683 : 13 : }
684 : :
685 : : static S2N_RESULT s2n_async_pkey_verify_async(struct s2n_connection *conn, s2n_signature_algorithm sig_alg,
686 : : struct s2n_hash_state *digest, struct s2n_blob *signature)
687 : 13 : {
688 [ - + ][ # # ]: 13 : RESULT_ENSURE_REF(conn);
689 [ - + ][ # # ]: 13 : RESULT_ENSURE_REF(digest);
690 [ - + ][ # # ]: 13 : RESULT_ENSURE_REF(signature);
691 : :
692 : 13 : struct s2n_async_offload_op *op = &conn->async_offload_op;
693 : 13 : op->conn = conn;
694 : 13 : op->type = S2N_ASYNC_OFFLOAD_PKEY_VERIFY;
695 : 13 : op->perform = s2n_async_pkey_verify_perform;
696 : 13 : op->op_data_free = s2n_async_pkey_verify_data_free;
697 : :
698 : 13 : struct s2n_async_pkey_verify_data *verify = &op->op_data.async_pkey_verify;
699 : 13 : verify->sig_alg = sig_alg;
700 : :
701 [ - + ]: 13 : RESULT_GUARD_POSIX(s2n_hash_new(&verify->digest));
702 [ - + ]: 13 : RESULT_GUARD_POSIX(s2n_hash_copy(&verify->digest, digest));
703 [ - + ]: 13 : RESULT_GUARD_POSIX(s2n_dup(signature, &verify->signature));
704 : :
705 [ + + ]: 13 : RESULT_GUARD(s2n_async_offload_cb_invoke(conn, op));
706 : 4 : return S2N_RESULT_OK;
707 : 13 : }
708 : :
709 : : int s2n_async_pkey_verify(struct s2n_connection *conn, s2n_signature_algorithm sig_alg,
710 : : struct s2n_hash_state *digest, struct s2n_blob *signature)
711 : 3513 : {
712 [ # # ][ - + ]: 3513 : POSIX_ENSURE_REF(conn);
713 [ # # ][ - + ]: 3513 : POSIX_ENSURE_REF(digest);
714 [ - + ][ # # ]: 3513 : POSIX_ENSURE_REF(signature);
715 : :
716 : 3513 : struct s2n_pkey *pub_key = NULL;
717 [ + + ]: 3513 : if (conn->mode == S2N_CLIENT) {
718 : 3368 : pub_key = &conn->handshake_params.server_public_key;
719 : 3368 : } else {
720 : 145 : pub_key = &conn->handshake_params.client_public_key;
721 : 145 : }
722 : :
723 [ + + ]: 3513 : if (s2n_async_offload_op_is_in_allow_list(conn->config, S2N_ASYNC_OFFLOAD_PKEY_VERIFY)) {
724 [ + + ]: 13 : POSIX_GUARD_RESULT(s2n_async_pkey_verify_async(conn, sig_alg, digest, signature));
725 : 3500 : } else {
726 [ + + ]: 3500 : POSIX_GUARD(s2n_pkey_verify(pub_key, sig_alg, digest, signature));
727 : 3500 : }
728 : :
729 : 3486 : return S2N_SUCCESS;
730 : 3513 : }
|