1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *    http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "hkdf_openssl.h"
17 
18 #include "log.h"
19 #include "memory.h"
20 #include "result.h"
21 #include "securec.h"
22 #include "utils.h"
23 #include "openssl_adapter.h"
24 #include "openssl_common.h"
25 #include "openssl/kdf.h"
26 #include "detailed_hkdf_params.h"
27 
28 #define HKDF_ALG_NAME "HKDF"
29 
30 typedef struct {
31     unsigned char *salt;
32     int saltLen;
33     unsigned char *key;
34     int keyLen;
35     unsigned char *info;
36     int infoLen;
37     unsigned char *out;
38     int outLen;
39 } HcfHkdfData;
40 
41 typedef struct {
42     HcfKdfSpi base;
43     int digestAlg;
44     int mode;
45     HcfHkdfData *kdfData;
46 } OpensslHkdfSpiImpl;
47 
EngineGetKdfClass(void)48 static const char *EngineGetKdfClass(void)
49 {
50     return "OpensslHkdf";
51 }
52 
HcfClearAndFree(unsigned char * buf,int bufLen)53 static void HcfClearAndFree(unsigned char *buf, int bufLen)
54 {
55     // when buf == null, bufLen must be 0; in check func, bufLen >= 0
56     if (buf == NULL) {
57         return;
58     }
59     (void)memset_s(buf, bufLen, 0, bufLen);
60     HcfFree(buf);
61 }
62 
FreeHkdfData(HcfHkdfData ** data)63 static void FreeHkdfData(HcfHkdfData **data)
64 {
65     if (data == NULL || *data == NULL) {
66         return;
67     }
68     HcfClearAndFree((*data)->out, (*data)->outLen);
69     HcfClearAndFree((*data)->salt, (*data)->saltLen);
70     HcfClearAndFree((*data)->info, (*data)->infoLen);
71     HcfClearAndFree((*data)->key, (*data)->keyLen);
72     (void)memset_s(*data, sizeof(HcfHkdfData), 0, sizeof(HcfHkdfData));
73     HcfFree(*data);
74     *data = NULL;
75 }
76 
EngineDestroyKdf(HcfObjectBase * self)77 static void EngineDestroyKdf(HcfObjectBase *self)
78 {
79     if (self == NULL) {
80         LOGE("Self ptr is NULL!");
81         return;
82     }
83     if (!HcfIsClassMatch(self, EngineGetKdfClass())) {
84         LOGE("Class is not match.");
85         return;
86     }
87     OpensslHkdfSpiImpl *impl = (OpensslHkdfSpiImpl *)self;
88     FreeHkdfData(&(impl->kdfData));
89     HcfFree(self);
90 }
91 
CheckHkdfParams(HcfHkdfParamsSpec * params)92 static bool CheckHkdfParams(HcfHkdfParamsSpec *params)
93 {
94     // openssl only support INT and blob attribute is size_t, it should samller than INT_MAX.
95     if (params->output.len > INT_MAX || params->salt.len > INT_MAX || params->key.len > INT_MAX ||
96         params->info.len > INT_MAX) {
97             LOGE("beyond the length");
98             return false;
99     }
100     if (params->key.data == NULL && params->key.len == 0) {
101         LOGE("check params failed, key is NULL");
102         return false;
103     }
104     if (params->output.data == NULL || params->output.len == 0) {
105         LOGE("check params failed, output data is NULL");
106         return false;
107     }
108     if (params->salt.data == NULL && params->salt.len == 0) {
109         LOGD("empty salt");
110     }
111     if (params->info.data == NULL && params->info.len == 0) {
112         LOGD("empty info");
113     }
114     return true;
115 }
116 
GetHkdfKeyFromSpec(HcfHkdfData * data,HcfHkdfParamsSpec * params)117 static bool GetHkdfKeyFromSpec(HcfHkdfData *data, HcfHkdfParamsSpec *params)
118 {
119     data->key = (unsigned char *)HcfMalloc(params->key.len, 0);
120     if (data->key == NULL) {
121         return false;
122     }
123     (void)memcpy_s(data->key, params->key.len, params->key.data, params->key.len);
124     data->keyLen = params->key.len;
125     return true;
126 }
127 
GetHkdfMode(OpensslHkdfSpiImpl * self)128 static int GetHkdfMode(OpensslHkdfSpiImpl *self)
129 {
130     switch (self->mode) {
131         case HCF_ALG_MODE_EXTRACT_AND_EXPAND:
132             return EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND;
133         case HCF_ALG_MODE_EXTRACT_ONLY:
134             return EVP_KDF_HKDF_MODE_EXTRACT_ONLY;
135         case HCF_ALG_MODE_EXPAND_ONLY:
136             return EVP_KDF_HKDF_MODE_EXPAND_ONLY;
137         default:
138             return EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND;
139     }
140 }
141 
GetHkdfInfoFromSpec(OpensslHkdfSpiImpl * self,HcfHkdfData * data,HcfHkdfParamsSpec * params)142 static bool GetHkdfInfoFromSpec(OpensslHkdfSpiImpl *self, HcfHkdfData *data, HcfHkdfParamsSpec *params)
143 {
144     if (self->mode == HCF_ALG_MODE_EXTRACT_ONLY) {
145         LOGD("EXTRACT_ONLY mode does not require info");
146         return true;
147     }
148 
149     if (params->info.len == 0) {
150         LOGD("info can be empty.");
151         return true;
152     }
153 
154     data->info = (unsigned char *)HcfMalloc(params->info.len, 0);
155     if (data->info == NULL) {
156         return false;
157     }
158     (void)memcpy_s(data->info, params->info.len, params->info.data, params->info.len);
159     data->infoLen = params->info.len;
160     return true;
161 }
162 
GetHkdfSaltFromSpec(OpensslHkdfSpiImpl * self,HcfHkdfData * data,HcfHkdfParamsSpec * params)163 static bool GetHkdfSaltFromSpec(OpensslHkdfSpiImpl *self, HcfHkdfData *data, HcfHkdfParamsSpec *params)
164 {
165     if (self->mode == HCF_ALG_MODE_EXPAND_ONLY) {
166         LOGD("EXPAND_ONLY mode does not require salt");
167         return true;
168     }
169 
170     if (params->salt.len == 0) {
171         LOGD("salt can be empty.");
172         return true;
173     }
174 
175     data->salt = (unsigned char *)HcfMalloc(params->salt.len, 0);
176     if (data->salt == NULL) {
177         return false;
178     }
179     (void)memcpy_s(data->salt, params->salt.len, params->salt.data, params->salt.len);
180     data->saltLen = params->salt.len;
181     return true;
182 }
183 
InitHkdfData(OpensslHkdfSpiImpl * self,HcfHkdfParamsSpec * params)184 static HcfResult InitHkdfData(OpensslHkdfSpiImpl *self, HcfHkdfParamsSpec *params)
185 {
186     LOGD("MODE IS %d", self->mode);
187     HcfHkdfData *data = (HcfHkdfData *)HcfMalloc(sizeof(HcfHkdfData), 0);
188     do {
189         if (data == NULL) {
190             LOGE("malloc data failed");
191             break;
192         }
193         if (!GetHkdfKeyFromSpec(data, params)) {
194             LOGE("malloc key failed!");
195             break;
196         }
197         if (!GetHkdfSaltFromSpec(self, data, params)) {
198             LOGE("malloc salt failed!");
199             break;
200         }
201         if (!GetHkdfInfoFromSpec(self, data, params)) {
202             LOGE("malloc info failed!");
203             break;
204         }
205         data->out = (unsigned char *)HcfMalloc(params->output.len, 0);
206         if (data->out == NULL) {
207             LOGE("malloc out failed!");
208             break;
209         }
210         data->outLen = params->output.len;
211         self->kdfData = data;
212         return HCF_SUCCESS;
213     } while (0);
214     FreeHkdfData(&data);
215     return HCF_ERR_MALLOC;
216 }
217 
SwitchMd(OpensslHkdfSpiImpl * self)218 static char *SwitchMd(OpensslHkdfSpiImpl *self)
219 {
220     switch (self->digestAlg) {
221         case HCF_OPENSSL_DIGEST_NONE:
222             return "";
223         case HCF_OPENSSL_DIGEST_MD5:
224             return "MD5";
225         case HCF_OPENSSL_DIGEST_SM3:
226             return "SM3";
227         case HCF_OPENSSL_DIGEST_SHA1:
228             return "SHA1";
229         case HCF_OPENSSL_DIGEST_SHA224:
230             return "SHA224";
231         case HCF_OPENSSL_DIGEST_SHA256:
232             return "SHA256";
233         case HCF_OPENSSL_DIGEST_SHA384:
234             return "SHA384";
235         case HCF_OPENSSL_DIGEST_SHA512:
236             return "SHA512";
237         default:
238             return "";
239     }
240 }
241 
OpensslHkdf(OpensslHkdfSpiImpl * self,HcfBlob * output)242 static HcfResult OpensslHkdf(OpensslHkdfSpiImpl *self, HcfBlob *output)
243 {
244     EVP_KDF *kdf = NULL;
245     EVP_KDF_CTX *kctx = NULL;
246     // need set 6 params
247     OSSL_PARAM params[6] = {};
248     OSSL_PARAM *p = params;
249 
250     kdf = OpensslEvpKdfFetch(NULL, "HKDF", NULL);
251     if (kdf == NULL) {
252         LOGE("kdf fetch failed");
253         return HCF_ERR_CRYPTO_OPERATION;
254     }
255 
256     kctx = OpensslEvpKdfCtxNew(kdf);
257     OpensslEvpKdfFree(kdf);
258     if (kctx == NULL) {
259         LOGE("kdf ctx new failed");
260         return HCF_ERR_CRYPTO_OPERATION;
261     }
262 
263     int mode = GetHkdfMode(self);
264     char *digest = SwitchMd(self);
265     *p++ = OpensslOsslParamConstructUtf8String("digest", digest, 0);
266     *p++ = OpensslOsslParamConstructOctetString("key", self->kdfData->key, self->kdfData->keyLen);
267     *p++ = OpensslOsslParamConstructOctetString("info", self->kdfData->info, self->kdfData->infoLen);
268     *p++ = OpensslOsslParamConstructOctetString("salt", self->kdfData->salt, self->kdfData->saltLen);
269     *p++ = OpensslOsslParamConstructInt("mode", &mode);
270     *p = OpensslOsslParamConstructEnd();
271     if (OpensslEvpKdfDerive(kctx, output->data, output->len, params) <= 0) {
272         HcfPrintOpensslError();
273         LOGE("EVP_KDF_derive failed");
274         OpensslEvpKdfCtxFree(kctx);
275         return HCF_ERR_CRYPTO_OPERATION;
276     }
277     OpensslEvpKdfCtxFree(kctx);
278     return HCF_SUCCESS;
279 }
280 
EngineGenerateSecret(HcfKdfSpi * self,HcfKdfParamsSpec * paramsSpec)281 static HcfResult EngineGenerateSecret(HcfKdfSpi *self, HcfKdfParamsSpec *paramsSpec)
282 {
283     if (self == NULL || paramsSpec == NULL) {
284         LOGE("Invalid input parameter.");
285         return HCF_INVALID_PARAMS;
286     }
287     if (!HcfIsClassMatch((HcfObjectBase *)self, EngineGetKdfClass())) {
288         return HCF_INVALID_PARAMS;
289     }
290     OpensslHkdfSpiImpl *hkdfImpl = (OpensslHkdfSpiImpl *)self;
291     if (paramsSpec->algName == NULL || strcmp(paramsSpec->algName, HKDF_ALG_NAME) != 0) {
292         LOGE("Not hkdf paramsSpec");
293         return HCF_INVALID_PARAMS;
294     }
295     HcfHkdfParamsSpec *params = (HcfHkdfParamsSpec *)paramsSpec;
296     if (!CheckHkdfParams(params)) {
297         LOGE("params error");
298         return HCF_INVALID_PARAMS;
299     }
300     HcfResult res = InitHkdfData(hkdfImpl, params);
301     if (res != HCF_SUCCESS) {
302         LOGE("InitCipherData failed!");
303         return res;
304     }
305     res = OpensslHkdf(hkdfImpl, &params->output);
306     FreeHkdfData(&(hkdfImpl->kdfData));
307     return res;
308 }
309 
HcfKdfHkdfSpiCreate(HcfKdfDeriveParams * params,HcfKdfSpi ** spiObj)310 HcfResult HcfKdfHkdfSpiCreate(HcfKdfDeriveParams *params, HcfKdfSpi **spiObj)
311 {
312     if (params == NULL || spiObj == NULL) {
313         LOGE("Invalid input parameter.");
314         return HCF_INVALID_PARAMS;
315     }
316     OpensslHkdfSpiImpl *returnSpiImpl = (OpensslHkdfSpiImpl *)HcfMalloc(sizeof(OpensslHkdfSpiImpl), 0);
317     if (returnSpiImpl == NULL) {
318         LOGE("Failed to allocate returnImpl memory!");
319         return HCF_ERR_MALLOC;
320     }
321     returnSpiImpl->base.base.getClass = EngineGetKdfClass;
322     returnSpiImpl->base.base.destroy = EngineDestroyKdf;
323     returnSpiImpl->base.generateSecret = EngineGenerateSecret;
324     returnSpiImpl->digestAlg = params->md;
325     returnSpiImpl->mode = params->mode;
326     *spiObj = (HcfKdfSpi *)returnSpiImpl;
327     return HCF_SUCCESS;
328 }
329