xref: /optee_os/core/lib/libtomcrypt/sm2-kep.c (revision 5b25c76ac40f830867e3d60800120ffd7874e8dc)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2020 Huawei Technologies Co., Ltd
4  */
5 
6 #include <crypto/crypto.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <string_ext.h>
10 #include <tee_api_types.h>
11 #include <tee/tee_cryp_utl.h>
12 #include <util.h>
13 #include <utee_defines.h>
14 
15 #include "acipher_helpers.h"
16 
17 /* SM2 uses 256 bit unsigned integers in big endian format */
18 #define SM2_INT_SIZE_BYTES 32
19 
20 /*
21  * Compute a hash of a user's identity and public key
22  * For user A: ZA = SM3(ENTLA || IDA || a || b || xG || yG || xA || yA)
23  */
24 static TEE_Result sm2_kep_compute_Z(uint8_t *Z, size_t Zlen, const uint8_t *id,
25 				    size_t idlen, const ecc_key *key)
26 {
27 	TEE_Result res = TEE_ERROR_GENERIC;
28 	uint8_t ENTLEN[2] = { };
29 	uint8_t buf[SM2_INT_SIZE_BYTES];
30 	void *ctx = NULL;
31 
32 	if (Zlen < TEE_SM3_HASH_SIZE)
33 		return TEE_ERROR_SHORT_BUFFER;
34 
35 	/*
36 	 * ENTLEN is the length in bits if the user's distinguished identifier
37 	 * encoded over 16 bits in big endian format.
38 	 */
39 	ENTLEN[0] = (idlen * 8) >> 8;
40 	ENTLEN[1] = idlen * 8;
41 
42 	res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SM3);
43 	if (res)
44 		goto out;
45 
46 	res = crypto_hash_init(ctx);
47 	if (res)
48 		goto out;
49 
50 	res = crypto_hash_update(ctx, ENTLEN, sizeof(ENTLEN));
51 	if (res)
52 		goto out;
53 
54 	res = crypto_hash_update(ctx, id, idlen);
55 	if (res)
56 		goto out;
57 
58 	mp_to_unsigned_bin2(key->dp.A, buf, SM2_INT_SIZE_BYTES);
59 	res = crypto_hash_update(ctx, buf, sizeof(buf));
60 	if (res)
61 		goto out;
62 
63 	mp_to_unsigned_bin2(key->dp.B, buf, SM2_INT_SIZE_BYTES);
64 	res = crypto_hash_update(ctx, buf, sizeof(buf));
65 	if (res)
66 		goto out;
67 
68 	mp_to_unsigned_bin2(key->dp.base.x, buf, SM2_INT_SIZE_BYTES);
69 	res = crypto_hash_update(ctx, buf, sizeof(buf));
70 	if (res)
71 		goto out;
72 
73 	mp_to_unsigned_bin2(key->dp.base.y, buf, SM2_INT_SIZE_BYTES);
74 	res = crypto_hash_update(ctx, buf, sizeof(buf));
75 	if (res)
76 		goto out;
77 
78 	mp_to_unsigned_bin2(key->pubkey.x, buf, SM2_INT_SIZE_BYTES);
79 	res = crypto_hash_update(ctx, buf, sizeof(buf));
80 	if (res)
81 		goto out;
82 
83 	mp_to_unsigned_bin2(key->pubkey.y, buf, SM2_INT_SIZE_BYTES);
84 	res = crypto_hash_update(ctx, buf, sizeof(buf));
85 	if (res)
86 		goto out;
87 
88 	res = crypto_hash_final(ctx, Z, TEE_SM3_HASH_SIZE);
89 out:
90 	crypto_hash_free_ctx(ctx);
91 	return res;
92 }
93 
94 /*
95  * Compute a verification value, to be checked against the value sent by the
96  * peer.
97  * On the initiator's side:
98  *   S1 = SM3(0x02 || yU || SM3(xU || ZA || ZB || x1 || y1 || x2 || y2))
99  * On the responder's side:
100  *   S2 = SM3(0x03 || yV || SM3(xV || ZA || ZB || x1 || y1 || x2 || y2))
101  */
102 static TEE_Result sm2_kep_compute_S(uint8_t *S, size_t S_len, uint8_t flag,
103 				    ecc_point *UV, const uint8_t *ZAZB,
104 				    size_t ZAZB_len, ecc_key *initiator_eph_key,
105 				    ecc_key *responder_eph_key)
106 {
107 	uint8_t hash[TEE_SM3_HASH_SIZE] = { };
108 	TEE_Result res = TEE_ERROR_GENERIC;
109 	uint8_t buf[SM2_INT_SIZE_BYTES];
110 	void *ctx = NULL;
111 
112 	if (S_len < TEE_SM3_HASH_SIZE)
113 		return TEE_ERROR_SHORT_BUFFER;
114 
115 	res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SM3);
116 	if (res)
117 		goto out;
118 
119 	/* Compute the inner hash */
120 
121 	res = crypto_hash_init(ctx);
122 	if (res)
123 		goto out;
124 
125 	/* xU or xV */
126 	mp_to_unsigned_bin2(UV->x, buf, SM2_INT_SIZE_BYTES);
127 	res = crypto_hash_update(ctx, buf, sizeof(buf));
128 	if (res)
129 		goto out;
130 
131 	/* ZA || ZB */
132 	res = crypto_hash_update(ctx, ZAZB, ZAZB_len);
133 	if (res)
134 		goto out;
135 
136 	/* x1 */
137 	mp_to_unsigned_bin2(initiator_eph_key->pubkey.x, buf,
138 			    SM2_INT_SIZE_BYTES);
139 	res = crypto_hash_update(ctx, buf, sizeof(buf));
140 	if (res)
141 		goto out;
142 
143 	/* y1 */
144 	mp_to_unsigned_bin2(initiator_eph_key->pubkey.y, buf,
145 			    SM2_INT_SIZE_BYTES);
146 	res = crypto_hash_update(ctx, buf, sizeof(buf));
147 	if (res)
148 		goto out;
149 
150 	/* x2 */
151 	mp_to_unsigned_bin2(responder_eph_key->pubkey.x, buf,
152 			    SM2_INT_SIZE_BYTES);
153 	res = crypto_hash_update(ctx, buf, sizeof(buf));
154 	if (res)
155 		goto out;
156 
157 	/* y2 */
158 	mp_to_unsigned_bin2(responder_eph_key->pubkey.y, buf,
159 			   SM2_INT_SIZE_BYTES);
160 	res = crypto_hash_update(ctx, buf, sizeof(buf));
161 	if (res)
162 		goto out;
163 
164 	res = crypto_hash_final(ctx, hash, sizeof(hash));
165 	if (res)
166 		goto out;
167 
168 	/* Now compute S */
169 
170 	res = crypto_hash_init(ctx);
171 	if (res)
172 		goto out;
173 
174 	/* 0x02 or 0x03  */
175 	res = crypto_hash_update(ctx, &flag, sizeof(flag));
176 	if (res)
177 		goto out;
178 
179 	/* yU or yV */
180 	mp_to_unsigned_bin2(UV->y, buf, SM2_INT_SIZE_BYTES);
181 	res = crypto_hash_update(ctx, buf, sizeof(buf));
182 	if (res)
183 		goto out;
184 
185 	/* Inner SM3(...) */
186 	res = crypto_hash_update(ctx, hash, sizeof(hash));
187 	if (res)
188 		goto out;
189 
190 	res = crypto_hash_final(ctx, S, TEE_SM3_HASH_SIZE);
191 
192 out:
193 	crypto_hash_free_ctx(ctx);
194 	return res;
195 
196 }
197 
198 /*
199  * GM/T 0003.1‒2012 Part 3 Section 6.1
200  * Key exchange protocol
201  */
202 static TEE_Result sm2_kep_derive(ecc_key *my_key, ecc_key *my_eph_key,
203 				 ecc_key *peer_key, ecc_key *peer_eph_key,
204 				 struct sm2_kep_parms *p)
205 {
206 	/*
207 	 * Variable names and documented steps reflect the initator side (user A
208 	 * in the spec), but the other side is quite similar hence only one
209 	 * function.
210 	 */
211 	uint8_t xUyUZAZB[2 * SM2_INT_SIZE_BYTES + 2 * TEE_SM3_HASH_SIZE] = { };
212 	ecc_key *initiator_eph_key = p->is_initiator ? my_eph_key :
213 						       peer_eph_key;
214 	ecc_key *responder_eph_key = p->is_initiator ? peer_eph_key :
215 						       my_eph_key;
216 	ecc_key *initiator_key = p->is_initiator ? my_key : peer_key;
217 	ecc_key *responder_key = p->is_initiator ? peer_key : my_key;
218 	TEE_Result res = TEE_ERROR_BAD_STATE;
219 	uint8_t tmp[SM2_INT_SIZE_BYTES];
220 	void *n = my_key->dp.order;
221 	ecc_point *U = NULL;
222 	void *x1bar = NULL;
223 	void *x2bar = NULL;
224 	void *tA = NULL;
225 	void *h = NULL;
226 	void *htA = NULL;
227 	void *mp = NULL;
228 	void *mu = NULL;
229 	void *ma = NULL;
230 	void *one = NULL;
231 	int ltc_res = 0;
232 	int inf = 0;
233 
234 	ltc_res = mp_init_multi(&x1bar, &x2bar, &tA, &h, &htA, &mu, &ma, &one,
235 				NULL);
236 	if (ltc_res != CRYPT_OK) {
237 		res = TEE_ERROR_OUT_OF_MEMORY;
238 		goto out;
239 	}
240 
241 	U = ltc_ecc_new_point();
242 	if (!U) {
243 		res = TEE_ERROR_OUT_OF_MEMORY;
244 		goto out;
245 	}
246 
247 	/*
248 	 * Steps A1-A3 are supposedly done already (generate ephemeral key, send
249 	 * it to peer).
250 	 * Step A4: (x1, y1) = RA; x1bar = 2^w + (x1 & (2^w - 1))
251 	 */
252 
253 	mp_to_unsigned_bin2(my_eph_key->pubkey.x, tmp, SM2_INT_SIZE_BYTES);
254 	tmp[SM2_INT_SIZE_BYTES / 2] |= 0x80;
255 	mp_read_unsigned_bin(x1bar, tmp + SM2_INT_SIZE_BYTES / 2,
256 			     SM2_INT_SIZE_BYTES / 2);
257 
258 	/* Step A5: tA = (dA + x1bar * rA) mod n */
259 
260 	ltc_res = mp_mulmod(x1bar, my_eph_key->k, n, tA);
261 	if (ltc_res != CRYPT_OK)
262 		goto out;
263 
264 	ltc_res = mp_addmod(tA, my_key->k, n, tA);
265 	if (ltc_res != CRYPT_OK)
266 		goto out;
267 
268 	/* Step A6: verify whether RB verifies the curve equation */
269 
270 	ltc_res = ltc_ecc_is_point(&peer_eph_key->dp, peer_eph_key->pubkey.x,
271 				   peer_eph_key->pubkey.y);
272 	if (ltc_res != CRYPT_OK)
273 		goto out;
274 
275 	/* Step A6 (continued): (x2, y2) = RB; x2bar = 2^w + (x2 & (2^w - 1)) */
276 
277 	mp_to_unsigned_bin2(peer_eph_key->pubkey.x, tmp, SM2_INT_SIZE_BYTES);
278 	tmp[SM2_INT_SIZE_BYTES / 2] |= 0x80;
279 	mp_read_unsigned_bin(x2bar, tmp + SM2_INT_SIZE_BYTES / 2,
280 			     SM2_INT_SIZE_BYTES / 2);
281 
282 
283 	/* Step A7: compute U = [h.tA](PB + [x2bar]RB) and check for infinity */
284 
285 	ltc_res = mp_montgomery_setup(peer_key->dp.prime, &mp);
286 	if (ltc_res != CRYPT_OK)
287 		goto out;
288 
289 	ltc_res = mp_montgomery_normalization(mu, peer_key->dp.prime);
290 	if (ltc_res != CRYPT_OK)
291 		goto out;
292 
293 	ltc_res = mp_mulmod(peer_key->dp.A, mu, peer_key->dp.prime, ma);
294 	if (ltc_res != CRYPT_OK)
295 		goto out;
296 
297 	ltc_res = mp_set_int(one, 1);
298 	if (ltc_res != CRYPT_OK)
299 		goto out;
300 
301 	ltc_res = ltc_ecc_mul2add(&peer_key->pubkey, one, &peer_eph_key->pubkey,
302 				  x2bar, U, ma, peer_key->dp.prime);
303 	if (ltc_res != CRYPT_OK)
304 		goto out;
305 
306 	ltc_res = mp_set_int(h, peer_key->dp.cofactor);
307 	if (ltc_res != CRYPT_OK)
308 		goto out;
309 
310 	ltc_res = mp_mul(h, tA, htA);
311 	if (ltc_res != CRYPT_OK)
312 		goto out;
313 
314 	ltc_res = ltc_ecc_mulmod(htA, U, U, peer_key->dp.A, peer_key->dp.prime,
315 				 1);
316 	if (ltc_res != CRYPT_OK)
317 		goto out;
318 
319 	ltc_res = ltc_ecc_is_point_at_infinity(U, peer_key->dp.prime, &inf);
320 	if (ltc_res != CRYPT_OK)
321 		goto out;
322 
323 	if (inf)
324 		goto out;
325 
326 	/* Step A8: compute KA = KDF(xU || yU || ZA || ZB, klen) */
327 
328 	/* xU */
329 	mp_to_unsigned_bin2(U->x, xUyUZAZB, SM2_INT_SIZE_BYTES);
330 
331 	/* yU */
332 	mp_to_unsigned_bin2(U->y, xUyUZAZB + SM2_INT_SIZE_BYTES,
333 			    SM2_INT_SIZE_BYTES);
334 
335 	/* ZA */
336 	res = sm2_kep_compute_Z(xUyUZAZB + 2 * SM2_INT_SIZE_BYTES,
337 				TEE_SM3_HASH_SIZE, p->initiator_id,
338 				p->initiator_id_len, initiator_key);
339 	if (res)
340 		goto out;
341 
342 	/* ZB */
343 	res = sm2_kep_compute_Z(xUyUZAZB + 2 * SM2_INT_SIZE_BYTES +
344 					TEE_SM3_HASH_SIZE,
345 				TEE_SM3_HASH_SIZE, p->responder_id,
346 				p->responder_id_len, responder_key);
347 	if (res)
348 		goto out;
349 
350 	res = sm2_kdf(xUyUZAZB, sizeof(xUyUZAZB), p->out, p->out_len);
351 	if (res)
352 		goto out;
353 
354 	/* Step A9: compute S1 and check S1 == SB */
355 
356 	if (p->conf_in) {
357 		uint8_t S1[TEE_SM3_HASH_SIZE];
358 		uint8_t flag = p->is_initiator ? 0x02 : 0x03;
359 
360 		if (p->conf_in_len < TEE_SM3_HASH_SIZE) {
361 			res = TEE_ERROR_BAD_PARAMETERS;
362 			goto out;
363 		}
364 		res = sm2_kep_compute_S(S1, sizeof(S1), flag, U,
365 					xUyUZAZB + 2 * SM2_INT_SIZE_BYTES,
366 					2 * SM2_INT_SIZE_BYTES,
367 					initiator_eph_key, responder_eph_key);
368 		if (res)
369 			goto out;
370 
371 		if (consttime_memcmp(S1, p->conf_in, sizeof(S1))) {
372 			/* Verification failed */
373 			res = TEE_ERROR_BAD_STATE;
374 			goto out;
375 		}
376 	}
377 
378 	/* Step A10: compute SA */
379 
380 	if (p->conf_out) {
381 		uint8_t flag = p->is_initiator ? 0x03 : 0x02;
382 
383 		if (p->conf_out_len < TEE_SM3_HASH_SIZE) {
384 			res = TEE_ERROR_BAD_PARAMETERS;
385 			goto out;
386 		}
387 
388 		res = sm2_kep_compute_S(p->conf_out, TEE_SM3_HASH_SIZE, flag, U,
389 					xUyUZAZB + 2 * SM2_INT_SIZE_BYTES,
390 					2 * SM2_INT_SIZE_BYTES,
391 					initiator_eph_key, responder_eph_key);
392 		if (res)
393 			goto out;
394 	}
395 out:
396 	mp_montgomery_free(mp);
397 	ltc_ecc_del_point(U);
398 	mp_clear_multi(x1bar, x2bar, tA, h, htA, mu, ma, one, NULL);
399 	return res;
400 }
401 
402 TEE_Result crypto_acipher_sm2_kep_derive(struct ecc_keypair *my_key,
403 					 struct ecc_keypair *my_eph_key,
404 					 struct ecc_public_key *peer_key,
405 					 struct ecc_public_key *peer_eph_key,
406 					 struct sm2_kep_parms *p)
407 {
408 	TEE_Result res = TEE_SUCCESS;
409 	ecc_key ltc_my_key = { };
410 	ecc_key ltc_my_eph_key = { };
411 	ecc_key ltc_peer_key = { };
412 	ecc_key ltc_peer_eph_key = { };
413 
414 	res = ecc_populate_ltc_private_key(&ltc_my_key, my_key,
415 					   TEE_ALG_SM2_KEP, NULL);
416 	if (res)
417 		goto out;
418 
419 	res = ecc_populate_ltc_private_key(&ltc_my_eph_key, my_eph_key,
420 					   TEE_ALG_SM2_KEP, NULL);
421 	if (res)
422 		goto out;
423 
424 	res = ecc_populate_ltc_public_key(&ltc_peer_key, peer_key,
425 					  TEE_ALG_SM2_KEP, NULL);
426 	if (res)
427 		goto out;
428 
429 	res = ecc_populate_ltc_public_key(&ltc_peer_eph_key, peer_eph_key,
430 					  TEE_ALG_SM2_KEP, NULL);
431 	if (res)
432 		goto out;
433 
434 	res = sm2_kep_derive(&ltc_my_key, &ltc_my_eph_key, &ltc_peer_key,
435 			     &ltc_peer_eph_key, p);
436 out:
437 	ecc_free(&ltc_peer_eph_key);
438 	ecc_free(&ltc_peer_key);
439 	ecc_free(&ltc_my_eph_key);
440 	ecc_free(&ltc_my_key);
441 	return res;
442 }
443