Blame crypto/sm2/sm2_pmeth.c

Packit Service 084de1
/*
Packit Service 084de1
 * Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved.
Packit Service 084de1
 *
Packit Service 084de1
 * Licensed under the OpenSSL license (the "License").  You may not use
Packit Service 084de1
 * this file except in compliance with the License.  You can obtain a copy
Packit Service 084de1
 * in the file LICENSE in the source distribution or at
Packit Service 084de1
 * https://www.openssl.org/source/license.html
Packit Service 084de1
 */
Packit Service 084de1
Packit Service 084de1
#include "internal/cryptlib.h"
Packit Service 084de1
#include <openssl/asn1t.h>
Packit Service 084de1
#include <openssl/ec.h>
Packit Service 084de1
#include <openssl/evp.h>
Packit Service 084de1
#include "crypto/evp.h"
Packit Service 084de1
#include "crypto/sm2.h"
Packit Service 084de1
#include "crypto/sm2err.h"
Packit Service 084de1
Packit Service 084de1
/* EC pkey context structure */
Packit Service 084de1
Packit Service 084de1
typedef struct {
Packit Service 084de1
    /* Key and paramgen group */
Packit Service 084de1
    EC_GROUP *gen_group;
Packit Service 084de1
    /* message digest */
Packit Service 084de1
    const EVP_MD *md;
Packit Service 084de1
    /* Distinguishing Identifier, ISO/IEC 15946-3 */
Packit Service 084de1
    uint8_t *id;
Packit Service 084de1
    size_t id_len;
Packit Service 084de1
    /* id_set indicates if the 'id' field is set (1) or not (0) */
Packit Service 084de1
    int id_set;
Packit Service 084de1
} SM2_PKEY_CTX;
Packit Service 084de1
Packit Service 084de1
static int pkey_sm2_init(EVP_PKEY_CTX *ctx)
Packit Service 084de1
{
Packit Service 084de1
    SM2_PKEY_CTX *smctx;
Packit Service 084de1
Packit Service 084de1
    if ((smctx = OPENSSL_zalloc(sizeof(*smctx))) == NULL) {
Packit Service 084de1
        SM2err(SM2_F_PKEY_SM2_INIT, ERR_R_MALLOC_FAILURE);
Packit Service 084de1
        return 0;
Packit Service 084de1
    }
Packit Service 084de1
Packit Service 084de1
    ctx->data = smctx;
Packit Service 084de1
    return 1;
Packit Service 084de1
}
Packit Service 084de1
Packit Service 084de1
static void pkey_sm2_cleanup(EVP_PKEY_CTX *ctx)
Packit Service 084de1
{
Packit Service 084de1
    SM2_PKEY_CTX *smctx = ctx->data;
Packit Service 084de1
Packit Service 084de1
    if (smctx != NULL) {
Packit Service 084de1
        EC_GROUP_free(smctx->gen_group);
Packit Service 084de1
        OPENSSL_free(smctx->id);
Packit Service 084de1
        OPENSSL_free(smctx);
Packit Service 084de1
        ctx->data = NULL;
Packit Service 084de1
    }
Packit Service 084de1
}
Packit Service 084de1
Packit Service 084de1
static int pkey_sm2_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
Packit Service 084de1
{
Packit Service 084de1
    SM2_PKEY_CTX *dctx, *sctx;
Packit Service 084de1
Packit Service 084de1
    if (!pkey_sm2_init(dst))
Packit Service 084de1
        return 0;
Packit Service 084de1
    sctx = src->data;
Packit Service 084de1
    dctx = dst->data;
Packit Service 084de1
    if (sctx->gen_group != NULL) {
Packit Service 084de1
        dctx->gen_group = EC_GROUP_dup(sctx->gen_group);
Packit Service 084de1
        if (dctx->gen_group == NULL) {
Packit Service 084de1
            pkey_sm2_cleanup(dst);
Packit Service 084de1
            return 0;
Packit Service 084de1
        }
Packit Service 084de1
    }
Packit Service 084de1
    if (sctx->id != NULL) {
Packit Service 084de1
        dctx->id = OPENSSL_malloc(sctx->id_len);
Packit Service 084de1
        if (dctx->id == NULL) {
Packit Service 084de1
            SM2err(SM2_F_PKEY_SM2_COPY, ERR_R_MALLOC_FAILURE);
Packit Service 084de1
            pkey_sm2_cleanup(dst);
Packit Service 084de1
            return 0;
Packit Service 084de1
        }
Packit Service 084de1
        memcpy(dctx->id, sctx->id, sctx->id_len);
Packit Service 084de1
    }
Packit Service 084de1
    dctx->id_len = sctx->id_len;
Packit Service 084de1
    dctx->id_set = sctx->id_set;
Packit Service 084de1
    dctx->md = sctx->md;
Packit Service 084de1
Packit Service 084de1
    return 1;
Packit Service 084de1
}
Packit Service 084de1
Packit Service 084de1
static int pkey_sm2_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
Packit Service 084de1
                         const unsigned char *tbs, size_t tbslen)
