1 /*
2 * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (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 <openssl/evp.h>
11 #include <openssl/core_names.h>
12 #include <openssl/proverr.h>
13 #include <openssl/err.h>
14 #include "prov/provider_ctx.h"
15 #include "prov/providercommon.h"
16 #include "prov/implementations.h"
17 #include "prov/provider_util.h"
18
19 static OSSL_FUNC_kdf_newctx_fn kdf_pvk_new;
20 static OSSL_FUNC_kdf_freectx_fn kdf_pvk_free;
21 static OSSL_FUNC_kdf_reset_fn kdf_pvk_reset;
22 static OSSL_FUNC_kdf_derive_fn kdf_pvk_derive;
23 static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_pvk_settable_ctx_params;
24 static OSSL_FUNC_kdf_set_ctx_params_fn kdf_pvk_set_ctx_params;
25 static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_pvk_gettable_ctx_params;
26 static OSSL_FUNC_kdf_get_ctx_params_fn kdf_pvk_get_ctx_params;
27
28 typedef struct {
29 void *provctx;
30 unsigned char *pass;
31 size_t pass_len;
32 unsigned char *salt;
33 size_t salt_len;
34 PROV_DIGEST digest;
35 } KDF_PVK;
36
37 static void kdf_pvk_init(KDF_PVK *ctx);
38
kdf_pvk_new(void * provctx)39 static void *kdf_pvk_new(void *provctx)
40 {
41 KDF_PVK *ctx;
42
43 if (!ossl_prov_is_running())
44 return NULL;
45
46 ctx = OPENSSL_zalloc(sizeof(*ctx));
47 if (ctx == NULL) {
48 ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
49 return NULL;
50 }
51 ctx->provctx = provctx;
52 kdf_pvk_init(ctx);
53 return ctx;
54 }
55
kdf_pvk_cleanup(KDF_PVK * ctx)56 static void kdf_pvk_cleanup(KDF_PVK *ctx)
57 {
58 ossl_prov_digest_reset(&ctx->digest);
59 OPENSSL_free(ctx->salt);
60 OPENSSL_clear_free(ctx->pass, ctx->pass_len);
61 OPENSSL_cleanse(ctx, sizeof(*ctx));
62 }
63
kdf_pvk_free(void * vctx)64 static void kdf_pvk_free(void *vctx)
65 {
66 KDF_PVK *ctx = (KDF_PVK *)vctx;
67
68 if (ctx != NULL) {
69 kdf_pvk_cleanup(ctx);
70 OPENSSL_free(ctx);
71 }
72 }
73
kdf_pvk_reset(void * vctx)74 static void kdf_pvk_reset(void *vctx)
75 {
76 KDF_PVK *ctx = (KDF_PVK *)vctx;
77 void *provctx = ctx->provctx;
78
79 kdf_pvk_cleanup(ctx);
80 ctx->provctx = provctx;
81 kdf_pvk_init(ctx);
82 }
83
kdf_pvk_init(KDF_PVK * ctx)84 static void kdf_pvk_init(KDF_PVK *ctx)
85 {
86 OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
87 OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx);
88
89 params[0] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
90 SN_sha1, 0);
91 if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx))
92 /* This is an error, but there is no way to indicate such directly */
93 ossl_prov_digest_reset(&ctx->digest);
94 }
95
pvk_set_membuf(unsigned char ** buffer,size_t * buflen,const OSSL_PARAM * p)96 static int pvk_set_membuf(unsigned char **buffer, size_t *buflen,
97 const OSSL_PARAM *p)
98 {
99 OPENSSL_clear_free(*buffer, *buflen);
100 if (p->data_size == 0) {
101 if ((*buffer = OPENSSL_malloc(1)) == NULL) {
102 ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
103 return 0;
104 }
105 } else if (p->data != NULL) {
106 *buffer = NULL;
107 if (!OSSL_PARAM_get_octet_string(p, (void **)buffer, 0, buflen))
108 return 0;
109 }
110 return 1;
111 }
112
kdf_pvk_derive(void * vctx,unsigned char * key,size_t keylen,const OSSL_PARAM params[])113 static int kdf_pvk_derive(void *vctx, unsigned char *key, size_t keylen,
114 const OSSL_PARAM params[])
115 {
116 KDF_PVK *ctx = (KDF_PVK *)vctx;
117 const EVP_MD *md;
118 EVP_MD_CTX *mctx;
119 int res;
120
121 if (!ossl_prov_is_running() || !kdf_pvk_set_ctx_params(ctx, params))
122 return 0;
123
124 if (ctx->pass == NULL) {
125 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_PASS);
126 return 0;
127 }
128
129 if (ctx->salt == NULL) {
130 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SALT);
131 return 0;
132 }
133
134 md = ossl_prov_digest_md(&ctx->digest);
135 if (md == NULL) {
136 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST);
137 return 0;
138 }
139 res = EVP_MD_get_size(md);
140 if (res <= 0) {
141 ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH);
142 return 0;
143 }
144 if ((size_t)res > keylen) {
145 ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE);
146 return 0;
147 }
148
149 mctx = EVP_MD_CTX_new();
150 res = mctx != NULL
151 && EVP_DigestInit_ex(mctx, md, NULL)
152 && EVP_DigestUpdate(mctx, ctx->salt, ctx->salt_len)
153 && EVP_DigestUpdate(mctx, ctx->pass, ctx->pass_len)
154 && EVP_DigestFinal_ex(mctx, key, NULL);
155 EVP_MD_CTX_free(mctx);
156 return res;
157 }
158
kdf_pvk_set_ctx_params(void * vctx,const OSSL_PARAM params[])159 static int kdf_pvk_set_ctx_params(void *vctx, const OSSL_PARAM params[])
160 {
161 const OSSL_PARAM *p;
162 KDF_PVK *ctx = vctx;
163 OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx);
164
165 if (params == NULL)
166 return 1;
167
168 if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx))
169 return 0;
170
171 if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL)
172 if (!pvk_set_membuf(&ctx->pass, &ctx->pass_len, p))
173 return 0;
174
175 if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) {
176 if (!pvk_set_membuf(&ctx->salt, &ctx->salt_len, p))
177 return 0;
178 }
179
180 return 1;
181 }
182
kdf_pvk_settable_ctx_params(ossl_unused void * ctx,ossl_unused void * p_ctx)183 static const OSSL_PARAM *kdf_pvk_settable_ctx_params(ossl_unused void *ctx,
184 ossl_unused void *p_ctx)
185 {
186 static const OSSL_PARAM known_settable_ctx_params[] = {
187 OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
188 OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0),
189 OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PASSWORD, NULL, 0),
190 OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0),
191 OSSL_PARAM_END
192 };
193 return known_settable_ctx_params;
194 }
195
kdf_pvk_get_ctx_params(void * vctx,OSSL_PARAM params[])196 static int kdf_pvk_get_ctx_params(void *vctx, OSSL_PARAM params[])
197 {
198 OSSL_PARAM *p;
199
200 if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
201 return OSSL_PARAM_set_size_t(p, SIZE_MAX);
202 return -2;
203 }
204
kdf_pvk_gettable_ctx_params(ossl_unused void * ctx,ossl_unused void * p_ctx)205 static const OSSL_PARAM *kdf_pvk_gettable_ctx_params(ossl_unused void *ctx,
206 ossl_unused void *p_ctx)
207 {
208 static const OSSL_PARAM known_gettable_ctx_params[] = {
209 OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
210 OSSL_PARAM_END
211 };
212 return known_gettable_ctx_params;
213 }
214
215 const OSSL_DISPATCH ossl_kdf_pvk_functions[] = {
216 { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_pvk_new },
217 { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_pvk_free },
218 { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_pvk_reset },
219 { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_pvk_derive },
220 { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS,
221 (void(*)(void))kdf_pvk_settable_ctx_params },
222 { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_pvk_set_ctx_params },
223 { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
224 (void(*)(void))kdf_pvk_gettable_ctx_params },
225 { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_pvk_get_ctx_params },
226 { 0, NULL }
227 };
228