1 /*
2  * Copyright (c) 2020 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 "pake_client.h"
17 #include "log.h"
18 #include "mem_stat.h"
19 
20 #if !(defined(_CUT_PAKE_) || defined(_CUT_PAKE_CLIENT_))
21 
22 #include <string.h>
23 #include "securec.h"
24 #include "huks_adapter.h"
25 #include "commonutil.h"
26 
27 static int32_t build_start_request_data(void *handle, void *data);
28 static int32_t parse_start_response_data(void *handle, void *data);
29 static int32_t build_end_request_data(void *handle, void *data);
30 static int32_t parse_end_response_data(void *handle, void *data);
31 
32 #define HICHAIN_SPEKE_BASE_INFO       "hichain_speke_base_info"
33 #define HICHAIN_RETURN_KEY            "hichain_return_key"
34 #define HICHAIN_SPEKE_SESSIONKEY_INFO "hichain_speke_sessionkey_info"
35 
build_pake_client(const struct session_identity * identity,const struct hc_pin * pin,uint32_t key_length,const struct hc_auth_id * client,const struct hc_auth_id * server)36 struct pake_client *build_pake_client(const struct session_identity *identity, const struct hc_pin *pin,
37     uint32_t key_length, const struct hc_auth_id *client, const struct hc_auth_id *server)
38 {
39     struct pake_client *pake_client = (struct pake_client *)MALLOC(sizeof(struct pake_client));
40     if (pake_client == NULL) {
41         LOGE("Build pake client object failed");
42         return NULL;
43     }
44 
45     (void)memset_s(pake_client, sizeof(*pake_client), 0, sizeof(*pake_client));
46     struct client_virtual_func_group funcs = { build_start_request_data, parse_start_response_data,
47                                                build_end_request_data, parse_end_response_data };
48 
49     init_client(&pake_client->client_info, &funcs);
50     pake_client->pin = *pin;
51     pake_client->key_length = key_length;
52     pake_client->self_id = *client;
53     pake_client->peer_id = *server;
54     pake_client->identity = identity;
55     pake_client->prime_type = NUM_LEN_384;
56     LOGI("Build pake client object %u success", pake_client_sn(pake_client));
57 
58     return pake_client;
59 }
60 
destroy_pake_client(struct pake_client * pake_client)61 void destroy_pake_client(struct pake_client *pake_client)
62 {
63     if (pake_client == NULL) {
64         return;
65     }
66 
67     LOGI("Destroy pake client object %u success", pake_client_sn(pake_client));
68     (void)memset_s(&pake_client->pin, sizeof(struct hc_pin), 0, sizeof(struct hc_pin));
69     (void)memset_s(&pake_client->self_esk, sizeof(struct esk), 0, sizeof(struct esk));
70     (void)memset_s(&pake_client->session_key, sizeof(struct pake_session_key), 0, sizeof(struct pake_session_key));
71     (void)memset_s(&pake_client->hmac_key, sizeof(struct pake_hmac_key), 0, sizeof(struct pake_hmac_key));
72     (void)memset_s(&pake_client->service_key, sizeof(struct hc_session_key), 0, sizeof(struct hc_session_key));
73     FREE(pake_client);
74 }
75 
send_pake_start_request(struct pake_client * pake_client,struct message * send)76 int32_t send_pake_start_request(struct pake_client *pake_client, struct message *send)
77 {
78     check_ptr_return_val(pake_client, HC_INPUT_ERROR);
79     check_ptr_return_val(send, HC_INPUT_ERROR);
80     struct pake_start_request_data *send_data =
81         (struct pake_start_request_data *)MALLOC(sizeof(struct pake_start_request_data));
82     if (send_data == NULL) {
83         LOGE("Malloc struct PAKE_START_REQUEST_DATA failed");
84         return HC_MALLOC_FAILED;
85     }
86     (void)memset_s(send_data, sizeof(*send_data), 0, sizeof(*send_data));
87 
88     int32_t ret = send_start_request(pake_client, send_data);
89     if (ret != HC_OK) {
90         LOGE("Called send_start_request failed, error code is %d", ret);
91         FREE(send_data);
92         send->msg_code = INFORM_MESSAGE;
93     } else {
94         DBG_OUT("Called send_start_request success");
95         send->msg_code = PAKE_REQUEST;
96         send->payload = send_data;
97     }
98 
99     return ret;
100 }
101 
send_pake_end_request(struct pake_client * pake_client,const struct message * receive,struct message * send)102 int32_t send_pake_end_request(struct pake_client *pake_client, const struct message *receive, struct message *send)
103 {
104     check_ptr_return_val(pake_client, HC_INPUT_ERROR);
105     check_ptr_return_val(receive, HC_INPUT_ERROR);
106     check_ptr_return_val(send, HC_INPUT_ERROR);
107     DBG_OUT("Receive pake start response message object %u success", pake_client_sn(pake_client));
108     struct pake_start_response_data *receive_data = (struct pake_start_response_data *)receive->payload;
109 
110     struct pake_end_request_data *send_data =
111         (struct pake_end_request_data *)MALLOC(sizeof(struct pake_end_request_data));
112     if (send_data == NULL) {
113         LOGE("Malloc struct pake_end_request_data failed");
114         return HC_MALLOC_FAILED;
115     }
116     (void)memset_s(send_data, sizeof(*send_data), 0, sizeof(*send_data));
117 
118     int32_t ret = send_end_request(pake_client, receive_data, send_data);
119     if (ret != HC_OK) {
120         LOGE("Called send_end_request failed, error code is %d", ret);
121         FREE(send_data);
122         send->msg_code = INFORM_MESSAGE;
123     } else {
124         DBG_OUT("Called send_end_request success");
125         send->msg_code = PAKE_CLIENT_CONFIRM;
126         send->payload = send_data;
127     }
128 
129     return ret;
130 }
131 
receive_pake_end_response(struct pake_client * pake_client,struct message * receive)132 int32_t receive_pake_end_response(struct pake_client *pake_client, struct message *receive)
133 {
134     check_ptr_return_val(pake_client, HC_INPUT_ERROR);
135     check_ptr_return_val(receive, HC_INPUT_ERROR);
136     DBG_OUT("Receive pake end response message object %u success", pake_client_sn(pake_client));
137     struct pake_end_response_data *receive_data = (struct pake_end_response_data *)receive->payload;
138     int32_t ret = receive_end_response(pake_client, receive_data);
139     if (ret != HC_OK) {
140         LOGE("Called receive_end_response failed, error code is %d", ret);
141         receive->msg_code = INFORM_MESSAGE;
142     } else {
143         DBG_OUT("Called receive_end_response success");
144         receive->msg_code = PAKE_SERVER_CONFIRM_RESPONSE;
145         receive->payload = receive_data;
146     }
147 
148     return ret;
149 }
150 
build_start_request_data(void * handle,void * data)151 static int32_t build_start_request_data(void *handle, void *data)
152 {
153     struct pake_client *pake_client = (struct pake_client *)handle;
154     struct pake_start_request_data *send_data = (struct pake_start_request_data *)data;
155 
156     send_data->peer_version.first = 1;
157     send_data->peer_version.second = 0;
158     send_data->peer_version.third = 0;
159     send_data->peer_support_version.first = 1;
160     send_data->peer_support_version.second = 0;
161     send_data->peer_support_version.third = 0;
162     send_data->operation_code = pake_client->operation_code;
163     send_data->epk_len = HC_BIG_PRIME_MAX_LEN;
164 
165     return HC_OK;
166 }
167 
gen_esk_prime_len(struct pake_client * pake_client,struct pake_start_response_data * receive,uint32_t * esk_len,uint32_t * prime_len)168 static int32_t gen_esk_prime_len(struct pake_client *pake_client, struct pake_start_response_data *receive,
169     uint32_t *esk_len, uint32_t *prime_len)
170 {
171     if (receive->epk.length == HC_BIG_PRIME_MAX_LEN_384) {
172         pake_client->prime_type = NUM_LEN_384;
173     } else if (receive->epk.length == HC_BIG_PRIME_MAX_LEN_256) {
174         pake_client->prime_type = NUM_LEN_256;
175     } else {
176         LOGE("Object %u peer is not support big number len %u", pake_client_sn(pake_client), receive->epk.length);
177         return HC_LARGE_PRIME_NUMBER_LEN_UNSUPPORT;
178     }
179     *esk_len = (pake_client->prime_type == NUM_LEN_384) ? PAKE_ESK_LENGTH : PAKE_ESK_SHORT_LENGTH;
180     *prime_len = (pake_client->prime_type == NUM_LEN_384) ?
181                          HC_BIG_PRIME_MAX_LEN_384 : HC_BIG_PRIME_MAX_LEN_256;
182     return HC_OK;
183 }
184 
parse_start_response_data(void * handle,void * data)185 static int32_t parse_start_response_data(void *handle, void *data)
186 {
187     struct pake_client *pake_client = (struct pake_client *)handle;
188     struct pake_start_response_data *receive = (struct pake_start_response_data *)data;
189 
190     if (!is_peer_support_current_version(&receive->self_version, &receive->self_support_version)) {
191         LOGE("Unsupport version received");
192         return HC_VERSION_UNSUPPORT;
193     }
194 
195     pake_client->salt = receive->salt;
196     pake_client->peer_epk = receive->epk;
197     pake_client->peer_challenge = receive->challenge;
198 
199     struct hkdf secret = { 0, {0} };
200     int32_t ret = compute_hkdf((struct var_buffer *)&pake_client->pin, &pake_client->salt,
201                                HICHAIN_SPEKE_BASE_INFO, HC_HKDF_SECRET_LEN, (struct var_buffer *)&secret);
202     if (ret != HC_OK) {
203         LOGE("Object %u generate hkdf failed, error code is %d", pake_client_sn(pake_client), ret);
204         return ret;
205     }
206 
207     uint32_t esk_len = 0;
208     uint32_t prime_len = 0;
209     ret = gen_esk_prime_len(pake_client, receive, &esk_len, &prime_len);
210     if (ret != HC_OK) {
211         (void)memset_s(&secret, sizeof(struct hkdf), 0, sizeof(struct hkdf));
212         return ret;
213     }
214     if (pake_client->client_info.protocol_base_info.state == START_REQUEST) {
215         struct random_value rand = generate_random(esk_len);
216         if (rand.length == 0) {
217             LOGE("Generate random value failed");
218             (void)memset_s(&secret, sizeof(struct hkdf), 0, sizeof(struct hkdf));
219             return HC_GEN_RANDOM_FAILED;
220         }
221 
222         pake_client->self_esk = *(struct esk *)&rand;
223     }
224     struct exponent exp = {.length = 1};
225 
226     exp.exp[0] = 2; /* square */
227     struct epk base = { 0, {0} };
228 
229     ret = cal_bignum_exp((struct var_buffer *)&secret, (struct var_buffer *)&exp, prime_len, (struct big_num *)&base);
230     (void)memset_s(&secret, sizeof(struct hkdf), 0, sizeof(struct hkdf));
231     if (ret != HC_OK) {
232         return HC_CAL_BIGNUM_EXP_FAILED;
233     }
234     struct epk self_epk = { 0, {0} };
235 
236     ret = cal_bignum_exp((struct var_buffer *)&base, (struct var_buffer *)&pake_client->self_esk,
237                          prime_len, (struct big_num *)&self_epk);
238     if (ret != HC_OK) {
239         return HC_CAL_BIGNUM_EXP_FAILED;
240     }
241     pake_client->self_epk = self_epk;
242 
243     return HC_OK;
244 }
245 
246 static int32_t generate_session_key(struct pake_client *pake_client, struct epk *peer_epk);
247 static struct hmac generate_proof(struct pake_client *pake_client);
build_end_request_data(void * handle,void * data)248 static int32_t build_end_request_data(void *handle, void *data)
249 {
250     struct pake_client *pake_client = (struct pake_client *)handle;
251     struct pake_end_request_data *send = (struct pake_end_request_data *)data;
252     int32_t ret = generate_session_key(pake_client, &pake_client->peer_epk);
253     if (ret != HC_OK) {
254         LOGE("Object %u generate session key failed", pake_client_sn(pake_client));
255         return ret;
256     }
257     struct challenge challenge = { 0, {0} };
258     struct random_value rand = generate_random(CHALLENGE_BUFF_LENGTH);
259     if (rand.length == CHALLENGE_BUFF_LENGTH) {
260         DBG_OUT("Generate challenge success");
261         challenge.length = rand.length;
262         if (memcpy_s(challenge.challenge, sizeof(challenge.challenge), rand.random_value,
263             CHALLENGE_BUFF_LENGTH) != EOK) {
264             return memory_copy_error(__func__, __LINE__);
265         }
266     } else {
267         LOGE("Generate challenge failed.");
268     }
269     pake_client->self_challenge = challenge;
270     pake_client->kcf_data = generate_proof(pake_client);
271     send->challenge = challenge;
272     send->epk = pake_client->self_epk;
273     send->kcf_data = pake_client->kcf_data;
274 
275     return HC_OK;
276 }
277 
278 static bool verify_proof_is_ok(struct pake_client *pake_client, struct hmac *kcf_data);
279 static void generate_output_key(struct pake_client *pake_client);
parse_end_response_data(void * handle,void * data)280 static int32_t parse_end_response_data(void *handle, void *data)
281 {
282     struct pake_client *pake_client = (struct pake_client *)handle;
283     struct pake_end_response_data *receive = (struct pake_end_response_data *)data;
284 
285     if (verify_proof_is_ok(pake_client, &receive->kcf_data) != true) {
286         LOGE("Object %u verify proof failed", pake_client_sn(pake_client));
287         return HC_VERIFY_PROOF_FAILED;
288     }
289 
290     generate_output_key(pake_client);
291 
292     return HC_OK;
293 }
294 
generate_session_key(struct pake_client * pake_client,struct epk * peer_epk)295 static int32_t generate_session_key(struct pake_client *pake_client, struct epk *peer_epk)
296 {
297     struct pake_shared_secret shared_secret = { 0, {0} };
298     uint32_t prime_len = (pake_client->prime_type == NUM_LEN_384) ?
299                          HC_BIG_PRIME_MAX_LEN_384 : HC_BIG_PRIME_MAX_LEN_256;
300     if (CheckDlSpekePublicKey((const struct var_buffer *)peer_epk, prime_len) != HC_OK) {
301         LOGE("CheckDlSpekePublicKey failed.");
302         return HC_GENERATE_SESSION_KEY_FAILED;
303     }
304     int32_t ret = cal_bignum_exp((struct var_buffer *)peer_epk, (struct var_buffer *)&pake_client->self_esk,
305                                  prime_len, (struct big_num *)&shared_secret);
306     pake_client->shared_secret = shared_secret;
307     if (ret != HC_OK) {
308         LOGE("Object %u generate shared secret failed, error code is %d", pake_client_sn(pake_client), ret);
309         goto error;
310     }
311 
312     struct hkdf hkdf = { 0, {0} };
313     ret = compute_hkdf((struct var_buffer *)&shared_secret, &pake_client->salt,
314                        HICHAIN_SPEKE_SESSIONKEY_INFO, HC_HKDF_SECRET_LEN, (struct var_buffer *)&hkdf);
315     (void)memset_s(&shared_secret, sizeof(struct pake_shared_secret), 0, sizeof(struct pake_shared_secret));
316     if (ret != HC_OK) {
317         LOGE("Object %u generate hkdf failed, error code is %d", pake_client_sn(pake_client), ret);
318         goto error;
319     }
320 
321     (void)memcpy_s(pake_client->session_key.key, sizeof(pake_client->session_key.key),
322                    hkdf.hkdf, PAKE_SESSION_KEY_LENGTH);
323     (void)memcpy_s(pake_client->hmac_key.key, sizeof(pake_client->hmac_key.key),
324                    hkdf.hkdf + PAKE_SESSION_KEY_LENGTH, PAKE_HMAC_KEY_LENGTH);
325     pake_client->session_key.length = PAKE_SESSION_KEY_LENGTH;
326     pake_client->hmac_key.length = PAKE_HMAC_KEY_LENGTH;
327     (void)memset_s(&hkdf, sizeof(struct hkdf), 0, sizeof(struct hkdf));
328     return HC_OK;
329 
330 error:
331     pake_client->session_key.length = 0;
332     pake_client->hmac_key.length = 0;
333     return HC_GENERATE_SESSION_KEY_FAILED;
334 }
335 
generate_proof(struct pake_client * pake_client)336 static struct hmac generate_proof(struct pake_client *pake_client)
337 {
338     struct hmac proof = { 0, {0} };
339     struct uint8_buff challenge = {
340         .val = NULL,
341         .length = 0,
342         .size = CHALLENGE_BUFF_LENGTH + CHALLENGE_BUFF_LENGTH
343     };
344 
345     challenge.val = (uint8_t *)MALLOC(challenge.size);
346     if (challenge.val == NULL) {
347         LOGE("Object %u MALLOC generate proof buffer failed.", pake_client_sn(pake_client));
348         return proof;
349     }
350     (void)memset_s(challenge.val, challenge.size, 0, challenge.size);
351     (void)memcpy_s(challenge.val, challenge.size, pake_client->self_challenge.challenge, CHALLENGE_BUFF_LENGTH);
352     challenge.length = CHALLENGE_BUFF_LENGTH;
353     (void)memcpy_s(challenge.val + challenge.length, challenge.size - challenge.length,
354                    pake_client->peer_challenge.challenge, CHALLENGE_BUFF_LENGTH);
355     challenge.length += CHALLENGE_BUFF_LENGTH;
356 
357     int32_t ret = compute_hmac((struct var_buffer *)&pake_client->hmac_key, &challenge, &proof);
358     FREE(challenge.val);
359     if (ret != HC_OK) {
360         LOGE("Object %u generate proof hmac failed, error code is %d.", pake_client_sn(pake_client), ret);
361         proof.length = 0;
362     }
363     DBG_OUT("Object %u generate proof success", pake_client_sn(pake_client));
364     return proof;
365 }
366 
verify_proof_is_ok(struct pake_client * pake_client,struct hmac * kcf_data)367 static bool verify_proof_is_ok(struct pake_client *pake_client, struct hmac *kcf_data)
368 {
369     struct uint8_buff challenge = {.size = CHALLENGE_BUFF_LENGTH + CHALLENGE_BUFF_LENGTH};
370 
371     challenge.val = (uint8_t *)MALLOC(challenge.size);
372     if (challenge.val == NULL) {
373         LOGE("Object %u MALLOC verify proof buffer failed", pake_client_sn(pake_client));
374         return false;
375     }
376 
377     (void)memcpy_s(challenge.val, challenge.size, pake_client->peer_challenge.challenge, CHALLENGE_BUFF_LENGTH);
378     challenge.length = CHALLENGE_BUFF_LENGTH;
379     (void)memcpy_s(challenge.val + challenge.length, challenge.size - challenge.length,
380                    pake_client->self_challenge.challenge, CHALLENGE_BUFF_LENGTH);
381     challenge.length += CHALLENGE_BUFF_LENGTH;
382     struct hmac verify_proof = { 0, {0} };
383     int32_t ret = compute_hmac((struct var_buffer *)&pake_client->hmac_key, &challenge, &verify_proof);
384 
385     FREE(challenge.val);
386     challenge.val = NULL;
387     if (ret != HC_OK) {
388         LOGE("Object %u verify proof hmac failed, error code is %d", pake_client_sn(pake_client), ret);
389         return false;
390     }
391 
392     ret = memcmp(&verify_proof, kcf_data, sizeof(verify_proof));
393     LOGI("Object %u verify proof hmac result is %d", pake_client_sn(pake_client), ret);
394 
395     return (ret == 0);
396 }
397 
generate_output_key(struct pake_client * pake_client)398 static void generate_output_key(struct pake_client *pake_client)
399 {
400     DBG_OUT("pake client generate output key");
401     int32_t ret = compute_hkdf((struct var_buffer *)&pake_client->session_key, &pake_client->salt,
402                                HICHAIN_RETURN_KEY, pake_client->key_length,
403                                (struct var_buffer *)&pake_client->service_key);
404     if (ret != HC_OK) {
405         LOGE("Object %u generate output key failed, error code is %d", pake_client_sn(pake_client), ret);
406         return;
407     } else {
408         DBG_OUT("Pake client generate output key success");
409         return;
410     }
411 }
412 
413 #else /* _CUT_XXX */
414 
build_pake_client(const struct session_identity * identity,const struct hc_pin * pin,uint32_t key_length,const struct hc_auth_id * client,const struct hc_auth_id * server)415 struct pake_client *build_pake_client(const struct session_identity *identity, const struct hc_pin *pin,
416     uint32_t key_length, const struct hc_auth_id *client, const struct hc_auth_id *server)
417 {
418     LOGE("Donot support pake protocol");
419     (void)identity;
420     (void)pin;
421     (void)key_length;
422     (void)client;
423     (void)server;
424     return (struct pake_client *)MALLOC(sizeof(struct pake_client));
425 }
426 
destroy_pake_client(struct pake_client * pake_client)427 void destroy_pake_client(struct pake_client *pake_client)
428 {
429     LOGE("Donot support pake protocol");
430     FREE(pake_client);
431 }
432 
433 #endif /* _CUT_XXX */
434 
435