--- /dev/null
+/* $OpenBSD: sm2.h,v 1.1.1.1 2021/08/18 16:04:32 tb Exp $ */
+/*
+ * Copyright (c) 2017, 2019 Ribose Inc
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HEADER_SM2_H
+#define HEADER_SM2_H
+
+#include <openssl/opensslconf.h>
+
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+
+#ifdef OPENSSL_NO_SM2
+#error SM2 is disabled.
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * SM2 signature generation.
+ */
+int SM2_sign(const unsigned char *dgst, int dgstlen, unsigned char *sig,
+ unsigned int *siglen, EC_KEY *eckey);
+
+/*
+ * SM2 signature verification. Assumes input is an SM3 digest
+ */
+int SM2_verify(const unsigned char *dgst, int dgstlen, const unsigned char *sig,
+ int siglen, EC_KEY *eckey);
+
+/*
+ * SM2 encryption
+ */
+int SM2_ciphertext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len,
+ size_t *c_size);
+
+int SM2_plaintext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len,
+ size_t *pl_size);
+
+int SM2_encrypt(const EC_KEY *key, const EVP_MD *digest, const uint8_t *msg,
+ size_t msg_len, uint8_t *ciphertext_buf, size_t *ciphertext_len);
+
+int SM2_decrypt(const EC_KEY *key, const EVP_MD *digest,
+ const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *ptext_buf,
+ size_t *ptext_len);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_SM2_strings(void);
+
+/* Error codes for the SM2 functions. */
+
+/* Function codes. */
+# define SM2_F_PKEY_SM2_CTRL 274
+# define SM2_F_PKEY_SM2_CTRL_STR 275
+# define SM2_F_PKEY_SM2_KEYGEN 276
+# define SM2_F_PKEY_SM2_PARAMGEN 277
+# define SM2_F_PKEY_SM2_SIGN 278
+# define SM2_F_PKEY_SM2_VERIFY 279
+# define SM2_F_PKEY_SM2_ENCRYPT 280
+# define SM2_F_PKEY_SM2_DECRYPT 281
+
+/* Reason codes. */
+# define SM2_R_ASN1_ERROR 115
+# define SM2_R_ASN5_ERROR 1150
+# define SM2_R_BAD_SIGNATURE 156
+# define SM2_R_BIGNUM_OUT_OF_RANGE 144
+# define SM2_R_BUFFER_TOO_SMALL 100
+# define SM2_R_COORDINATES_OUT_OF_RANGE 146
+# define SM2_R_CURVE_DOES_NOT_SUPPORT_ECDH 160
+# define SM2_R_CURVE_DOES_NOT_SUPPORT_SIGNING 159
+# define SM2_R_D2I_ECPKPARAMETERS_FAILURE 117
+# define SM2_R_DECODE_ERROR 142
+# define SM2_R_DIGEST_FAILURE 163
+# define SM2_R_DISCRIMINANT_IS_ZERO 118
+# define SM2_R_EC_GROUP_NEW_BY_NAME_FAILURE 119
+# define SM2_R_FIELD_TOO_LARGE 143
+# define SM2_R_GF2M_NOT_SUPPORTED 147
+# define SM2_R_GROUP2PKPARAMETERS_FAILURE 120
+# define SM2_R_I2D_ECPKPARAMETERS_FAILURE 121
+# define SM2_R_INCOMPATIBLE_OBJECTS 101
+# define SM2_R_INVALID_ARGUMENT 112
+# define SM2_R_INVALID_COMPRESSED_POINT 110
+# define SM2_R_INVALID_COMPRESSION_BIT 109
+# define SM2_R_INVALID_CURVE 141
+# define SM2_R_INVALID_DIGEST 151
+# define SM2_R_INVALID_DIGEST_TYPE 138
+# define SM2_R_INVALID_ENCODING 102
+# define SM2_R_INVALID_FIELD 103
+# define SM2_R_INVALID_FORM 104
+# define SM2_R_INVALID_GROUP_ORDER 122
+# define SM2_R_INVALID_KEY 116
+# define SM2_R_INVALID_OUTPUT_LENGTH 161
+# define SM2_R_INVALID_PEER_KEY 133
+# define SM2_R_INVALID_PENTANOMIAL_BASIS 132
+# define SM2_R_INVALID_PRIVATE_KEY 123
+# define SM2_R_INVALID_TRINOMIAL_BASIS 137
+# define SM2_R_KDF_FAILURE 162
+# define SM2_R_KDF_PARAMETER_ERROR 148
+# define SM2_R_KEYS_NOT_SET 140
+# define SM2_R_MISSING_PARAMETERS 124
+# define SM2_R_MISSING_PRIVATE_KEY 125
+# define SM2_R_NEED_NEW_SETUP_VALUES 157
+# define SM2_R_NOT_A_NIST_PRIME 135
+# define SM2_R_NOT_IMPLEMENTED 126
+# define SM2_R_NOT_INITIALIZED 111
+# define SM2_R_NO_PARAMETERS_SET 139
+# define SM2_R_NO_PRIVATE_VALUE 154
+# define SM2_R_OPERATION_NOT_SUPPORTED 152
+# define SM2_R_PASSED_NULL_PARAMETER 134
+# define SM2_R_PEER_KEY_ERROR 149
+# define SM2_R_PKPARAMETERS2GROUP_FAILURE 127
+# define SM2_R_POINT_ARITHMETIC_FAILURE 155
+# define SM2_R_POINT_AT_INFINITY 106
+# define SM2_R_POINT_IS_NOT_ON_CURVE 107
+# define SM2_R_RANDOM_NUMBER_GENERATION_FAILED 158
+# define SM2_R_SHARED_INFO_ERROR 150
+# define SM2_R_SLOT_FULL 108
+# define SM2_R_UNDEFINED_GENERATOR 113
+# define SM2_R_UNDEFINED_ORDER 128
+# define SM2_R_UNKNOWN_GROUP 129
+# define SM2_R_UNKNOWN_ORDER 114
+# define SM2_R_UNSUPPORTED_FIELD 131
+# define SM2_R_WRONG_CURVE_PARAMETERS 145
+# define SM2_R_WRONG_ORDER 130
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null
+/* $OpenBSD: sm2_crypt.c,v 1.1.1.1 2021/08/18 16:04:32 tb Exp $ */
+/*
+ * Copyright (c) 2017, 2019 Ribose Inc
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef OPENSSL_NO_SM2
+
+#include <string.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/sm2.h>
+
+#include "sm2_locl.h"
+
+typedef struct SM2_Ciphertext_st SM2_Ciphertext;
+
+SM2_Ciphertext *SM2_Ciphertext_new(void);
+void SM2_Ciphertext_free(SM2_Ciphertext *a);
+SM2_Ciphertext *d2i_SM2_Ciphertext(SM2_Ciphertext **a, const unsigned char **in,
+ long len);
+int i2d_SM2_Ciphertext(SM2_Ciphertext *a, unsigned char **out);
+
+struct SM2_Ciphertext_st {
+ BIGNUM *C1x;
+ BIGNUM *C1y;
+ ASN1_OCTET_STRING *C3;
+ ASN1_OCTET_STRING *C2;
+};
+
+static const ASN1_TEMPLATE SM2_Ciphertext_seq_tt[] = {
+ {
+ .flags = 0,
+ .tag = 0,
+ .offset = offsetof(SM2_Ciphertext, C1x),
+ .field_name = "C1x",
+ .item = &BIGNUM_it,
+ },
+ {
+ .flags = 0,
+ .tag = 0,
+ .offset = offsetof(SM2_Ciphertext, C1y),
+ .field_name = "C1y",
+ .item = &BIGNUM_it,
+ },
+ {
+ .flags = 0,
+ .tag = 0,
+ .offset = offsetof(SM2_Ciphertext, C3),
+ .field_name = "C3",
+ .item = &ASN1_OCTET_STRING_it,
+ },
+ {
+ .flags = 0,
+ .tag = 0,
+ .offset = offsetof(SM2_Ciphertext, C2),
+ .field_name = "C2",
+ .item = &ASN1_OCTET_STRING_it,
+ },
+};
+
+const ASN1_ITEM SM2_Ciphertext_it = {
+ .itype = ASN1_ITYPE_SEQUENCE,
+ .utype = V_ASN1_SEQUENCE,
+ .templates = SM2_Ciphertext_seq_tt,
+ .tcount = sizeof(SM2_Ciphertext_seq_tt) / sizeof(ASN1_TEMPLATE),
+ .funcs = NULL,
+ .size = sizeof(SM2_Ciphertext),
+ .sname = "SM2_Ciphertext",
+};
+
+SM2_Ciphertext *
+d2i_SM2_Ciphertext(SM2_Ciphertext **a, const unsigned char **in, long len)
+{
+ return (SM2_Ciphertext *) ASN1_item_d2i((ASN1_VALUE **)a, in, len,
+ &SM2_Ciphertext_it);
+}
+
+int
+i2d_SM2_Ciphertext(SM2_Ciphertext *a, unsigned char **out)
+{
+ return ASN1_item_i2d((ASN1_VALUE *)a, out, &SM2_Ciphertext_it);
+}
+
+SM2_Ciphertext *
+SM2_Ciphertext_new(void)
+{
+ return (SM2_Ciphertext *)ASN1_item_new(&SM2_Ciphertext_it);
+}
+
+void
+SM2_Ciphertext_free(SM2_Ciphertext *a)
+{
+ ASN1_item_free((ASN1_VALUE *)a, &SM2_Ciphertext_it);
+}
+
+static size_t
+ec_field_size(const EC_GROUP *group)
+{
+ /* Is there some simpler way to do this? */
+ BIGNUM *p;
+ size_t field_size = 0;
+
+ if ((p = BN_new()) == NULL)
+ goto err;
+ if (!EC_GROUP_get_curve(group, p, NULL, NULL, NULL))
+ goto err;
+ field_size = BN_num_bytes(p);
+ err:
+ BN_free(p);
+ return field_size;
+}
+
+int
+SM2_plaintext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len,
+ size_t *pl_size)
+{
+ size_t field_size, overhead;
+ int md_size;
+
+ if ((field_size = ec_field_size(EC_KEY_get0_group(key))) == 0) {
+ SM2error(SM2_R_INVALID_FIELD);
+ return 0;
+ }
+
+ if ((md_size = EVP_MD_size(digest)) < 0) {
+ SM2error(SM2_R_INVALID_DIGEST);
+ return 0;
+ }
+
+ overhead = 10 + 2 * field_size + md_size;
+ if (msg_len <= overhead) {
+ SM2error(SM2_R_INVALID_ARGUMENT);
+ return 0;
+ }
+
+ *pl_size = msg_len - overhead;
+ return 1;
+}
+
+int
+SM2_ciphertext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len,
+ size_t *c_size)
+{
+ size_t asn_size, field_size;
+ int md_size;
+
+ if ((field_size = ec_field_size(EC_KEY_get0_group(key))) == 0) {
+ SM2error(SM2_R_INVALID_FIELD);
+ return 0;
+ }
+
+ if ((md_size = EVP_MD_size(digest)) < 0) {
+ SM2error(SM2_R_INVALID_DIGEST);
+ return 0;
+ }
+
+ asn_size = 2 * ASN1_object_size(0, field_size + 1, V_ASN1_INTEGER) +
+ ASN1_object_size(0, md_size, V_ASN1_OCTET_STRING) +
+ ASN1_object_size(0, msg_len, V_ASN1_OCTET_STRING);
+
+ *c_size = ASN1_object_size(1, asn_size, V_ASN1_SEQUENCE);
+ return 1;
+}
+
+int
+sm2_kdf(uint8_t *key, size_t key_len, uint8_t *secret, size_t secret_len,
+ const EVP_MD *digest)
+{
+ EVP_MD_CTX *hash;
+ uint8_t *hash_buf = NULL;
+ uint32_t ctr = 1;
+ uint8_t ctr_buf[4] = {0};
+ size_t hadd, hlen;
+ int rc = 0;
+
+ if ((hash = EVP_MD_CTX_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if ((hlen = EVP_MD_size(digest)) < 0) {
+ SM2error(SM2_R_INVALID_DIGEST);
+ goto err;
+ }
+ if ((hash_buf = malloc(hlen)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ EVP_MD_CTX_init(hash);
+ while ((key_len > 0) && (ctr != 0)) {
+ if (!EVP_DigestInit_ex(hash, digest, NULL)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+ if (!EVP_DigestUpdate(hash, secret, secret_len)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ /* big-endian counter representation */
+ ctr_buf[0] = (ctr >> 24) & 0xff;
+ ctr_buf[1] = (ctr >> 16) & 0xff;
+ ctr_buf[2] = (ctr >> 8) & 0xff;
+ ctr_buf[3] = ctr & 0xff;
+ ctr++;
+
+ if (!EVP_DigestUpdate(hash, ctr_buf, 4)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+ if (!EVP_DigestFinal(hash, hash_buf, NULL)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ hadd = key_len > hlen ? hlen : key_len;
+ memcpy(key, hash_buf, hadd);
+ memset(hash_buf, 0, hlen);
+ key_len -= hadd;
+ key += hadd;
+ }
+
+ rc = 1;
+ err:
+ free(hash_buf);
+ EVP_MD_CTX_free(hash);
+ return rc;
+}
+
+int
+SM2_encrypt(const EC_KEY *key, const EVP_MD *digest, const uint8_t *msg,
+ size_t msg_len, uint8_t *ciphertext_buf, size_t *ciphertext_len)
+{
+ SM2_Ciphertext ctext_struct;
+ EVP_MD_CTX *hash = NULL;
+ BN_CTX *ctx = NULL;
+ BIGNUM *order = NULL;
+ BIGNUM *k, *x1, *y1, *x2, *y2;
+ const EC_GROUP *group;
+ const EC_POINT *P;
+ EC_POINT *kG = NULL, *kP = NULL;
+ uint8_t *msg_mask = NULL, *x2y2 = NULL, *C3 = NULL;
+ size_t C3_size, field_size, i, x2size, y2size;
+ int rc = 0;
+ int clen;
+
+ ctext_struct.C2 = NULL;
+ ctext_struct.C3 = NULL;
+
+ if ((hash = EVP_MD_CTX_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if ((group = EC_KEY_get0_group(key)) == NULL) {
+ SM2error(SM2_R_INVALID_KEY);
+ goto err;
+ }
+
+ if ((order = BN_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!EC_GROUP_get_order(group, order, NULL)) {
+ SM2error(SM2_R_INVALID_GROUP_ORDER);
+ goto err;
+ }
+
+ if ((P = EC_KEY_get0_public_key(key)) == NULL) {
+ SM2error(SM2_R_INVALID_KEY);
+ goto err;
+ }
+
+ if ((field_size = ec_field_size(group)) == 0) {
+ SM2error(SM2_R_INVALID_FIELD);
+ goto err;
+ }
+
+ if ((C3_size = EVP_MD_size(digest)) < 0) {
+ SM2error(SM2_R_INVALID_DIGEST);
+ goto err;
+ }
+
+ if ((kG = EC_POINT_new(group)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if ((kP = EC_POINT_new(group)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if ((ctx = BN_CTX_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ BN_CTX_start(ctx);
+ if ((k = BN_CTX_get(ctx)) == NULL) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+ if ((x1 = BN_CTX_get(ctx)) == NULL) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+ if ((x2 = BN_CTX_get(ctx)) == NULL) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+ if ((y1 = BN_CTX_get(ctx)) == NULL) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+ if ((y2 = BN_CTX_get(ctx)) == NULL) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+
+ if ((x2y2 = calloc(2, field_size)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if ((C3 = calloc(1, C3_size)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ memset(ciphertext_buf, 0, *ciphertext_len);
+
+ if (!BN_rand_range(k, order)) {
+ SM2error(SM2_R_RANDOM_NUMBER_GENERATION_FAILED);
+ goto err;
+ }
+
+ if (!EC_POINT_mul(group, kG, k, NULL, NULL, ctx)) {
+ SM2error(ERR_R_EC_LIB);
+ goto err;
+ }
+
+ if (!EC_POINT_get_affine_coordinates(group, kG, x1, y1, ctx)) {
+ SM2error(ERR_R_EC_LIB);
+ goto err;
+ }
+
+ if (!EC_POINT_mul(group, kP, NULL, P, k, ctx)) {
+ SM2error(ERR_R_EC_LIB);
+ goto err;
+ }
+
+ if (!EC_POINT_get_affine_coordinates(group, kP, x2, y2, ctx)) {
+ SM2error(ERR_R_EC_LIB);
+ goto err;
+ }
+
+ if ((x2size = BN_num_bytes(x2)) > field_size ||
+ (y2size = BN_num_bytes(y2)) > field_size) {
+ SM2error(SM2_R_BIGNUM_OUT_OF_RANGE);
+ goto err;
+ }
+
+ BN_bn2bin(x2, x2y2 + field_size - x2size);
+ BN_bn2bin(y2, x2y2 + 2 * field_size - y2size);
+
+ if ((msg_mask = calloc(1, msg_len)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!sm2_kdf(msg_mask, msg_len, x2y2, 2 * field_size, digest)) {
+ SM2error(SM2_R_KDF_FAILURE);
+ goto err;
+ }
+
+ for (i = 0; i != msg_len; i++)
+ msg_mask[i] ^= msg[i];
+
+ if (!EVP_DigestInit(hash, digest)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ if (!EVP_DigestUpdate(hash, x2y2, field_size)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ if (!EVP_DigestUpdate(hash, msg, msg_len)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ if (!EVP_DigestUpdate(hash, x2y2 + field_size, field_size)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ if (!EVP_DigestFinal(hash, C3, NULL)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ ctext_struct.C1x = x1;
+ ctext_struct.C1y = y1;
+ if ((ctext_struct.C3 = ASN1_OCTET_STRING_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if ((ctext_struct.C2 = ASN1_OCTET_STRING_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (!ASN1_OCTET_STRING_set(ctext_struct.C3, C3, C3_size)) {
+ SM2error(ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ if (!ASN1_OCTET_STRING_set(ctext_struct.C2, msg_mask, msg_len)) {
+ SM2error(ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if ((clen = i2d_SM2_Ciphertext(&ctext_struct, &ciphertext_buf)) < 0) {
+ SM2error(ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ *ciphertext_len = clen;
+ rc = 1;
+
+ err:
+ ASN1_OCTET_STRING_free(ctext_struct.C2);
+ ASN1_OCTET_STRING_free(ctext_struct.C3);
+ free(msg_mask);
+ free(x2y2);
+ free(C3);
+ EVP_MD_CTX_free(hash);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ EC_POINT_free(kG);
+ EC_POINT_free(kP);
+ BN_free(order);
+ return rc;
+}
+
+int
+SM2_decrypt(const EC_KEY *key, const EVP_MD *digest, const uint8_t *ciphertext,
+ size_t ciphertext_len, uint8_t *ptext_buf, size_t *ptext_len)
+{
+ SM2_Ciphertext *sm2_ctext = NULL;
+ EVP_MD_CTX *hash = NULL;
+ BN_CTX *ctx = NULL;
+ BIGNUM *x2, *y2;
+ const EC_GROUP *group;
+ EC_POINT *C1 = NULL;
+ const uint8_t *C2, *C3;
+ uint8_t *computed_C3 = NULL, *msg_mask = NULL, *x2y2 = NULL;
+ size_t field_size, x2size, y2size;
+ int msg_len = 0, rc = 0;
+ int hash_size, i;
+
+ if ((group = EC_KEY_get0_group(key)) == NULL) {
+ SM2error(SM2_R_INVALID_KEY);
+ goto err;
+ }
+
+ if ((field_size = ec_field_size(group)) == 0) {
+ SM2error(SM2_R_INVALID_FIELD);
+ goto err;
+ }
+
+ if ((hash_size = EVP_MD_size(digest)) < 0) {
+ SM2error(SM2_R_INVALID_DIGEST);
+ goto err;
+ }
+
+ memset(ptext_buf, 0xFF, *ptext_len);
+
+ if ((sm2_ctext = d2i_SM2_Ciphertext(NULL, &ciphertext,
+ ciphertext_len)) == NULL) {
+ SM2error(SM2_R_ASN1_ERROR);
+ goto err;
+ }
+
+ if (sm2_ctext->C3->length != hash_size) {
+ SM2error(SM2_R_INVALID_ENCODING);
+ goto err;
+ }
+
+ C2 = sm2_ctext->C2->data;
+ C3 = sm2_ctext->C3->data;
+ msg_len = sm2_ctext->C2->length;
+
+ if ((ctx = BN_CTX_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ BN_CTX_start(ctx);
+ if ((x2 = BN_CTX_get(ctx)) == NULL) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+ if ((y2 = BN_CTX_get(ctx)) == NULL) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+
+ if ((msg_mask = calloc(1, msg_len)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if ((x2y2 = calloc(2, field_size)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if ((computed_C3 = calloc(1, hash_size)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if ((C1 = EC_POINT_new(group)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!EC_POINT_set_affine_coordinates(group, C1, sm2_ctext->C1x,
+ sm2_ctext->C1y, ctx))
+ {
+ SM2error(ERR_R_EC_LIB);
+ goto err;
+ }
+
+ if (!EC_POINT_mul(group, C1, NULL, C1, EC_KEY_get0_private_key(key),
+ ctx)) {
+ SM2error(ERR_R_EC_LIB);
+ goto err;
+ }
+
+ if (!EC_POINT_get_affine_coordinates(group, C1, x2, y2, ctx)) {
+ SM2error(ERR_R_EC_LIB);
+ goto err;
+ }
+
+ if ((x2size = BN_num_bytes(x2)) > field_size ||
+ (y2size = BN_num_bytes(y2)) > field_size) {
+ SM2error(SM2_R_BIGNUM_OUT_OF_RANGE);
+ goto err;
+ }
+
+ BN_bn2bin(x2, x2y2 + field_size - x2size);
+ BN_bn2bin(y2, x2y2 + 2 * field_size - y2size);
+
+ if (!sm2_kdf(msg_mask, msg_len, x2y2, 2 * field_size, digest)) {
+ SM2error(SM2_R_KDF_FAILURE);
+ goto err;
+ }
+
+ for (i = 0; i != msg_len; ++i)
+ ptext_buf[i] = C2[i] ^ msg_mask[i];
+
+ if ((hash = EVP_MD_CTX_new()) == NULL) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ if (!EVP_DigestInit(hash, digest)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ if (!EVP_DigestUpdate(hash, x2y2, field_size)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ if (!EVP_DigestUpdate(hash, ptext_buf, msg_len)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ if (!EVP_DigestUpdate(hash, x2y2 + field_size, field_size)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ if (!EVP_DigestFinal(hash, computed_C3, NULL)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ if (memcmp(computed_C3, C3, hash_size) != 0)
+ goto err;
+
+ rc = 1;
+ *ptext_len = msg_len;
+
+ err:
+ if (rc == 0)
+ memset(ptext_buf, 0, *ptext_len);
+
+ free(msg_mask);
+ free(x2y2);
+ free(computed_C3);
+ EC_POINT_free(C1);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ SM2_Ciphertext_free(sm2_ctext);
+ EVP_MD_CTX_free(hash);
+
+ return rc;
+}
+
+#endif /* OPENSSL_NO_SM2 */
--- /dev/null
+/* $OpenBSD: sm2_err.c,v 1.1.1.1 2021/08/18 16:04:32 tb Exp $ */
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2017 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
+ */
+
+#ifndef OPENSSL_NO_SM2
+
+#include <openssl/err.h>
+#include <openssl/sm2.h>
+
+#ifndef OPENSSL_NO_ERR
+
+#define ERR_FUNC(func) ERR_PACK(ERR_LIB_SM2,func,0)
+#define ERR_REASON(reason) ERR_PACK(ERR_LIB_SM2,0,reason)
+
+static ERR_STRING_DATA SM2_str_functs[] = {
+ {ERR_FUNC(0xfff), "CRYPTO_internal"},
+ {0, NULL}
+};
+
+static ERR_STRING_DATA SM2_str_reasons[] = {
+ {ERR_REASON(SM2_R_ASN1_ERROR), "asn1 error"},
+ {ERR_REASON(SM2_R_ASN5_ERROR), "asn5 error"},
+ {ERR_REASON(SM2_R_BAD_SIGNATURE), "bad signature"},
+ {ERR_REASON(SM2_R_BIGNUM_OUT_OF_RANGE), "bignum out of range"},
+ {ERR_REASON(SM2_R_BUFFER_TOO_SMALL), "buffer too small"},
+ {ERR_REASON(SM2_R_COORDINATES_OUT_OF_RANGE), "coordinates out of range"},
+ {ERR_REASON(SM2_R_CURVE_DOES_NOT_SUPPORT_ECDH), "curve does not support ecdh"},
+ {ERR_REASON(SM2_R_CURVE_DOES_NOT_SUPPORT_SIGNING), "curve does not support signing"},
+ {ERR_REASON(SM2_R_D2I_ECPKPARAMETERS_FAILURE), "d2i ecpkparameters failure"},
+ {ERR_REASON(SM2_R_DECODE_ERROR), "decode error"},
+ {ERR_REASON(SM2_R_DIGEST_FAILURE), "digest calculation failure"},
+ {ERR_REASON(SM2_R_DISCRIMINANT_IS_ZERO), "discriminant is zero"},
+ {ERR_REASON(SM2_R_EC_GROUP_NEW_BY_NAME_FAILURE), "ec group new by name failure"},
+ {ERR_REASON(SM2_R_FIELD_TOO_LARGE), "field too large"},
+ {ERR_REASON(SM2_R_GF2M_NOT_SUPPORTED), "gf2m not supported"},
+ {ERR_REASON(SM2_R_GROUP2PKPARAMETERS_FAILURE), "group2pkparameters failure"},
+ {ERR_REASON(SM2_R_I2D_ECPKPARAMETERS_FAILURE), "i2d ecpkparameters failure"},
+ {ERR_REASON(SM2_R_INCOMPATIBLE_OBJECTS), "incompatible objects"},
+ {ERR_REASON(SM2_R_INVALID_ARGUMENT), "invalid argument"},
+ {ERR_REASON(SM2_R_INVALID_COMPRESSED_POINT), "invalid compressed point"},
+ {ERR_REASON(SM2_R_INVALID_COMPRESSION_BIT), "invalid compression bit"},
+ {ERR_REASON(SM2_R_INVALID_CURVE), "invalid curve"},
+ {ERR_REASON(SM2_R_INVALID_DIGEST), "invalid digest"},
+ {ERR_REASON(SM2_R_INVALID_DIGEST_TYPE), "invalid digest type"},
+ {ERR_REASON(SM2_R_INVALID_ENCODING), "invalid encoding"},
+ {ERR_REASON(SM2_R_INVALID_FIELD), "invalid field"},
+ {ERR_REASON(SM2_R_INVALID_FORM), "invalid form"},
+ {ERR_REASON(SM2_R_INVALID_GROUP_ORDER), "invalid group order"},
+ {ERR_REASON(SM2_R_INVALID_KEY), "invalid key"},
+ {ERR_REASON(SM2_R_INVALID_OUTPUT_LENGTH), "invalid output length"},
+ {ERR_REASON(SM2_R_INVALID_PEER_KEY), "invalid peer key"},
+ {ERR_REASON(SM2_R_INVALID_PENTANOMIAL_BASIS), "invalid pentanomial basis"},
+ {ERR_REASON(SM2_R_INVALID_PRIVATE_KEY), "invalid private key"},
+ {ERR_REASON(SM2_R_INVALID_TRINOMIAL_BASIS), "invalid trinomial basis"},
+ {ERR_REASON(SM2_R_KDF_FAILURE), "kdf calculation failure"},
+ {ERR_REASON(SM2_R_KDF_PARAMETER_ERROR), "kdf parameter error"},
+ {ERR_REASON(SM2_R_KEYS_NOT_SET), "keys not set"},
+ {ERR_REASON(SM2_R_MISSING_PARAMETERS), "missing parameters"},
+ {ERR_REASON(SM2_R_MISSING_PRIVATE_KEY), "missing private key"},
+ {ERR_REASON(SM2_R_NEED_NEW_SETUP_VALUES), "need new setup values"},
+ {ERR_REASON(SM2_R_NOT_A_NIST_PRIME), "not a NIST prime"},
+ {ERR_REASON(SM2_R_NOT_IMPLEMENTED), "not implemented"},
+ {ERR_REASON(SM2_R_NOT_INITIALIZED), "not initialized"},
+ {ERR_REASON(SM2_R_NO_PARAMETERS_SET), "no parameters set"},
+ {ERR_REASON(SM2_R_NO_PRIVATE_VALUE), "no private value"},
+ {ERR_REASON(SM2_R_OPERATION_NOT_SUPPORTED), "operation not supported"},
+ {ERR_REASON(SM2_R_PASSED_NULL_PARAMETER), "passed null parameter"},
+ {ERR_REASON(SM2_R_PEER_KEY_ERROR), "peer key error"},
+ {ERR_REASON(SM2_R_PKPARAMETERS2GROUP_FAILURE), "pkparameters2group failure"},
+ {ERR_REASON(SM2_R_POINT_ARITHMETIC_FAILURE), "point arithmetic failure"},
+ {ERR_REASON(SM2_R_POINT_AT_INFINITY), "point at infinity"},
+ {ERR_REASON(SM2_R_POINT_IS_NOT_ON_CURVE), "point is not on curve"},
+ {ERR_REASON(SM2_R_RANDOM_NUMBER_GENERATION_FAILED), "random number generation failed"},
+ {ERR_REASON(SM2_R_SHARED_INFO_ERROR), "shared info error"},
+ {ERR_REASON(SM2_R_SLOT_FULL), "slot full"},
+ {ERR_REASON(SM2_R_UNDEFINED_GENERATOR), "undefined generator"},
+ {ERR_REASON(SM2_R_UNDEFINED_ORDER), "undefined order"},
+ {ERR_REASON(SM2_R_UNKNOWN_GROUP), "unknown group"},
+ {ERR_REASON(SM2_R_UNKNOWN_ORDER), "unknown order"},
+ {ERR_REASON(SM2_R_UNSUPPORTED_FIELD), "unsupported field"},
+ {ERR_REASON(SM2_R_WRONG_CURVE_PARAMETERS), "wrong curve parameters"},
+ {ERR_REASON(SM2_R_WRONG_ORDER), "wrong order"},
+ {0, NULL}
+};
+
+#endif
+
+void
+ERR_load_SM2_strings(void)
+{
+#ifndef OPENSSL_NO_ERR
+ if (ERR_func_error_string(SM2_str_functs[0].error) == NULL) {
+ ERR_load_strings(0, SM2_str_functs);
+ ERR_load_strings(0, SM2_str_reasons);
+ }
+#endif
+}
+
+#endif /* OPENSSL_NO_SM2 */
--- /dev/null
+/* $OpenBSD: sm2_locl.h,v 1.1.1.1 2021/08/18 16:04:32 tb Exp $ */
+/*
+ * Copyright (c) 2017, 2019 Ribose Inc
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HEADER_SM2_LOCL_H
+#define HEADER_SM2_LOCL_H
+
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+
+__BEGIN_HIDDEN_DECLS
+
+int sm2_compute_userid_digest(uint8_t *out, const EVP_MD *digest,
+ const uint8_t *uid, size_t uid_len, const EC_KEY *key);
+
+/*
+ * SM2 signature operation. Computes ZA (user id digest) and then signs
+ * H(ZA || msg) using SM2
+ */
+ECDSA_SIG *sm2_do_sign(const EC_KEY *key, const EVP_MD *digest,
+ const uint8_t *uid, size_t uid_len, const uint8_t *msg, size_t msg_len);
+
+int sm2_do_verify(const EC_KEY *key, const EVP_MD *digest,
+ const ECDSA_SIG *signature, const uint8_t *uid, size_t uid_len,
+ const uint8_t *msg, size_t msg_len);
+
+__END_HIDDEN_DECLS
+
+#endif
+
--- /dev/null
+/* $OpenBSD: sm2_pmeth.c,v 1.1.1.1 2021/08/18 16:04:32 tb Exp $ */
+/*
+ * Copyright (c) 2017, 2019 Ribose Inc
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef OPENSSL_NO_SM2
+
+#include <string.h>
+
+#include <openssl/sm2.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+
+#include "evp_locl.h"
+#include "sm2_locl.h"
+
+/* SM2 pkey context structure */
+
+typedef struct {
+ /* key and paramgen group */
+ EC_GROUP *gen_group;
+ /* message digest */
+ const EVP_MD *md;
+ EVP_MD_CTX *md_ctx;
+ /* personalization string */
+ uint8_t* uid;
+ size_t uid_len;
+} SM2_PKEY_CTX;
+
+static int
+pkey_sm2_init(EVP_PKEY_CTX *ctx)
+{
+ SM2_PKEY_CTX *dctx;
+
+ if ((dctx = calloc(1, sizeof(*dctx))) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ ctx->data = dctx;
+ return 1;
+}
+
+static void
+pkey_sm2_cleanup(EVP_PKEY_CTX *ctx)
+{
+ SM2_PKEY_CTX *dctx = ctx->data;
+
+ if (ctx == NULL || ctx->data == NULL)
+ return;
+
+ EC_GROUP_free(dctx->gen_group);
+ free(dctx->uid);
+ free(dctx);
+ 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) {
+ if ((dctx->gen_group = EC_GROUP_dup(sctx->gen_group)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ if (sctx->uid != NULL) {
+ if ((dctx->uid = malloc(sctx->uid_len)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ memcpy(dctx->uid, sctx->uid, sctx->uid_len);
+ dctx->uid_len = sctx->uid_len;
+ }
+
+ dctx->md = sctx->md;
+
+ if (!EVP_MD_CTX_copy(dctx->md_ctx, sctx->md_ctx))
+ goto err;
+
+ return 1;
+
+ err:
+ pkey_sm2_cleanup(dst);
+ return 0;
+}
+
+static int
+pkey_sm2_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
+ const unsigned char *tbs, size_t tbslen)
+{
+ unsigned int sltmp;
+ int ret, sig_sz;
+
+ if ((sig_sz = ECDSA_size(ctx->pkey->pkey.ec)) <= 0)
+ return 0;
+
+ if (sig == NULL) {
+ *siglen = sig_sz;
+ return 1;
+ }
+
+ if (*siglen < (size_t)sig_sz) {
+ SM2error(SM2_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+
+ if ((ret = SM2_sign(tbs, tbslen, sig, &sltmp, ctx->pkey->pkey.ec)) <= 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)
+{
+ return SM2_verify(tbs, tbslen, sig, siglen, ctx->pkey->pkey.ec);
+}
+
+static int
+pkey_sm2_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
+ const unsigned char *in, size_t inlen)
+{
+ SM2_PKEY_CTX *dctx = ctx->data;
+ const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md;
+
+ if (out == NULL) {
+ if (!SM2_ciphertext_size(ctx->pkey->pkey.ec, md, inlen, outlen))
+ return -1;
+ else
+ return 1;
+ }
+
+ return SM2_encrypt(ctx->pkey->pkey.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)
+{
+ SM2_PKEY_CTX *dctx = ctx->data;
+ const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md;
+
+ if (out == NULL) {
+ if (!SM2_plaintext_size(ctx->pkey->pkey.ec, md, inlen, outlen))
+ return -1;
+ else
+ return 1;
+ }
+
+ return SM2_decrypt(ctx->pkey->pkey.ec, md, in, inlen, out, outlen);
+}
+
+static int
+pkey_sm2_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
+{
+ SM2_PKEY_CTX *dctx = ctx->data;
+ EC_GROUP *group = NULL;
+
+ switch (type) {
+ case EVP_PKEY_CTRL_DIGESTINIT:
+ dctx->md_ctx = p2;
+ return 1;
+
+ case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID:
+ if ((group = EC_GROUP_new_by_curve_name(p1)) == NULL) {
+ SM2error(SM2_R_INVALID_CURVE);
+ return 0;
+ }
+ EC_GROUP_free(dctx->gen_group);
+ dctx->gen_group = group;
+ return 1;
+
+ case EVP_PKEY_CTRL_SM2_SET_UID:
+ if ((p1 < 0) || ((p1 == 0) && (p2 != NULL))) {
+ SM2error(SM2_R_INVALID_ARGUMENT);
+ return 0;
+ }
+ if ((p1 > 0) && (p2 == NULL)) {
+ SM2error(ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ free(dctx->uid);
+ if (p2 == NULL) {
+ dctx->uid = NULL;
+ dctx->uid_len = 0;
+ return 1;
+ }
+
+ if ((dctx->uid = malloc(p1)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ return 1;
+ }
+ memcpy(dctx->uid, p2, p1);
+ dctx->uid_len = p1;
+ return 1;
+
+ case EVP_PKEY_CTRL_SM2_HASH_UID:
+ {
+ const EVP_MD* md;
+ uint8_t za[EVP_MAX_MD_SIZE] = {0};
+ int md_len;
+
+ if (dctx->uid == NULL) {
+ SM2error(SM2_R_INVALID_ARGUMENT);
+ return 0;
+ }
+
+ if ((md = EVP_MD_CTX_md(dctx->md_ctx)) == NULL) {
+ SM2error(ERR_R_EVP_LIB);
+ return 0;
+ }
+
+ if ((md_len = EVP_MD_size(md)) < 0) {
+ SM2error(SM2_R_INVALID_DIGEST);
+ return 0;
+ }
+
+ if (sm2_compute_userid_digest(za, md, dctx->uid, dctx->uid_len,
+ ctx->pkey->pkey.ec) != 1) {
+ SM2error(SM2_R_DIGEST_FAILURE);
+ return 0;
+ }
+ return EVP_DigestUpdate(dctx->md_ctx, za, md_len);
+ }
+
+ case EVP_PKEY_CTRL_SM2_GET_UID_LEN:
+ if (p2 == NULL) {
+ SM2error(ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ *(size_t *)p2 = dctx->uid_len;
+ return 1;
+
+ case EVP_PKEY_CTRL_SM2_GET_UID:
+ if (p2 == NULL) {
+ SM2error(ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ if (dctx->uid_len == 0) {
+ return 1;
+ }
+ memcpy(p2, dctx->uid, dctx->uid_len);
+ return 1;
+
+ case EVP_PKEY_CTRL_MD:
+ dctx->md = p2;
+ return 1;
+
+ default:
+ return -2;
+ }
+}
+
+static int
+pkey_sm2_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value)
+{
+ int nid;
+
+ if (strcmp(type, "ec_paramgen_curve") == 0) {
+ if (((nid = EC_curve_nist2nid(value)) == NID_undef) &&
+ ((nid = OBJ_sn2nid(value)) == NID_undef) &&
+ ((nid = OBJ_ln2nid(value)) == NID_undef)) {
+ SM2error(SM2_R_INVALID_CURVE);
+ return 0;
+ }
+ return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid);
+ } else if (strcmp(type, "sm2_uid") == 0) {
+ return EVP_PKEY_CTX_set_sm2_uid(ctx, (void*) value,
+ (int)strlen(value));
+ }
+
+ return -2;
+}
+
+const EVP_PKEY_METHOD sm2_pkey_meth = {
+ .pkey_id = EVP_PKEY_SM2,
+ .init = pkey_sm2_init,
+ .copy = pkey_sm2_copy,
+ .cleanup = pkey_sm2_cleanup,
+
+ .sign = pkey_sm2_sign,
+
+ .verify = pkey_sm2_verify,
+
+ .encrypt = pkey_sm2_encrypt,
+
+ .decrypt = pkey_sm2_decrypt,
+
+ .ctrl = pkey_sm2_ctrl,
+ .ctrl_str = pkey_sm2_ctrl_str
+};
+
+#endif /* OPENSSL_NO_SM2 */
--- /dev/null
+/* $OpenBSD: sm2_sign.c,v 1.1.1.1 2021/08/18 16:04:32 tb Exp $ */
+/*
+ * Copyright (c) 2017, 2019 Ribose Inc
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef OPENSSL_NO_SM2
+
+#include <string.h>
+
+#include <openssl/sm2.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/bn.h>
+
+#include "bn_lcl.h"
+#include "sm2_locl.h"
+
+static BIGNUM *
+sm2_compute_msg_hash(const EVP_MD *digest, const EC_KEY *key,
+ const uint8_t *uid, size_t uid_len, const uint8_t *msg, size_t msg_len)
+{
+ EVP_MD_CTX *hash;
+ BIGNUM *e = NULL;
+ int md_size;
+ uint8_t *za = NULL;
+
+ if ((hash = EVP_MD_CTX_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if ((md_size = EVP_MD_size(digest)) < 0) {
+ SM2error(SM2_R_INVALID_DIGEST);
+ goto err;
+ }
+
+ if ((za = calloc(1, md_size)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!sm2_compute_userid_digest(za, digest, uid, uid_len, key)) {
+ SM2error(SM2_R_DIGEST_FAILURE);
+ goto err;
+ }
+
+ if (!EVP_DigestInit(hash, digest)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ if (!EVP_DigestUpdate(hash, za, md_size)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ if (!EVP_DigestUpdate(hash, msg, msg_len)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ /* reuse za buffer to hold H(ZA || M) */
+ if (!EVP_DigestFinal(hash, za, NULL)) {
+ SM2error(ERR_R_EVP_LIB);
+ goto err;
+ }
+
+ e = BN_bin2bn(za, md_size, NULL);
+
+ err:
+ free(za);
+ EVP_MD_CTX_free(hash);
+ return e;
+}
+
+static ECDSA_SIG *
+sm2_sig_gen(const EC_KEY *key, const BIGNUM *e)
+{
+ ECDSA_SIG *sig = NULL;
+ const EC_GROUP *group;
+ EC_POINT *kG = NULL;
+ BN_CTX *ctx = NULL;
+ const BIGNUM *dA;
+ BIGNUM *order = NULL, *r = NULL, *s = NULL;
+ BIGNUM *k, *rk, *tmp, *x1;
+
+ if ((dA = EC_KEY_get0_private_key(key)) == NULL) {
+ SM2error(SM2_R_INVALID_FIELD);
+ goto err;
+ }
+
+ if ((group = EC_KEY_get0_group(key)) == NULL) {
+ SM2error(SM2_R_INVALID_FIELD);
+ goto err;
+ }
+
+ if ((order = BN_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!EC_GROUP_get_order(group, order, NULL)) {
+ SM2error(ERR_R_EC_LIB);
+ goto err;
+ }
+
+ if ((kG = EC_POINT_new(group)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if ((ctx = BN_CTX_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ BN_CTX_start(ctx);
+
+ if ((k = BN_CTX_get(ctx)) == NULL) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+ if ((rk = BN_CTX_get(ctx)) == NULL) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+ if ((x1 = BN_CTX_get(ctx)) == NULL) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+ if ((tmp = BN_CTX_get(ctx)) == NULL) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+
+ /* r and s are returned as part of sig, so they can't be part of ctx. */
+ if ((r = BN_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if ((s = BN_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ for (;;) {
+ if (!BN_rand_range(k, order)) {
+ SM2error(SM2_R_RANDOM_NUMBER_GENERATION_FAILED);
+ goto err;
+ }
+
+ if (!EC_POINT_mul(group, kG, k, NULL, NULL, ctx)) {
+ SM2error(ERR_R_EC_LIB);
+ goto err;
+ }
+
+ if (!EC_POINT_get_affine_coordinates(group, kG, x1, NULL,
+ ctx)) {
+ SM2error(ERR_R_EC_LIB);
+ goto err;
+ }
+
+ if (!BN_mod_add(r, e, x1, order, ctx)) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+
+ /* try again if r == 0 or r + k == n */
+ if (BN_is_zero(r))
+ continue;
+
+ if (!BN_add(rk, r, k)) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+
+ if (BN_cmp(rk, order) == 0)
+ continue;
+
+ if (!BN_add(s, dA, BN_value_one())) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+
+ if (!BN_mod_inverse_ct(s, s, order, ctx)) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+
+ if (!BN_mod_mul(tmp, dA, r, order, ctx)) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+
+ if (!BN_sub(tmp, k, tmp)) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+
+ if (!BN_mod_mul(s, s, tmp, order, ctx)) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+
+ if ((sig = ECDSA_SIG_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* sig takes ownership of r and s */
+ if (!ECDSA_SIG_set0(sig, r, s)) {
+ SM2error(ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ break;
+ }
+
+ err:
+ if (sig == NULL) {
+ BN_free(r);
+ BN_free(s);
+ }
+
+ BN_free(order);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ EC_POINT_free(kG);
+ return sig;
+}
+
+static int
+sm2_sig_verify(const EC_KEY *key, const ECDSA_SIG *sig, const BIGNUM *e)
+{
+ const EC_GROUP *group;
+ EC_POINT *pt = NULL;
+ const BIGNUM *r = NULL, *s = NULL;
+ BN_CTX *ctx = NULL;
+ BIGNUM *order, *t, *x1;
+ int ret = 0;
+
+ if ((group = EC_KEY_get0_group(key)) == NULL) {
+ SM2error(SM2_R_INVALID_FIELD);
+ goto err;
+ }
+
+ if ((ctx = BN_CTX_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ BN_CTX_start(ctx);
+
+ if ((order = BN_CTX_get(ctx)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!EC_GROUP_get_order(group, order, NULL)) {
+ SM2error(ERR_R_EC_LIB);
+ goto err;
+ }
+
+ if ((pt = EC_POINT_new(group)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if ((t = BN_CTX_get(ctx)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if ((x1 = BN_CTX_get(ctx)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /*
+ * Section 5.3.1 in https://tools.ietf.org/html/draft-shen-sm2-ecdsa-00
+ *
+ * B1: verify that r' is in [1, n-1]
+ * B2: verify that s' is in [1, n-1]
+ * B3: set M' ~= ZA || M'
+ * B4: calculate e' = Hv(M'~)
+ * B5: verify that t = r' + s' (mod n) is not zero
+ * B6: calculate the point (x1', y1') = [s']G + [t]PA
+ * B7: verify that r' == e' + x1' (mod n)
+ */
+
+ ECDSA_SIG_get0(sig, &r, &s);
+
+ /* B1: verify that r' is in [1, n-1] */
+ if (BN_cmp(r, BN_value_one()) < 0 || BN_cmp(order, r) <= 0) {
+ SM2error(SM2_R_BAD_SIGNATURE);
+ goto err;
+ }
+
+ /* B2: verify that s' is in [1, n-1] */
+ if (BN_cmp(s, BN_value_one()) < 0 || BN_cmp(order, s) <= 0) {
+ SM2error(SM2_R_BAD_SIGNATURE);
+ goto err;
+ }
+
+ /* B5: verify that t = r + s is not zero */
+ if (!BN_mod_add(t, r, s, order, ctx)) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+ if (BN_is_zero(t)) {
+ SM2error(SM2_R_BAD_SIGNATURE);
+ goto err;
+ }
+
+ /* B6: calculate pt = (x1', y1') = [s']G + [t]PA */
+ if (!EC_POINT_mul(group, pt, s, EC_KEY_get0_public_key(key), t, ctx)) {
+ SM2error(ERR_R_EC_LIB);
+ goto err;
+ }
+
+ if (!EC_POINT_get_affine_coordinates(group, pt, x1, NULL, ctx)) {
+ SM2error(ERR_R_EC_LIB);
+ goto err;
+ }
+
+ /* B7: verify that r' == e' + x1' (mod n) */
+ if (!BN_mod_add(t, e, x1, order, ctx)) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+ if (BN_cmp(r, t) == 0)
+ ret = 1;
+
+ err:
+ EC_POINT_free(pt);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return ret;
+}
+
+ECDSA_SIG *
+sm2_do_sign(const EC_KEY *key, const EVP_MD *digest, const uint8_t *uid,
+ size_t uid_len, const uint8_t *msg, size_t msg_len)
+{
+ ECDSA_SIG *sig = NULL;
+ BIGNUM *e;
+
+ e = sm2_compute_msg_hash(digest, key, uid, uid_len, msg, msg_len);
+ if (e == NULL) {
+ SM2error(SM2_R_DIGEST_FAILURE);
+ goto err;
+ }
+
+ sig = sm2_sig_gen(key, e);
+
+ err:
+ BN_free(e);
+ return sig;
+}
+
+int
+sm2_do_verify(const EC_KEY *key, const EVP_MD *digest, const ECDSA_SIG *sig,
+ const uint8_t *uid, size_t uid_len, const uint8_t *msg, size_t msg_len)
+{
+ BIGNUM *e;
+ int ret = -1;
+
+ e = sm2_compute_msg_hash(digest, key, uid, uid_len, msg, msg_len);
+ if (e == NULL) {
+ SM2error(SM2_R_DIGEST_FAILURE);
+ goto err;
+ }
+
+ ret = sm2_sig_verify(key, sig, e);
+
+ err:
+ BN_free(e);
+ return ret;
+}
+
+int
+SM2_sign(const unsigned char *dgst, int dgstlen, unsigned char *sig,
+ unsigned int *siglen, EC_KEY *eckey)
+{
+ BIGNUM *e;
+ ECDSA_SIG *s = NULL;
+ int outlen = 0;
+ int ret = -1;
+
+ if ((e = BN_bin2bn(dgst, dgstlen, NULL)) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if ((s = sm2_sig_gen(eckey, e)) == NULL) {
+ goto err;
+ }
+
+ if ((outlen = i2d_ECDSA_SIG(s, &sig)) < 0) {
+ SM2error(SM2_R_ASN1_ERROR);
+ goto err;
+ }
+
+ *siglen = outlen;
+ ret = 1;
+
+ err:
+ ECDSA_SIG_free(s);
+ BN_free(e);
+ return ret;
+}
+
+int
+SM2_verify(const unsigned char *dgst, int dgstlen, const unsigned char *sig,
+ int sig_len, EC_KEY *eckey)
+{
+ ECDSA_SIG *s;
+ BIGNUM *e = NULL;
+ const unsigned char *p = sig;
+ unsigned char *der = NULL;
+ int derlen = -1;
+ int ret = -1;
+
+ if ((s = ECDSA_SIG_new()) == NULL) {
+ SM2error(ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (d2i_ECDSA_SIG(&s, &p, sig_len) == NULL) {
+ SM2error(SM2_R_INVALID_ENCODING);
+ goto err;
+ }
+
+ /* Ensure signature uses DER and doesn't have trailing garbage */
+ derlen = i2d_ECDSA_SIG(s, &der);
+ if (derlen != sig_len || memcmp(sig, der, derlen) != 0) {
+ SM2error(SM2_R_INVALID_ENCODING);
+ goto err;
+ }
+
+ if ((e = BN_bin2bn(dgst, dgstlen, NULL)) == NULL) {
+ SM2error(ERR_R_BN_LIB);
+ goto err;
+ }
+
+ ret = sm2_sig_verify(eckey, s, e);
+
+ err:
+ free(der);
+ BN_free(e);
+ ECDSA_SIG_free(s);
+ return ret;
+}
+
+#endif /* OPENSSL_NO_SM2 */
--- /dev/null
+/* $OpenBSD: sm2_za.c,v 1.1.1.1 2021/08/18 16:04:32 tb Exp $ */
+/*
+ * Copyright (c) 2017, 2019 Ribose Inc
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef OPENSSL_NO_SM2
+
+#include <openssl/sm2.h>
+#include <openssl/evp.h>
+#include <openssl/bn.h>
+#include <string.h>
+
+int
+sm2_compute_userid_digest(uint8_t *out, const EVP_MD *digest, uint8_t *uid,
+ size_t uid_len, const EC_KEY *key)
+{
+ const EC_GROUP *group;
+ EVP_MD_CTX *hash = NULL;
+ BN_CTX *ctx = NULL;
+ BIGNUM *p, *a, *b, *xG, *yG, *xA, *yA;
+ uint8_t *buf = NULL;
+ uint16_t entla;
+ uint8_t e_byte;
+ int bytes, p_bytes;
+ int rc = 0;
+
+ if ((group = EC_KEY_get0_group(key)) == NULL)
+ goto err;
+
+ if ((hash = EVP_MD_CTX_new()) == NULL)
+ goto err;
+
+ if ((ctx = BN_CTX_new()) == NULL)
+ goto err;
+
+ if ((p = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((a = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((b = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((xG = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((yG = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((xA = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((yA = BN_CTX_get(ctx)) == NULL)
+ goto err;
+
+ memset(out, 0, EVP_MD_size(digest));
+
+ if (!EVP_DigestInit(hash, digest))
+ goto err;
+
+ /*
+ * ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA)
+ */
+
+ if (uid_len >= 8192)
+ goto err;
+
+ entla = (unsigned short)(8 * uid_len);
+
+ e_byte = entla >> 8;
+ if (!EVP_DigestUpdate(hash, &e_byte, 1))
+ goto err;
+
+ e_byte = entla & 0xFF;
+ if (!EVP_DigestUpdate(hash, &e_byte, 1))
+ goto err;
+
+ if (!EVP_DigestUpdate(hash, uid, uid_len))
+ goto err;
+
+ if (!EC_GROUP_get_curve(group, p, a, b, ctx))
+ goto err;
+
+ p_bytes = BN_num_bytes(p);
+
+ if ((buf = calloc(1, p_bytes)) == NULL)
+ goto err;
+
+ if ((bytes = BN_num_bytes(a)) > p_bytes)
+ goto err;
+ BN_bn2bin(a, buf + p_bytes - bytes);
+ if (!EVP_DigestUpdate(hash, buf, p_bytes))
+ goto err;
+
+ if ((bytes = BN_num_bytes(b)) > p_bytes)
+ goto err;
+ memset(buf, 0, p_bytes - bytes);
+ BN_bn2bin(b, buf + p_bytes - bytes);
+ if (!EVP_DigestUpdate(hash, buf, p_bytes))
+ goto err;
+
+ if (!EC_POINT_get_affine_coordinates(group,
+ EC_GROUP_get0_generator(group), xG, yG, ctx))
+ goto err;
+
+ if ((bytes = BN_num_bytes(xG)) > p_bytes)
+ goto err;
+ memset(buf, 0, p_bytes - bytes);
+ BN_bn2bin(xG, buf + p_bytes - bytes);
+
+ if (!EVP_DigestUpdate(hash, buf, p_bytes))
+ goto err;
+
+ if ((bytes = BN_num_bytes(yG)) > p_bytes)
+ goto err;
+ memset(buf, 0, p_bytes - bytes);
+ BN_bn2bin(yG, buf + p_bytes - bytes);
+
+ if (!EVP_DigestUpdate(hash, buf, p_bytes))
+ goto err;
+
+ if (!EC_POINT_get_affine_coordinates(group,
+ EC_KEY_get0_public_key(key), xA, yA, ctx))
+ goto err;
+
+ if ((bytes = BN_num_bytes(xA)) > p_bytes)
+ goto err;
+ memset(buf, 0, p_bytes - bytes);
+ BN_bn2bin(xA, buf + p_bytes - bytes);
+
+ if (!EVP_DigestUpdate(hash, buf, p_bytes))
+ goto err;
+
+ if ((bytes = BN_num_bytes(yA)) > p_bytes)
+ goto err;
+ memset(buf, 0, p_bytes - bytes);
+ BN_bn2bin(yA, buf + p_bytes - bytes);
+
+ if (!EVP_DigestUpdate(hash, buf, p_bytes))
+ goto err;
+
+ if (!EVP_DigestFinal(hash, out, NULL))
+ goto err;
+
+ rc = 1;
+
+ err:
+ free(buf);
+ BN_CTX_free(ctx);
+ EVP_MD_CTX_free(hash);
+ return rc;
+}
+
+#endif /* OPENSSL_NO_SM2 */