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