sm2_sign.c 9.9 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 14
#include "internal/sm2err.h"
#include <openssl/err.h>
J
Jack Lloyd 已提交
15
#include <openssl/evp.h>
J
Jack Lloyd 已提交
16
#include <openssl/err.h>
J
Jack Lloyd 已提交
17 18 19
#include <openssl/bn.h>
#include <string.h>

J
Jack Lloyd 已提交
20 21 22 23
static BIGNUM *SM2_compute_msg_hash(const EVP_MD *digest,
                                    const EC_KEY *key,
                                    const char *user_id,
                                    const uint8_t *msg, size_t msg_len)
J
Jack Lloyd 已提交
24 25 26 27 28 29 30
{
    EVP_MD_CTX *hash = EVP_MD_CTX_new();
    const int md_size = EVP_MD_size(digest);
    uint8_t *za = OPENSSL_zalloc(md_size);
    BIGNUM *e = NULL;

    if (za == NULL)
J
Jack Lloyd 已提交
31 32
        {
        SM2err(SM2_F_SM2_COMPUTE_MSG_HASH, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
33
        goto done;
J
Jack Lloyd 已提交
34
        }
J
Jack Lloyd 已提交
35 36

    if (hash == NULL)
J
Jack Lloyd 已提交
37 38
        {
        SM2err(SM2_F_SM2_COMPUTE_MSG_HASH, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
39
        goto done;
J
Jack Lloyd 已提交
40
        }
J
Jack Lloyd 已提交
41 42 43 44 45

    if (SM2_compute_userid_digest(za, digest, user_id, key) == 0)
        goto done;

    if (EVP_DigestInit(hash, digest) == 0)
J
Jack Lloyd 已提交
46 47
        {
        SM2err(SM2_F_SM2_COMPUTE_MSG_HASH, ERR_R_EVP_LIB);
J
Jack Lloyd 已提交
48
        goto done;
J
Jack Lloyd 已提交
49
        }
J
Jack Lloyd 已提交
50 51

    if (EVP_DigestUpdate(hash, za, md_size) == 0)
J
Jack Lloyd 已提交
52 53
        {
        SM2err(SM2_F_SM2_COMPUTE_MSG_HASH, ERR_R_EVP_LIB);
J
Jack Lloyd 已提交
54
        goto done;
J
Jack Lloyd 已提交
55
        }
J
Jack Lloyd 已提交
56 57

    if (EVP_DigestUpdate(hash, msg, msg_len) == 0)
J
Jack Lloyd 已提交
58 59
        {
        SM2err(SM2_F_SM2_COMPUTE_MSG_HASH, ERR_R_EVP_LIB);
J
Jack Lloyd 已提交
60
        goto done;
J
Jack Lloyd 已提交
61
        }
J
Jack Lloyd 已提交
62 63 64

    /* reuse za buffer to hold H(ZA || M) */
    if (EVP_DigestFinal(hash, za, NULL) == 0)
J
Jack Lloyd 已提交
65 66
        {
        SM2err(SM2_F_SM2_COMPUTE_MSG_HASH, ERR_R_EVP_LIB);
J
Jack Lloyd 已提交
67
        goto done;
J
Jack Lloyd 已提交
68
        }
J
Jack Lloyd 已提交
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

    e = BN_bin2bn(za, md_size, NULL);

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

static
ECDSA_SIG *SM2_sig_gen(const EC_KEY *key, const BIGNUM *e)
{
    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);
    if (kG == NULL)
J
Jack Lloyd 已提交
97 98
        {
        SM2err(SM2_F_SM2_SIG_GEN, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
99
        goto done;
J
Jack Lloyd 已提交
100
        }
J
Jack Lloyd 已提交
101 102 103

    ctx = BN_CTX_new();
    if (ctx == NULL)
J
Jack Lloyd 已提交
104 105
        {
        SM2err(SM2_F_SM2_SIG_GEN, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
106
        goto done;
J
Jack Lloyd 已提交
107
        }
J
Jack Lloyd 已提交
108 109 110 111 112 113 114 115 116

    BN_CTX_start(ctx);

    k = BN_CTX_get(ctx);
    rk = BN_CTX_get(ctx);
    x1 = BN_CTX_get(ctx);
    tmp = BN_CTX_get(ctx);

    if (tmp == NULL)
J
Jack Lloyd 已提交
117 118
        {
        SM2err(SM2_F_SM2_SIG_GEN, ERR_R_BN_LIB);
J
Jack Lloyd 已提交
119
        goto done;
J
Jack Lloyd 已提交
120
        }
J
Jack Lloyd 已提交
121 122 123 124 125 126

    /* These values are returned and so should not be allocated out of the context */
    r = BN_new();
    s = BN_new();

    if (r == NULL || s == NULL)
J
Jack Lloyd 已提交
127 128
        {
        SM2err(SM2_F_SM2_SIG_GEN, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
129
        goto done;
J
Jack Lloyd 已提交
130
        }
J
Jack Lloyd 已提交
131 132 133 134 135

    for (;;) {
        BN_priv_rand_range(k, order);

        if (EC_POINT_mul(group, kG, k, NULL, NULL, ctx) == 0)
J
Jack Lloyd 已提交
136 137
            {
            SM2err(SM2_F_SM2_SIG_GEN, ERR_R_EC_LIB);
J
Jack Lloyd 已提交
138
            goto done;
J
Jack Lloyd 已提交
139
            }
J
Jack Lloyd 已提交
140 141

        if (EC_POINT_get_affine_coordinates_GFp(group, kG, x1, NULL, ctx) == 0)
J
Jack Lloyd 已提交
142 143
            {
            SM2err(SM2_F_SM2_SIG_GEN, ERR_R_EC_LIB);
J
Jack Lloyd 已提交
144
            goto done;
J
Jack Lloyd 已提交
145
            }
J
Jack Lloyd 已提交
146 147

        if (BN_mod_add(r, e, x1, order, ctx) == 0)
J
Jack Lloyd 已提交
148 149
            {
            SM2err(SM2_F_SM2_SIG_GEN, ERR_R_BN_LIB);
J
Jack Lloyd 已提交
150
            goto done;
J
Jack Lloyd 已提交
151
            }
J
Jack Lloyd 已提交
152 153 154 155 156 157 158 159 160 161

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

        BN_add(rk, r, k);

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

J
Jack Lloyd 已提交
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
        if(BN_add(s, dA, BN_value_one()) == 0)
           {
           SM2err(SM2_F_SM2_SIG_GEN, ERR_R_BN_LIB);
           goto done;
           }

        if(BN_mod_inverse(s, s, order, ctx) == 0)
           {
           SM2err(SM2_F_SM2_SIG_GEN, ERR_R_BN_LIB);
           goto done;
           }

        if(BN_mod_mul(tmp, dA, r, order, ctx) == 0)
           {
           SM2err(SM2_F_SM2_SIG_GEN, ERR_R_BN_LIB);
           goto done;
           }

        if(BN_sub(tmp, k, tmp) == 0)
           {
           SM2err(SM2_F_SM2_SIG_GEN, ERR_R_BN_LIB);
           goto done;
           }

        if(BN_mod_mul(s, s, tmp, order, ctx) == 0)
           {
           SM2err(SM2_F_SM2_SIG_GEN, ERR_R_BN_LIB);
           goto done;
           }
J
Jack Lloyd 已提交
191 192 193 194

        sig = ECDSA_SIG_new();

        if (sig == NULL)
J
Jack Lloyd 已提交
195 196
            {
            SM2err(SM2_F_SM2_SIG_GEN, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
197
            goto done;
J
Jack Lloyd 已提交
198
            }
J
Jack Lloyd 已提交
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233

         /* 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;

}

static
int SM2_sig_verify(const EC_KEY *key, const ECDSA_SIG *sig, const BIGNUM *e)
{
    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();
    if (ctx == NULL)
J
Jack Lloyd 已提交
234 235
        {
        SM2err(SM2_F_SM2_SIG_VERIFY, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
236
        goto done;
J
Jack Lloyd 已提交
237 238
        }

J
Jack Lloyd 已提交
239 240
    pt = EC_POINT_new(group);
    if (pt == NULL)
J
Jack Lloyd 已提交
241 242
        {
        SM2err(SM2_F_SM2_SIG_VERIFY, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
243
        goto done;
J
Jack Lloyd 已提交
244
        }
J
Jack Lloyd 已提交
245 246 247 248 249 250 251

    BN_CTX_start(ctx);

    t = BN_CTX_get(ctx);
    x1 = BN_CTX_get(ctx);

    if (x1 == NULL)
J
Jack Lloyd 已提交
252 253 254 255
       {
       SM2err(SM2_F_SM2_SIG_VERIFY, ERR_R_MALLOC_FAILURE);
       goto done;
       }
J
Jack Lloyd 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268

    /*
       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
     */

    ECDSA_SIG_get0(sig, &r, &s);

J
Jack Lloyd 已提交
269 270 271
    if ((BN_cmp(r, BN_value_one()) < 0) || (BN_cmp(s, BN_value_one()) < 0))
        {
        SM2err(SM2_F_SM2_SIG_VERIFY, SM2_R_BAD_SIGNATURE);
J
Jack Lloyd 已提交
272
        goto done;
J
Jack Lloyd 已提交
273
        }
J
Jack Lloyd 已提交
274

J
Jack Lloyd 已提交
275 276 277
    if ((BN_cmp(order, r) <= 0) || (BN_cmp(order, s) <= 0))
        {
        SM2err(SM2_F_SM2_SIG_VERIFY, SM2_R_BAD_SIGNATURE);
J
Jack Lloyd 已提交
278
        goto done;
J
Jack Lloyd 已提交
279
        }
J
Jack Lloyd 已提交
280 281

    if (BN_mod_add(t, r, s, order, ctx) == 0)
J
Jack Lloyd 已提交
282 283
        {
        SM2err(SM2_F_SM2_SIG_VERIFY, ERR_R_BN_LIB);
J
Jack Lloyd 已提交
284
        goto done;
J
Jack Lloyd 已提交
285
        }
J
Jack Lloyd 已提交
286 287

    if (BN_is_zero(t) == 1)
J
Jack Lloyd 已提交
288 289
        {
        SM2err(SM2_F_SM2_SIG_VERIFY, SM2_R_BAD_SIGNATURE);
J
Jack Lloyd 已提交
290
        goto done;
J
Jack Lloyd 已提交
291
        }
J
Jack Lloyd 已提交
292 293

    if (EC_POINT_mul(group, pt, s, EC_KEY_get0_public_key(key), t, ctx) == 0)
J
Jack Lloyd 已提交
294 295
        {
        SM2err(SM2_F_SM2_SIG_VERIFY, ERR_R_EC_LIB);
J
Jack Lloyd 已提交
296
        goto done;
J
Jack Lloyd 已提交
297
        }
J
Jack Lloyd 已提交
298 299

    if (EC_POINT_get_affine_coordinates_GFp(group, pt, x1, NULL, ctx) == 0)
J
Jack Lloyd 已提交
300 301
        {
        SM2err(SM2_F_SM2_SIG_VERIFY, ERR_R_EC_LIB);
J
Jack Lloyd 已提交
302
        goto done;
J
Jack Lloyd 已提交
303
        }
J
Jack Lloyd 已提交
304 305

    if (BN_mod_add(t, e, x1, order, ctx) == 0)
J
Jack Lloyd 已提交
306 307
        {
        SM2err(SM2_F_SM2_SIG_VERIFY, ERR_R_BN_LIB);
J
Jack Lloyd 已提交
308
        goto done;
J
Jack Lloyd 已提交
309
        }
J
Jack Lloyd 已提交
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326

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

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

ECDSA_SIG *SM2_do_sign(const EC_KEY *key,
                       const EVP_MD *digest,
                       const char *user_id, const uint8_t *msg, size_t msg_len)
{
    BIGNUM *e = NULL;
    ECDSA_SIG *sig = NULL;

J
Jack Lloyd 已提交
327
    e = SM2_compute_msg_hash(digest, key, user_id, msg, msg_len);
J
Jack Lloyd 已提交
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
    if (e == NULL)
        goto done;

    sig = SM2_sig_gen(key, e);

 done:
    BN_free(e);
    return sig;
}

int SM2_do_verify(const EC_KEY *key,
                  const EVP_MD *digest,
                  const ECDSA_SIG *sig,
                  const char *user_id, const uint8_t *msg, size_t msg_len)
{
    BIGNUM *e = NULL;
    int ret = -1;

J
Jack Lloyd 已提交
346
    e = SM2_compute_msg_hash(digest, key, user_id, msg, msg_len);
J
Jack Lloyd 已提交
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
    if (e == NULL)
        goto done;

    ret = SM2_sig_verify(key, sig, e);

 done:
    BN_free(e);
    return ret;
}

int SM2_sign(int type, const unsigned char *dgst, int dgstlen,
             unsigned char *sig, unsigned int *siglen, EC_KEY *eckey)
{
    BIGNUM *e = NULL;
    ECDSA_SIG *s = NULL;
    int ret = -1;

J
Jack Lloyd 已提交
364 365 366 367 368
    if (type != NID_sm3 || dgstlen != 32)
       {
       SM2err(SM2_F_SM2_SIGN, SM2_R_INVALID_DIGEST_TYPE);
       goto done;
       }
J
Jack Lloyd 已提交
369 370 371 372 373 374 375

    e = BN_bin2bn(dgst, dgstlen, NULL);

    s = SM2_sig_gen(eckey, e);

    *siglen = i2d_ECDSA_SIG(s, &sig);

376
    ret = 1;
J
Jack Lloyd 已提交
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394

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

int SM2_verify(int type, const unsigned char *dgst, int dgstlen,
               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;

    if (type != NID_sm3)
J
Jack Lloyd 已提交
395 396 397 398
       {
       SM2err(SM2_F_SM2_VERIFY, SM2_R_INVALID_DIGEST_TYPE);
       goto done;
       }
J
Jack Lloyd 已提交
399 400 401

    s = ECDSA_SIG_new();
    if (s == NULL)
J
Jack Lloyd 已提交
402 403
        {
        SM2err(SM2_F_SM2_VERIFY, ERR_R_MALLOC_FAILURE);
J
Jack Lloyd 已提交
404
        goto done;
J
Jack Lloyd 已提交
405
        }
J
Jack Lloyd 已提交
406
    if (d2i_ECDSA_SIG(&s, &p, sig_len) == NULL)
J
Jack Lloyd 已提交
407 408
        {
        SM2err(SM2_F_SM2_VERIFY, SM2_R_INVALID_ENCODING);
J
Jack Lloyd 已提交
409
        goto done;
J
Jack Lloyd 已提交
410
        }
J
Jack Lloyd 已提交
411 412 413
    /* Ensure signature uses DER and doesn't have trailing garbage */
    derlen = i2d_ECDSA_SIG(s, &der);
    if (derlen != sig_len || memcmp(sig, der, derlen) != 0)
J
Jack Lloyd 已提交
414 415
        {
        SM2err(SM2_F_SM2_VERIFY, SM2_R_INVALID_ENCODING);
J
Jack Lloyd 已提交
416
        goto done;
J
Jack Lloyd 已提交
417
        }
J
Jack Lloyd 已提交
418 419 420 421 422 423 424 425 426 427 428

    e = BN_bin2bn(dgst, dgstlen, NULL);

    ret = SM2_sig_verify(eckey, s, e);

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