1 | /* |
2 | * Copyright 2018-2019 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 <stdarg.h> |
12 | #include <string.h> |
13 | #include <openssl/evp.h> |
14 | #include <openssl/kdf.h> |
15 | #include <openssl/core_names.h> |
16 | #include "internal/cryptlib.h" |
17 | #include "internal/numbers.h" |
18 | #include "crypto/evp.h" |
19 | #include "prov/provider_ctx.h" |
20 | #include "prov/providercommonerr.h" |
21 | #include "prov/implementations.h" |
22 | # include "prov/provider_util.h" |
23 | |
24 | /* See RFC 4253, Section 7.2 */ |
25 | static OSSL_OP_kdf_newctx_fn kdf_sshkdf_new; |
26 | static OSSL_OP_kdf_freectx_fn kdf_sshkdf_free; |
27 | static OSSL_OP_kdf_reset_fn kdf_sshkdf_reset; |
28 | static OSSL_OP_kdf_derive_fn kdf_sshkdf_derive; |
29 | static OSSL_OP_kdf_settable_ctx_params_fn kdf_sshkdf_settable_ctx_params; |
30 | static OSSL_OP_kdf_set_ctx_params_fn kdf_sshkdf_set_ctx_params; |
31 | static OSSL_OP_kdf_gettable_ctx_params_fn kdf_sshkdf_gettable_ctx_params; |
32 | static OSSL_OP_kdf_get_ctx_params_fn kdf_sshkdf_get_ctx_params; |
33 | |
34 | static int SSHKDF(const EVP_MD *evp_md, |
35 | const unsigned char *key, size_t key_len, |
36 | const unsigned char *xcghash, size_t xcghash_len, |
37 | const unsigned char *session_id, size_t session_id_len, |
38 | char type, unsigned char *okey, size_t okey_len); |
39 | |
40 | typedef struct { |
41 | void *provctx; |
42 | PROV_DIGEST digest; |
43 | unsigned char *key; /* K */ |
44 | size_t key_len; |
45 | unsigned char *xcghash; /* H */ |
46 | size_t xcghash_len; |
47 | char type; /* X */ |
48 | unsigned char *session_id; |
49 | size_t session_id_len; |
50 | } KDF_SSHKDF; |
51 | |
52 | static void *kdf_sshkdf_new(void *provctx) |
53 | { |
54 | KDF_SSHKDF *ctx; |
55 | |
56 | if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) |
57 | ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); |
58 | ctx->provctx = provctx; |
59 | return ctx; |
60 | } |
61 | |
62 | static void kdf_sshkdf_free(void *vctx) |
63 | { |
64 | KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx; |
65 | |
66 | if (ctx != NULL) { |
67 | kdf_sshkdf_reset(ctx); |
68 | OPENSSL_free(ctx); |
69 | } |
70 | } |
71 | |
72 | static void kdf_sshkdf_reset(void *vctx) |
73 | { |
74 | KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx; |
75 | |
76 | ossl_prov_digest_reset(&ctx->digest); |
77 | OPENSSL_clear_free(ctx->key, ctx->key_len); |
78 | OPENSSL_clear_free(ctx->xcghash, ctx->xcghash_len); |
79 | OPENSSL_clear_free(ctx->session_id, ctx->session_id_len); |
80 | memset(ctx, 0, sizeof(*ctx)); |
81 | } |
82 | |
83 | static int sshkdf_set_membuf(unsigned char **dst, size_t *dst_len, |
84 | const OSSL_PARAM *p) |
85 | { |
86 | OPENSSL_clear_free(*dst, *dst_len); |
87 | *dst = NULL; |
88 | return OSSL_PARAM_get_octet_string(p, (void **)dst, 0, dst_len); |
89 | } |
90 | |
91 | static int kdf_sshkdf_derive(void *vctx, unsigned char *key, |
92 | size_t keylen) |
93 | { |
94 | KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx; |
95 | const EVP_MD *md = ossl_prov_digest_md(&ctx->digest); |
96 | |
97 | if (md == NULL) { |
98 | ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); |
99 | return 0; |
100 | } |
101 | if (ctx->key == NULL) { |
102 | ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); |
103 | return 0; |
104 | } |
105 | if (ctx->xcghash == NULL) { |
106 | ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_XCGHASH); |
107 | return 0; |
108 | } |
109 | if (ctx->session_id == NULL) { |
110 | ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SESSION_ID); |
111 | return 0; |
112 | } |
113 | if (ctx->type == 0) { |
114 | ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_TYPE); |
115 | return 0; |
116 | } |
117 | return SSHKDF(md, ctx->key, ctx->key_len, |
118 | ctx->xcghash, ctx->xcghash_len, |
119 | ctx->session_id, ctx->session_id_len, |
120 | ctx->type, key, keylen); |
121 | } |
122 | |
123 | static int kdf_sshkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) |
124 | { |
125 | const OSSL_PARAM *p; |
126 | KDF_SSHKDF *ctx = vctx; |
127 | OPENSSL_CTX *provctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx); |
128 | int t; |
129 | |
130 | if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx)) |
131 | return 0; |
132 | |
133 | if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL) |
134 | if (!sshkdf_set_membuf(&ctx->key, &ctx->key_len, p)) |
135 | return 0; |
136 | |
137 | if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_XCGHASH)) |
138 | != NULL) |
139 | if (!sshkdf_set_membuf(&ctx->xcghash, &ctx->xcghash_len, p)) |
140 | return 0; |
141 | |
142 | if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_SESSION_ID)) |
143 | != NULL) |
144 | if (!sshkdf_set_membuf(&ctx->session_id, &ctx->session_id_len, p)) |
145 | return 0; |
146 | |
147 | if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_TYPE)) |
148 | != NULL) { |
149 | if (p->data == NULL || p->data_size == 0) |
150 | return 0; |
151 | t = *(unsigned char *)p->data; |
152 | if (t < 65 || t > 70) { |
153 | ERR_raise(ERR_LIB_PROV, PROV_R_VALUE_ERROR); |
154 | return 0; |
155 | } |
156 | ctx->type = (char)t; |
157 | } |
158 | return 1; |
159 | } |
160 | |
161 | static const OSSL_PARAM *kdf_sshkdf_settable_ctx_params(void) |
162 | { |
163 | static const OSSL_PARAM known_settable_ctx_params[] = { |
164 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), |
165 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), |
166 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), |
167 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SSHKDF_XCGHASH, NULL, 0), |
168 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SSHKDF_SESSION_ID, NULL, 0), |
169 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_SSHKDF_TYPE, NULL, 0), |
170 | OSSL_PARAM_END |
171 | }; |
172 | return known_settable_ctx_params; |
173 | } |
174 | |
175 | static int kdf_sshkdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) |
176 | { |
177 | OSSL_PARAM *p; |
178 | |
179 | if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) |
180 | return OSSL_PARAM_set_size_t(p, SIZE_MAX); |
181 | return -2; |
182 | } |
183 | |
184 | static const OSSL_PARAM *kdf_sshkdf_gettable_ctx_params(void) |
185 | { |
186 | static const OSSL_PARAM known_gettable_ctx_params[] = { |
187 | OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), |
188 | OSSL_PARAM_END |
189 | }; |
190 | return known_gettable_ctx_params; |
191 | } |
192 | |
193 | const OSSL_DISPATCH kdf_sshkdf_functions[] = { |
194 | { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_sshkdf_new }, |
195 | { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_sshkdf_free }, |
196 | { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_sshkdf_reset }, |
197 | { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_sshkdf_derive }, |
198 | { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, |
199 | (void(*)(void))kdf_sshkdf_settable_ctx_params }, |
200 | { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_sshkdf_set_ctx_params }, |
201 | { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, |
202 | (void(*)(void))kdf_sshkdf_gettable_ctx_params }, |
203 | { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_sshkdf_get_ctx_params }, |
204 | { 0, NULL } |
205 | }; |
206 | |
207 | static int SSHKDF(const EVP_MD *evp_md, |
208 | const unsigned char *key, size_t key_len, |
209 | const unsigned char *xcghash, size_t xcghash_len, |
210 | const unsigned char *session_id, size_t session_id_len, |
211 | char type, unsigned char *okey, size_t okey_len) |
212 | { |
213 | EVP_MD_CTX *md = NULL; |
214 | unsigned char digest[EVP_MAX_MD_SIZE]; |
215 | unsigned int dsize = 0; |
216 | size_t cursize = 0; |
217 | int ret = 0; |
218 | |
219 | md = EVP_MD_CTX_new(); |
220 | if (md == NULL) |
221 | return 0; |
222 | |
223 | if (!EVP_DigestInit_ex(md, evp_md, NULL)) |
224 | goto out; |
225 | |
226 | if (!EVP_DigestUpdate(md, key, key_len)) |
227 | goto out; |
228 | |
229 | if (!EVP_DigestUpdate(md, xcghash, xcghash_len)) |
230 | goto out; |
231 | |
232 | if (!EVP_DigestUpdate(md, &type, 1)) |
233 | goto out; |
234 | |
235 | if (!EVP_DigestUpdate(md, session_id, session_id_len)) |
236 | goto out; |
237 | |
238 | if (!EVP_DigestFinal_ex(md, digest, &dsize)) |
239 | goto out; |
240 | |
241 | if (okey_len < dsize) { |
242 | memcpy(okey, digest, okey_len); |
243 | ret = 1; |
244 | goto out; |
245 | } |
246 | |
247 | memcpy(okey, digest, dsize); |
248 | |
249 | for (cursize = dsize; cursize < okey_len; cursize += dsize) { |
250 | |
251 | if (!EVP_DigestInit_ex(md, evp_md, NULL)) |
252 | goto out; |
253 | |
254 | if (!EVP_DigestUpdate(md, key, key_len)) |
255 | goto out; |
256 | |
257 | if (!EVP_DigestUpdate(md, xcghash, xcghash_len)) |
258 | goto out; |
259 | |
260 | if (!EVP_DigestUpdate(md, okey, cursize)) |
261 | goto out; |
262 | |
263 | if (!EVP_DigestFinal_ex(md, digest, &dsize)) |
264 | goto out; |
265 | |
266 | if (okey_len < cursize + dsize) { |
267 | memcpy(okey + cursize, digest, okey_len - cursize); |
268 | ret = 1; |
269 | goto out; |
270 | } |
271 | |
272 | memcpy(okey + cursize, digest, dsize); |
273 | } |
274 | |
275 | ret = 1; |
276 | |
277 | out: |
278 | EVP_MD_CTX_free(md); |
279 | OPENSSL_cleanse(digest, EVP_MAX_MD_SIZE); |
280 | return ret; |
281 | } |
282 | |
283 | |