sm2_pmeth.c 7.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved.
 *
 * 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
 */

#include "internal/cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
14 15 16
#include "crypto/evp.h"
#include "crypto/sm2.h"
#include "crypto/sm2err.h"
17 18 19 20 21 22 23 24

/* EC pkey context structure */

typedef struct {
    /* Key and paramgen group */
    EC_GROUP *gen_group;
    /* message digest */
    const EVP_MD *md;
P
Paul Yang 已提交
25
    /* Distinguishing Identifier, ISO/IEC 15946-3 */
P
Paul Yang 已提交
26 27
    uint8_t *id;
    size_t id_len;
P
Paul Yang 已提交
28 29
    /* id_set indicates if the 'id' field is set (1) or not (0) */
    int id_set;
30 31 32 33
} SM2_PKEY_CTX;

static int pkey_sm2_init(EVP_PKEY_CTX *ctx)
{
P
Paul Yang 已提交
34
    SM2_PKEY_CTX *smctx;
35

P
Paul Yang 已提交
36
    if ((smctx = OPENSSL_zalloc(sizeof(*smctx))) == NULL) {
37 38 39 40
        SM2err(SM2_F_PKEY_SM2_INIT, ERR_R_MALLOC_FAILURE);
        return 0;
    }

P
Paul Yang 已提交
41
    ctx->data = smctx;
42 43 44 45 46
    return 1;
}

static void pkey_sm2_cleanup(EVP_PKEY_CTX *ctx)
{
P
Paul Yang 已提交
47
    SM2_PKEY_CTX *smctx = ctx->data;
48

P
Paul Yang 已提交
49 50 51 52
    if (smctx != NULL) {
        EC_GROUP_free(smctx->gen_group);
        OPENSSL_free(smctx->id);
        OPENSSL_free(smctx);
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
        ctx->data = NULL;
    }
}

static int pkey_sm2_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
{
    SM2_PKEY_CTX *dctx, *sctx;

    if (!pkey_sm2_init(dst))
        return 0;
    sctx = src->data;
    dctx = dst->data;
    if (sctx->gen_group != NULL) {
        dctx->gen_group = EC_GROUP_dup(sctx->gen_group);
        if (dctx->gen_group == NULL) {
            pkey_sm2_cleanup(dst);
            return 0;
        }
    }
P
Paul Yang 已提交
72 73 74
    if (sctx->id != NULL) {
        dctx->id = OPENSSL_malloc(sctx->id_len);
        if (dctx->id == NULL) {
P
Paul Yang 已提交
75
            SM2err(SM2_F_PKEY_SM2_COPY, ERR_R_MALLOC_FAILURE);
P
Paul Yang 已提交
76 77 78 79 80 81 82
            pkey_sm2_cleanup(dst);
            return 0;
        }
        memcpy(dctx->id, sctx->id, sctx->id_len);
    }
    dctx->id_len = sctx->id_len;
    dctx->id_set = sctx->id_set;
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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
    dctx->md = sctx->md;

    return 1;
}

static int pkey_sm2_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
                         const unsigned char *tbs, size_t tbslen)
{
    int ret;
    unsigned int sltmp;
    EC_KEY *ec = ctx->pkey->pkey.ec;
    const int sig_sz = ECDSA_size(ctx->pkey->pkey.ec);

    if (sig_sz <= 0) {
        return 0;
    }

    if (sig == NULL) {
        *siglen = (size_t)sig_sz;
        return 1;
    }

    if (*siglen < (size_t)sig_sz) {
        SM2err(SM2_F_PKEY_SM2_SIGN, SM2_R_BUFFER_TOO_SMALL);
        return 0;
    }

    ret = sm2_sign(tbs, tbslen, sig, &sltmp, ec);

    if (ret <= 0)
        return ret;
    *siglen = (size_t)sltmp;
    return 1;
}