Packit Service 084de1
{
Packit Service 084de1
    int ret;
Packit Service 084de1
    unsigned int sltmp;
Packit Service 084de1
    EC_KEY *ec = ctx->pkey->pkey.ec;
Packit Service 084de1
    const int sig_sz = ECDSA_size(ctx->pkey->pkey.ec);
Packit Service 084de1
Packit Service 084de1
    if (sig_sz <= 0) {
Packit Service 084de1
        return 0;
Packit Service 084de1
    }
Packit Service 084de1
Packit Service 084de1
    if (sig == NULL) {
Packit Service 084de1
        *siglen = (size_t)sig_sz;
Packit Service 084de1
        return 1;
Packit Service 084de1
    }
Packit Service 084de1
Packit Service 084de1
    if (*siglen < (size_t)sig_sz) {
Packit Service 084de1
        SM2err(SM2_F_PKEY_SM2_SIGN, SM2_R_BUFFER_TOO_SMALL);
Packit Service 084de1
        return 0;
Packit Service 084de1
    }
Packit Service 084de1
Packit Service 084de1
    ret = sm2_sign(tbs, tbslen, sig, &sltmp, ec);
Packit Service 084de1
Packit Service 084de1
    if (ret <= 0)
Packit Service 084de1
        return ret;
Packit Service 084de1
    *siglen = (size_t)sltmp;
Packit Service 084de1
    return 1;
Packit Service 084de1
}
Packit Service 084de1
Packit Service 084de1
static int pkey_sm2_verify(EVP_PKEY_CTX *ctx,
Packit Service 084de1
                           const unsigned char *sig, size_t siglen,
Packit Service 084de1
                           const unsigned char *tbs, size_t tbslen)
Packit Service 084de1
{
Packit Service 084de1
    EC_KEY *ec = ctx->pkey->pkey.ec;
Packit Service 084de1
Packit Service 084de1
    return sm2_verify(tbs, tbslen, sig, siglen, ec);
Packit Service 084de1
}
Packit Service 084de1
Packit Service 084de1
static int pkey_sm2_encrypt(EVP_PKEY_CTX *ctx,
Packit Service 084de1
                            unsigned char *out, size_t *outlen,
Packit Service 084de1
                            const unsigned char *in, size_t inlen)
Packit Service 084de1
{
Packit Service 084de1
    EC_KEY *ec = ctx->pkey->pkey.ec;
Packit Service 084de1
    SM2_PKEY_CTX *dctx = ctx->data;
Packit Service 084de1
    const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md;
Packit Service 084de1
Packit Service 084de1
    if (out == NULL) {
Packit Service 084de1
        if (!sm2_ciphertext_size(ec, md, inlen, outlen))
Packit Service 084de1
            return -1;
Packit Service 084de1
        else
Packit Service 084de1
            return 1;
Packit Service 084de1
    }
Packit Service 084de1
Packit Service 084de1
    return sm2_encrypt(ec, md, in, inlen, out, outlen);
Packit Service 084de1
}
Packit Service 084de1
Packit Service 084de1
static int pkey_sm2_decrypt(EVP_PKEY_CTX *ctx,
Packit Service 084de1
                            unsigned char *out, size_t *outlen,
Packit Service 084de1
                            const unsigned char *in, size_t inlen)
