sm2_sign.c 12.5 KB
Newer Older
J
Jack Lloyd 已提交
1
/*
M
Matt Caswell 已提交
2
 * Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved.
J
Jack Lloyd 已提交
3 4 5 6 7 8 9 10 11
 * Copyright 2017 Ribose Inc. All Rights Reserved.
 * Ported from Ribose contributions from Botan.
 *
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
 */

J
Jack Lloyd 已提交
12
#include "internal/sm2.h"
J
Jack Lloyd 已提交
13
#include "internal/sm2err.h"
14
#include "internal/ec_int.h" /* ec_group_do_inverse_ord() */
J
Jack Lloyd 已提交
15
#include <openssl/err.h>
J
Jack Lloyd 已提交
16
#include <openssl/evp.h>
J
Jack Lloyd 已提交
17
#include <openssl/err.h>
J
Jack Lloyd 已提交
18 19 20
#include <openssl/bn.h>
#include <string.h>

P
Paul Yang 已提交
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
static int sm2_compute_userid_digest(uint8_t *out,
                                     const EVP_MD *digest,
                                     const char *user_id,
                                     const EC_KEY *key)
{
    int rc = 0;
    const EC_GROUP *group = EC_KEY_get0_group(key);
    BN_CTX *ctx = NULL;
    EVP_MD_CTX *hash = NULL;
    BIGNUM *p = NULL;
    BIGNUM *a = NULL;
    BIGNUM *b = NULL;
    BIGNUM *xG = NULL;
    BIGNUM *yG = NULL;
    BIGNUM *xA = NULL;
    BIGNUM *yA = NULL;
    int p_bytes = 0;
    uint8_t *buf = NULL;
    size_t uid_len = 0;
    uint16_t entla = 0;
    uint8_t e_byte = 0;

    hash = EVP_MD_CTX_new();
    ctx = BN_CTX_new();
    if (hash == NULL || ctx == NULL) {
        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_MALLOC_FAILURE);
        goto done;
    }

    p = BN_CTX_get(ctx);
    a = BN_CTX_get(ctx);
    b = BN_CTX_get(ctx);
    xG = BN_CTX_get(ctx);
    yG = BN_CTX_get(ctx);
    xA = BN_CTX_get(ctx);
    yA = BN_CTX_get(ctx);

    if (yA == NULL) {
        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_MALLOC_FAILURE);
        goto done;
    }

    if (!EVP_DigestInit(hash, digest)) {
        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_EVP_LIB);
        goto done;
    }

    /* Z = SM3(ENTLA || IDA || a || b || xG || yG || xA || yA) */

    uid_len = strlen(user_id);
    if (uid_len >= (UINT16_MAX / 8)) {
        /* too large */
        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, SM2_R_USER_ID_TOO_LARGE);
        goto done;
    }

    entla = (uint16_t)(8 * uid_len);

    e_byte = entla >> 8;
    if (!EVP_DigestUpdate(hash, &e_byte, 1)) {
        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_EVP_LIB);
        goto done;
    }
    e_byte = entla & 0xFF;
    if (!EVP_DigestUpdate(hash, &e_byte, 1)
            || !EVP_DigestUpdate(hash, user_id, uid_len)) {
        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_EVP_LIB);
        goto done;
    }

    if (!EC_GROUP_get_curve(group, p, a, b, ctx)) {
        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_EC_LIB);
        goto done;
    }

    p_bytes = BN_num_bytes(p);
    buf = OPENSSL_zalloc(p_bytes);
    if (buf == NULL) {
        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_MALLOC_FAILURE);
        goto done;
    }

    if (BN_bn2binpad(a, buf, p_bytes) < 0
            || !EVP_DigestUpdate(hash, buf, p_bytes)
            || BN_bn2binpad(b, buf, p_bytes) < 0
            || !EVP_DigestUpdate(hash, buf, p_bytes)
            || !EC_POINT_get_affine_coordinates(group,
                                                EC_GROUP_get0_generator(group),
                                                xG, yG, ctx)
            || BN_bn2binpad(xG, buf, p_bytes) < 0
            || !EVP_DigestUpdate(hash, buf, p_bytes)
            || BN_bn2binpad(yG, buf, p_bytes) < 0
            || !EVP_DigestUpdate(hash, buf, p_bytes)
            || !EC_POINT_get_affine_coordinates(group,
                                                EC_KEY_get0_public_key(key),
                                                xA, yA, ctx)
            || BN_bn2binpad(xA, buf, p_bytes) < 0
            || !EVP_DigestUpdate(hash, buf, p_bytes)
            || BN_bn2binpad(yA, buf, p_bytes) < 0
            || !EVP_DigestUpdate(hash, buf, p_bytes)
            || !EVP_DigestFinal(hash, out, NULL)) {
        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_INTERNAL_ERROR);
        goto done;
    }

    rc = 1;

 done:
    OPENSSL_free(buf);
    BN_CTX_free(ctx);
    EVP_MD_CTX_free(hash);
    return rc;
}

