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