### Changes between 1.1.1 and 3.0 [xx XXX xxxx]
+ * Validation of SM2 keys has been separated from the validation of regular EC
+ keys, allowing to improve the SM2 validation process to reject loaded private
+ keys that are not conforming to the SM2 ISO standard.
+ In particular, a private scalar `k` outside the range `1 <= k < n-1` is now
+ correctly rejected.
+
+ *Nicola Tuveri*
+
* Behavior of the `pkey` app is changed, when using the `-check` or `-pubcheck`
switches: a validation failure triggers an early exit, returning a failure
exit status to the parent process.
SM2_R_INVALID_DIGEST_TYPE:103:invalid digest type
SM2_R_INVALID_ENCODING:104:invalid encoding
SM2_R_INVALID_FIELD:105:invalid field
+SM2_R_INVALID_PRIVATE_KEY:113:invalid private key
SM2_R_NO_PARAMETERS_SET:109:no parameters set
SM2_R_USER_ID_TOO_LARGE:106:user id too large
SSL_R_ALGORITHM_FETCH_FAILED:295:algorithm fetch failed
LIBS=../../libcrypto
SOURCE[../../libcrypto]=\
- sm2_sign.c sm2_crypt.c sm2_err.c
+ sm2_sign.c sm2_crypt.c sm2_err.c sm2_key.c
"invalid digest type"},
{ERR_PACK(ERR_LIB_SM2, 0, SM2_R_INVALID_ENCODING), "invalid encoding"},
{ERR_PACK(ERR_LIB_SM2, 0, SM2_R_INVALID_FIELD), "invalid field"},
+ {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_INVALID_PRIVATE_KEY),
+ "invalid private key"},
{ERR_PACK(ERR_LIB_SM2, 0, SM2_R_NO_PARAMETERS_SET), "no parameters set"},
{ERR_PACK(ERR_LIB_SM2, 0, SM2_R_USER_ID_TOO_LARGE), "user id too large"},
{0, NULL}
--- /dev/null
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (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 <openssl/err.h>
+#include "crypto/sm2err.h"
+#include "crypto/sm2.h"
+#include <openssl/ec.h> /* EC_KEY and EC_GROUP functions */
+
+/*
+ * SM2 key generation is implemented within ec_generate_key() in
+ * crypto/ec/ec_key.c
+ */
+
+int sm2_key_private_check(const EC_KEY *eckey)
+{
+ int ret = 0;
+ BIGNUM *max = NULL;
+ const EC_GROUP *group = NULL;
+ const BIGNUM *priv_key = NULL, *order = NULL;
+
+ if (eckey == NULL
+ || (group = EC_KEY_get0_group(eckey)) == NULL
+ || (priv_key = EC_KEY_get0_private_key(eckey)) == NULL
+ || (order = EC_GROUP_get0_order(group)) == NULL ) {
+ ERR_raise(ERR_LIB_SM2, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ /* range of SM2 private key is [1, n-1) */
+ max = BN_dup(order);
+ if (max == NULL || !BN_sub_word(max, 1))
+ goto end;
+ if (BN_cmp(priv_key, BN_value_one()) < 0
+ || BN_cmp(priv_key, max) >= 0) {
+ ERR_raise(ERR_LIB_SM2, SM2_R_INVALID_PRIVATE_KEY);
+ goto end;
+ }
+ ret = 1;
+
+ end:
+ BN_free(max);
+ return ret;
+}
# include <openssl/ec.h>
+int sm2_key_private_check(const EC_KEY *eckey);
+
/* The default user id as specified in GM/T 0009-2012 */
# define SM2_DEFAULT_USERID "1234567812345678"
# define SM2_R_INVALID_DIGEST_TYPE 103
# define SM2_R_INVALID_ENCODING 104
# define SM2_R_INVALID_FIELD 105
+# define SM2_R_INVALID_PRIVATE_KEY 113
# define SM2_R_NO_PARAMETERS_SET 109
# define SM2_R_USER_ID_TOO_LARGE 106
# We make separate GOAL variables for each algorithm, to make it easy to
# switch each to the Legacy provider when needed.
-$EC_GOAL=../../libimplementations.a
$ECX_GOAL=../../libimplementations.a
$KDF_GOAL=../../libimplementations.a
SOURCE[../../libnonfips.a]=dsa_kmgmt.c
ENDIF
IF[{- !$disabled{ec} -}]
- SOURCE[$EC_GOAL]=ec_kmgmt.c
+ SOURCE[../../libfips.a]=ec_kmgmt.c
+ SOURCE[../../libnonfips.a]=ec_kmgmt.c
ENDIF
IF[{- !$disabled{asm} -}]
#include "prov/providercommonerr.h"
#include "prov/provider_ctx.h"
#include "internal/param_build_set.h"
-#include "crypto/sm2.h"
+
+#ifndef FIPS_MODULE
+# ifndef OPENSSL_NO_SM2
+# include "crypto/sm2.h"
+# endif
+#endif
static OSSL_FUNC_keymgmt_new_fn ec_newdata;
static OSSL_FUNC_keymgmt_gen_init_fn ec_gen_init;
static OSSL_FUNC_keymgmt_export_fn ec_export;
static OSSL_FUNC_keymgmt_export_types_fn ec_export_types;
static OSSL_FUNC_keymgmt_query_operation_name_fn ec_query_operation_name;
-#ifndef OPENSSL_NO_SM2
+#ifndef FIPS_MODULE
+# ifndef OPENSSL_NO_SM2
static OSSL_FUNC_keymgmt_gen_fn sm2_gen;
static OSSL_FUNC_keymgmt_get_params_fn sm2_get_params;
static OSSL_FUNC_keymgmt_gettable_params_fn sm2_gettable_params;
static OSSL_FUNC_keymgmt_settable_params_fn sm2_settable_params;
static OSSL_FUNC_keymgmt_import_fn sm2_import;
static OSSL_FUNC_keymgmt_query_operation_name_fn sm2_query_operation_name;
+static OSSL_FUNC_keymgmt_validate_fn sm2_validate;
+# endif
#endif
#define EC_DEFAULT_MD "SHA256"
return NULL;
}
-#ifndef OPENSSL_NO_SM2
+#ifndef FIPS_MODULE
+# ifndef OPENSSL_NO_SM2
static
const char *sm2_query_operation_name(int operation_id)
{
}
return NULL;
}
+# endif
#endif
/*
return common_import(keydata, selection, params, 0);
}
-#ifndef OPENSSL_NO_SM2
+#ifndef FIPS_MODULE
+# ifndef OPENSSL_NO_SM2
static
int sm2_import(void *keydata, int selection, const OSSL_PARAM params[])
{
return common_import(keydata, selection, params, 1);
}
+# endif
#endif
static
return ec_key_otherparams_fromdata(eck, params);
}
-#ifndef OPENSSL_NO_SM2
+#ifndef FIPS_MODULE
+# ifndef OPENSSL_NO_SM2
static
int sm2_get_params(void *key, OSSL_PARAM params[])
{
{
return sm2_known_settable_params;
}
+
+static
+int sm2_validate(const void *keydata, int selection)
+{
+ const EC_KEY *eck = keydata;
+ int ok = 0;
+ BN_CTX *ctx = NULL;
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+ ctx = BN_CTX_new_ex(ec_key_get_libctx(eck));
+ if (ctx == NULL)
+ return 0;
+
+ if ((selection & EC_POSSIBLE_SELECTIONS) != 0)
+ ok = 1;
+
+ if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
+ ok = ok && EC_GROUP_check(EC_KEY_get0_group(eck), ctx);
+
+ if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+ ok = ok && ec_key_public_check(eck, ctx);
+
+ if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+ ok = ok && sm2_key_private_check(eck);
+
+ if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == OSSL_KEYMGMT_SELECT_KEYPAIR)
+ ok = ok && ec_key_pairwise_check(eck, ctx);
+
+ BN_CTX_free(ctx);
+ return ok;
+}
+# endif
#endif
static
return NULL;
}
-#ifndef OPENSSL_NO_SM2
+#ifndef FIPS_MODULE
+# ifndef OPENSSL_NO_SM2
/*
* The callback arguments (osslcb & cbarg) are not used by EC_KEY generation
*/
EC_KEY_free(ec);
return NULL;
}
+# endif
#endif
static void ec_gen_cleanup(void *genctx)
{ 0, NULL }
};
-#ifndef OPENSSL_NO_SM2
+#ifndef FIPS_MODULE
+# ifndef OPENSSL_NO_SM2
const OSSL_DISPATCH sm2_keymgmt_functions[] = {
{ OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))ec_newdata },
{ OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))ec_gen_init },
{ OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))sm2_settable_params },
{ OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ec_has },
{ OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))ec_match },
- { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))ec_validate },
+ { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))sm2_validate },
{ OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))sm2_import },
{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))ec_import_types },
{ OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ec_export },
(void (*)(void))sm2_query_operation_name },
{ 0, NULL }
};
+# endif
#endif