1 /*
2 * Copyright (c) 2021-2022 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 #ifdef HKS_CONFIG_FILE
17 #include HKS_CONFIG_FILE
18 #else
19 #include "hks_config.h"
20 #endif
21
22 #ifdef HKS_SUPPORT_DH_C
23
24 #include "hks_openssl_dh.h"
25
26 #include <openssl/bn.h>
27 #include <openssl/dh.h>
28 #include <openssl/obj_mac.h>
29 #include <openssl/ossl_typ.h>
30 #include <stdbool.h>
31 #include <stddef.h>
32
33 #include "hks_log.h"
34 #include "hks_mem.h"
35 #include "hks_openssl_engine.h"
36 #include "hks_template.h"
37 #include "securec.h"
38
HksOpensslGetNid(uint32_t keySize,int * nid)39 static int32_t HksOpensslGetNid(uint32_t keySize, int *nid)
40 {
41 switch (keySize) {
42 case HKS_DH_KEY_SIZE_2048:
43 *nid = NID_ffdhe2048;
44 return HKS_SUCCESS;
45 case HKS_DH_KEY_SIZE_3072:
46 *nid = NID_ffdhe3072;
47 return HKS_SUCCESS;
48 case HKS_DH_KEY_SIZE_4096:
49 *nid = NID_ffdhe4096;
50 return HKS_SUCCESS;
51 default:
52 HKS_LOG_E("invalid key size, keySize = %" LOG_PUBLIC "u", keySize);
53 return HKS_ERROR_INVALID_KEY_SIZE;
54 }
55 }
56
HksFreeBigNum(BIGNUM * numOne,BIGNUM * numTwo,BIGNUM * numThree)57 static void HksFreeBigNum(BIGNUM *numOne, BIGNUM *numTwo, BIGNUM *numThree)
58 {
59 if (numOne != NULL) {
60 BN_free(numOne);
61 }
62 if (numTwo != NULL) {
63 BN_free(numTwo);
64 }
65 if (numThree != NULL) {
66 BN_free(numThree);
67 }
68 }
69
InitDhStruct(const struct HksBlob * key)70 static DH *InitDhStruct(const struct HksBlob *key)
71 {
72 const struct KeyMaterialDh *keyMaterial = (struct KeyMaterialDh *)(key->data);
73 if (key->size != sizeof(struct KeyMaterialDh) + keyMaterial->pubKeySize + keyMaterial->priKeySize) {
74 return NULL;
75 }
76
77 int nid = 0;
78 int32_t ret = HksOpensslGetNid(keyMaterial->keySize, &nid);
79 HKS_IF_NOT_SUCC_RETURN(ret, NULL)
80
81 DH *dh = DH_new_by_nid(nid);
82 if (dh == NULL) {
83 HksLogOpensslError();
84 return NULL;
85 }
86
87 uint32_t offset = sizeof(struct KeyMaterialDh);
88 BIGNUM *pubKey = BN_bin2bn(key->data + offset, keyMaterial->pubKeySize, NULL);
89 offset += keyMaterial->pubKeySize;
90 BIGNUM *privKey = BN_bin2bn(key->data + offset, keyMaterial->priKeySize, NULL);
91
92 if (DH_set0_key(dh, pubKey, privKey) != HKS_OPENSSL_SUCCESS) {
93 HksLogOpensslError();
94 DH_free(dh);
95 return NULL;
96 }
97
98 return dh;
99 }
100
InitDhPubStruct(const struct HksBlob * key)101 static DH *InitDhPubStruct(const struct HksBlob *key)
102 {
103 const struct KeyMaterialDh *keyMaterial = (struct KeyMaterialDh *)(key->data);
104
105 int nid = 0;
106 int32_t ret = HksOpensslGetNid(keyMaterial->keySize, &nid);
107 HKS_IF_NOT_SUCC_RETURN(ret, NULL)
108
109 DH *dh = DH_new_by_nid(nid);
110 if (dh == NULL) {
111 HksLogOpensslError();
112 return NULL;
113 }
114
115 uint32_t offset = sizeof(struct KeyMaterialDh);
116 BIGNUM *pubKey = BN_bin2bn(key->data + offset, keyMaterial->pubKeySize, NULL);
117
118 if (DH_set0_key(dh, pubKey, NULL) != HKS_OPENSSL_SUCCESS) {
119 HksLogOpensslError();
120 DH_free(dh);
121 return NULL;
122 }
123
124 return dh;
125 }
126
127 #ifdef HKS_SUPPORT_DH_GENERATE_KEY
DhSaveKeyMaterial(const DH * dh,const uint32_t keySize,struct HksBlob * key)128 static int32_t DhSaveKeyMaterial(const DH *dh, const uint32_t keySize, struct HksBlob *key)
129 {
130 const BIGNUM *pubKey = NULL;
131 const BIGNUM *privKey = NULL;
132 DH_get0_key(dh, &pubKey, &privKey);
133 const uint32_t rawMaterialLen = sizeof(struct KeyMaterialDh) + (uint32_t)BN_num_bytes(pubKey)
134 + (uint32_t)BN_num_bytes(privKey);
135 uint8_t *rawMaterial = (uint8_t *)HksMalloc(rawMaterialLen);
136 HKS_IF_NULL_RETURN(rawMaterial, HKS_ERROR_MALLOC_FAIL)
137
138 (void)memset_s(rawMaterial, rawMaterialLen, 0, rawMaterialLen);
139
140 struct KeyMaterialDh *keyMaterial = (struct KeyMaterialDh *)rawMaterial;
141 keyMaterial->keyAlg = HKS_ALG_DH;
142 keyMaterial->keySize = keySize;
143 keyMaterial->pubKeySize = (uint32_t)BN_num_bytes(pubKey);
144 keyMaterial->priKeySize = (uint32_t)BN_num_bytes(privKey);
145 keyMaterial->reserved = 0;
146
147 uint32_t offset = sizeof(struct KeyMaterialDh);
148 BN_bn2bin(pubKey, rawMaterial + offset);
149 offset += keyMaterial->pubKeySize;
150 BN_bn2bin(privKey, rawMaterial + offset);
151
152 key->size = rawMaterialLen;
153 key->data = rawMaterial;
154
155 return HKS_SUCCESS;
156 }
157
HksOpensslDhGenerateKey(const struct HksKeySpec * spec,struct HksBlob * key)158 int32_t HksOpensslDhGenerateKey(const struct HksKeySpec *spec, struct HksBlob *key)
159 {
160 int32_t ret;
161 int nid = 0;
162 ret = HksOpensslGetNid(spec->keyLen, &nid);
163 HKS_IF_NOT_SUCC_RETURN(ret, ret)
164
165 DH *dh = DH_new_by_nid(nid);
166 if (dh == NULL) {
167 HksLogOpensslError();
168 return HKS_ERROR_CRYPTO_ENGINE_ERROR;
169 }
170 if (DH_generate_key(dh) != HKS_OPENSSL_SUCCESS) {
171 HksLogOpensslError();
172 DH_free(dh);
173 return HKS_ERROR_CRYPTO_ENGINE_ERROR;
174 }
175
176 ret = DhSaveKeyMaterial(dh, spec->keyLen, key);
177
178 DH_free(dh);
179
180 return ret;
181 }
182 #endif /* HKS_SUPPORT_DH_GENERATE_KEY */
183
184 #ifdef HKS_SUPPORT_DH_GET_PUBLIC_KEY
HksOpensslGetDhPubKey(const struct HksBlob * input,struct HksBlob * output)185 int32_t HksOpensslGetDhPubKey(const struct HksBlob *input, struct HksBlob *output)
186 {
187 struct KeyMaterialDh *keyMaterial = (struct KeyMaterialDh *)input->data;
188 if (input->size < sizeof(struct KeyMaterialDh) + keyMaterial->pubKeySize) {
189 return HKS_ERROR_INVALID_ARGUMENT;
190 }
191 if (output->size < sizeof(struct KeyMaterialDh) + keyMaterial->pubKeySize) {
192 return HKS_ERROR_INVALID_ARGUMENT;
193 }
194
195 (void)memcpy_s(output->data, output->size, input->data, sizeof(struct KeyMaterialDh) + keyMaterial->pubKeySize);
196 ((struct KeyMaterialDh *)output->data)->priKeySize = 0;
197 ((struct KeyMaterialDh *)output->data)->reserved = 0;
198 output->size = sizeof(struct KeyMaterialDh) + keyMaterial->pubKeySize;
199
200 return HKS_SUCCESS;
201 }
202 #endif /* HKS_SUPPORT_DH_GET_PUBLIC_KEY */
203
204 #ifdef HKS_SUPPORT_DH_AGREE_KEY
HksOpensslDhCheckPubKey(const struct HksBlob * nativeKey,DH * dh)205 static int32_t HksOpensslDhCheckPubKey(const struct HksBlob *nativeKey, DH *dh)
206 {
207 int32_t ret = HKS_ERROR_INVALID_KEY_INFO;
208 struct KeyMaterialDh *pubKeyMaterial = (struct KeyMaterialDh *)nativeKey->data;
209 BIGNUM *pub = BN_bin2bn(nativeKey->data + sizeof(struct KeyMaterialDh), pubKeyMaterial->pubKeySize, NULL);
210 const BIGNUM *p = NULL;
211 BIGNUM *one = BN_new();
212 BIGNUM *r = BN_new();
213 do {
214 if (one == NULL || r == NULL || pub == NULL) {
215 HKS_LOG_E("compute bignum fail");
216 break;
217 }
218 if (BN_is_zero(pub) == HKS_OPENSSL_SUCCESS) {
219 HKS_LOG_E("pub is not secure, pub equals 0");
220 break;
221 }
222 if (BN_is_one(pub) == HKS_OPENSSL_SUCCESS) {
223 HKS_LOG_E("pub is not secure, pub equals 1");
224 break;
225 }
226 DH_get0_pqg((const DH *)dh, &p, NULL, NULL);
227 if (BN_cmp(pub, p) == 0) {
228 HKS_LOG_E("pub is not secure, pub equals p");
229 break;
230 }
231
232 if (BN_one(one) != HKS_OPENSSL_SUCCESS) {
233 HKS_LOG_E("set one fail");
234 break;
235 }
236 if (BN_sub(r, p, one) != HKS_OPENSSL_SUCCESS) {
237 HKS_LOG_E("compute p-1 fail");
238 break;
239 }
240 if (BN_cmp(pub, r) == 0) {
241 HKS_LOG_E("pub is not secure, pub equals p-1");
242 break;
243 }
244 ret = HKS_SUCCESS;
245 } while (0);
246
247 HksFreeBigNum(one, r, pub);
248 return ret;
249 }
250
HksOpensslCheckDhKey(const struct HksBlob * key,enum HksImportKeyType importKeyType)251 int32_t HksOpensslCheckDhKey(const struct HksBlob *key, enum HksImportKeyType importKeyType)
252 {
253 DH *dh = NULL;
254 if (importKeyType == HKS_KEY_TYPE_KEY_PAIR) {
255 dh = InitDhStruct(key);
256 } else if (importKeyType == HKS_KEY_TYPE_PUBLIC_KEY) {
257 dh = InitDhPubStruct(key);
258 }
259 if (dh == NULL) {
260 HKS_LOG_E("Init dh struct fail");
261 return HKS_ERROR_CRYPTO_ENGINE_ERROR;
262 }
263
264 int32_t ret = HksOpensslDhCheckPubKey(key, dh);
265 if (ret != HKS_SUCCESS) {
266 HKS_LOG_E("dh public key is not secure");
267 }
268 DH_free(dh);
269 return ret;
270 }
271
HksOpensslDhAgreeKey(const struct HksBlob * nativeKey,const struct HksBlob * pubKey,const struct HksKeySpec * spec,struct HksBlob * sharedKey)272 int32_t HksOpensslDhAgreeKey(const struct HksBlob *nativeKey, const struct HksBlob *pubKey,
273 const struct HksKeySpec *spec, struct HksBlob *sharedKey)
274 {
275 int32_t ret;
276 if (HKS_KEY_BYTES(spec->keyLen) > sharedKey->size) {
277 return HKS_ERROR_INVALID_KEY_SIZE;
278 }
279
280 struct KeyMaterialDh *pubKeyMaterial = (struct KeyMaterialDh *)pubKey->data;
281 BIGNUM *pub = BN_bin2bn(pubKey->data + sizeof(struct KeyMaterialDh), pubKeyMaterial->pubKeySize, NULL);
282 HKS_IF_NULL_RETURN(pub, HKS_ERROR_CRYPTO_ENGINE_ERROR)
283
284 ret = HksOpensslCheckDhKey(pubKey, HKS_KEY_TYPE_PUBLIC_KEY);
285 if (ret != HKS_SUCCESS) {
286 BN_free(pub);
287 return ret;
288 }
289
290 DH *dh = InitDhStruct(nativeKey);
291 uint8_t *computeKey = HksMalloc(DH_size(dh));
292 if (computeKey == NULL) {
293 BN_free(pub);
294 DH_free(dh);
295 return HKS_ERROR_MALLOC_FAIL;
296 }
297
298 if (DH_compute_key_padded(computeKey, pub, dh) <= 0) {
299 HksLogOpensslError();
300 BN_free(pub);
301 DH_free(dh);
302 HKS_FREE(computeKey);
303 return HKS_ERROR_CRYPTO_ENGINE_ERROR;
304 }
305
306 if (HKS_KEY_BYTES(spec->keyLen) > (uint32_t)DH_size(dh)) {
307 ret = HKS_ERROR_INVALID_KEY_SIZE;
308 } else {
309 if (memcpy_s(sharedKey->data, sharedKey->size, computeKey, HKS_KEY_BYTES(spec->keyLen)) != EOK) {
310 ret = HKS_ERROR_INSUFFICIENT_MEMORY;
311 } else {
312 HKS_LOG_I("get agreed key size %" LOG_PUBLIC "u", HKS_KEY_BYTES(spec->keyLen));
313 sharedKey->size = HKS_KEY_BYTES(spec->keyLen);
314 ret = HKS_SUCCESS;
315 }
316 }
317
318 (void)memset_s(computeKey, DH_size(dh), 0, DH_size(dh));
319 BN_free(pub);
320 DH_free(dh);
321 HKS_FREE(computeKey);
322 return ret;
323 }
324 #endif /* HKS_SUPPORT_DH_AGREE_KEY */
325
326 #endif /* HKS_SUPPORT_DH_C */