Templatize util/domd
[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_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
142                                 size_t *keylen)
143 {
144     TLS1_PRF_PKEY_CTX *kctx = ctx->data;
145     if (kctx->md == NULL || kctx->sec == NULL || kctx->seedlen == 0)
146         return 0;
147     return tls1_prf_alg(kctx->md, kctx->sec, kctx->seclen,
148                         kctx->seed, kctx->seedlen,
149                         key, *keylen);
150 }
151
152 const EVP_PKEY_METHOD tls1_prf_pkey_meth = {
153     EVP_PKEY_TLS1_PRF,
154     0,
155     pkey_tls1_prf_init,
156     0,
157     pkey_tls1_prf_cleanup,
158
159     0, 0,
160     0, 0,
161
162     0,
163     0,
164
165     0,
166     0,
167
168     0, 0,
169
170     0, 0, 0, 0,
171
172     0, 0,
173
174     0, 0,
175
176     0,
177     pkey_tls1_prf_derive,
178     pkey_tls1_prf_ctrl,
179     0
180 };
181
182 static int tls1_prf_P_hash(const EVP_MD *md,
183                            const unsigned char *sec, size_t sec_len,
184                            const unsigned char *seed, size_t seed_len,
185                            unsigned char *out, size_t olen)
186 {
187     int chunk;
188     EVP_MD_CTX *ctx = NULL, *ctx_tmp = NULL, *ctx_init = NULL;
189     EVP_PKEY *mac_key = NULL;
190     unsigned char A1[EVP_MAX_MD_SIZE];
191     size_t A1_len;
192     int ret = 0;
193
194     chunk = EVP_MD_size(md);
195     OPENSSL_assert(chunk >= 0);
196
197     ctx = EVP_MD_CTX_new();
198     ctx_tmp = EVP_MD_CTX_new();
199     ctx_init = EVP_MD_CTX_new();
200     if (ctx == NULL || ctx_tmp == NULL || ctx_init == NULL)
201         goto err;
202     EVP_MD_CTX_set_flags(ctx_init, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
203     mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, sec, sec_len);
204     if (mac_key == NULL)
205         goto err;
206     if (!EVP_DigestSignInit(ctx_init, NULL, md, NULL, mac_key))
207         goto err;
208     if (!EVP_MD_CTX_copy_ex(ctx, ctx_init))
209         goto err;
210     if (seed != NULL && !EVP_DigestSignUpdate(ctx, seed, seed_len))
211         goto err;
212     if (!EVP_DigestSignFinal(ctx, A1, &A1_len))
213         goto err;
214
215     for (;;) {
216         /* Reinit mac contexts */
217         if (!EVP_MD_CTX_copy_ex(ctx, ctx_init))
218             goto err;
219         if (!EVP_DigestSignUpdate(ctx, A1, A1_len))
220             goto err;
221         if (olen > (size_t)chunk && !EVP_MD_CTX_copy_ex(ctx_tmp, ctx))
222             goto err;
223         if (seed && !EVP_DigestSignUpdate(ctx, seed, seed_len))
224             goto err;
225
226         if (olen > (size_t)chunk) {
227             size_t mac_len;
228             if (!EVP_DigestSignFinal(ctx, out, &mac_len))
229                 goto err;
230             out += mac_len;
231             olen -= mac_len;
232             /* calc the next A1 value */
233             if (!EVP_DigestSignFinal(ctx_tmp, A1, &A1_len))
234                 goto err;
235         } else {                /* last one */
236
237             if (!EVP_DigestSignFinal(ctx, A1, &A1_len))
238                 goto err;
239             memcpy(out, A1, olen);
240             break;
241         }
242     }
243     ret = 1;
244  err:
245     EVP_PKEY_free(mac_key);
246     EVP_MD_CTX_free(ctx);
247     EVP_MD_CTX_free(ctx_tmp);
248     EVP_MD_CTX_free(ctx_init);
249     OPENSSL_cleanse(A1, sizeof(A1));
250     return ret;
251 }
252
253 static int tls1_prf_alg(const EVP_MD *md,
254                         const unsigned char *sec, size_t slen,
255                         const unsigned char *seed, size_t seed_len,
256                         unsigned char *out, size_t olen)
257 {
258
259     if (EVP_MD_type(md) == NID_md5_sha1) {
260         size_t i;
261         unsigned char *tmp;
262         if (!tls1_prf_P_hash(EVP_md5(), sec, slen/2 + (slen & 1),
263                          seed, seed_len, out, olen))
264             return 0;
265
266         tmp = OPENSSL_malloc(olen);
267         if (tmp == NULL)
268             return 0;
269         if (!tls1_prf_P_hash(EVP_sha1(), sec + slen/2, slen/2 + (slen & 1),
270                          seed, seed_len, tmp, olen)) {
271             OPENSSL_clear_free(tmp, olen);
272             return 0;
273         }
274         for (i = 0; i < olen; i++)
275             out[i] ^= tmp[i];
276         OPENSSL_clear_free(tmp, olen);
277         return 1;
278     }
279     if (!tls1_prf_P_hash(md, sec, slen, seed, seed_len, out, olen))
280         return 0;
281
282     return 1;
283 }