xref: /freebsd/crypto/openssl/test/sm2_internal_test.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 2017-2024 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 /*
11  * Low level APIs are deprecated for public use, but still ok for internal use.
12  */
13 #include "internal/deprecated.h"
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #include <openssl/bio.h>
20 #include <openssl/evp.h>
21 #include <openssl/bn.h>
22 #include <openssl/crypto.h>
23 #include <openssl/err.h>
24 #include <openssl/rand.h>
25 #include "testutil.h"
26 
27 #ifndef OPENSSL_NO_SM2
28 
29 #include "crypto/sm2.h"
30 
31 static fake_random_generate_cb get_faked_bytes;
32 
33 static OSSL_PROVIDER *fake_rand = NULL;
34 static uint8_t *fake_rand_bytes = NULL;
35 static size_t fake_rand_bytes_offset = 0;
36 static size_t fake_rand_size = 0;
37 
get_faked_bytes(unsigned char * buf,size_t num,ossl_unused const char * name,ossl_unused EVP_RAND_CTX * ctx)38 static int get_faked_bytes(unsigned char *buf, size_t num,
39     ossl_unused const char *name,
40     ossl_unused EVP_RAND_CTX *ctx)
41 {
42     if (!TEST_ptr(fake_rand_bytes) || !TEST_size_t_gt(fake_rand_size, 0))
43         return 0;
44 
45     while (num-- > 0) {
46         if (fake_rand_bytes_offset >= fake_rand_size)
47             fake_rand_bytes_offset = 0;
48         *buf++ = fake_rand_bytes[fake_rand_bytes_offset++];
49     }
50 
51     return 1;
52 }
53 
start_fake_rand(const char * hex_bytes)54 static int start_fake_rand(const char *hex_bytes)
55 {
56     OPENSSL_free(fake_rand_bytes);
57     fake_rand_bytes_offset = 0;
58     fake_rand_size = strlen(hex_bytes) / 2;
59     if (!TEST_ptr(fake_rand_bytes = OPENSSL_hexstr2buf(hex_bytes, NULL)))
60         return 0;
61 
62     /* use own random function */
63     fake_rand_set_public_private_callbacks(NULL, get_faked_bytes);
64     return 1;
65 }
66 
restore_rand(void)67 static void restore_rand(void)
68 {
69     fake_rand_set_public_private_callbacks(NULL, NULL);
70     OPENSSL_free(fake_rand_bytes);
71     fake_rand_bytes = NULL;
72     fake_rand_bytes_offset = 0;
73 }
74 
create_EC_group(const char * p_hex,const char * a_hex,const char * b_hex,const char * x_hex,const char * y_hex,const char * order_hex,const char * cof_hex)75 static EC_GROUP *create_EC_group(const char *p_hex, const char *a_hex,
76     const char *b_hex, const char *x_hex,
77     const char *y_hex, const char *order_hex,
78     const char *cof_hex)
79 {
80     BIGNUM *p = NULL;
81     BIGNUM *a = NULL;
82     BIGNUM *b = NULL;
83     BIGNUM *g_x = NULL;
84     BIGNUM *g_y = NULL;
85     BIGNUM *order = NULL;
86     BIGNUM *cof = NULL;
87     EC_POINT *generator = NULL;
88     EC_GROUP *group = NULL;
89     int ok = 0;
90 
91     if (!TEST_true(BN_hex2bn(&p, p_hex))
92         || !TEST_true(BN_hex2bn(&a, a_hex))
93         || !TEST_true(BN_hex2bn(&b, b_hex)))
94         goto done;
95 
96     group = EC_GROUP_new_curve_GFp(p, a, b, NULL);
97     if (!TEST_ptr(group))
98         goto done;
99 
100     generator = EC_POINT_new(group);
101     if (!TEST_ptr(generator))
102         goto done;
103 
104     if (!TEST_true(BN_hex2bn(&g_x, x_hex))
105         || !TEST_true(BN_hex2bn(&g_y, y_hex))
106         || !TEST_true(EC_POINT_set_affine_coordinates(group, generator, g_x,
107             g_y, NULL)))
108         goto done;
109 
110     if (!TEST_true(BN_hex2bn(&order, order_hex))
111         || !TEST_true(BN_hex2bn(&cof, cof_hex))
112         || !TEST_true(EC_GROUP_set_generator(group, generator, order, cof)))
113         goto done;
114 
115     ok = 1;
116 done:
117     BN_free(p);
118     BN_free(a);
119     BN_free(b);
120     BN_free(g_x);
121     BN_free(g_y);
122     EC_POINT_free(generator);
123     BN_free(order);
124     BN_free(cof);
125     if (!ok) {
126         EC_GROUP_free(group);
127         group = NULL;
128     }
129 
130     return group;
131 }
132 
test_sm2_crypt(const EC_GROUP * group,const EVP_MD * digest,const char * privkey_hex,const char * message,const char * k_hex,const char * ctext_hex)133 static int test_sm2_crypt(const EC_GROUP *group,
134     const EVP_MD *digest,
135     const char *privkey_hex,
136     const char *message,
137     const char *k_hex, const char *ctext_hex)
138 {
139     const size_t msg_len = strlen(message);
140     BIGNUM *priv = NULL;
141     EC_KEY *key = NULL;
142     EC_POINT *pt = NULL;
143     unsigned char *expected = OPENSSL_hexstr2buf(ctext_hex, NULL);
144     size_t ctext_len = 0;
145     size_t ptext_len = 0;
146     uint8_t *ctext = NULL;
147     uint8_t *recovered = NULL;
148     size_t recovered_len = msg_len;
149     int rc = 0;
150 
151     if (!TEST_ptr(expected)
152         || !TEST_true(BN_hex2bn(&priv, privkey_hex)))
153         goto done;
154 
155     key = EC_KEY_new();
156     if (!TEST_ptr(key)
157         || !TEST_true(EC_KEY_set_group(key, group))
158         || !TEST_true(EC_KEY_set_private_key(key, priv)))
159         goto done;
160 
161     pt = EC_POINT_new(group);
162     if (!TEST_ptr(pt)
163         || !TEST_true(EC_POINT_mul(group, pt, priv, NULL, NULL, NULL))
164         || !TEST_true(EC_KEY_set_public_key(key, pt))
165         || !TEST_true(ossl_sm2_ciphertext_size(key, digest, msg_len,
166             &ctext_len)))
167         goto done;
168 
169     ctext = OPENSSL_zalloc(ctext_len);
170     if (!TEST_ptr(ctext))
171         goto done;
172 
173     start_fake_rand(k_hex);
174     if (!TEST_true(ossl_sm2_encrypt(key, digest,
175             (const uint8_t *)message, msg_len,
176             ctext, &ctext_len))) {
177         restore_rand();
178         goto done;
179     }
180     restore_rand();
181 
182     if (!TEST_mem_eq(ctext, ctext_len, expected, ctext_len))
183         goto done;
184 
185     if (!TEST_true(ossl_sm2_plaintext_size(ctext, ctext_len, &ptext_len))
186         || !TEST_int_eq(ptext_len, msg_len))
187         goto done;
188 
189     recovered = OPENSSL_zalloc(ptext_len);
190     if (!TEST_ptr(recovered)
191         || !TEST_true(ossl_sm2_decrypt(key, digest, ctext, ctext_len,
192             recovered, &recovered_len))
193         || !TEST_int_eq(recovered_len, msg_len)
194         || !TEST_mem_eq(recovered, recovered_len, message, msg_len))
195         goto done;
196 
197     rc = 1;
198 done:
199     BN_free(priv);
200     EC_POINT_free(pt);
201     OPENSSL_free(ctext);
202     OPENSSL_free(recovered);
203     OPENSSL_free(expected);
204     EC_KEY_free(key);
205     return rc;
206 }
207 
sm2_crypt_test(void)208 static int sm2_crypt_test(void)
209 {
210     int testresult = 0;
211     EC_GROUP *gm_group = NULL;
212     EC_GROUP *test_group = create_EC_group("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",
213         "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",
214         "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",
215         "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",
216         "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2",
217         "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",
218         "1");
219 
220     if (!TEST_ptr(test_group))
221         goto done;
222 
223     if (!test_sm2_crypt(
224             test_group,
225             EVP_sm3(),
226             "1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0",
227             "encryption standard",
228             "004C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F"
229             "0092e8ff62146873c258557548500ab2df2a365e0609ab67640a1f6d57d7b17820"
230             "008349312695a3e1d2f46905f39a766487f2432e95d6be0cb009fe8c69fd8825a7",
231             "307B0220245C26FB68B1DDDDB12C4B6BF9F2B6D5FE60A383B0D18D1C4144ABF1"
232             "7F6252E7022076CB9264C2A7E88E52B19903FDC47378F605E36811F5C07423A2"
233             "4B84400F01B804209C3D7360C30156FAB7C80A0276712DA9D8094A634B766D3A"
234             "285E07480653426D0413650053A89B41C418B0C3AAD00D886C00286467"))
235         goto done;
236 
237     /* Same test as above except using SHA-256 instead of SM3 */
238     if (!test_sm2_crypt(
239             test_group,
240             EVP_sha256(),
241             "1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0",
242             "encryption standard",
243             "004C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F"
244             "003da18008784352192d70f22c26c243174a447ba272fec64163dd4742bae8bc98"
245             "00df17605cf304e9dd1dfeb90c015e93b393a6f046792f790a6fa4228af67d9588",
246             "307B0220245C26FB68B1DDDDB12C4B6BF9F2B6D5FE60A383B0D18D1C4144ABF17F"
247             "6252E7022076CB9264C2A7E88E52B19903FDC47378F605E36811F5C07423A24B84"
248             "400F01B80420BE89139D07853100EFA763F60CBE30099EA3DF7F8F364F9D10A5E9"
249             "88E3C5AAFC0413229E6C9AEE2BB92CAD649FE2C035689785DA33"))
250         goto done;
251 
252     /* From Annex C in both GM/T0003.5-2012 and GB/T 32918.5-2016.*/
253     gm_group = create_EC_group(
254         "fffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffff",
255         "fffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc",
256         "28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93",
257         "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7",
258         "bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0",
259         "fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123",
260         "1");
261 
262     if (!TEST_ptr(gm_group))
263         goto done;
264 
265     if (!test_sm2_crypt(
266             gm_group,
267             EVP_sm3(),
268             /* privkey (from which the encrypting public key is derived) */
269             "3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8",
270             /* plaintext message */
271             "encryption standard",
272             /* ephemeral nonce k */
273             "59276E27D506861A16680F3AD9C02DCCEF3CC1FA3CDBE4CE6D54B80DEAC1BC21",
274             /*
275              * expected ciphertext, the field values are from GM/T 0003.5-2012
276              * (Annex C), but serialized following the ASN.1 format specified
277              * in GM/T 0009-2012 (Sec. 7.2).
278              */
279             "307C" /* SEQUENCE, 0x7c bytes */
280             "0220" /* INTEGER, 0x20 bytes */
281             "04EBFC718E8D1798620432268E77FEB6415E2EDE0E073C0F4F640ECD2E149A73"
282             "0221" /* INTEGER, 0x21 bytes */
283             "00" /* leading 00 due to DER for pos. int with topmost bit set */
284             "E858F9D81E5430A57B36DAAB8F950A3C64E6EE6A63094D99283AFF767E124DF0"
285             "0420" /* OCTET STRING, 0x20 bytes */
286             "59983C18F809E262923C53AEC295D30383B54E39D609D160AFCB1908D0BD8766"
287             "0413" /* OCTET STRING, 0x13 bytes */
288             "21886CA989CA9C7D58087307CA93092D651EFA"))
289         goto done;
290 
291     testresult = 1;
292 done:
293     EC_GROUP_free(test_group);
294     EC_GROUP_free(gm_group);
295 
296     return testresult;
297 }
298 
test_sm2_sign(const EC_GROUP * group,const char * userid,const char * privkey_hex,const char * message,const char * k_hex,const char * r_hex,const char * s_hex,int omit_pubkey)299 static int test_sm2_sign(const EC_GROUP *group,
300     const char *userid,
301     const char *privkey_hex,
302     const char *message,
303     const char *k_hex,
304     const char *r_hex,
305     const char *s_hex,
306     int omit_pubkey)
307 {
308     const size_t msg_len = strlen(message);
309     int ok = 0;
310     BIGNUM *priv = NULL;
311     EC_POINT *pt = NULL;
312     EC_KEY *key = NULL;
313     ECDSA_SIG *sig = NULL;
314     const BIGNUM *sig_r = NULL;
315     const BIGNUM *sig_s = NULL;
316     BIGNUM *r = NULL;
317     BIGNUM *s = NULL;
318 
319     if (!TEST_true(BN_hex2bn(&priv, privkey_hex)))
320         goto done;
321 
322     key = EC_KEY_new();
323     if (!TEST_ptr(key)
324         || !TEST_true(EC_KEY_set_group(key, group))
325         || !TEST_true(EC_KEY_set_private_key(key, priv)))
326         goto done;
327 
328     if (omit_pubkey == 0) {
329         pt = EC_POINT_new(group);
330         if (!TEST_ptr(pt)
331             || !TEST_true(EC_POINT_mul(group, pt, priv, NULL, NULL, NULL))
332             || !TEST_true(EC_KEY_set_public_key(key, pt)))
333             goto done;
334     }
335 
336     start_fake_rand(k_hex);
337     sig = ossl_sm2_do_sign(key, EVP_sm3(), (const uint8_t *)userid,
338         strlen(userid), (const uint8_t *)message, msg_len);
339     if (!TEST_ptr(sig)) {
340         restore_rand();
341         goto done;
342     }
343     restore_rand();
344 
345     ECDSA_SIG_get0(sig, &sig_r, &sig_s);
346 
347     if (!TEST_true(BN_hex2bn(&r, r_hex))
348         || !TEST_true(BN_hex2bn(&s, s_hex))
349         || !TEST_BN_eq(r, sig_r)
350         || !TEST_BN_eq(s, sig_s))
351         goto done;
352 
353     ok = ossl_sm2_do_verify(key, EVP_sm3(), sig, (const uint8_t *)userid,
354         strlen(userid), (const uint8_t *)message, msg_len);
355 
356     /* We goto done whether this passes or fails */
357     TEST_true(ok);
358 
359 done:
360     ECDSA_SIG_free(sig);
361     EC_POINT_free(pt);
362     EC_KEY_free(key);
363     BN_free(priv);
364     BN_free(r);
365     BN_free(s);
366 
367     return ok;
368 }
369 
sm2_sig_test(void)370 static int sm2_sig_test(void)
371 {
372     int testresult = 0;
373     EC_GROUP *gm_group = NULL;
374     /* From draft-shen-sm2-ecdsa-02 */
375     EC_GROUP *test_group = create_EC_group("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",
376         "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",
377         "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",
378         "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",
379         "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2",
380         "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",
381         "1");
382 
383     if (!TEST_ptr(test_group))
384         goto done;
385 
386     if (!TEST_true(test_sm2_sign(
387             test_group,
388             "ALICE123@YAHOO.COM",
389             "128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263",
390             "message digest",
391             "006CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F"
392             "007c47811054c6f99613a578eb8453706ccb96384fe7df5c171671e760bfa8be3a",
393             "40F1EC59F793D9F49E09DCEF49130D4194F79FB1EED2CAA55BACDB49C4E755D1",
394             "6FC6DAC32C5D5CF10C77DFB20F7C2EB667A457872FB09EC56327A67EC7DEEBE7", 0)))
395         goto done;
396 
397     /* From Annex A in both GM/T0003.5-2012 and GB/T 32918.5-2016.*/
398     gm_group = create_EC_group(
399         "fffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffff",
400         "fffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc",
401         "28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93",
402         "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7",
403         "bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0",
404         "fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123",
405         "1");
406 
407     if (!TEST_ptr(gm_group))
408         goto done;
409 
410     if (!TEST_true(test_sm2_sign(
411             gm_group,
412             /* the default ID specified in GM/T 0009-2012 (Sec. 10).*/
413             SM2_DEFAULT_USERID,
414             /* privkey */
415             "3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8",
416             /* plaintext message */
417             "message digest",
418             /* ephemeral nonce k */
419             "59276E27D506861A16680F3AD9C02DCCEF3CC1FA3CDBE4CE6D54B80DEAC1BC21",
420             /* expected signature, the field values are from GM/T 0003.5-2012,
421                Annex A. */
422             /* signature R, 0x20 bytes */
423             "F5A03B0648D2C4630EEAC513E1BB81A15944DA3827D5B74143AC7EACEEE720B3",
424             /* signature S, 0x20 bytes */
425             "B1B6AA29DF212FD8763182BC0D421CA1BB9038FD1F7F42D4840B69C485BBC1AA", 0)))
426         goto done;
427 
428     /* Make sure we fail if we omit the public portion of the key */
429     if (!TEST_false(test_sm2_sign(
430             gm_group,
431             /* the default ID specified in GM/T 0009-2012 (Sec. 10).*/
432             SM2_DEFAULT_USERID,
433             /* privkey */
434             "3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8",
435             /* plaintext message */
436             "message digest",
437             /* ephemeral nonce k */
438             "59276E27D506861A16680F3AD9C02DCCEF3CC1FA3CDBE4CE6D54B80DEAC1BC21",
439             /* expected signature, the field values are from GM/T 0003.5-2012,
440                Annex A. */
441             /* signature R, 0x20 bytes */
442             "F5A03B0648D2C4630EEAC513E1BB81A15944DA3827D5B74143AC7EACEEE720B3",
443             /* signature S, 0x20 bytes */
444             "B1B6AA29DF212FD8763182BC0D421CA1BB9038FD1F7F42D4840B69C485BBC1AA", 1)))
445         goto done;
446 
447     testresult = 1;
448 
449 done:
450     EC_GROUP_free(test_group);
451     EC_GROUP_free(gm_group);
452 
453     return testresult;
454 }
455 
456 #endif
457 
setup_tests(void)458 int setup_tests(void)
459 {
460 #ifdef OPENSSL_NO_SM2
461     TEST_note("SM2 is disabled.");
462 #else
463     fake_rand = fake_rand_start(NULL);
464     if (fake_rand == NULL)
465         return 0;
466 
467     ADD_TEST(sm2_crypt_test);
468     ADD_TEST(sm2_sig_test);
469 #endif
470     return 1;
471 }
472 
cleanup_tests(void)473 void cleanup_tests(void)
474 {
475 #ifndef OPENSSL_NO_SM2
476     fake_rand_finish(fake_rand);
477 #endif
478 }
479