]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/kdf/hkdf.c
Added differentiation between missing secret and missing seed
[thirdparty/openssl.git] / crypto / kdf / hkdf.c
CommitLineData
d2e9e320
RS
1/*
2 * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
aacfb134 3 *
d2e9e320
RS
4 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
aacfb134
AG
8 */
9
10#include <stdlib.h>
11#include <string.h>
12#include <openssl/hmac.h>
13#include <openssl/kdf.h>
14#include <openssl/evp.h>
15#include "internal/cryptlib.h"
16#include "internal/evp_int.h"
17
18#define HKDF_MAXBUF 1024
19
20static unsigned char *HKDF(const EVP_MD *evp_md,
21 const unsigned char *salt, size_t salt_len,
22 const unsigned char *key, size_t key_len,
23 const unsigned char *info, size_t info_len,
24 unsigned char *okm, size_t okm_len);
25
26static unsigned char *HKDF_Extract(const EVP_MD *evp_md,
27 const unsigned char *salt, size_t salt_len,
28 const unsigned char *key, size_t key_len,
29 unsigned char *prk, size_t *prk_len);
30
31static unsigned char *HKDF_Expand(const EVP_MD *evp_md,
32 const unsigned char *prk, size_t prk_len,
33 const unsigned char *info, size_t info_len,
34 unsigned char *okm, size_t okm_len);
35
36typedef struct {
d2139cf8 37 int mode;
aacfb134
AG
38 const EVP_MD *md;
39 unsigned char *salt;
40 size_t salt_len;
41 unsigned char *key;
42 size_t key_len;
43 unsigned char info[HKDF_MAXBUF];
44 size_t info_len;
45} HKDF_PKEY_CTX;
46
47static int pkey_hkdf_init(EVP_PKEY_CTX *ctx)
48{
49 HKDF_PKEY_CTX *kctx;
50
51 kctx = OPENSSL_zalloc(sizeof(*kctx));
52 if (kctx == NULL)
53 return 0;
54
55 ctx->data = kctx;
56
57 return 1;
58}
59
60static void pkey_hkdf_cleanup(EVP_PKEY_CTX *ctx)
61{
62 HKDF_PKEY_CTX *kctx = ctx->data;
63 OPENSSL_clear_free(kctx->salt, kctx->salt_len);
64 OPENSSL_clear_free(kctx->key, kctx->key_len);
65 OPENSSL_cleanse(kctx->info, kctx->info_len);
66 OPENSSL_free(kctx);
67}
68
69static int pkey_hkdf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
70{
71 HKDF_PKEY_CTX *kctx = ctx->data;
72
73 switch (type) {
74 case EVP_PKEY_CTRL_HKDF_MD:
75 if (p2 == NULL)
76 return 0;
77
78 kctx->md = p2;
79 return 1;
80
d2139cf8
MC
81 case EVP_PKEY_CTRL_HKDF_MODE:
82 kctx->mode = p1;
83 return 1;
84
aacfb134
AG
85 case EVP_PKEY_CTRL_HKDF_SALT:
86 if (p1 == 0 || p2 == NULL)
87 return 1;
88
89 if (p1 < 0)
90 return 0;
91
92 if (kctx->salt != NULL)
93 OPENSSL_clear_free(kctx->salt, kctx->salt_len);
94
95 kctx->salt = OPENSSL_memdup(p2, p1);
96 if (kctx->salt == NULL)
97 return 0;
98
99 kctx->salt_len = p1;
100 return 1;
101
102 case EVP_PKEY_CTRL_HKDF_KEY:
103 if (p1 < 0)
104 return 0;
105
106 if (kctx->key != NULL)
107 OPENSSL_clear_free(kctx->key, kctx->key_len);
108
109 kctx->key = OPENSSL_memdup(p2, p1);
110 if (kctx->key == NULL)
111 return 0;
112
113 kctx->key_len = p1;
114 return 1;
115
116 case EVP_PKEY_CTRL_HKDF_INFO:
117 if (p1 == 0 || p2 == NULL)
118 return 1;
119
120 if (p1 < 0 || p1 > (int)(HKDF_MAXBUF - kctx->info_len))
121 return 0;
122
123 memcpy(kctx->info + kctx->info_len, p2, p1);
124 kctx->info_len += p1;
125 return 1;
126
127 default:
128 return -2;
129
130 }
131}
132
133static int pkey_hkdf_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
134 const char *value)
135{
ddd2c389
MC
136 if (strcmp(type, "mode") == 0) {
137 int mode;
138
139 if (strcmp(value, "EXTRACT_AND_EXPAND") == 0)
140 mode = EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND;
141 else if (strcmp(value, "EXTRACT_ONLY") == 0)
142 mode = EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY;
143 else if (strcmp(value, "EXPAND_ONLY") == 0)
144 mode = EVP_PKEY_HKDEF_MODE_EXPAND_ONLY;
145 else
146 return 0;
147
148 return EVP_PKEY_CTX_hkdf_mode(ctx, mode);
149 }
150
f55129c7
JB
151 if (strcmp(type, "md") == 0)
152 return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_DERIVE,
153 EVP_PKEY_CTRL_HKDF_MD, value);
aacfb134
AG
154
155 if (strcmp(type, "salt") == 0)
156 return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_HKDF_SALT, value);
157
158 if (strcmp(type, "hexsalt") == 0)
159 return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_HKDF_SALT, value);
160
161 if (strcmp(type, "key") == 0)
162 return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_HKDF_KEY, value);
163
164 if (strcmp(type, "hexkey") == 0)
165 return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_HKDF_KEY, value);
166
167 if (strcmp(type, "info") == 0)
168 return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_HKDF_INFO, value);
169
170 if (strcmp(type, "hexinfo") == 0)
171 return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_HKDF_INFO, value);
172
a24a5b8c 173 KDFerr(KDF_F_PKEY_HKDF_CTRL_STR, KDF_R_UNKNOWN_PARAMETER_TYPE);
aacfb134
AG
174 return -2;
175}
176
177static int pkey_hkdf_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
178 size_t *keylen)
179{
180 HKDF_PKEY_CTX *kctx = ctx->data;
181
f55129c7
JB
182 if (kctx->md == NULL) {
183 KDFerr(KDF_F_PKEY_HKDF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST);
184 return 0;
185 }
186 if (kctx->key == NULL) {
187 KDFerr(KDF_F_PKEY_HKDF_DERIVE, KDF_R_MISSING_KEY);
aacfb134 188 return 0;
e65f6509 189 }
aacfb134 190
d2139cf8
MC
191 switch (kctx->mode) {
192 case EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND:
193 return HKDF(kctx->md, kctx->salt, kctx->salt_len, kctx->key,
194 kctx->key_len, kctx->info, kctx->info_len, key,
195 *keylen) != NULL;
196
197 case EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY:
198 if (key == NULL) {
199 *keylen = EVP_MD_size(kctx->md);
200 return 1;
201 }
202 return HKDF_Extract(kctx->md, kctx->salt, kctx->salt_len, kctx->key,
203 kctx->key_len, key, keylen) != NULL;
204
205 case EVP_PKEY_HKDEF_MODE_EXPAND_ONLY:
206 return HKDF_Expand(kctx->md, kctx->key, kctx->key_len, kctx->info,
207 kctx->info_len, key, *keylen) != NULL;
208
209 default:
aacfb134
AG
210 return 0;
211 }
aacfb134
AG
212}
213
214const EVP_PKEY_METHOD hkdf_pkey_meth = {
215 EVP_PKEY_HKDF,
216 0,
217 pkey_hkdf_init,
218 0,
219 pkey_hkdf_cleanup,
220
221 0, 0,
222 0, 0,
223
224 0,
225 0,
226
227 0,
228 0,
229
230 0, 0,
231
232 0, 0, 0, 0,
233
234 0, 0,
235
236 0, 0,
237
238 0,
239 pkey_hkdf_derive,
240 pkey_hkdf_ctrl,
241 pkey_hkdf_ctrl_str
242};
243
244static unsigned char *HKDF(const EVP_MD *evp_md,
245 const unsigned char *salt, size_t salt_len,
246 const unsigned char *key, size_t key_len,
247 const unsigned char *info, size_t info_len,
248 unsigned char *okm, size_t okm_len)
249{
250 unsigned char prk[EVP_MAX_MD_SIZE];
d2139cf8 251 unsigned char *ret;
aacfb134
AG
252 size_t prk_len;
253
254 if (!HKDF_Extract(evp_md, salt, salt_len, key, key_len, prk, &prk_len))
255 return NULL;
256
d2139cf8
MC
257 ret = HKDF_Expand(evp_md, prk, prk_len, info, info_len, okm, okm_len);
258 OPENSSL_cleanse(prk, sizeof(prk));
259
260 return ret;
aacfb134
AG
261}
262
263static unsigned char *HKDF_Extract(const EVP_MD *evp_md,
264 const unsigned char *salt, size_t salt_len,
265 const unsigned char *key, size_t key_len,
266 unsigned char *prk, size_t *prk_len)
267{
268 unsigned int tmp_len;
269
270 if (!HMAC(evp_md, salt, salt_len, key, key_len, prk, &tmp_len))
271 return NULL;
272
273 *prk_len = tmp_len;
274 return prk;
275}
276
277static unsigned char *HKDF_Expand(const EVP_MD *evp_md,
278 const unsigned char *prk, size_t prk_len,
279 const unsigned char *info, size_t info_len,
280 unsigned char *okm, size_t okm_len)
281{
282 HMAC_CTX *hmac;
283
284 unsigned int i;
285
286 unsigned char prev[EVP_MAX_MD_SIZE];
287
288 size_t done_len = 0, dig_len = EVP_MD_size(evp_md);
289
290 size_t n = okm_len / dig_len;
291 if (okm_len % dig_len)
292 n++;
293
d2139cf8 294 if (n > 255 || okm == NULL)
aacfb134
AG
295 return NULL;
296
297 if ((hmac = HMAC_CTX_new()) == NULL)
298 return NULL;
299
300 if (!HMAC_Init_ex(hmac, prk, prk_len, evp_md, NULL))
301 goto err;
302
303 for (i = 1; i <= n; i++) {
304 size_t copy_len;
305 const unsigned char ctr = i;
306
307 if (i > 1) {
308 if (!HMAC_Init_ex(hmac, NULL, 0, NULL, NULL))
309 goto err;
310
311 if (!HMAC_Update(hmac, prev, dig_len))
312 goto err;
313 }
314
315 if (!HMAC_Update(hmac, info, info_len))
316 goto err;
317
318 if (!HMAC_Update(hmac, &ctr, 1))
319 goto err;
320
321 if (!HMAC_Final(hmac, prev, NULL))
322 goto err;
323
324 copy_len = (done_len + dig_len > okm_len) ?
325 okm_len - done_len :
326 dig_len;
327
328 memcpy(okm + done_len, prev, copy_len);
329
330 done_len += copy_len;
331 }
332
333 HMAC_CTX_free(hmac);
334 return okm;
335
336 err:
337 HMAC_CTX_free(hmac);
338 return NULL;
339}