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_hkdf.h"
17 : :
18 : : #include "crypto/s2n_fips.h"
19 : : #include "crypto/s2n_hmac.h"
20 : : #include "error/s2n_errno.h"
21 : : #include "stuffer/s2n_stuffer.h"
22 : : #include "utils/s2n_blob.h"
23 : : #include "utils/s2n_mem.h"
24 : : #include "utils/s2n_safety.h"
25 : :
26 : : #ifdef S2N_LIBCRYPTO_SUPPORTS_HKDF
27 : : #include <openssl/hkdf.h>
28 : : #endif
29 : :
30 : : #define MAX_DIGEST_SIZE 64 /* Current highest is SHA512 */
31 : : #define MAX_HKDF_ROUNDS 255
32 : :
33 : : /* Reference: RFC 5869 */
34 : :
35 : : struct s2n_hkdf_impl {
36 : : int (*hkdf)(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt,
37 : : const struct s2n_blob *key, const struct s2n_blob *info, struct s2n_blob *output);
38 : : int (*hkdf_extract)(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt,
39 : : const struct s2n_blob *key, struct s2n_blob *pseudo_rand_key);
40 : : int (*hkdf_expand)(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *pseudo_rand_key,
41 : : const struct s2n_blob *info, struct s2n_blob *output);
42 : : };
43 : :
44 : : static int s2n_custom_hkdf_extract(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt,
45 : : const struct s2n_blob *key, struct s2n_blob *pseudo_rand_key)
46 : 39482 : {
47 : 39482 : uint8_t hmac_size = 0;
48 [ - + ]: 39482 : POSIX_GUARD(s2n_hmac_digest_size(alg, &hmac_size));
49 [ + + ][ + - ]: 39482 : POSIX_ENSURE(hmac_size <= pseudo_rand_key->size, S2N_ERR_HKDF_OUTPUT_SIZE);
50 : 39481 : pseudo_rand_key->size = hmac_size;
51 : :
52 [ - + ]: 39481 : POSIX_GUARD(s2n_hmac_init(hmac, alg, salt->data, salt->size));
53 [ - + ]: 39481 : POSIX_GUARD(s2n_hmac_update(hmac, key->data, key->size));
54 [ - + ]: 39481 : POSIX_GUARD(s2n_hmac_digest(hmac, pseudo_rand_key->data, pseudo_rand_key->size));
55 : :
56 [ - + ]: 39481 : POSIX_GUARD(s2n_hmac_reset(hmac));
57 : :
58 : 39481 : return S2N_SUCCESS;
59 : 39481 : }
60 : :
61 : : static int s2n_custom_hkdf_expand(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg,
62 : : const struct s2n_blob *pseudo_rand_key, const struct s2n_blob *info, struct s2n_blob *output)
63 : 141500 : {
64 : 141500 : uint8_t prev[MAX_DIGEST_SIZE] = { 0 };
65 : :
66 : 141500 : uint32_t done_len = 0;
67 : 141500 : uint8_t hash_len = 0;
68 [ - + ]: 141500 : POSIX_GUARD(s2n_hmac_digest_size(alg, &hash_len));
69 [ - + ][ # # ]: 141500 : POSIX_ENSURE_GT(hash_len, 0);
70 : 141500 : uint32_t total_rounds = output->size / hash_len;
71 [ + + ]: 141500 : if (output->size % hash_len) {
72 : 58858 : total_rounds++;
73 : 58858 : }
74 : :
75 [ + + ][ + - ]: 141500 : POSIX_ENSURE(total_rounds > 0, S2N_ERR_HKDF_OUTPUT_SIZE);
76 [ + + ][ + - ]: 141499 : POSIX_ENSURE(total_rounds <= MAX_HKDF_ROUNDS, S2N_ERR_HKDF_OUTPUT_SIZE);
77 : :
78 [ + + ]: 283159 : for (uint32_t curr_round = 1; curr_round <= total_rounds; curr_round++) {
79 : 141661 : uint32_t cat_len = 0;
80 [ - + ]: 141661 : POSIX_GUARD(s2n_hmac_init(hmac, alg, pseudo_rand_key->data, pseudo_rand_key->size));
81 [ + + ]: 141661 : if (curr_round != 1) {
82 [ - + ]: 163 : POSIX_GUARD(s2n_hmac_update(hmac, prev, hash_len));
83 : 163 : }
84 [ - + ]: 141661 : POSIX_GUARD(s2n_hmac_update(hmac, info->data, info->size));
85 [ - + ]: 141661 : POSIX_GUARD(s2n_hmac_update(hmac, &curr_round, 1));
86 [ - + ]: 141661 : POSIX_GUARD(s2n_hmac_digest(hmac, prev, hash_len));
87 : :
88 : 141661 : cat_len = hash_len;
89 [ + + ]: 141661 : if (done_len + hash_len > output->size) {
90 : 58857 : cat_len = output->size - done_len;
91 : 58857 : }
92 : :
93 [ - + ][ # # ]: 141661 : POSIX_CHECKED_MEMCPY(output->data + done_len, prev, cat_len);
[ + - ]
94 : :
95 : 141661 : done_len += cat_len;
96 : :
97 [ - + ]: 141661 : POSIX_GUARD(s2n_hmac_reset(hmac));
98 : 141661 : }
99 : :
100 : 141498 : return S2N_SUCCESS;
101 : 141498 : }
102 : :
103 : : static int s2n_custom_hkdf(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt,
104 : : const struct s2n_blob *key, const struct s2n_blob *info, struct s2n_blob *output)
105 : 765 : {
106 : 765 : uint8_t prk_pad[MAX_DIGEST_SIZE] = { 0 };
107 : 765 : struct s2n_blob pseudo_rand_key = { 0 };
108 [ - + ]: 765 : POSIX_GUARD(s2n_blob_init(&pseudo_rand_key, prk_pad, sizeof(prk_pad)));
109 : :
110 [ - + ]: 765 : POSIX_GUARD(s2n_custom_hkdf_extract(hmac, alg, salt, key, &pseudo_rand_key));
111 [ + + ]: 765 : POSIX_GUARD(s2n_custom_hkdf_expand(hmac, alg, &pseudo_rand_key, info, output));
112 : :
113 : 763 : return S2N_SUCCESS;
114 : 765 : }
115 : :
116 : : const struct s2n_hkdf_impl s2n_custom_hkdf_impl = {
117 : : .hkdf = &s2n_custom_hkdf,
118 : : .hkdf_extract = &s2n_custom_hkdf_extract,
119 : : .hkdf_expand = &s2n_custom_hkdf_expand,
120 : : };
121 : :
122 : : #ifdef S2N_LIBCRYPTO_SUPPORTS_HKDF
123 : : static int s2n_libcrypto_hkdf_extract(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt,
124 : : const struct s2n_blob *key, struct s2n_blob *pseudo_rand_key)
125 : : {
126 : : const EVP_MD *digest = NULL;
127 : : POSIX_GUARD_RESULT(s2n_hmac_md_from_alg(alg, &digest));
128 : :
129 : : /* The out_len argument of HKDF_extract is set to the number of bytes written to out_key, and
130 : : * is not used to ensure that out_key is large enough to contain the PRK. Ensure that the PRK
131 : : * output will fit in the blob.
132 : : */
133 : : uint8_t hmac_size = 0;
134 : : POSIX_GUARD(s2n_hmac_digest_size(alg, &hmac_size));
135 : : POSIX_ENSURE(hmac_size <= pseudo_rand_key->size, S2N_ERR_HKDF_OUTPUT_SIZE);
136 : :
137 : : size_t bytes_written = 0;
138 : : POSIX_GUARD_OSSL(HKDF_extract(pseudo_rand_key->data, &bytes_written, digest, key->data, key->size,
139 : : salt->data, salt->size),
140 : : S2N_ERR_HKDF);
141 : :
142 : : /* HKDF_extract updates the out_len argument based on the digest size. Update the blob's size based on this. */
143 : : POSIX_ENSURE_LTE(bytes_written, pseudo_rand_key->size);
144 : : pseudo_rand_key->size = bytes_written;
145 : :
146 : : return S2N_SUCCESS;
147 : : }
148 : :
149 : : static int s2n_libcrypto_hkdf_expand(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg,
150 : : const struct s2n_blob *pseudo_rand_key, const struct s2n_blob *info, struct s2n_blob *output)
151 : : {
152 : : POSIX_ENSURE(output->size > 0, S2N_ERR_HKDF_OUTPUT_SIZE);
153 : :
154 : : const EVP_MD *digest = NULL;
155 : : POSIX_GUARD_RESULT(s2n_hmac_md_from_alg(alg, &digest));
156 : :
157 : : POSIX_GUARD_OSSL(HKDF_expand(output->data, output->size, digest, pseudo_rand_key->data, pseudo_rand_key->size,
158 : : info->data, info->size),
159 : : S2N_ERR_HKDF);
160 : :
161 : : return S2N_SUCCESS;
162 : : }
163 : :
164 : : static int s2n_libcrypto_hkdf(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt,
165 : : const struct s2n_blob *key, const struct s2n_blob *info, struct s2n_blob *output)
166 : : {
167 : : POSIX_ENSURE(output->size > 0, S2N_ERR_HKDF_OUTPUT_SIZE);
168 : :
169 : : const EVP_MD *digest = NULL;
170 : : POSIX_GUARD_RESULT(s2n_hmac_md_from_alg(alg, &digest));
171 : :
172 : : POSIX_GUARD_OSSL(HKDF(output->data, output->size, digest, key->data, key->size, salt->data, salt->size,
173 : : info->data, info->size),
174 : : S2N_ERR_HKDF);
175 : :
176 : : return S2N_SUCCESS;
177 : : }
178 : :
179 : : bool s2n_libcrypto_supports_hkdf()
180 : : {
181 : : return true;
182 : : }
183 : :
184 : : #elif S2N_OPENSSL_VERSION_AT_LEAST(3, 0, 0)
185 : :
186 : : #include "crypto/s2n_kdf.h"
187 : :
188 : : static S2N_RESULT s2n_hkdf_kdf(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg,
189 : : const struct s2n_blob *salt, const struct s2n_blob *key, const struct s2n_blob *info,
190 : : struct s2n_blob *output, int mode)
191 : 0 : {
192 : : /* As an optimization, we should be able to fetch and cache this EVP_KDF*
193 : : * once when s2n_init is called.
194 : : */
195 : 0 : DEFER_CLEANUP(EVP_KDF *hkdf_impl = EVP_KDF_fetch(NULL, "HKDF", NULL),
196 : 0 : EVP_KDF_free_pointer);
197 [ # # ][ # # ]: 0 : RESULT_ENSURE(hkdf_impl, S2N_ERR_PRF_INVALID_ALGORITHM);
198 : :
199 : 0 : DEFER_CLEANUP(EVP_KDF_CTX *hkdf_ctx = EVP_KDF_CTX_new(hkdf_impl),
200 : 0 : EVP_KDF_CTX_free_pointer);
201 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(hkdf_ctx);
202 : :
203 : 0 : const EVP_MD *digest = NULL;
204 [ # # ]: 0 : RESULT_GUARD(s2n_hmac_md_from_alg(alg, &digest));
205 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(digest);
206 : 0 : const char *digest_name = EVP_MD_get0_name(digest);
207 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(digest_name);
208 : :
209 : 0 : OSSL_PARAM params[] = {
210 : 0 : S2N_OSSL_PARAM_INT(OSSL_KDF_PARAM_MODE, mode),
211 : 0 : S2N_OSSL_PARAM_BLOB(OSSL_KDF_PARAM_KEY, key),
212 : 0 : S2N_OSSL_PARAM_BLOB(OSSL_KDF_PARAM_INFO, info),
213 : 0 : S2N_OSSL_PARAM_BLOB(OSSL_KDF_PARAM_SALT, salt),
214 : : /* Casting away the const is safe because providers are forbidden from
215 : : * modifying any OSSL_PARAM value other than return_size.
216 : : * Even the examples in the Openssl documentation cast const strings to
217 : : * non-const void pointers when setting up OSSL_PARAMs.
218 : : */
219 : 0 : S2N_OSSL_PARAM_STR(OSSL_KDF_PARAM_DIGEST, (void *) (uintptr_t) digest_name),
220 : 0 : OSSL_PARAM_END,
221 : 0 : };
222 : :
223 : : /* From the HKDF docs (https://docs.openssl.org/3.1/man7/EVP_KDF-HKDF/):
224 : : * > When using EVP_KDF_HKDF_MODE_EXTRACT_ONLY the keylen parameter must equal
225 : : * > the size of the intermediate fixed-length pseudorandom key otherwise an
226 : : * > error will occur.
227 : : */
228 [ # # ]: 0 : if (mode == EVP_KDF_HKDF_MODE_EXTRACT_ONLY) {
229 [ # # ][ # # ]: 0 : RESULT_GUARD_OSSL(EVP_KDF_CTX_set_params(hkdf_ctx, params), S2N_ERR_HKDF);
230 : 0 : size_t key_size = EVP_KDF_CTX_get_kdf_size(hkdf_ctx);
231 [ # # ][ # # ]: 0 : RESULT_ENSURE(key_size > 0, S2N_ERR_HKDF_OUTPUT_SIZE);
232 [ # # ][ # # ]: 0 : RESULT_ENSURE(key_size <= output->size, S2N_ERR_HKDF_OUTPUT_SIZE);
233 : 0 : output->size = key_size;
234 : 0 : }
235 : :
236 [ # # ][ # # ]: 0 : RESULT_GUARD_OSSL(EVP_KDF_derive(hkdf_ctx, output->data, output->size, params),
237 : 0 : S2N_ERR_HKDF);
238 : 0 : return S2N_RESULT_OK;
239 : 0 : }
240 : :
241 : : static int s2n_libcrypto_hkdf_extract(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg,
242 : : const struct s2n_blob *salt, const struct s2n_blob *key, struct s2n_blob *pseudo_rand_key)
243 : 0 : {
244 : 0 : struct s2n_blob empty_info = { 0 };
245 [ # # ]: 0 : POSIX_GUARD_RESULT(s2n_hkdf_kdf(hmac, alg, salt, key, &empty_info, pseudo_rand_key,
246 : 0 : EVP_KDF_HKDF_MODE_EXTRACT_ONLY));
247 : 0 : return S2N_SUCCESS;
248 : 0 : }
249 : :
250 : : static int s2n_libcrypto_hkdf_expand(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg,
251 : : const struct s2n_blob *pseudo_rand_key, const struct s2n_blob *info, struct s2n_blob *output)
252 : 0 : {
253 : 0 : struct s2n_blob empty_salt = { 0 };
254 [ # # ]: 0 : POSIX_GUARD_RESULT(s2n_hkdf_kdf(hmac, alg, &empty_salt, pseudo_rand_key, info, output,
255 : 0 : EVP_KDF_HKDF_MODE_EXPAND_ONLY));
256 : 0 : return S2N_SUCCESS;
257 : 0 : }
258 : :
259 : : static int s2n_libcrypto_hkdf(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt,
260 : : const struct s2n_blob *key, const struct s2n_blob *info, struct s2n_blob *output)
261 : 0 : {
262 [ # # ]: 0 : POSIX_GUARD_RESULT(s2n_hkdf_kdf(hmac, alg, salt, key, info, output,
263 : 0 : EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND));
264 : 0 : return S2N_SUCCESS;
265 : 0 : }
266 : :
267 : : bool s2n_libcrypto_supports_hkdf()
268 : 0 : {
269 : 0 : return true;
270 : 0 : }
271 : :
272 : : #else
273 : :
274 : : static int s2n_libcrypto_hkdf_extract(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt,
275 : : const struct s2n_blob *key, struct s2n_blob *pseudo_rand_key)
276 : : {
277 : : POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
278 : : }
279 : :
280 : : static int s2n_libcrypto_hkdf_expand(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg,
281 : : const struct s2n_blob *pseudo_rand_key, const struct s2n_blob *info, struct s2n_blob *output)
282 : : {
283 : : POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
284 : : }
285 : :
286 : : static int s2n_libcrypto_hkdf(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt,
287 : : const struct s2n_blob *key, const struct s2n_blob *info, struct s2n_blob *output)
288 : : {
289 : : POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
290 : : }
291 : :
292 : : bool s2n_libcrypto_supports_hkdf()
293 : : {
294 : : return false;
295 : : }
296 : :
297 : : #endif /* S2N_LIBCRYPTO_SUPPORTS_HKDF */
298 : :
299 : : const struct s2n_hkdf_impl s2n_libcrypto_hkdf_impl = {
300 : : .hkdf = &s2n_libcrypto_hkdf,
301 : : .hkdf_extract = &s2n_libcrypto_hkdf_extract,
302 : : .hkdf_expand = &s2n_libcrypto_hkdf_expand,
303 : : };
304 : :
305 : : static const struct s2n_hkdf_impl *s2n_get_hkdf_implementation()
306 : 180217 : {
307 : : /* By default, s2n-tls uses a custom HKDF implementation. When operating in FIPS mode, the
308 : : * FIPS-validated libcrypto implementation is used instead, if an implementation is provided.
309 : : */
310 [ - + ][ # # ]: 180217 : if (s2n_is_in_fips_mode() && s2n_libcrypto_supports_hkdf()) {
311 : 0 : return &s2n_libcrypto_hkdf_impl;
312 : 0 : }
313 : :
314 : 180217 : return &s2n_custom_hkdf_impl;
315 : 180217 : }
316 : :
317 : : int s2n_hkdf_extract(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt,
318 : : const struct s2n_blob *key, struct s2n_blob *pseudo_rand_key)
319 : 38717 : {
320 [ - + ][ # # ]: 38717 : POSIX_ENSURE_REF(hmac);
321 [ - + ][ # # ]: 38717 : POSIX_ENSURE_REF(salt);
322 [ - + ][ # # ]: 38717 : POSIX_ENSURE_REF(key);
323 [ - + ][ # # ]: 38717 : POSIX_ENSURE_REF(pseudo_rand_key);
324 : :
325 : 38717 : const struct s2n_hkdf_impl *hkdf_implementation = s2n_get_hkdf_implementation();
326 [ # # ][ - + ]: 38717 : POSIX_ENSURE_REF(hkdf_implementation);
327 : :
328 [ + + ]: 38717 : POSIX_GUARD(hkdf_implementation->hkdf_extract(hmac, alg, salt, key, pseudo_rand_key));
329 : :
330 : 38716 : return S2N_SUCCESS;
331 : 38717 : }
332 : :
333 : : static int s2n_hkdf_expand(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *pseudo_rand_key,
334 : : const struct s2n_blob *info, struct s2n_blob *output)
335 : 140735 : {
336 [ # # ][ - + ]: 140735 : POSIX_ENSURE_REF(hmac);
337 [ - + ][ # # ]: 140735 : POSIX_ENSURE_REF(pseudo_rand_key);
338 [ # # ][ - + ]: 140735 : POSIX_ENSURE_REF(info);
339 [ - + ][ # # ]: 140735 : POSIX_ENSURE_REF(output);
340 : :
341 : 140735 : const struct s2n_hkdf_impl *hkdf_implementation = s2n_get_hkdf_implementation();
342 [ - + ][ # # ]: 140735 : POSIX_ENSURE_REF(hkdf_implementation);
343 : :
344 [ - + ]: 140735 : POSIX_GUARD(hkdf_implementation->hkdf_expand(hmac, alg, pseudo_rand_key, info, output));
345 : :
346 : 140735 : return S2N_SUCCESS;
347 : 140735 : }
348 : :
349 : : int s2n_hkdf_expand_label(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *secret, const struct s2n_blob *label,
350 : : const struct s2n_blob *context, struct s2n_blob *output)
351 : 140735 : {
352 [ # # ][ - + ]: 140735 : POSIX_ENSURE_REF(label);
353 [ - + ][ # # ]: 140735 : POSIX_ENSURE_REF(context);
354 [ # # ][ - + ]: 140735 : POSIX_ENSURE_REF(output);
355 : :
356 : : /* Per RFC8446: 7.1, a HKDF label is a 2 byte length field, and two 1...255 byte arrays with a one byte length field each. */
357 : 140735 : uint8_t hkdf_label_buf[2 + 256 + 256];
358 : 140735 : struct s2n_blob hkdf_label_blob = { 0 };
359 : 140735 : struct s2n_stuffer hkdf_label = { 0 };
360 : :
361 [ - + ][ # # ]: 140735 : POSIX_ENSURE_LTE(label->size, S2N_MAX_HKDF_EXPAND_LABEL_LENGTH);
362 : :
363 [ - + ]: 140735 : POSIX_GUARD(s2n_blob_init(&hkdf_label_blob, hkdf_label_buf, sizeof(hkdf_label_buf)));
364 [ - + ]: 140735 : POSIX_GUARD(s2n_stuffer_init(&hkdf_label, &hkdf_label_blob));
365 [ - + ]: 140735 : POSIX_GUARD(s2n_stuffer_write_uint16(&hkdf_label, output->size));
366 [ - + ]: 140735 : POSIX_GUARD(s2n_stuffer_write_uint8(&hkdf_label, label->size + sizeof("tls13 ") - 1));
367 [ - + ]: 140735 : POSIX_GUARD(s2n_stuffer_write_str(&hkdf_label, "tls13 "));
368 [ - + ]: 140735 : POSIX_GUARD(s2n_stuffer_write(&hkdf_label, label));
369 [ - + ]: 140735 : POSIX_GUARD(s2n_stuffer_write_uint8(&hkdf_label, context->size));
370 [ - + ]: 140735 : POSIX_GUARD(s2n_stuffer_write(&hkdf_label, context));
371 : :
372 : 140735 : hkdf_label_blob.size = s2n_stuffer_data_available(&hkdf_label);
373 [ - + ]: 140735 : POSIX_GUARD(s2n_hkdf_expand(hmac, alg, secret, &hkdf_label_blob, output));
374 : :
375 : 140735 : return S2N_SUCCESS;
376 : 140735 : }
377 : :
378 : : int s2n_hkdf(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt,
379 : : const struct s2n_blob *key, const struct s2n_blob *info, struct s2n_blob *output)
380 : 765 : {
381 [ - + ][ # # ]: 765 : POSIX_ENSURE_REF(hmac);
382 [ # # ][ - + ]: 765 : POSIX_ENSURE_REF(salt);
383 [ - + ][ # # ]: 765 : POSIX_ENSURE_REF(key);
384 [ - + ][ # # ]: 765 : POSIX_ENSURE_REF(info);
385 [ - + ][ # # ]: 765 : POSIX_ENSURE_REF(output);
386 : :
387 : 765 : const struct s2n_hkdf_impl *hkdf_implementation = s2n_get_hkdf_implementation();
388 [ - + ][ # # ]: 765 : POSIX_ENSURE_REF(hkdf_implementation);
389 : :
390 [ + + ]: 765 : POSIX_GUARD(hkdf_implementation->hkdf(hmac, alg, salt, key, info, output));
391 : :
392 : 763 : return S2N_SUCCESS;
393 : 765 : }
|