1/*
2 * Copyright 2020-2024 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/crypto.h>
11#include <openssl/kdf.h>
12#include <openssl/core_dispatch.h>
13#include <openssl/core_names.h>
14#include <openssl/err.h>
15#include <openssl/proverr.h>
16#include <openssl/params.h>
17#include "internal/numbers.h"
18#include "prov/implementations.h"
19#include "prov/provider_ctx.h"
20#include "prov/kdfexchange.h"
21#include "prov/providercommon.h"
22
23static OSSL_FUNC_keyexch_newctx_fn kdf_tls1_prf_newctx;
24static OSSL_FUNC_keyexch_newctx_fn kdf_hkdf_newctx;
25static OSSL_FUNC_keyexch_newctx_fn kdf_scrypt_newctx;
26static OSSL_FUNC_keyexch_init_fn kdf_init;
27static OSSL_FUNC_keyexch_derive_fn kdf_derive;
28static OSSL_FUNC_keyexch_freectx_fn kdf_freectx;
29static OSSL_FUNC_keyexch_dupctx_fn kdf_dupctx;
30static OSSL_FUNC_keyexch_set_ctx_params_fn kdf_set_ctx_params;
31static OSSL_FUNC_keyexch_get_ctx_params_fn kdf_get_ctx_params;
32static OSSL_FUNC_keyexch_settable_ctx_params_fn kdf_tls1_prf_settable_ctx_params;
33static OSSL_FUNC_keyexch_settable_ctx_params_fn kdf_hkdf_settable_ctx_params;
34static OSSL_FUNC_keyexch_settable_ctx_params_fn kdf_scrypt_settable_ctx_params;
35static OSSL_FUNC_keyexch_gettable_ctx_params_fn kdf_tls1_prf_gettable_ctx_params;
36static OSSL_FUNC_keyexch_gettable_ctx_params_fn kdf_hkdf_gettable_ctx_params;
37static OSSL_FUNC_keyexch_gettable_ctx_params_fn kdf_scrypt_gettable_ctx_params;
38
39typedef struct {
40    void *provctx;
41    EVP_KDF_CTX *kdfctx;
42    KDF_DATA *kdfdata;
43} PROV_KDF_CTX;
44
45static void *kdf_newctx(const char *kdfname, void *provctx)
46{
47    PROV_KDF_CTX *kdfctx;
48    EVP_KDF *kdf = NULL;
49
50    if (!ossl_prov_is_running())
51        return NULL;
52
53    kdfctx = OPENSSL_zalloc(sizeof(PROV_KDF_CTX));
54    if (kdfctx == NULL)
55        return NULL;
56
57    kdfctx->provctx = provctx;
58
59    kdf = EVP_KDF_fetch(PROV_LIBCTX_OF(provctx), kdfname, NULL);
60    if (kdf == NULL)
61        goto err;
62    kdfctx->kdfctx = EVP_KDF_CTX_new(kdf);
63    EVP_KDF_free(kdf);
64
65    if (kdfctx->kdfctx == NULL)
66        goto err;
67
68    return kdfctx;
69err:
70    OPENSSL_free(kdfctx);
71    return NULL;
72}
73
74#define KDF_NEWCTX(funcname, kdfname) \
75    static void *kdf_##funcname##_newctx(void *provctx) \
76    { \
77        return kdf_newctx(kdfname, provctx); \
78    }
79
80KDF_NEWCTX(tls1_prf, "TLS1-PRF")
81KDF_NEWCTX(hkdf, "HKDF")
82KDF_NEWCTX(scrypt, "SCRYPT")
83
84static int kdf_init(void *vpkdfctx, void *vkdf, const OSSL_PARAM params[])
85{
86    PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx;
87
88    if (!ossl_prov_is_running()
89            || pkdfctx == NULL
90            || vkdf == NULL
91            || !ossl_kdf_data_up_ref(vkdf))
92        return 0;
93    pkdfctx->kdfdata = vkdf;
94
95    return kdf_set_ctx_params(pkdfctx, params);
96}
97
98static int kdf_derive(void *vpkdfctx, unsigned char *secret, size_t *secretlen,
99                      size_t outlen)
100{
101    PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx;
102    size_t kdfsize;
103    int ret;
104
105    if (!ossl_prov_is_running())
106        return 0;
107
108    kdfsize = EVP_KDF_CTX_get_kdf_size(pkdfctx->kdfctx);
109
110    if (secret == NULL) {
111        *secretlen = kdfsize;
112        return 1;
113    }
114
115    if (kdfsize != SIZE_MAX) {
116        if (outlen < kdfsize) {
117            ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
118            return 0;
119        }
120        outlen = kdfsize;
121    }
122
123    ret = EVP_KDF_derive(pkdfctx->kdfctx, secret, outlen, NULL);
124    if (ret <= 0)
125        return 0;
126
127    *secretlen = outlen;
128    return 1;
129}
130
131static void kdf_freectx(void *vpkdfctx)
132{
133    PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx;
134
135    EVP_KDF_CTX_free(pkdfctx->kdfctx);
136    ossl_kdf_data_free(pkdfctx->kdfdata);
137
138    OPENSSL_free(pkdfctx);
139}
140
141static void *kdf_dupctx(void *vpkdfctx)
142{
143    PROV_KDF_CTX *srcctx = (PROV_KDF_CTX *)vpkdfctx;
144    PROV_KDF_CTX *dstctx;
145
146    if (!ossl_prov_is_running())
147        return NULL;
148
149    dstctx = OPENSSL_zalloc(sizeof(*srcctx));
150    if (dstctx == NULL)
151        return NULL;
152
153    *dstctx = *srcctx;
154
155    dstctx->kdfctx = EVP_KDF_CTX_dup(srcctx->kdfctx);
156    if (dstctx->kdfctx == NULL) {
157        OPENSSL_free(dstctx);
158        return NULL;
159    }
160    if (!ossl_kdf_data_up_ref(dstctx->kdfdata)) {
161        EVP_KDF_CTX_free(dstctx->kdfctx);
162        OPENSSL_free(dstctx);
163        return NULL;
164    }
165
166    return dstctx;
167}
168
169static int kdf_set_ctx_params(void *vpkdfctx, const OSSL_PARAM params[])
170{
171    PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx;
172
173    return EVP_KDF_CTX_set_params(pkdfctx->kdfctx, params);
174}
175
176static int kdf_get_ctx_params(void *vpkdfctx, OSSL_PARAM params[])
177{
178    PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx;
179
180    return EVP_KDF_CTX_get_params(pkdfctx->kdfctx, params);
181}
182
183static const OSSL_PARAM *kdf_settable_ctx_params(ossl_unused void *vpkdfctx,
184                                                 void *provctx,
185                                                 const char *kdfname)
186{
187    EVP_KDF *kdf = EVP_KDF_fetch(PROV_LIBCTX_OF(provctx), kdfname,
188                                 NULL);
189    const OSSL_PARAM *params;
190
191    if (kdf == NULL)
192        return NULL;
193
194    params = EVP_KDF_settable_ctx_params(kdf);
195    EVP_KDF_free(kdf);
196
197    return params;
198}
199
200#define KDF_SETTABLE_CTX_PARAMS(funcname, kdfname) \
201    static const OSSL_PARAM *kdf_##funcname##_settable_ctx_params(void *vpkdfctx, \
202                                                                  void *provctx) \
203    { \
204        return kdf_settable_ctx_params(vpkdfctx, provctx, kdfname); \
205    }
206
207KDF_SETTABLE_CTX_PARAMS(tls1_prf, "TLS1-PRF")
208KDF_SETTABLE_CTX_PARAMS(hkdf, "HKDF")
209KDF_SETTABLE_CTX_PARAMS(scrypt, "SCRYPT")
210
211static const OSSL_PARAM *kdf_gettable_ctx_params(ossl_unused void *vpkdfctx,
212                                                 void *provctx,
213                                                 const char *kdfname)
214{
215    EVP_KDF *kdf = EVP_KDF_fetch(PROV_LIBCTX_OF(provctx), kdfname,
216                                 NULL);
217    const OSSL_PARAM *params;
218
219    if (kdf == NULL)
220        return NULL;
221
222    params = EVP_KDF_gettable_ctx_params(kdf);
223    EVP_KDF_free(kdf);
224
225    return params;
226}
227
228#define KDF_GETTABLE_CTX_PARAMS(funcname, kdfname) \
229    static const OSSL_PARAM *kdf_##funcname##_gettable_ctx_params(void *vpkdfctx, \
230                                                                  void *provctx) \
231    { \
232        return kdf_gettable_ctx_params(vpkdfctx, provctx, kdfname); \
233    }
234
235KDF_GETTABLE_CTX_PARAMS(tls1_prf, "TLS1-PRF")
236KDF_GETTABLE_CTX_PARAMS(hkdf, "HKDF")
237KDF_GETTABLE_CTX_PARAMS(scrypt, "SCRYPT")
238
239#define KDF_KEYEXCH_FUNCTIONS(funcname) \
240    const OSSL_DISPATCH ossl_kdf_##funcname##_keyexch_functions[] = { \
241        { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))kdf_##funcname##_newctx }, \
242        { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))kdf_init }, \
243        { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))kdf_derive }, \
244        { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))kdf_freectx }, \
245        { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))kdf_dupctx }, \
246        { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))kdf_set_ctx_params }, \
247        { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))kdf_get_ctx_params }, \
248        { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS, \
249        (void (*)(void))kdf_##funcname##_settable_ctx_params }, \
250        { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS, \
251        (void (*)(void))kdf_##funcname##_gettable_ctx_params }, \
252        { 0, NULL } \
253    };
254
255KDF_KEYEXCH_FUNCTIONS(tls1_prf)
256KDF_KEYEXCH_FUNCTIONS(hkdf)
257KDF_KEYEXCH_FUNCTIONS(scrypt)
258