135
static BIGNUM *sm2_compute_msg_hash(const EVP_MD *digest,
J
Jack Lloyd 已提交
136 137 138
                                    const EC_KEY *key,
                                    const char *user_id,
                                    const uint8_t *msg, size_t msg_len)
J
Jack Lloyd 已提交
139 140 141
{
    EVP_MD_CTX *hash = EVP_MD_CTX_new();
    const int md_size = EVP_MD_size(digest);
142
    uint8_t *za = NULL;
J
Jack Lloyd 已提交
143 144
    BIGNUM *e = NULL;

145 146
    if (md_size < 0) {
        SM2err(SM2_F_SM2_COMPUTE_MSG_HASH, SM2_R_INVALID_DIGEST);
J
Jack Lloyd 已提交
147
        goto done;
148
    }
J
Jack Lloyd 已提交
149

150 151 152
    za = OPENSSL_zalloc(md_size);
    if (hash == NULL || za == NULL) {
        SM2err(SM2_F_SM2_COMPUTE_MSG_HASH, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
153
        goto done;
154
    }
J
Jack Lloyd 已提交
155

156
    if (!sm2_compute_userid_digest(za, digest, user_id, key)) {
157
        /* SM2err already called */
J
Jack Lloyd 已提交
158
        goto done;
159
    }
J
Jack Lloyd 已提交
160

161 162 163 164 165
    if (!EVP_DigestInit(hash, digest)
            || !EVP_DigestUpdate(hash, za, md_size)
            || !EVP_DigestUpdate(hash, msg, msg_len)
               /* reuse za buffer to hold H(ZA || M) */
            || !EVP_DigestFinal(hash, za, NULL)) {
J
Jack Lloyd 已提交
166
        SM2err(SM2_F_SM2_COMPUTE_MSG_HASH, ERR_R_EVP_LIB);
J
Jack Lloyd 已提交
167
        goto done;
168
    }
J
Jack Lloyd 已提交
169 170

    e = BN_bin2bn(za, md_size, NULL);
171 172
    if (e == NULL)
        SM2err(SM2_F_SM2_COMPUTE_MSG_HASH, ERR_R_INTERNAL_ERROR);
J
Jack Lloyd 已提交
173 174 175 176 177 178 179

 done:
    OPENSSL_free(za);
    EVP_MD_CTX_free(hash);
    return e;
}

180
static ECDSA_SIG *sm2_sig_gen(const EC_KEY *key, const BIGNUM *e)
J
Jack Lloyd 已提交
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
{
    const BIGNUM *dA = EC_KEY_get0_private_key(key);
    const EC_GROUP *group = EC_KEY_get0_group(key);
    const BIGNUM *order = EC_GROUP_get0_order(group);
    ECDSA_SIG *sig = NULL;
    EC_POINT *kG = NULL;
    BN_CTX *ctx = NULL;
    BIGNUM *k = NULL;
    BIGNUM *rk = NULL;
    BIGNUM *r = NULL;
    BIGNUM *s = NULL;
    BIGNUM *x1 = NULL;
    BIGNUM *tmp = NULL;

    kG = EC_POINT_new(group);
    ctx = BN_CTX_new();
197
    if (kG == NULL || ctx == NULL) {
J
Jack Lloyd 已提交
198
        SM2err(SM2_F_SM2_SIG_GEN, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
199
        goto done;
200
    }
J
Jack Lloyd 已提交
201

202
    BN_CTX_start(ctx);
J
Jack Lloyd 已提交
203 204 205 206
    k = BN_CTX_get(ctx);
    rk = BN_CTX_get(ctx);
    x1 = BN_CTX_get(ctx);
    tmp = BN_CTX_get(ctx);
207 208
    if (tmp == NULL) {
        SM2err(SM2_F_SM2_SIG_GEN, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
209
        goto done;
210
    }
J
Jack Lloyd 已提交
211

212 213 214 215
    /*
     * These values are returned and so should not be allocated out of the
     * context
     */
J
Jack Lloyd 已提交
216 217 218
    r = BN_new();
    s = BN_new();

219
    if (r == NULL || s == NULL) {
J
Jack Lloyd 已提交
220
        SM2err(SM2_F_SM2_SIG_GEN, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
221
        goto done;
222
    }
J
Jack Lloyd 已提交
223 224

    for (;;) {
225 226
        if (!BN_priv_rand_range(k, order)) {
            SM2err(SM2_F_SM2_SIG_GEN, ERR_R_INTERNAL_ERROR);
227
            goto done;
228
        }
J
Jack Lloyd 已提交
229

230
        if (!EC_POINT_mul(group, kG, k, NULL, NULL, ctx)
231
                || !EC_POINT_get_affine_coordinates(group, kG, x1, NULL,
P
Paul Yang 已提交
232
                                                    ctx)
233 234
                || !BN_mod_add(r, e, x1, order, ctx)) {
            SM2err(SM2_F_SM2_SIG_GEN, ERR_R_INTERNAL_ERROR);
J
Jack Lloyd 已提交
235
            goto done;
236
        }
J
Jack Lloyd 已提交
237 238 239 240 241

        /* try again if r == 0 or r+k == n */
        if (BN_is_zero(r))
            continue;

242 243 244 245
        if (!BN_add(rk, r, k)) {
            SM2err(SM2_F_SM2_SIG_GEN, ERR_R_INTERNAL_ERROR);
            goto done;
        }
J
Jack Lloyd 已提交
246 247 248 249

        if (BN_cmp(rk, order) == 0)
            continue;

250
        if (!BN_add(s, dA, BN_value_one())
251
                || !ec_group_do_inverse_ord(group, s, s, ctx)
252 253 254 255 256 257
                || !BN_mod_mul(tmp, dA, r, order, ctx)
                || !BN_sub(tmp, k, tmp)
                || !BN_mod_mul(s, s, tmp, order, ctx)) {
            SM2err(SM2_F_SM2_SIG_GEN, ERR_R_BN_LIB);
            goto done;
        }
J
Jack Lloyd 已提交
258 259

        sig = ECDSA_SIG_new();
260
        if (sig == NULL) {
J
Jack Lloyd 已提交
261
            SM2err(SM2_F_SM2_SIG_GEN, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
262
            goto done;
263
        }
J
Jack Lloyd 已提交
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280

         /* takes ownership of r and s */
        ECDSA_SIG_set0(sig, r, s);
        break;
    }

 done:
    if (sig == NULL) {
        BN_free(r);
        BN_free(s);
    }

    BN_CTX_free(ctx);
    EC_POINT_free(kG);
    return sig;
}

281
static int sm2_sig_verify(const EC_KEY *key, const ECDSA_SIG *sig,
282
                          const BIGNUM *e)
J
Jack Lloyd 已提交
283 284 285 286 287 288 289 290 291 292 293 294 295
{
    int ret = 0;
    const EC_GROUP *group = EC_KEY_get0_group(key);
    const BIGNUM *order = EC_GROUP_get0_order(group);
    BN_CTX *ctx = NULL;
    EC_POINT *pt = NULL;
    BIGNUM *t = NULL;
    BIGNUM *x1 = NULL;
    const BIGNUM *r = NULL;
    const BIGNUM *s = NULL;

    ctx = BN_CTX_new();
    pt = EC_POINT_new(group);
296
    if (ctx == NULL || pt == NULL) {
J
Jack Lloyd 已提交
297
        SM2err(SM2_F_SM2_SIG_VERIFY, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
298
        goto done;
299
    }
J
Jack Lloyd 已提交
300 301 302 303

    BN_CTX_start(ctx);
    t = BN_CTX_get(ctx);
    x1 = BN_CTX_get(ctx);
304 305 306 307
    if (x1 == NULL) {
        SM2err(SM2_F_SM2_SIG_VERIFY, ERR_R_MALLOC_FAILURE);
        goto done;
    }
J
Jack Lloyd 已提交
308 309

    /*
310 311 312 313 314 315 316
     * B1: verify whether r' in [1,n-1], verification failed if not
     * B2: vefify whether s' in [1,n-1], verification failed if not
     * B3: set M'~=ZA || M'
     * B4: calculate e'=Hv(M'~)
     * B5: calculate t = (r' + s') modn, verification failed if t=0
     * B6: calculate the point (x1', y1')=[s']G + [t]PA
     * B7: calculate R=(e'+x1') modn, verfication pass if yes, otherwise failed
J
Jack Lloyd 已提交
317 318 319 320
     */

    ECDSA_SIG_get0(sig, &r, &s);

321 322 323 324
    if (BN_cmp(r, BN_value_one()) < 0
            || BN_cmp(s, BN_value_one()) < 0
            || BN_cmp(order, r) <= 0
            || BN_cmp(order, s) <= 0) {
J
Jack Lloyd 已提交
325
        SM2err(SM2_F_SM2_SIG_VERIFY, SM2_R_BAD_SIGNATURE);
J
Jack Lloyd 已提交
326
        goto done;
327
    }
J
Jack Lloyd 已提交
328

329
    if (!BN_mod_add(t, r, s, order, ctx)) {
J
Jack Lloyd 已提交
330
        SM2err(SM2_F_SM2_SIG_VERIFY, ERR_R_BN_LIB);
J
Jack Lloyd 已提交
331
        goto done;
332
    }
J
Jack Lloyd 已提交
333

334
    if (BN_is_zero(t)) {
J
Jack Lloyd 已提交
335
        SM2err(SM2_F_SM2_SIG_VERIFY, SM2_R_BAD_SIGNATURE);
J
Jack Lloyd 已提交
336
        goto done;
337
    }
J
Jack Lloyd 已提交
338

339
    if (!EC_POINT_mul(group, pt, s, EC_KEY_get0_public_key(key), t, ctx)
340
            || !EC_POINT_get_affine_coordinates(group, pt, x1, NULL, ctx)) {
J
Jack Lloyd 已提交
341
        SM2err(SM2_F_SM2_SIG_VERIFY, ERR_R_EC_LIB);
J
Jack Lloyd 已提交
342
        goto done;
343
    }
J
Jack Lloyd 已提交
344

345
    if (!BN_mod_add(t, e, x1, order, ctx)) {
J
Jack Lloyd 已提交
346
        SM2err(SM2_F_SM2_SIG_VERIFY, ERR_R_BN_LIB);
J
Jack Lloyd 已提交
347
        goto done;
348
    }
J
Jack Lloyd 已提交
349 350 351 352 353 354 355 356 357 358

    if (BN_cmp(r, t) == 0)
        ret = 1;

 done:
    EC_POINT_free(pt);
    BN_CTX_free(ctx);
    return ret;
}

359
ECDSA_SIG *sm2_do_sign(const EC_KEY *key,
J
Jack Lloyd 已提交
360 361 362 363 364 365
                       const EVP_MD *digest,
                       const char *user_id, const uint8_t *msg, size_t msg_len)
{
    BIGNUM *e = NULL;
    ECDSA_SIG *sig = NULL;

366
    e = sm2_compute_msg_hash(digest, key, user_id, msg, msg_len);
367 368
    if (e == NULL) {
        /* SM2err already called */
J
Jack Lloyd 已提交
369
        goto done;
370
    }
J
Jack Lloyd 已提交
371

372
    sig = sm2_sig_gen(key, e);
J
Jack Lloyd 已提交
373 374 375 376 377 378

 done:
    BN_free(e);
    return sig;
}

379
int sm2_do_verify(const EC_KEY *key,
J
Jack Lloyd 已提交
380 381 382 383 384
                  const EVP_MD *digest,
                  const ECDSA_SIG *sig,
                  const char *user_id, const uint8_t *msg, size_t msg_len)
{
    BIGNUM *e = NULL;
385
    int ret = 0;
J
Jack Lloyd 已提交
386

387
    e = sm2_compute_msg_hash(digest, key, user_id, msg, msg_len);
388 389
    if (e == NULL) {
        /* SM2err already called */
J
Jack Lloyd 已提交
390
        goto done;
391
    }
J
Jack Lloyd 已提交
392

393
    ret = sm2_sig_verify(key, sig, e);
J
Jack Lloyd 已提交
394 395 396 397 398 399

 done:
    BN_free(e);
    return ret;
}

400
int sm2_sign(const unsigned char *dgst, int dgstlen,
J
Jack Lloyd 已提交
401 402 403 404
             unsigned char *sig, unsigned int *siglen, EC_KEY *eckey)
{
    BIGNUM *e = NULL;
    ECDSA_SIG *s = NULL;
405
    int sigleni;
J
Jack Lloyd 已提交
406 407 408
    int ret = -1;

    e = BN_bin2bn(dgst, dgstlen, NULL);
409 410 411 412
    if (e == NULL) {
       SM2err(SM2_F_SM2_SIGN, ERR_R_BN_LIB);
       goto done;
    }
J
Jack Lloyd 已提交
413

414
    s = sm2_sig_gen(eckey, e);
J
Jack Lloyd 已提交
415

416 417 418 419 420 421
    sigleni = i2d_ECDSA_SIG(s, &sig);
    if (sigleni < 0) {
       SM2err(SM2_F_SM2_SIGN, ERR_R_INTERNAL_ERROR);
       goto done;
    }
    *siglen = (unsigned int)sigleni;
J
Jack Lloyd 已提交
422

423
    ret = 1;
J
Jack Lloyd 已提交
424 425 426 427 428 429 430

 done:
    ECDSA_SIG_free(s);
    BN_free(e);
    return ret;
}

431
int sm2_verify(const unsigned char *dgst, int dgstlen,
J
Jack Lloyd 已提交
432 433 434 435 436 437 438 439 440 441
               const unsigned char *sig, int sig_len, EC_KEY *eckey)
{
    ECDSA_SIG *s = NULL;
    BIGNUM *e = NULL;
    const unsigned char *p = sig;
    unsigned char *der = NULL;
    int derlen = -1;
    int ret = -1;

    s = ECDSA_SIG_new();
442
    if (s == NULL) {
J
Jack Lloyd 已提交
443
        SM2err(SM2_F_SM2_VERIFY, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
444
        goto done;
445 446
    }
    if (d2i_ECDSA_SIG(&s, &p, sig_len) == NULL) {
J
Jack Lloyd 已提交
447
        SM2err(SM2_F_SM2_VERIFY, SM2_R_INVALID_ENCODING);
J
Jack Lloyd 已提交
448
        goto done;
449
    }
J
Jack Lloyd 已提交
450 451
    /* Ensure signature uses DER and doesn't have trailing garbage */
    derlen = i2d_ECDSA_SIG(s, &der);
452
    if (derlen != sig_len || memcmp(sig, der, derlen) != 0) {
J
Jack Lloyd 已提交
453
        SM2err(SM2_F_SM2_VERIFY, SM2_R_INVALID_ENCODING);
J
Jack Lloyd 已提交
454
        goto done;
455
    }
J
Jack Lloyd 已提交
456 457

    e = BN_bin2bn(dgst, dgstlen, NULL);
458 459 460 461
    if (e == NULL) {
        SM2err(SM2_F_SM2_VERIFY, ERR_R_BN_LIB);
        goto done;
    }
J
Jack Lloyd 已提交
462

463
    ret = sm2_sig_verify(eckey, s, e);
J
Jack Lloyd 已提交
464 465 466 467 468 469 470

 done:
    OPENSSL_free(der);
    BN_free(e);
    ECDSA_SIG_free(s);
    return ret;
}