xref: /openbsd-src/lib/libcrypto/sm2/sm2_pmeth.c (revision c9675a23de50ec5aa20be3956f170f2eccffb293)
1 /*	$OpenBSD: sm2_pmeth.c,v 1.2 2022/11/26 16:08:54 tb Exp $ */
2 /*
3  * Copyright (c) 2017, 2019 Ribose Inc
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #ifndef OPENSSL_NO_SM2
19 
20 #include <string.h>
21 
22 #include <openssl/sm2.h>
23 #include <openssl/asn1t.h>
24 #include <openssl/x509.h>
25 #include <openssl/err.h>
26 #include <openssl/evp.h>
27 
28 #include "evp_local.h"
29 #include "sm2_local.h"
30 
31 /* SM2 pkey context structure */
32 
33 typedef struct {
34 	/* key and paramgen group */
35 	EC_GROUP *gen_group;
36 	/* message  digest */
37 	const EVP_MD *md;
38 	EVP_MD_CTX *md_ctx;
39 	/* personalization string */
40 	uint8_t* uid;
41 	size_t uid_len;
42 } SM2_PKEY_CTX;
43 
44 static int
pkey_sm2_init(EVP_PKEY_CTX * ctx)45 pkey_sm2_init(EVP_PKEY_CTX *ctx)
46 {
47 	SM2_PKEY_CTX *dctx;
48 
49 	if ((dctx = calloc(1, sizeof(*dctx))) == NULL) {
50 		SM2error(ERR_R_MALLOC_FAILURE);
51 		return 0;
52 	}
53 	ctx->data = dctx;
54 	return 1;
55 }
56 
57 static void
pkey_sm2_cleanup(EVP_PKEY_CTX * ctx)58 pkey_sm2_cleanup(EVP_PKEY_CTX *ctx)
59 {
60 	SM2_PKEY_CTX *dctx = ctx->data;
61 
62 	if (ctx == NULL || ctx->data == NULL)
63 		return;
64 
65 	EC_GROUP_free(dctx->gen_group);
66 	free(dctx->uid);
67 	free(dctx);
68 	ctx->data = NULL;
69 }
70 
71 static int
pkey_sm2_copy(EVP_PKEY_CTX * dst,EVP_PKEY_CTX * src)72 pkey_sm2_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
73 {
74 	SM2_PKEY_CTX *dctx, *sctx;
75 
76 	if (!pkey_sm2_init(dst))
77 		return 0;
78 	sctx = src->data;
79 	dctx = dst->data;
80 	if (sctx->gen_group) {
81 		if ((dctx->gen_group = EC_GROUP_dup(sctx->gen_group)) == NULL) {
82 			SM2error(ERR_R_MALLOC_FAILURE);
83 			goto err;
84 		}
85 	}
86 
87 	if (sctx->uid != NULL) {
88 		if ((dctx->uid = malloc(sctx->uid_len)) == NULL) {
89 			SM2error(ERR_R_MALLOC_FAILURE);
90 			goto err;
91 		}
92 		memcpy(dctx->uid, sctx->uid, sctx->uid_len);
93 		dctx->uid_len = sctx->uid_len;
94 	}
95 
96 	dctx->md = sctx->md;
97 
98 	if (!EVP_MD_CTX_copy(dctx->md_ctx, sctx->md_ctx))
99 		goto err;
100 
101 	return 1;
102 
103  err:
104 	pkey_sm2_cleanup(dst);
105 	return 0;
106 }
107 
108 static int
pkey_sm2_sign(EVP_PKEY_CTX * ctx,unsigned char * sig,size_t * siglen,const unsigned char * tbs,size_t tbslen)109 pkey_sm2_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
110     const unsigned char *tbs, size_t tbslen)
111 {
112 	unsigned int sltmp;
113 	int ret, sig_sz;
114 
115 	if ((sig_sz = ECDSA_size(ctx->pkey->pkey.ec)) <= 0)
116 		return 0;
117 
118 	if (sig == NULL) {
119 		*siglen = sig_sz;
120 		return 1;
121 	}
122 
123 	if (*siglen < (size_t)sig_sz) {
124 		SM2error(SM2_R_BUFFER_TOO_SMALL);
125 		return 0;
126 	}
127 
128 	if ((ret = SM2_sign(tbs, tbslen, sig, &sltmp, ctx->pkey->pkey.ec)) <= 0)
129 		return ret;
130 
131 	*siglen = (size_t)sltmp;
132 	return 1;
133 }
134 
135 static int
pkey_sm2_verify(EVP_PKEY_CTX * ctx,const unsigned char * sig,size_t siglen,const unsigned char * tbs,size_t tbslen)136 pkey_sm2_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, size_t siglen,
137     const unsigned char *tbs, size_t tbslen)
138 {
139 	return SM2_verify(tbs, tbslen, sig, siglen, ctx->pkey->pkey.ec);
140 }
141 
142 static int
pkey_sm2_encrypt(EVP_PKEY_CTX * ctx,unsigned char * out,size_t * outlen,const unsigned char * in,size_t inlen)143 pkey_sm2_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
144     const unsigned char *in, size_t inlen)
145 {
146 	SM2_PKEY_CTX *dctx = ctx->data;
147 	const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md;
148 
149 	if (out == NULL) {
150 		if (!SM2_ciphertext_size(ctx->pkey->pkey.ec, md, inlen, outlen))
151 			return -1;
152 		else
153 			return 1;
154 	}
155 
156 	return SM2_encrypt(ctx->pkey->pkey.ec, md, in, inlen, out, outlen);
157 }
158 
159 static int
pkey_sm2_decrypt(EVP_PKEY_CTX * ctx,unsigned char * out,size_t * outlen,const unsigned char * in,size_t inlen)160 pkey_sm2_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
161     const unsigned char *in, size_t inlen)
162 {
163 	SM2_PKEY_CTX *dctx = ctx->data;
164 	const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md;
165 
166 	if (out == NULL) {
167 		if (!SM2_plaintext_size(ctx->pkey->pkey.ec, md, inlen, outlen))
168 			return -1;
169 		else
170 			return 1;
171 	}
172 
173 	return SM2_decrypt(ctx->pkey->pkey.ec, md, in, inlen, out, outlen);
174 }
175 
176 static int
pkey_sm2_ctrl(EVP_PKEY_CTX * ctx,int type,int p1,void * p2)177 pkey_sm2_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
178 {
179 	SM2_PKEY_CTX *dctx = ctx->data;
180 	EC_GROUP *group = NULL;
181 
182 	switch (type) {
183 	case EVP_PKEY_CTRL_DIGESTINIT:
184 		dctx->md_ctx = p2;
185 		return 1;
186 
187 	case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID:
188 		if ((group = EC_GROUP_new_by_curve_name(p1)) == NULL) {
189 			SM2error(SM2_R_INVALID_CURVE);
190 			return 0;
191 		}
192 		EC_GROUP_free(dctx->gen_group);
193 		dctx->gen_group = group;
194 		return 1;
195 
196 	case EVP_PKEY_CTRL_SM2_SET_UID:
197 		if ((p1 < 0) || ((p1 == 0) && (p2 != NULL)))  {
198 			SM2error(SM2_R_INVALID_ARGUMENT);
199 			return 0;
200 		}
201 		if ((p1 > 0) && (p2 == NULL)) {
202 			SM2error(ERR_R_PASSED_NULL_PARAMETER);
203 			return 0;
204 		}
205 		free(dctx->uid);
206 		if (p2 == NULL) {
207 			dctx->uid = NULL;
208 			dctx->uid_len = 0;
209 			return 1;
210 		}
211 
212 		if ((dctx->uid = malloc(p1)) == NULL) {
213 			SM2error(ERR_R_MALLOC_FAILURE);
214 			return 1;
215 		}
216 		memcpy(dctx->uid, p2, p1);
217 		dctx->uid_len = p1;
218 		return 1;
219 
220 	case EVP_PKEY_CTRL_SM2_HASH_UID:
221 	    {
222 		const EVP_MD* md;
223 		uint8_t za[EVP_MAX_MD_SIZE] = {0};
224 		int md_len;
225 
226 		if (dctx->uid == NULL) {
227 			SM2error(SM2_R_INVALID_ARGUMENT);
228 			return 0;
229 		}
230 
231 		if ((md = EVP_MD_CTX_md(dctx->md_ctx)) == NULL) {
232 			SM2error(ERR_R_EVP_LIB);
233 			return 0;
234 		}
235 
236 		if ((md_len = EVP_MD_size(md)) < 0) {
237 			SM2error(SM2_R_INVALID_DIGEST);
238 			return 0;
239 		}
240 
241 		if (sm2_compute_userid_digest(za, md, dctx->uid, dctx->uid_len,
242 		    ctx->pkey->pkey.ec) != 1) {
243 			SM2error(SM2_R_DIGEST_FAILURE);
244 			return 0;
245 		}
246 		return EVP_DigestUpdate(dctx->md_ctx, za, md_len);
247 	    }
248 
249 	case EVP_PKEY_CTRL_SM2_GET_UID_LEN:
250 		if (p2 == NULL) {
251 			SM2error(ERR_R_PASSED_NULL_PARAMETER);
252 			return 0;
253 		}
254 		*(size_t *)p2 = dctx->uid_len;
255 		return 1;
256 
257 	case EVP_PKEY_CTRL_SM2_GET_UID:
258 		if (p2 == NULL) {
259 			SM2error(ERR_R_PASSED_NULL_PARAMETER);
260 			return 0;
261 		}
262 		if (dctx->uid_len == 0) {
263 			return 1;
264 		}
265 		memcpy(p2, dctx->uid, dctx->uid_len);
266 		return 1;
267 
268 	case EVP_PKEY_CTRL_MD:
269 		dctx->md = p2;
270 		return 1;
271 
272 	default:
273 		return -2;
274 	}
275 }
276 
277 static int
pkey_sm2_ctrl_str(EVP_PKEY_CTX * ctx,const char * type,const char * value)278 pkey_sm2_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value)
279 {
280 	int nid;
281 
282 	if (strcmp(type, "ec_paramgen_curve") == 0) {
283 		if (((nid = EC_curve_nist2nid(value)) == NID_undef) &&
284 		    ((nid = OBJ_sn2nid(value)) == NID_undef) &&
285 		    ((nid = OBJ_ln2nid(value)) == NID_undef)) {
286 			SM2error(SM2_R_INVALID_CURVE);
287 			return 0;
288 		}
289 		return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid);
290 	} else if (strcmp(type, "sm2_uid") == 0) {
291 		return EVP_PKEY_CTX_set_sm2_uid(ctx, (void*) value,
292 		    (int)strlen(value));
293 	}
294 
295 	return -2;
296 }
297 
298 const EVP_PKEY_METHOD sm2_pkey_meth = {
299 	.pkey_id = EVP_PKEY_SM2,
300 	.init = pkey_sm2_init,
301 	.copy = pkey_sm2_copy,
302 	.cleanup = pkey_sm2_cleanup,
303 
304 	.sign = pkey_sm2_sign,
305 
306 	.verify = pkey_sm2_verify,
307 
308 	.encrypt = pkey_sm2_encrypt,
309 
310 	.decrypt = pkey_sm2_decrypt,
311 
312 	.ctrl = pkey_sm2_ctrl,
313 	.ctrl_str = pkey_sm2_ctrl_str
314 };
315 
316 #endif /* OPENSSL_NO_SM2 */
317