Packit Service 084de1
{
Packit Service 084de1
    EC_KEY *ec = ctx->pkey->pkey.ec;
Packit Service 084de1
    SM2_PKEY_CTX *dctx = ctx->data;
Packit Service 084de1
    const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md;
Packit Service 084de1
Packit Service 084de1
    if (out == NULL) {
Packit Service 084de1
        if (!sm2_plaintext_size(ec, md, inlen, outlen))
Packit Service 084de1
            return -1;
Packit Service 084de1
        else
Packit Service 084de1
            return 1;
Packit Service 084de1
    }
Packit Service 084de1
Packit Service 084de1
    return sm2_decrypt(ec, md, in, inlen, out, outlen);
Packit Service 084de1
}
Packit Service 084de1
Packit Service 084de1
static int pkey_sm2_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
Packit Service 084de1
{
Packit Service 084de1
    SM2_PKEY_CTX *smctx = ctx->data;
Packit Service 084de1
    EC_GROUP *group;
Packit Service 084de1
    uint8_t *tmp_id;
Packit Service 084de1
Packit Service 084de1
    switch (type) {
Packit Service 084de1
    case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID:
Packit Service 084de1
        group = EC_GROUP_new_by_curve_name(p1);
Packit Service 084de1
        if (group == NULL) {
Packit Service 084de1
            SM2err(SM2_F_PKEY_SM2_CTRL, SM2_R_INVALID_CURVE);
Packit Service 084de1
            return 0;
Packit Service 084de1
        }
Packit Service 084de1
        EC_GROUP_free(smctx->gen_group);
Packit Service 084de1
        smctx->gen_group = group;
Packit Service 084de1
        return 1;
Packit Service 084de1
Packit Service 084de1
    case EVP_PKEY_CTRL_EC_PARAM_ENC:
Packit Service 084de1
        if (smctx->gen_group == NULL) {
Packit Service 084de1
            SM2err(SM2_F_PKEY_SM2_CTRL, SM2_R_NO_PARAMETERS_SET);
Packit Service 084de1
            return 0;
Packit Service 084de1
        }
Packit Service 084de1
        EC_GROUP_set_asn1_flag(smctx->gen_group, p1);
Packit Service 084de1
        return 1;
Packit Service 084de1
Packit Service 084de1
    case EVP_PKEY_CTRL_MD:
Packit Service 084de1
        smctx->md = p2;
Packit Service 084de1
        return 1;
Packit Service 084de1
Packit Service 084de1
    case EVP_PKEY_CTRL_GET_MD:
Packit Service 084de1
        *(const EVP_MD **)p2 = smctx->md;
Packit Service 084de1
        return 1;
Packit Service 084de1
Packit Service 084de1
    case EVP_PKEY_CTRL_SET1_ID:
Packit Service 084de1
        if (p1 > 0) {
Packit Service 084de1
            tmp_id = OPENSSL_malloc(p1);
Packit Service 084de1
            if (tmp_id == NULL) {
Packit Service 084de1
                SM2err(SM2_F_PKEY_SM2_CTRL, ERR_R_MALLOC_FAILURE);
Packit Service 084de1
                return 0;
Packit Service 084de1
            }
Packit Service 084de1
            memcpy(tmp_id, p2, p1);
Packit Service 084de1
            OPENSSL_free(smctx->id);
Packit Service 084de1
            smctx->id = tmp_id;
Packit Service 084de1
        } else {
Packit Service 084de1
            /* set null-ID */
Packit Service 084de1
            OPENSSL_free(smctx->id);
Packit Service 084de1
            smctx->id = NULL;
Packit Service 084de1
        }
Packit Service 084de1
        smctx->id_len = (size_t)p1;
Packit Service 084de1
        smctx->id_set = 1;
Packit Service 084de1
        return 1;
Packit Service 084de1
Packit Service 084de1
    case EVP_PKEY_CTRL_GET1_ID:
Packit Service 084de1
        memcpy(p2, smctx->id, smctx->id_len);
Packit Service 084de1
        return 1;
Packit Service 084de1
Packit Service 084de1
    case EVP_PKEY_CTRL_GET1_ID_LEN:
Packit Service 084de1
        *(size_t *)p2 = smctx->id_len;
Packit Service 084de1
        return 1;
Packit Service 084de1
Packit Service 084de1
    case EVP_PKEY_CTRL_DIGESTINIT:
Packit Service 084de1
        /* nothing to be inited, this is to suppress the error... */
Packit Service 084de1
        return 1;
Packit Service 084de1
Packit Service 084de1
    default:
Packit Service 084de1
        return -2;
Packit Service 084de1
    }
Packit Service 084de1
}
Packit Service 084de1
Packit Service 084de1
static int pkey_sm2_ctrl_str(EVP_PKEY_CTX *ctx,
Packit Service 084de1
                             const char *type, const char *value)
Packit Service 084de1
{
Packit Service 084de1
    if (strcmp(type, "ec_paramgen_curve") == 0) {
Packit Service 084de1
        int nid = NID_undef;
Packit Service 084de1
Packit Service 084de1
        if (((nid = EC_curve_nist2nid(value)) == NID_undef)
Packit Service 084de1
            && ((nid = OBJ_sn2nid(value)) == NID_undef)
Packit Service 084de1
            && ((nid = OBJ_ln2nid(value)) == NID_undef)) {
Packit Service 084de1
            SM2err(SM2_F_PKEY_SM2_CTRL_STR, SM2_R_INVALID_CURVE);
Packit Service 084de1
            return 0;
Packit Service 084de1
        }
Packit Service 084de1
        return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid);
Packit Service 084de1
    } else if (strcmp(type, "ec_param_enc") == 0) {
Packit Service 084de1
        int param_enc;
Packit Service 084de1
Packit Service 084de1
        if (strcmp(value, "explicit") == 0)
Packit Service 084de1
            param_enc = 0;
Packit Service 084de1
        else if (strcmp(value, "named_curve") == 0)
Packit Service 084de1
            param_enc = OPENSSL_EC_NAMED_CURVE;
Packit Service 084de1
        else
Packit Service 084de1
            return -2;
Packit Service 084de1
        return EVP_PKEY_CTX_set_ec_param_enc(ctx, param_enc);
Packit Service 084de1
    }
