Add string ctrl operations to TLS1 PRF, update documentation.
[openssl.git] / crypto / kdf / tls1_prf.c
1 /*
2  * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
3  * 2016.
4  */
5 /* ====================================================================
6  * Copyright (c) 2015 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58
59 #include <stdio.h>
60 #include "internal/cryptlib.h"
61 #include <openssl/kdf.h>
62 #include <openssl/evp.h>
63 #include "internal/evp_int.h"
64
65 static int tls1_prf_alg(const EVP_MD *md,
66                         const unsigned char *sec, size_t slen,
67                         const unsigned char *seed, size_t seed_len,
68                         unsigned char *out, size_t olen);
69
70 #define TLS1_PRF_MAXBUF 1024
71
72 /* TLS KDF pkey context structure */
73
74 typedef struct {
75     /* Digest to use for PRF */
76     const EVP_MD *md;
77     /* Secret value to use for PRF */
78     unsigned char *sec;
79     size_t seclen;
80     /* Buffer of concatenated seed data */
81     unsigned char seed[TLS1_PRF_MAXBUF];
82     size_t seedlen;
83 } TLS1_PRF_PKEY_CTX;
84
85 static int pkey_tls1_prf_init(EVP_PKEY_CTX *ctx)
86 {
87     TLS1_PRF_PKEY_CTX *kctx;
88
89     kctx = OPENSSL_zalloc(sizeof(*kctx));
90     if (kctx == NULL)
91         return 0;
92     ctx->data = kctx;
93
94     return 1;
95 }
96
97 static void pkey_tls1_prf_cleanup(EVP_PKEY_CTX *ctx)
98 {
99     TLS1_PRF_PKEY_CTX *kctx = ctx->data;
100     OPENSSL_clear_free(kctx->sec, kctx->seclen);
101     OPENSSL_cleanse(kctx->seed, kctx->seedlen);
102     OPENSSL_free(kctx);
103 }
104
105 static int pkey_tls1_prf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
106 {
107     TLS1_PRF_PKEY_CTX *kctx = ctx->data;
108     switch (type) {
109     case EVP_PKEY_CTRL_TLS_MD:
110         kctx->md = p2;
111         return 1;
112
113     case EVP_PKEY_CTRL_TLS_SECRET:
114         if (p1 < 0)
115             return 0;
116         if (kctx->sec != NULL)
117             OPENSSL_clear_free(kctx->sec, kctx->seclen);
118         OPENSSL_cleanse(kctx->seed, kctx->seedlen);
119         kctx->seedlen = 0;
120         kctx->sec = OPENSSL_memdup(p2, p1);
121         if (kctx->sec == NULL)
122             return 0;
123         kctx->seclen  = p1;
124         return 1;
125
126     case EVP_PKEY_CTRL_TLS_SEED:
127         if (p1 == 0 || p2 == NULL)
128             return 1;
129         if (p1 < 0 || p1 > (int)(TLS1_PRF_MAXBUF - kctx->seedlen))
130             return 0;
131         memcpy(kctx->seed + kctx->seedlen, p2, p1);
132         kctx->seedlen += p1;
133         return 1;
134
135     default:
136         return -2;
137
138     }
139 }
140
141 static int pkey_tls1_prf_ctrl_str(EVP_PKEY_CTX *ctx,
142                                   const char *type, const char *value)
143 {
144     if (value == NULL)
145         return 0;
146     if (strcmp(type, "md") == 0) {
147         TLS1_PRF_PKEY_CTX *kctx = ctx->data;
148
149         const EVP_MD *md = EVP_get_digestbyname(value);
150         if (md == NULL)
151             return 0;
152         kctx->md = md;
153         return 1;
154     }
155     if (strcmp(type, "secret") == 0)
156         return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_TLS_SECRET, value);
157     if (strcmp(type, "hexsecret") == 0)
158         return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_TLS_SECRET, value);
159     if (strcmp(type, "seed") == 0)
160         return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_TLS_SEED, value);
161     if (strcmp(type, "hexseed") == 0)
162         return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_TLS_SEED, value);
163     return -2;
164 }
165
166 static int pkey_tls1_prf_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
167                                 size_t *keylen)
168 {
169     TLS1_PRF_PKEY_CTX *kctx = ctx->data;
170     if (kctx->md == NULL || kctx->sec == NULL || kctx->seedlen == 0)
171         return 0;
172     return tls1_prf_alg(kctx->md, kctx->sec, kctx->seclen,
173                         kctx->seed, kctx->seedlen,
174                         key, *keylen);
175 }
176
177 const EVP_PKEY_METHOD tls1_prf_pkey_meth = {
178     EVP_PKEY_TLS1_PRF,
179     0,
180     pkey_tls1_prf_init,
181     0,
182     pkey_tls1_prf_cleanup,
183
184     0, 0,
185     0, 0,
186
187     0,
188     0,
189
190     0,
191     0,
192
193     0, 0,
194
195     0, 0, 0, 0,
196
197     0, 0,
198
199     0, 0,
200
201     0,
202     pkey_tls1_prf_derive,
203     pkey_tls1_prf_ctrl,
204     pkey_tls1_prf_ctrl_str
205 };
206
207 static int tls1_prf_P_hash(const EVP_MD *md,
208                            const unsigned char *sec, size_t sec_len,
209                            const unsigned char *seed, size_t seed_len,
210                            unsigned char *out, size_t olen)
211 {
212     int chunk;
213     EVP_MD_CTX *ctx = NULL, *ctx_tmp = NULL, *ctx_init = NULL;
214     EVP_PKEY *mac_key = NULL;
215     unsigned char A1[EVP_MAX_MD_SIZE];
216     size_t A1_len;
217     int ret = 0;
218
219     chunk = EVP_MD_size(md);
220     OPENSSL_assert(chunk >= 0);
221
222     ctx = EVP_MD_CTX_new();
223     ctx_tmp = EVP_MD_CTX_new();
224     ctx_init = EVP_MD_CTX_new();
225     if (ctx == NULL || ctx_tmp == NULL || ctx_init == NULL)
226         goto err;
227     EVP_MD_CTX_set_flags(ctx_init, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
228     mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, sec, sec_len);
229     if (mac_key == NULL)
230         goto err;
231     if (!EVP_DigestSignInit(ctx_init, NULL, md, NULL, mac_key))
232         goto err;
233     if (!EVP_MD_CTX_copy_ex(ctx, ctx_init))
234         goto err;
235     if (seed != NULL && !EVP_DigestSignUpdate(ctx, seed, seed_len))
236         goto err;
237     if (!EVP_DigestSignFinal(ctx, A1, &A1_len))
238         goto err;
239
240     for (;;) {
241         /* Reinit mac contexts */
242         if (!EVP_MD_CTX_copy_ex(ctx, ctx_init))
243             goto err;
244         if (!EVP_DigestSignUpdate(ctx, A1, A1_len))
245             goto err;
246         if (olen > (size_t)chunk && !EVP_MD_CTX_copy_ex(ctx_tmp, ctx))
247             goto err;
248         if (seed && !EVP_DigestSignUpdate(ctx, seed, seed_len))
249             goto err;
250
251         if (olen > (size_t)chunk) {
252             size_t mac_len;
253             if (!EVP_DigestSignFinal(ctx, out, &mac_len))
254                 goto err;
255             out += mac_len;
256             olen -= mac_len;
257             /* calc the next A1 value */
258             if (!EVP_DigestSignFinal(ctx_tmp, A1, &A1_len))
259                 goto err;
260         } else {                /* last one */
261
262             if (!EVP_DigestSignFinal(ctx, A1, &A1_len))
263                 goto err;
264             memcpy(out, A1, olen);
265             break;
266         }
267     }
268     ret = 1;
269  err:
270     EVP_PKEY_free(mac_key);
271     EVP_MD_CTX_free(ctx);
272     EVP_MD_CTX_free(ctx_tmp);
273     EVP_MD_CTX_free(ctx_init);
274     OPENSSL_cleanse(A1, sizeof(A1));
275     return ret;
276 }
277
278 static int tls1_prf_alg(const EVP_MD *md,
279                         const unsigned char *sec, size_t slen,
280                         const unsigned char *seed, size_t seed_len,
281                         unsigned char *out, size_t olen)
282 {
283
284     if (EVP_MD_type(md) == NID_md5_sha1) {
285         size_t i;
286         unsigned char *tmp;
287         if (!tls1_prf_P_hash(EVP_md5(), sec, slen/2 + (slen & 1),
288                          seed, seed_len, out, olen))
289             return 0;
290
291         tmp = OPENSSL_malloc(olen);
292         if (tmp == NULL)
293             return 0;
294         if (!tls1_prf_P_hash(EVP_sha1(), sec + slen/2, slen/2 + (slen & 1),
295                          seed, seed_len, tmp, olen)) {
296             OPENSSL_clear_free(tmp, olen);
297             return 0;
298         }
299         for (i = 0; i < olen; i++)
300             out[i] ^= tmp[i];
301         OPENSSL_clear_free(tmp, olen);
302         return 1;
303     }
304     if (!tls1_prf_P_hash(md, sec, slen, seed, seed_len, out, olen))
305         return 0;
306
307     return 1;
308 }