static int pkey_sm2_verify(EVP_PKEY_CTX *ctx,
                           const unsigned char *sig, size_t siglen,
                           const unsigned char *tbs, size_t tbslen)
{
    EC_KEY *ec = ctx->pkey->pkey.ec;

    return sm2_verify(tbs, tbslen, sig, siglen, ec);
}

static int pkey_sm2_encrypt(EVP_PKEY_CTX *ctx,
                            unsigned char *out, size_t *outlen,
                            const unsigned char *in, size_t inlen)
{
    EC_KEY *ec = ctx->pkey->pkey.ec;
    SM2_PKEY_CTX *dctx = ctx->data;
    const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md;

    if (out == NULL) {
        if (!sm2_ciphertext_size(ec, md, inlen, outlen))
            return -1;
        else
            return 1;
    }

    return sm2_encrypt(ec, md, in, inlen, out, outlen);
}

static int pkey_sm2_decrypt(EVP_PKEY_CTX *ctx,
                            unsigned char *out, size_t *outlen,
                            const unsigned char *in, size_t inlen)
{
    EC_KEY *ec = ctx->pkey->pkey.ec;
    SM2_PKEY_CTX *dctx = ctx->data;
    const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md;

    if (out == NULL) {
154
        if (!sm2_plaintext_size(in, inlen, outlen))
155 156 157 158 159 160 161 162 163 164
            return -1;
        else
            return 1;
    }

    return sm2_decrypt(ec, md, in, inlen, out, outlen);
}

static int pkey_sm2_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
{
P
Paul Yang 已提交
165
    SM2_PKEY_CTX *smctx = ctx->data;
166
    EC_GROUP *group;
P
Paul Yang 已提交
167
    uint8_t *tmp_id;
168 169 170 171 172 173 174 175

    switch (type) {
    case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID:
        group = EC_GROUP_new_by_curve_name(p1);
        if (group == NULL) {
            SM2err(SM2_F_PKEY_SM2_CTRL, SM2_R_INVALID_CURVE);
            return 0;
        }
P
Paul Yang 已提交
176 177
        EC_GROUP_free(smctx->gen_group);
        smctx->gen_group = group;
178 179 180
        return 1;

    case EVP_PKEY_CTRL_EC_PARAM_ENC:
P
Paul Yang 已提交
181
        if (smctx->gen_group == NULL) {
182 183 184
            SM2err(SM2_F_PKEY_SM2_CTRL, SM2_R_NO_PARAMETERS_SET);
            return 0;
        }
P
Paul Yang 已提交
185
        EC_GROUP_set_asn1_flag(smctx->gen_group, p1);
186 187 188
        return 1;

    case EVP_PKEY_CTRL_MD:
P
Paul Yang 已提交
189
        smctx->md = p2;
190 191 192
        return 1;

    case EVP_PKEY_CTRL_GET_MD:
P
Paul Yang 已提交
193 194 195 196 197
        *(const EVP_MD **)p2 = smctx->md;
        return 1;

    case EVP_PKEY_CTRL_SET1_ID:
        if (p1 > 0) {
P
Paul Yang 已提交
198
            tmp_id = OPENSSL_malloc(p1);
P
Paul Yang 已提交
199 200
            if (tmp_id == NULL) {
                SM2err(SM2_F_PKEY_SM2_CTRL, ERR_R_MALLOC_FAILURE);
P
Paul Yang 已提交
201
                return 0;
P
Paul Yang 已提交
202
            }
P
Paul Yang 已提交
203 204 205
            memcpy(tmp_id, p2, p1);
            OPENSSL_free(smctx->id);
            smctx->id = tmp_id;
P
Paul Yang 已提交
206 207
        } else {
            /* set null-ID */
P
Paul Yang 已提交
208
            OPENSSL_free(smctx->id);
P
Paul Yang 已提交
209 210 211 212 213 214 215 216 217 218 219 220
            smctx->id = NULL;
        }
        smctx->id_len = (size_t)p1;
        smctx->id_set = 1;
        return 1;

    case EVP_PKEY_CTRL_GET1_ID:
        memcpy(p2, smctx->id, smctx->id_len);
        return 1;

    case EVP_PKEY_CTRL_GET1_ID_LEN:
        *(size_t *)p2 = smctx->id_len;
221 222
        return 1;

223 224 225 226
    case EVP_PKEY_CTRL_DIGESTINIT:
        /* nothing to be inited, this is to suppress the error... */
        return 1;

227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
    default:
        return -2;
    }
}

