Browse Source

Add SM2 private key range validation

According to the relevant standards, the valid range for SM2 private
keys is [1, n-1), where n is the order of the curve generator.

For this reason we cannot reuse the EC validation function as it is, and
we introduce a new internal function `sm2_key_private_check()`.

Partially fixes https://github.com/openssl/openssl/issues/8435

Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/13359)
master
Nicola Tuveri 2 years ago
parent
commit
9e49aff2aa
9 changed files with 125 additions and 11 deletions
  1. +8
    -0
      CHANGES.md
  2. +1
    -0
      crypto/err/openssl.txt
  3. +1
    -1
      crypto/sm2/build.info
  4. +2
    -0
      crypto/sm2/sm2_err.c
  5. +49
    -0
      crypto/sm2/sm2_key.c
  6. +2
    -0
      include/crypto/sm2.h
  7. +1
    -0
      include/crypto/sm2err.h
  8. +2
    -2
      providers/implementations/keymgmt/build.info
  9. +59
    -8
      providers/implementations/keymgmt/ec_kmgmt.c

+ 8
- 0
CHANGES.md View File

@ -23,6 +23,14 @@ OpenSSL 3.0
### 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.


+ 1
- 0
crypto/err/openssl.txt View File

@ -3103,6 +3103,7 @@ SM2_R_INVALID_DIGEST:102:invalid digest
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


+ 1
- 1
crypto/sm2/build.info View File

@ -1,5 +1,5 @@
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

+ 2
- 0
crypto/sm2/sm2_err.c View File

@ -28,6 +28,8 @@ static const ERR_STRING_DATA SM2_str_reasons[] = {
"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}


+ 49
- 0
crypto/sm2/sm2_key.c View File

@ -0,0 +1,49 @@
/*
* 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;
}

+ 2
- 0
include/crypto/sm2.h View File

@ -17,6 +17,8 @@
# 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"


+ 1
- 0
include/crypto/sm2err.h View File

@ -61,6 +61,7 @@ int err_load_SM2_strings_int(void);
# 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


+ 2
- 2
providers/implementations/keymgmt/build.info View File

@ -1,7 +1,6 @@
# 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
@ -14,7 +13,8 @@ IF[{- !$disabled{dsa} -}]
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} -}]


+ 59
- 8
providers/implementations/keymgmt/ec_kmgmt.c View File

@ -27,7 +27,12 @@
#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;
@ -50,13 +55,16 @@ static OSSL_FUNC_keymgmt_import_types_fn ec_import_types;
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"
@ -76,7 +84,8 @@ const char *ec_query_operation_name(int operation_id)
return NULL;
}
#ifndef OPENSSL_NO_SM2
#ifndef FIPS_MODULE
# ifndef OPENSSL_NO_SM2
static
const char *sm2_query_operation_name(int operation_id)
{
@ -86,6 +95,7 @@ const char *sm2_query_operation_name(int operation_id)
}
return NULL;
}
# endif
#endif
/*
@ -364,12 +374,14 @@ int ec_import(void *keydata, int selection, const OSSL_PARAM params[])
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
@ -746,7 +758,8 @@ int ec_set_params(void *key, const OSSL_PARAM params[])
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[])
{
@ -782,6 +795,40 @@ const OSSL_PARAM *sm2_settable_params(ossl_unused void *provctx)
{
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
@ -1084,7 +1131,8 @@ err:
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
*/
@ -1130,6 +1178,7 @@ err:
EC_KEY_free(ec);
return NULL;
}
# endif
#endif
static void ec_gen_cleanup(void *genctx)
@ -1195,7 +1244,8 @@ const OSSL_DISPATCH ossl_ec_keymgmt_functions[] = {
{ 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 },
@ -1213,7 +1263,7 @@ const OSSL_DISPATCH sm2_keymgmt_functions[] = {
{ 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 },
@ -1222,4 +1272,5 @@ const OSSL_DISPATCH sm2_keymgmt_functions[] = {
(void (*)(void))sm2_query_operation_name },
{ 0, NULL }
};
# endif
#endif

Loading…
Cancel
Save