1/*
2 * Copyright 2020-2022 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_settable_ctx_params_fn kdf_tls1_prf_settable_ctx_params;
32static OSSL_FUNC_keyexch_settable_ctx_params_fn kdf_hkdf_settable_ctx_params;
33static OSSL_FUNC_keyexch_settable_ctx_params_fn kdf_scrypt_settable_ctx_params;
34
35typedef struct {
36    void *provctx;
37    EVP_KDF_CTX *kdfctx;
38    KDF_DATA *kdfdata;
39} PROV_KDF_CTX;
40
41static void *kdf_newctx(const char *kdfname, void *provctx)
42{
43    PROV_KDF_CTX *kdfctx;
44    EVP_KDF *kdf = NULL;
45
46    if (!ossl_prov_is_running())
47        return NULL;
48
49    kdfctx = OPENSSL_zalloc(sizeof(PROV_KDF_CTX));
50    if (kdfctx == NULL)
51        return NULL;
52
53    kdfctx->provctx = provctx;
54
55    kdf = EVP_KDF_fetch(PROV_LIBCTX_OF(provctx), kdfname, NULL);
56    if (kdf == NULL)
57        goto err;
58    kdfctx->kdfctx = EVP_KDF_CTX_new(kdf);
59    EVP_KDF_free(kdf);
60
61    if (kdfctx->kdfctx == NULL)
62        goto err;
63
64    return kdfctx;
65err:
66    OPENSSL_free(kdfctx);
67    return NULL;
68}
69
70#define KDF_NEWCTX(funcname, kdfname) \
71    static void *kdf_##funcname##_newctx(void *provctx) \
72    { \
73        return kdf_newctx(kdfname, provctx); \
74    }
75
76KDF_NEWCTX(tls1_prf, "TLS1-PRF")
77KDF_NEWCTX(hkdf, "HKDF")
78KDF_NEWCTX(scrypt, "SCRYPT")
79
80static int kdf_init(void *vpkdfctx, void *vkdf, const OSSL_PARAM params[])
81{
82    PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx;
83
84    if (!ossl_prov_is_running()
85            || pkdfctx == NULL
86            || vkdf == NULL
87            || !ossl_kdf_data_up_ref(vkdf))
88        return 0;
89    pkdfctx->kdfdata = vkdf;
90
91    return kdf_set_ctx_params(pkdfctx, params);
92}
93
94static int kdf_derive(void *vpkdfctx, unsigned char *secret, size_t *secretlen,
95                      size_t outlen)
96{
97    PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx;
98    size_t kdfsize;
99    int ret;
100
101    if (!ossl_prov_is_running())
102        return 0;
103
104    kdfsize = EVP_KDF_CTX_get_kdf_size(pkdfctx->kdfctx);
105
106    if (secret == NULL) {
107        *secretlen = kdfsize;
108        return 1;
109    }
110
111    if (kdfsize != SIZE_MAX) {
112        if (outlen < kdfsize) {
113            ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
114            return 0;
115        }
116        outlen = kdfsize;
117    }
118
119    ret = EVP_KDF_derive(pkdfctx->kdfctx, secret, outlen, NULL);
120    if (ret <= 0)
121        return 0;
122
123    *secretlen = outlen;
124    return 1;
125}
126
127static void kdf_freectx(void *vpkdfctx)
128{
129    PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx;
130
131    EVP_KDF_CTX_free(pkdfctx->kdfctx);
132    ossl_kdf_data_free(pkdfctx->kdfdata);
133
134    OPENSSL_free(pkdfctx);
135}
136
137static void *kdf_dupctx(void *vpkdfctx)
138{
139    PROV_KDF_CTX *srcctx = (PROV_KDF_CTX *)vpkdfctx;
140    PROV_KDF_CTX *dstctx;
141
142    if (!ossl_prov_is_running())
143        return NULL;
144
145    dstctx = OPENSSL_zalloc(sizeof(*srcctx));
146    if (dstctx == NULL)
147        return NULL;
148
149    *dstctx = *srcctx;
150
151    dstctx->kdfctx = EVP_KDF_CTX_dup(srcctx->kdfctx);
152    if (dstctx->kdfctx == NULL) {
153        OPENSSL_free(dstctx);
154        return NULL;
155    }
156    if (!ossl_kdf_data_up_ref(dstctx->kdfdata)) {
157        EVP_KDF_CTX_free(dstctx->kdfctx);
158        OPENSSL_free(dstctx);
159        return NULL;
160    }
161
162    return dstctx;
163}
164
165static int kdf_set_ctx_params(void *vpkdfctx, const OSSL_PARAM params[])
166{
167    PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx;
168
169    return EVP_KDF_CTX_set_params(pkdfctx->kdfctx, params);
170}
171
172static const OSSL_PARAM *kdf_settable_ctx_params(ossl_unused void *vpkdfctx,
173                                                 void *provctx,
174                                                 const char *kdfname)
175{
176    EVP_KDF *kdf = EVP_KDF_fetch(PROV_LIBCTX_OF(provctx), kdfname,
177                                 NULL);
178    const OSSL_PARAM *params;
179
180    if (kdf == NULL)
181        return NULL;
182
183    params = EVP_KDF_settable_ctx_params(kdf);
184    EVP_KDF_free(kdf);
185
186    return params;
187}
188
189#define KDF_SETTABLE_CTX_PARAMS(funcname, kdfname) \
190    static const OSSL_PARAM *kdf_##funcname##_settable_ctx_params(void *vpkdfctx, \
191                                                                  void *provctx) \
192    { \
193        return kdf_settable_ctx_params(vpkdfctx, provctx, kdfname); \
194    }
195
196KDF_SETTABLE_CTX_PARAMS(tls1_prf, "TLS1-PRF")
197KDF_SETTABLE_CTX_PARAMS(hkdf, "HKDF")
198KDF_SETTABLE_CTX_PARAMS(scrypt, "SCRYPT")
199
200#define KDF_KEYEXCH_FUNCTIONS(funcname) \
201    const OSSL_DISPATCH ossl_kdf_##funcname##_keyexch_functions[] = { \
202        { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))kdf_##funcname##_newctx }, \
203        { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))kdf_init }, \
204        { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))kdf_derive }, \
205        { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))kdf_freectx }, \
206        { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))kdf_dupctx }, \
207        { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))kdf_set_ctx_params }, \
208        { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS, \
209        (void (*)(void))kdf_##funcname##_settable_ctx_params }, \
210        { 0, NULL } \
211    };
212
213KDF_KEYEXCH_FUNCTIONS(tls1_prf)
214KDF_KEYEXCH_FUNCTIONS(hkdf)
215KDF_KEYEXCH_FUNCTIONS(scrypt)
216