Packit Service 084de1
Packit Service 084de1
    return -2;
Packit Service 084de1
}
Packit Service 084de1
Packit Service 084de1
static int pkey_sm2_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
Packit Service 084de1
{
Packit Service 084de1
    uint8_t z[EVP_MAX_MD_SIZE];
Packit Service 084de1
    SM2_PKEY_CTX *smctx = ctx->data;
Packit Service 084de1
    EC_KEY *ec = ctx->pkey->pkey.ec;
Packit Service 084de1
    const EVP_MD *md = EVP_MD_CTX_md(mctx);
Packit Service 084de1
    int mdlen = EVP_MD_size(md);
Packit Service 084de1
Packit Service 084de1
    if (!smctx->id_set) {
Packit Service 084de1
        /*
Packit Service 084de1
         * An ID value must be set. The specifications are not clear whether a
Packit Service 084de1
         * NULL is allowed. We only allow it if set explicitly for maximum
Packit Service 084de1
         * flexibility.
Packit Service 084de1
         */
Packit Service 084de1
        SM2err(SM2_F_PKEY_SM2_DIGEST_CUSTOM, SM2_R_ID_NOT_SET);
Packit Service 084de1
        return 0;
Packit Service 084de1
    }
Packit Service 084de1
Packit Service 084de1
    if (mdlen < 0) {
Packit Service 084de1
        SM2err(SM2_F_PKEY_SM2_DIGEST_CUSTOM, SM2_R_INVALID_DIGEST);
Packit Service 084de1
        return 0;
Packit Service 084de1
    }
Packit Service 084de1
Packit Service 084de1
    /* get hashed prefix 'z' of tbs message */
Packit Service 084de1
    if (!sm2_compute_z_digest(z, md, smctx->id, smctx->id_len, ec))
Packit Service 084de1
        return 0;
Packit Service 084de1
Packit Service 084de1
    return EVP_DigestUpdate(mctx, z, (size_t)mdlen);
Packit Service 084de1
}
Packit Service 084de1
Packit Service 084de1
const EVP_PKEY_METHOD sm2_pkey_meth = {
Packit Service 084de1
    EVP_PKEY_SM2,
Packit Service 084de1
    0,
Packit Service 084de1
    pkey_sm2_init,
Packit Service 084de1
    pkey_sm2_copy,
Packit Service 084de1
    pkey_sm2_cleanup,
Packit Service 084de1
Packit Service 084de1
    0,
Packit Service 084de1
    0,
Packit Service 084de1
Packit Service 084de1
    0,
Packit Service 084de1
    0,
Packit Service 084de1
Packit Service 084de1
    0,
Packit Service 084de1
    pkey_sm2_sign,
Packit Service 084de1
Packit Service 084de1
    0,
Packit Service 084de1
    pkey_sm2_verify,
Packit Service 084de1
Packit Service 084de1
    0, 0,
Packit Service 084de1
Packit Service 084de1
    0, 0, 0, 0,
Packit Service 084de1
Packit Service 084de1
    0,
Packit Service 084de1
    pkey_sm2_encrypt,
Packit Service 084de1
Packit Service 084de1
    0,
Packit Service 084de1
    pkey_sm2_decrypt,
Packit Service 084de1
Packit Service 084de1
    0,
Packit Service 084de1
    0,
Packit Service 084de1
    pkey_sm2_ctrl,
Packit Service 084de1
    pkey_sm2_ctrl_str,
Packit Service 084de1
Packit Service 084de1
    0, 0,
Packit Service 084de1
Packit Service 084de1
    0, 0, 0,
Packit Service 084de1
Packit Service 084de1
    pkey_sm2_digest_custom
Packit Service 084de1
};
Packit Service 084de1
Packit Service 084de1
const EVP_PKEY_METHOD *sm2_pkey_method(void)
Packit Service 084de1
{
Packit Service 084de1
    return &sm2_pkey_meth;
Packit Service 084de1
}