linux/crypto/sm2.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-or-later */
   2/*
   3 * SM2 asymmetric public-key algorithm
   4 * as specified by OSCCA GM/T 0003.1-2012 -- 0003.5-2012 SM2 and
   5 * described at https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02
   6 *
   7 * Copyright (c) 2020, Alibaba Group.
   8 * Authors: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/mpi.h>
  13#include <crypto/internal/akcipher.h>
  14#include <crypto/akcipher.h>
  15#include <crypto/hash.h>
  16#include <crypto/sm3_base.h>
  17#include <crypto/rng.h>
  18#include <crypto/sm2.h>
  19#include "sm2signature.asn1.h"
  20
  21#define MPI_NBYTES(m)   ((mpi_get_nbits(m) + 7) / 8)
  22
  23struct ecc_domain_parms {
  24        const char *desc;           /* Description of the curve.  */
  25        unsigned int nbits;         /* Number of bits.  */
  26        unsigned int fips:1; /* True if this is a FIPS140-2 approved curve */
  27
  28        /* The model describing this curve.  This is mainly used to select
  29         * the group equation.
  30         */
  31        enum gcry_mpi_ec_models model;
  32
  33        /* The actual ECC dialect used.  This is used for curve specific
  34         * optimizations and to select encodings etc.
  35         */
  36        enum ecc_dialects dialect;
  37
  38        const char *p;              /* The prime defining the field.  */
  39        const char *a, *b;          /* The coefficients.  For Twisted Edwards
  40                                     * Curves b is used for d.  For Montgomery
  41                                     * Curves (a,b) has ((A-2)/4,B^-1).
  42                                     */
  43        const char *n;              /* The order of the base point.  */
  44        const char *g_x, *g_y;      /* Base point.  */
  45        unsigned int h;             /* Cofactor.  */
  46};
  47
  48static const struct ecc_domain_parms sm2_ecp = {
  49        .desc = "sm2p256v1",
  50        .nbits = 256,
  51        .fips = 0,
  52        .model = MPI_EC_WEIERSTRASS,
  53        .dialect = ECC_DIALECT_STANDARD,
  54        .p   = "0xfffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffff",
  55        .a   = "0xfffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc",
  56        .b   = "0x28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93",
  57        .n   = "0xfffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123",
  58        .g_x = "0x32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7",
  59        .g_y = "0xbc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0",
  60        .h = 1
  61};
  62
  63static int sm2_ec_ctx_init(struct mpi_ec_ctx *ec)
  64{
  65        const struct ecc_domain_parms *ecp = &sm2_ecp;
  66        MPI p, a, b;
  67        MPI x, y;
  68        int rc = -EINVAL;
  69
  70        p = mpi_scanval(ecp->p);
  71        a = mpi_scanval(ecp->a);
  72        b = mpi_scanval(ecp->b);
  73        if (!p || !a || !b)
  74                goto free_p;
  75
  76        x = mpi_scanval(ecp->g_x);
  77        y = mpi_scanval(ecp->g_y);
  78        if (!x || !y)
  79                goto free;
  80
  81        rc = -ENOMEM;
  82
  83        ec->Q = mpi_point_new(0);
  84        if (!ec->Q)
  85                goto free;
  86
  87        /* mpi_ec_setup_elliptic_curve */
  88        ec->G = mpi_point_new(0);
  89        if (!ec->G) {
  90                mpi_point_release(ec->Q);
  91                goto free;
  92        }
  93
  94        mpi_set(ec->G->x, x);
  95        mpi_set(ec->G->y, y);
  96        mpi_set_ui(ec->G->z, 1);
  97
  98        rc = -EINVAL;
  99        ec->n = mpi_scanval(ecp->n);
 100        if (!ec->n) {
 101                mpi_point_release(ec->Q);
 102                mpi_point_release(ec->G);
 103                goto free;
 104        }
 105
 106        ec->h = ecp->h;
 107        ec->name = ecp->desc;
 108        mpi_ec_init(ec, ecp->model, ecp->dialect, 0, p, a, b);
 109
 110        rc = 0;
 111
 112free:
 113        mpi_free(x);
 114        mpi_free(y);
 115free_p:
 116        mpi_free(p);
 117        mpi_free(a);
 118        mpi_free(b);
 119
 120        return rc;
 121}
 122
 123static void sm2_ec_ctx_deinit(struct mpi_ec_ctx *ec)
 124{
 125        mpi_ec_deinit(ec);
 126
 127        memset(ec, 0, sizeof(*ec));
 128}
 129
 130/* RESULT must have been initialized and is set on success to the
 131 * point given by VALUE.
 132 */
 133static int sm2_ecc_os2ec(MPI_POINT result, MPI value)
 134{
 135        int rc;
 136        size_t n;
 137        unsigned char *buf;
 138        MPI x, y;
 139
 140        n = MPI_NBYTES(value);
 141        buf = kmalloc(n, GFP_KERNEL);
 142        if (!buf)
 143                return -ENOMEM;
 144
 145        rc = mpi_print(GCRYMPI_FMT_USG, buf, n, &n, value);
 146        if (rc)
 147                goto err_freebuf;
 148
 149        rc = -EINVAL;
 150        if (n < 1 || ((n - 1) % 2))
 151                goto err_freebuf;
 152        /* No support for point compression */
 153        if (*buf != 0x4)
 154                goto err_freebuf;
 155
 156        rc = -ENOMEM;
 157        n = (n - 1) / 2;
 158        x = mpi_read_raw_data(buf + 1, n);
 159        if (!x)
 160                goto err_freebuf;
 161        y = mpi_read_raw_data(buf + 1 + n, n);
 162        if (!y)
 163                goto err_freex;
 164
 165        mpi_normalize(x);
 166        mpi_normalize(y);
 167        mpi_set(result->x, x);
 168        mpi_set(result->y, y);
 169        mpi_set_ui(result->z, 1);
 170
 171        rc = 0;
 172
 173        mpi_free(y);
 174err_freex:
 175        mpi_free(x);
 176err_freebuf:
 177        kfree(buf);
 178        return rc;
 179}
 180
 181struct sm2_signature_ctx {
 182        MPI sig_r;
 183        MPI sig_s;
 184};
 185
 186int sm2_get_signature_r(void *context, size_t hdrlen, unsigned char tag,
 187                                const void *value, size_t vlen)
 188{
 189        struct sm2_signature_ctx *sig = context;
 190
 191        if (!value || !vlen)
 192                return -EINVAL;
 193
 194        sig->sig_r = mpi_read_raw_data(value, vlen);
 195        if (!sig->sig_r)
 196                return -ENOMEM;
 197
 198        return 0;
 199}
 200
 201int sm2_get_signature_s(void *context, size_t hdrlen, unsigned char tag,
 202                                const void *value, size_t vlen)
 203{
 204        struct sm2_signature_ctx *sig = context;
 205
 206        if (!value || !vlen)
 207                return -EINVAL;
 208
 209        sig->sig_s = mpi_read_raw_data(value, vlen);
 210        if (!sig->sig_s)
 211                return -ENOMEM;
 212
 213        return 0;
 214}
 215
 216static int sm2_z_digest_update(struct shash_desc *desc,
 217                        MPI m, unsigned int pbytes)
 218{
 219        static const unsigned char zero[32];
 220        unsigned char *in;
 221        unsigned int inlen;
 222
 223        in = mpi_get_buffer(m, &inlen, NULL);
 224        if (!in)
 225                return -EINVAL;
 226
 227        if (inlen < pbytes) {
 228                /* padding with zero */
 229                crypto_sm3_update(desc, zero, pbytes - inlen);
 230                crypto_sm3_update(desc, in, inlen);
 231        } else if (inlen > pbytes) {
 232                /* skip the starting zero */
 233                crypto_sm3_update(desc, in + inlen - pbytes, pbytes);
 234        } else {
 235                crypto_sm3_update(desc, in, inlen);
 236        }
 237
 238        kfree(in);
 239        return 0;
 240}
 241
 242static int sm2_z_digest_update_point(struct shash_desc *desc,
 243                MPI_POINT point, struct mpi_ec_ctx *ec, unsigned int pbytes)
 244{
 245        MPI x, y;
 246        int ret = -EINVAL;
 247
 248        x = mpi_new(0);
 249        y = mpi_new(0);
 250
 251        if (!mpi_ec_get_affine(x, y, point, ec) &&
 252                !sm2_z_digest_update(desc, x, pbytes) &&
 253                !sm2_z_digest_update(desc, y, pbytes))
 254                ret = 0;
 255
 256        mpi_free(x);
 257        mpi_free(y);
 258        return ret;
 259}
 260
 261int sm2_compute_z_digest(struct crypto_akcipher *tfm,
 262                        const unsigned char *id, size_t id_len,
 263                        unsigned char dgst[SM3_DIGEST_SIZE])
 264{
 265        struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
 266        uint16_t bits_len;
 267        unsigned char entl[2];
 268        SHASH_DESC_ON_STACK(desc, NULL);
 269        unsigned int pbytes;
 270
 271        if (id_len > (USHRT_MAX / 8) || !ec->Q)
 272                return -EINVAL;
 273
 274        bits_len = (uint16_t)(id_len * 8);
 275        entl[0] = bits_len >> 8;
 276        entl[1] = bits_len & 0xff;
 277
 278        pbytes = MPI_NBYTES(ec->p);
 279
 280        /* ZA = H256(ENTLA | IDA | a | b | xG | yG | xA | yA) */
 281        sm3_base_init(desc);
 282        crypto_sm3_update(desc, entl, 2);
 283        crypto_sm3_update(desc, id, id_len);
 284
 285        if (sm2_z_digest_update(desc, ec->a, pbytes) ||
 286                sm2_z_digest_update(desc, ec->b, pbytes) ||
 287                sm2_z_digest_update_point(desc, ec->G, ec, pbytes) ||
 288                sm2_z_digest_update_point(desc, ec->Q, ec, pbytes))
 289                return -EINVAL;
 290
 291        crypto_sm3_final(desc, dgst);
 292        return 0;
 293}
 294EXPORT_SYMBOL(sm2_compute_z_digest);
 295
 296static int _sm2_verify(struct mpi_ec_ctx *ec, MPI hash, MPI sig_r, MPI sig_s)
 297{
 298        int rc = -EINVAL;
 299        struct gcry_mpi_point sG, tP;
 300        MPI t = NULL;
 301        MPI x1 = NULL, y1 = NULL;
 302
 303        mpi_point_init(&sG);
 304        mpi_point_init(&tP);
 305        x1 = mpi_new(0);
 306        y1 = mpi_new(0);
 307        t = mpi_new(0);
 308
 309        /* r, s in [1, n-1] */
 310        if (mpi_cmp_ui(sig_r, 1) < 0 || mpi_cmp(sig_r, ec->n) > 0 ||
 311                mpi_cmp_ui(sig_s, 1) < 0 || mpi_cmp(sig_s, ec->n) > 0) {
 312                goto leave;
 313        }
 314
 315        /* t = (r + s) % n, t == 0 */
 316        mpi_addm(t, sig_r, sig_s, ec->n);
 317        if (mpi_cmp_ui(t, 0) == 0)
 318                goto leave;
 319
 320        /* sG + tP = (x1, y1) */
 321        rc = -EBADMSG;
 322        mpi_ec_mul_point(&sG, sig_s, ec->G, ec);
 323        mpi_ec_mul_point(&tP, t, ec->Q, ec);
 324        mpi_ec_add_points(&sG, &sG, &tP, ec);
 325        if (mpi_ec_get_affine(x1, y1, &sG, ec))
 326                goto leave;
 327
 328        /* R = (e + x1) % n */
 329        mpi_addm(t, hash, x1, ec->n);
 330
 331        /* check R == r */
 332        rc = -EKEYREJECTED;
 333        if (mpi_cmp(t, sig_r))
 334                goto leave;
 335
 336        rc = 0;
 337
 338leave:
 339        mpi_point_free_parts(&sG);
 340        mpi_point_free_parts(&tP);
 341        mpi_free(x1);
 342        mpi_free(y1);
 343        mpi_free(t);
 344
 345        return rc;
 346}
 347
 348static int sm2_verify(struct akcipher_request *req)
 349{
 350        struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
 351        struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
 352        unsigned char *buffer;
 353        struct sm2_signature_ctx sig;
 354        MPI hash;
 355        int ret;
 356
 357        if (unlikely(!ec->Q))
 358                return -EINVAL;
 359
 360        buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL);
 361        if (!buffer)
 362                return -ENOMEM;
 363
 364        sg_pcopy_to_buffer(req->src,
 365                sg_nents_for_len(req->src, req->src_len + req->dst_len),
 366                buffer, req->src_len + req->dst_len, 0);
 367
 368        sig.sig_r = NULL;
 369        sig.sig_s = NULL;
 370        ret = asn1_ber_decoder(&sm2signature_decoder, &sig,
 371                                buffer, req->src_len);
 372        if (ret)
 373                goto error;
 374
 375        ret = -ENOMEM;
 376        hash = mpi_read_raw_data(buffer + req->src_len, req->dst_len);
 377        if (!hash)
 378                goto error;
 379
 380        ret = _sm2_verify(ec, hash, sig.sig_r, sig.sig_s);
 381
 382        mpi_free(hash);
 383error:
 384        mpi_free(sig.sig_r);
 385        mpi_free(sig.sig_s);
 386        kfree(buffer);
 387        return ret;
 388}
 389
 390static int sm2_set_pub_key(struct crypto_akcipher *tfm,
 391                        const void *key, unsigned int keylen)
 392{
 393        struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
 394        MPI a;
 395        int rc;
 396
 397        /* include the uncompressed flag '0x04' */
 398        a = mpi_read_raw_data(key, keylen);
 399        if (!a)
 400                return -ENOMEM;
 401
 402        mpi_normalize(a);
 403        rc = sm2_ecc_os2ec(ec->Q, a);
 404        mpi_free(a);
 405
 406        return rc;
 407}
 408
 409static unsigned int sm2_max_size(struct crypto_akcipher *tfm)
 410{
 411        /* Unlimited max size */
 412        return PAGE_SIZE;
 413}
 414
 415static int sm2_init_tfm(struct crypto_akcipher *tfm)
 416{
 417        struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
 418
 419        return sm2_ec_ctx_init(ec);
 420}
 421
 422static void sm2_exit_tfm(struct crypto_akcipher *tfm)
 423{
 424        struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
 425
 426        sm2_ec_ctx_deinit(ec);
 427}
 428
 429static struct akcipher_alg sm2 = {
 430        .verify = sm2_verify,
 431        .set_pub_key = sm2_set_pub_key,
 432        .max_size = sm2_max_size,
 433        .init = sm2_init_tfm,
 434        .exit = sm2_exit_tfm,
 435        .base = {
 436                .cra_name = "sm2",
 437                .cra_driver_name = "sm2-generic",
 438                .cra_priority = 100,
 439                .cra_module = THIS_MODULE,
 440                .cra_ctxsize = sizeof(struct mpi_ec_ctx),
 441        },
 442};
 443
 444static int sm2_init(void)
 445{
 446        return crypto_register_akcipher(&sm2);
 447}
 448
 449static void sm2_exit(void)
 450{
 451        crypto_unregister_akcipher(&sm2);
 452}
 453
 454subsys_initcall(sm2_init);
 455module_exit(sm2_exit);
 456
 457MODULE_LICENSE("GPL");
 458MODULE_AUTHOR("Tianjia Zhang <tianjia.zhang@linux.alibaba.com>");
 459MODULE_DESCRIPTION("SM2 generic algorithm");
 460MODULE_ALIAS_CRYPTO("sm2-generic");
 461
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.