static int pkey_sm2_ctrl_str(EVP_PKEY_CTX *ctx,
                             const char *type, const char *value)
{
    if (strcmp(type, "ec_paramgen_curve") == 0) {
        int nid = NID_undef;

        if (((nid = EC_curve_nist2nid(value)) == NID_undef)
            && ((nid = OBJ_sn2nid(value)) == NID_undef)
            && ((nid = OBJ_ln2nid(value)) == NID_undef)) {
            SM2err(SM2_F_PKEY_SM2_CTRL_STR, SM2_R_INVALID_CURVE);
            return 0;
        }
        return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid);
    } else if (strcmp(type, "ec_param_enc") == 0) {
        int param_enc;

        if (strcmp(value, "explicit") == 0)
            param_enc = 0;
        else if (strcmp(value, "named_curve") == 0)
            param_enc = OPENSSL_EC_NAMED_CURVE;
        else
            return -2;
        return EVP_PKEY_CTX_set_ec_param_enc(ctx, param_enc);
    }

    return -2;
}

P
Paul Yang 已提交
260 261 262
static int pkey_sm2_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
{
    uint8_t z[EVP_MAX_MD_SIZE];
P
Paul Yang 已提交
263
    SM2_PKEY_CTX *smctx = ctx->data;
P
Paul Yang 已提交
264 265
    EC_KEY *ec = ctx->pkey->pkey.ec;
    const EVP_MD *md = EVP_MD_CTX_md(mctx);
266
    int mdlen = EVP_MD_size(md);
P
Paul Yang 已提交
267

P
Paul Yang 已提交
268 269 270 271 272
    if (!smctx->id_set) {
        /*
         * An ID value must be set. The specifications are not clear whether a
         * NULL is allowed. We only allow it if set explicitly for maximum
         * flexibility.
P
Paul Yang 已提交
273
         */
P
Paul Yang 已提交
274
        SM2err(SM2_F_PKEY_SM2_DIGEST_CUSTOM, SM2_R_ID_NOT_SET);
P
Paul Yang 已提交
275 276 277
        return 0;
    }

278 279 280 281 282
    if (mdlen < 0) {
        SM2err(SM2_F_PKEY_SM2_DIGEST_CUSTOM, SM2_R_INVALID_DIGEST);
        return 0;
    }

P
Paul Yang 已提交
283 284
    /* get hashed prefix 'z' of tbs message */
    if (!sm2_compute_z_digest(z, md, smctx->id, smctx->id_len, ec))
P
Paul Yang 已提交
285 286
        return 0;

287
    return EVP_DigestUpdate(mctx, z, (size_t)mdlen);
P
Paul Yang 已提交
288 289
}

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
const EVP_PKEY_METHOD sm2_pkey_meth = {
    EVP_PKEY_SM2,
    0,
    pkey_sm2_init,
    pkey_sm2_copy,
    pkey_sm2_cleanup,

    0,
    0,

    0,
    0,

    0,
    pkey_sm2_sign,

    0,
    pkey_sm2_verify,

    0, 0,

    0, 0, 0, 0,

    0,
    pkey_sm2_encrypt,

    0,
    pkey_sm2_decrypt,

    0,
    0,
    pkey_sm2_ctrl,
P
Paul Yang 已提交
322 323 324 325 326 327 328
    pkey_sm2_ctrl_str,

    0, 0,

    0, 0, 0,

    pkey_sm2_digest_custom
329
};