xref: /openbsd-src/lib/libcrypto/sm2/sm2_pmeth.c (revision c9675a23de50ec5aa20be3956f170f2eccffb293)
1*c9675a23Stb /*	$OpenBSD: sm2_pmeth.c,v 1.2 2022/11/26 16:08:54 tb Exp $ */
251892d90Stb /*
351892d90Stb  * Copyright (c) 2017, 2019 Ribose Inc
451892d90Stb  *
551892d90Stb  * Permission to use, copy, modify, and/or distribute this software for any
651892d90Stb  * purpose with or without fee is hereby granted, provided that the above
751892d90Stb  * copyright notice and this permission notice appear in all copies.
851892d90Stb  *
951892d90Stb  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1051892d90Stb  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1151892d90Stb  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1251892d90Stb  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1351892d90Stb  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1451892d90Stb  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1551892d90Stb  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1651892d90Stb  */
1751892d90Stb 
1851892d90Stb #ifndef OPENSSL_NO_SM2
1951892d90Stb 
2051892d90Stb #include <string.h>
2151892d90Stb 
2251892d90Stb #include <openssl/sm2.h>
2351892d90Stb #include <openssl/asn1t.h>
2451892d90Stb #include <openssl/x509.h>
2551892d90Stb #include <openssl/err.h>
2651892d90Stb #include <openssl/evp.h>
2751892d90Stb 
28*c9675a23Stb #include "evp_local.h"
29*c9675a23Stb #include "sm2_local.h"
3051892d90Stb 
3151892d90Stb /* SM2 pkey context structure */
3251892d90Stb 
3351892d90Stb typedef struct {
3451892d90Stb 	/* key and paramgen group */
3551892d90Stb 	EC_GROUP *gen_group;
3651892d90Stb 	/* message  digest */
3751892d90Stb 	const EVP_MD *md;
3851892d90Stb 	EVP_MD_CTX *md_ctx;
3951892d90Stb 	/* personalization string */
4051892d90Stb 	uint8_t* uid;
4151892d90Stb 	size_t uid_len;
4251892d90Stb } SM2_PKEY_CTX;
4351892d90Stb 
4451892d90Stb static int
pkey_sm2_init(EVP_PKEY_CTX * ctx)4551892d90Stb pkey_sm2_init(EVP_PKEY_CTX *ctx)
4651892d90Stb {
4751892d90Stb 	SM2_PKEY_CTX *dctx;
4851892d90Stb 
4951892d90Stb 	if ((dctx = calloc(1, sizeof(*dctx))) == NULL) {
5051892d90Stb 		SM2error(ERR_R_MALLOC_FAILURE);
5151892d90Stb 		return 0;
5251892d90Stb 	}
5351892d90Stb 	ctx->data = dctx;
5451892d90Stb 	return 1;
5551892d90Stb }
5651892d90Stb 
5751892d90Stb static void
pkey_sm2_cleanup(EVP_PKEY_CTX * ctx)5851892d90Stb pkey_sm2_cleanup(EVP_PKEY_CTX *ctx)
5951892d90Stb {
6051892d90Stb 	SM2_PKEY_CTX *dctx = ctx->data;
6151892d90Stb 
6251892d90Stb 	if (ctx == NULL || ctx->data == NULL)
6351892d90Stb 		return;
6451892d90Stb 
6551892d90Stb 	EC_GROUP_free(dctx->gen_group);
6651892d90Stb 	free(dctx->uid);
6751892d90Stb 	free(dctx);
6851892d90Stb 	ctx->data = NULL;
6951892d90Stb }
7051892d90Stb 
7151892d90Stb static int
pkey_sm2_copy(EVP_PKEY_CTX * dst,EVP_PKEY_CTX * src)7251892d90Stb pkey_sm2_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
7351892d90Stb {
7451892d90Stb 	SM2_PKEY_CTX *dctx, *sctx;
7551892d90Stb 
7651892d90Stb 	if (!pkey_sm2_init(dst))
7751892d90Stb 		return 0;
7851892d90Stb 	sctx = src->data;
7951892d90Stb 	dctx = dst->data;
8051892d90Stb 	if (sctx->gen_group) {
8151892d90Stb 		if ((dctx->gen_group = EC_GROUP_dup(sctx->gen_group)) == NULL) {
8251892d90Stb 			SM2error(ERR_R_MALLOC_FAILURE);
8351892d90Stb 			goto err;
8451892d90Stb 		}
8551892d90Stb 	}
8651892d90Stb 
8751892d90Stb 	if (sctx->uid != NULL) {
8851892d90Stb 		if ((dctx->uid = malloc(sctx->uid_len)) == NULL) {
8951892d90Stb 			SM2error(ERR_R_MALLOC_FAILURE);
9051892d90Stb 			goto err;
9151892d90Stb 		}
9251892d90Stb 		memcpy(dctx->uid, sctx->uid, sctx->uid_len);
9351892d90Stb 		dctx->uid_len = sctx->uid_len;
9451892d90Stb 	}
9551892d90Stb 
9651892d90Stb 	dctx->md = sctx->md;
9751892d90Stb 
9851892d90Stb 	if (!EVP_MD_CTX_copy(dctx->md_ctx, sctx->md_ctx))
9951892d90Stb 		goto err;
10051892d90Stb 
10151892d90Stb 	return 1;
10251892d90Stb 
10351892d90Stb  err:
10451892d90Stb 	pkey_sm2_cleanup(dst);
10551892d90Stb 	return 0;
10651892d90Stb }
10751892d90Stb 
10851892d90Stb static int
pkey_sm2_sign(EVP_PKEY_CTX * ctx,unsigned char * sig,size_t * siglen,const unsigned char * tbs,size_t tbslen)10951892d90Stb pkey_sm2_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
11051892d90Stb     const unsigned char *tbs, size_t tbslen)
11151892d90Stb {
11251892d90Stb 	unsigned int sltmp;
11351892d90Stb 	int ret, sig_sz;
11451892d90Stb 
11551892d90Stb 	if ((sig_sz = ECDSA_size(ctx->pkey->pkey.ec)) <= 0)
11651892d90Stb 		return 0;
11751892d90Stb 
11851892d90Stb 	if (sig == NULL) {
11951892d90Stb 		*siglen = sig_sz;
12051892d90Stb 		return 1;
12151892d90Stb 	}
12251892d90Stb 
12351892d90Stb 	if (*siglen < (size_t)sig_sz) {
12451892d90Stb 		SM2error(SM2_R_BUFFER_TOO_SMALL);
12551892d90Stb 		return 0;
12651892d90Stb 	}
12751892d90Stb 
12851892d90Stb 	if ((ret = SM2_sign(tbs, tbslen, sig, &sltmp, ctx->pkey->pkey.ec)) <= 0)
12951892d90Stb 		return ret;
13051892d90Stb 
13151892d90Stb 	*siglen = (size_t)sltmp;
13251892d90Stb 	return 1;
13351892d90Stb }
13451892d90Stb 
13551892d90Stb static int
pkey_sm2_verify(EVP_PKEY_CTX * ctx,const unsigned char * sig,size_t siglen,const unsigned char * tbs,size_t tbslen)13651892d90Stb pkey_sm2_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, size_t siglen,
13751892d90Stb     const unsigned char *tbs, size_t tbslen)
13851892d90Stb {
13951892d90Stb 	return SM2_verify(tbs, tbslen, sig, siglen, ctx->pkey->pkey.ec);
14051892d90Stb }
14151892d90Stb 
14251892d90Stb static int
pkey_sm2_encrypt(EVP_PKEY_CTX * ctx,unsigned char * out,size_t * outlen,const unsigned char * in,size_t inlen)14351892d90Stb pkey_sm2_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
14451892d90Stb     const unsigned char *in, size_t inlen)
14551892d90Stb {
14651892d90Stb 	SM2_PKEY_CTX *dctx = ctx->data;
14751892d90Stb 	const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md;
14851892d90Stb 
14951892d90Stb 	if (out == NULL) {
15051892d90Stb 		if (!SM2_ciphertext_size(ctx->pkey->pkey.ec, md, inlen, outlen))
15151892d90Stb 			return -1;
15251892d90Stb 		else
15351892d90Stb 			return 1;
15451892d90Stb 	}
15551892d90Stb 
15651892d90Stb 	return SM2_encrypt(ctx->pkey->pkey.ec, md, in, inlen, out, outlen);
15751892d90Stb }
15851892d90Stb 
15951892d90Stb static int
pkey_sm2_decrypt(EVP_PKEY_CTX * ctx,unsigned char * out,size_t * outlen,const unsigned char * in,size_t inlen)16051892d90Stb pkey_sm2_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
16151892d90Stb     const unsigned char *in, size_t inlen)
16251892d90Stb {
16351892d90Stb 	SM2_PKEY_CTX *dctx = ctx->data;
16451892d90Stb 	const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md;
16551892d90Stb 
16651892d90Stb 	if (out == NULL) {
16751892d90Stb 		if (!SM2_plaintext_size(ctx->pkey->pkey.ec, md, inlen, outlen))
16851892d90Stb 			return -1;
16951892d90Stb 		else
17051892d90Stb 			return 1;
17151892d90Stb 	}
17251892d90Stb 
17351892d90Stb 	return SM2_decrypt(ctx->pkey->pkey.ec, md, in, inlen, out, outlen);
17451892d90Stb }
17551892d90Stb 
17651892d90Stb static int
pkey_sm2_ctrl(EVP_PKEY_CTX * ctx,int type,int p1,void * p2)17751892d90Stb pkey_sm2_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
17851892d90Stb {
17951892d90Stb 	SM2_PKEY_CTX *dctx = ctx->data;
18051892d90Stb 	EC_GROUP *group = NULL;
18151892d90Stb 
18251892d90Stb 	switch (type) {
18351892d90Stb 	case EVP_PKEY_CTRL_DIGESTINIT:
18451892d90Stb 		dctx->md_ctx = p2;
18551892d90Stb 		return 1;
18651892d90Stb 
18751892d90Stb 	case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID:
18851892d90Stb 		if ((group = EC_GROUP_new_by_curve_name(p1)) == NULL) {
18951892d90Stb 			SM2error(SM2_R_INVALID_CURVE);
19051892d90Stb 			return 0;
19151892d90Stb 		}
19251892d90Stb 		EC_GROUP_free(dctx->gen_group);
19351892d90Stb 		dctx->gen_group = group;
19451892d90Stb 		return 1;
19551892d90Stb 
19651892d90Stb 	case EVP_PKEY_CTRL_SM2_SET_UID:
19751892d90Stb 		if ((p1 < 0) || ((p1 == 0) && (p2 != NULL)))  {
19851892d90Stb 			SM2error(SM2_R_INVALID_ARGUMENT);
19951892d90Stb 			return 0;
20051892d90Stb 		}
20151892d90Stb 		if ((p1 > 0) && (p2 == NULL)) {
20251892d90Stb 			SM2error(ERR_R_PASSED_NULL_PARAMETER);
20351892d90Stb 			return 0;
20451892d90Stb 		}
20551892d90Stb 		free(dctx->uid);
20651892d90Stb 		if (p2 == NULL) {
20751892d90Stb 			dctx->uid = NULL;
20851892d90Stb 			dctx->uid_len = 0;
20951892d90Stb 			return 1;
21051892d90Stb 		}
21151892d90Stb 
21251892d90Stb 		if ((dctx->uid = malloc(p1)) == NULL) {
21351892d90Stb 			SM2error(ERR_R_MALLOC_FAILURE);
21451892d90Stb 			return 1;
21551892d90Stb 		}
21651892d90Stb 		memcpy(dctx->uid, p2, p1);
21751892d90Stb 		dctx->uid_len = p1;
21851892d90Stb 		return 1;
21951892d90Stb 
22051892d90Stb 	case EVP_PKEY_CTRL_SM2_HASH_UID:
22151892d90Stb 	    {
22251892d90Stb 		const EVP_MD* md;
22351892d90Stb 		uint8_t za[EVP_MAX_MD_SIZE] = {0};
22451892d90Stb 		int md_len;
22551892d90Stb 
22651892d90Stb 		if (dctx->uid == NULL) {
22751892d90Stb 			SM2error(SM2_R_INVALID_ARGUMENT);
22851892d90Stb 			return 0;
22951892d90Stb 		}
23051892d90Stb 
23151892d90Stb 		if ((md = EVP_MD_CTX_md(dctx->md_ctx)) == NULL) {
23251892d90Stb 			SM2error(ERR_R_EVP_LIB);
23351892d90Stb 			return 0;
23451892d90Stb 		}
23551892d90Stb 
23651892d90Stb 		if ((md_len = EVP_MD_size(md)) < 0) {
23751892d90Stb 			SM2error(SM2_R_INVALID_DIGEST);
23851892d90Stb 			return 0;
23951892d90Stb 		}
24051892d90Stb 
24151892d90Stb 		if (sm2_compute_userid_digest(za, md, dctx->uid, dctx->uid_len,
24251892d90Stb 		    ctx->pkey->pkey.ec) != 1) {
24351892d90Stb 			SM2error(SM2_R_DIGEST_FAILURE);
24451892d90Stb 			return 0;
24551892d90Stb 		}
24651892d90Stb 		return EVP_DigestUpdate(dctx->md_ctx, za, md_len);
24751892d90Stb 	    }
24851892d90Stb 
24951892d90Stb 	case EVP_PKEY_CTRL_SM2_GET_UID_LEN:
25051892d90Stb 		if (p2 == NULL) {
25151892d90Stb 			SM2error(ERR_R_PASSED_NULL_PARAMETER);
25251892d90Stb 			return 0;
25351892d90Stb 		}
25451892d90Stb 		*(size_t *)p2 = dctx->uid_len;
25551892d90Stb 		return 1;
25651892d90Stb 
25751892d90Stb 	case EVP_PKEY_CTRL_SM2_GET_UID:
25851892d90Stb 		if (p2 == NULL) {
25951892d90Stb 			SM2error(ERR_R_PASSED_NULL_PARAMETER);
26051892d90Stb 			return 0;
26151892d90Stb 		}
26251892d90Stb 		if (dctx->uid_len == 0) {
26351892d90Stb 			return 1;
26451892d90Stb 		}
26551892d90Stb 		memcpy(p2, dctx->uid, dctx->uid_len);
26651892d90Stb 		return 1;
26751892d90Stb 
26851892d90Stb 	case EVP_PKEY_CTRL_MD:
26951892d90Stb 		dctx->md = p2;
27051892d90Stb 		return 1;
27151892d90Stb 
27251892d90Stb 	default:
27351892d90Stb 		return -2;
27451892d90Stb 	}
27551892d90Stb }
27651892d90Stb 
27751892d90Stb static int
pkey_sm2_ctrl_str(EVP_PKEY_CTX * ctx,const char * type,const char * value)27851892d90Stb pkey_sm2_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value)
27951892d90Stb {
28051892d90Stb 	int nid;
28151892d90Stb 
28251892d90Stb 	if (strcmp(type, "ec_paramgen_curve") == 0) {
28351892d90Stb 		if (((nid = EC_curve_nist2nid(value)) == NID_undef) &&
28451892d90Stb 		    ((nid = OBJ_sn2nid(value)) == NID_undef) &&
28551892d90Stb 		    ((nid = OBJ_ln2nid(value)) == NID_undef)) {
28651892d90Stb 			SM2error(SM2_R_INVALID_CURVE);
28751892d90Stb 			return 0;
28851892d90Stb 		}
28951892d90Stb 		return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid);
29051892d90Stb 	} else if (strcmp(type, "sm2_uid") == 0) {
29151892d90Stb 		return EVP_PKEY_CTX_set_sm2_uid(ctx, (void*) value,
29251892d90Stb 		    (int)strlen(value));
29351892d90Stb 	}
29451892d90Stb 
29551892d90Stb 	return -2;
29651892d90Stb }
29751892d90Stb 
29851892d90Stb const EVP_PKEY_METHOD sm2_pkey_meth = {
29951892d90Stb 	.pkey_id = EVP_PKEY_SM2,
30051892d90Stb 	.init = pkey_sm2_init,
30151892d90Stb 	.copy = pkey_sm2_copy,
30251892d90Stb 	.cleanup = pkey_sm2_cleanup,
30351892d90Stb 
30451892d90Stb 	.sign = pkey_sm2_sign,
30551892d90Stb 
30651892d90Stb 	.verify = pkey_sm2_verify,
30751892d90Stb 
30851892d90Stb 	.encrypt = pkey_sm2_encrypt,
30951892d90Stb 
31051892d90Stb 	.decrypt = pkey_sm2_decrypt,
31151892d90Stb 
31251892d90Stb 	.ctrl = pkey_sm2_ctrl,
31351892d90Stb 	.ctrl_str = pkey_sm2_ctrl_str
31451892d90Stb };
31551892d90Stb 
31651892d90Stb #endif /* OPENSSL_NO_SM2 */
317