• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     if (memcpy_s(output->data, output->size, input->data, sizeof(struct KeyMaterialDh) +
196         keyMaterial->pubKeySize) != EOK) {
197         HKS_LOG_E("copy output data failed!");
198         return HKS_ERROR_INSUFFICIENT_MEMORY;
199     }
200     ((struct KeyMaterialDh *)output->data)->priKeySize = 0;
201     ((struct KeyMaterialDh *)output->data)->reserved = 0;
202     output->size = sizeof(struct KeyMaterialDh) + keyMaterial->pubKeySize;
203 
204     return HKS_SUCCESS;
205 }
206 #endif /* HKS_SUPPORT_DH_GET_PUBLIC_KEY */
207 
208 #ifdef HKS_SUPPORT_DH_AGREE_KEY
HksOpensslDhCheckPubKey(const struct HksBlob * nativeKey,DH * dh)209 static int32_t HksOpensslDhCheckPubKey(const struct HksBlob *nativeKey, DH *dh)
210 {
211     int32_t ret = HKS_ERROR_INVALID_KEY_INFO;
212     struct KeyMaterialDh *pubKeyMaterial = (struct KeyMaterialDh *)nativeKey->data;
213     BIGNUM *pub = BN_bin2bn(nativeKey->data + sizeof(struct KeyMaterialDh), pubKeyMaterial->pubKeySize, NULL);
214     const BIGNUM *p = NULL;
215     BIGNUM *one = BN_new();
216     BIGNUM *r = BN_new();
217     do {
218         if (one == NULL || r == NULL || pub == NULL) {
219             HKS_LOG_E("compute bignum fail");
220             break;
221         }
222         if (BN_is_zero(pub) == HKS_OPENSSL_SUCCESS) {
223             HKS_LOG_E("pub is not secure, pub equals 0");
224             break;
225         }
226         if (BN_is_one(pub) == HKS_OPENSSL_SUCCESS) {
227             HKS_LOG_E("pub is not secure, pub equals 1");
228             break;
229         }
230         DH_get0_pqg((const DH *)dh, &p, NULL, NULL);
231         if (BN_cmp(pub, p) == 0) {
232             HKS_LOG_E("pub is not secure, pub equals p");
233             break;
234         }
235 
236         if (BN_one(one) != HKS_OPENSSL_SUCCESS) {
237             HKS_LOG_E("set one fail");
238             break;
239         }
240         if (BN_sub(r, p, one) != HKS_OPENSSL_SUCCESS) {
241             HKS_LOG_E("compute p-1 fail");
242             break;
243         }
244         if (BN_cmp(pub, r) == 0) {
245             HKS_LOG_E("pub is not secure, pub equals p-1");
246             break;
247         }
248         ret = HKS_SUCCESS;
249     } while (0);
250 
251     HksFreeBigNum(one, r, pub);
252     return ret;
253 }
254 
HksOpensslCheckDhKey(const struct HksBlob * key,enum HksImportKeyType importKeyType)255 int32_t HksOpensslCheckDhKey(const struct HksBlob *key, enum HksImportKeyType importKeyType)
256 {
257     DH *dh = NULL;
258     if (importKeyType == HKS_KEY_TYPE_KEY_PAIR) {
259         dh = InitDhStruct(key);
260     } else if (importKeyType == HKS_KEY_TYPE_PUBLIC_KEY) {
261         dh = InitDhPubStruct(key);
262     }
263     if (dh == NULL) {
264         HKS_LOG_E("Init dh struct fail");
265         return HKS_ERROR_CRYPTO_ENGINE_ERROR;
266     }
267 
268     int32_t ret = HksOpensslDhCheckPubKey(key, dh);
269     if (ret != HKS_SUCCESS) {
270         HKS_LOG_E("dh public key is not secure");
271     }
272     DH_free(dh);
273     return ret;
274 }
275 
HksOpensslDhAgreeKey(const struct HksBlob * nativeKey,const struct HksBlob * pubKey,const struct HksKeySpec * spec,struct HksBlob * sharedKey)276 int32_t HksOpensslDhAgreeKey(const struct HksBlob *nativeKey, const struct HksBlob *pubKey,
277     const struct HksKeySpec *spec, struct HksBlob *sharedKey)
278 {
279     int32_t ret;
280     if (HKS_KEY_BYTES(spec->keyLen) > sharedKey->size) {
281         return HKS_ERROR_INVALID_KEY_SIZE;
282     }
283 
284     struct KeyMaterialDh *pubKeyMaterial = (struct KeyMaterialDh *)pubKey->data;
285     BIGNUM *pub = BN_bin2bn(pubKey->data + sizeof(struct KeyMaterialDh), pubKeyMaterial->pubKeySize, NULL);
286     HKS_IF_NULL_RETURN(pub, HKS_ERROR_CRYPTO_ENGINE_ERROR)
287 
288     ret = HksOpensslCheckDhKey(pubKey, HKS_KEY_TYPE_PUBLIC_KEY);
289     if (ret != HKS_SUCCESS) {
290         BN_free(pub);
291         return ret;
292     }
293 
294     DH *dh = InitDhStruct(nativeKey);
295     uint8_t *computeKey = HksMalloc(DH_size(dh));
296     if (computeKey == NULL) {
297         BN_free(pub);
298         DH_free(dh);
299         return HKS_ERROR_MALLOC_FAIL;
300     }
301 
302     if (DH_compute_key_padded(computeKey, pub, dh) <= 0) {
303         HksLogOpensslError();
304         BN_free(pub);
305         DH_free(dh);
306         HKS_FREE(computeKey);
307         return HKS_ERROR_CRYPTO_ENGINE_ERROR;
308     }
309 
310     if (HKS_KEY_BYTES(spec->keyLen) > (uint32_t)DH_size(dh)) {
311         ret = HKS_ERROR_INVALID_KEY_SIZE;
312     } else {
313         if (memcpy_s(sharedKey->data, sharedKey->size, computeKey, HKS_KEY_BYTES(spec->keyLen)) != EOK) {
314             ret = HKS_ERROR_INSUFFICIENT_MEMORY;
315         } else {
316             HKS_LOG_I("get agreed key size %" LOG_PUBLIC "u", HKS_KEY_BYTES(spec->keyLen));
317             sharedKey->size = HKS_KEY_BYTES(spec->keyLen);
318             ret = HKS_SUCCESS;
319         }
320     }
321 
322     (void)memset_s(computeKey, DH_size(dh), 0, DH_size(dh));
323     BN_free(pub);
324     DH_free(dh);
325     HKS_FREE(computeKey);
326     return ret;
327 }
328 #endif /* HKS_SUPPORT_DH_AGREE_KEY */
329 
330 #endif /* HKS_SUPPORT_DH_C */