Make SM2 ID stick to specification
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/7113)
Paul Yang
5 years ago
19 | 19 | /* The default user id as specified in GM/T 0009-2012 */ |
20 | 20 | # define SM2_DEFAULT_USERID "1234567812345678" |
21 | 21 | |
22 | int sm2_compute_userid_digest(uint8_t *out, | |
23 | const EVP_MD *digest, | |
24 | const uint8_t *id, | |
25 | const size_t id_len, | |
26 | const EC_KEY *key); | |
27 | ||
22 | 28 | /* |
23 | 29 | * SM2 signature operation. Computes ZA (user id digest) and then signs |
24 | 30 | * H(ZA || msg) using SM2 |
25 | 31 | */ |
26 | 32 | ECDSA_SIG *sm2_do_sign(const EC_KEY *key, |
27 | 33 | const EVP_MD *digest, |
28 | const char *user_id, const uint8_t *msg, size_t msg_len); | |
34 | const uint8_t *id, | |
35 | const size_t id_len, | |
36 | const uint8_t *msg, size_t msg_len); | |
29 | 37 | |
30 | 38 | int sm2_do_verify(const EC_KEY *key, |
31 | 39 | const EVP_MD *digest, |
32 | 40 | const ECDSA_SIG *signature, |
33 | const char *user_id, const uint8_t *msg, size_t msg_len); | |
41 | const uint8_t *id, | |
42 | const size_t id_len, | |
43 | const uint8_t *msg, size_t msg_len); | |
34 | 44 | |
35 | 45 | /* |
36 | 46 | * SM2 signature generation. |
21 | 21 | EC_GROUP *gen_group; |
22 | 22 | /* message digest */ |
23 | 23 | const EVP_MD *md; |
24 | uint8_t *id; | |
25 | size_t id_len; | |
24 | 26 | } SM2_PKEY_CTX; |
25 | 27 | |
26 | 28 | static int pkey_sm2_init(EVP_PKEY_CTX *ctx) |
208 | 210 | return -2; |
209 | 211 | } |
210 | 212 | |
213 | static int pkey_sm2_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) | |
214 | { | |
215 | uint8_t z[EVP_MAX_MD_SIZE]; | |
216 | SM2_PKEY_CTX *sctx = ctx->data; | |
217 | EC_KEY *ec = ctx->pkey->pkey.ec; | |
218 | const EVP_MD *md = EVP_MD_CTX_md(mctx); | |
219 | ||
220 | if (sctx->id == NULL) { | |
221 | /* XXX: | |
222 | * currently we reject all null-ID for SM2, but this needs | |
223 | * more considerations and discussion since the specifications | |
224 | * on SM2 are not clear on null-ID | |
225 | */ | |
226 | return 0; | |
227 | } | |
228 | ||
229 | /* get hashed prefix of tbs message */ | |
230 | if (!sm2_compute_userid_digest(z, md, sctx->id, sctx->id_len, ec)) | |
231 | return 0; | |
232 | ||
233 | return EVP_DigestUpdate(mctx, z, EVP_MD_size(md)); | |
234 | } | |
235 | ||
211 | 236 | const EVP_PKEY_METHOD sm2_pkey_meth = { |
212 | 237 | EVP_PKEY_SM2, |
213 | 238 | 0, |
240 | 265 | 0, |
241 | 266 | 0, |
242 | 267 | pkey_sm2_ctrl, |
243 | pkey_sm2_ctrl_str | |
268 | pkey_sm2_ctrl_str, | |
269 | ||
270 | 0, 0, | |
271 | ||
272 | 0, 0, 0, | |
273 | ||
274 | pkey_sm2_digest_custom | |
244 | 275 | }; |
17 | 17 | #include <openssl/bn.h> |
18 | 18 | #include <string.h> |
19 | 19 | |
20 | static int sm2_compute_userid_digest(uint8_t *out, | |
21 | const EVP_MD *digest, | |
22 | const char *user_id, | |
23 | const EC_KEY *key) | |
20 | int sm2_compute_userid_digest(uint8_t *out, | |
21 | const EVP_MD *digest, | |
22 | const uint8_t *id, | |
23 | const size_t id_len, | |
24 | const EC_KEY *key) | |
24 | 25 | { |
25 | 26 | int rc = 0; |
26 | 27 | const EC_GROUP *group = EC_KEY_get0_group(key); |
35 | 36 | BIGNUM *yA = NULL; |
36 | 37 | int p_bytes = 0; |
37 | 38 | uint8_t *buf = NULL; |
38 | size_t uid_len = 0; | |
39 | 39 | uint16_t entla = 0; |
40 | 40 | uint8_t e_byte = 0; |
41 | 41 | |
66 | 66 | |
67 | 67 | /* Z = SM3(ENTLA || IDA || a || b || xG || yG || xA || yA) */ |
68 | 68 | |
69 | uid_len = strlen(user_id); | |
70 | if (uid_len >= (UINT16_MAX / 8)) { | |
69 | if (id_len >= (UINT16_MAX / 8)) { | |
71 | 70 | /* too large */ |
72 | 71 | SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, SM2_R_USER_ID_TOO_LARGE); |
73 | 72 | goto done; |
74 | 73 | } |
75 | 74 | |
76 | entla = (uint16_t)(8 * uid_len); | |
75 | entla = (uint16_t)(8 * id_len); | |
77 | 76 | |
78 | 77 | e_byte = entla >> 8; |
79 | 78 | if (!EVP_DigestUpdate(hash, &e_byte, 1)) { |
82 | 81 | } |
83 | 82 | e_byte = entla & 0xFF; |
84 | 83 | if (!EVP_DigestUpdate(hash, &e_byte, 1) |
85 | || !EVP_DigestUpdate(hash, user_id, uid_len)) { | |
84 | || !EVP_DigestUpdate(hash, id, id_len)) { | |
86 | 85 | SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_EVP_LIB); |
87 | 86 | goto done; |
88 | 87 | } |
133 | 132 | |
134 | 133 | static BIGNUM *sm2_compute_msg_hash(const EVP_MD *digest, |
135 | 134 | const EC_KEY *key, |
136 | const char *user_id, | |
135 | const uint8_t *id, | |
136 | const size_t id_len, | |
137 | 137 | const uint8_t *msg, size_t msg_len) |
138 | 138 | { |
139 | 139 | EVP_MD_CTX *hash = EVP_MD_CTX_new(); |
152 | 152 | goto done; |
153 | 153 | } |
154 | 154 | |
155 | if (!sm2_compute_userid_digest(za, digest, user_id, key)) { | |
155 | if (!sm2_compute_userid_digest(za, digest, id, id_len, key)) { | |
156 | 156 | /* SM2err already called */ |
157 | 157 | goto done; |
158 | 158 | } |
357 | 357 | |
358 | 358 | ECDSA_SIG *sm2_do_sign(const EC_KEY *key, |
359 | 359 | const EVP_MD *digest, |
360 | const char *user_id, const uint8_t *msg, size_t msg_len) | |
360 | const uint8_t *id, | |
361 | const size_t id_len, | |
362 | const uint8_t *msg, size_t msg_len) | |
361 | 363 | { |
362 | 364 | BIGNUM *e = NULL; |
363 | 365 | ECDSA_SIG *sig = NULL; |
364 | 366 | |
365 | e = sm2_compute_msg_hash(digest, key, user_id, msg, msg_len); | |
367 | e = sm2_compute_msg_hash(digest, key, id, id_len, msg, msg_len); | |
366 | 368 | if (e == NULL) { |
367 | 369 | /* SM2err already called */ |
368 | 370 | goto done; |
378 | 380 | int sm2_do_verify(const EC_KEY *key, |
379 | 381 | const EVP_MD *digest, |
380 | 382 | const ECDSA_SIG *sig, |
381 | const char *user_id, const uint8_t *msg, size_t msg_len) | |
383 | const uint8_t *id, | |
384 | const size_t id_len, | |
385 | const uint8_t *msg, size_t msg_len) | |
382 | 386 | { |
383 | 387 | BIGNUM *e = NULL; |
384 | 388 | int ret = 0; |
385 | 389 | |
386 | e = sm2_compute_msg_hash(digest, key, user_id, msg, msg_len); | |
390 | e = sm2_compute_msg_hash(digest, key, id, id_len, msg, msg_len); | |
387 | 391 | if (e == NULL) { |
388 | 392 | /* SM2err already called */ |
389 | 393 | goto done; |
293 | 293 | goto done; |
294 | 294 | |
295 | 295 | start_fake_rand(k_hex); |
296 | sig = sm2_do_sign(key, EVP_sm3(), userid, (const uint8_t *)message, msg_len); | |
296 | sig = sm2_do_sign(key, EVP_sm3(), (const uint8_t *)userid, strlen(userid), | |
297 | (const uint8_t *)message, msg_len); | |
297 | 298 | if (!TEST_ptr(sig) |
298 | 299 | || !TEST_size_t_eq(fake_rand_bytes_offset, fake_rand_size)) { |
299 | 300 | restore_rand(); |
309 | 310 | || !TEST_BN_eq(s, sig_s)) |
310 | 311 | goto done; |
311 | 312 | |
312 | ok = sm2_do_verify(key, EVP_sm3(), sig, userid, (const uint8_t *)message, | |
313 | msg_len); | |
313 | ok = sm2_do_verify(key, EVP_sm3(), sig, (const uint8_t *)userid, | |
314 | strlen(userid), (const uint8_t *)message, msg_len); | |
314 | 315 | |
315 | 316 | /* We goto done whether this passes or fails */ |
316 | 317 | TEST_true(ok); |