/src/boringssl/crypto/fipsmodule/tls/kdf.cc.inc
Line | Count | Source |
1 | | // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <assert.h> |
16 | | |
17 | | #include <openssl/bytestring.h> |
18 | | #include <openssl/digest.h> |
19 | | #include <openssl/hkdf.h> |
20 | | #include <openssl/hmac.h> |
21 | | #include <openssl/mem.h> |
22 | | #include <openssl/tls_prf.h> |
23 | | |
24 | | #include "../../internal.h" |
25 | | #include "../service_indicator/internal.h" |
26 | | #include "internal.h" |
27 | | |
28 | | |
29 | | using namespace bssl; |
30 | | |
31 | | // tls1_P_hash computes the TLS P_<hash> function as described in RFC 5246, |
32 | | // section 5. It XORs `out_len` bytes to `out`, using `md` as the hash and |
33 | | // `secret` as the secret. `label`, `seed1`, and `seed2` are concatenated to |
34 | | // form the seed parameter. It returns true on success and false on failure. |
35 | | static int tls1_P_hash(uint8_t *out, size_t out_len, const EVP_MD *md, |
36 | | const uint8_t *secret, size_t secret_len, |
37 | | const uint8_t *label, size_t label_len, |
38 | | const uint8_t *seed1, size_t seed1_len, |
39 | 171k | const uint8_t *seed2, size_t seed2_len) { |
40 | 171k | HMAC_CTX ctx, ctx_tmp, ctx_init; |
41 | 171k | uint8_t A1[EVP_MAX_MD_SIZE]; |
42 | 171k | unsigned A1_len; |
43 | 171k | int ret = 0; |
44 | | |
45 | 171k | const size_t chunk = EVP_MD_size(md); |
46 | 171k | HMAC_CTX_init(&ctx); |
47 | 171k | HMAC_CTX_init(&ctx_tmp); |
48 | 171k | HMAC_CTX_init(&ctx_init); |
49 | | |
50 | 171k | if (!HMAC_Init_ex(&ctx_init, secret, secret_len, md, nullptr) || |
51 | 171k | !HMAC_CTX_copy_ex(&ctx, &ctx_init) || |
52 | 171k | !HMAC_Update(&ctx, label, label_len) || |
53 | 171k | !HMAC_Update(&ctx, seed1, seed1_len) || |
54 | 171k | !HMAC_Update(&ctx, seed2, seed2_len) || // |
55 | 171k | !HMAC_Final(&ctx, A1, &A1_len)) { |
56 | 0 | goto err; |
57 | 0 | } |
58 | | |
59 | 307k | for (;;) { |
60 | 307k | unsigned len_u; |
61 | 307k | uint8_t hmac[EVP_MAX_MD_SIZE]; |
62 | 307k | if (!HMAC_CTX_copy_ex(&ctx, &ctx_init) || !HMAC_Update(&ctx, A1, A1_len) || |
63 | | // Save a copy of `ctx` to compute the next A1 value below. |
64 | 307k | (out_len > chunk && !HMAC_CTX_copy_ex(&ctx_tmp, &ctx)) || |
65 | 307k | !HMAC_Update(&ctx, (const uint8_t *)label, label_len) || |
66 | 307k | !HMAC_Update(&ctx, seed1, seed1_len) || |
67 | 307k | !HMAC_Update(&ctx, seed2, seed2_len) || |
68 | 307k | !HMAC_Final(&ctx, hmac, &len_u)) { |
69 | 0 | goto err; |
70 | 0 | } |
71 | 307k | size_t len = len_u; |
72 | 307k | assert(len == chunk); |
73 | | |
74 | | // XOR the result into `out`. |
75 | 307k | if (len > out_len) { |
76 | 160k | len = out_len; |
77 | 160k | } |
78 | 6.68M | for (size_t i = 0; i < len; i++) { |
79 | 6.37M | out[i] ^= hmac[i]; |
80 | 6.37M | } |
81 | 307k | out += len; |
82 | 307k | out_len -= len; |
83 | | |
84 | 307k | if (out_len == 0) { |
85 | 171k | break; |
86 | 171k | } |
87 | | |
88 | | // Calculate the next A1 value. |
89 | 136k | if (!HMAC_Final(&ctx_tmp, A1, &A1_len)) { |
90 | 0 | goto err; |
91 | 0 | } |
92 | 136k | } |
93 | | |
94 | 171k | ret = 1; |
95 | | |
96 | 171k | err: |
97 | 171k | OPENSSL_cleanse(A1, sizeof(A1)); |
98 | 171k | HMAC_CTX_cleanup(&ctx); |
99 | 171k | HMAC_CTX_cleanup(&ctx_tmp); |
100 | 171k | HMAC_CTX_cleanup(&ctx_init); |
101 | 171k | return ret; |
102 | 171k | } |
103 | | |
104 | | int CRYPTO_tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len, |
105 | | const uint8_t *secret, size_t secret_len, |
106 | | const uint8_t *label, size_t label_len, |
107 | | const uint8_t *seed1, size_t seed1_len, |
108 | 162k | const uint8_t *seed2, size_t seed2_len) { |
109 | 162k | if (out_len == 0) { |
110 | 0 | return 1; |
111 | 0 | } |
112 | | |
113 | 162k | OPENSSL_memset(out, 0, out_len); |
114 | | |
115 | 162k | const EVP_MD *const original_digest = digest; |
116 | 162k | FIPS_service_indicator_lock_state(); |
117 | 162k | int ret = 0; |
118 | | |
119 | 162k | if (digest == EVP_md5_sha1()) { |
120 | | // If using the MD5/SHA1 PRF, `secret` is partitioned between MD5 and SHA-1. |
121 | 8.68k | size_t secret_half = secret_len - (secret_len / 2); |
122 | 8.68k | if (!tls1_P_hash(out, out_len, EVP_md5(), secret, secret_half, label, |
123 | 8.68k | label_len, seed1, seed1_len, seed2, seed2_len)) { |
124 | 0 | goto end; |
125 | 0 | } |
126 | | |
127 | | // Note that, if `secret_len` is odd, the two halves share a byte. |
128 | 8.68k | secret += secret_len - secret_half; |
129 | 8.68k | secret_len = secret_half; |
130 | 8.68k | digest = EVP_sha1(); |
131 | 8.68k | } |
132 | | |
133 | 162k | ret = tls1_P_hash(out, out_len, digest, secret, secret_len, label, label_len, |
134 | 162k | seed1, seed1_len, seed2, seed2_len); |
135 | | |
136 | 162k | end: |
137 | 162k | FIPS_service_indicator_unlock_state(); |
138 | 162k | if (ret) { |
139 | 162k | TLSKDF_verify_service_indicator(original_digest); |
140 | 162k | } |
141 | 162k | return ret; |
142 | 162k | } |
143 | | |
144 | | int bssl::CRYPTO_tls13_hkdf_expand_label(uint8_t *out, size_t out_len, |
145 | | const EVP_MD *digest, // |
146 | | const uint8_t *secret, |
147 | | size_t secret_len, |
148 | | const uint8_t *label, size_t label_len, |
149 | 52.0k | const uint8_t *hash, size_t hash_len) { |
150 | 52.0k | static const uint8_t kProtocolLabel[] = "tls13 "; |
151 | 52.0k | CBB cbb, child; |
152 | 52.0k | uint8_t *hkdf_label = nullptr; |
153 | 52.0k | size_t hkdf_label_len; |
154 | | |
155 | 52.0k | FIPS_service_indicator_lock_state(); |
156 | 52.0k | CBB_zero(&cbb); |
157 | 52.0k | if (!CBB_init(&cbb, 2 + 1 + sizeof(kProtocolLabel) - 1 + label_len + 1 + |
158 | 52.0k | hash_len) || |
159 | 52.0k | !CBB_add_u16(&cbb, out_len) || |
160 | 52.0k | !CBB_add_u8_length_prefixed(&cbb, &child) || |
161 | 52.0k | !CBB_add_bytes(&child, kProtocolLabel, sizeof(kProtocolLabel) - 1) || |
162 | 52.0k | !CBB_add_bytes(&child, label, label_len) || |
163 | 52.0k | !CBB_add_u8_length_prefixed(&cbb, &child) || |
164 | 52.0k | !CBB_add_bytes(&child, hash, hash_len) || |
165 | 52.0k | !CBB_finish(&cbb, &hkdf_label, &hkdf_label_len)) { |
166 | 0 | CBB_cleanup(&cbb); |
167 | 0 | FIPS_service_indicator_unlock_state(); |
168 | 0 | return 0; |
169 | 0 | } |
170 | | |
171 | 52.0k | const int ret = HKDF_expand(out, out_len, digest, secret, secret_len, |
172 | 52.0k | hkdf_label, hkdf_label_len); |
173 | 52.0k | OPENSSL_free(hkdf_label); |
174 | | |
175 | 52.0k | FIPS_service_indicator_unlock_state(); |
176 | 52.0k | if (ret) { |
177 | 52.0k | TLSKDF_verify_service_indicator(digest); |
178 | 52.0k | } |
179 | 52.0k | return ret; |
180 | 52.0k | } |