fi
git clone --depth 1 -b $OPENSSL_BRANCH https://github.com/openssl/openssl.git
+if [ "${PATCH_OPENSSL}" == "1" ]; then
+ git apply patches/openssl-tls1.3.patch
+fi
cd openssl
git describe --always --long
mkdir build
cd build
-cmake -DOPENSSL_ROOT_DIR=$PREFIX -DOPENSSL_ENGINES_DIR=$PREFIX/engines ${ASAN-} ..
+cmake -DTLS13_PATCHED_OPENSSL=$PATCH_OPENSSL -DOPENSSL_ROOT_DIR=$PREFIX -DOPENSSL_ENGINES_DIR=$PREFIX/engines ${ASAN-} ..
make
make test CTEST_OUTPUT_ON_FAILURE=1
if [ -z "${ASAN-}" ]; then
- make tcl_tests
+ make tcl_tests_engine
+ make tcl_tests_provider
fi
on: [push, pull_request]
env:
- OPENSSL_BRANCH: openssl-3.0
+ OPENSSL_BRANCH: openssl-3.4.2
USE_RPATH: yes
+ PATCH_OPENSSL: 0
+ GOST_PROVIDER_ENABLE_ONLINE_TESTS: 1
jobs:
gcc-openssl-stable:
runs-on: ubuntu-latest
+ env:
+ PATCH_OPENSSL: 1
steps:
- uses: actions/checkout@v2
with:
runs-on: ubuntu-latest
env:
CC: clang
+ PATCH_OPENSSL: 1
steps:
- uses: actions/checkout@v2
with:
runs-on: macos-latest
env:
USE_RPATH:
+ PATCH_OPENSSL: 1
+ GOST_PROVIDER_ENABLE_ONLINE_TESTS: 0 # macOS runner has no network access to infotecs TLS1.3 server
steps:
- uses: actions/checkout@v2
with:
LDFLAGS: -m32
SETARCH: "setarch i386"
APT_INSTALL: gcc-multilib
+ PATCH_OPENSSL: 1
steps:
- uses: actions/checkout@v2
with:
name: "CodeQL"
env:
- OPENSSL_BRANCH: openssl-3.0
+ OPENSSL_BRANCH: openssl-3.4.2
#RPATH: "-Wl,-rpath=${PREFIX}/lib"
#PREFIX: ${HOME}/opt
#PATH: ${PREFIX}/bin:${PATH}
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'gost-engine' || github.event_name == 'workflow_dispatch' }}
env:
- OPENSSL_BRANCH: openssl-3.0
+ OPENSSL_BRANCH: openssl-3.4.2
USE_RPATH: yes
+ PATCH_OPENSSL: 1
+ GOST_PROVIDER_ENABLE_ONLINE_TESTS: 0
steps:
- uses: actions/checkout@v2
outputs:
openssl-head: ${{ steps.openssl.outputs.head }}
steps:
+ - uses: actions/checkout@v2
- uses: actions/checkout@v2
with:
repository: openssl/openssl
+ path: openssl
+ ref: openssl-3.4.2
fetch-depth: 0
- - run: echo "::set-output name=head::$(git describe --always --long)"
+ - run: echo "::set-output name=head::$(git -C openssl describe --always --long)"
id: openssl
- uses: actions/cache@v4
id: cache
with:
- path: _dest
+ path: openssl/_dest
key: ${{ runner.os }}-openssl-${{ steps.openssl.outputs.head }}
+ - name: Apply patches
+ run: |
+ git apply patches/openssl-tls1.3.patch
- uses: ilammy/msvc-dev-cmd@v1
- name: Build OpenSSL
if: steps.cache.outputs.cache-hit != 'true'
+ working-directory: openssl
run: |
perl Configure no-makedepend no-tests no-asm VC-WIN64A
perl configdata.pm --dump
submodules: true
- uses: actions/cache@v4
with:
- path: _dest
+ path: openssl/_dest
key: ${{ runner.os }}-openssl-${{ needs.msvc-openssl.outputs.openssl-head }}
- - run: cmake -DOPENSSL_ROOT_DIR="_dest\Program Files\OpenSSL" -DOPENSSL_ENGINES_DIR=bin .
+ - run: cmake -DOPENSSL_ROOT_DIR="openssl\_dest\Program Files\OpenSSL" -DOPENSSL_ENGINES_DIR=bin .
- run: cmake --build .
- name: Run tests
run: |
- $env:PATH = "$env:PATH;$pwd\_dest\Program Files\OpenSSL\bin"
+ $env:PATH = "$pwd\openssl\_dest\Program Files\OpenSSL\bin;$env:PATH"
$env:OPENSSL_ENGINES = "$pwd\bin\Debug"
$env:OPENSSL_MODULES = "$pwd\bin\Debug"
ctest -C Debug --output-on-failure
enable_testing()
-find_package(OpenSSL 3.0 REQUIRED)
+find_package(OpenSSL 3.4 REQUIRED)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to 'RelWithDebInfo' as none was specified.")
set(CMAKE_C_FLAGS_RELEASE -O2)
set(CMAKE_C_FLAGS_DEBUG "-O0 -ggdb")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -ggdb")
- add_compile_options(-Werror -Wall -Wno-unused-parameter -Wno-unused-function -Wno-missing-braces -Qunused-arguments -Wno-deprecated-declarations)
+ add_compile_options(-Werror -Wall -Wno-unused-parameter -Wno-unused-function -Wno-missing-braces -Qunused-arguments -Wno-deprecated-declarations -Wno-error=\#warnings)
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU")
set(CMAKE_C_FLAGS_RELEASE -O2)
set(CMAKE_C_FLAGS_DEBUG "-O0 -ggdb")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -ggdb")
- add_compile_options(-Werror -Wall -Wno-unused-parameter -Wno-unused-function -Wno-missing-braces -Wno-error=unknown-pragmas -Wno-error=pragmas -Wno-deprecated-declarations)
+ add_compile_options(-Werror -Wall -Wno-unused-parameter -Wno-unused-function -Wno-missing-braces -Wno-error=unknown-pragmas -Wno-error=pragmas -Wno-deprecated-declarations -Wno-error=cpp)
elseif(CMAKE_C_COMPILER_ID MATCHES "MSVC")
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-D_CRT_DEPRECATED_NO_WARNINGS)
set(GOST_PROV_SOURCE_FILES
gost_prov.c
+ gost_prov.h
gost_prov_cipher.c
gost_prov_digest.c
gost_prov_mac.c
+ gost_prov_keymgmt.c
+ gost_prov_encoder.c
+ gost_prov_signature.c
+ gost_prov_decoder.c
+ gost_prov_keyexch.c
+ gost_prov_tls.c
+ gost_prov_tls.h
)
set(TEST_ENVIRONMENT_COMMON
+ TLS13_PATCHED_OPENSSL=${TLS13_PATCHED_OPENSSL}
CMAKE_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}
PERL5LIB=${CMAKE_CURRENT_SOURCE_DIR}/test
OPENSSL_PROGRAM=${OPENSSL_PROGRAM}
+ OPENSSL_MODULES=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
OPENSSL_CRYPTO_LIBRARY=${OPENSSL_CRYPTO_LIBRARY}
)
PROPERTIES ENVIRONMENT "${TEST_ENVIRONMENT_PROVIDER}")
# test_curves is an internals testing program, it doesn't need a test env
+
+add_executable(test_ecdhe test_ecdhe.c)
+target_link_libraries(test_ecdhe gost_core gost_err)
+add_test(NAME ecdhe COMMAND test_ecdhe)
+set_tests_properties(ecdhe
+ PROPERTIES ENVIRONMENT "${TEST_ENVIRONMENT_ENGINE}")
+
add_executable(test_curves test_curves.c)
target_link_libraries(test_curves gost_core gost_err)
add_test(NAME curves COMMAND test_curves)
target_link_libraries(test_gost89 gost_core gost_err)
add_test(NAME gost89 COMMAND test_gost89)
-add_executable(test_mgm test_mgm.c)
-target_link_libraries(test_mgm OpenSSL::Crypto)
-add_test(NAME mgm-with-engine COMMAND test_mgm)
-set_tests_properties(mgm-with-engine
- PROPERTIES ENVIRONMENT "${TEST_ENVIRONMENT_ENGINE}")
-add_test(NAME mgm-with-provider COMMAND test_mgm)
-set_tests_properties(mgm-with-provider
- PROPERTIES ENVIRONMENT "${TEST_ENVIRONMENT_PROVIDER}")
+if(TLS13_PATCHED_OPENSSL)
+ add_executable(test_mgm test_mgm.c)
+ target_link_libraries(test_mgm OpenSSL::Crypto)
+ add_test(NAME mgm-with-engine COMMAND test_mgm)
+ set_tests_properties(mgm-with-engine
+ PROPERTIES ENVIRONMENT "${TEST_ENVIRONMENT_ENGINE}")
+ add_test(NAME mgm-with-provider COMMAND test_mgm)
+ set_tests_properties(mgm-with-provider
+ PROPERTIES ENVIRONMENT "${TEST_ENVIRONMENT_PROVIDER}")
+ set_property(TARGET test_mgm APPEND PROPERTY COMPILE_DEFINITIONS ENGINE_DIR="${OUTPUT_DIRECTORY}")
+endif()
if(NOT SKIP_PERL_TESTS)
execute_process(COMMAND perl -MTest2::V0 -e ""
test_digest
test_ciphers
test_curves
+ test_ecdhe
test_params
test_derive
test_sign
test_keyexpimp
test_gost89
test_tls
- test_mgm
)
set_property(TARGET ${BINARY_TESTS_TARGETS} APPEND PROPERTY COMPILE_DEFINITIONS ENGINE_DIR="${OUTPUT_DIRECTORY}")
COMMAND ctags -R . ${OPENSSL_ROOT_DIR}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
-add_custom_target(tcl_tests
+add_custom_target(tcl_tests_provider
+ COMMAND OPENSSL_LIBCRYPTO=${OPENSSL_CRYPTO_LIBRARY}
+ OPENSSL_APP=${OPENSSL_PROGRAM}
+ TESTSRC=${CMAKE_SOURCE_DIR}/tcl_tests
+ TESTDIR=${CMAKE_BINARY_DIR}/tcl_tests_provider
+ OPENSSL_MODULES_DIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
+ OPENSSL_CONF=${CMAKE_SOURCE_DIR}/tcl_tests/openssl-gost-provider.cnf
+ sh ./runtest.sh
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tcl_tests)
+
+add_custom_target(tcl_tests_engine
COMMAND OPENSSL_LIBCRYPTO=${OPENSSL_CRYPTO_LIBRARY}
OPENSSL_APP=${OPENSSL_PROGRAM}
TESTSRC=${CMAKE_SOURCE_DIR}/tcl_tests
TESTDIR=${CMAKE_BINARY_DIR}/tcl_tests
ENGINE_DIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
+ OPENSSL_CONF=${CMAKE_SOURCE_DIR}/tcl_tests/openssl-gost-engine.cnf
sh ./runtest.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tcl_tests)
- kuznyechik-mac
- kuznyechik-ctr-acpkm-omac
-## TODO, not requiring additional OpenSSL support
+Keymgmt:
-- Basic support for GOST keys, i.e. implementations of KEYMGMT
- (including key generation), DECODER and DECODER.
+- id-GostR3410-2001 ("GOST R 34.10-2001", "1.2.643.2.2.19")
+- id-GostR3410-2001DH ("GOST R 34.10-2001 DH", "1.2.643.2.2.98")
+- gost2012_256 ("GOST R 34.10-2012 with 256 bit modulus", "1.2.643.7.1.1.1.1")
+- gost2012_512 ("GOST R 34.10-2012 with 512 bit modulus", "1.2.643.7.1.1.1.2")
-- Support for these operations using GOST keys:
+Encoder:
+- id-GostR3410-2001 ("GOST R 34.10-2001", "1.2.643.2.2.19") with structure format = pem/der/text
+- id-GostR3410-2001DH ("GOST R 34.10-2001 DH", "1.2.643.2.2.98") with structure format = pem/der/text
+- gost2012_256 ("GOST R 34.10-2012 with 256 bit modulus", "1.2.643.7.1.1.1.1") with structure format = pem/der/text
+- gost2012_512 ("GOST R 34.10-2012 with 512 bit modulus", "1.2.643.7.1.1.1.2") with structure format = pem/der/text
+
+PrivateKeyInfo can only be saved in pkcs8 format without encryption.
+
+Decoder:
+- id-GostR3410-2001 ("GOST R 34.10-2001", "1.2.643.2.2.19") with structure format = der
+- id-GostR3410-2001DH ("GOST R 34.10-2001 DH", "1.2.643.2.2.98") with structure format = der
+- gost2012_256 ("GOST R 34.10-2012 with 256 bit modulus", "1.2.643.7.1.1.1.1") with structure format = der
+- gost2012_512 ("GOST R 34.10-2012 with 512 bit modulus", "1.2.643.7.1.1.1.2") with structure format = der
+
+pem2der decoder already implemented by OpenSSL default provider.
+
+PrivateKeyInfo can only be loaded in pkcs8 format without decryption.
+
+Signature:
+- SN_id_GostR3410_2001, "id-GostR3411-94-with-GostR3410-2001", "GOST R 34.11-94 with GOST R 34.10-2001", "1.2.643.2.2.3"
+- SN_id_GostR3410_2012_256, "id-tc26-signwithdigest-gost3410-2012-256", "GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)", "1.2.643.7.1.1.3.2"
+- gost2012_256, "id-tc26-signwithdigest-gost3410-2012-512", "GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)", "1.2.643.7.1.1.3.3"
+Keyexchange:
+- ECDHE
+
+TLS1.3:
+- OpenSSL patch has been implemented that allows to connect TLS1.3 using a provider.
+
+## TODO, not requiring additional OpenSSL support
+
+- Support for these operations using GOST keys:
- ASYM_CIPHER (encryption and decryption using GOST keys)
- - SIGNATURE (signing and verifying using GOST keys)
## TODO, which requires additional OpenSSL support
-- TLSTREE support. This may require additional changes in libssl.
- Needs investigation.
-
- PKCS7 and CMS support. This requires OpenSSL PKCS7 and CMS code
to change for better interfacing with providers.
return 1;
}
-static int pkey_bits_gost(const EVP_PKEY *pk)
+static int internal_pkey_bits(int key_type)
{
- if (!pk)
- return -1;
-
- switch (EVP_PKEY_base_id(pk)) {
+ switch (key_type) {
case NID_id_GostR3410_2001:
case NID_id_GostR3410_2001DH:
case NID_id_GostR3410_2012_256:
return -1;
}
-static ASN1_STRING *encode_gost_algor_params(const EVP_PKEY *key)
+static int pkey_bits_gost(const EVP_PKEY *pk)
+{
+ int key_type = (pk == NULL) ? NID_undef : EVP_PKEY_base_id(pk);
+
+ return internal_pkey_bits(key_type);
+}
+
+static ASN1_STRING *internal_encode_algor_params(EC_KEY *key_ptr,
+ int key_type)
{
ASN1_STRING *params = ASN1_STRING_new();
GOST_KEY_PARAMS *gkp = GOST_KEY_PARAMS_new();
int pkey_param_nid = NID_undef;
- void *key_ptr = EVP_PKEY_get0((EVP_PKEY *)key);
int result = 0;
+ if (!key_ptr)
+ goto err;
if (!params || !gkp) {
GOSTerr(GOST_F_ENCODE_GOST_ALGOR_PARAMS, ERR_R_MALLOC_FAILURE);
goto err;
}
- switch (EVP_PKEY_base_id(key)) {
+ switch (key_type) {
case NID_id_GostR3410_2012_256:
pkey_param_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(key_ptr));
switch (pkey_param_nid) {
return params;
}
-static int gost_decode_nid_params(EVP_PKEY *pkey, int pkey_nid, int param_nid)
+static ASN1_STRING *encode_gost_algor_params(const EVP_PKEY *key)
{
- void *key_ptr = EVP_PKEY_get0(pkey);
+ EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)key);
+ int key_type = (key == NULL) ? NID_undef : EVP_PKEY_base_id(key);
+
+ if (!ec)
+ return 0;
+ return internal_encode_algor_params(ec, key_type);
+}
+static int internal_is_gost_pkey_nid(int pkey_nid)
+{
switch (pkey_nid) {
case NID_id_GostR3410_2012_256:
case NID_id_GostR3410_2012_512:
case NID_id_GostR3410_2001:
case NID_id_GostR3410_2001DH:
- if (!key_ptr) {
- key_ptr = EC_KEY_new();
- if (!EVP_PKEY_assign(pkey, pkey_nid, key_ptr)) {
- EC_KEY_free(key_ptr);
- break;
- }
- }
- return fill_GOST_EC_params(key_ptr, param_nid);
+ return 1;
}
-
return 0;
}
* Parses GOST algorithm parameters from X509_ALGOR and modifies pkey setting
* NID and parameters
*/
-static int decode_gost_algor_params(EVP_PKEY *pkey,
+static int decode_gost_algor_params(EC_KEY *ec, int *key_type,
const X509_ALGOR *palg)
{
const ASN1_OBJECT *palg_obj = NULL;
const unsigned char *p;
GOST_KEY_PARAMS *gkp = NULL;
- if (!pkey || !palg)
+ if (!ec || !palg || !key_type)
return 0;
X509_ALGOR_get0(&palg_obj, &ptype, (const void **)&pval, palg);
if (ptype != V_ASN1_SEQUENCE) {
}
p = pval->data;
pkey_nid = OBJ_obj2nid(palg_obj);
-
+ if (!internal_is_gost_pkey_nid(pkey_nid))
+ return 0;
+ *key_type = pkey_nid;
gkp = d2i_GOST_KEY_PARAMS(NULL, &p, pval->length);
if (!gkp) {
GOSTerr(GOST_F_DECODE_GOST_ALGOR_PARAMS,
}
param_nid = OBJ_obj2nid(gkp->key_params);
GOST_KEY_PARAMS_free(gkp);
- if (!EVP_PKEY_set_type(pkey, pkey_nid)) {
- GOSTerr(GOST_F_DECODE_GOST_ALGOR_PARAMS, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- return gost_decode_nid_params(pkey, pkey_nid, param_nid);
+
+ return fill_GOST_EC_params(ec, param_nid);
}
-static int gost_set_priv_key(EVP_PKEY *pkey, BIGNUM *priv)
+static int gost_set_priv_key(EC_KEY *ec, BIGNUM *priv, int key_type)
{
- switch (EVP_PKEY_base_id(pkey)) {
+ switch (key_type) {
case NID_id_GostR3410_2012_512:
case NID_id_GostR3410_2012_256:
case NID_id_GostR3410_2001:
case NID_id_GostR3410_2001DH:
{
- EC_KEY *ec = EVP_PKEY_get0(pkey);
- if (!ec) {
- ec = EC_KEY_new();
- EVP_PKEY_assign(pkey, EVP_PKEY_base_id(pkey), ec);
- }
if (!EC_KEY_set_private_key(ec, priv))
return 0;
- if (!EVP_PKEY_missing_parameters(pkey))
- return gost_ec_compute_public(ec);
+ if (!gost_ec_compute_public(ec))
+ return 0;
+ if (!EC_KEY_check_key(ec))
+ return 0;
break;
}
default:
}
/* ------------------ private key functions -----------------------------*/
-
-static BIGNUM *unmask_priv_key(EVP_PKEY *pk,
- const unsigned char *buf, int len, int num_masks)
+static BIGNUM *internal_unmask_priv_key(const EC_KEY *key_ptr,
+ const unsigned char *buf, int len, int num_masks)
{
BIGNUM *pknum_masked = NULL, *q = NULL;
- const EC_KEY *key_ptr = (pk) ? EVP_PKEY_get0(pk) : NULL;
const EC_GROUP *group = (key_ptr) ? EC_KEY_get0_group(key_ptr) : NULL;
pknum_masked = BN_lebin2bn(buf, len, BN_secure_new());
return pknum_masked;
}
-static int priv_decode_gost(EVP_PKEY *pk,
- const PKCS8_PRIV_KEY_INFO *p8inf)
+int internal_priv_decode(EC_KEY *ec, int *key_type,
+ const PKCS8_PRIV_KEY_INFO *p8inf)
{
const unsigned char *pkey_buf = NULL, *p = NULL;
int priv_len = 0;
ASN1_INTEGER *priv_key = NULL;
int expected_key_len;
+ if (!key_type || !ec)
+ return 0;
if (!PKCS8_pkey_get0(&palg_obj, &pkey_buf, &priv_len, &palg, p8inf))
return 0;
p = pkey_buf;
- if (!decode_gost_algor_params(pk, palg)) {
+ if (!decode_gost_algor_params(ec, key_type, palg))
return 0;
- }
-
- expected_key_len = pkey_bits_gost(pk) > 0 ? pkey_bits_gost(pk) / 8 : 0;
+ expected_key_len = internal_pkey_bits(*key_type) > 0 ? internal_pkey_bits(*key_type) / 8 : 0;
if (expected_key_len == 0) {
GOSTerr(GOST_F_PRIV_DECODE_GOST, EVP_R_DECODE_ERROR);
return 0;
if (priv_len % expected_key_len == 0) {
/* Key is not wrapped but masked */
- pk_num = unmask_priv_key(pk, pkey_buf, expected_key_len,
- priv_len / expected_key_len - 1);
+ pk_num = internal_unmask_priv_key(ec, pkey_buf, expected_key_len,
+ priv_len / expected_key_len - 1);
} else if (V_ASN1_OCTET_STRING == *p) {
/* New format - Little endian octet string */
ASN1_OCTET_STRING *s = d2i_ASN1_OCTET_STRING(NULL, &p, priv_len);
return 0;
}
- pk_num = unmask_priv_key(pk, mgk->masked_priv_key->data,
- expected_key_len,
- priv_len / expected_key_len - 1);
+ pk_num = internal_unmask_priv_key(ec, mgk->masked_priv_key->data,
+ expected_key_len,
+ priv_len / expected_key_len - 1);
MASKED_GOST_KEY_free(mgk);
} else {
GOSTerr(GOST_F_PRIV_DECODE_GOST, EVP_R_DECODE_ERROR);
return 0;
}
- ret = gost_set_priv_key(pk, pk_num);
+ ret = gost_set_priv_key(ec, pk_num, *key_type);
BN_free(pk_num);
return ret;
}
-/* ----------------------------------------------------------------------*/
-static int priv_encode_gost(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk)
+static int priv_decode_gost(EVP_PKEY *pk, const PKCS8_PRIV_KEY_INFO *p8inf)
+{
+ int ret = 0;
+ int key_type = NID_undef;
+ EC_KEY *ec = NULL;
+
+ ec = EC_KEY_new();
+ if (!ec)
+ goto exit;
+ if (!internal_priv_decode(ec, &key_type, p8inf))
+ goto exit;
+ if (!EVP_PKEY_assign(pk, key_type, ec))
+ goto exit;
+ ret = 1;
+exit:
+ if (!ret)
+ EC_KEY_free(ec);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------- */
+int internal_priv_encode(PKCS8_PRIV_KEY_INFO *p8, EC_KEY *ec, int key_type)
{
- ASN1_OBJECT *algobj = OBJ_nid2obj(EVP_PKEY_base_id(pk));
+ ASN1_OBJECT *algobj = OBJ_nid2obj(key_type);
ASN1_STRING *params = NULL;
unsigned char *buf = NULL;
- int key_len = pkey_bits_gost(pk), i = 0;
+ int key_len = internal_pkey_bits(key_type), i = 0;
/* unmasked private key */
const char *pk_format = get_gost_engine_param(GOST_PARAM_PK_FORMAT);
+ if (!ec || !internal_is_gost_pkey_nid(key_type))
+ return 0;
+
key_len = (key_len < 0) ? 0 : key_len / 8;
if (key_len == 0 || !(buf = OPENSSL_secure_malloc(key_len))) {
return 0;
}
- if (!store_bignum(gost_get0_priv_key(pk), buf, key_len)) {
+ if (!store_bignum(EC_KEY_get0_private_key(ec), buf, key_len)) {
OPENSSL_secure_free(buf);
return 0;
}
- params = encode_gost_algor_params(pk);
+ params = internal_encode_algor_params(ec, key_type);
if (!params) {
OPENSSL_secure_free(buf);
return 0;
buf, key_len);
}
-/* --------- printing keys --------------------------------*/
-static int print_gost_priv(BIO *out, const EVP_PKEY *pkey, int indent)
+static int priv_encode_gost(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk)
+{
+ int key_type = (pk == NULL) ? NID_undef : EVP_PKEY_base_id(pk);
+ EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pk);
+
+ return internal_priv_encode(p8, ec, key_type);
+}
+
+/* --------- printing keys -------------------------------- */
+int internal_print_gost_priv(BIO *out, const EC_KEY *ec, int indent, int pkey_nid)
{
- BIGNUM *key;
+ const BIGNUM *key;
if (!BIO_indent(out, indent, 128))
return 0;
+
BIO_printf(out, "Private key: ");
- key = gost_get0_priv_key(pkey);
- if (!key)
+ key = ec ? EC_KEY_get0_private_key(ec) : NULL;
+ if (!key || !internal_is_gost_pkey_nid(pkey_nid))
BIO_printf(out, "<undefined>");
else
BN_print(out, key);
- BIO_printf(out, "\n");
+ BIO_printf(out, "\n");
return 1;
}
-static int print_gost_ec_pub(BIO *out, const EVP_PKEY *pkey, int indent)
+int internal_print_gost_ec_pub(BIO *out, const EC_KEY *ec, int indent, int pkey_nid)
{
- BN_CTX *ctx;
- BIGNUM *X, *Y;
- const EC_POINT *pubkey;
- const EC_GROUP *group;
- EC_KEY *key = (EC_KEY *)EVP_PKEY_get0((EVP_PKEY *)pkey);
- int ok = 0;
-
- ctx = BN_CTX_new();
- if (!ctx) {
- GOSTerr(GOST_F_PRINT_GOST_EC_PUB, ERR_R_MALLOC_FAILURE);
+ if (!ec)
return 0;
- }
+ if (!internal_is_gost_pkey_nid(pkey_nid))
+ return 0;
+
+ BN_CTX *ctx = BN_CTX_new();
+ BIGNUM *X = NULL, *Y = NULL;
+ const EC_POINT *pubkey = EC_KEY_get0_public_key(ec);
+ const EC_GROUP *group = EC_KEY_get0_group(ec);
+ int ret = 0;
+
+ if (!ctx || !pubkey || !group)
+ goto err;
BN_CTX_start(ctx);
X = BN_CTX_get(ctx);
Y = BN_CTX_get(ctx);
- pubkey = (key) ? EC_KEY_get0_public_key(key) : NULL;
- group = (key) ? EC_KEY_get0_group(key) : NULL;
- if (!pubkey || !group)
+ if (!X || !Y)
goto err;
- if (!EC_POINT_get_affine_coordinates(group, pubkey, X, Y, ctx)) {
- GOSTerr(GOST_F_PRINT_GOST_EC_PUB, ERR_R_EC_LIB);
+ if (!EC_POINT_get_affine_coordinates(group, pubkey, X, Y, ctx))
goto err;
- }
+
if (!BIO_indent(out, indent, 128))
goto err;
BIO_printf(out, "Public key:\n");
+
if (!BIO_indent(out, indent + 3, 128))
goto err;
BIO_printf(out, "X:");
BN_print(out, X);
BIO_printf(out, "\n");
+
if (!BIO_indent(out, indent + 3, 128))
goto err;
BIO_printf(out, "Y:");
BN_print(out, Y);
BIO_printf(out, "\n");
- ok = 1;
- err:
+
+ ret = 1;
+err:
BN_CTX_end(ctx);
BN_CTX_free(ctx);
-
- return ok;
+ return ret;
}
-static int print_gost_ec_param(BIO *out, const EVP_PKEY *pkey, int indent)
+int internal_print_gost_ec_param(BIO *out, const EC_KEY *ec, int indent)
{
- EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pkey);
- const EC_GROUP *group = (ec) ? EC_KEY_get0_group(ec) : NULL;
+ if (!ec)
+ return 0;
+
+ const EC_GROUP *group = EC_KEY_get0_group(ec);
int param_nid;
if (!group)
param_nid = EC_GROUP_get_curve_name(group);
if (!BIO_indent(out, indent, 128))
return 0;
- BIO_printf(out, "Parameter set: %s\n", OBJ_nid2ln(param_nid));
+ BIO_printf(out, "Parameter set: %s\n", OBJ_nid2ln(param_nid));
return 1;
}
static int print_gost_ec(BIO *out, const EVP_PKEY *pkey, int indent,
ASN1_PCTX *pctx, int type)
{
- if (type == 2) {
- if (print_gost_priv(out, pkey, indent) == 0)
- return 0;
- }
- if (type >= 1) {
- if (print_gost_ec_pub(out, pkey, indent) == 0)
- return 0;
- }
+ const EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pkey);
+ int pkey_nid = EVP_PKEY_base_id(pkey);
+
+ if (type == 2 && !internal_print_gost_priv(out, ec, indent, pkey_nid))
+ return 0;
+
+ if (type >= 1 && !internal_print_gost_ec_pub(out, ec, indent, pkey_nid))
+ return 0;
- return print_gost_ec_param(out, pkey, indent);
+ return internal_print_gost_ec_param(out, ec, indent);
}
static int param_print_gost_ec(BIO *out, const EVP_PKEY *pkey, int indent,
}
/* ---------- Public key functions * --------------------------------------*/
-static int pub_decode_gost_ec(EVP_PKEY *pk, const X509_PUBKEY *pub)
+int internal_pub_decode_ec(EC_KEY *ec, int *key_type, X509_ALGOR *palg,
+ const unsigned char *pubkey_buf, int pub_len)
{
- X509_ALGOR *palg = NULL;
- const unsigned char *pubkey_buf = NULL;
unsigned char *databuf = NULL;
- ASN1_OBJECT *palgobj = NULL;
- int pub_len;
EC_POINT *pub_key = NULL;
BIGNUM *X = NULL, *Y = NULL;
ASN1_OCTET_STRING *octet = NULL;
const EC_GROUP *group;
int retval = 0;
- if (!X509_PUBKEY_get0_param(&palgobj, &pubkey_buf, &pub_len, &palg, pub))
+ if (!key_type || !ec)
goto ret;
- EVP_PKEY_assign(pk, OBJ_obj2nid(palgobj), NULL);
- if (!decode_gost_algor_params(pk, palg))
+
+ if (!decode_gost_algor_params(ec, key_type, palg))
goto ret;
- group = EC_KEY_get0_group(EVP_PKEY_get0(pk));
+
+ group = EC_KEY_get0_group(ec);
octet = d2i_ASN1_OCTET_STRING(NULL, &pubkey_buf, pub_len);
if (!octet) {
GOSTerr(GOST_F_PUB_DECODE_GOST_EC, ERR_R_MALLOC_FAILURE);
goto ret;
}
- retval = EC_KEY_set_public_key(EVP_PKEY_get0(pk), pub_key);
+ retval = EC_KEY_set_public_key(ec, pub_key);
if (!retval)
GOSTerr(GOST_F_PUB_DECODE_GOST_EC, ERR_R_EC_LIB);
return retval;
}
-static int pub_encode_gost_ec(X509_PUBKEY *pub, const EVP_PKEY *pk)
+static int pub_decode_gost_ec(EVP_PKEY *pk, const X509_PUBKEY *pub)
{
- ASN1_OBJECT *algobj;
+ int ret = 0;
+ int key_type = NID_undef;
+ EC_KEY *ec = NULL;
+ ASN1_OBJECT *palgobj = NULL;
+ const unsigned char *pubkey_buf = NULL;
+ int pubkey_len = 0;
+ X509_ALGOR *palg = NULL;
+
+ if (!pub)
+ goto exit;
+
+ ec = EC_KEY_new();
+ if (!ec)
+ goto exit;
+
+ if (!X509_PUBKEY_get0_param(&palgobj, &pubkey_buf, &pubkey_len, &palg, pub))
+ goto exit;
+
+ if (!internal_pub_decode_ec(ec, &key_type, palg, pubkey_buf, pubkey_len))
+ goto exit;
+
+ if (!EVP_PKEY_assign(pk, key_type, ec))
+ goto exit;
+ ret = 1;
+exit:
+ if (!ret)
+ EC_KEY_free(ec);
+ return ret;
+}
+
+int internal_pub_encode_ec(X509_PUBKEY *pub, EC_KEY *ec, int key_type)
+{
+ ASN1_OBJECT *algobj = NULL;
ASN1_OCTET_STRING *octet = NULL;
- void *pval;
unsigned char *buf = NULL, *databuf = NULL;
- int data_len, ret = -1;
+ int data_len, buf_len, ret = 0;
const EC_POINT *pub_key;
- BIGNUM *X = NULL, *Y = NULL, *order;
- const EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pk);
+ BIGNUM *X = NULL, *Y = NULL, *order = NULL;
int ptype = V_ASN1_SEQUENCE;
- ASN1_STRING *params;
+ ASN1_STRING *params = NULL;
- algobj = OBJ_nid2obj(EVP_PKEY_base_id(pk));
+ if (!ec)
+ goto err;
- params = encode_gost_algor_params(pk);
- pval = params;
+ algobj = OBJ_nid2obj(key_type);
+ params = internal_encode_algor_params(ec, key_type);
+ if (!params) {
+ GOSTerr(GOST_F_PUB_ENCODE_GOST_EC, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
order = BN_new();
if (order == NULL || EC_GROUP_get_order(EC_KEY_get0_group(ec), order, NULL) == 0) {
goto err;
}
- ret = i2d_ASN1_OCTET_STRING(octet, &buf);
+ buf_len = i2d_ASN1_OCTET_STRING(octet, &buf);
+ if (buf_len < 0) {
+ GOSTerr(GOST_F_PUB_ENCODE_GOST_EC, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ ret = X509_PUBKEY_set0_param(pub, algobj, ptype, params, buf, buf_len);
+ if (!ret) {
+ GOSTerr(GOST_F_PUB_ENCODE_GOST_EC, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
err:
+ if (!ret) {
+ ASN1_STRING_free(params);
+ OPENSSL_free(buf);
+ }
ASN1_BIT_STRING_free(octet);
if (X)
BN_free(X);
if (databuf)
OPENSSL_free(databuf);
- if (ret < 0)
+ return ret;
+}
+
+static int pub_encode_gost_ec(X509_PUBKEY *pub, const EVP_PKEY *pk)
+{
+ EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pk);
+ int key_type = (pk == NULL) ? NID_undef : EVP_PKEY_base_id(pk);
+
+ if (!ec)
return 0;
- return X509_PUBKEY_set0_param(pub, algobj, ptype, pval, buf, ret);
+ return internal_pub_encode_ec(pub, ec, key_type);
}
static int pub_cmp_gost_ec(const EVP_PKEY *a, const EVP_PKEY *b)
return -2;
}
-static int gost2001_param_encode(const EVP_PKEY *pkey, unsigned char **pder)
+int internal_gost2001_param_encode(const EC_KEY *ec, unsigned char **pder)
{
- int nid =
- EC_GROUP_get_curve_name(EC_KEY_get0_group
- (EVP_PKEY_get0((EVP_PKEY *)pkey)));
+ int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
+
return i2d_ASN1_OBJECT(OBJ_nid2obj(nid), pder);
}
-static int gost2001_param_decode(EVP_PKEY *pkey, const unsigned char **pder,
- int derlen)
+static int gost2001_param_encode(const EVP_PKEY *pkey, unsigned char **pder)
+{
+ EC_KEY *ec = EVP_PKEY_get0(pkey);
+
+ if (!ec)
+ return 0;
+ return internal_gost2001_param_encode(ec, pder);
+}
+
+int internal_gost2001_param_decode(EC_KEY *ec, const unsigned char **pder,
+ int derlen)
{
ASN1_OBJECT *obj = NULL;
- int nid;
if (d2i_ASN1_OBJECT(&obj, pder, derlen) == NULL) {
return 0;
}
- nid = OBJ_obj2nid(obj);
+ int nid = OBJ_obj2nid(obj);
ASN1_OBJECT_free(obj);
- return gost_decode_nid_params(pkey, NID_id_GostR3410_2001, nid);
+ return fill_GOST_EC_params(ec, nid);
+}
+
+static int gost2001_param_decode(EVP_PKEY *pkey, const unsigned char **pder,
+ int derlen)
+{
+ int ret = 0;
+ int key_type = NID_id_GostR3410_2001;
+ EC_KEY *ec = NULL;
+
+ ec = EC_KEY_new();
+ if (!ec)
+ goto exit;
+ if (!internal_gost2001_param_decode(ec, pder, derlen))
+ goto exit;
+ if (!EVP_PKEY_assign(pkey, key_type, ec))
+ goto exit;
+ ret = 1;
+exit:
+ if (!ret)
+ EC_KEY_free(ec);
+ return ret;
}
/* ----------------------------------------------------------------------*/
if (!gost_cipher_set_param(&mctx->ks.g_ks, NID_id_tc26_gost_28147_param_Z))
return 0;
magma_key(&(mctx->ks.g_ks.cctx), key);
+ magma_master_key(&(mctx->ks.g_ks.cctx), key);
gost_mgm128_init(&mctx->mgm, &mctx->ks,
(block128_f) gost_magma_encrypt_wrap, gf64_mul, bl);
mctx->ivlen = ivlen;
mctx->iv = iv;
mctx->taglen = -1;
+ mctx->tlstree_mode = TLSTREE_MODE_NONE;
return 1;
case EVP_CTRL_GET_IVLEN:
memcpy(ptr, buf, arg);
return 1;
+ case EVP_CTRL_SET_TLSTREE_PARAMS:
+ if (strcmp((char *)ptr, "strong") == 0)
+ mctx->tlstree_mode = TLSTREE_MODE_S;
+ else if (strcmp((char *)ptr, "light") == 0)
+ mctx->tlstree_mode = TLSTREE_MODE_L;
+ else {
+ // TODO: set err
+ return 0;
+ }
+ return 1;
+
+ case EVP_CTRL_TLSTREE:
+ {
+ unsigned char newkey[32];
+ if (gost_tlstree(NID_magma_mgm,
+ (const unsigned char *)mctx->ks.g_ks.cctx.master_key,
+ newkey, (const unsigned char *)ptr, mctx->tlstree_mode)
+ > 0) {
+ magma_key(&mctx->ks.g_ks.cctx, newkey);
+ OPENSSL_cleanse(newkey, sizeof(newkey));
+ }
+ }
+ return 1;
+
default:
return -1;
}
}
if (gost_tlstree(NID_magma_cbc, (const unsigned char *)c->master_key, newkey,
- (const unsigned char *)seq) > 0) {
+ (const unsigned char *)seq, TLSTREE_MODE_NONE) > 0) {
memset(adjusted_iv, 0, 8);
memcpy(adjusted_iv, EVP_CIPHER_CTX_original_iv(ctx), 4);
for (j = 3, carry = 0; j >= 0; j--)
#include "gost_keywrap.h"
#include "gost_lcl.h"
-/* Implementation of CryptoPro VKO 34.10-2001/2012 algorithm */
-int VKO_compute_key(unsigned char *shared_key,
- const EC_POINT *pub_key, const EC_KEY *priv_key,
- const unsigned char *ukm, const size_t ukm_size,
- const int vko_dgst_nid)
+int internal_compute_ecdh(unsigned char *out, size_t *out_len,
+ const unsigned char *ukm, size_t ukm_size,
+ const EC_POINT *pub_key, const EC_KEY *priv_key)
{
- unsigned char *databuf = NULL;
- BIGNUM *scalar = NULL, *X = NULL, *Y = NULL;
+ BIGNUM *X = NULL, *Y = NULL;
const EC_GROUP *grp = NULL;
EC_POINT *pnt = NULL;
BN_CTX *ctx = NULL;
- EVP_MD_CTX *mdctx = NULL;
- const EVP_MD *md = NULL;
- int buf_len, half_len;
int ret = 0;
+ int half_len;
- if ((ctx = BN_CTX_secure_new()) == NULL) {
- GOSTerr(GOST_F_VKO_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
- return 0;
+ grp = EC_KEY_get0_group(priv_key);
+ half_len = BN_num_bytes(EC_GROUP_get0_field(grp));
+ if (out == NULL) {
+ *out_len = 2 * half_len;
+ ret = 1;
+ goto exit;
}
- BN_CTX_start(ctx);
- md = EVP_get_digestbynid(vko_dgst_nid);
- if (!md) {
- GOSTerr(GOST_F_VKO_COMPUTE_KEY, GOST_R_INVALID_DIGEST_TYPE);
- goto err;
- }
+ if (*out_len < 2 * half_len)
+ goto exit;
- grp = EC_KEY_get0_group(priv_key);
- scalar = BN_CTX_get(ctx);
+ if ((ctx = BN_CTX_secure_new()) == NULL)
+ goto exit;
+
+ BN_CTX_start(ctx);
X = BN_CTX_get(ctx);
+ Y = BN_CTX_get(ctx);
+ if (X == NULL || Y == NULL || (pnt = EC_POINT_new(grp)) == NULL)
+ goto exit;
- if ((Y = BN_CTX_get(ctx)) == NULL
- || (pnt = EC_POINT_new(grp)) == NULL
- || BN_lebin2bn(ukm, ukm_size, scalar) == NULL
- || !BN_mod_mul(scalar, scalar, EC_KEY_get0_private_key(priv_key),
- EC_GROUP_get0_order(grp), ctx))
- goto err;
+ if (BN_lebin2bn(ukm, ukm_size, X) == NULL)
+ goto exit;
-#if 0
- /*-
- * These two curves have cofactor 4; the rest have cofactor 1.
- * But currently gost_ec_point_mul takes care of the cofactor clearing,
- * hence this code is not needed.
- */
- switch (EC_GROUP_get_curve_name(grp)) {
- case NID_id_tc26_gost_3410_2012_256_paramSetA:
- case NID_id_tc26_gost_3410_2012_512_paramSetC:
- if (!BN_lshift(scalar, scalar, 2))
- goto err;
- break;
- }
-#endif
+ if (!BN_mod_mul(X, X, EC_KEY_get0_private_key(priv_key), EC_GROUP_get0_order(grp), ctx))
+ goto exit;
- if (!gost_ec_point_mul(grp, pnt, NULL, pub_key, scalar, ctx)) {
+ if (!gost_ec_point_mul(grp, pnt, NULL, pub_key, X, ctx)) {
GOSTerr(GOST_F_VKO_COMPUTE_KEY, GOST_R_ERROR_POINT_MUL);
- goto err;
+ goto exit;
}
if (!EC_POINT_get_affine_coordinates(grp, pnt, X, Y, ctx)) {
GOSTerr(GOST_F_VKO_COMPUTE_KEY, ERR_R_EC_LIB);
- goto err;
+ goto exit;
}
+ if ((BN_bn2lebinpad(X, out, half_len) == -1)
+ || (BN_bn2lebinpad(Y, out + half_len, half_len) == -1))
+ goto exit;
- half_len = BN_num_bytes(EC_GROUP_get0_field(grp));
- buf_len = 2 * half_len;
- if ((databuf = OPENSSL_malloc(buf_len)) == NULL) {
+ *out_len = 2 * half_len;
+ ret = 1;
+exit:
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ EC_POINT_free(pnt);
+ return ret;
+}
+
+/* Implementation of CryptoPro VKO 34.10-2001/2012 algorithm */
+
+int VKO_compute_key(unsigned char *shared_key,
+ const EC_POINT *pub_key, const EC_KEY *priv_key,
+ const unsigned char *ukm, const size_t ukm_size,
+ const int vko_dgst_nid)
+{
+ unsigned char *ecdh_secret = NULL;
+ size_t secret_len = 0;
+ EVP_MD_CTX *mdctx = NULL;
+ const EVP_MD *md = NULL;
+ int ret = 0;
+
+ md = EVP_get_digestbynid(vko_dgst_nid);
+ if (!md) {
+ GOSTerr(GOST_F_VKO_COMPUTE_KEY, GOST_R_INVALID_DIGEST_TYPE);
+ goto exit;
+ }
+
+ if (internal_compute_ecdh(NULL, &secret_len, ukm, ukm_size,
+ pub_key, priv_key) == 0)
+ goto exit;
+
+ if ((ecdh_secret = OPENSSL_malloc(secret_len)) == NULL) {
GOSTerr(GOST_F_VKO_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
- goto err;
+ goto exit;
}
- /*
- * Serialize elliptic curve point same way as we do it when saving key
- */
- if (BN_bn2lebinpad(X, databuf, half_len) != half_len
- || BN_bn2lebinpad(Y, databuf + half_len, half_len) != half_len)
- goto err;
+ if (internal_compute_ecdh(ecdh_secret, &secret_len, ukm, ukm_size,
+ pub_key, priv_key) == 0)
+ goto exit;
if ((mdctx = EVP_MD_CTX_new()) == NULL) {
GOSTerr(GOST_F_VKO_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
- goto err;
+ goto exit;
}
- if (EVP_MD_CTX_init(mdctx) == 0
- || EVP_DigestInit_ex(mdctx, md, NULL) == 0
- || EVP_DigestUpdate(mdctx, databuf, buf_len) == 0
+ if (EVP_DigestInit_ex(mdctx, md, NULL) == 0
+ || EVP_DigestUpdate(mdctx, ecdh_secret, secret_len) == 0
|| EVP_DigestFinal_ex(mdctx, shared_key, NULL) == 0) {
GOSTerr(GOST_F_VKO_COMPUTE_KEY, ERR_R_EVP_LIB);
- goto err;
+ goto exit;
}
ret = (EVP_MD_size(md) > 0) ? EVP_MD_size(md) : 0;
+exit:
- err:
- BN_CTX_end(ctx);
- BN_CTX_free(ctx);
- EC_POINT_free(pnt);
EVP_MD_CTX_free(mdctx);
- OPENSSL_free(databuf);
+ OPENSSL_free(ecdh_secret);
return ret;
}
#include "e_gost_err.h"
#include "gost_lcl.h"
#include "gost-engine.h"
+#include <assert.h>
#include "gost_grasshopper_cipher.h"
if (!register_pmeth_gost(minfo->nid, minfo->pmeth, 0))
goto end;
}
+ int i;
+
+ for (i = 0; i < OSSL_NELEM(gost_digest_array); i++) {
+ const EVP_MD *md = GOST_init_digest(gost_digest_array[i]);
+
+ if (!EVP_add_digest(md))
+ goto end;
+
+ assert(EVP_get_digestbynid(gost_digest_array[i]->nid) != NULL);
+ }
ret = 1;
end:
if (key) {
bl = EVP_CIPHER_CTX_iv_length(ctx);
gost_grasshopper_cipher_key(&mctx->ks.gh_ks, key);
+ gost_grasshopper_master_key(&mctx->ks.gh_ks, key);
gost_mgm128_init(&mctx->mgm, &mctx->ks,
(block128_f) gost_grasshopper_encrypt_wrap, gf128_mul_uint64, bl);
mctx->ivlen = ivlen;
mctx->iv = iv;
mctx->taglen = -1;
+ mctx->tlstree_mode = TLSTREE_MODE_NONE;
return 1;
case EVP_CTRL_GET_IVLEN:
memcpy(ptr, buf, arg);
return 1;
+ case EVP_CTRL_SET_TLSTREE_PARAMS:
+ if (strcmp((char *)ptr, "strong") == 0)
+ mctx->tlstree_mode = TLSTREE_MODE_S;
+ else if (strcmp((char *)ptr, "light") == 0)
+ mctx->tlstree_mode = TLSTREE_MODE_L;
+ else {
+ // TODO: set err
+ return 0;
+ }
+ return 1;
+
+ case EVP_CTRL_TLSTREE:
+ {
+ unsigned char newkey[32];
+ if (gost_tlstree(NID_kuznyechik_mgm,
+ mctx->ks.gh_ks.master_key.k.b, newkey,
+ (const unsigned char *)ptr, mctx->tlstree_mode)
+ > 0) {
+ gost_grasshopper_cipher_key(&mctx->ks.gh_ks, newkey);
+ OPENSSL_cleanse(newkey, sizeof(newkey));
+ }
+ }
+ return 1;
+
default:
return -1;
}
}
if (gost_tlstree(NID_grasshopper_cbc, c->master_key.k.b, newkey,
- (const unsigned char *)seq) > 0) {
+ (const unsigned char *)seq, TLSTREE_MODE_NONE) > 0) {
memset(adjusted_iv, 0, 16);
memcpy(adjusted_iv, EVP_CIPHER_CTX_original_iv(ctx), 8);
for(j=7,carry=0; j>=0; j--)
}
int gost_tlstree(int cipher_nid, const unsigned char *in, unsigned char *out,
- const unsigned char *tlsseq)
+ const unsigned char *tlsseq, int mode)
{
- uint64_t gh_c1 = 0x00000000FFFFFFFF, gh_c2 = 0x0000F8FFFFFFFFFF,
- gh_c3 = 0xC0FFFFFFFFFFFFFF;
- uint64_t mg_c1 = 0x00000000C0FFFFFF, mg_c2 = 0x000000FEFFFFFFFF,
- mg_c3 = 0x00F0FFFFFFFFFFFF;
uint64_t c1, c2, c3;
uint64_t seed1, seed2, seed3;
uint64_t seq;
switch (cipher_nid) {
case NID_magma_cbc:
- c1 = mg_c1;
- c2 = mg_c2;
- c3 = mg_c3;
+ c1 = 0x00000000C0FFFFFF;
+ c2 = 0x000000FEFFFFFFFF;
+ c3 = 0x00F0FFFFFFFFFFFF;
break;
case NID_grasshopper_cbc:
- c1 = gh_c1;
- c2 = gh_c2;
- c3 = gh_c3;
+ c1 = 0x00000000FFFFFFFF;
+ c2 = 0x0000F8FFFFFFFFFF;
+ c3 = 0xC0FFFFFFFFFFFFFF;
+ break;
+ case NID_magma_mgm:
+ switch (mode) {
+ case TLSTREE_MODE_S: // TLS_GOSTR341112_256_WITH_MAGMA_MGM_S
+ c1 = 0x000000fcffffffff;
+ c2 = 0x00e0ffffffffffff;
+ c3 = 0xffffffffffffffff;
+ break;
+ case TLSTREE_MODE_L: // TLS_GOSTR341112_256_WITH_MAGMA_MGM_L
+ c1 = 0x000000000000e0ff;
+ c2 = 0x000000c0ffffffff;
+ c3 = 0x80ffffffffffffff;
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case NID_kuznyechik_mgm:
+ switch (mode) {
+ case TLSTREE_MODE_S: // TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S
+ c1 = 0x000000e0ffffffff;
+ c2 = 0x0000ffffffffffff;
+ c3 = 0xf8ffffffffffffff;
+ break;
+ case TLSTREE_MODE_L: // TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L
+ c1 = 0x00000000000000f8;
+ c2 = 0x00000000f0ffffff;
+ c3 = 0x00e0ffffffffffff;
+ break;
+ default:
+ return 0;
+ }
break;
default:
return 0;
# include <openssl/asn1.h>
# include "gost89.h"
# include "gosthash.h"
+
+/*
+ * This definitions are added in the patch to OpenSSL 3.4.2 version to support
+ * GOST TLS 1.3. Definitions below must be removed when the patch is added to
+ * OpenSSL upstream.
+ */
+# ifndef EVP_CTRL_SET_TLSTREE_PARAMS
+# if defined(_MSC_VER)
+# pragma message("Gost-engine is built against not fully supported version of OpenSSL. \
+EVP_CTRL_SET_TLSTREE_PARAMS definition in OpenSSL is expected.")
+# else
+# warning "Gost-engine is built against not fully supported version of OpenSSL. \
+EVP_CTRL_SET_TLSTREE_PARAMS definition in OpenSSL is expected."
+# endif
+# define EVP_CTRL_SET_TLSTREE_PARAMS 0xFF
+# endif
+
+# ifndef NID_magma_mgm
+# if defined(_MSC_VER)
+# pragma message("Gost-engine is built against not fully supported version of OpenSSL. \
+NID_magma_mgm definition in OpenSSL is expected. No magma mgm functionality is \
+guaranteed.")
+# else
+# warning "Gost-engine is built against not fully supported version of OpenSSL. \
+NID_magma_mgm definition in OpenSSL is expected. No magma mgm functionality is \
+guaranteed."
+# endif
+# define NID_magma_mgm ((int)(INT_MAX - 1))
+# endif
+
+# ifndef NID_kuznyechik_mgm
+# if defined(_MSC_VER)
+# pragma message("Gost-engine is built against not fully supported version of OpenSSL. \
+NID_kuznyechik_mgm definition in OpenSSL is expected. No magma mgm functionality is \
+guaranteed.")
+# else
+# warning "Gost-engine is built against not fully supported version of OpenSSL. \
+NID_kuznyechik_mgm definition in OpenSSL is expected. No kuznyechik mgm functionality is \
+guaranteed."
+# endif
+# define NID_kuznyechik_mgm ((int)(INT_MAX - 2))
+# endif
+
/* Control commands */
# define GOST_PARAM_CRYPT_PARAMS 0
# define GOST_PARAM_PBE_PARAMS 1
void gost_param_free(void);
/* method registration */
-
-/* Provider implementation data */
-extern const OSSL_ALGORITHM GOST_prov_macs[];
-void GOST_prov_deinit_mac_digests(void);
-
int register_ameth_gost(int nid, EVP_PKEY_ASN1_METHOD **ameth,
const char *pemstr, const char *info);
int register_pmeth_gost(int id, EVP_PKEY_METHOD **pmeth, int flags);
# define EVP_PKEY_CTRL_GOST_MAC_HEXKEY (EVP_PKEY_ALG_CTRL+3)
# define EVP_PKEY_CTRL_MAC_LEN (EVP_PKEY_ALG_CTRL+5)
# define EVP_PKEY_CTRL_SET_VKO (EVP_PKEY_ALG_CTRL+11)
+# define TLSTREE_MODE_NONE 0
+# define TLSTREE_MODE_S 1
+# define TLSTREE_MODE_L 2
/* Pmeth internal representation */
struct gost_pmeth_data {
int sign_param_nid; /* Should be set whenever parameters are
const size_t representation);
int gost_tlstree(int cipher_nid, const unsigned char *in, unsigned char *out,
- const unsigned char *tlsseq);
+ const unsigned char *tlsseq, int mode);
/* KExp/KImp */
int gost_kexp15(const unsigned char *shared_key, const int shared_len,
int cipher_nid, const unsigned char *cipher_key,
extern GOST_cipher magma_kexp15_cipher;
extern GOST_cipher kuznyechik_kexp15_cipher;
-/* Provider implementation data */
-extern const OSSL_ALGORITHM GOST_prov_ciphers[];
-void GOST_prov_deinit_ciphers(void);
struct gost_digest_st {
struct gost_digest_st *template;
EVP_MD *GOST_init_digest(GOST_digest *d);
void GOST_deinit_digest(GOST_digest *d);
+/* Internal functions */
+EC_KEY * internal_ec_paramgen(int sign_param_nid);
+int internal_ec_ctrl(struct gost_pmeth_data *pctx, int pkey_nid,
+ int type, int p1, void *p2);
+int internal_ec_ctrl_str_common(struct gost_pmeth_data *ctx, int key_type,
+ const char *type, const char *value);
+int internal_ec_ctrl_str_256(struct gost_pmeth_data *ctx, int key_type,
+ const char *type, const char *value);
+int internal_ec_ctrl_str_512(struct gost_pmeth_data *ctx, int key_type,
+ const char *type, const char *value);
+int internal_priv_decode(EC_KEY *ec, int *key_type,
+ const PKCS8_PRIV_KEY_INFO *p8inf);
+int internal_priv_encode(PKCS8_PRIV_KEY_INFO *p8,
+ EC_KEY *ec, int key_type);
+int internal_pub_decode_ec(EC_KEY *ec, int *key_type, X509_ALGOR *palg,
+ const unsigned char *pubkey_buf, int pub_len);
+int internal_pub_encode_ec(X509_PUBKEY *pub, EC_KEY *ec, int key_type);
+int internal_gost2001_param_decode(EC_KEY *ec, const unsigned char **pder,
+ int derlen);
+int internal_gost2001_param_encode(const EC_KEY *ec, unsigned char **pder);
+int internal_pkey_ec_cp_sign(EC_KEY *ec, int key_type, unsigned char *sig,
+ size_t *siglen, const unsigned char *tbs,
+ size_t tbs_len);
+int internal_pkey_ec_cp_verify(EC_KEY *ec, const unsigned char *sig,
+ size_t siglen, const unsigned char *tbs,
+ size_t tbs_len);
+int internal_param_str_to_nid_256(const char *value, int *param_nid_ptr);
+int internal_param_str_to_nid_512(const char *value, int *param_nid_ptr);
+int internal_compute_ecdh(unsigned char *out, size_t *out_len,
+ const unsigned char *ukm, const size_t ukm_size,
+ const EC_POINT *pub_key, const EC_KEY *priv_key);
+int internal_print_gost_priv(BIO *out, const EC_KEY *ec, int indent, int pkey_nid);
+int internal_print_gost_ec_pub(BIO *out, const EC_KEY *ec, int indent, int pkey_nid);
+int internal_print_gost_ec_param(BIO *out, const EC_KEY *ec, int indent);
+
/* ENGINE implementation data */
extern GOST_digest GostR3411_94_digest;
extern GOST_digest Gost28147_89_MAC_digest;
extern GOST_digest kuznyechik_ctracpkm_omac_digest;
extern GOST_digest magma_ctracpkm_omac_digest;
-/* Provider implementation data */
-extern const OSSL_ALGORITHM GOST_prov_digests[];
-void GOST_prov_deinit_digests(void);
/* job to initialize a missing NID */
struct gost_nid_job {
int ret = 0;
if (gost_tlstree(OBJ_txt2nid(c->cipher_name),
c->key, diversed_key,
- (const unsigned char *)ptr)) {
+ (const unsigned char *)ptr, TLSTREE_MODE_NONE)) {
EVP_CIPHER *cipher;
if ((cipher = (EVP_CIPHER *)EVP_get_cipherbyname(c->cipher_name))
|| (cipher = EVP_CIPHER_fetch(NULL, c->cipher_name, NULL)))
OPENSSL_free(data);
}
-/* --------------------- control functions ------------------------------*/
-static int pkey_gost_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
+/* --------------------- control functions internal ------------------------------ */
+int internal_ec_ctrl(struct gost_pmeth_data *pctx, int pkey_nid,
+ int type, int p1, void *p2)
{
- struct gost_pmeth_data *pctx =
- (struct gost_pmeth_data *)EVP_PKEY_CTX_get_data(ctx);
- if (pctx == NULL)
- return 0;
-
switch (type) {
case EVP_PKEY_CTRL_MD:
{
- EVP_PKEY *key = EVP_PKEY_CTX_get0_pkey(ctx);
- int pkey_nid = (key == NULL) ? NID_undef : EVP_PKEY_base_id(key);
-
OPENSSL_assert(p2 != NULL);
switch (EVP_MD_type((const EVP_MD *)p2)) {
return -2;
}
-static int pkey_gost_ec_ctrl_str_common(EVP_PKEY_CTX *ctx,
- const char *type, const char *value)
+int internal_ec_ctrl_str_common(struct gost_pmeth_data *ctx, int key_type,
+ const char *type, const char *value)
{
- if (0 == strcmp(type, ukm_ctrl_string)) {
- unsigned char ukm_buf[32], *tmp = NULL;
- long len = 0;
- tmp = OPENSSL_hexstr2buf(value, &len);
- if (tmp == NULL)
- return 0;
-
- if (len > 32) {
- OPENSSL_free(tmp);
- GOSTerr(GOST_F_PKEY_GOST_EC_CTRL_STR_COMMON, GOST_R_CTRL_CALL_FAILED);
- return 0;
+ if (strcmp(type, ukm_ctrl_string) == 0) {
+ unsigned char ukm_buf[32], *tmp = NULL;
+ long len = 0;
+
+ tmp = OPENSSL_hexstr2buf(value, &len);
+ if (tmp == NULL)
+ return 0;
+ if (len > 32) {
+ OPENSSL_free(tmp);
+ GOSTerr(GOST_F_PKEY_GOST_EC_CTRL_STR_COMMON, GOST_R_CTRL_CALL_FAILED);
+ return 0;
+ }
+ memcpy(ukm_buf, tmp, len);
+ OPENSSL_free(tmp);
+ return internal_ec_ctrl(ctx, key_type, EVP_PKEY_CTRL_SET_IV, len, ukm_buf);
+ } else if (strcmp(type, vko_ctrl_string) == 0) {
+ int bits = atoi(value);
+ int vko_dgst_nid = 0;
+
+ if (bits == 256) {
+ vko_dgst_nid = NID_id_GostR3411_2012_256;
+ } else if (bits == 512) {
+ vko_dgst_nid = NID_id_GostR3411_2012_512;
+ } else if (bits != 0) {
+ GOSTerr(GOST_F_PKEY_GOST_EC_CTRL_STR_COMMON, GOST_R_INVALID_DIGEST_TYPE);
+ return 0;
+ }
+ return internal_ec_ctrl(ctx, key_type, EVP_PKEY_CTRL_SET_VKO, vko_dgst_nid, NULL);
}
- memcpy(ukm_buf, tmp, len);
- OPENSSL_free(tmp);
-
- return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_SET_IV, len, ukm_buf);
- } else if (strcmp(type, vko_ctrl_string) == 0) {
- int bits = atoi(value);
- int vko_dgst_nid = 0;
-
- if (bits == 256)
- vko_dgst_nid = NID_id_GostR3411_2012_256;
- else if (bits == 512)
- vko_dgst_nid = NID_id_GostR3411_2012_512;
- else if (bits != 0) {
- GOSTerr(GOST_F_PKEY_GOST_EC_CTRL_STR_COMMON, GOST_R_INVALID_DIGEST_TYPE);
- return 0;
- }
- return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_SET_VKO, vko_dgst_nid, NULL);
- }
- return -2;
+ return -2;
}
-static int pkey_gost_ec_ctrl_str_256(EVP_PKEY_CTX *ctx,
- const char *type, const char *value)
+int internal_ec_ctrl_str_256(struct gost_pmeth_data *ctx, int key_type,
+ const char *type, const char *value)
{
- if (strcmp(type, param_ctrl_string) == 0) {
- int param_nid = 0;
+ if (strcmp(type, param_ctrl_string))
+ return internal_ec_ctrl_str_common(ctx, key_type, type, value);
+
+ int param_nid = NID_undef;
- if (!value) {
+ if (!internal_param_str_to_nid_256(value, ¶m_nid))
+ return 0;
+
+ return internal_ec_ctrl(ctx, key_type, EVP_PKEY_CTRL_GOST_PARAMSET,
+ param_nid, NULL);
+}
+
+int internal_param_str_to_nid_256(const char *value, int *param_nid_ptr)
+{
+ if (!value)
+ return 0;
+
+ int param_nid = NID_undef;
+
+ if (strlen(value) == 1) {
+ switch (toupper((unsigned char)value[0])) {
+ case 'A':
+ param_nid = NID_id_GostR3410_2001_CryptoPro_A_ParamSet;
+ break;
+ case 'B':
+ param_nid = NID_id_GostR3410_2001_CryptoPro_B_ParamSet;
+ break;
+ case 'C':
+ param_nid = NID_id_GostR3410_2001_CryptoPro_C_ParamSet;
+ break;
+ case '0':
+ param_nid = NID_id_GostR3410_2001_TestParamSet;
+ break;
+ default:
+ return 0;
+ }
+ } else if ((strlen(value) == 2)
+ && (toupper((unsigned char)value[0]) == 'X')) {
+ switch (toupper((unsigned char)value[1])) {
+ case 'A':
+ param_nid = NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet;
+ break;
+ case 'B':
+ param_nid = NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet;
+ break;
+ default:
return 0;
}
- if (strlen(value) == 1) {
- switch (toupper((unsigned char)value[0])) {
- case 'A':
- param_nid = NID_id_GostR3410_2001_CryptoPro_A_ParamSet;
- break;
- case 'B':
- param_nid = NID_id_GostR3410_2001_CryptoPro_B_ParamSet;
- break;
- case 'C':
- param_nid = NID_id_GostR3410_2001_CryptoPro_C_ParamSet;
- break;
- case '0':
- param_nid = NID_id_GostR3410_2001_TestParamSet;
- break;
- default:
- return 0;
- }
- } else if ((strlen(value) == 2)
- && (toupper((unsigned char)value[0]) == 'X')) {
- switch (toupper((unsigned char)value[1])) {
- case 'A':
- param_nid = NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet;
- break;
- case 'B':
- param_nid = NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet;
- break;
- default:
- return 0;
- }
} else if ((strlen(value) == 3)
&& (toupper((unsigned char)value[0]) == 'T')
&& (toupper((unsigned char)value[1]) == 'C')) {
- switch (toupper((unsigned char)value[2])) {
- case 'A':
- param_nid = NID_id_tc26_gost_3410_2012_256_paramSetA;
- break;
- case 'B':
- param_nid = NID_id_tc26_gost_3410_2012_256_paramSetB;
- break;
- case 'C':
- param_nid = NID_id_tc26_gost_3410_2012_256_paramSetC;
- break;
- case 'D':
- param_nid = NID_id_tc26_gost_3410_2012_256_paramSetD;
- break;
- default:
- return 0;
- }
- } else {
- R3410_ec_params *p = R3410_2001_paramset;
- param_nid = OBJ_txt2nid(value);
- if (param_nid == NID_undef) {
- return 0;
- }
- for (; p->nid != NID_undef; p++) {
- if (p->nid == param_nid)
- break;
- }
- if (p->nid == NID_undef) {
- GOSTerr(GOST_F_PKEY_GOST_EC_CTRL_STR_256,
- GOST_R_INVALID_PARAMSET);
- return 0;
- }
+ switch (toupper((unsigned char)value[2])) {
+ case 'A':
+ param_nid = NID_id_tc26_gost_3410_2012_256_paramSetA;
+ break;
+ case 'B':
+ param_nid = NID_id_tc26_gost_3410_2012_256_paramSetB;
+ break;
+ case 'C':
+ param_nid = NID_id_tc26_gost_3410_2012_256_paramSetC;
+ break;
+ case 'D':
+ param_nid = NID_id_tc26_gost_3410_2012_256_paramSetD;
+ break;
+ default:
+ return 0;
}
+ } else {
+ R3410_ec_params *p = R3410_2001_paramset;
- return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
- param_nid, NULL);
+ param_nid = OBJ_txt2nid(value);
+ if (param_nid == NID_undef)
+ return 0;
+
+ for (; p->nid != NID_undef; p++) {
+ if (p->nid == param_nid)
+ break;
+ }
+ if (p->nid == NID_undef) {
+ GOSTerr(GOST_F_PKEY_GOST_EC_CTRL_STR_256,
+ GOST_R_INVALID_PARAMSET);
+ return 0;
+ }
}
- return pkey_gost_ec_ctrl_str_common(ctx, type, value);
+ *param_nid_ptr = param_nid;
+
+ return 1;
}
-static int pkey_gost_ec_ctrl_str_512(EVP_PKEY_CTX *ctx,
- const char *type, const char *value)
+int internal_ec_ctrl_str_512(struct gost_pmeth_data *ctx, int key_type,
+ const char *type, const char *value)
{
+ if (strcmp(type, param_ctrl_string))
+ return internal_ec_ctrl_str_common(ctx, key_type, type, value);
+
int param_nid = NID_undef;
+ if (!internal_param_str_to_nid_512(value, ¶m_nid))
+ return 0;
- if (strcmp(type, param_ctrl_string))
- return pkey_gost_ec_ctrl_str_common(ctx, type, value);
+ return internal_ec_ctrl(ctx, key_type, EVP_PKEY_CTRL_GOST_PARAMSET, param_nid, NULL);
+}
+int internal_param_str_to_nid_512(const char *value, int *param_nid_ptr)
+{
if (!value)
return 0;
+ int param_nid = NID_undef;
+
if (strlen(value) == 1) {
switch (toupper((unsigned char)value[0])) {
case 'A':
}
}
- return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET, param_nid, NULL);
+ *param_nid_ptr = param_nid;
+
+ return 1;
+}
+
+/* --------------------- control functions pkey ------------------------------ */
+static int pkey_gost_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
+{
+ struct gost_pmeth_data *pctx =
+ (struct gost_pmeth_data *)EVP_PKEY_CTX_get_data(ctx);
+
+ if (pctx == NULL)
+ return 0;
+ EVP_PKEY *key = EVP_PKEY_CTX_get0_pkey(ctx);
+ int key_type = (key == NULL) ? NID_undef : EVP_PKEY_base_id(key);
+ return internal_ec_ctrl(pctx, key_type, type, p1, p2);
+}
+
+static int pkey_gost_ec_ctrl_str_256(EVP_PKEY_CTX *ctx,
+ const char *type, const char *value)
+{
+ struct gost_pmeth_data *pctx =
+ (struct gost_pmeth_data *)EVP_PKEY_CTX_get_data(ctx);
+
+ if (pctx == NULL)
+ return 0;
+ EVP_PKEY *key = EVP_PKEY_CTX_get0_pkey(ctx);
+ int key_type = (key == NULL) ? NID_undef : EVP_PKEY_base_id(key);
+ return internal_ec_ctrl_str_256(pctx, key_type, type, value);
+}
+
+static int pkey_gost_ec_ctrl_str_512(EVP_PKEY_CTX *ctx,
+ const char *type, const char *value)
+{
+ struct gost_pmeth_data *pctx =
+ (struct gost_pmeth_data *)EVP_PKEY_CTX_get_data(ctx);
+
+ if (pctx == NULL)
+ return 0;
+ EVP_PKEY *key = EVP_PKEY_CTX_get0_pkey(ctx);
+ int key_type = (key == NULL) ? NID_undef : EVP_PKEY_base_id(key);
+ return internal_ec_ctrl_str_512(pctx, key_type, type, value);
}
/* --------------------- key generation --------------------------------*/
return 1;
}
+EC_KEY *internal_ec_paramgen(int sign_param_nid)
+{
+ EC_KEY *ec = EC_KEY_new();
+
+ if (!fill_GOST_EC_params(ec, sign_param_nid)) {
+ EC_KEY_free(ec);
+ return NULL;
+ }
+
+ return ec;
+}
+
static int pkey_gost2001_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
{
struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
return 0;
}
- ec = EC_KEY_new();
- if (!fill_GOST_EC_params(ec, data->sign_param_nid)
- || !EVP_PKEY_assign(pkey, NID_id_GostR3410_2001, ec)) {
+ ec = internal_ec_paramgen(data->sign_param_nid);
+
+ if (!ec)
+ return 0;
+
+ if (!EVP_PKEY_assign(pkey, NID_id_GostR3410_2001, ec)) {
EC_KEY_free(ec);
return 0;
}
return 0;
}
- ec = EC_KEY_new();
- if (!fill_GOST_EC_params(ec, data->sign_param_nid)) {
- EC_KEY_free(ec);
+ ec = internal_ec_paramgen(data->sign_param_nid);
+
+ if (!ec)
return 0;
- }
switch (data->sign_param_nid) {
case NID_id_tc26_gost_3410_2012_512_paramSetA:
return 1;
}
-static int pkey_gost_ec_cp_sign(EVP_PKEY_CTX *ctx, unsigned char *sig,
- size_t *siglen, const unsigned char *tbs,
- size_t tbs_len)
+int internal_pkey_ec_cp_sign(EC_KEY *ec, int key_type, unsigned char *sig,
+ size_t *siglen, const unsigned char *tbs,
+ size_t tbs_len)
{
ECDSA_SIG *unpacked_sig = NULL;
- EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
int order = 0;
- if (!siglen)
- return 0;
- if (!pkey)
+ if (!siglen || !ec)
return 0;
- switch (EVP_PKEY_base_id(pkey)) {
+ switch (key_type) {
case NID_id_GostR3410_2001:
case NID_id_GostR3410_2001DH:
case NID_id_GostR3410_2012_256:
*siglen = order;
return 1;
}
- unpacked_sig = gost_ec_sign(tbs, tbs_len, EVP_PKEY_get0(pkey));
+
+ if (*siglen < order)
+ return 0;
+
+ unpacked_sig = gost_ec_sign(tbs, tbs_len, ec);
if (!unpacked_sig) {
return 0;
}
return pack_sign_cp(unpacked_sig, order / 2, sig, siglen);
}
-/* ------------------- verify callbacks ---------------------------*/
+static int pkey_gost_ec_cp_sign(EVP_PKEY_CTX *ctx, unsigned char *sig,
+ size_t *siglen, const unsigned char *tbs,
+ size_t tbs_len)
+{
+ EVP_PKEY *pkey = NULL;
+ EC_KEY *ec = NULL;
+ int key_type = NID_undef;
+
+ pkey = EVP_PKEY_CTX_get0_pkey(ctx);
+ ec = EVP_PKEY_get0(pkey);
+ key_type = (pkey == NULL) ? NID_undef : EVP_PKEY_base_id(pkey);
+ if (!pkey || !ec)
+ return 0;
+
+ return internal_pkey_ec_cp_sign(ec, key_type, sig, siglen, tbs, tbs_len);
+}
+
+/* ------------------- verify callbacks --------------------------- */
/* Unpack signature according to cryptopro rules */
ECDSA_SIG *unpack_cp_signature(const unsigned char *sigbuf, size_t siglen)
{
return sig;
}
-static int pkey_gost_ec_cp_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
- size_t siglen, const unsigned char *tbs,
- size_t tbs_len)
+int internal_pkey_ec_cp_verify(EC_KEY *ec, const unsigned char *sig,
+ size_t siglen, const unsigned char *tbs,
+ size_t tbs_len)
{
int ok = 0;
- EVP_PKEY *pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
- ECDSA_SIG *s = (sig) ? unpack_cp_signature(sig, siglen) : NULL;
+ ECDSA_SIG *s = NULL;
+
+ if (!ec)
+ return 0;
+
+ s = (sig) ? unpack_cp_signature(sig, siglen) : NULL;
if (!s)
return 0;
+
#ifdef DEBUG_SIGN
fprintf(stderr, "R=");
BN_print_fp(stderr, ECDSA_SIG_get0_r(s));
BN_print_fp(stderr, ECDSA_SIG_get0_s(s));
fprintf(stderr, "\n");
#endif
- if (pub_key)
- ok = gost_ec_verify(tbs, tbs_len, s, EVP_PKEY_get0(pub_key));
+ ok = gost_ec_verify(tbs, tbs_len, s, ec);
ECDSA_SIG_free(s);
return ok;
}
-/* ------------- encrypt init -------------------------------------*/
+static int pkey_gost_ec_cp_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
+ size_t siglen, const unsigned char *tbs,
+ size_t tbs_len)
+{
+ EVP_PKEY *pkey = NULL;
+ EC_KEY *ec = NULL;
+
+ pkey = EVP_PKEY_CTX_get0_pkey(ctx);
+ ec = EVP_PKEY_get0(pkey);
+ if (!pkey || !ec)
+ return 0;
+
+ return internal_pkey_ec_cp_verify(ec, sig, siglen, tbs, tbs_len);
+}
+
+/* ------------- encrypt init ------------------------------------- */
/* Generates ephermeral key */
static int pkey_gost_encrypt_init(EVP_PKEY_CTX *ctx)
{
#include <openssl/core_dispatch.h>
#include <openssl/core_names.h>
#include "gost_prov.h"
+#include "gost_prov_tls.h"
#include "gost_lcl.h"
#include "prov/err.h" /* libprov err functions */
if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL
&& (ctx->proverr_handle = proverr_new_handle(core, in)) != NULL
- && (ctx->libctx = OSSL_LIB_CTX_new()) != NULL
+ && (ctx->libctx = OSSL_LIB_CTX_new_child(core, in)) != NULL
&& (ctx->e = ENGINE_new()) != NULL
&& populate_gost_engine(ctx->e)) {
ctx->core_handle = core;
return GOST_prov_digests;
case OSSL_OP_MAC:
return GOST_prov_macs;
+ case OSSL_OP_KEYMGMT:
+ return GOST_prov_keymgmt;
+ case OSSL_OP_ENCODER:
+ return GOST_prov_encoder;
+ case OSSL_OP_SIGNATURE:
+ return GOST_prov_signature;
+ case OSSL_OP_DECODER:
+ return GOST_prov_decoder;
+ case OSSL_OP_KEYEXCH:
+ return GOST_prov_keyexch;
}
return NULL;
}
provider_ctx_free(vprovctx);
}
+int gost_prov_get_capabilities(void *provctx, const char *capability,
+ OSSL_CALLBACK *cb, void *arg)
+{
+ if (!cb)
+ return 0;
+
+ if (OPENSSL_strcasecmp(capability, "TLS-GROUP") == 0)
+ return gost_prov_get_tls_group_capability(cb, arg);
+
+ if (OPENSSL_strcasecmp(capability, "TLS-SIGALG") == 0)
+ return gost_prov_get_tls_sigalg_capability(cb, arg);
+
+ return 0;
+}
+
/* The base dispatch table */
static const OSSL_DISPATCH provider_functions[] = {
{ OSSL_FUNC_PROVIDER_QUERY_OPERATION, (fptr_t)gost_operation },
{ OSSL_FUNC_PROVIDER_GET_REASON_STRINGS, (fptr_t)gost_get_reason_strings },
{ OSSL_FUNC_PROVIDER_GET_PARAMS, (fptr_t)gost_get_params },
{ OSSL_FUNC_PROVIDER_TEARDOWN, (fptr_t)gost_teardown },
+ { OSSL_FUNC_PROVIDER_GET_CAPABILITIES, (fptr_t)gost_prov_get_capabilities },
{ 0, NULL }
};
-struct prov_ctx_st {
- void *core_handle;
- struct proverr_functions_st *err_handle;
-};
-
#ifdef BUILDING_PROVIDER_AS_LIBRARY
/*
* This allows the provider to be built in library form. In this case, the
+#pragma once
+
/**********************************************************************
* gost_prov.h - The provider itself *
* *
#include <openssl/core.h>
#include <openssl/engine.h>
+/* OID constants for GOST algorithms */
+#define OID_id_GostR3410_2001 "1.2.643.2.2.19"
+#define OID_id_GostR3410_2001DH "1.2.643.2.2.98"
+#define OID_id_GostR3410_2012_256 "1.2.643.7.1.1.1.1"
+#define OID_id_GostR3410_2012_512 "1.2.643.7.1.1.1.2"
+#define OID_id_GostR3411_94_with_GostR3410_2001 "1.2.643.2.2.3"
+#define OID_id_tc26_signwithdigest_gost3410_2012_256 "1.2.643.7.1.1.3.2"
+#define OID_id_tc26_signwithdigest_gost3410_2012_512 "1.2.643.7.1.1.3.3"
+
+/* Algorithm name constants for initializing OSSL_ALGORITHM */
+#define ALG_NAME_GOST2001 \
+ SN_id_GostR3410_2001 ":" \
+ LN_id_GostR3410_2001 ":" \
+ OID_id_GostR3410_2001
+
+#define ALG_NAME_GOST2001DH \
+ SN_id_GostR3410_2001DH ":" \
+ LN_id_GostR3410_2001DH ":" \
+ OID_id_GostR3410_2001DH
+
+#define ALG_NAME_GOST2012_256 \
+ SN_id_GostR3410_2012_256 ":" \
+ LN_id_GostR3410_2012_256 ":" \
+ OID_id_GostR3410_2012_256
+
+#define ALG_NAME_GOST2012_512 \
+ SN_id_GostR3410_2012_512 ":" \
+ LN_id_GostR3410_2012_512 ":" \
+ OID_id_GostR3410_2012_512
+
+/* Utilities for checking and working with bit flags */
+#define FLAGS_CONTAIN(flags, subset) (((flags)&(subset)) == (subset))
+#define FLAGS_INTERSECT(flags, subset) (((flags)&(subset)) != 0)
+
+OSSL_FUNC_keymgmt_dup_fn keymgmt_dup;
+OSSL_FUNC_keymgmt_free_fn keymgmt_free;
+OSSL_FUNC_keymgmt_match_fn keymgmt_match;
+
struct provider_ctx_st {
OSSL_LIB_CTX *libctx;
const OSSL_CORE_HANDLE *core_handle;
ENGINE *e;
};
typedef struct provider_ctx_st PROV_CTX;
+
+typedef struct gost_key_data_st
+{
+ EC_KEY *ec;
+ int type;
+ int param_nid;
+} GOST_KEY_DATA;
+
+int gost_get_max_keyexch_size(const GOST_KEY_DATA *);
+int gost_get_max_signature_size(const GOST_KEY_DATA *);
+
+void GOST_prov_deinit_mac_digests(void);
+void GOST_prov_deinit_ciphers(void);
+void GOST_prov_deinit_digests(void);
+
+extern const OSSL_ALGORITHM GOST_prov_macs[];
+extern const OSSL_ALGORITHM GOST_prov_ciphers[];
+extern const OSSL_ALGORITHM GOST_prov_digests[];
+extern const OSSL_ALGORITHM GOST_prov_keymgmt[];
+extern const OSSL_ALGORITHM GOST_prov_encoder[];
+extern const OSSL_ALGORITHM GOST_prov_signature[];
+extern const OSSL_ALGORITHM GOST_prov_decoder[];
+extern const OSSL_ALGORITHM GOST_prov_keyexch[];
#include "gost_prov.h"
#include "gost_lcl.h"
+/*
+ * This definitions are added in the patch to OpenSSL 3.4.2 version to support
+ * GOST TLS 1.3. Definitions below must be removed when the patch is added to
+ * OpenSSL upstream.
+ */
+#ifndef OSSL_CIPHER_PARAM_TLSTREE
+# if defined(_MSC_VER)
+# pragma message("Gost-engine is built against not fully supported version of OpenSSL. \
+OSSL_CIPHER_PARAM_TLSTREE definition in OpenSSL is expected.")
+# else
+# warning "Gost-engine is built against not fully supported version of OpenSSL. \
+NID_kuznyechik_mgm definition in OpenSSL is expected. No kuznyechik mgm functionality is \
+guaranteed."
+# endif
+# define OSSL_CIPHER_PARAM_TLSTREE "tlstree"
+#endif
+
+#ifndef OSSL_CIPHER_PARAM_TLSTREE_MODE
+# if defined(_MSC_VER)
+# pragma message("Gost-engine is built against not fully supported version of OpenSSL. \
+OSSL_CIPHER_PARAM_TLSTREE_MODE definition in OpenSSL is expected.")
+# else
+# warning "Gost-engine is built against not fully supported version of OpenSSL. \
+NID_kuznyechik_mgm definition in OpenSSL is expected. No kuznyechik mgm functionality is \
+guaranteed."
+# endif
+# define OSSL_CIPHER_PARAM_TLSTREE_MODE "tlstree_mode"
+#endif
+
/*
* Forward declarations of all generic OSSL_DISPATCH functions, to make sure
* they are correctly defined further down. For the algorithm specific ones
|| ((p = OSSL_PARAM_locate(params, "keylen")) != NULL
&& !OSSL_PARAM_set_size_t(p, EVP_CIPHER_key_length(c)))
|| ((p = OSSL_PARAM_locate(params, "mode")) != NULL
- && !OSSL_PARAM_set_size_t(p, EVP_CIPHER_flags(c))))
+ && !OSSL_PARAM_set_size_t(p, EVP_CIPHER_flags(c)))
+ || ((p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD)) != NULL
+ && (strcmp(EVP_CIPHER_name(c), "magma-mgm") == 0
+ || strcmp(EVP_CIPHER_name(c), "kuznyechik-mgm") == 0)
+ && !OSSL_PARAM_set_size_t(p, 1)))
return 0;
return 1;
}
taglen, &tag) <= 0)
return 0;
}
+ if ((p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLSTREE)) != NULL) {
+ const void *val = NULL;
+ size_t arg = 0;
+
+ if (!OSSL_PARAM_get_octet_string_ptr(p, &val, &arg)
+ || EVP_CIPHER_CTX_ctrl(gctx->cctx, EVP_CTRL_TLSTREE,
+ arg, (void *)val) <= 0)
+ return 0;
+ }
+ if ((p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLSTREE_MODE)) != NULL) {
+ const void *val = NULL;
+ size_t arg = 0;
+
+ if (!OSSL_PARAM_get_octet_string_ptr(p, &val, &arg)
+ || EVP_CIPHER_CTX_ctrl(gctx->cctx, EVP_CTRL_SET_TLSTREE_PARAMS,
+ arg, (void *)val) <= 0)
+ return 0;
+ }
return 1;
}
--- /dev/null
+#include <openssl/core_names.h>
+#include <openssl/core_object.h>
+#include "gost_prov.h"
+#include "gost_lcl.h"
+#include <openssl/asn1t.h>
+#include <ctype.h>
+
+/*
+ * Forward declarations of all generic OSSL_DISPATCH functions, to make sure
+ * they are correctly defined further down. For the structure specific ones
+ * MAKE_DECODER_FUNCTIONS() does it for us.
+ */
+static OSSL_FUNC_decoder_newctx_fn decoder_newctx;
+static OSSL_FUNC_decoder_freectx_fn decoder_freectx;
+
+typedef struct {
+ PROV_CTX *provctx;
+} GOST_DECODER_CTX;
+
+typedef int (st2ec_fn)(EC_KEY *ec, int *key_type, const void *st);
+typedef void *(bio2st_fn)(BIO *bio, void **st);
+typedef void (st_free_fn)(void *st);
+
+typedef struct {
+ X509_ALGOR *algor;
+ ASN1_BIT_STRING *public_key;
+} x509_pubkey_st;
+
+typedef struct {
+ int key_type;
+ unsigned char *data;
+ long int data_size;
+} params_st;
+
+ASN1_NDEF_SEQUENCE(x509_pubkey_st) = {
+ ASN1_SIMPLE(x509_pubkey_st, algor, X509_ALGOR),
+ ASN1_SIMPLE(x509_pubkey_st, public_key, ASN1_BIT_STRING)
+} ASN1_NDEF_SEQUENCE_END(x509_pubkey_st)
+
+IMPLEMENT_ASN1_FUNCTIONS(x509_pubkey_st)
+
+static st2ec_fn pkcs8_decode_wrapper;
+static bio2st_fn pkcs8_read_bio_der_wrapper;
+static st_free_fn pkcs8_free_wrapper;
+
+static st2ec_fn x509_pub_decode_wrapper;
+static bio2st_fn x509_pub_read_bio_der_wrapper;
+static st_free_fn x509_pub_free_wrapper;
+
+static st2ec_fn param_decode_wrapper;
+static bio2st_fn param_read_bio_pem_wrapper;
+static st_free_fn param_free_wrapper;
+
+static int pkcs8_decode_wrapper(EC_KEY *ec, int *key_type, const void *st)
+{
+ return internal_priv_decode(ec, key_type, (PKCS8_PRIV_KEY_INFO *)st);
+}
+static void *pkcs8_read_bio_der_wrapper(BIO *bio, void **st)
+{
+ return d2i_PKCS8_PRIV_KEY_INFO_bio(bio, (PKCS8_PRIV_KEY_INFO **)st);
+}
+static void pkcs8_free_wrapper(void *st)
+{
+ PKCS8_PRIV_KEY_INFO_free((PKCS8_PRIV_KEY_INFO *)st);
+}
+
+static int x509_pub_decode_wrapper(EC_KEY *ec, int *key_type, const void *st)
+{
+ return internal_pub_decode_ec(ec, key_type,
+ ((x509_pubkey_st *)st)->algor,
+ ((x509_pubkey_st *)st)->public_key->data,
+ ((x509_pubkey_st *)st)->public_key->length);
+}
+static void *x509_pub_read_bio_der_wrapper(BIO *bio, void **st)
+{
+ unsigned char *data = NULL;
+ size_t dlen;
+
+ dlen = BIO_get_mem_data(bio, &data);
+ if (!dlen)
+ return 0;
+ return d2i_x509_pubkey_st((x509_pubkey_st **)st, (const unsigned char **) &data, dlen);
+}
+static void x509_pub_free_wrapper(void *st)
+{
+ x509_pubkey_st_free((x509_pubkey_st *)st);
+}
+
+static int param_decode_wrapper(EC_KEY *ec, int *key_type, const void *st)
+{
+ const params_st *params = (const params_st *)st;
+ const unsigned char *pdata = params->data;
+
+ if (!internal_gost2001_param_decode(ec, &pdata, params->data_size))
+ return 0;
+
+ *key_type = params->key_type;
+
+ return 1;
+}
+
+static int get_key_type_from_pem_name(char *pem_name)
+{
+ if (!pem_name)
+ return NID_undef;
+
+ char *space_pos = strchr(pem_name, ' ');
+ if (space_pos)
+ *space_pos = '\0';
+
+ size_t i;
+ for (i = 0; pem_name[i]; ++i)
+ pem_name[i] = tolower((unsigned char)pem_name[i]);
+
+ return OBJ_sn2nid(pem_name);
+}
+
+static void *param_read_bio_pem_wrapper(BIO *bio, void **st)
+{
+ params_st *params = NULL;
+ char *name = NULL;
+ char *header = NULL;
+
+ params = OPENSSL_zalloc(sizeof(params_st));
+ if (!params)
+ goto exit;
+
+ int len = PEM_read_bio(bio, &name, &header,
+ ¶ms->data,
+ ¶ms->data_size);
+
+ if (len <= 0 || name == NULL)
+ goto exit;
+
+ params->key_type = get_key_type_from_pem_name(name);
+ if (params->key_type == NID_undef)
+ goto exit;
+exit:
+ OPENSSL_free(name);
+ OPENSSL_free(header);
+
+ *st = params;
+ return *st;
+}
+
+static void param_free_wrapper(void *st)
+{
+ params_st *params = (params_st *)st;
+
+ if (!params)
+ return;
+
+ OPENSSL_free(params->data);
+ OPENSSL_free(params);
+}
+
+static void *decoder_newctx(void *provctx)
+{
+ if (!provctx)
+ return NULL;
+
+ GOST_DECODER_CTX *ctx = OPENSSL_zalloc(sizeof(GOST_DECODER_CTX));
+ if (!ctx)
+ return NULL;
+
+ ctx->provctx = provctx;
+ return ctx;
+}
+
+static void decoder_freectx(void *ctx)
+{
+ GOST_DECODER_CTX *ectx = ctx;
+
+ OPENSSL_free(ectx);
+}
+
+static int decoder_does_selection(int selection, int selection_mask)
+{
+ return FLAGS_INTERSECT(selection, selection_mask);
+}
+
+static int decoder_decode(void *ctx, OSSL_CORE_BIO *cbio, int selection,
+ int selection_mask, OSSL_CALLBACK *data_cb,
+ void *data_cdarg, bio2st_fn *bio2st,
+ st2ec_fn *st2ec, st_free_fn *st_free)
+{
+ GOST_DECODER_CTX *dctx = NULL;
+ GOST_KEY_DATA *key_data = NULL;
+ BIO *bio = NULL;
+ void *st = NULL;
+ int ret = 1;
+
+ if (!FLAGS_INTERSECT(selection, selection_mask))
+ goto exit;
+
+ if (!cbio || !data_cb)
+ goto exit;
+
+ dctx = ctx;
+ if (!dctx || !dctx->provctx || !dctx->provctx->libctx)
+ goto exit;
+
+ bio = BIO_new_from_core_bio(dctx->provctx->libctx, cbio);
+ if (!bio)
+ goto exit;
+
+ if (!bio2st(bio, &st))
+ goto exit;
+
+ key_data = OPENSSL_zalloc(sizeof(GOST_KEY_DATA));
+ if (!key_data) {
+ ret = 0;
+ goto exit;
+ }
+
+ key_data->ec = EC_KEY_new();
+ if (!key_data->ec) {
+ ret = 0;
+ goto exit;
+ }
+
+ if (!st2ec(key_data->ec, &key_data->type, st))
+ goto exit;
+
+ key_data->param_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(key_data->ec));
+ if (key_data->param_nid == NID_undef) {
+ ret = 0;
+ goto exit;
+ }
+
+ OSSL_PARAM params[4];
+ int object_type = OSSL_OBJECT_PKEY;
+ params[0] = OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type);
+ params[1] = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
+ (char *)OBJ_nid2sn(key_data->type), 0);
+ params[2] = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE,
+ &key_data, sizeof(key_data));
+ params[3] = OSSL_PARAM_construct_end();
+
+ ret = data_cb(params, data_cdarg);
+
+exit:
+
+ keymgmt_free(key_data);
+ BIO_free(bio);
+ st_free(st);
+ return ret;
+}
+
+typedef void (*fptr_t)(void);
+#define MAKE_DECODER_FUNCTIONS(input, structure, bio2st, st2ec, st_free, selection_mask) \
+ static OSSL_FUNC_decoder_decode_fn input##_##structure##_decoder_decode; \
+ static int input##_##structure##_decoder_decode(void *ctx, OSSL_CORE_BIO *cbio, \
+ int selection, \
+ OSSL_CALLBACK *data_cb, \
+ void *data_cdarg, \
+ OSSL_PASSPHRASE_CALLBACK *cb, \
+ void *cbarg) \
+ { \
+ return decoder_decode(ctx, cbio, selection, selection_mask, data_cb, data_cdarg, \
+ bio2st, st2ec, st_free); \
+ } \
+ static OSSL_FUNC_decoder_does_selection_fn \
+ input##_##structure##_decoder_does_selection; \
+ static int input##_##structure##_decoder_does_selection(void *ctx, \
+ int selection) \
+ { \
+ return decoder_does_selection(selection, selection_mask); \
+ } \
+ static const OSSL_DISPATCH id_##input##_##structure##_decoder_functions[] = { \
+ { OSSL_FUNC_DECODER_NEWCTX, (fptr_t)decoder_newctx }, \
+ { OSSL_FUNC_DECODER_FREECTX, (fptr_t)decoder_freectx }, \
+ { OSSL_FUNC_DECODER_DOES_SELECTION, \
+ (fptr_t)input##_##structure##_decoder_does_selection }, \
+ { OSSL_FUNC_DECODER_DECODE, (fptr_t)input##_##structure##_decoder_decode }, \
+ { 0, NULL } \
+ };
+
+#define DECODER(decoder_name, input, structure) \
+ { \
+ decoder_name, \
+ "provider=gostprov,input=" #input ",structure=" #structure, \
+ (id_##input##_##structure##_decoder_functions) \
+ }
+
+MAKE_DECODER_FUNCTIONS(der, PrivateKeyInfo, pkcs8_read_bio_der_wrapper,
+ pkcs8_decode_wrapper, pkcs8_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY)
+
+MAKE_DECODER_FUNCTIONS(der, SubjectPublicKeyInfo, x509_pub_read_bio_der_wrapper,
+ x509_pub_decode_wrapper, x509_pub_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
+MAKE_DECODER_FUNCTIONS(pem, type_specific, param_read_bio_pem_wrapper,
+ param_decode_wrapper, param_free_wrapper,
+ OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)
+
+/*
+ * Each algorithm of PRIVATE KEYS (PrivateKeyInfo) and PUBLIC KEYS (SubjectPublicKeyInfo)
+ * is registered separately because OpenSSL extracts the algorithm OID from ASN.1
+ * structure and directly maps it to the specific decoder (no iteration needed).
+ *
+ * Decoding of the keys from PEM to DER happens in default provider, while the key
+ * parameters (type_specific) are decoded directly from PEM since the PEM header
+ * is crucial for the algorithm identification.
+ */
+const OSSL_ALGORITHM GOST_prov_decoder[] = {
+ DECODER(ALG_NAME_GOST2001, der, SubjectPublicKeyInfo),
+ DECODER(ALG_NAME_GOST2001, pem, type_specific), /* Decode domain parameters */
+ DECODER(ALG_NAME_GOST2001DH, der, SubjectPublicKeyInfo),
+ DECODER(ALG_NAME_GOST2012_256, der, SubjectPublicKeyInfo),
+ DECODER(ALG_NAME_GOST2012_512, der, SubjectPublicKeyInfo),
+ DECODER(ALG_NAME_GOST2001, der, PrivateKeyInfo),
+ DECODER(ALG_NAME_GOST2001DH, der, PrivateKeyInfo),
+ DECODER(ALG_NAME_GOST2012_256, der, PrivateKeyInfo),
+ DECODER(ALG_NAME_GOST2012_512, der, PrivateKeyInfo),
+ { NULL, NULL, NULL }
+};
* https://www.ietf.org/archive/id/draft-deremin-rfc4491-bis-06.txt
* (is there not an RFC namming these?)
*/
- { "id-tc26-gost3411-12-256:md_gost12_256:1.2.643.7.1.1.2.2", NULL,
+ { SN_id_GostR3411_2012_256":id-tc26-gost3411-12-256:1.2.643.7.1.1.2.2", NULL,
GostR3411_2012_256_digest_functions,
"GOST R 34.11-2012 with 256 bit hash" },
- { "id-tc26-gost3411-12-512:md_gost12_512:1.2.643.7.1.1.2.3", NULL,
+ { SN_id_GostR3411_2012_512":id-tc26-gost3411-12-512:1.2.643.7.1.1.2.3", NULL,
GostR3411_2012_512_digest_functions,
"GOST R 34.11-2012 with 512 bit hash" },
/* Described in RFC 5831, first name from RFC 4357, section 10.4 */
- { "id-GostR3411-94:md_gost94:1.2.643.2.2.9", NULL,
+ { SN_id_GostR3411_94":id-GostR3411-94:1.2.643.2.2.9", NULL,
GostR3411_94_digest_functions, "GOST R 34.11-94" },
{ NULL , NULL, NULL }
};
--- /dev/null
+#include <openssl/core_dispatch.h>
+#include "gost_prov.h"
+#include "gost_lcl.h"
+
+/*
+ * Forward declarations of all generic OSSL_DISPATCH functions, to make sure
+ * they are correctly defined further down. For the algorithm and structure specific ones
+ * MAKE_ENCODER_FUNCTIONS() and MAKE_ENCODER_TEXT_FUNCTIONS() does it for us.
+ */
+static OSSL_FUNC_encoder_freectx_fn encoder_freectx;
+static OSSL_FUNC_encoder_newctx_fn encoder_newctx;
+
+typedef void * (st_new_fn)(void);
+typedef int (ec2st_encode_fn)(void *st, const EC_KEY *key, int key_type);
+typedef int (st2bio_fn)(BIO *bio, void *st);
+typedef void (st_free_fn)(void *st);
+
+static st_new_fn pkcs8_new_wrapper;
+static ec2st_encode_fn pkcs8_priv_encode_wrapper;
+static st2bio_fn pkcs8_write_bio_pem;
+static st2bio_fn pkcs8_write_bio_der;
+static st_free_fn pkcs8_free_wrapper;
+static st_new_fn x509_pub_new_wrapper;
+static ec2st_encode_fn x509_pub_encode_wrapper;
+static st2bio_fn x509_write_bio_pem;
+static st2bio_fn x509_write_bio_der;
+static st_free_fn x509_pub_free_wrapper;
+
+static void *pkcs8_new_wrapper(void)
+{
+ return PKCS8_PRIV_KEY_INFO_new();
+}
+
+static int pkcs8_priv_encode_wrapper(void *st, const EC_KEY *key, int key_type)
+{
+ return internal_priv_encode((PKCS8_PRIV_KEY_INFO *)st, (EC_KEY *)key, key_type);
+}
+
+static int pkcs8_write_bio_pem(BIO *bio, void *st)
+{
+ return PEM_write_bio_PKCS8_PRIV_KEY_INFO(bio, (PKCS8_PRIV_KEY_INFO *)st);
+}
+
+static int pkcs8_write_bio_der(BIO *bio, void *st)
+{
+ return i2d_PKCS8_PRIV_KEY_INFO_bio(bio, (PKCS8_PRIV_KEY_INFO *)st);
+}
+
+static void pkcs8_free_wrapper(void *st)
+{
+ PKCS8_PRIV_KEY_INFO_free((PKCS8_PRIV_KEY_INFO *)st);
+}
+
+static void *x509_pub_new_wrapper(void)
+{
+ return X509_PUBKEY_new();
+}
+
+static int x509_pub_encode_wrapper(void *st, const EC_KEY *key, int key_type)
+{
+ return internal_pub_encode_ec((X509_PUBKEY *)st, (EC_KEY *)key, key_type);
+}
+
+static int x509_write_bio_pem(BIO *bio, void *st)
+{
+ return PEM_write_bio_X509_PUBKEY(bio, (X509_PUBKEY *)st);
+}
+
+static int x509_write_bio_der(BIO *bio, void *st)
+{
+ return i2d_X509_PUBKEY_bio(bio, (X509_PUBKEY *)st);
+}
+
+static void x509_pub_free_wrapper(void *st)
+{
+ X509_PUBKEY_free((X509_PUBKEY *)st);
+}
+
+typedef struct {
+ PROV_CTX *provctx;
+} GOST_ENCODER_CTX;
+
+static void encoder_freectx(void *ctx)
+{
+ GOST_ENCODER_CTX *ectx = ctx;
+
+ OPENSSL_free(ectx);
+}
+
+static void *encoder_newctx(void *provctx)
+{
+ if (!provctx)
+ return NULL;
+
+ GOST_ENCODER_CTX *ctx = OPENSSL_zalloc(sizeof(GOST_ENCODER_CTX));
+ if (!ctx)
+ return NULL;
+
+ ctx->provctx = provctx;
+ return ctx;
+}
+
+static int encoder_does_selection(int selection, int selection_mask)
+{
+ return FLAGS_INTERSECT(selection, selection_mask);
+}
+
+static int encoder_encode(
+ void *ctx,
+ OSSL_CORE_BIO *cbio,
+ const void *key,
+ const OSSL_PARAM key_params[],
+ int selection,
+ int selection_mask,
+ st_new_fn *st_new,
+ ec2st_encode_fn *ec2st_encode,
+ st2bio_fn *st2bio,
+ st_free_fn *st_free)
+{
+ int ok = 0;
+ BIO *out = NULL;
+ void *key_st = NULL;
+ GOST_ENCODER_CTX *ectx = NULL;
+ const GOST_KEY_DATA *key_data = NULL;
+
+ if (!ctx || !cbio || !key)
+ goto exit;
+
+ if (key_params != NULL)
+ goto exit;
+
+ if (!FLAGS_INTERSECT(selection, selection_mask))
+ goto exit;
+
+ ectx = ctx;
+ key_data = key;
+
+ if (!ectx->provctx || !ectx->provctx->libctx)
+ goto exit;
+
+ out = BIO_new_from_core_bio(ectx->provctx->libctx, cbio);
+ if (!out)
+ goto exit;
+
+ key_st = st_new();
+ if (!key_st)
+ goto exit;
+
+ if (!ec2st_encode(key_st, key_data->ec, key_data->type))
+ goto exit;
+
+ if (!st2bio(out, key_st))
+ goto exit;
+
+ ok = 1;
+
+exit:
+ st_free(key_st);
+ BIO_free(out);
+ return ok;
+}
+
+static int encoder_text_encode(void *vctx, OSSL_CORE_BIO *cbio,
+ const void *key, const OSSL_PARAM key_params[],
+ int selection, int selection_mask)
+{
+ GOST_ENCODER_CTX *ctx = vctx;
+ const GOST_KEY_DATA *key_data = key;
+ BIO *out = NULL;
+ int ok = 0;
+
+ if (!ctx || !cbio || !key)
+ goto exit;
+
+ if (!FLAGS_INTERSECT(selection, selection_mask))
+ goto exit;
+
+ out = BIO_new_from_core_bio(ctx->provctx->libctx, cbio);
+ if (!out)
+ goto exit;
+
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_PRIVATE_KEY)
+ && !internal_print_gost_priv(out, key_data->ec, 0, key_data->type))
+ goto exit;
+
+ if (FLAGS_INTERSECT(selection, OSSL_KEYMGMT_SELECT_KEYPAIR)
+ && !internal_print_gost_ec_pub(out, key_data->ec, 0, key_data->type))
+ goto exit;
+
+ if (!internal_print_gost_ec_param(out, key_data->ec, 0))
+ goto exit;
+
+ ok = 1;
+
+exit:
+ BIO_free(out);
+ return ok;
+}
+
+typedef void (*fptr_t)(void);
+#define MAKE_ENCODER_FUNCTIONS(alg, output, structure, st_new_fn, ec2st_encode, write_key_st, \
+ key_st_free, selection_mask) \
+ static OSSL_FUNC_encoder_encode_fn alg##_##output##_##structure##_encoder_encode; \
+ static int alg##_##output##_##structure##_encoder_encode( \
+ void *ctx, \
+ OSSL_CORE_BIO *cbio, \
+ const void *key, \
+ const OSSL_PARAM key_params[], \
+ int selection, \
+ OSSL_PASSPHRASE_CALLBACK *cb, \
+ void *cbarg) \
+ { \
+ return encoder_encode( \
+ ctx, cbio, key, key_params, \
+ selection, selection_mask, \
+ st_new_fn, ec2st_encode, write_key_st, key_st_free); \
+ } \
+ static OSSL_FUNC_encoder_does_selection_fn \
+ alg##_##output##_##structure##_encoder_does_selection; \
+ static int alg##_##output##_##structure##_encoder_does_selection(void *ctx, int selection) \
+ { \
+ return encoder_does_selection(selection, selection_mask); \
+ } \
+ static const OSSL_DISPATCH id_##alg##_##output##_##structure##_encoder_functions[] = \
+ { \
+ { OSSL_FUNC_ENCODER_NEWCTX, (fptr_t)encoder_newctx }, \
+ { OSSL_FUNC_ENCODER_FREECTX, (fptr_t)encoder_freectx }, \
+ { OSSL_FUNC_ENCODER_DOES_SELECTION, \
+ (fptr_t)alg##_##output##_##structure##_encoder_does_selection }, \
+ { OSSL_FUNC_ENCODER_ENCODE, (fptr_t)alg##_##output##_##structure##_encoder_encode }, \
+ { 0, NULL } \
+ }; \
+
+#define MAKE_ENCODER_TEXT_FUNCTIONS(alg, output, selection_mask) \
+ static OSSL_FUNC_encoder_encode_fn alg##_##output##_encoder_text_encode; \
+ static int alg##_##output##_encoder_text_encode( \
+ void *vctx, \
+ OSSL_CORE_BIO *cbio, \
+ const void *key, \
+ const OSSL_PARAM key_params[], \
+ int selection, \
+ OSSL_PASSPHRASE_CALLBACK *cb, \
+ void *cbarg) \
+ { \
+ if (key_params != NULL) { \
+ ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); \
+ return 0; \
+ } \
+ return encoder_text_encode( \
+ vctx, cbio, key, key_params, \
+ selection, selection_mask); \
+ } \
+ static OSSL_FUNC_encoder_does_selection_fn \
+ alg##_##output##_encoder_does_selection; \
+ static int alg##_##output##_encoder_does_selection(void *ctx, int selection) \
+ { \
+ return encoder_does_selection(selection, selection_mask); \
+ } \
+ static const OSSL_DISPATCH id_##alg##_##output##_encoder_text_functions[] = \
+ { \
+ { OSSL_FUNC_ENCODER_NEWCTX, (fptr_t)encoder_newctx }, \
+ { OSSL_FUNC_ENCODER_FREECTX, (fptr_t)encoder_freectx }, \
+ { OSSL_FUNC_ENCODER_DOES_SELECTION, \
+ (fptr_t)alg##_##output##_encoder_does_selection }, \
+ { OSSL_FUNC_ENCODER_ENCODE, \
+ (fptr_t)alg##_##output##_encoder_text_encode }, \
+ { 0, NULL } \
+ };
+
+#define ENCODER(sn_name, name, output, structure) \
+ { \
+ sn_name, \
+ "provider=gostprov,output=" #output \
+ ",structure=" #structure, \
+ (id_##name##_##output##_##structure##_encoder_functions) \
+ }
+
+#define ENCODER_TEXT(sn_name, name, output) \
+ { \
+ sn_name, \
+ "provider=gostprov,output=" #output, \
+ (id_##name##_##output##_encoder_text_functions) \
+ }
+
+MAKE_ENCODER_FUNCTIONS(gost2001, pem, PrivateKeyInfo,
+ pkcs8_new_wrapper,
+ pkcs8_priv_encode_wrapper,
+ pkcs8_write_bio_pem,
+ pkcs8_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2001dh, pem, PrivateKeyInfo,
+ pkcs8_new_wrapper,
+ pkcs8_priv_encode_wrapper,
+ pkcs8_write_bio_pem,
+ pkcs8_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2012_256, pem, PrivateKeyInfo,
+ pkcs8_new_wrapper,
+ pkcs8_priv_encode_wrapper,
+ pkcs8_write_bio_pem,
+ pkcs8_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2012_512, pem, PrivateKeyInfo,
+ pkcs8_new_wrapper,
+ pkcs8_priv_encode_wrapper,
+ pkcs8_write_bio_pem,
+ pkcs8_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2001, der, PrivateKeyInfo,
+ pkcs8_new_wrapper,
+ pkcs8_priv_encode_wrapper,
+ pkcs8_write_bio_der,
+ pkcs8_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2001dh, der, PrivateKeyInfo,
+ pkcs8_new_wrapper,
+ pkcs8_priv_encode_wrapper,
+ pkcs8_write_bio_der,
+ pkcs8_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2012_256, der, PrivateKeyInfo,
+ pkcs8_new_wrapper,
+ pkcs8_priv_encode_wrapper,
+ pkcs8_write_bio_der,
+ pkcs8_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2012_512, der, PrivateKeyInfo,
+ pkcs8_new_wrapper,
+ pkcs8_priv_encode_wrapper,
+ pkcs8_write_bio_der,
+ pkcs8_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2001, pem, SubjectPublicKeyInfo,
+ x509_pub_new_wrapper,
+ x509_pub_encode_wrapper,
+ x509_write_bio_pem,
+ x509_pub_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2001dh, pem, SubjectPublicKeyInfo,
+ x509_pub_new_wrapper,
+ x509_pub_encode_wrapper,
+ x509_write_bio_pem,
+ x509_pub_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2012_256, pem, SubjectPublicKeyInfo,
+ x509_pub_new_wrapper,
+ x509_pub_encode_wrapper,
+ x509_write_bio_pem,
+ x509_pub_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2012_512, pem, SubjectPublicKeyInfo,
+ x509_pub_new_wrapper,
+ x509_pub_encode_wrapper,
+ x509_write_bio_pem,
+ x509_pub_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2001, der, SubjectPublicKeyInfo,
+ x509_pub_new_wrapper,
+ x509_pub_encode_wrapper,
+ x509_write_bio_der,
+ x509_pub_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2001dh, der, SubjectPublicKeyInfo,
+ x509_pub_new_wrapper,
+ x509_pub_encode_wrapper,
+ x509_write_bio_der,
+ x509_pub_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2012_256, der, SubjectPublicKeyInfo,
+ x509_pub_new_wrapper,
+ x509_pub_encode_wrapper,
+ x509_write_bio_der,
+ x509_pub_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
+
+MAKE_ENCODER_FUNCTIONS(gost2012_512, der, SubjectPublicKeyInfo,
+ x509_pub_new_wrapper,
+ x509_pub_encode_wrapper,
+ x509_write_bio_der,
+ x509_pub_free_wrapper,
+ OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
+
+MAKE_ENCODER_TEXT_FUNCTIONS(gost2001, text,
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY | OSSL_KEYMGMT_SELECT_PUBLIC_KEY
+ | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)
+
+MAKE_ENCODER_TEXT_FUNCTIONS(gost2001dh, text,
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY | OSSL_KEYMGMT_SELECT_PUBLIC_KEY
+ | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)
+
+MAKE_ENCODER_TEXT_FUNCTIONS(gost2012_256, text,
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY | OSSL_KEYMGMT_SELECT_PUBLIC_KEY
+ | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)
+
+MAKE_ENCODER_TEXT_FUNCTIONS(gost2012_512, text,
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY | OSSL_KEYMGMT_SELECT_PUBLIC_KEY
+ | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)
+
+const OSSL_ALGORITHM GOST_prov_encoder[] = {
+ ENCODER(ALG_NAME_GOST2001, gost2001, pem, PrivateKeyInfo),
+ ENCODER(ALG_NAME_GOST2001, gost2001, der, PrivateKeyInfo),
+ ENCODER(ALG_NAME_GOST2001, gost2001, pem, SubjectPublicKeyInfo),
+ ENCODER(ALG_NAME_GOST2001, gost2001, der, SubjectPublicKeyInfo),
+ ENCODER_TEXT(ALG_NAME_GOST2001, gost2001, text),
+ ENCODER(ALG_NAME_GOST2001DH, gost2001dh, pem, PrivateKeyInfo),
+ ENCODER(ALG_NAME_GOST2001DH, gost2001dh, der, PrivateKeyInfo),
+ ENCODER(ALG_NAME_GOST2001DH, gost2001dh, pem, SubjectPublicKeyInfo),
+ ENCODER(ALG_NAME_GOST2001DH, gost2001dh, der, SubjectPublicKeyInfo),
+ ENCODER_TEXT(ALG_NAME_GOST2001DH, gost2001dh, text),
+ ENCODER(ALG_NAME_GOST2012_256, gost2012_256, pem, PrivateKeyInfo),
+ ENCODER(ALG_NAME_GOST2012_256, gost2012_256, der, PrivateKeyInfo),
+ ENCODER(ALG_NAME_GOST2012_256, gost2012_256, pem, SubjectPublicKeyInfo),
+ ENCODER(ALG_NAME_GOST2012_256, gost2012_256, der, SubjectPublicKeyInfo),
+ ENCODER_TEXT(ALG_NAME_GOST2012_256, gost2012_256, text),
+ ENCODER(ALG_NAME_GOST2012_512, gost2012_512, pem, PrivateKeyInfo),
+ ENCODER(ALG_NAME_GOST2012_512, gost2012_512, der, PrivateKeyInfo),
+ ENCODER(ALG_NAME_GOST2012_512, gost2012_512, pem, SubjectPublicKeyInfo),
+ ENCODER(ALG_NAME_GOST2012_512, gost2012_512, der, SubjectPublicKeyInfo),
+ ENCODER_TEXT(ALG_NAME_GOST2012_512, gost2012_512, text),
+ { NULL, NULL, NULL }
+};
\ No newline at end of file
--- /dev/null
+#include <openssl/core_names.h>
+#include <assert.h>
+#include "gost_prov.h"
+#include "gost_lcl.h"
+
+#define GOST_MAX_ECDH_LEN 128
+
+int gost_get_max_keyexch_size(const GOST_KEY_DATA *key_data)
+{
+ /* You should modify this function when add new derive algorithm */
+ return GOST_MAX_ECDH_LEN / 2;
+}
+
+/*
+ * Forward declarations of all generic OSSL_DISPATCH functions, to make sure
+ * they are correctly defined further down.
+ */
+static OSSL_FUNC_keyexch_newctx_fn ecdhe_newctx;
+static OSSL_FUNC_keyexch_init_fn ecdhe_init;
+static OSSL_FUNC_keyexch_set_peer_fn ecdhe_set_peer;
+static OSSL_FUNC_keyexch_derive_fn ecdhe_derive;
+static OSSL_FUNC_keyexch_freectx_fn ecdhe_freectx;
+
+typedef struct {
+ GOST_KEY_DATA *key_data;
+ GOST_KEY_DATA *peer_key_data;
+} GOST_ECDHE_CTX;
+
+static void *ecdhe_newctx(void *provctx)
+{
+ GOST_ECDHE_CTX *ctx;
+
+ ctx = OPENSSL_zalloc(sizeof(*ctx));
+ return ctx;
+}
+
+static int ecdhe_init(void *vctx, void *vkey_data, const OSSL_PARAM params[])
+{
+ GOST_ECDHE_CTX *ctx = vctx;
+ GOST_KEY_DATA *key_data = vkey_data;
+
+ if (!ctx || !key_data || !key_data->ec)
+ return 0;
+
+ ctx->key_data = keymgmt_dup(key_data, (OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS
+ | OSSL_KEYMGMT_SELECT_PRIVATE_KEY));
+ if (!ctx->key_data)
+ return 0;
+
+ return 1;
+}
+
+static int ecdhe_set_peer(void *vctx, void *vpeer_key_data)
+{
+ GOST_ECDHE_CTX *ctx = vctx;
+ GOST_KEY_DATA *peer_key_data = vpeer_key_data;
+
+ if (!ctx || !ctx->key_data || !ctx->key_data->ec || !peer_key_data || !peer_key_data->ec)
+ return 0;
+
+ if (!EC_KEY_get0_public_key(peer_key_data->ec))
+ return 0;
+
+ if (!keymgmt_match(ctx->key_data, peer_key_data, OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS))
+ return 0;
+
+ keymgmt_free(ctx->peer_key_data);
+ ctx->peer_key_data = keymgmt_dup(peer_key_data, (OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS
+ | OSSL_KEYMGMT_SELECT_PUBLIC_KEY));
+ if (!ctx->peer_key_data)
+ return 0;
+
+ return 1;
+}
+
+static void ecdhe_freectx(void *vctx)
+{
+ GOST_ECDHE_CTX *ctx = (GOST_ECDHE_CTX *)vctx;
+
+ if (!ctx)
+ return;
+
+ keymgmt_free(ctx->key_data);
+ keymgmt_free(ctx->peer_key_data);
+ OPENSSL_free(ctx);
+}
+
+static int ecdhe_derive(void *vctx, unsigned char *secret,
+ size_t *psecretlen, size_t outlen)
+{
+ GOST_ECDHE_CTX *ctx = vctx;
+ size_t ecdh_result_len;
+ unsigned char ecdh_result[GOST_MAX_ECDH_LEN];
+ const unsigned char ukm[] = {1};
+
+ if (!psecretlen
+ || !ctx
+ || !ctx->key_data
+ || !ctx->peer_key_data
+ || !ctx->peer_key_data->ec
+ || !internal_compute_ecdh(NULL, &ecdh_result_len, ukm, sizeof(ukm),
+ EC_KEY_get0_public_key(ctx->peer_key_data->ec),
+ ctx->key_data->ec))
+ return 0;
+
+ assert(ecdh_result_len <= sizeof(ecdh_result));
+
+ /* Return only X coordinate */
+ *psecretlen = ecdh_result_len >> 1;
+
+ if (!secret)
+ return 1;
+
+ if (outlen < *psecretlen)
+ return 0;
+
+ if (!internal_compute_ecdh(ecdh_result, &ecdh_result_len, ukm, sizeof(ukm),
+ EC_KEY_get0_public_key(ctx->peer_key_data->ec), ctx->key_data->ec))
+ return 0;
+
+ memcpy(secret, ecdh_result, *psecretlen);
+ OPENSSL_cleanse(ecdh_result, sizeof(ecdh_result));
+
+ return 1;
+}
+
+static const OSSL_DISPATCH ecdh_keyexch_functions[] = {
+ { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))ecdhe_newctx },
+ { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecdhe_init },
+ { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecdhe_derive },
+ { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecdhe_set_peer },
+ { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecdhe_freectx },
+ OSSL_DISPATCH_END
+};
+
+const OSSL_ALGORITHM GOST_prov_keyexch[] = {
+ { "ECDHE", NULL, ecdh_keyexch_functions },
+ { NULL, NULL, NULL }
+};
\ No newline at end of file
--- /dev/null
+#include <openssl/ec.h>
+#include <openssl/core_names.h>
+#include "gost_prov.h"
+#include "gost_lcl.h"
+
+#define PARAMSET_NID "paramset_nid"
+
+#define GOST_MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+
+/*
+ * Forward declarations of all generic OSSL_DISPATCH functions, to make sure
+ * they are correctly defined further down. For the algorithm specific ones
+ * MAKE_FUNCTIONS() does it for us.
+ */
+static OSSL_FUNC_keymgmt_set_params_fn keymgmt_set_params;
+static OSSL_FUNC_keymgmt_settable_params_fn keymgmt_settable_params;
+static OSSL_FUNC_keymgmt_gen_set_params_fn keymgmt_gen_set_params;
+static OSSL_FUNC_keymgmt_gen_fn keymgmt_gen;
+static OSSL_FUNC_keymgmt_gen_cleanup_fn keymgmt_gen_cleanup;
+static OSSL_FUNC_keymgmt_has_fn keymgmt_has;
+static OSSL_FUNC_keymgmt_get_params_fn keymgmt_get_params;
+static OSSL_FUNC_keymgmt_gettable_params_fn keymgmt_gettable_params;
+static OSSL_FUNC_keymgmt_gen_get_params_fn keymgmt_gen_get_params;
+static OSSL_FUNC_keymgmt_gen_gettable_params_fn keymgmt_gen_gettable_params;
+static OSSL_FUNC_keymgmt_gen_settable_params_fn keymgmt_gen_settable_params;
+static OSSL_FUNC_keymgmt_load_fn keymgmt_load;
+static OSSL_FUNC_keymgmt_query_operation_name_fn keymgmt_gost2001_operation_name;
+static OSSL_FUNC_keymgmt_query_operation_name_fn keymgmt_gost2012_256_operation_name;
+static OSSL_FUNC_keymgmt_query_operation_name_fn keymgmt_gost2012_512_operation_name;
+static OSSL_FUNC_keymgmt_validate_fn keymgmt_validate;
+
+typedef struct gost_gen_ctx_st {
+ int type;
+ int sign_param_nid;
+ int selection;
+} GOST_GEN_CTX;
+
+static const char *keymgmt_gost2012_256_operation_name(int operation_id)
+{
+ switch (operation_id) {
+ case OSSL_OP_SIGNATURE:
+ return SN_id_GostR3410_2012_256;
+ case OSSL_OP_KEYEXCH:
+ return "ECDHE";
+ default:
+ return NULL;
+ }
+}
+
+static const char *keymgmt_gost2012_512_operation_name(int operation_id)
+{
+ switch (operation_id) {
+ case OSSL_OP_SIGNATURE:
+ return SN_id_GostR3410_2012_512;
+ case OSSL_OP_KEYEXCH:
+ return "ECDHE";
+ default:
+ return NULL;
+ }
+}
+
+static const char *keymgmt_gost2001_operation_name(int operation_id)
+{
+ if (operation_id == OSSL_OP_SIGNATURE)
+ return SN_id_GostR3410_2001;
+ return NULL;
+}
+
+static void *keymgmt_new(void *vprovctx, int type)
+{
+ GOST_KEY_DATA *key_data = NULL;
+
+ key_data = OPENSSL_zalloc(sizeof(GOST_KEY_DATA));
+ if (!key_data)
+ return NULL;
+
+ key_data->type = type;
+ key_data->param_nid = NID_undef;
+ key_data->ec = EC_KEY_new();
+ if (!key_data->ec) {
+ OPENSSL_free(key_data);
+ return NULL;
+ }
+
+ return key_data;
+}
+
+void keymgmt_free(void *vkctx)
+{
+ GOST_KEY_DATA *key_data = vkctx;
+
+ if (!key_data)
+ return;
+ EC_KEY_free(key_data->ec);
+ OPENSSL_free(key_data);
+}
+
+static int keymgmt_has(const void *vkctx, int selection)
+{
+ const GOST_KEY_DATA *key_data = vkctx;
+ int ok = 1;
+
+ if (!vkctx)
+ return !ok;
+
+ if (!FLAGS_INTERSECT(selection, OSSL_KEYMGMT_SELECT_ALL))
+ return ok;
+
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_PUBLIC_KEY))
+ ok = ok && (EC_KEY_get0_public_key(key_data->ec) != NULL);
+
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_PRIVATE_KEY))
+ ok = ok && (EC_KEY_get0_private_key(key_data->ec) != NULL);
+
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS))
+ ok = ok && (EC_KEY_get0_group(key_data->ec) != NULL);
+
+ return ok;
+}
+
+static void *keymgmt_load(const void *reference, size_t reference_sz)
+{
+ GOST_KEY_DATA *key_data = NULL;
+
+ if (!reference)
+ return NULL;
+
+ if (reference_sz != sizeof(key_data))
+ return NULL;
+
+ key_data = *(GOST_KEY_DATA **)reference;
+
+ /* Questionable hack of changing the constant value by pointer */
+ *(GOST_KEY_DATA **)reference = NULL;
+
+ return key_data;
+}
+
+static void keymgmt_gen_cleanup(void *genctx)
+{
+ if (!genctx)
+ return;
+
+ GOST_GEN_CTX *gctx = genctx;
+ OPENSSL_free(gctx);
+}
+
+void *keymgmt_gen_init(int selection, const OSSL_PARAM params[], int type)
+{
+ if (!FLAGS_INTERSECT(selection, OSSL_KEYMGMT_SELECT_ALL))
+ return NULL;
+
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
+ && !FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_PRIVATE_KEY))
+ return NULL;
+
+ GOST_GEN_CTX *gctx = OPENSSL_zalloc(sizeof(GOST_GEN_CTX));
+ if (!gctx)
+ return NULL;
+
+ gctx->type = type;
+ gctx->selection = selection;
+ gctx->sign_param_nid = NID_undef;
+
+ if (params && !keymgmt_gen_set_params(gctx, params)) {
+ keymgmt_gen_cleanup(gctx);
+ return NULL;
+ }
+
+ return gctx;
+}
+
+/*
+ * The callback arguments (osslcb & cbarg) are not used by EC_KEY generation
+ */
+static void *keymgmt_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
+{
+ GOST_GEN_CTX *gctx = genctx;
+ GOST_KEY_DATA *key_data = NULL;
+
+ if (!gctx)
+ goto end;
+
+ if (gctx->sign_param_nid == NID_undef)
+ goto end;
+
+ key_data = OPENSSL_zalloc(sizeof(GOST_KEY_DATA));
+ if (!key_data)
+ goto end;
+
+ key_data->type = gctx->type;
+ key_data->param_nid = gctx->sign_param_nid;
+
+ key_data->ec = internal_ec_paramgen(key_data->param_nid);
+ if (!key_data->ec)
+ goto end;
+
+ if (FLAGS_CONTAIN(gctx->selection, OSSL_KEYMGMT_SELECT_PRIVATE_KEY)
+ && !gost_ec_keygen(key_data->ec))
+ goto end;
+
+ return key_data;
+
+end:
+ keymgmt_free(key_data);
+ return NULL;
+}
+
+static const OSSL_PARAM known_settable_params[] = {
+ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *keymgmt_settable_params(void *provctx)
+{
+ return known_settable_params;
+}
+
+static int set_encoded_key(GOST_KEY_DATA *key_data, const OSSL_PARAM *p)
+{
+ int ret = 0;
+ BN_CTX *ctx = NULL;
+ BIGNUM *x = NULL, *y = NULL;
+ EC_POINT *point = NULL;
+ const EC_GROUP *group = EC_KEY_get0_group(key_data->ec);
+ const unsigned char *pub_key_buf = NULL;
+ size_t pub_key_buflen = 0;
+
+ if (!group)
+ goto end;
+
+ if (!OSSL_PARAM_get_octet_string_ptr(p, (const void **)&pub_key_buf, &pub_key_buflen))
+ goto end;
+
+ size_t coord_len = pub_key_buflen / 2;
+ if (pub_key_buflen % 2 != 0 || coord_len == 0)
+ goto end;
+
+ ctx = BN_CTX_new();
+ if (!ctx)
+ goto end;
+ BN_CTX_start(ctx);
+
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ if (!x || !y)
+ goto end;
+
+ if (!BN_lebin2bn(pub_key_buf, coord_len, x))
+ goto end;
+ if (!BN_lebin2bn(pub_key_buf + coord_len, coord_len, y))
+ goto end;
+
+ point = EC_POINT_new(group);
+ if (!point)
+ goto end;
+
+ if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx))
+ goto end;
+ if (!EC_KEY_set_public_key(key_data->ec, point))
+ goto end;
+
+ ret = 1;
+
+end:
+ EC_POINT_free(point);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return ret;
+}
+
+static int keymgmt_set_params(void *key, const OSSL_PARAM params[])
+{
+ if (key == NULL)
+ return 0;
+ if (params == NULL)
+ return 1;
+
+ GOST_KEY_DATA *key_data = key;
+ const OSSL_PARAM *p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY);
+
+ if (p != NULL && !set_encoded_key(key_data, p))
+ return 0;
+
+ return 1;
+}
+
+const OSSL_PARAM *keymgmt_gen_settable_params(void *genctx, void *provctx)
+{
+ static const OSSL_PARAM settable_params[] = {
+ OSSL_PARAM_utf8_string(param_ctrl_string, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0),
+ OSSL_PARAM_END
+ };
+
+ return settable_params;
+}
+
+static int keygmgmt_gen_set_paramset_param(GOST_GEN_CTX *genctx, const OSSL_PARAM *param)
+{
+ int result = 0;
+ const char *paramset = NULL;
+
+ if (!OSSL_PARAM_get_utf8_string_ptr(param, ¶mset))
+ goto exit;
+
+ int sign_param_nid = NID_undef;
+
+ switch (genctx->type) {
+ case NID_id_GostR3410_2001:
+ case NID_id_GostR3410_2001DH:
+ case NID_id_GostR3410_2012_256:
+ result = internal_param_str_to_nid_256(paramset, &sign_param_nid);
+ break;
+ case NID_id_GostR3410_2012_512:
+ result = internal_param_str_to_nid_512(paramset, &sign_param_nid);
+ break;
+ }
+
+ if (!result)
+ goto exit;
+
+ genctx->sign_param_nid = sign_param_nid;
+
+exit:
+ return result;
+}
+
+int keymgmt_gen_set_params(void *p0, const OSSL_PARAM params[])
+{
+ GOST_GEN_CTX *gctx = p0;
+
+ if (!gctx)
+ return 0;
+ if (!params)
+ return 1;
+
+ const OSSL_PARAM *p = OSSL_PARAM_locate_const(params, param_ctrl_string);
+ if (p != NULL && !keygmgmt_gen_set_paramset_param(gctx, p))
+ return 0;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME);
+ if (p != NULL && !keygmgmt_gen_set_paramset_param(gctx, p))
+ return 0;
+
+ return 1;
+}
+
+static const OSSL_PARAM known_gettable_params[] = {
+ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0),
+ OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
+ OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
+ OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_MANDATORY_DIGEST, NULL, 0),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *keymgmt_gettable_params(void *provctx)
+{
+ return known_gettable_params;
+}
+
+static int get_encoded_key(const GOST_KEY_DATA *key_data, OSSL_PARAM *p)
+{
+ BN_CTX *ctx = NULL;
+ BIGNUM *x = NULL, *y = NULL;
+ unsigned char *buf = NULL;
+ int ret = 0;
+ const EC_POINT *pub = EC_KEY_get0_public_key(key_data->ec);
+ const EC_GROUP *group = EC_KEY_get0_group(key_data->ec);
+
+ if (!pub || !group)
+ goto end;
+
+ ctx = BN_CTX_new();
+ if (!ctx)
+ goto end;
+
+ BN_CTX_start(ctx);
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ if (!x || !y)
+ goto end;
+
+ if (!EC_POINT_get_affine_coordinates(group, pub, x, y, ctx))
+ goto end;
+
+ int field_size = (EC_GROUP_get_degree(group) + 7) / 8;
+ buf = OPENSSL_zalloc(2 * field_size);
+ if (!buf)
+ goto end;
+
+ if (BN_bn2lebinpad(x, buf, field_size) != field_size ||
+ BN_bn2lebinpad(y, buf + field_size, field_size) != field_size)
+ goto end;
+
+ if (!OSSL_PARAM_set_octet_string(p, buf, 2 * field_size))
+ goto end;
+
+ ret = 1;
+
+end:
+ OPENSSL_free(buf);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return ret;
+}
+
+static int get_bits(GOST_KEY_DATA *key_data, OSSL_PARAM *p)
+{
+ const EC_GROUP *group = EC_KEY_get0_group(key_data->ec);
+
+ if (!group)
+ return 0;
+ return OSSL_PARAM_set_int(p, EC_GROUP_get_degree(group));
+}
+
+static int get_security_bits(GOST_KEY_DATA *key_data, OSSL_PARAM *p)
+{
+ const EC_GROUP *group = EC_KEY_get0_group(key_data->ec);
+
+ if (!group)
+ return 0;
+
+ int sec_bits = EC_GROUP_get_degree(group) >> 1;
+ return OSSL_PARAM_set_int(p, sec_bits);
+}
+
+static int get_default_digest_name(const GOST_KEY_DATA *key_data, OSSL_PARAM *p)
+{
+ const char *digest = NULL;
+
+ switch (key_data->type) {
+ case NID_id_GostR3410_2001:
+ case NID_id_GostR3410_2001DH:
+ digest = SN_id_GostR3411_94;
+ break;
+
+ case NID_id_GostR3410_2012_256:
+ digest = SN_id_GostR3411_2012_256;
+ break;
+
+ case NID_id_GostR3410_2012_512:
+ digest = SN_id_GostR3411_2012_512;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return OSSL_PARAM_set_utf8_string(p, digest);
+}
+
+static int get_max_size(const GOST_KEY_DATA *key_data, OSSL_PARAM *p)
+{
+ int max_signature_size = gost_get_max_signature_size(key_data);
+
+ if (max_signature_size == -1)
+ return 0;
+
+ int size = GOST_MAX(max_signature_size, gost_get_max_keyexch_size(key_data));
+
+ return OSSL_PARAM_set_int(p, size);
+}
+
+static int keymgmt_get_params(void *key, OSSL_PARAM params[])
+{
+ if (key == NULL)
+ return 0;
+ if (params == NULL)
+ return 1;
+
+ GOST_KEY_DATA *key_data = key;
+ OSSL_PARAM *p = NULL;
+
+ p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE);
+ if (p && !get_max_size(key_data, p))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY);
+ if (p && !get_encoded_key(key_data, p))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS);
+ if (p && !get_bits(key_data, p))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS);
+ if (p && !get_security_bits(key_data, p))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MANDATORY_DIGEST);
+ if (p && !get_default_digest_name(key_data, p))
+ return 0;
+
+ return 1;
+}
+
+static int keymgmt_gen_get_params(void *genctx, OSSL_PARAM params[])
+{
+ int ret = 0;
+
+ if (!genctx || !params)
+ goto end;
+
+ GOST_GEN_CTX *gctx = genctx;
+ OSSL_PARAM *p = OSSL_PARAM_locate(params, PARAMSET_NID);
+ if (p != NULL && !OSSL_PARAM_set_int(p, gctx->sign_param_nid))
+ goto end;
+
+ ret = 1;
+
+end:
+ return ret;
+}
+
+const OSSL_PARAM *keymgmt_gen_gettable_params(void *provctx, void *unused)
+{
+ static const OSSL_PARAM gettable_params[] = {
+ OSSL_PARAM_int(PARAMSET_NID, NULL),
+ OSSL_PARAM_END
+ };
+ return gettable_params;
+}
+
+void *keymgmt_dup(const void *src, int selection)
+{
+ const GOST_KEY_DATA *src_data = src;
+ GOST_KEY_DATA *dst = NULL;
+
+ if (!src_data || !src_data->ec)
+ goto err;
+ if (!FLAGS_INTERSECT(selection, OSSL_KEYMGMT_SELECT_ALL))
+ goto err;
+ dst = OPENSSL_zalloc(sizeof(GOST_KEY_DATA));
+ if (!dst)
+ goto err;
+
+ dst->type = src_data->type;
+ dst->param_nid = src_data->param_nid;
+
+ dst->ec = EC_KEY_new();
+ if (!dst->ec)
+ goto err;
+
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)) {
+ const EC_GROUP *group = EC_KEY_get0_group(src_data->ec);
+
+ if (!group || !EC_KEY_set_group(dst->ec, group))
+ goto err;
+ }
+
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_PUBLIC_KEY)) {
+ const EC_POINT *pub = EC_KEY_get0_public_key(src_data->ec);
+ const EC_GROUP *group = EC_KEY_get0_group(dst->ec);
+
+ if (!pub || !group || !EC_KEY_set_public_key(dst->ec, pub))
+ goto err;
+ }
+
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_PRIVATE_KEY)) {
+ const BIGNUM *priv = EC_KEY_get0_private_key(src_data->ec);
+ const EC_GROUP *group = EC_KEY_get0_group(dst->ec);
+
+ if (!priv || !group || !EC_KEY_set_private_key(dst->ec, priv))
+ goto err;
+ }
+
+ return dst;
+
+err:
+ keymgmt_free(dst);
+ return NULL;
+}
+
+int keymgmt_match(const void *vkctx1, const void *vkctx2, int selection)
+{
+ GOST_KEY_DATA *key_data1 = (GOST_KEY_DATA *)vkctx1;
+ GOST_KEY_DATA *key_data2 = (GOST_KEY_DATA *)vkctx2;
+ int ok = 1;
+
+ if (!key_data1 || !key_data2 || !key_data1->ec || !key_data2->ec)
+ return 0;
+
+ if (!FLAGS_INTERSECT(selection, OSSL_KEYMGMT_SELECT_ALL))
+ return 1;
+
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_PUBLIC_KEY)) {
+ const EC_POINT *pub_key1 = EC_KEY_get0_public_key(key_data1->ec);
+ const EC_POINT *pub_key2 = EC_KEY_get0_public_key(key_data2->ec);
+ const EC_GROUP *group1 = EC_KEY_get0_group(key_data1->ec);
+ const EC_GROUP *group2 = EC_KEY_get0_group(key_data2->ec);
+
+ if (!pub_key1 || !pub_key2 || !group1 || !group2)
+ return 0;
+
+ if (EC_GROUP_cmp(group1, group2, NULL) != 0)
+ return 0;
+
+ ok = ok && (EC_POINT_cmp(group1, pub_key1, pub_key2, NULL) == 0);
+ }
+
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_PRIVATE_KEY)) {
+ const BIGNUM *priv_key1 = EC_KEY_get0_private_key(key_data1->ec);
+ const BIGNUM *priv_key2 = EC_KEY_get0_private_key(key_data2->ec);
+
+ if (!priv_key1 || !priv_key2)
+ return 0;
+
+ ok = ok && (BN_cmp(priv_key1, priv_key2) == 0);
+ }
+
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)) {
+ const EC_GROUP *group1 = EC_KEY_get0_group(key_data1->ec);
+ const EC_GROUP *group2 = EC_KEY_get0_group(key_data2->ec);
+
+ if (!group1 || !group2)
+ return 0;
+
+ ok = ok && (EC_GROUP_cmp(group1, group2, NULL) == 0);
+ }
+
+ return ok;
+}
+
+int gost_key_public_check(const EC_POINT *pub_key, const EC_GROUP *group)
+{
+ BIGNUM *x = NULL;
+ BIGNUM *y = NULL;
+ BIGNUM *p = NULL;
+ BIGNUM *order = NULL;
+ BN_CTX *ctx = NULL;
+ int ret = 0;
+
+ ctx = BN_CTX_new();
+ if (!ctx)
+ goto exit;
+
+ BN_CTX_start(ctx);
+ p = BN_CTX_get(ctx);
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ order = BN_CTX_get(ctx);
+
+ if (!p || !x || !y || !order)
+ goto exit;
+
+ if (EC_POINT_is_at_infinity(group, pub_key))
+ goto exit;
+
+ if (!EC_POINT_get_affine_coordinates(group, pub_key, x, y, NULL))
+ goto exit;
+
+ if (!EC_GROUP_get_curve(group, p, NULL, NULL, NULL))
+ goto exit;
+
+ if (BN_cmp(x, p) >= 0 || BN_cmp(y, p) >= 0)
+ goto exit;
+
+ if (EC_POINT_is_on_curve(group, pub_key, NULL) <= 0)
+ goto exit;
+
+ if (EC_GROUP_get_order(group, order, NULL) == 0)
+ goto exit;
+
+ if (BN_cmp(order, BN_value_one()) <= 0)
+ goto exit;
+
+ ret = 1;
+exit:
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return ret;
+}
+
+static int keymgmt_validate(const void *vkctx, int selection, int checktype)
+{
+ GOST_KEY_DATA *key_data = (GOST_KEY_DATA *)vkctx;
+
+ if (!key_data || !key_data->ec)
+ return 0;
+
+ if (!FLAGS_INTERSECT(selection, OSSL_KEYMGMT_SELECT_ALL))
+ return 1;
+
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)) {
+ const EC_GROUP *group = EC_KEY_get0_group(key_data->ec);
+
+ if (!group || !EC_GROUP_check(group, NULL))
+ return 0;
+ }
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_PUBLIC_KEY)) {
+ const EC_POINT *pub_key = EC_KEY_get0_public_key(key_data->ec);
+ const EC_GROUP *group = EC_KEY_get0_group(key_data->ec);
+
+ if (!pub_key || !group || !gost_key_public_check(pub_key, group))
+ return 0;
+ }
+
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_PRIVATE_KEY)) {
+ const BIGNUM *priv_key = EC_KEY_get0_private_key(key_data->ec);
+ const EC_GROUP *group = EC_KEY_get0_group(key_data->ec);
+
+ if (!priv_key || !group)
+ return 0;
+
+ BIGNUM *order = BN_new();
+ if (!order
+ || !EC_GROUP_get_order(group, order, NULL)
+ || !((BN_cmp(priv_key, BN_value_one()) >= 0) && (BN_cmp(priv_key, order) < 0))) {
+ BN_free(order);
+ return 0;
+ }
+
+ BN_free(order);
+ }
+
+ if (FLAGS_CONTAIN(selection, OSSL_KEYMGMT_SELECT_KEYPAIR)) {
+ const EC_POINT *pub_key = EC_KEY_get0_public_key(key_data->ec);
+ const BIGNUM *priv_key = EC_KEY_get0_private_key(key_data->ec);
+ const EC_GROUP *group = EC_KEY_get0_group(key_data->ec);
+
+ if (!pub_key || !priv_key || !group)
+ return 0;
+
+ EC_POINT *tmp_pub_key = EC_POINT_new(group);
+ if (!tmp_pub_key
+ || !EC_POINT_mul(group, tmp_pub_key,
+ priv_key, NULL, NULL, NULL)
+ || EC_POINT_cmp(group, pub_key, tmp_pub_key, NULL)) {
+ EC_POINT_free(tmp_pub_key);
+ return 0;
+ }
+
+ EC_POINT_free(tmp_pub_key);
+ }
+
+ return 1;
+}
+
+static int keymgmt_gen_set_template(void *genctx, void *template)
+{
+ GOST_GEN_CTX *gctx = genctx;
+ GOST_KEY_DATA *template_key_data = template;
+
+ if (!genctx || !template)
+ return 0;
+
+ if (gctx->type != template_key_data->type)
+ return 0;
+
+ gctx->sign_param_nid = template_key_data->param_nid;
+ return 1;
+}
+
+typedef void (*fptr_t)(void);
+#define MAKE_KEYMGMT_FUNCTIONS(alg, type, operation_name_fn) \
+ static OSSL_FUNC_keymgmt_gen_init_fn alg##_gen_init; \
+ static void *alg##_gen_init(void *provctx, int selection, const OSSL_PARAM params[]) \
+ { \
+ return keymgmt_gen_init(selection, params, type); \
+ } \
+ static OSSL_FUNC_keymgmt_new_fn alg##_new; \
+ static void *alg##_new(void *provctx) \
+ { \
+ return keymgmt_new(provctx, type); \
+ } \
+ static const OSSL_DISPATCH id_##alg##_keymgmt_functions[] = { \
+ { OSSL_FUNC_KEYMGMT_NEW, (fptr_t)alg##_new}, \
+ { OSSL_FUNC_KEYMGMT_FREE, (fptr_t)keymgmt_free }, \
+ { OSSL_FUNC_KEYMGMT_HAS, (fptr_t)keymgmt_has }, \
+ { OSSL_FUNC_KEYMGMT_GEN_INIT, (fptr_t)alg##_gen_init }, \
+ { OSSL_FUNC_KEYMGMT_GEN, (fptr_t)keymgmt_gen }, \
+ { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (fptr_t)keymgmt_gen_cleanup }, \
+ { OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, (fptr_t)keymgmt_gen_set_template}, \
+ { OSSL_FUNC_KEYMGMT_SET_PARAMS, (fptr_t)keymgmt_set_params }, \
+ { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (fptr_t)keymgmt_settable_params }, \
+ { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (fptr_t)keymgmt_gen_set_params }, \
+ { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, (fptr_t)keymgmt_gen_settable_params }, \
+ { OSSL_FUNC_KEYMGMT_GET_PARAMS, (fptr_t)keymgmt_get_params}, \
+ { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (fptr_t)keymgmt_gettable_params}, \
+ { OSSL_FUNC_KEYMGMT_GEN_GET_PARAMS, (fptr_t)keymgmt_gen_get_params}, \
+ { OSSL_FUNC_KEYMGMT_GEN_GETTABLE_PARAMS, (fptr_t)keymgmt_gen_gettable_params}, \
+ { OSSL_FUNC_KEYMGMT_LOAD, (fptr_t)keymgmt_load}, \
+ { OSSL_FUNC_KEYMGMT_MATCH, (fptr_t)keymgmt_match}, \
+ { OSSL_FUNC_KEYMGMT_VALIDATE, (fptr_t)keymgmt_validate}, \
+ { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, (fptr_t)operation_name_fn}, \
+ { OSSL_FUNC_KEYMGMT_DUP, (fptr_t)keymgmt_dup}, \
+ OSSL_DISPATCH_END \
+ };
+
+MAKE_KEYMGMT_FUNCTIONS(gost2001, NID_id_GostR3410_2001, keymgmt_gost2001_operation_name);
+MAKE_KEYMGMT_FUNCTIONS(gost2001dh, NID_id_GostR3410_2001DH, NULL);
+MAKE_KEYMGMT_FUNCTIONS(gost2012_256, NID_id_GostR3410_2012_256,
+ keymgmt_gost2012_256_operation_name);
+MAKE_KEYMGMT_FUNCTIONS(gost2012_512, NID_id_GostR3410_2012_512,
+ keymgmt_gost2012_512_operation_name);
+
+/* The OSSL_ALGORITHM for the provider's operation query function */
+const OSSL_ALGORITHM GOST_prov_keymgmt[] = {
+ { ALG_NAME_GOST2001, NULL, id_gost2001_keymgmt_functions },
+ { ALG_NAME_GOST2001DH, NULL, id_gost2001dh_keymgmt_functions },
+ { ALG_NAME_GOST2012_256, NULL, id_gost2012_256_keymgmt_functions },
+ { ALG_NAME_GOST2012_512, NULL, id_gost2012_512_keymgmt_functions },
+ { NULL, NULL, NULL }
+};
\ No newline at end of file
--- /dev/null
+#include <assert.h>
+#include <openssl/core_names.h>
+#include "gost_prov.h"
+#include "gost_lcl.h"
+
+#define GOST_MAX_ALG_NAME_SIZE 50 /* Algorithm name */
+#define GOST_MAX_PROPQUERY_SIZE 256 /* Property query strings */
+#define GOST_NELEM(x) (sizeof(x) / sizeof((x)[0]))
+
+#define SIGN_OPERATION 0
+#define VERIFY_OPERATION 1
+
+int gost_get_max_signature_size(const GOST_KEY_DATA *key_data)
+{
+ int size = -1;
+
+ switch (key_data->type) {
+ case NID_id_GostR3410_2001:
+ case NID_id_GostR3410_2001DH:
+ case NID_id_GostR3410_2012_256:
+ size = 64;
+ break;
+ case NID_id_GostR3410_2012_512:
+ size = 128;
+ break;
+ default:
+ assert(!"Invalid key type");
+ }
+
+ return size;
+}
+
+/*
+ * Forward declarations of all generic OSSL_DISPATCH functions, to make sure
+ * they are correctly defined further down.
+ */
+static OSSL_FUNC_signature_newctx_fn signature_newctx;
+static OSSL_FUNC_signature_freectx_fn signature_free;
+static OSSL_FUNC_signature_digest_sign_init_fn signature_digest_sign_init;
+static OSSL_FUNC_signature_digest_sign_update_fn signature_digest_sign_update;
+static OSSL_FUNC_signature_digest_sign_final_fn signature_digest_sign_final;
+static OSSL_FUNC_signature_digest_verify_init_fn signature_digest_verify_init;
+static OSSL_FUNC_signature_digest_verify_update_fn signature_digest_verify_update;
+static OSSL_FUNC_signature_digest_verify_final_fn signature_digest_verify_final;
+static OSSL_FUNC_signature_get_ctx_params_fn signature_get_ctx_params;
+static OSSL_FUNC_signature_gettable_ctx_params_fn signature_gettable_ctx_params;
+
+typedef struct {
+ PROV_CTX *provctx;
+ GOST_KEY_DATA *key_data;
+ char *propq;
+ EVP_MD_CTX *mdctx;
+ EVP_MD *md;
+ int operation;
+} GOST_SIGNATURE_CTX;
+
+typedef struct {
+ int key_type;
+ const char *sn;
+} GOST_SUPPORTED_HASH;
+
+static const GOST_SUPPORTED_HASH supported_hash[] = {
+ {NID_id_GostR3410_2012_256, SN_id_GostR3411_2012_256},
+ {NID_id_GostR3410_2012_512, SN_id_GostR3411_2012_512},
+ {NID_id_GostR3410_2001, SN_id_GostR3411_94},
+};
+
+static void signature_free(void *vctx)
+{
+ if (!vctx)
+ return;
+
+ GOST_SIGNATURE_CTX *ctx = vctx;
+
+ EVP_MD_CTX_free(ctx->mdctx);
+ EVP_MD_free(ctx->md);
+ OPENSSL_free(ctx->propq);
+ keymgmt_free(ctx->key_data);
+ OPENSSL_free(ctx);
+}
+
+static void *signature_newctx(void *vprovctx, const char *propq)
+{
+ if (!vprovctx)
+ return NULL;
+
+ GOST_SIGNATURE_CTX *ctx = OPENSSL_zalloc(sizeof(GOST_SIGNATURE_CTX));
+ if (!ctx)
+ return NULL;
+
+ ctx->provctx = vprovctx;
+ if (propq && (ctx->propq = OPENSSL_strdup(propq)) == NULL) {
+ OPENSSL_free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+static int is_digest_supported_for_key(int key_type, const EVP_MD *md)
+{
+ size_t i;
+
+ for (i = 0; i < GOST_NELEM(supported_hash); ++i) {
+ if (supported_hash[i].key_type == key_type && EVP_MD_is_a(md, supported_hash[i].sn))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int signature_setup_md(GOST_SIGNATURE_CTX *ctx, const char *mdname, const char *mdprops)
+{
+ EVP_MD *md = NULL;
+
+ if (mdprops == NULL)
+ mdprops = ctx->propq;
+
+ if (mdname == NULL)
+ return 0;
+
+ md = EVP_MD_fetch(ctx->provctx->libctx, mdname, mdprops);
+ if (md == NULL)
+ return 0;
+
+ if (!is_digest_supported_for_key(ctx->key_data->type, md)) {
+ EVP_MD_free(md);
+ return 0;
+ }
+
+ EVP_MD_CTX_free(ctx->mdctx);
+ EVP_MD_free(ctx->md);
+
+ ctx->mdctx = NULL;
+ ctx->md = md;
+
+ return 1;
+}
+
+static int signature_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ GOST_SIGNATURE_CTX *ctx = vctx;
+ const OSSL_PARAM *p, *propsp;
+ char mdname[GOST_MAX_ALG_NAME_SIZE] = "", *pmdname = mdname;
+ char mdprops[GOST_MAX_PROPQUERY_SIZE] = "", *pmdprops = mdprops;
+
+ if (params == NULL)
+ return 1;
+
+ propsp = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PROPERTIES);
+ if (propsp != NULL
+ && !OSSL_PARAM_get_utf8_string(propsp, &pmdprops, sizeof(mdprops)))
+ return 0;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST);
+ if (p != NULL
+ && !OSSL_PARAM_get_utf8_string(p, &pmdname, sizeof(mdname)))
+ return 0;
+
+ if ((p != NULL || propsp != NULL) && !signature_setup_md(ctx, mdname, mdprops))
+ return 0;
+
+ return 1;
+}
+
+static int signature_get_algorithm_id(GOST_SIGNATURE_CTX *ctx, OSSL_PARAM *p)
+{
+ int nid;
+ ASN1_OBJECT *oid = NULL;
+ X509_ALGOR *algor = NULL;
+ unsigned char *der = NULL;
+ int derlen;
+ int ret = 0;
+
+ if (ctx == NULL || ctx->key_data == NULL)
+ return 0;
+
+ switch (ctx->key_data->type) {
+ case NID_id_GostR3410_2001:
+ nid = NID_id_GostR3411_94_with_GostR3410_2001;
+ break;
+ case NID_id_GostR3410_2012_256:
+ nid = NID_id_tc26_signwithdigest_gost3410_2012_256;
+ break;
+ case NID_id_GostR3410_2012_512:
+ nid = NID_id_tc26_signwithdigest_gost3410_2012_512;
+ break;
+ default:
+ return 0;
+ }
+
+ oid = OBJ_nid2obj(nid);
+ if (oid == NULL)
+ goto cleanup;
+
+ algor = X509_ALGOR_new();
+ if (algor == NULL)
+ goto cleanup;
+
+ X509_ALGOR_set0(algor, oid, V_ASN1_NULL, NULL);
+ oid = NULL;
+
+ derlen = i2d_X509_ALGOR(algor, &der);
+ if (derlen <= 0)
+ goto cleanup;
+
+ if (!OSSL_PARAM_set_octet_string(p, der, derlen))
+ goto cleanup;
+
+ ret = 1;
+
+cleanup:
+ X509_ALGOR_free(algor);
+ ASN1_OBJECT_free(oid);
+ OPENSSL_free(der);
+ return ret;
+}
+
+static int signature_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ if (vctx == NULL)
+ return 0;
+
+ GOST_SIGNATURE_CTX *ctx = vctx;
+
+ if (params == NULL)
+ return 1;
+
+ OSSL_PARAM *p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID);
+ if (p != NULL && !signature_get_algorithm_id(ctx, p))
+ return 0;
+
+ return 1;
+}
+
+static const OSSL_PARAM signature_gettable_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *signature_gettable_ctx_params(void *vctx, void *provctx)
+{
+ return signature_gettable_params;
+}
+
+static int signature_signverify_init(GOST_SIGNATURE_CTX *ctx, void *key_data,
+ const OSSL_PARAM params[], int operation)
+{
+ ctx->key_data = keymgmt_dup(key_data,
+ (OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS |
+ (operation == SIGN_OPERATION ?
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY :
+ OSSL_KEYMGMT_SELECT_PUBLIC_KEY)));
+ if (ctx->key_data == NULL)
+ return 0;
+
+ ctx->operation = operation;
+
+ if (!signature_set_ctx_params(ctx, params))
+ return 0;
+
+ return 1;
+}
+
+static int signature_digest_signverify_init(GOST_SIGNATURE_CTX *ctx, const char *mdname,
+ void *key_data, const OSSL_PARAM params[],
+ int operation)
+{
+ if (!ctx
+ || !ctx->provctx
+ || !ctx->provctx->libctx
+ || !key_data)
+ goto error;
+
+ if (!signature_signverify_init(ctx, key_data, params,
+ operation))
+ goto error;
+
+ if ((mdname != NULL) && !signature_setup_md(ctx, mdname, NULL))
+ goto error;
+
+ if (!ctx->md)
+ goto error;
+
+ if (ctx->mdctx == NULL && ((ctx->mdctx = EVP_MD_CTX_new()) == NULL))
+ goto error_clean_md;
+
+ if (!EVP_DigestInit_ex2(ctx->mdctx, ctx->md, params))
+ goto error_clean_md;
+
+ return 1;
+error_clean_md:
+ EVP_MD_CTX_free(ctx->mdctx);
+ EVP_MD_free(ctx->md);
+ ctx->md = NULL;
+ ctx->mdctx = NULL;
+error:
+ return 0;
+}
+
+static int signature_signverify_message_update(GOST_SIGNATURE_CTX *ctx,
+ const unsigned char *data, size_t datalen)
+{
+ if (!ctx->mdctx)
+ return 0;
+
+ if (!data && datalen)
+ return 0;
+
+ return EVP_DigestUpdate(ctx->mdctx, data, datalen);
+}
+
+static int signature_digest_sign_init(void *ctx, const char *mdname,
+ void *provkey,
+ const OSSL_PARAM params[])
+{
+ return signature_digest_signverify_init(ctx, mdname, provkey, params, SIGN_OPERATION);
+}
+
+static int signature_digest_sign_update(void *vctx, const unsigned char *data,
+ size_t datalen)
+{
+ GOST_SIGNATURE_CTX *ctx = vctx;
+
+ if (!ctx || ctx->operation != SIGN_OPERATION)
+ return 0;
+
+ return signature_signverify_message_update(ctx, data, datalen);
+}
+
+static int signature_digest_sign_final(void *vctx, unsigned char *sig,
+ size_t *siglen, size_t sigsize)
+{
+ GOST_SIGNATURE_CTX *ctx = vctx;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int dlen = 0;
+
+ if (!ctx
+ || !ctx->mdctx
+ || !siglen
+ || ctx->operation != SIGN_OPERATION)
+ return 0;
+
+ if (sig != NULL
+ && !EVP_DigestFinal_ex(ctx->mdctx, digest, &dlen))
+ return 0;
+
+ *siglen = sigsize;
+ return internal_pkey_ec_cp_sign(ctx->key_data->ec, ctx->key_data->type, sig,
+ siglen, digest, dlen);
+}
+
+static int signature_digest_verify_init(void *ctx, const char *mdname,
+ void *provkey,
+ const OSSL_PARAM params[])
+{
+ return signature_digest_signverify_init(ctx, mdname, provkey, params, VERIFY_OPERATION);
+}
+
+static int signature_digest_verify_update(void *vctx, const unsigned char *data,
+ size_t datalen)
+{
+ GOST_SIGNATURE_CTX *ctx = vctx;
+
+ if (!ctx || ctx->operation != VERIFY_OPERATION)
+ return 0;
+
+ return signature_signverify_message_update(ctx, data, datalen);
+}
+
+static int signature_digest_verify_final(void *vctx, const unsigned char *sig,
+ size_t siglen)
+{
+ GOST_SIGNATURE_CTX *ctx = vctx;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int dlen = 0;
+
+ if (!sig || !ctx || !ctx->mdctx || ctx->operation != VERIFY_OPERATION)
+ return 0;
+
+ if (!EVP_DigestFinal_ex(ctx->mdctx, digest, &dlen))
+ return 0;
+
+ return internal_pkey_ec_cp_verify(ctx->key_data->ec, sig, siglen, digest, dlen);
+}
+
+typedef void (*fptr_t)(void);
+static const OSSL_DISPATCH id_signature_functions[] = {
+ { OSSL_FUNC_SIGNATURE_NEWCTX, (fptr_t)signature_newctx },
+ { OSSL_FUNC_SIGNATURE_FREECTX, (fptr_t)signature_free },
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (fptr_t)signature_get_ctx_params },
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, (fptr_t)signature_gettable_ctx_params},
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (fptr_t)signature_digest_sign_init },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, (fptr_t)signature_digest_sign_update },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, (fptr_t)signature_digest_sign_final },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, (fptr_t)signature_digest_verify_init },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE, (fptr_t)signature_digest_verify_update },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL, (fptr_t)signature_digest_verify_final},
+ { 0, NULL }
+};
+
+const OSSL_ALGORITHM GOST_prov_signature[] = {
+ {
+ SN_id_GostR3410_2001
+ ":" SN_id_GostR3411_94_with_GostR3410_2001
+ ":" LN_id_GostR3411_94_with_GostR3410_2001
+ ":" OID_id_GostR3411_94_with_GostR3410_2001,
+ NULL,
+ id_signature_functions
+ },
+ {
+ SN_id_GostR3410_2012_256
+ ":" SN_id_tc26_signwithdigest_gost3410_2012_256
+ ":" LN_id_tc26_signwithdigest_gost3410_2012_256
+ ":" OID_id_tc26_signwithdigest_gost3410_2012_256,
+ NULL,
+ id_signature_functions
+ },
+ {
+ SN_id_GostR3410_2012_512
+ ":" SN_id_tc26_signwithdigest_gost3410_2012_512
+ ":" LN_id_tc26_signwithdigest_gost3410_2012_512
+ ":" OID_id_tc26_signwithdigest_gost3410_2012_512,
+ NULL,
+ id_signature_functions
+ },
+ { NULL, NULL, NULL }
+};
--- /dev/null
+#include "gost_prov_tls.h"
+
+#include <openssl/core_names.h>
+#include <openssl/objects.h>
+#include <openssl/params.h>
+#include <openssl/prov_ssl.h>
+
+#define OSSL_TLS_GROUP_ID_gc256A 0x0022
+#define OSSL_TLS_GROUP_ID_gc256B 0x0023
+#define OSSL_TLS_GROUP_ID_gc256C 0x0024
+#define OSSL_TLS_GROUP_ID_gc256D 0x0025
+#define OSSL_TLS_GROUP_ID_gc512A 0x0026
+#define OSSL_TLS_GROUP_ID_gc512B 0x0027
+#define OSSL_TLS_GROUP_ID_gc512C 0x0028
+
+typedef struct tls_group_constants_st {
+ unsigned int group_id; /* Group ID */
+ unsigned int secbits; /* Bits of security */
+ int mintls; /* Minimum TLS version, -1 unsupported */
+ int maxtls; /* Maximum TLS version (or 0 for undefined) */
+ int mindtls; /* Minimum DTLS version, -1 unsupported */
+ int maxdtls; /* Maximum DTLS version (or 0 for undefined) */
+} TLS_GROUP_CONSTANTS;
+
+static const TLS_GROUP_CONSTANTS group_list[] = {
+ { OSSL_TLS_GROUP_ID_gc256A, 128, TLS1_3_VERSION, 0, -1, -1 },
+ { OSSL_TLS_GROUP_ID_gc256B, 128, TLS1_3_VERSION, 0, -1, -1 },
+ { OSSL_TLS_GROUP_ID_gc256C, 128, TLS1_3_VERSION, 0, -1, -1 },
+ { OSSL_TLS_GROUP_ID_gc256D, 128, TLS1_3_VERSION, 0, -1, -1 },
+ { OSSL_TLS_GROUP_ID_gc512A, 256, TLS1_3_VERSION, 0, -1, -1 },
+ { OSSL_TLS_GROUP_ID_gc512B, 256, TLS1_3_VERSION, 0, -1, -1 },
+ { OSSL_TLS_GROUP_ID_gc512C, 256, TLS1_3_VERSION, 0, -1, -1 },
+};
+
+#define TLS_GROUP_ENTRY(group_name, name_internal, alg, idx) \
+ { \
+ OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_NAME, \
+ group_name, sizeof(group_name)), \
+ OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_NAME_INTERNAL, \
+ name_internal, sizeof(name_internal)), \
+ OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_ALG, \
+ alg, sizeof(alg)), \
+ OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_ID, \
+ (unsigned int *)&group_list[idx].group_id), \
+ OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_SECURITY_BITS, \
+ (unsigned int *)&group_list[idx].secbits), \
+ OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MIN_TLS, \
+ (unsigned int *)&group_list[idx].mintls), \
+ OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MAX_TLS, \
+ (unsigned int *)&group_list[idx].maxtls), \
+ OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MIN_DTLS, \
+ (unsigned int *)&group_list[idx].mindtls), \
+ OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MAX_DTLS, \
+ (unsigned int *)&group_list[idx].maxdtls), \
+ OSSL_PARAM_END \
+ }
+
+static const OSSL_PARAM param_group_list[][10] = {
+ TLS_GROUP_ENTRY("GC256A", "TCA", SN_id_GostR3410_2012_256, 0),
+ TLS_GROUP_ENTRY("GC256B", "TCB", SN_id_GostR3410_2012_256, 1),
+ TLS_GROUP_ENTRY("GC256C", "TCC", SN_id_GostR3410_2012_256, 2),
+ TLS_GROUP_ENTRY("GC256D", "TCD", SN_id_GostR3410_2012_256, 3),
+ TLS_GROUP_ENTRY("GC512A", "A", SN_id_GostR3410_2012_512, 4),
+ TLS_GROUP_ENTRY("GC512B", "B", SN_id_GostR3410_2012_512, 5),
+ TLS_GROUP_ENTRY("GC512C", "C", SN_id_GostR3410_2012_512, 6),
+};
+
+int gost_prov_get_tls_group_capability(OSSL_CALLBACK *cb, void *arg)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof(param_group_list) / sizeof(param_group_list[0]); i++)
+ if (!cb(param_group_list[i], arg))
+ return 0;
+ return 1;
+}
+
+#define TLS_SIGALG_gostr34102012_256a 0x0709
+#define TLS_SIGALG_gostr34102012_256b 0x070A
+#define TLS_SIGALG_gostr34102012_256c 0x070B
+#define TLS_SIGALG_gostr34102012_256d 0x070C
+#define TLS_SIGALG_gostr34102012_512a 0x070D
+#define TLS_SIGALG_gostr34102012_512b 0x070E
+#define TLS_SIGALG_gostr34102012_512c 0x070F
+
+typedef struct tls_sigalg_constants_st {
+ unsigned int code_point; /* SignatureScheme */
+ unsigned int secbits; /* Bits of security */
+ int mintls; /* Minimum TLS version, -1 unsupported */
+ int maxtls; /* Maximum TLS version (or 0 for undefined) */
+} TLS_SIGALG_CONSTANTS;
+
+static const TLS_SIGALG_CONSTANTS gost_sigalg_constants[] = {
+ { TLS_SIGALG_gostr34102012_256a, 128, TLS1_3_VERSION, TLS1_3_VERSION },
+ { TLS_SIGALG_gostr34102012_256b, 128, TLS1_3_VERSION, TLS1_3_VERSION },
+ { TLS_SIGALG_gostr34102012_256c, 128, TLS1_3_VERSION, TLS1_3_VERSION },
+ { TLS_SIGALG_gostr34102012_256d, 128, TLS1_3_VERSION, TLS1_3_VERSION },
+ { TLS_SIGALG_gostr34102012_512a, 256, TLS1_3_VERSION, TLS1_3_VERSION },
+ { TLS_SIGALG_gostr34102012_512b, 256, TLS1_3_VERSION, TLS1_3_VERSION },
+ { TLS_SIGALG_gostr34102012_512c, 256, TLS1_3_VERSION, TLS1_3_VERSION },
+};
+
+#define TLS_SIGALG_ENTRY(iana_name, sigalg_name, hash_name, idx) \
+ { \
+ OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_SIGALG_IANA_NAME, iana_name, sizeof(iana_name)), \
+ OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_SIGALG_CODE_POINT, \
+ (unsigned int *)&gost_sigalg_constants[idx].code_point), \
+ OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_SIGALG_NAME, sigalg_name, sizeof(sigalg_name)), \
+ OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_SIGALG_HASH_NAME, hash_name, sizeof(hash_name)), \
+ OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_SIGALG_SECURITY_BITS, \
+ (unsigned int *)&gost_sigalg_constants[idx].secbits), \
+ OSSL_PARAM_int(OSSL_CAPABILITY_TLS_SIGALG_MIN_TLS, \
+ (int *)&gost_sigalg_constants[idx].mintls), \
+ OSSL_PARAM_int(OSSL_CAPABILITY_TLS_SIGALG_MAX_TLS, \
+ (int *)&gost_sigalg_constants[idx].maxtls), \
+ OSSL_PARAM_END \
+ }
+
+static const OSSL_PARAM param_sigalg_list[][8] = {
+ TLS_SIGALG_ENTRY("gostr34102012_256a", SN_id_GostR3410_2012_256,
+ SN_id_GostR3411_2012_256, 0),
+ TLS_SIGALG_ENTRY("gostr34102012_256b", SN_id_GostR3410_2012_256,
+ SN_id_GostR3411_2012_256, 1),
+ TLS_SIGALG_ENTRY("gostr34102012_256c", SN_id_GostR3410_2012_256,
+ SN_id_GostR3411_2012_256, 2),
+ TLS_SIGALG_ENTRY("gostr34102012_256d", SN_id_GostR3410_2012_256,
+ SN_id_GostR3411_2012_256, 3),
+ TLS_SIGALG_ENTRY("gostr34102012_512a", SN_id_GostR3410_2012_512,
+ SN_id_GostR3411_2012_512, 4),
+ TLS_SIGALG_ENTRY("gostr34102012_512b", SN_id_GostR3410_2012_512,
+ SN_id_GostR3411_2012_512, 5),
+ TLS_SIGALG_ENTRY("gostr34102012_512c", SN_id_GostR3410_2012_512,
+ SN_id_GostR3411_2012_512, 6)
+};
+
+int gost_prov_get_tls_sigalg_capability(OSSL_CALLBACK *cb, void *arg)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof(param_sigalg_list) / sizeof(param_sigalg_list[0]); i++)
+ if (!cb(param_sigalg_list[i], arg))
+ return 0;
+
+ return 1;
+}
--- /dev/null
+#pragma once
+
+#include <openssl/core.h>
+
+int gost_prov_get_tls_group_capability(OSSL_CALLBACK *cb, void *arg);
+int gost_prov_get_tls_sigalg_capability(OSSL_CALLBACK *cb, void *arg);
\ No newline at end of file
--- /dev/null
+diff --git a/openssl/crypto/evp/evp_enc.c b/openssl/crypto/evp/evp_enc.c
+index f96d46f..1c657ce 100644
+--- a/openssl/crypto/evp/evp_enc.c
++++ b/openssl/crypto/evp/evp_enc.c
+@@ -1293,6 +1293,14 @@ int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
+ params[0] = OSSL_PARAM_construct_octet_string(
+ OSSL_CIPHER_PARAM_AEAD_MAC_KEY, ptr, sz);
+ break;
++ case EVP_CTRL_TLSTREE:
++ params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_TLSTREE, ptr, sz);
++ params[1] = OSSL_PARAM_construct_end();
++ break;
++ case EVP_CTRL_SET_TLSTREE_PARAMS:
++ params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_TLSTREE_MODE, ptr, sz);
++ params[1] = OSSL_PARAM_construct_end();
++ break;
+ }
+
+ if (set_params)
+diff --git a/openssl/crypto/objects/obj_dat.h b/openssl/crypto/objects/obj_dat.h
+index 4c61e96..8237adf 100644
+--- a/openssl/crypto/objects/obj_dat.h
++++ b/openssl/crypto/objects/obj_dat.h
+@@ -1187,7 +1187,7 @@ static const unsigned char so[8504] = {
+ 0x2B,0x06,0x01,0x04,0x01,0x82,0xE4,0x25,0x01, /* [ 8494] OBJ_id_kp_wisun_fan_device */
+ };
+
+-#define NUM_NID 1324
++#define NUM_NID 1326
+ static const ASN1_OBJECT nid_objs[NUM_NID] = {
+ {"UNDEF", "undefined", NID_undef},
+ {"rsadsi", "RSA Data Security, Inc.", NID_rsadsi, 6, &so[0]},
+@@ -2513,6 +2513,8 @@ static const ASN1_OBJECT nid_objs[NUM_NID] = {
+ {"id-on-hardwareModuleName", "Hardware Module Name", NID_id_on_hardwareModuleName, 8, &so[8486]},
+ {"id-kp-wisun-fan-device", "Wi-SUN Alliance Field Area Network (FAN)", NID_id_kp_wisun_fan_device, 9, &so[8494]},
+ {"NULL", "NULL", NID_ac_auditEntity},
++ {"magma-mgm", "magma-mgm", NID_magma_mgm},
++ {"kuznyechik-mgm", "kuznyechik-mgm", NID_kuznyechik_mgm},
+ };
+
+ #define NUM_SN 1315
+diff --git a/openssl/include/openssl/evp.h b/openssl/include/openssl/evp.h
+index 5466327..19c3b8e 100644
+--- a/openssl/include/openssl/evp.h
++++ b/openssl/include/openssl/evp.h
+@@ -439,6 +439,7 @@ OSSL_DEPRECATEDIN_3_0 int
+ #define EVP_CTRL_GET_WRAP_CIPHER 0x29
+ /* TLSTREE key diversification */
+ #define EVP_CTRL_TLSTREE 0x2A
++#define EVP_CTRL_SET_TLSTREE_PARAMS 0x2B
+
+ /* Padding modes */
+ #define EVP_PADDING_PKCS7 1
+@@ -477,6 +478,10 @@ typedef struct {
+ /* Length of CCM8 tag for TLS */
+ # define EVP_CCM8_TLS_TAG_LEN 8
+
++/* GOST TLS 1.3 tag lengths */
++# define EVP_MAGMA_TLS_TAG_LEN 8
++# define EVP_KUZNYECHIK_TLS_TAG_LEN 16
++
+ /* Length of tag for TLS */
+ # define EVP_CHACHAPOLY_TLS_TAG_LEN 16
+
+diff --git a/openssl/include/openssl/obj_mac.h b/openssl/include/openssl/obj_mac.h
+index ea603c2..ea4af43 100644
+--- a/openssl/include/openssl/obj_mac.h
++++ b/openssl/include/openssl/obj_mac.h
+@@ -4880,6 +4880,9 @@
+ #define SN_kuznyechik_mac "kuznyechik-mac"
+ #define NID_kuznyechik_mac 1017
+
++#define SN_kuznyechik_mgm "kuznyechik-mgm"
++#define NID_kuznyechik_mgm 1325
++
+ #define SN_magma_ecb "magma-ecb"
+ #define NID_magma_ecb 1187
+
+@@ -4898,6 +4901,9 @@
+ #define SN_magma_mac "magma-mac"
+ #define NID_magma_mac 1192
+
++#define SN_magma_mgm "magma-mgm"
++#define NID_magma_mgm 1324
++
+ #define SN_camellia_128_cbc "CAMELLIA-128-CBC"
+ #define LN_camellia_128_cbc "camellia-128-cbc"
+ #define NID_camellia_128_cbc 751
+diff --git a/openssl/include/openssl/tls1.h b/openssl/include/openssl/tls1.h
+index 8e9b110..8cadff9 100644
+--- a/openssl/include/openssl/tls1.h
++++ b/openssl/include/openssl/tls1.h
+@@ -658,6 +658,12 @@ int SSL_CTX_set_tlsext_ticket_key_evp_cb
+ # define TLS1_CK_RSA_PSK_WITH_ARIA_128_GCM_SHA256 0x0300C06E
+ # define TLS1_CK_RSA_PSK_WITH_ARIA_256_GCM_SHA384 0x0300C06F
+
++/* TLS1.3 GOST ciphersuites from RFC9367 */
++# define TLS1_3_CK_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L 0x0300C103
++# define TLS1_3_CK_GOSTR341112_256_WITH_MAGMA_MGM_L 0x0300C104
++# define TLS1_3_CK_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S 0x0300C105
++# define TLS1_3_CK_GOSTR341112_256_WITH_MAGMA_MGM_S 0x0300C106
++
+ /* a bundle of RFC standard cipher names, generated from ssl3_ciphers[] */
+ # define TLS1_RFC_RSA_WITH_AES_128_SHA "TLS_RSA_WITH_AES_128_CBC_SHA"
+ # define TLS1_RFC_DHE_DSS_WITH_AES_128_SHA "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"
+@@ -850,6 +856,10 @@ int SSL_CTX_set_tlsext_ticket_key_evp_cb
+ # define TLS1_RFC_DHE_PSK_WITH_ARIA_256_GCM_SHA384 "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384"
+ # define TLS1_RFC_RSA_PSK_WITH_ARIA_128_GCM_SHA256 "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256"
+ # define TLS1_RFC_RSA_PSK_WITH_ARIA_256_GCM_SHA384 "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384"
++# define TLS1_RFC_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L"
++# define TLS1_RFC_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S"
++# define TLS1_RFC_GOSTR341112_256_WITH_MAGMA_MGM_L "TLS_GOSTR341112_256_WITH_MAGMA_MGM_L"
++# define TLS1_RFC_GOSTR341112_256_WITH_MAGMA_MGM_S "TLS_GOSTR341112_256_WITH_MAGMA_MGM_S"
+
+
+ /*
+diff --git a/openssl/ssl/record/methods/tls13_meth.c b/openssl/ssl/record/methods/tls13_meth.c
+index 6bbba84..40cbc0c 100644
+--- a/openssl/ssl/record/methods/tls13_meth.c
++++ b/openssl/ssl/record/methods/tls13_meth.c
+@@ -78,6 +78,18 @@ static int tls13_set_crypto_state(OSSL_RECORD_LAYER *rl, int level,
+ ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
+ return OSSL_RECORD_RETURN_FATAL;
+ }
++
++ if (!rl->isdtls && rl->tlstree) {
++ int res = 0;
++
++ if (rl->tlstree & TLS1_TLSTREE_S)
++ res = EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_SET_TLSTREE_PARAMS, 0, "strong");
++ else if (rl->tlstree & TLS1_TLSTREE_L)
++ res = EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_SET_TLSTREE_PARAMS, 0, "light");
++
++ if (res <= 0)
++ return OSSL_RECORD_RETURN_FATAL;
++ }
+ end:
+ return OSSL_RECORD_RETURN_SUCCESS;
+ }
+@@ -162,6 +174,11 @@ static int tls13_cipher(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *recs,
+ for (loop = 0; loop < SEQ_NUM_SIZE; loop++)
+ nonce[offset + loop] = staticiv[offset + loop] ^ seq[loop];
+
++ if (!rl->isdtls && rl->tlstree && EVP_CIPHER_CTX_ctrl(enc_ctx, EVP_CTRL_TLSTREE, 0, seq) <= 0) {
++ RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++ return 0;
++ }
++
+ if (!tls_increment_sequence_ctr(rl)) {
+ /* RLAYERfatal already called */
+ return 0;
+diff --git a/openssl/ssl/record/rec_layer_s3.c b/openssl/ssl/record/rec_layer_s3.c
+index cce236b..48fedcb 100644
+--- a/openssl/ssl/record/rec_layer_s3.c
++++ b/openssl/ssl/record/rec_layer_s3.c
+@@ -1310,6 +1310,10 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
+ tlstree = 1;
+ }
+
++ if (SSL_CONNECTION_IS_TLS13(s))
++ tlstree = (s->s3.tmp.new_cipher->algorithm2 & TLS1_TLSTREE_L)
++ | (s->s3.tmp.new_cipher->algorithm2 & TLS1_TLSTREE_S);
++
+ if (use_etm)
+ *set++ = OSSL_PARAM_construct_int(OSSL_LIBSSL_RECORD_LAYER_PARAM_USE_ETM,
+ &use_etm);
+diff --git a/openssl/ssl/s3_lib.c b/openssl/ssl/s3_lib.c
+index 86d8198..19edb89 100644
+--- a/openssl/ssl/s3_lib.c
++++ b/openssl/ssl/s3_lib.c
+@@ -146,6 +146,72 @@ static SSL_CIPHER tls13_ciphers[] = {
+ 384,
+ },
+ #endif
++#ifndef OPENSSL_NO_GOST
++ {
++ 1,
++ TLS1_RFC_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L,
++ TLS1_RFC_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L,
++ TLS1_3_CK_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L,
++ SSL_kANY,
++ SSL_aANY,
++ SSL_KUZNYECHIK_MGM,
++ SSL_AEAD,
++ TLS1_3_VERSION, TLS1_3_VERSION,
++ 0, 0,
++ SSL_HIGH,
++ SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_PRF_GOST12_256 | TLS1_TLSTREE | TLS1_TLSTREE_L,
++ 256,
++ 256,
++ },
++ {
++ 1,
++ TLS1_RFC_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S,
++ TLS1_RFC_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S,
++ TLS1_3_CK_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S,
++ SSL_kANY,
++ SSL_aANY,
++ SSL_KUZNYECHIK_MGM,
++ SSL_AEAD,
++ TLS1_3_VERSION, TLS1_3_VERSION,
++ 0, 0,
++ SSL_HIGH,
++ SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_PRF_GOST12_256 | TLS1_TLSTREE | TLS1_TLSTREE_S,
++ 256,
++ 256,
++ },
++ {
++ 1,
++ TLS1_RFC_GOSTR341112_256_WITH_MAGMA_MGM_L,
++ TLS1_RFC_GOSTR341112_256_WITH_MAGMA_MGM_L,
++ TLS1_3_CK_GOSTR341112_256_WITH_MAGMA_MGM_L,
++ SSL_kANY,
++ SSL_aANY,
++ SSL_MAGMA_MGM,
++ SSL_AEAD,
++ TLS1_3_VERSION, TLS1_3_VERSION,
++ 0, 0,
++ SSL_HIGH,
++ SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_PRF_GOST12_256 | TLS1_TLSTREE | TLS1_TLSTREE_L,
++ 256,
++ 256,
++ },
++ {
++ 1,
++ TLS1_RFC_GOSTR341112_256_WITH_MAGMA_MGM_S,
++ TLS1_RFC_GOSTR341112_256_WITH_MAGMA_MGM_S,
++ TLS1_3_CK_GOSTR341112_256_WITH_MAGMA_MGM_S,
++ SSL_kANY,
++ SSL_aANY,
++ SSL_MAGMA_MGM,
++ SSL_AEAD,
++ TLS1_3_VERSION, TLS1_3_VERSION,
++ 0, 0,
++ SSL_HIGH,
++ SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_PRF_GOST12_256 | TLS1_TLSTREE | TLS1_TLSTREE_S,
++ 256,
++ 256,
++ },
++#endif
+ };
+
+ /*
+diff --git a/openssl/ssl/ssl_ciph.c b/openssl/ssl/ssl_ciph.c
+index e5d6237..78dd7de 100644
+--- a/openssl/ssl/ssl_ciph.c
++++ b/openssl/ssl/ssl_ciph.c
+@@ -54,8 +54,10 @@ static const ssl_cipher_table ssl_cipher_table_cipher[SSL_ENC_NUM_IDX] = {
+ {SSL_CHACHA20POLY1305, NID_chacha20_poly1305}, /* SSL_ENC_CHACHA_IDX 19 */
+ {SSL_ARIA128GCM, NID_aria_128_gcm}, /* SSL_ENC_ARIA128GCM_IDX 20 */
+ {SSL_ARIA256GCM, NID_aria_256_gcm}, /* SSL_ENC_ARIA256GCM_IDX 21 */
+- {SSL_MAGMA, NID_magma_ctr_acpkm}, /* SSL_ENC_MAGMA_IDX */
+- {SSL_KUZNYECHIK, NID_kuznyechik_ctr_acpkm}, /* SSL_ENC_KUZNYECHIK_IDX */
++ {SSL_MAGMA, NID_magma_ctr_acpkm}, /* SSL_ENC_MAGMA_IDX 22 */
++ {SSL_KUZNYECHIK, NID_kuznyechik_ctr_acpkm}, /* SSL_ENC_KUZNYECHIK_IDX 23 */
++ {SSL_MAGMA_MGM, NID_magma_mgm}, /* SSL_ENC_MAGMA_MGM_IDX 24 */
++ {SSL_KUZNYECHIK_MGM, NID_kuznyechik_mgm}, /* SSL_ENC_KUZNYECHIK_MGM_IDX 25 */
+ };
+
+ /* NB: make sure indices in this table matches values above */
+@@ -310,6 +312,23 @@ static int get_optional_pkey_id(const char *pkey_name)
+
+ #endif
+
++/* Checks to see if algorithms are fetchable */
++#define IS_FETCHABLE(type, TYPE) \
++ static int is_ ## type ## _fetchable(SSL_CTX *ctx, const char *name) \
++ { \
++ TYPE *impl; \
++ \
++ ERR_set_mark(); \
++ impl = TYPE ## _fetch(ctx->libctx, name, ctx->propq); \
++ ERR_pop_to_mark(); \
++ if (impl == NULL) \
++ return 0; \
++ TYPE ## _free(impl); \
++ return 1; \
++ }
++
++IS_FETCHABLE(keymgmt, EVP_KEYMGMT)
++
+ int ssl_load_ciphers(SSL_CTX *ctx)
+ {
+ size_t i;
+@@ -418,11 +437,14 @@ int ssl_load_ciphers(SSL_CTX *ctx)
+ else
+ ctx->disabled_mac_mask |= SSL_KUZNYECHIKOMAC;
+
+- if (!get_optional_pkey_id(SN_id_GostR3410_2001))
++ if (!get_optional_pkey_id(SN_id_GostR3410_2001)
++ && !is_keymgmt_fetchable(ctx, SN_id_GostR3410_2001))
+ ctx->disabled_auth_mask |= SSL_aGOST01 | SSL_aGOST12;
+- if (!get_optional_pkey_id(SN_id_GostR3410_2012_256))
++ if (!get_optional_pkey_id(SN_id_GostR3410_2012_256)
++ && !is_keymgmt_fetchable(ctx, SN_id_GostR3410_2012_256))
+ ctx->disabled_auth_mask |= SSL_aGOST12;
+- if (!get_optional_pkey_id(SN_id_GostR3410_2012_512))
++ if (!get_optional_pkey_id(SN_id_GostR3410_2012_512)
++ && !is_keymgmt_fetchable(ctx, SN_id_GostR3410_2012_512))
+ ctx->disabled_auth_mask |= SSL_aGOST12;
+ /*
+ * Disable GOST key exchange if no GOST signature algs are available *
+@@ -1827,9 +1849,15 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
+ case SSL_MAGMA:
+ enc = "MAGMA";
+ break;
++ case SSL_MAGMA_MGM:
++ enc = "MAGMAMGM";
++ break;
+ case SSL_KUZNYECHIK:
+ enc = "KUZNYECHIK";
+ break;
++ case SSL_KUZNYECHIK_MGM:
++ enc = "KUZNYECHIKMGM";
++ break;
+ case SSL_CHACHA20POLY1305:
+ enc = "CHACHA20/POLY1305(256)";
+ break;
+diff --git a/openssl/ssl/ssl_local.h b/openssl/ssl/ssl_local.h
+index 277be30..bf36ac7 100644
+--- a/openssl/ssl/ssl_local.h
++++ b/openssl/ssl/ssl_local.h
+@@ -153,6 +153,8 @@
+ # define SSL_ARIA256GCM 0x00200000U
+ # define SSL_MAGMA 0x00400000U
+ # define SSL_KUZNYECHIK 0x00800000U
++# define SSL_MAGMA_MGM 0x01000000U
++# define SSL_KUZNYECHIK_MGM 0x02000000U
+
+ # define SSL_AESGCM (SSL_AES128GCM | SSL_AES256GCM)
+ # define SSL_AESCCM (SSL_AES128CCM | SSL_AES256CCM | SSL_AES128CCM8 | SSL_AES256CCM8)
+@@ -235,7 +237,9 @@
+ * TLSTREE cipher/mac key derivation from draft-smyshlyaev-tls12-gost-suites
+ * (currently this also goes into algorithm2)
+ */
+-# define TLS1_TLSTREE 0x20000
++# define TLS1_TLSTREE 0x20000
++# define TLS1_TLSTREE_S 0x40000
++# define TLS1_TLSTREE_L 0x80000
+
+ /* Ciphersuite supported in QUIC */
+ # define SSL_QUIC 0x00040000U
+@@ -335,31 +339,33 @@
+ # define SSL_PKEY_ED448 8
+ # define SSL_PKEY_NUM 9
+
+-# define SSL_ENC_DES_IDX 0
+-# define SSL_ENC_3DES_IDX 1
+-# define SSL_ENC_RC4_IDX 2
+-# define SSL_ENC_RC2_IDX 3
+-# define SSL_ENC_IDEA_IDX 4
+-# define SSL_ENC_NULL_IDX 5
+-# define SSL_ENC_AES128_IDX 6
+-# define SSL_ENC_AES256_IDX 7
+-# define SSL_ENC_CAMELLIA128_IDX 8
+-# define SSL_ENC_CAMELLIA256_IDX 9
+-# define SSL_ENC_GOST89_IDX 10
+-# define SSL_ENC_SEED_IDX 11
+-# define SSL_ENC_AES128GCM_IDX 12
+-# define SSL_ENC_AES256GCM_IDX 13
+-# define SSL_ENC_AES128CCM_IDX 14
+-# define SSL_ENC_AES256CCM_IDX 15
+-# define SSL_ENC_AES128CCM8_IDX 16
+-# define SSL_ENC_AES256CCM8_IDX 17
+-# define SSL_ENC_GOST8912_IDX 18
+-# define SSL_ENC_CHACHA_IDX 19
+-# define SSL_ENC_ARIA128GCM_IDX 20
+-# define SSL_ENC_ARIA256GCM_IDX 21
+-# define SSL_ENC_MAGMA_IDX 22
+-# define SSL_ENC_KUZNYECHIK_IDX 23
+-# define SSL_ENC_NUM_IDX 24
++# define SSL_ENC_DES_IDX 0
++# define SSL_ENC_3DES_IDX 1
++# define SSL_ENC_RC4_IDX 2
++# define SSL_ENC_RC2_IDX 3
++# define SSL_ENC_IDEA_IDX 4
++# define SSL_ENC_NULL_IDX 5
++# define SSL_ENC_AES128_IDX 6
++# define SSL_ENC_AES256_IDX 7
++# define SSL_ENC_CAMELLIA128_IDX 8
++# define SSL_ENC_CAMELLIA256_IDX 9
++# define SSL_ENC_GOST89_IDX 10
++# define SSL_ENC_SEED_IDX 11
++# define SSL_ENC_AES128GCM_IDX 12
++# define SSL_ENC_AES256GCM_IDX 13
++# define SSL_ENC_AES128CCM_IDX 14
++# define SSL_ENC_AES256CCM_IDX 15
++# define SSL_ENC_AES128CCM8_IDX 16
++# define SSL_ENC_AES256CCM8_IDX 17
++# define SSL_ENC_GOST8912_IDX 18
++# define SSL_ENC_CHACHA_IDX 19
++# define SSL_ENC_ARIA128GCM_IDX 20
++# define SSL_ENC_ARIA256GCM_IDX 21
++# define SSL_ENC_MAGMA_IDX 22
++# define SSL_ENC_KUZNYECHIK_IDX 23
++# define SSL_ENC_MAGMA_MGM_IDX 24
++# define SSL_ENC_KUZNYECHIK_MGM_IDX 25
++# define SSL_ENC_NUM_IDX 26
+
+ /*-
+ * SSL_kRSA <- RSA_ENC
+diff --git a/openssl/ssl/statem/statem_lib.c b/openssl/ssl/statem/statem_lib.c
+index a52b8af..6437f66 100644
+--- a/openssl/ssl/statem/statem_lib.c
++++ b/openssl/ssl/statem/statem_lib.c
+@@ -501,10 +501,10 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL_CONNECTION *s, PACKET *pkt)
+ #ifndef OPENSSL_NO_GOST
+ if (!SSL_USE_SIGALGS(s)
+ && ((PACKET_remaining(pkt) == 64
+- && (EVP_PKEY_get_id(pkey) == NID_id_GostR3410_2001
+- || EVP_PKEY_get_id(pkey) == NID_id_GostR3410_2012_256))
++ && (EVP_PKEY_is_a(pkey, SN_id_GostR3410_2001)
++ || EVP_PKEY_is_a(pkey, SN_id_GostR3410_2012_256)))
+ || (PACKET_remaining(pkt) == 128
+- && EVP_PKEY_get_id(pkey) == NID_id_GostR3410_2012_512))) {
++ && EVP_PKEY_is_a(pkey, SN_id_GostR3410_2012_512)))) {
+ len = PACKET_remaining(pkt);
+ } else
+ #endif
+@@ -539,10 +539,9 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL_CONNECTION *s, PACKET *pkt)
+ }
+ #ifndef OPENSSL_NO_GOST
+ {
+- int pktype = EVP_PKEY_get_id(pkey);
+- if (pktype == NID_id_GostR3410_2001
+- || pktype == NID_id_GostR3410_2012_256
+- || pktype == NID_id_GostR3410_2012_512) {
++ if (EVP_PKEY_is_a(pkey, SN_id_GostR3410_2001)
++ || EVP_PKEY_is_a(pkey, SN_id_GostR3410_2012_256)
++ || EVP_PKEY_is_a(pkey, SN_id_GostR3410_2012_512)) {
+ if ((gost_data = OPENSSL_malloc(len)) == NULL)
+ goto err;
+ BUF_reverse(gost_data, data, len);
+@@ -1931,8 +1930,6 @@ static int is_tls13_capable(const SSL_CONNECTION *s)
+ switch (i) {
+ case SSL_PKEY_DSA_SIGN:
+ case SSL_PKEY_GOST01:
+- case SSL_PKEY_GOST12_256:
+- case SSL_PKEY_GOST12_512:
+ continue;
+ default:
+ break;
+@@ -1949,6 +1946,15 @@ static int is_tls13_capable(const SSL_CONNECTION *s)
+ curve = ssl_get_EC_curve_nid(s->cert->pkeys[SSL_PKEY_ECC].privatekey);
+ if (tls_check_sigalg_curve(s, curve))
+ return 1;
++
++ /*
++ * TODO: There must be an opportunity to check that the sig algs are
++ * consistent with the keys in case if the sig algs are provider-based.
++ * For example, OSSL_FUNC_keymgmt_get_params could return the list of
++ * sig alg code points supported by the key, and this list could be
++ * checked against the sig algs code points stored in
++ * SSL_CTX.sigalg_lookup_cache
++ */
+ }
+
+ return 0;
+diff --git a/openssl/ssl/t1_lib.c b/openssl/ssl/t1_lib.c
+index bd85167..9b3b821 100644
+--- a/openssl/ssl/t1_lib.c
++++ b/openssl/ssl/t1_lib.c
+@@ -1565,14 +1565,19 @@ int ssl_setup_sigalgs(SSL_CTX *ctx)
+ /* Now complete cache and tls12_sigalgs list with provider sig information */
+ cache_idx = OSSL_NELEM(sigalg_lookup_tbl);
+ for (i = 0; i < ctx->sigalg_list_len; i++) {
++ size_t idx;
+ TLS_SIGALG_INFO si = ctx->sigalg_list[i];
++
++ if (!ssl_cert_lookup_by_nid(OBJ_txt2nid(si.sigalg_name), &idx, ctx))
++ goto err;
++
+ cache[cache_idx].name = si.name;
+ cache[cache_idx].sigalg = si.code_point;
+ tls12_sigalgs_list[cache_idx] = si.code_point;
+ cache[cache_idx].hash = si.hash_name?OBJ_txt2nid(si.hash_name):NID_undef;
+ cache[cache_idx].hash_idx = ssl_get_md_idx(cache[cache_idx].hash);
+ cache[cache_idx].sig = OBJ_txt2nid(si.sigalg_name);
+- cache[cache_idx].sig_idx = i + SSL_PKEY_NUM;
++ cache[cache_idx].sig_idx = idx;
+ cache[cache_idx].sigandhash = OBJ_txt2nid(si.sigalg_name);
+ cache[cache_idx].curve = NID_undef;
+ /* all provided sigalgs are enabled by load */
+@@ -2601,10 +2606,8 @@ static int tls12_sigalg_allowed(const SSL_CONNECTION *s, int op,
+ if (ssl_cert_is_disabled(SSL_CONNECTION_GET_CTX(s), lu->sig_idx))
+ return 0;
+
+- if (lu->sig == NID_id_GostR3410_2012_256
+- || lu->sig == NID_id_GostR3410_2012_512
+- || lu->sig == NID_id_GostR3410_2001) {
+- /* We never allow GOST sig algs on the server with TLSv1.3 */
++ if (lu->sig == NID_id_GostR3410_2001) {
++ /* We never allow GOST2001 sig algs on the server with TLSv1.3 */
+ if (s->server && SSL_CONNECTION_IS_TLS13(s))
+ return 0;
+ if (!s->server
+@@ -2640,6 +2643,18 @@ static int tls12_sigalg_allowed(const SSL_CONNECTION *s, int op,
+ }
+ }
+
++ /* TLS1.2 GOST sig algs could not be negotiated for the use in TLS1.3 */
++ if ((lu->sig == NID_id_GostR3410_2012_256 || lu->sig == NID_id_GostR3410_2012_512)
++ && (((s->server && SSL_CONNECTION_IS_TLS13(s)))
++ || (!s->server
++ && SSL_CONNECTION_GET_SSL(s)->method->version == TLS_ANY_VERSION
++ && s->s3.tmp.min_ver >= TLS1_3_VERSION))
++ && (strcmp(lu->name, TLSEXT_SIGALG_gostr34102012_256_intrinsic_name) == 0
++ || strcmp(lu->name, TLSEXT_SIGALG_gostr34102012_512_intrinsic_name) == 0
++ || strcmp(lu->name, TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256_name) == 0
++ || strcmp(lu->name, TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512_name) == 0))
++ return 0;
++
+ /* Finally see if security callback allows it */
+ secbits = sigalg_security_bits(SSL_CONNECTION_GET_CTX(s), lu);
+ sigalgstr[0] = (lu->sigalg >> 8) & 0xff;
+@@ -2994,9 +3009,12 @@ static int sig_cb(const char *elem, int len, void *arg)
+ if (sarg->ctx != NULL) {
+ /* Check if a provider supports the sigalg */
+ for (i = 0; i < sarg->ctx->sigalg_list_len; i++) {
+- if (sarg->ctx->sigalg_list[i].sigalg_name != NULL
+- && strcmp(etmp,
+- sarg->ctx->sigalg_list[i].sigalg_name) == 0) {
++ if ((sarg->ctx->sigalg_list[i].sigalg_name != NULL
++ && strcmp(etmp,
++ sarg->ctx->sigalg_list[i].sigalg_name) == 0)
++ || (sarg->ctx->sigalg_list[i].name != NULL
++ && strcmp(etmp,
++ sarg->ctx->sigalg_list[i].name) == 0)) {
+ sarg->sigalgs[sarg->sigalgcnt++] =
+ sarg->ctx->sigalg_list[i].code_point;
+ break;
+diff --git a/openssl/ssl/tls13_enc.c b/openssl/ssl/tls13_enc.c
+index 7846c73..ca81bb3 100644
+--- a/openssl/ssl/tls13_enc.c
++++ b/openssl/ssl/tls13_enc.c
+@@ -386,26 +386,26 @@ static int derive_secret_key_and_iv(SSL_CONNECTION *s, const EVP_MD *md,
+ *ivlen = *taglen = (size_t)mac_mdleni;
+ *keylen = s->s3.tmp.new_mac_secret_size;
+ } else {
++ uint32_t algenc;
+
+ *keylen = EVP_CIPHER_get_key_length(ciph);
+
++ if (s->s3.tmp.new_cipher != NULL) {
++ algenc = s->s3.tmp.new_cipher->algorithm_enc;
++ } else if (s->session->cipher != NULL) {
++ /* We've not selected a cipher yet - we must be doing early data */
++ algenc = s->session->cipher->algorithm_enc;
++ } else if (s->psksession != NULL && s->psksession->cipher != NULL) {
++ /* We must be doing early data with out-of-band PSK */
++ algenc = s->psksession->cipher->algorithm_enc;
++ } else {
++ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
++ return 0;
++ }
++
+ mode = EVP_CIPHER_get_mode(ciph);
+ if (mode == EVP_CIPH_CCM_MODE) {
+- uint32_t algenc;
+-
+ *ivlen = EVP_CCM_TLS_IV_LEN;
+- if (s->s3.tmp.new_cipher != NULL) {
+- algenc = s->s3.tmp.new_cipher->algorithm_enc;
+- } else if (s->session->cipher != NULL) {
+- /* We've not selected a cipher yet - we must be doing early data */
+- algenc = s->session->cipher->algorithm_enc;
+- } else if (s->psksession != NULL && s->psksession->cipher != NULL) {
+- /* We must be doing early data with out-of-band PSK */
+- algenc = s->psksession->cipher->algorithm_enc;
+- } else {
+- SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
+- return 0;
+- }
+ if (algenc & (SSL_AES128CCM8 | SSL_AES256CCM8))
+ *taglen = EVP_CCM8_TLS_TAG_LEN;
+ else
+@@ -415,6 +415,12 @@ static int derive_secret_key_and_iv(SSL_CONNECTION *s, const EVP_MD *md,
+
+ if (mode == EVP_CIPH_GCM_MODE) {
+ *taglen = EVP_GCM_TLS_TAG_LEN;
++#ifndef OPENSSL_NO_GOST
++ } else if (algenc & SSL_MAGMA_MGM) {
++ *taglen = EVP_MAGMA_TLS_TAG_LEN;
++ } else if (algenc & SSL_KUZNYECHIK_MGM) {
++ *taglen = EVP_KUZNYECHIK_TLS_TAG_LEN;
++#endif
+ } else {
+ /* CHACHA20P-POLY1305 */
+ *taglen = EVP_CHACHAPOLY_TLS_TAG_LEN;
+diff --git a/openssl/util/perl/OpenSSL/paramnames.pm b/openssl/util/perl/OpenSSL/paramnames.pm
+index 163a61d..dafcf6c 100644
+--- a/openssl/util/perl/OpenSSL/paramnames.pm
++++ b/openssl/util/perl/OpenSSL/paramnames.pm
+@@ -158,6 +158,9 @@ my %params = (
+ 'CIPHER_PARAM_TLS1_MULTIBLOCK_ENC_IN' => "tls1multi_encin", # octet_string
+ 'CIPHER_PARAM_TLS1_MULTIBLOCK_ENC_LEN' => "tls1multi_enclen", # size_t
+
++ 'CIPHER_PARAM_TLSTREE' => "tlstree", # octet_string
++ 'CIPHER_PARAM_TLSTREE_MODE' => "tlstree_mode", # octet_string
++
+ # digest parameters
+ 'DIGEST_PARAM_XOFLEN' => "xoflen", # size_t
+ 'DIGEST_PARAM_SSL3_MS' => "ssl3-ms", # octet string
if {[info exists env(ALG_LIST)]} {
set alg_pair_list $env(ALG_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set alg_pair_list {gost2001:A {gost2001:B} gost2012_256:A {gost2012_256:C} gost2012_512:B {gost2012_256:B gost2012_512:A}}}
"open" {
set alg_pair_list {
gost2012_512:C {gost2012_256:B gost2012_256:TCB gost2012_512:B gost2012_512:C}
}
}
+ "openprov" {
+ set all_algorithms {
+ gost2001:A gost2001:B gost2001:C gost2001:XA gost2001:XB
+ gost2012_256:A gost2012_256:B gost2012_256:C gost2012_256:TCA gost2012_256:TCB gost2012_256:TCC gost2012_256:TCD
+ gost2012_512:A gost2012_512:B gost2012_512:C
+ }
+
+ set run_all 0
+ if {[info exists env(GOST_TEST_RUN_EXTENDED)]} {
+ set run_all 1
+ }
+
+ if {!$run_all} {
+ set alg_sample_count 5
+ set all_algorithms [get_sample $all_algorithms $alg_sample_count]
+ }
+
+ set alg_pair_list {}
+ foreach ca_alg $all_algorithms {
+ lappend alg_pair_list $ca_alg $all_algorithms
+ }
+ }
}
}
if {[info exists env(ALG_LIST)]} {
set alg_list $env(ALG_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set alg_list {gost2001:A gost2001:B gost2001:C gost2012_256:A gost2012_256:B gost2012_256:C gost2012_512:A gost2012_512:B}}
"open" {set alg_list {gost2001:A gost2001:B gost2001:C gost2012_256:A gost2012_256:B gost2012_256:C gost2012_512:A gost2012_512:B}}
}
if {[info exists env(ALG_LIST)]} {
set alg_list $env(ALG_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set alg_list {gost2001:A gost2001:B gost2001:C}}
"open" {set alg_list {gost2001:A gost2001:B gost2001:C}}
}
if {[info exists env(ALG_LIST)]} {
set alg_list $env(ALG_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set alg_list {gost2001:A gost2001:B gost2001:C gost2012_256:A gost2012_256:B gost2012_256:C gost2012_512:A gost2012_512:B}}
"open" {set alg_list {gost2001:A gost2001:B gost2001:C gost2012_256:A gost2012_256:B gost2012_256:C gost2012_512:A gost2012_512:B}}
}
if {[info exist env(ENC_LIST)]} {
set enc_list $env(ENC_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set enc_list {gost2001:XA:1.2.643.2.2.31.3 gost2001:XB:1.2.643.2.2.31.4 gost2001:XA: gost2012_256:XA:1.2.643.2.2.31.1 gost2012_256:XB:1.2.643.7.1.2.5.1.1 gost2012_256:XA: gost2012_512:A:1.2.643.2.2.31.3 gost2012_512:B:1.2.643.7.1.2.5.1.1 gost2012_512:A:}}
"open" {set enc_list {gost2001:XA:1.2.643.2.2.31.3 gost2001:XB:1.2.643.2.2.31.4 gost2001:XA: gost2012_256:XA:1.2.643.2.2.31.1 gost2012_256:XB:1.2.643.7.1.2.5.1.1 gost2012_256:XA: gost2012_512:A:1.2.643.2.2.31.3 gost2012_512:B:1.2.643.7.1.2.5.1.1 gost2012_512:A:}}
}
if {[info exist env(ENC_LIST)]} {
set enc_list $env(ENC_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set enc_list {gost2001:XA:1.2.643.2.2.31.3 gost2001:XB:1.2.643.2.2.31.4 }}
"open" {set enc_list {gost2001:XA:1.2.643.2.2.31.3 gost2001:XB:1.2.643.2.2.31.4 }}
}
if {[info exist env(ENC_LIST)]} {
set enc_list $env(ENC_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set enc_list {gost2001:XA:1.2.643.2.2.31.3 gost2001:XB:1.2.643.2.2.31.4 gost2001:XA: gost2012_256:XA:1.2.643.2.2.31.1 gost2012_256:XB:1.2.643.7.1.2.5.1.1 gost2012_256:XA: gost2012_512:A:1.2.643.2.2.31.3 gost2012_512:B:1.2.643.7.1.2.5.1.1 gost2012_512:A:}}
"open" {set enc_list {gost2001:XA:1.2.643.2.2.31.3 gost2001:XB:1.2.643.2.2.31.4 gost2001:XA: gost2012_256:XA:1.2.643.2.2.31.1 gost2012_256:XB:1.2.643.7.1.2.5.1.1 gost2012_256:XA: gost2012_512:A:1.2.643.2.2.31.3 gost2012_512:B:1.2.643.7.1.2.5.1.1 gost2012_512:A:}}
}
if {[info exist env(ENC_LIST)]} {
set enc_list $env(ENC_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set enc_list {gost2001:XA:1.2.643.2.2.31.3 gost2001:XB:1.2.643.2.2.31.4 }}
"open" {set enc_list {gost2001:XA:1.2.643.2.2.31.3 gost2001:XB:1.2.643.2.2.31.4 }}
}
cd $::test::dir
start_tests "Тесты на команду dgst"
-switch -exact [engine_name] {
+switch -exact [test_target_name] {
"ccore" {set signalg { gost2001:A gost2012_256:A gost2012_512:A}}
"open" {set signalg { gost2001:A gost2012_256:A gost2012_512:A}}
+ "openprov" {
+ set signalg { gost2001:A gost2001:B gost2001:C gost2001:XA gost2001:XB
+ gost2012_256:A gost2012_256:B gost2012_256:C gost2012_256:TCA gost2012_256:TCB gost2012_256:TCC gost2012_256:TCD
+ gost2012_512:A gost2012_512:B gost2012_512:C }
+ }
}
if {[info exists env(ALG_LIST)]} {
} else {
test -skip {![file exists $username/seckey.pem]||![file exists dgst.dat]} -createsfiles "testmd5.bin" "Подпись несовместимого дайджеста $hash_alg c подписью $alg" {
- grep Error [openssl "dgst -[hash_short_name $hash_alg] -sign $username/seckey.pem -out testmd5.bin dgst.dat"]
- } 1 {invalid digest type}
+ [openssl "dgst -[hash_short_name $hash_alg] -sign $username/seckey.pem -out testmd5.bin dgst.dat"]
+ } 1
}
}
cd $::test::dir
start_tests "Тесты на команду engine"
-switch -exact [engine_name] {
+switch -exact [test_target_name] {
"ccore" {set list " \[RAND, gost89, gost89-cnt, gost89-cnt-12, gost89-cbc, id-tc26-cipher-gostr3412-2015-magma-ctracpkm, magma-ctr, magma-ofb, magma-ecb, magma-cbc, magma-cfb, grasshopper-ecb, grasshopper-cbc, grasshopper-ofb, grasshopper-cfb, grasshopper-ctr, id-tc26-cipher-gostr3412-2015-kuznyechik-ctracpkm, md_gost94, gost-mac, md_gost12_256, md_gost12_512, gost-mac-12, gost2001, id-GostR3410-2001DH, gost-mac, gost2012_256, gost2012_512, gost-mac-12\]\n"}
"open" {set list "(gost) Reference implementation of GOST engine\n \[gost89, gost89-cnt, gost89-cnt-12, gost89-cbc, kuznyechik-ecb, kuznyechik-cbc, kuznyechik-cfb, kuznyechik-ofb, kuznyechik-ctr, magma-ecb, kuznyechik-mgm, magma-cbc, magma-ctr, magma-ctr-acpkm, magma-ctr-acpkm-omac, magma-mgm, kuznyechik-ctr-acpkm, kuznyechik-ctr-acpkm-omac, magma-kexp15, kuznyechik-kexp15, md_gost94, gost-mac, md_gost12_256, md_gost12_512, gost-mac-12, magma-mac, kuznyechik-mac, kuznyechik-ctr-acpkm-omac, magma-ctr-acpkm-omac, gost2001, id-GostR3410-2001DH, gost-mac, gost2012_256, gost2012_512, gost-mac-12, magma-mac, kuznyechik-mac, magma-ctr-acpkm-omac, kuznyechik-ctr-acpkm-omac]\n"}
}
set env(OPENSSL_CONF) [file join [pwd] no_engine.cnf]
test "Проверяем поддержку российских алгоритмов" {
- grep "gost" [openssl "engine -c $env(ENGINE_NAME)"]
+ grep "gost" [openssl "engine -c $env(TEST_TARGET_NAME)"]
} 0 $list
-if {[engine_name] == "ccore"} {
+if {[test_target_name] == "ccore"} {
test "Получение списка конфигурационных параметров" {
openssl "engine -v cryptocom"
} 0 "(cryptocom) Cryptocom GOST engine
--- /dev/null
+#!/usr/bin/tclsh
+lappend auto_path .
+package require ossltest
+
+proc getConfigLine {var {section ""}} {
+ global config
+ if {[string length $section]} {
+ if {[regexp -indices "\n\\s*\\\[\\s*$section\\s*\\\]\\s*\n" $config start]} {
+ set start [lindex $start 1]
+ } else {
+ return -code error "Section $section is not found"
+ }
+ } else {
+ set start 0
+ }
+ if {[regexp -indices "\n\\s*\\\[\[^\n\]+\\\]\\s*\n" [string range $config $start end] end]} {
+ set end [expr $start+[lindex $end 0]]
+ } else {
+ set end end
+ }
+ if {![regexp "\n\\s*$var\\s*=\\s*(\\S\[^\n\]+?)\\s*\n" "\n[string range $config $start $end]" => value]} {
+ return -code error "No variable $var in section $section"
+ }
+ return $value
+}
+
+set config [getConfig]
+
+set openssl_def [getConfigLine openssl_conf]
+
+if {[catch {getConfigLine {(?!\s*default)[^#=]+?} [getConfigLine providers $openssl_def]} provider_section] == 0} {
+ puts [getConfigLine identity $provider_section]
+ exit 0
+}
+
+set engine_section [getConfigLine {[^#]+} [getConfigLine engines $openssl_def ]]
+
+puts [getConfigLine engine_id $engine_section]
+++ /dev/null
-#!/usr/bin/tclsh
-lappend auto_path .
-package require ossltest
-
-proc getConfigLine {var {section ""}} {
- global config
- if {[string length $section]} {
- if {[regexp -indices "\n\\s*\\\[\\s*$section\\s*\\\]\\s*\n" $config start]} {
- set start [lindex $start 1]
- } else {
- return -code error "Section $section is not found"
- }
- } else {
- set start 0
- }
- if {[regexp -indices "\n\\s*\\\[\[^\n\]+\\\]\\s*\n" [string range $config $start end] end]} {
- set end [expr $start+[lindex $end 0]]
- } else {
- set end end
- }
- if {![regexp "\n\\s*$var\\s*=\\s*(\\S\[^\n\]+?)\\s*\n" "\n[string range $config $start $end]" => value]} {
- return -code error "No variable $var in section $section"
- }
- return $value
-}
-
-set config [getConfig]
-
-set openssl_def [getConfigLine openssl_conf]
-
-set engine_section [getConfigLine {[^#]+} [getConfigLine engines $openssl_def ]]
-
-puts [getConfigLine engine_id $engine_section]
-
-
-
-
cd $::test::dir
start_tests "Тесты на команду dgst с MAC"
+proc mac_testcase { alg file mac_hex macopts } {
+ set opts [split $macopts " "]
+
+ if {[string equal [test_target_name] "openprov"]} {
+ set cmd [list mac -in $file]
+ lappend cmd {*}$opts $alg
+ set expected [string toupper $mac_hex]
+ } else {
+ set cmd [list dgst -mac $alg]
+ lappend cmd {*}$opts $file
+ set expected "[string toupper $alg]-$alg\($file\)= $mac_hex"
+ }
+
+ set result [openssl $cmd]
+ return [string equal [string trim $result] [string trim $expected]]
+}
+
test -createsfiles {dgst.dat dgst0.dat dgst2.dat dgst8.dat dgst63.dat mac-grasshopper.dat mac-magma.dat} "Формирование тестовых данных" {
makeFile dgst.dat [string repeat "Test data to digest.\n" 100] binary
makeFile dgst0.dat "" binary
test "Попытка вычислить MAC с ключом неправильной длины" {
grep gost-mac [openssl "dgst -mac gost-mac -macopt key:123456789012345678901234567890 dgst.dat"]
-} 1 "invalid mac key length"
+} 1 ""
test "Попытка вычислить MAC с hex ключом неправильной длины" {
grep gost-mac [openssl "dgst -mac gost-mac -macopt hexkey:414243444546474849404142434445464748494041424344454647484940 dgst.dat"]
-} 1 "invalid mac key length"
+} 1 ""
test "Вычисление MAC gost89" {
- grep gost-mac [openssl "dgst -mac gost-mac -macopt key:12345678901234567890123456789012 dgst.dat"]
-} 0 "GOST-MAC-gost-mac(dgst.dat)= 37f646d2\n"
+ mac_testcase "gost-mac" "dgst.dat" "37f646d2" "-macopt key:12345678901234567890123456789012"
+} 0 1
-test "Вычисление двух MAC gost89" {
+test -skip {[string equal [test_target_name] "openprov"]} "Вычисление двух MAC gost89" {
grep gost-mac [openssl "dgst -mac gost-mac -macopt key:12345678901234567890123456789012 dgst.dat dgst.dat"]
} 0 "GOST-MAC-gost-mac(dgst.dat)= 37f646d2\nGOST-MAC-gost-mac(dgst.dat)= 37f646d2\n"
-test "Ð\92Ñ\8bÑ\87иÑ\81лиение MAC gost89 Ñ\81 Ñ\88еÑ\81Ñ\82нацатиричным ключом" {
- grep gost-mac [openssl "dgst -mac gost-mac -macopt hexkey:3132333435363738393031323334353637383930313233343536373839303132 dgst.dat"]
-} 0 "GOST-MAC-gost-mac(dgst.dat)= 37f646d2\n"
+test "Ð\92Ñ\8bÑ\87иÑ\81ление MAC gost89 Ñ\81 Ñ\88еÑ\81Ñ\82надцатиричным ключом" {
+ mac_testcase "gost-mac" "dgst.dat" "37f646d2" "-macopt hexkey:3132333435363738393031323334353637383930313233343536373839303132"
+} 0 1
test "Вычисление MAC gost89 от файла нулевой длины" {
- grep gost-mac [openssl "dgst -mac gost-mac -macopt key:12345678901234567890123456789012 dgst0.dat"]
-} 0 "GOST-MAC-gost-mac(dgst0.dat)= 00000000\n"
+ mac_testcase "gost-mac" "dgst0.dat" "00000000" "-macopt key:12345678901234567890123456789012"
+} 0 1
test "Вычисление MAC gost89 от файла длины 2" {
- grep gost-mac [openssl "dgst -mac gost-mac -macopt key:12345678901234567890123456789012 dgst2.dat"]
-} 0 "GOST-MAC-gost-mac(dgst2.dat)= 87ea321f\n"
+ mac_testcase "gost-mac" "dgst2.dat" "87ea321f" "-macopt key:12345678901234567890123456789012"
+} 0 1
test "Вычисление MAC gost89 от файла длины 8" {
- grep gost-mac [openssl "dgst -mac gost-mac -macopt key:12345678901234567890123456789012 dgst8.dat"]
-} 0 "GOST-MAC-gost-mac(dgst8.dat)= ad9aeae0\n"
+ mac_testcase "gost-mac" "dgst8.dat" "ad9aeae0" "-macopt key:12345678901234567890123456789012"
+} 0 1
test "Вычисление MAC gost8912" {
- grep gost-mac [openssl "dgst -mac gost-mac-12 -macopt key:12345678901234567890123456789012 dgst8.dat"]
-} 0 "GOST-MAC-12-gost-mac-12(dgst8.dat)= be70ba5e\n"
+ mac_testcase "gost-mac-12" "dgst8.dat" "be70ba5e" "-macopt key:12345678901234567890123456789012"
+} 0 1
-test "Вычисление MAC gost89 со сменой параметров на параметры от gost8912 (symbolic)" {
+test -skip {[string equal [test_target_name] "openprov"]} "Вычисление MAC gost89 со сменой параметров на параметры от gost8912 (symbolic)" {
grep gost-mac [openssl "dgst -mac gost-mac -macopt key:12345678901234567890123456789012 -macopt paramset:id-tc26-gost-28147-param-Z dgst8.dat"]
} 0 "GOST-MAC-gost-mac(dgst8.dat)= be70ba5e\n"
-test "Вычисление MAC gost8912 со сменой параметров на параметры от gost89 (OID)" {
+test -skip {[string equal [test_target_name] "openprov"]} "Вычисление MAC gost8912 со сменой параметров на параметры от gost89 (OID)" {
grep gost-mac [openssl "dgst -mac gost-mac-12 -macopt key:12345678901234567890123456789012 -macopt paramset:1.2.643.2.2.31.1 dgst8.dat"]
} 0 "GOST-MAC-12-gost-mac-12(dgst8.dat)= ad9aeae0\n"
-test "Вычисление MAC gost89 со сменой параметров на параметры 1.2.643.2.2.31.2" {
+test -skip {[string equal [test_target_name] "openprov"]} "Вычисление MAC gost89 со сменой параметров на параметры 1.2.643.2.2.31.2" {
grep gost-mac [openssl "dgst -mac gost-mac -macopt key:12345678901234567890123456789012 -macopt paramset:1.2.643.2.2.31.2 dgst8.dat"]
} 0 "GOST-MAC-gost-mac(dgst8.dat)= c7fdc644\n"
-test "Вычисление MAC gost8912 со сменой параметров на параметры id-Gost28147-89-CryptoPro-B-ParamSet" {
+test -skip {[string equal [test_target_name] "openprov"]} "Вычисление MAC gost8912 со сменой параметров на параметры id-Gost28147-89-CryptoPro-B-ParamSet" {
grep gost-mac [openssl "dgst -mac gost-mac-12 -macopt key:12345678901234567890123456789012 -macopt paramset:id-Gost28147-89-CryptoPro-B-ParamSet dgst8.dat"]
} 0 "GOST-MAC-12-gost-mac-12(dgst8.dat)= c7fdc644\n"
test "Вычисление MAC gost89 с изменение длины имитовставки (8)" {
- grep gost-mac [openssl "dgst -mac gost-mac -macopt key:12345678901234567890123456789012 -sigopt size:8 dgst8.dat"]
-} 0 "GOST-MAC-gost-mac(dgst8.dat)= ad9aeae05a7f6f71\n"
+ mac_testcase "gost-mac" "dgst8.dat" "ad9aeae05a7f6f71" \
+ "-macopt key:12345678901234567890123456789012 -macopt size:8"
+} 0 1
test "Вычисление MAC gost8912 с изменение длины имитовставки (6)" {
- grep gost-mac [openssl "dgst -mac gost-mac-12 -macopt key:12345678901234567890123456789012 -sigopt size:6 dgst8.dat"]
-} 0 "GOST-MAC-12-gost-mac-12(dgst8.dat)= be70ba5ed6b0\n"
+ mac_testcase "gost-mac-12" "dgst8.dat" "be70ba5ed6b0" \
+ "-macopt key:12345678901234567890123456789012 -macopt size:6"
+} 0 1
test "Вычисление MAC gost89 с изменение длины имитовставки (2)" {
- grep gost-mac [openssl "dgst -mac gost-mac -macopt key:12345678901234567890123456789012 -sigopt size:3 dgst8.dat"]
-} 0 "GOST-MAC-gost-mac(dgst8.dat)= ad9aea\n"
-
-test "Вычисление MAC gost89 с изменение длины имитовставки через macopt" {
- grep gost-mac [openssl "dgst -mac gost-mac -macopt key:12345678901234567890123456789012 -macopt size:3 dgst8.dat"]
-} 0 "GOST-MAC-gost-mac(dgst8.dat)= ad9aea\n"
+ mac_testcase "gost-mac" "dgst8.dat" "ad9a" \
+ "-macopt key:12345678901234567890123456789012 -macopt size:2"
+} 0 1
-test "Вычисление MAC gost8912 с изменение длины имитовставки через macopt" {
- grep gost-mac [openssl "dgst -mac gost-mac-12 -macopt key:12345678901234567890123456789012 -macopt size:6 dgst8.dat"]
-} 0 "GOST-MAC-12-gost-mac-12(dgst8.dat)= be70ba5ed6b0\n"
+test -skip {[string equal [test_target_name] "openprov"]} "Вычисление MAC gost89 с изменение длины имитовставки через sigopt" {
+ mac_testcase "gost-mac" "dgst8.dat" "ad9aea" "-macopt key:12345678901234567890123456789012 -sigopt size:3"
+} 0 1
-test "Вычисление MAC gost8912 с изменение длины имитовставки:sigopt переписывает macopt " {
- grep gost-mac [openssl "dgst -mac gost-mac-12 -macopt key:12345678901234567890123456789012 -macopt size:2 -sigopt size:6 dgst8.dat"]
-} 0 "GOST-MAC-12-gost-mac-12(dgst8.dat)= be70ba5ed6b0\n"
+test -skip {[string equal [test_target_name] "openprov"]} "Вычисление MAC gost8912 с изменение длины имитовставки через sigopt" {
+ mac_testcase "gost-mac-12" "dgst8.dat" "be70ba5ed6b0" "-macopt key:12345678901234567890123456789012 -sigopt size:6"
+} 0 1
-test "Вычисление MAC gost8912 с изменение длины имитовставки:sigopt переписывает macopt " {
+test -skip {[string equal [test_target_name] "openprov"]} "Вычисление MAC gost8912 с изменение длины имитовставки:sigopt переписывает macopt " {
grep gost-mac [openssl "dgst -mac gost-mac-12 -macopt key:12345678901234567890123456789012 -macopt size:2 -sigopt size:6 dgst8.dat"]
} 0 "GOST-MAC-12-gost-mac-12(dgst8.dat)= be70ba5ed6b0\n"
test "Вычисление MAC magma-mac (пример из ГОСТ 2015 34.13)" {
- grep magma-mac [openssl "dgst -mac magma-mac -macopt hexkey:ffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff mac-magma.dat"]
-} 0 "MAGMA-MAC-magma-mac(mac-magma.dat)= 154e72102030c5bb\n"
+ mac_testcase "magma-mac" "mac-magma.dat" "154e72102030c5bb" "-macopt hexkey:ffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
+} 0 1
#FIXME my regression
test "Вычисление MAC grasshopper-mac (пример из ГОСТ 2015 34.13)" {
- grep kuznyechik-mac [openssl "dgst -mac kuznyechik-mac -macopt hexkey:8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef mac-grasshopper.dat"]
-} 0 "KUZNYECHIK-MAC-kuznyechik-mac(mac-grasshopper.dat)= 336f4d296059fbe34ddeb35b37749c67\n"
+ mac_testcase "kuznyechik-mac" "mac-grasshopper.dat" "336f4d296059fbe34ddeb35b37749c67" "-macopt hexkey:8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef"
+} 0 1
end_tests
if {[info exists env(ALG_LIST)]} {
set alg_list $env(ALG_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set alg_list {gost2001:A gost2012_256:A gost2012_512:B}}
"open" {set alg_list {gost2001:A gost2012_256:A gost2012_512:B}}
}
--- /dev/null
+openssl_conf = openssl_def
+
+[openssl_def]
+engines = engine_section
+
+[engine_section]
+gost = gost_section
+
+[gost_section]
+engine_id = gost
+default_algorithms = ALL
--- /dev/null
+openssl_conf = openssl_def
+
+[openssl_def]
+providers = provider_sect
+
+[provider_sect]
+default = default_sect
+gostprov = gost_sect
+
+[default_sect]
+activate = 1
+[gost_sect]
+activate = 1
+identity = gostprov
\ No newline at end of file
+++ /dev/null
-openssl_conf = openssl_def
-
-[openssl_def]
-engines = engine_section
-
-[engine_section]
-gost = gost_section
-
-[gost_section]
-engine_id = gost
-default_algorithms = ALL
}
return $found
}
-
+
+# Получение случайно подвыборки из доступного списка
+proc get_sample {list count} {
+ set result {}
+ set n [llength $list]
+ if {$count >= $n} {
+ return $list
+ }
+ unset -nocomplain seen;
+ while {[llength $result] < $count} {
+ set idx [expr {int(rand() * $n)}]
+ if {![info exists seen($idx)]} {
+ lappend result [lindex $list $idx]
+ set seen($idx) 1
+ }
+ }
+ return $result
+}
# Вызывает команду openssl.
# Посылает в лог вывод на stdout и на stderr, возвращает его же.
set exesuffix ""
}
log "Keyname is $keyname"
-# if {[engine_name] eq "open"} {
+# if {[test_target_name] eq "open"} {
log "Calling openssl cmd to create private key"
openssl "genpkey $optname -out $filename"
# } elseif {[info exists ::env(OBJ)] && [file executable ../$::env(OBJ)/keytest$exesuffix]&& $alg eq "gost2001"} {
global output finished
#puts -nonewline stderr "Waiting for server startup..."
- while {![regexp "\nACCEPT\n" $output($server)]} {
+ while {![regexp "ACCEPT" $output($server)]} {
vwait output($server)
if {[info exists finished($server)]} {
#puts stderr "error"
}
}
-proc engine_name {} {
+proc test_target_name {} {
global env
- if {[info exists env(ENGINE_NAME)]} {
- switch -exact $env(ENGINE_NAME) {
+ if {[info exists env(TEST_TARGET_NAME)]} {
+ switch -exact $env(TEST_TARGET_NAME) {
"open" {return "open"}
"gost" {return "open"}
+ "gostprov" {return "openprov"}
"cryptocom" {return "ccore"}
"ccore" {return "ccore"}
- default {error "Unknown engine '$env(ENGINE_NAME)'"}
+ default {error "Unknown engine '$env(TEST_TARGET_NAME)'"}
}
} else {
return "ccore"
if {[info exists env(ALG_LIST)]} {
set alg_list $env(ALG_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set alg_list {gost2001:A gost2001:B gost2001:C gost2001:XA gost2001:XB gost2012_256:A gost2012_256:B gost2012_256:C gost2012_256:XA gost2012_256:XB gost2012_512:A gost2012_512:B}}
"open" {
set alg_list {
lappend auto_path [file dirname [info script]]
package require ossltest
cd $::test::dir
+
+set is_provider 0
+switch -exact [test_target_name] {
+ "openprov" { set is_provider 1 }
+}
+
start_tests "тесты на команду pkcs8"
set key "-----BEGIN PRIVATE KEY-----
MEUCAQAwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEEIgIgSZ82qYpu6RQj
save_env2 {CRYPT_PARAMS GOST_PBE_HMAC}
-test "Зашифровываем незашифрованный ключ gost2001, параметры CryptoPro-A" {
+test -skip {$is_provider} "Зашифровываем незашифрованный ключ gost2001, параметры CryptoPro-A" {
makeFile pkcs8-1A.key $key
set env(CRYPT_PARAMS) "id-Gost28147-89-CryptoPro-A-ParamSet"
set env(GOST_PBE_HMAC) "md_gost94"
} 0 1
restore_env2 {CRYPT_PARAMS GOST_PBE_HMAC}
-test -skip {![file exists encA.key]} "Проверяем OID-ы PBE" {
+test -skip {$is_provider || ![file exists encA.key]} "Проверяем OID-ы PBE" {
set res [extract_oids encA.key]
regexp "HMAC GOST 34\.11-94" $res && regexp "GOST .*89"
} 0 1
-test "Расшифровываем зашифрованный ключ gost2001" {
+test -skip {$is_provider} "Расшифровываем зашифрованный ключ gost2001" {
set unencrypted [openssl [list pkcs8 -passin pass:qwertyu -topk8 -nocrypt -in encA.key]]
openssl [list pkey -text -noout << $unencrypted]
} 0 $etalon
save_env2 {CRYPT_PARAMS GOST_PBE_HMAC}
-test "Зашифровываем незашифрованный ключ gost2001, параметры CryptoPro-B" {
+test -skip {$is_provider} "Зашифровываем незашифрованный ключ gost2001, параметры CryptoPro-B" {
makeFile pkcs8-1B.key $key
set env(CRYPT_PARAMS) "id-Gost28147-89-CryptoPro-B-ParamSet"
set env(GOST_PBE_HMAC) "md_gost94"
} 0 1
restore_env2 {CRYPT_PARAMS GOST_PBE_HMAC}
-test -skip {![file exists encB.key]} "Проверяем OID-ы PBE" {
+test -skip {$is_provider || ![file exists encB.key]} "Проверяем OID-ы PBE" {
set res [extract_oids encB.key]
regexp "HMAC GOST 34\.11-94" $res && regexp "GOST .*89"
} 0 1
-test "Расшифровываем зашифрованный ключ gost2001" {
+test -skip {$is_provider} "Расшифровываем зашифрованный ключ gost2001" {
set unencrypted [openssl [list pkcs8 -passin pass:qwertyu -topk8 -nocrypt -in encB.key]]
openssl [list pkey -text -noout << $unencrypted]
} 0 $etalon
-test "Расшифровываем ключ, созданный mkkey" {
+test -skip {$is_provider} "Расшифровываем ключ, созданный mkkey" {
makeFile pkcs8-2.key "-----BEGIN ENCRYPTED PRIVATE KEY-----
MIGvMFUGCSqGSIb3DQEFDTBIMCcGCSqGSIb3DQEFDDAaBAjIvbrnGmGbTAIC
CAAwCgYGKoUDAgIKBQAwHQYGKoUDAgIVMBMECOtWtCMQo3dzBgcqhQMCAh8B
openssl [list pkey -text -noout << $unencrypted]
} 0 $etalon
-test "Расшифровываем ключ, созданный mkkey, русский пароль" {
+test -skip {$is_provider} "Расшифровываем ключ, созданный mkkey, русский пароль" {
set env(PASS) [encoding convertfrom [encoding convertto utf-8 [rus "йцукенг"]]]
makeFile pkcs8-3.key "-----BEGIN ENCRYPTED PRIVATE KEY-----
MIGvMFUGCSqGSIb3DQEFDTBIMCcGCSqGSIb3DQEFDDAaBAgSfbLQ+fNe0AIC
} 0 $etalon
save_env2 {CRYPT_PARAMS GOST_PBE_HMAC}
-test "Зашифровываем незашифрованный ключ gost2012_256, параметры TK26 (умолчательные)" {
+test -skip {$is_provider} "Зашифровываем незашифрованный ключ gost2012_256, параметры TK26 (умолчательные)" {
makeFile pkcs8-256.key $key256
catch {unset env(CRYPT_PARAMS)}
catch {unset env(GOST_PBE_HMAC)}
} 0 1
restore_env2 {CRYPT_PARAMS GOST_PBE_HMAC}
-test -skip {![file exists enc256.key]} "Проверяем OID-ы PBE" {
+test -skip {$is_provider || ![file exists enc256.key]} "Проверяем OID-ы PBE" {
set res [extract_oids enc256.key]
regexp "HMAC GOST 34\.11-2012" $res && regexp "GOST .*89"
} 0 1
-test "Расшифровываем зашифрованный ключ gost2012_256" {
+test -skip {$is_provider} "Расшифровываем зашифрованный ключ gost2012_256" {
set unencrypted [openssl [list pkcs8 -passin pass:qwertyu -topk8 -nocrypt -in enc256.key]]
openssl [list pkey -text -noout << $unencrypted]
openssl [list pkey -inform DER -text -noout -in pkcs8-512.der]
} 0 $etalon
-test "Зашифровываем незашифрованный ключ gost2012_512, параметры TK26 (умолчательные)" {
+test -skip {$is_provider} "Зашифровываем незашифрованный ключ gost2012_512, параметры TK26 (умолчательные)" {
makeFile pkcs8-512.key $key512
catch {unset env(CRYPT_PARAMS)}
set env(GOST_PBE_HMAC) "md_gost12_512"
} 0 1
restore_env2 {CRYPT_PARAMS GOST_PBE_HMAC}
-test -skip {![file exists enc512.key]} "Проверяем OID-ы PBE" {
+test -skip {$is_provider || ![file exists enc512.key]} "Проверяем OID-ы PBE" {
set res [extract_oids enc512.key]
regexp "HMAC GOST 34\.11-2012" $res && regexp "GOST .*89"
} 0 1
-test "Расшифровываем зашифрованный ключ gost2012 512 bit" {
+test -skip {$is_provider} "Расшифровываем зашифрованный ключ gost2012 512 bit" {
set unencrypted [openssl [list pkcs8 -passin pass:qwertyu -topk8 -nocrypt -in enc512.key]]
openssl [list pkey -text -noout << $unencrypted]
--- /dev/null
+#!/usr/bin/tclsh
+
+lappend auto_path [file dirname [info script]]
+package require ossltest
+
+cd $::test::dir
+start_tests "Проверка алгоритмов GOST в провайдере"
+
+test "Проверка наличия алгоритмов GOST в провайдере" {
+ set output [openssl "list --cipher-algorithms"]
+
+ if {![regexp -all {@ gostprov} $output]} {
+ error "Алгоритмы GOST не найдены в выводе --cipher-algorithms"
+ }
+
+ set expected_algs {
+ "{ 1.2.643.2.2.21, GOST 28147-89, gost89 } @ gostprov"
+ "{ 1.2.643.7.1.1.5.2.2, kuznyechik-ctr-acpkm-omac } @ gostprov"
+ "{ 1.2.643.7.1.1.5.2.1, kuznyechik-ctr-acpkm } @ gostprov"
+ "{ 1.2.643.7.1.1.5.1.1, magma-ctr-acpkm } @ gostprov"
+ "{ 1.2.643.7.1.1.5.1.2, magma-ctr-acpkm-omac } @ gostprov"
+ "gost89-cnt @ gostprov"
+ "gost89-cnt-12 @ gostprov"
+ "gost89-cbc @ gostprov"
+ "kuznyechik-ecb @ gostprov"
+ "kuznyechik-cbc @ gostprov"
+ "kuznyechik-cfb @ gostprov"
+ "kuznyechik-ofb @ gostprov"
+ "kuznyechik-ctr @ gostprov"
+ "magma-cbc @ gostprov"
+ "magma-ctr @ gostprov"
+ "magma-mgm @ gostprov"
+ "kuznyechik-mgm @ gostprov"
+ }
+
+ set output_lines {}
+ foreach line [split $output \n] {
+ lappend output_lines [string trim $line]
+ }
+
+ foreach alg $expected_algs {
+ if {$alg ni $output_lines} {
+ error "Алгоритм '$alg' отсутствует в выводе --cipher-algorithms"
+ }
+ }
+} 0
+
+end_tests
\ No newline at end of file
if {[info exists env(ALG_LIST)]} {
set alg_list $env(ALG_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set alg_list {gost2001:A gost2001:B gost2001:C gost2001:XA gost2001:XB gost2012_256:A gost2012_256:B gost2012_256:C gost2012_256:XA gost2012_256:XB gost2012_512:A gost2012_512:B}}
"open" {set alg_list {gost2001:A gost2001:B gost2001:C gost2001:XA gost2001:XB gost2012_256:0 gost2012_256:A gost2012_256:B gost2012_256:C gost2012_256:XA gost2012_256:XB gost2012_512:A gost2012_512:B}}
+ "openprov" {set alg_list {gost2001:A gost2001:B gost2001:C gost2001:XA gost2001:XB gost2012_256:A gost2012_256:B gost2012_256:C gost2012_256:XA gost2012_256:XB gost2012_256:0 gost2012_512:A gost2012_512:B}}
}
}
package require asn 0.4.1
cd $::test::dir
-switch -exact [engine_name] {
+switch -exact [test_target_name] {
"ccore" {
set no_param_set "no public key parameters set"
set invalid_paramset "invalid pubic key paramset name"
set no_param_set "no parameters set"
set invalid_paramset "parameter error"
}
+ "openprov" {
+ set no_param_set "Error generating"
+ set invalid_paramset "parameter error"
+ }
}
start_tests "Создание ключей и заявок, команда req -newkey"
gost2001:B "ГОСТ 2001 Криптопро B" 0 1.2.643.2.2.35.2
gost2001:C "ГОСТ 2001 Криптопро C" 0 1.2.643.2.2.35.3
gost2001:D "ГОСТ 2001 Криптопро неверный параметр" 1 invalid_paramset
-gost2001:test "ГОСТ 2001 Криптопро тестовый" 0 1.2.643.2.2.35.0
+gost2001:id-GostR3410-2001-TestParamSet "ГОСТ 2001 Криптопро тестовый" 0 1.2.643.2.2.35.0
gost2001:XA "ГОСТ 2001 Криптопро XA" 0 1.2.643.2.2.36.0
gost2001:XB "ГОСТ 2001 Криптопро XB" 0 1.2.643.2.2.36.1
gost2001:id-GostR3410-2001-CryptoPro-XchB-ParamSet "ГОСТ 2001 Криптопро XB по имени" 0 1.2.643.2.2.36.1
set algparamcmdline ""
}
- test -skip {{[engine_name] eq "open" && $alg eq "gost2001:test"}} $descr {
+ test $descr {
openssl "req -newkey $algname $algparamcmdline -keyout test.key -out test.req -batch -nodes -config $::test::ca/req.conf"
set pkcs8 [readpem test.key]
asn::asnGetSequence pkcs8 seq1
IF "%OPENSSL_APP%"=="" set OPENSSL_APP=c:\cryptopack3\bin\openssl.exe\r
IF "%TCLSH%"=="" set TCLSH=c:\Tcl\bin\tclsh.exe\r
\r
-%TCLSH% getengine.tcl > engine_name.txt\r
-set /p ENGINE_NAME= < engine_name.txt\r
-del engine_name.txt\r
+%TCLSH% get_test_target_name.tcl > test_target_name.txt\r
+set /p TEST_TARGET_NAME= < test_target_name.txt\r
+del test_target_name.txt\r
\r
hostname > host_name.txt\r
set /p HOST_NAME= < host_name.txt\r
del host_name.txt\r
-set TESTDIR=%HOST_NAME%-bat-%ENGINE_NAME%\r
+set TESTDIR=%HOST_NAME%-bat-%TEST_TARGET_NAME%\r
rmdir /s /q %TESTDIR%\r
mkdir %TESTDIR%\r
copy oidfile %TESTDIR%\r
set OTHER_VERSION=../OtherVersion\r
\r
-IF %ENGINE_NAME%==cryptocom (\r
+IF %TEST_TARGET_NAME%==cryptocom (\r
set BASE_TESTS=engine dgst pkcs8 enc req-genpkey req-newkey ca smime smime2 smimeenc cms cms2 cmsenc pkcs12 nopath ocsp ts ssl smime_io cms_io smimeenc_io cmsenc_io\r
set OTHER_DIR=../%HOST_NAME%-bat-gost\r
) ELSE (\r
- IF %ENGINE_NAME%==gost (\r
+ IF %TEST_TARGET_NAME%==gost (\r
set BASE_TESTS=engine dgst pkcs8 enc req-genpkey req-newkey ca smime smime2 smimeenc cms cms2 cmsenc pkcs12 nopath ocsp ts ssl smime_io cms_io smimeenc_io cmsenc_io\r
set OTHER_DIR=../%HOST_NAME%-bat-cryptocom\r
) ELSE (\r
IF EXIST %TESTDIR%\%OTHER_DIR% %TCLSH% interop.try\r
IF EXIST %TESTDIR%\%OTHER_VERSION% (\r
set OTHER_DIR=%OTHER_VERSION%\r
- IF %ENGINE_NAME%==cryptocom (\r
+ IF %TEST_TARGET_NAME%==cryptocom (\r
set ALG_LIST="gost2001:A gost2001:B gost2001:C" \r
set ENC_LIST="gost2001:A:1.2.643.2.2.31.3 gost2001:B:1.2.643.2.2.31.4 gost2001:C:1.2.643.2.2.31.2 gost2001:A:"\r
) ELSE (\r
TCLSH="$TCLSH -encoding utf-8"
echo "PWD: $PWD"
-: ${OPENSSL_CONF:=$PWD/openssl-gost.cnf}
+: ${OPENSSL_CONF:=$PWD/openssl-gost-engine.cnf}
echo "OPENSSL_CONF: $OPENSSL_CONF"
export OPENSSL_CONF
+
echo "ENGINE_DIR: $ENGINE_DIR"
: ${OPENSSL_ENGINES:=$ENGINE_DIR}
echo "OPENSSL_ENGINES: $OPENSSL_ENGINES"
export OPENSSL_ENGINES
+
+echo "PROVIDER_DIR: $OPENSSL_MODULES_DIR"
+: ${OPENSSL_MODULES:=$OPENSSL_MODULES_DIR}
+echo "OPENSSL_MODULES: $OPENSSL_MODULES"
+export OPENSSL_MODULES
+
APP_SUFFIX=`basename $OPENSSL_APP .exe|sed s/openssl//`
[ -n "$OPENSSL_APP" ]&& export OPENSSL_APP
-ENGINE_NAME=`$TCLSH getengine.tcl`
-export ENGINE_NAME
+TEST_TARGET_NAME=`$TCLSH get_test_target_name.tcl`
+export TEST_TARGET_NAME
[ -z "$TESTDIR" ] && TESTDIR=`pwd`
-TESTDIR=${TESTDIR}/`hostname`-$ENGINE_NAME
+TESTDIR=${TESTDIR}/`hostname`-$TEST_TARGET_NAME
[ -n "$APP_SUFFIX" ] && TESTDIR=${TESTDIR}-${APP_SUFFIX}
[ -d ${TESTDIR} ] && rm -rf ${TESTDIR}
mkdir -p ${TESTDIR}
cp oidfile ${TESTDIR}
export TESTDIR
-case "$ENGINE_NAME" in
+case "$TEST_TARGET_NAME" in
gostkc3)
BASE_TEST="1"
;;
BASE_TESTS="engine dgst mac pkcs8 enc req-genpkey req-newkey ca smime smime2 smimeenc cms cms2 cmstc262019 cmsenc pkcs12 nopath ocsp ts ssl smime_io cms_io smimeenc_io cmsenc_io"
OTHER_DIR=`echo $TESTDIR |sed 's/gost/cryptocom/'`
;;
+ gostprov)
+ BASE_TESTS="provider enc ca dgst tls13 pkcs8 req-newkey req-genpkey mac"
+ ;;
*)
- echo "No GOST=providing engine found" 1>&2
+ echo "No GOST-providing engine/provider found" 1>&2
exit 1;
esac
if [ -x copy_param ]; then
$TCLSH wcli.try $t || fail=9
done
fi
-if [ -d $OTHER_DIR ]; then
+if [ -n "$OTHER_DIR" -a -d "$OTHER_DIR" ]; then
OTHER_DIR=../${OTHER_DIR} $TCLSH interop.try
fi
if [ -d OtherVersion ] ; then
- case "$ENGINE_NAME" in
+ case "$TEST_TARGET_NAME" in
gostkc3)
;;
cryptocom)
OTHER_DIR=../OtherVersion ALG_LIST="gost2001:A gost2001:B gost2001:C" ENC_LIST="gost2001:A:1.2.643.2.2.31.3 gost2001:B:1.2.643.2.2.31.4 gost2001:C:1.2.643.2.2.31.2 gost2001:A:" $TCLSH interop.try
;;
*)
- echo "No GOST=providing engine found" 1>&2
+ echo "No GOST-providing module found" 1>&2
exit 1;
esac
fi
IF "%OPENSSL_APP%"=="" set OPENSSL_APP=c:\cryptopack3\bin\openssl.exe\r
IF "%TCLSH%"=="" set TCLSH=c:\Tcl\bin\tclsh.exe\r
\r
-%TCLSH% getengine.tcl > engine_name.txt\r
-set /p ENGINE_NAME= < engine_name.txt\r
-del engine_name.txt\r
+%TCLSH% get_test_target_name.tcl > test_target_name.txt\r
+set /p TEST_TARGET_NAME= < test_target_name.txt\r
+del test_target_name.txt\r
\r
hostname > host_name.txt\r
set /p HOST_NAME= < host_name.txt\r
del host_name.txt\r
-set TESTDIR=%HOST_NAME%-bat-%ENGINE_NAME%\r
+set TESTDIR=%HOST_NAME%-bat-%TEST_TARGET_NAME%\r
rmdir /s /q %TESTDIR%\r
mkdir %TESTDIR%\r
copy oidfile %TESTDIR%\r
set OTHER_VERSION=../OtherVersion\r
\r
-IF %ENGINE_NAME%==cryptocom (\r
+IF %TEST_TARGET_NAME%==cryptocom (\r
set BASE_TESTS=engine ssl dgst pkcs8 enc req-genpkey req-newkey ca smime smime2 smimeenc cms cms2 cmsenc pkcs12 nopath ocsp ts smime_io cms_io smimeenc_io cmsenc_io\r
set OTHER_DIR=../%HOST_NAME%-bat-gost\r
) ELSE (\r
- IF %ENGINE_NAME%==gost (\r
+ IF %TEST_TARGET_NAME%==gost (\r
set BASE_TESTS=engine dgst pkcs8 enc req-genpkey req-newkey ca smime smime2 smimeenc cms cms2 cmsenc pkcs12 nopath ocsp ts ssl smime_io cms_io smimeenc_io cmsenc_io\r
set OTHER_DIR=../%HOST_NAME%-bat-cryptocom\r
) ELSE (\r
IF EXIST %TESTDIR%\%OTHER_DIR% %TCLSH% interop.try\r
IF EXIST %TESTDIR%\%OTHER_VERSION% (\r
set OTHER_DIR=%OTHER_VERSION%\r
- IF %ENGINE_NAME%==cryptocom (\r
+ IF %TEST_TARGET_NAME%==cryptocom (\r
set ALG_LIST="gost2001:A gost2001:B gost2001:C" \r
set ENC_LIST="gost2001:A:1.2.643.2.2.31.3 gost2001:B:1.2.643.2.2.31.4 gost2001:C:1.2.643.2.2.31.2 gost2001:A:"\r
) ELSE (\r
IF "%OPENSSL_APP%"=="" set OPENSSL_APP=c:\cryptopack3\bin\openssl.exe\r
IF "%TCLSH%"=="" set TCLSH=c:\Tcl\bin\tclsh.exe\r
\r
-%TCLSH% getengine.tcl > engine_name.txt\r
-set /p ENGINE_NAME= < engine_name.txt\r
-del engine_name.txt\r
+%TCLSH% get_test_target_name.tcl > test_target_name.txt\r
+set /p TEST_TARGET_NAME= < test_target_name.txt\r
+del test_target_name.txt\r
\r
hostname > host_name.txt\r
set /p HOST_NAME= < host_name.txt\r
del host_name.txt\r
-set TESTDIR=%HOST_NAME%-bat-%ENGINE_NAME%\r
+set TESTDIR=%HOST_NAME%-bat-%TEST_TARGET_NAME%\r
rem emdir /s /q %TESTDIR%\r
rem mkdir %TESTDIR%\r
rem copy oidfile %TESTDIR%\r
set OTHER_VERSION=../OtherVersion\r
\r
-IF %ENGINE_NAME%==cryptocom (\r
+IF %TEST_TARGET_NAME%==cryptocom (\r
set BASE_TESTS=engine ssl dgst pkcs8 enc req-genpkey req-newkey ca smime smime2 smimeenc cms cms2 cmsenc pkcs12 nopath ocsp ts smime_io cms_io smimeenc_io cmsenc_io\r
set OTHER_DIR=../%HOST_NAME%-bat-gost\r
) ELSE (\r
- IF %ENGINE_NAME%==gost (\r
+ IF %TEST_TARGET_NAME%==gost (\r
set BASE_TESTS=engine dgst pkcs8 enc req-genpkey req-newkey ca smime smime2 smimeenc cms cms2 cmsenc pkcs12 nopath ocsp ts ssl smime_io cms_io smimeenc_io cmsenc_io\r
set OTHER_DIR=../%HOST_NAME%-bat-cryptocom\r
) ELSE (\r
IF EXIST %TESTDIR%\%OTHER_DIR% %TCLSH% interop.try\r
IF EXIST %TESTDIR%\%OTHER_VERSION% (\r
set OTHER_DIR=%OTHER_VERSION%\r
- IF %ENGINE_NAME%==cryptocom (\r
+ IF %TEST_TARGET_NAME%==cryptocom (\r
set ALG_LIST="gost2001:A gost2001:B gost2001:C" \r
set ENC_LIST="gost2001:A:1.2.643.2.2.31.3 gost2001:B:1.2.643.2.2.31.4 gost2001:C:1.2.643.2.2.31.2 gost2001:A:"\r
) ELSE (\r
cd $::test::dir
start_tests "TLS-соединение с сервером [lindex $argv 0]"
-if {[engine_name] eq "ccore"} {
+if {[test_target_name] eq "ccore"} {
array unset hosts gost94*
}
if {[info exists env(ALG_LIST)]} {
set alg_list $env(ALG_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set alg_list {gost2001:A gost2001:B gost2001:C gost2012_256:A gost2012_256:B gost2012_256:C gost2012_512:A gost2012_512:B}}
"open" {set alg_list {gost2001:A gost2001:B gost2001:C gost2012_256:A gost2012_256:B gost2012_256:C gost2012_512:A gost2012_512:B}}
}
if {[info exists env(ALG_LIST)]} {
set alg_list $env(ALG_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set alg_list {gost2001:A gost2001:B gost2001:C}}
"open" {set alg_list {gost2001:A gost2001:B gost2001:C}}
}
if {[info exists env(ALG_LIST)]} {
set alg_list $env(ALG_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set alg_list {gost2001:A gost2001:B gost2001:C gost2012_256:A gost2012_256:B gost2012_256:C gost2012_512:A gost2012_512:B}}
"open" {set alg_list {gost2001:A gost2001:B gost2001:C gost2012_256:A gost2012_256:B gost2012_256:C gost2012_512:A gost2012_512:B}}
}
if {[info exist env(ENC_LIST)]} {
set enc_list $env(ENC_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set enc_list {gost2001:XA:1.2.643.2.2.31.3 gost2001:XB:1.2.643.2.2.31.4 gost2001:XA: gost2012_256:XA:1.2.643.2.2.31.1 gost2012_256:XB:1.2.643.7.1.2.5.1.1 gost2012_256:XA: gost2012_512:A:1.2.643.2.2.31.3 gost2012_512:B:1.2.643.7.1.2.5.1.1 gost2012_512:A:}}
"open" {set enc_list {gost2001:XA:1.2.643.2.2.31.3 gost2001:XB:1.2.643.2.2.31.4 gost2012_256:XA:1.2.643.2.2.31.1 gost2012_256:XB:1.2.643.7.1.2.5.1.1 gost2012_512:A:1.2.643.2.2.31.3 gost2012_512:B:1.2.643.7.1.2.5.1.1}}
}
if {[info exist env(ENC_LIST)]} {
set enc_list $env(ENC_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set enc_list {gost2001:XA:1.2.643.2.2.31.3 gost2001:XB:1.2.643.2.2.31.4 gost2001:XA: gost2012_256:XA:1.2.643.2.2.31.1 gost2012_256:XB:1.2.643.7.1.2.5.1.1 gost2012_256:XA: gost2012_512:A:1.2.643.2.2.31.3 gost2012_512:B:1.2.643.7.1.2.5.1.1 gost2012_512:A:}}
"open" {set enc_list {gost2001:XA:1.2.643.2.2.31.3 gost2001:XB:1.2.643.2.2.31.4 gost2012_256:XA:1.2.643.2.2.31.1 gost2012_256:XB:1.2.643.7.1.2.5.1.1 gost2012_512:A:1.2.643.2.2.31.3 gost2012_512:B:1.2.643.7.1.2.5.1.1}}
}
if {[info exists env(ALG_LIST)]} {
set alg_list $env(ALG_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set alg_list {rsa:1024 gost2001:XA gost2012_256:XA gost2012_512:A}}
"open" {set alg_list {rsa:1024 gost2001:XA gost2012_256:XA gost2012_512:A}}
}
--- /dev/null
+#!/usr/bin/tclsh
+# -*- coding: cp1251 -*-
+lappend auto_path [file dirname [info script]]
+package require ossltest
+
+array set protos {
+ TLSv1.3 -tls1_3
+}
+
+array set groups {
+ GC256A 256
+ GC256B 256
+ GC256C 256
+ GC256D 256
+ GC512A 512
+ GC512B 512
+ GC512C 512
+}
+
+cd $::test::dir
+
+start_tests "TLS 1.3 tests"
+
+if {![info exists ::env(TLS13_PATCHED_OPENSSL)] || !$::env(TLS13_PATCHED_OPENSSL) == 1} {
+ log "Test skipped. Use patched openssl to run the test. Set env variable TLS13_PATCHED_OPENSSL to run the test."
+ end_tests
+ return
+}
+
+if {[info exists env(ALG_LIST)]} {
+ set alg_list $env(ALG_LIST)
+} else {
+ switch -exact [test_target_name] {
+ "openprov" {set alg_list { gost2012_256:TCA gost2012_256:TCB gost2012_256:TCC gost2012_256:TCD gost2012_512:A gost2012_512:B gost2012_512:C }}
+ }
+}
+
+array set alg_to_rfc {
+ "gost2012_256:TCA" "gostr34102012_256a"
+ "gost2012_256:TCB" "gostr34102012_256b"
+ "gost2012_256:TCC" "gostr34102012_256c"
+ "gost2012_256:TCD" "gostr34102012_256d"
+ "gost2012_512:A" "gostr34102012_512a"
+ "gost2012_512:B" "gostr34102012_512b"
+ "gost2012_512:C" "gostr34102012_512c"
+}
+
+set suites {TLS_GOSTR341112_256_WITH_MAGMA_MGM_L TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L TLS_GOSTR341112_256_WITH_MAGMA_MGM_S TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S}
+
+set proto_list {"TLSv1.3"}
+set expected_proto "TLSv1.3"
+
+if {![file exists sslCA/cacert.pem]} {
+ makeCA sslCA gost2012_256:A
+} else {
+ set ::test::ca sslCA
+}
+
+proc sclient_args {ciphersuites_str groups_str {additional_args {}}} {
+ return [list \
+ -connect localhost:4433 -CAfile $::test::ca/cacert.pem -verify_return_error \
+ -verify 1 -state -ciphersuites $ciphersuites_str -curves $groups_str {*}$additional_args]
+}
+
+proc sclient_auth_args {cert key ciphersuites_str groups_str {additional_args {}}} {
+ return [sclient_args $ciphersuites_str $groups_str [list -cert $cert -key $key {*}$additional_args]]
+}
+
+proc sserver_args {cert key ciphersuites_str proto_str {additional_args {}}} {
+ return [list \
+ -no_dhe -www -cert $cert -key $key -ciphersuites $ciphersuites_str $proto_str {*}$additional_args]
+}
+
+set run_all 0
+if {[info exists env(GOST_TEST_RUN_EXTENDED)]} {
+ set run_all 1
+}
+
+foreach alg $alg_list {
+ set alg_fn [string map {":" "_"} $alg]
+
+ test -skip {[file exist localhost_$alg_fn/cert.pem]} \
+ "Создаем серверный сертификат $alg" {
+ makeRegisteredUser localhost_$alg_fn $alg CN localhost OU $alg_fn
+ } 0 1
+
+ test -skip {[file exists ssl_user_$alg_fn/cert.pem]} \
+ "Создаем клиентский сертификат $alg" {
+ makeRegisteredUser ssl_user_$alg_fn $alg CN ssl_user OU $alg_fn
+ } 0 1
+}
+
+foreach suite $suites {
+ test "Get GOST TLS1.3 ciphers" {
+ set ciphers_output [openssl [list ciphers -tls1_3 -ciphersuites $suite]]
+ regexp "\\y$suite\\y" $ciphers_output match
+ } 0 1
+}
+
+set full_alg_list $alg_list
+
+if {!$run_all} {
+ set proto_list [get_sample $proto_list 1]
+ set suite_sample_count 2
+ set alg_sample_count 5
+ set group_sample_count 2
+
+ set suites [get_sample $suites $suite_sample_count]
+ set alg_list [get_sample $alg_list $alg_sample_count]
+ set group_list [get_sample [array names groups] $group_sample_count]
+} else {
+ set group_list [array names groups]
+}
+
+foreach proto $proto_list {
+ foreach group $group_list {
+ foreach alg $alg_list {
+ set alg_fn [string map {":" "_"} $alg]
+
+ foreach suite $suites {
+ set raw_name [lindex [split $suite @] 0]
+ set server_cert localhost_$alg_fn/cert.pem
+ set server_key localhost_$alg_fn/seckey.pem
+
+ test "Handshake $group $suite $proto" {
+ set list [client_server \
+ [sclient_args $suite $group {}] \
+ [sserver_args $server_cert $server_key $suite $protos($proto)] \
+ {}]
+ if {[regexp -lineanchor \
+ {^Server Temp Key: <NULL>, (\d+) bits.*^\s*New,\s+(\S+),\s+Cipher\s+is\s+(\S+)\s*$} \
+ [lindex $list 0] -> group_name result_proto result_cipher]} {
+ list [lindex $list 2] $group_name $result_proto $result_cipher
+ } else {
+ lindex $list 1
+ }
+ } 0 [list 0 $groups($group) $proto $raw_name]
+
+ test "Get page $group $suite $proto" {
+ set list [client_server \
+ [sclient_args $suite $group {-ign_eof}] \
+ [sserver_args $server_cert $server_key $suite $protos($proto)] \
+ "GET /\n\n"]
+ grep "^New," [lindex $list 0]
+ } 0 "New, $expected_proto, Cipher is $raw_name\nNew, $expected_proto, Cipher is $raw_name\n"
+
+ test "Multi-ciphersuites server $proto, $group client" {
+ set list [client_server \
+ [sclient_args $suite $group] \
+ [sserver_args $server_cert $server_key $suite:TLS_AES_256_GCM_SHA384 $protos($proto)] \
+ {}]
+ if {[regexp -lineanchor \
+ {^Server Temp Key: <NULL>, (\d+) bits.*^\s*New,\s+(\S+),\s+Cipher\s+is\s+(\S+)\s*$} \
+ [lindex $list 0] -> group_name result_proto result_cipher]} {
+ list [lindex $list 2] $group_name $result_proto $result_cipher
+ } else {
+ lindex $list 1
+ }
+ } 0 [list 0 $groups($group) $proto $suite]
+
+ if {[string match *gost* $alg]} {
+ set alg_cli_list [list $alg gost2012_256:TCB gost2012_512:B]
+ } else {
+ set alg_cli_list $alg
+ }
+
+ foreach alg_cli $alg_cli_list {
+ set alg_cli_fn [string map {":" "_"} $alg_cli]
+
+ set user_cert ssl_user_$alg_cli_fn/cert.pem
+ set user_key ssl_user_$alg_cli_fn/seckey.pem
+
+ test "Server $alg, client certificate $alg_cli $proto $group" {
+ set list [client_server \
+ [sclient_auth_args $user_cert $user_key $suite $group {-ign_eof}]\
+ [sserver_args $server_cert $server_key $suite:TLS_AES_256_GCM_SHA384 $protos($proto) \
+ {-Verify 3}] \
+ "GET /\n"]
+ list [lindex $list 2] [grep "^New," [lindex $list 0]]
+ } 0 [list 0 [string repeat "New, $expected_proto, Cipher is $raw_name\n" 2]]
+
+
+ # TODO: Fix the test below when the following bug is fixed:
+ # on client side it is possible to specify key with a paramset
+ # that does not match sigalg.
+
+ set mismatching_alg ""
+ foreach other_alg $full_alg_list {
+ if {[string first ":" $alg] != -1 && [string first ":" $other_alg] != -1} {
+ set cli_group [lindex [split $alg ":"] 0]
+ set other_group [lindex [split $other_alg ":"] 0]
+
+ if {$other_alg != $alg && $cli_group == $other_group} {
+ set mismatching_alg $other_alg
+ break ;
+ }
+ }
+ }
+ set mm_alg_fn [string map {":" "_"} $mismatching_alg]
+ set mm_server_cert localhost_$mm_alg_fn/cert.pem
+ set mm_server_key localhost_$mm_alg_fn/seckey.pem
+ set mm_user_cert ssl_user_$mm_alg_fn/cert.pem
+ set mm_user_key ssl_user_$mm_alg_fn/seckey.pem
+
+ test "Mismatching sigalgs: client sigalgs $alg_to_rfc($alg), key $mismatching_alg, \
+ server $mismatching_alg $proto $group" {
+ set list [client_server \
+ [sclient_auth_args $mm_user_cert $mm_user_key $suite $group \
+ [list -ign_eof -sigalgs $alg_to_rfc($alg)]] \
+ [sserver_args $mm_server_cert $mm_server_key $suite:TLS_AES_256_GCM_SHA384 $protos($proto) \
+ {-Verify 3}] \
+ "GET /\n"]
+ list [lindex $list 2] [grep "^New," [lindex $list 0]]
+ } 0 [list 0 [string repeat "New, $expected_proto, Cipher is $raw_name\n" 2]]
+ }
+ }
+ }
+ }
+}
+
+end_tests
if {[info exists env(ALG_LIST)]} {
set alg_list $env(ALG_LIST)
} else {
- switch -exact [engine_name] {
+ switch -exact [test_target_name] {
"ccore" {set alg_list {gost2001:A gost2012_256:A gost2012_512:A}}
"open" {set alg_list {gost2001:A gost2012_256:A gost2012_512:A}}
}
#!/usr/bin/perl
use Test2::V0;
-skip_all('TODO: add pkey support in provider')
- unless $ARGV[0] eq 'engine';
+my @valid_target = qw(engine provider);
+my $target = $ARGV[0];
+
+unless (grep { $_ eq $target } @valid_target) {
+ skip_all("Unknown test mode '$target' – expected one of @valid_target");
+}
plan(2);
use Cwd 'abs_path';
-#
-# If this variable is set, engine would be loaded via configuration
-# file. Otherwise - via command line
-#
-my $use_config = 1;
-
# prepare data for
-
+my $openssl_bin = $ENV{OPENSSL_PROGRAM} || "openssl";
my $engine=$ENV{'ENGINE_NAME'}||"gost";
+my $provider=$ENV{'PROVIDER_NAME'}||"gostprov";
# Reopen STDERR to eliminate extra output
open STDERR, ">>","tests.err";
my $F;
-my $eng_param;
open $F,">","test.cnf";
-if (defined($use_config) && $use_config) {
- $eng_param = "";
- open $F,">","test.cnf";
+if ($target eq 'engine') {
print $F <<EOCFG;
openssl_conf = openssl_def
[openssl_def]
engines = engines
[engines]
-${engine}=gost_conf
+${engine} = gost_conf
[gost_conf]
default_algorithms = ALL
-
EOCFG
-} else {
- $eng_param = "-engine $engine"
+}
+elsif ($target eq 'provider') {
+ print $F <<EOCFG;
+openssl_conf = openssl_def
+[openssl_def]
+providers = providers
+[providers]
+${provider} = provider_conf
+default = provider_conf
+[provider_conf]
+activate = 1
+EOCFG
}
close $F;
$ENV{'OPENSSL_CONF'}=abs_path('test.cnf');
print $F $seckey;
close $F;
#1. Прочитать секретный ключ и напечатать публичный и секретный ключи
- is(`openssl pkey -noout -text -in tmp.pem`,$sectext . $pubtext,
+ is(`$openssl_bin pkey -noout -text -in tmp.pem`,$sectext . $pubtext,
"Print key pair $alg:$paramset");
#2. Прочитать секретный ключ и вывести публичный (все алгоритмы)
- is(`openssl pkey -pubout -in tmp.pem`,$pubkey,
+ is(`$openssl_bin pkey -pubout -in tmp.pem`,$pubkey,
"Compute public key $alg:$paramset");
open $F,">","tmp.pem";
print $F $pubkey;
close $F;
#3. Прочитать публичный и напечать его в виде текста
- is(`openssl pkey -pubin -noout -in tmp.pem -text_pub`,$pubtext,
+ is(`$openssl_bin pkey -pubin -noout -in tmp.pem -text_pub`,$pubtext,
"Read and print public key $alg:$paramset");
}
#unlink "tmp.pem";
-----END PRIVATE KEY-----',
'c019d8939e12740a328625cea86efa3b39170412772b3c110536410bdd58a854',
'e9f7c57547fa0cd3c9942c62f9c74a553626d5f9810975a476825cd6f22a4e86',
+'21c41441319adddafa29983dd2d970c1760a1c127c486edd31720ec8151c1055',
'-----BEGIN PUBLIC KEY-----
MF4wFwYIKoUDBwEBAQEwCwYJKoUDBwECAQEBA0MABEB3WS+MEcXnrMCdavPRgF28U5PDlV1atDh1ADUFxoB/f80OjqQ0T7cGQtk/2nWCGDX7uUrBGA8dql8Bnw9Sgn5+
-----END PUBLIC KEY-----'],
MD4CAQAwFwYIKoUDBwEBAQEwCwYJKoUDBwECAQECBCCvvOUfoyljV0zfUrfEj1nOgBbelamj+eXgl0qxDJjDDA==
-----END PRIVATE KEY-----',
'6f7c5716c08fca79725beb4afaf2a48fd2fa547536d267f2b869b6ced5fddfa4',
-'c9b2ad43f1aa70185f94dbc207ab4a147002f8aac5cf2fcec9d771a36f5f7a91'],
+'c9b2ad43f1aa70185f94dbc207ab4a147002f8aac5cf2fcec9d771a36f5f7a91',
+'21499f455c53ccf80f9a4c24d6370c2aa0c405e266ca9345fa373f13c9c763c5'],
'id-tc26-gost-3410-2012-256-paramSetC'=>
['-----BEGIN PRIVATE KEY-----
MD4CAQAwFwYIKoUDBwEBAQEwCwYJKoUDBwECAQEDBCDq9XGURfLDPrDiMNPUcunrvUwI46FBO2EU+ok8a1DANw==
MD4CAQAwFwYIKoUDBwEBAQEwCwYJKoUDBwECAQEDBCAWm69+rfnGTDZ24MR29IcjMsuPhjBQT6zxPvUYQBrGLg==
-----END PRIVATE KEY-----',
'27e3afdcb9f191b0465ae7d28245cee6ca44d537a7c67d938933cf2012ec71a6',
-'43c9f321b3659ee5108f0bcd5527f403d445f486c9e492768f46a82359ee0385'],
+'43c9f321b3659ee5108f0bcd5527f403d445f486c9e492768f46a82359ee0385',
+'40b6d4df162db8c8639fc55fc8e02e70137b8c46b0891d8990f81cb3452b0eb9'],
'id-tc26-gost-3410-2012-256-paramSetD'=>
['-----BEGIN PRIVATE KEY-----
MD4CAQAwFwYIKoUDBwEBAQEwCwYJKoUDBwECAQEEBCBnmzl1MutYiAXBmZa3GW5sK6Kznpt6V5i+xAl36RDhXQ==
MD4CAQAwFwYIKoUDBwEBAQEwCwYJKoUDBwECAQEEBCBpp7anU1gMcaK/BzAQzAbUHXW2kuh6h9t67i67eIfAgQ==
-----END PRIVATE KEY-----',
'902a174ace21dc8ecf94e6a7e84cde115f902484e2c37d1d2652b1ef0a402dfc',
-'3af2a69e68cd444acc269e75edb90dfe01b8f3d9f97fe7c8b36841df9a2771a1'],
+'3af2a69e68cd444acc269e75edb90dfe01b8f3d9f97fe7c8b36841df9a2771a1',
+'4971dad44d16df7c246daba399039264eec11bb99cb35390455df3736d1b5d4d'],
'id-tc26-gost-3410-2012-512-paramSetA'=>
['-----BEGIN PRIVATE KEY-----
MGgCAQAwIQYIKoUDBwEBAQIwFQYJKoUDBwECAQIBBggqhQMHAQECAwRAVbz5k/8Zj8XbTEtlv9bK9i8FaIbm+NN9kCp2wCbiaw6AXvdBiQlMj7hSGv7AdW928VRszq9Elwc63VQcYzdnkw==
MGgCAQAwIQYIKoUDBwEBAQIwFQYJKoUDBwECAQIBBggqhQMHAQECAwRASeoodGB639ETkSEfOLTFkTozKEpMVAlFPgvK6fOlD9u1/ITUXBoERea2R+HG3YNi81wTMqT0Njq9WnbQvgIx6g==
-----END PRIVATE KEY-----',
'e88ba18821e6a86787cb225ea9b731821efb9e07bdcfb7b0b8f78c70d4e88c2b',
-'4d032ae84928991a48d83fc462da4d21173d8e832a3b30df71a6974f66e377a8'],
+'4d032ae84928991a48d83fc462da4d21173d8e832a3b30df71a6974f66e377a8',
+'4329d5fbc3d5dd87d2633967d098042549ed9dbf76fe5adb27399a151b4a44d2'],
'id-tc26-gost-3410-2012-512-paramSetB'=>
['-----BEGIN PRIVATE KEY-----
MGgCAQAwIQYIKoUDBwEBAQIwFQYJKoUDBwECAQICBggqhQMHAQECAwRAvQKu1fl21NUXvdWlYtRs3Bs4ZW9vQlV1rf1D1rfRUdxjuC2A3xdD9RoUupzK6EeNFkhTMbZ+euQTXwPFN6ykbA==
MGgCAQAwIQYIKoUDBwEBAQIwFQYJKoUDBwECAQICBggqhQMHAQECAwRA+I8I9E0Fz0cKG21QHn7VluHB9j348leFmeXLfGUS+jLqllemtCObR7KLW3bkzH+EiqXbLNMm+JLsmeGv4/nvYQ==
-----END PRIVATE KEY-----',
'f7071ed951ac98570a5f9d299bf5a61d3dcb8082e8733b1571164ce6b54b2d8f',
-'f37881bf843ecee4f0935c4f7653d4cb48b8db6a50394f89792dad899765d7d9'],
+'f37881bf843ecee4f0935c4f7653d4cb48b8db6a50394f89792dad899765d7d9',
+'1e2b8e4beffe40bd9f94110f624f3d5f07ace14b7952f306b22010b51fec15e3'],
'id-tc26-gost-3410-2012-512-paramSetC'=>
['-----BEGIN PRIVATE KEY-----
MF4CAQAwFwYIKoUDBwEBAQIwCwYJKoUDBwECAQIDBEA79FKW7MqF4pQJJvpAhKd9YkwsFXBzcaUhYt3N1KuJV6n5aJ4+kaJfuT3YbhtwWWzNIsIdXUZRaBEGO2cEwysa
-----END PRIVATE KEY-----',
'6e1db0da8832660fbf761119e41d356a1599686a157c9a598b8e18b56cb09791',
'2df0dfa8d437689d41fad965f13ea28ce27c29dd84514b376ea6ad9f0c7e3ece',
+'cd8deae809dc76bc9f77765e3e73b822832ccb073caded0ae579b41a7da55cdb',
'-----BEGIN PUBLIC KEY-----
MIGgMBcGCCqFAwcBAQECMAsGCSqFAwcBAgECAwOBhAAEgYCPdAER26Ym73DSUXBamTLJcntdV3oZ7RRx/+Ijf13GnF36o36i8tEC13uJqOOmujEkAGPtui6yE4iJNVU0uM6yHmIEM5H0c81Sd/VQD8yXW1hyGAZvTMc+U/6oa30YU9YY7+t759d1CIVznPmq9C+VbAApyDCMFjuYnKD/nChsGA==
-----END PUBLIC KEY-----'],
MD4CAQAwFwYIKoUDBwEBAQEwCwYJKoUDBwECAQEBBCBmDDZsVa8VwTVme8jfzdgPAAAAAAAAAAAAAAAAAAAAQA==
-----END PRIVATE KEY-----',
'29132b8efb7b21a15133e51c70599031ea813cca86edb0985e86f331493b3d73',
-'7206480037eb130595c0ed350046af8c96b0fc5bfb4030be65dbf3e207a25de2'],
+'7206480037eb130595c0ed350046af8c96b0fc5bfb4030be65dbf3e207a25de2',
+'6e19ffd60b0fbbfc7657ea4c113b3ffe6aedb789ffbdb25cdb14dfedf400e312'],
'id-tc26-gost-3410-2012-512-paramSetC-rangetest'=>
['-----BEGIN PRIVATE KEY-----
MF4CAQAwFwYIKoUDBwEBAQIwCwYJKoUDBwECAQIDBEA79FKW7MqF4pQJJvpAhKd9YkwsFXBzcaUhYt3N1KuJV6n5aJ4+kaJfuT3YbhtwWWzNIsIdXUZRaBEGO2cEwysa
MF4CAQAwFwYIKoUDBwEBAQIwCwYJKoUDBwECAQIDBEDsI/BH7zxilCahaafnqe3ILFBHUf+pM0wAqwZlpNuMyf////////////////////////////////////////8/
-----END PRIVATE KEY-----',
'fbcd6e72572335d291be497b7bfb264138ab7b2ecca00bc7a9fd90ad7557c0cc',
-'8e5b7bd8b3680d3dc33627c5bed85fdeb4e1ba67307714eb260412ddbb4bb87e']
+'8e5b7bd8b3680d3dc33627c5bed85fdeb4e1ba67307714eb260412ddbb4bb87e',
+'3fbc1dc5b1922f17864871d57bdabd58e342b3e1bfcb39b9cff7b63b680bfcf0']
);
- plan(64);
+ plan(94);
+ my $pkeyopt = $target eq 'engine' ? "-pkeyopt ukmhex:0100000000000000" : "";
while(my($id, $v) = each %derives) {
- my ($alice,$alicehash,$bob,$bobhash,$secrethash,$malice) = @$v;
+ my ($alice,$alicehash,$bob,$bobhash,$secrethashvko,$secrethashecdhe,$malice) = @$v;
+ my $expected_secret_hash = $target eq 'engine' ? $secrethashvko : $secrethashecdhe;
# Alice: keygen
open $F,">",'alice.prv';
print $F $alice;
close $F;
- system("openssl pkey -in alice.prv -out alice.pub.der -pubout -outform DER");
- like(`openssl dgst -sha256 -r alice.pub.der`, qr/^$alicehash/, "Compute public key:$id:Alice");
+ system("$openssl_bin pkey -in alice.prv -out alice.pub.der -pubout -outform DER");
+ like(`$openssl_bin dgst -sha256 -r alice.pub.der`, qr/^$alicehash/, "Compute public key:$id:Alice");
# Bob: keygen
open $F,">",'bob.prv';
print $F $bob;
close $F;
- system("openssl pkey -in bob.prv -out bob.pub.der -pubout -outform DER");
- like(`openssl dgst -sha256 -r bob.pub.der`, qr/^$bobhash/, "Compute public key:$id:Bob");
- # Alice: derive
- system("openssl pkeyutl -derive -inkey alice.prv -keyform PEM -peerkey bob.pub.der -peerform DER -pkeyopt ukmhex:0100000000000000 -out secret_a.bin");
- like(`openssl dgst -sha256 -r secret_a.bin`, qr/^$secrethash/, "Compute shared key:$id:Alice:Bob");
- # Bob: derive
- system("openssl pkeyutl -derive -inkey bob.prv -keyform PEM -peerkey alice.pub.der -peerform DER -pkeyopt ukmhex:0100000000000000 -out secret_b.bin");
- like(`openssl dgst -sha256 -r secret_b.bin`, qr/^$secrethash/, "Compute shared key:$id:Bob:Alice");
+ system("$openssl_bin pkey -in bob.prv -out bob.pub.der -pubout -outform DER");
+ like(`$openssl_bin dgst -sha256 -r bob.pub.der`, qr/^$bobhash/, "Compute public key:$id:Bob");
+ SKIP: {
+ skip "Provider doesn't support derive for GOST2001 paramsets", 4
+ if $target eq 'provider' && $id =~ m/^id-GostR3410-2001-/;
+ # Alice: derive
+ ok(system("$openssl_bin pkeyutl -derive -inkey alice.prv -keyform PEM -peerkey bob.pub.der -peerform DER $pkeyopt -out secret_a.bin") == 0,"Derive succeeded for Alice");
+ like(`$openssl_bin dgst -sha256 -r secret_a.bin`,qr/^\Q$expected_secret_hash\E/,"Compute shared key:$id:Alice:Bob");
+ # Bob: derive
+ ok(system("$openssl_bin pkeyutl -derive -inkey bob.prv -keyform PEM -peerkey alice.pub.der -peerform DER $pkeyopt -out secret_b.bin") == 0,"Derive succeeded for Bob");
+ like(`$openssl_bin dgst -sha256 -r secret_b.bin`,qr/^\Q$expected_secret_hash\E/,"Compute shared key:$id:Bob:Alice");
+ }
if (defined $malice && $malice ne "") {
# Malice: negative test -- this PEM is in the small subgroup
open $F,">",'malice.pub';
print $F $malice;
close $F;
# NB system should return true on failure, so this is a negative test
- ok(system("openssl pkeyutl -derive -inkey alice.prv -keyform PEM -peerkey malice.pub -peerform PEM -pkeyopt ukmhex:0100000000000000 -out secret_m.bin"), "Compute shared key:$id:Alice:Malice");
- ok(system("openssl pkeyutl -derive -inkey bob.prv -keyform PEM -peerkey malice.pub -peerform PEM -pkeyopt ukmhex:0100000000000000 -out secret_m.bin"), "Compute shared key:$id:Bob:Malice");
+ ok(system("$openssl_bin pkeyutl -derive -inkey alice.prv -keyform PEM -peerkey malice.pub -peerform PEM $pkeyopt -out secret_m.bin"), "Compute shared key:$id:Alice:Malice");
+ ok(system("$openssl_bin pkeyutl -derive -inkey bob.prv -keyform PEM -peerkey malice.pub -peerform PEM $pkeyopt -out secret_m.bin"), "Compute shared key:$id:Bob:Malice");
}
}
unlink "alice.prv";
--- /dev/null
+#!/usr/bin/perl
+use strict;
+use warnings;
+use Test2::V0;
+use Cwd 'abs_path';
+use FindBin;
+use lib "$FindBin::Bin";
+use File::Temp qw(tempfile);
+use JSON::PP;
+use ProcessInteractor;
+use Utils;
+
+skip_all('Only for provider') unless $ARGV[0] eq 'provider';
+skip_all('Enable with GOST_PROVIDER_ENABLE_ONLINE_TESTS=1')
+ unless $ENV{GOST_PROVIDER_ENABLE_ONLINE_TESTS};
+
+skip_all('Test skipped. Use patched openssl to run the test. Set env variable TLS13_PATCHED_OPENSSL to run the test.')
+ unless $ENV{TLS13_PATCHED_OPENSSL};
+
+my $openssl_bin = $ENV{OPENSSL_PROGRAM} || "openssl";
+my $run_extended = $ENV{GOST_TEST_RUN_EXTENDED} || 0;
+
+my $config_dir = abs_path("$FindBin::Bin/tls13-configs");
+my @tests = make_test_plan($config_dir);
+
+unless ($run_extended) {
+ note("Set GOST_TEST_RUN_EXTENDED=1 to run all combinations in the test");
+ @tests = ($tests[rand @tests]);
+}
+
+plan tests => scalar @tests;
+
+for my $t (@tests) {
+ my @cmd = (
+ $openssl_bin, "s_client",
+ "-connect", "$t->{host}:$t->{port}", "-tls1_3", "-no_ign_eof",
+ "-ciphersuites", $t->{ciphersuite},
+ "-curves", $t->{curve},
+ "-sigalgs", $t->{sigalg},
+ "-CAfile", $t->{ca},
+ "-servername", $t->{servername}
+ );
+
+ if ($t->{use_auth}) {
+ push @cmd,
+ (
+ "-cert", $t->{cert}, "-key", $t->{key}, "-client_sigalgs",
+ $t->{client_sigalg},
+ );
+ }
+
+ my $cmdline = join(" ", @cmd);
+ note($cmdline);
+
+ my ($status, $output, $rc, $success) = (ProcessInteractor::STATUS_OK, '', -1, 0);
+ my $command = "HEAD / HTTP/1.1\r\nHost: $t->{servername}\r\n\r\n";
+ if (not $t->{use_auth} or $t->{expect_auth_success}) {
+ ($status, $output, $rc) = run_sclient($cmdline, $command, 30, 0);
+ $success = (($status == ProcessInteractor::STATUS_OK) and ($rc == 0));
+ }
+ else {
+ # Infotecs test certificates expire on 2025-12-09. After that we've got to set
+ # expect_auth_success=false in the config.
+ ($status, $output, $rc) = run_sclient($cmdline, $command, 1, 1);
+ $success = (($status == ProcessInteractor::STATUS_OK)
+ and ($output =~ /Connection: close/m));
+ }
+ my $info = "TLS1.3 to $t->{host}:$t->{port} ciphersuite=$t->{ciphersuite}"
+ ." group=$t->{curve} sigalg=$t->{sigalg}: status=@{[ProcessInteractor::status_str($status)]}, rc=$rc";
+ is($success, 1, $info) or diag($output);
+}
+
+sub end_on_blank {
+ my ($response) = @_;
+ return $response =~ /\r\n\r\n/m;
+}
+
+sub end_on_verify_return_code {
+ my ($response) = @_;
+ return $response =~ /Verify return code[^\n]*\n---\n/m;
+}
+
+sub run_sclient {
+ my ($cmdline, $command, $iterations, $server_closes_connection) = @_;
+
+ my $proc = ProcessInteractor->new(
+ cmdline => $cmdline,
+ start_timeout => 30,
+ read_timeout => 5,
+ exit_timeout => 1
+ );
+ my ($status, $out) = $proc->start(\&end_on_verify_return_code);
+ return ($status, $out, 1) if $status != ProcessInteractor::STATUS_OK;
+
+ my $resp;
+ for my $i (1 .. $iterations) {
+ ($status, $resp) = $proc->interact($command, \&end_on_blank);
+ $out .= $resp;
+ return ($status, $out, 1) if $status != ProcessInteractor::STATUS_OK;
+ }
+
+ unless ($server_closes_connection) {
+ $proc->close_stdin();
+ }
+
+ (undef, $resp, my $exitcode) = $proc->wait_for_exit();
+ $out .= $resp;
+ return (ProcessInteractor::STATUS_OK, $out, $exitcode);
+}
+
+sub read_file {
+ my ($path) = @_;
+ open my $fh, '<', $path;
+ local $/;
+ return <$fh>;
+}
+
+sub write_temp_file {
+ my ($data, $suffix, $template) = @_;
+ my ($fh, $filename) = tempfile(
+ TEMPLATE => ($template || "tls13_$$\_" . time . "_XXXXXXXX"),
+ DIR => "$FindBin::Bin",
+ SUFFIX => $suffix,
+ UNLINK => 1,
+ );
+ binmode($fh, ":utf8");
+ print $fh $data;
+ close $fh;
+ return $filename;
+}
+
+sub load_endpoint_tests {
+ my ($conf) = @_;
+ my @tests;
+
+ if ($conf->{skip} == 1) {
+ return @tests;
+ }
+
+ my $host = $conf->{host};
+ my $servername = $conf->{servername} // $host;
+ my $ca_path = write_temp_file(join("\n", @{$conf->{ca}}),
+ '.pem', "tls13_" . $servername . "_ca_XXXX");
+ my @users = @{$conf->{user} // []};
+
+ for my $user (@users) {
+ my $user_sigalg = $user->{sigalg};
+ my $cert = join("\n", @{$user->{cert}});
+ my $key = join("\n", @{$user->{key}});
+ $user->{cert_file} = write_temp_file($cert, '.pem',
+ "tls13_" . $servername . "_usercert_" . $user_sigalg . "_XXXX");
+ $user->{key_file} = write_temp_file($key, '.pem',
+ "tls13_" . $servername . "_userkey_" . $user_sigalg . "_XXXX");
+ }
+
+ srand(time ^ $$);
+
+ for my $ep (@{$conf->{endpoints}}) {
+ my $port = $ep->{port} // 443;
+ my $auth = $ep->{auth} // $conf->{auth} // 0;
+ my $join_sigalgs = $ep->{join_sigalgs} // $conf->{join_sigalgs} // 0;
+ my $expect_auth_success = $ep->{expect_auth_success} // $conf->{expect_auth_success} // $auth;
+ my @ciphersuites = @{$ep->{ciphersuites} // $conf->{ciphersuites}};
+ my @curves = @{$ep->{curves} // $conf->{curves}};
+ my @sigalgs = @{$ep->{sigalgs} // $conf->{sigalgs}};
+ my @supported_client_sigalgs = @{$ep->{supported_client_sigalgs} // $conf->{supported_client_sigalgs}};
+
+ if ($join_sigalgs) {
+ @sigalgs = (join(":", @sigalgs));
+ }
+
+ my $it;
+ if ($auth) {
+ $it = Utils::cartesian_product_iterator(\@ciphersuites,
+ \@curves, \@sigalgs, \@users);
+ }
+ else {
+ $it = Utils::cartesian_product_iterator(\@ciphersuites,
+ \@curves, \@sigalgs);
+ }
+
+ my @ep_tests;
+ while (my $combination = $it->()) {
+ my ($ciphersuite, $curve, $sigalg, $user) = @$combination;
+
+ my ($user_cert, $user_key, $user_sigalg);
+ if (defined($user)) {
+ $user_sigalg = $user->{sigalg};
+ unless (grep { $_ eq $user_sigalg } @supported_client_sigalgs) {
+ next;
+ }
+ $user_cert = $user->{cert_file};
+ $user_key = $user->{key_file};
+ }
+
+ push @ep_tests,
+ {
+ host => $host,
+ port => $port,
+ ciphersuite => $ciphersuite,
+ curve => $curve,
+ client_sigalg => $user_sigalg,
+ sigalg => $sigalg,
+ servername => $servername,
+ ca => $ca_path,
+ cert => $user_cert,
+ key => $user_key,
+ use_auth => $auth,
+ expect_auth_success => $expect_auth_success,
+ };
+ }
+
+ if (@ep_tests) {
+ push @tests, @ep_tests;
+ }
+ }
+
+ return @tests;
+}
+
+sub make_test_plan {
+ my ($config_dir) = @_;
+
+ opendir(my $dh, $config_dir)
+ or skip_all("Directory $config_dir is not found");
+ my @config_files = grep { /\.json$/ && -f "$config_dir/$_" } readdir($dh);
+ closedir($dh);
+ skip_all("Directory $config_dir has no test configs") unless @config_files;
+
+ my @tests;
+ for my $config_file (@config_files) {
+ my $data = read_file("$config_dir/$config_file");
+ my $config = JSON::PP->new->utf8->decode($data);
+ for my $server (@$config) {
+ push @tests, load_endpoint_tests($server);
+ }
+ }
+
+ return @tests;
+}
--- /dev/null
+# Implemented using ChatGPT
+package ProcessInteractor;
+use strict;
+use warnings;
+use IPC::Open3;
+use IO::Select;
+use POSIX ":sys_wait_h";
+use Symbol 'gensym';
+use feature "switch";
+use constant {
+ STATUS_OK => 0,
+ STATUS_TIMEOUT => 1,
+ STATUS_EOF => 2,
+};
+
+sub status_str {
+ my ($status) = @_;
+
+ if ($status == STATUS_OK) {
+ return "OK";
+ }
+ elsif ($status == STATUS_TIMEOUT) {
+ return "Timeout";
+ }
+ elsif ($status == STATUS_EOF) {
+ return "EOF";
+ }
+ else {
+ return "Unknown";
+ }
+}
+
+sub new {
+ my ($class, %args) = @_;
+ my $self = {
+ cmdline => ($args{cmdline} || die "cmdline required"),
+ start_timeout => ($args{start_timeout} || 1),
+ read_timeout => ($args{read_timeout} || 1),
+ exit_timeout => ($args{exit_timeout} || 1),
+ _pid => undef,
+ _reader => undef,
+ _writer => undef,
+ _err => undef,
+ _sel => undef,
+ };
+
+ return bless $self, $class;
+}
+
+sub _start_process {
+ my ($self) = @_;
+ my ($reader, $writer, $err);
+ $err = gensym;
+ my $pid = open3($writer, $reader, $err, "sh -c \'$self->{cmdline} 2>&1\' ")
+ or die "Cannot start process: $!";
+ my $sel = IO::Select->new($reader);
+ $writer->autoflush(1);
+ close $err;
+
+ $self->{_pid} = $pid;
+ $self->{_reader} = $reader;
+ $self->{_writer} = $writer;
+ $self->{_sel} = $sel;
+}
+
+sub _read_until {
+ my ($self, $check_sub, $timeout) = @_;
+ my $reader = $self->{_reader} or die "Reader not set";
+ my $sel = $self->{_sel} or die "Selector not set";
+ my $output = '';
+
+ my $buf;
+ while (1) {
+ my @ready = $sel->can_read($timeout);
+ unless (@ready) {
+ return (STATUS_TIMEOUT, $output);
+ }
+
+ # Читаем ВСЁ, что доступно прямо сейчас
+ while ($sel->can_read(0)) {
+ my $bytes_read = sysread($reader, $buf, 4096);
+ unless (defined $bytes_read) {
+ die "Error reading from process: $!";
+ }
+ if ($bytes_read == 0) {
+ return (STATUS_EOF, $output);
+ }
+ $output .= $buf;
+ }
+
+ if ($check_sub->($output)) {
+ return (STATUS_OK, $output);
+ }
+ }
+}
+
+sub start {
+ my ($self, $start_check) = @_;
+ $start_check ||= sub { 1 };
+ die "start_check must be a CODE ref" unless ref $start_check eq 'CODE';
+
+ $self->_start_process();
+ my ($status, $output) =
+ $self->_read_until($start_check, $self->{start_timeout});
+ return ($status, $output);
+}
+
+sub interact {
+ my ($self, $command, $response_check) = @_;
+ die "Process not started" unless defined $self->{_pid};
+ $response_check ||= sub { 1 };
+ die "response_check must be a CODE ref"
+ unless ref $response_check eq 'CODE';
+
+ my $writer = $self->{_writer};
+ print $writer "$command";
+
+ my ($status, $response) =
+ $self->_read_until($response_check, $self->{read_timeout});
+ return ($status, $response);
+}
+
+sub close_stdin {
+ my ($self) = @_;
+ close $self->{_writer};
+}
+
+sub wait_for_exit {
+ my ($self) = @_;
+ die "Process not started" unless defined $self->{_pid};
+
+ my ($status, $output) =
+ $self->_read_until(sub { 0 }, $self->{exit_timeout});
+
+ my $exit_timeout = $self->{exit_timeout};
+ my $elapsed = 0;
+ my $interval = 0.1;
+ while ($elapsed < $exit_timeout) {
+ my $res = waitpid($self->{_pid}, WNOHANG);
+ if ($res > 0) {
+ my $exitcode = $? >> 8;
+ return ($status, $output, $exitcode);
+ }
+ select(undef, undef, undef, $interval);
+ $elapsed += $interval;
+ }
+
+ kill 'TERM', $self->{_pid};
+ select(undef, undef, undef, 0.5);
+ if (waitpid($self->{_pid}, WNOHANG) == 0) {
+ kill 'KILL', $self->{_pid};
+ waitpid($self->{_pid}, 0);
+ }
+ my $exitcode = $? >> 8;
+ return ($status, $output, $exitcode);
+}
+
+1;
--- /dev/null
+package Utils;
+use strict;
+use warnings;
+
+# # Implemented using ChatGPT
+sub cartesian_product_iterator {
+ my @arrays = @_;
+
+ my $empty_result = sub {return};
+
+ unless (@arrays) {
+ return $empty_result;
+ }
+
+ for my $a (@arrays) {
+ unless (@$a) {
+ return $empty_result;
+ }
+ }
+
+ my @idx = (0) x @arrays;
+ my $done = 0;
+
+ return sub {
+ return if $done;
+ my @current = map {$arrays[$_]->[$idx[$_]]} 0 .. $#arrays;
+
+ # increment indices
+ for (my $i = $#idx ; $i >= 0 ; $i--) {
+ $idx[$i]++;
+ if ($idx[$i] < @{$arrays[$i]}) {
+ last;
+ }
+ else {
+ $idx[$i] = 0;
+ if ($i == 0) {$done = 1}
+ }
+ }
+ return \@current;
+ };
+}
+
+1;
--- /dev/null
+[
+ {
+ "name": "Infotecs",
+ "skip": false,
+ "host": "91.244.183.22",
+ "ca": [
+ "-----BEGIN CERTIFICATE-----",
+ "MIICcDCCAh2gAwIBAgIQFWZq8KR5sZRF3z1wqYxUlDAKBggqhQMHAQEDAjB5MQsw",
+ "CQYDVQQGEwJSVTEPMA0GA1UECBMGTW9zY293MREwDwYDVQQHEwhSb29tIDItMzEe",
+ "MBwGA1UECxMVQ3J5cHRvZ3JhcHlEZXBhcnRtZW50MREwDwYDVQQKEwhJbmZvdGVj",
+ "czETMBEGA1UEAxMKQ1JZUFRPNC1DQTAgFw0xOTExMDgwMjU4MjBaGA8yMDY5MTEw",
+ "ODAzMDgwM1oweTELMAkGA1UEBhMCUlUxDzANBgNVBAgTBk1vc2NvdzERMA8GA1UE",
+ "BxMIUm9vbSAyLTMxHjAcBgNVBAsTFUNyeXB0b2dyYXB5RGVwYXJ0bWVudDERMA8G",
+ "A1UEChMISW5mb3RlY3MxEzARBgNVBAMTCkNSWVBUTzQtQ0EwZjAfBggqhQMHAQEB",
+ "ATATBgcqhQMCAiMBBggqhQMHAQECAgNDAARAVCk2ydYf2zuj1dd0gwQiSaxqcTK/",
+ "o987avmYKyHWzwZRGzPUOpkW/7xHgqRbgEqh77KhXkttvayvevc63pNjW6N4MHYw",
+ "CwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOOsXFhoPf1/",
+ "svgUsBqEFya6ezufMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUCBBYE",
+ "FMA4xxW2VZcnLXQdYH4dAypxPLr7MAoGCCqFAwcBAQMCA0EAuQRaslNHZRwLli/U",
+ "86dH8BtHJ6gPLN2CFahrrgROFyQbNBWAQBsCEgjw6UBgW60U7uzYMwaKmvBaFPEq",
+ "pluXLg==",
+ "-----END CERTIFICATE-----"
+ ],
+ "curves": [
+ "GC256A",
+ "GC256B",
+ "GC256C",
+ "GC256D",
+ "GC512A",
+ "GC512B",
+ "GC512C"
+ ],
+ "ciphersuites": [
+ "TLS_GOSTR341112_256_WITH_MAGMA_MGM_L",
+ "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L",
+ "TLS_GOSTR341112_256_WITH_MAGMA_MGM_S",
+ "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S"
+ ],
+ "auth": true,
+ "expect_auth_success": true,
+ "supported_client_sigalgs": [
+ "gostr34102012_256a",
+ "gostr34102012_256b",
+ "gostr34102012_256c",
+ "gostr34102012_256d",
+ "gostr34102012_512a",
+ "gostr34102012_512b",
+ "gostr34102012_512c"
+ ],
+ "endpoints": [
+ {
+ "port": 15003,
+ "sigalgs": [
+ "gostr34102012_256a"
+ ]
+ },
+ {
+ "port": 15013,
+ "sigalgs": [
+ "gostr34102012_256b"
+ ]
+ },
+ {
+ "port": 15023,
+ "sigalgs": [
+ "gostr34102012_256c"
+ ]
+ },
+ {
+ "port": 15033,
+ "sigalgs": [
+ "gostr34102012_256d"
+ ]
+ },
+ {
+ "port": 15073,
+ "sigalgs": [
+ "gostr34102012_512a"
+ ]
+ },
+ {
+ "port": 15083,
+ "sigalgs": [
+ "gostr34102012_512b"
+ ]
+ },
+ {
+ "port": 15093,
+ "sigalgs": [
+ "gostr34102012_512c"
+ ]
+ },
+ {
+ "port": 15002,
+ "sigalgs": [
+ "gostr34102012_256a"
+ ],
+ "auth": false
+ },
+ {
+ "port": 15012,
+ "sigalgs": [
+ "gostr34102012_256b"
+ ],
+ "auth": false
+ },
+ {
+ "port": 15022,
+ "sigalgs": [
+ "gostr34102012_256c"
+ ],
+ "auth": false
+ },
+ {
+ "port": 15032,
+ "sigalgs": [
+ "gostr34102012_256d"
+ ],
+ "auth": false
+ },
+ {
+ "port": 15072,
+ "sigalgs": [
+ "gostr34102012_512a"
+ ],
+ "auth": false,
+ "supported_client_sigalgs": [
+ "gostr34102012_512a"
+ ]
+ },
+ {
+ "port": 15082,
+ "sigalgs": [
+ "gostr34102012_512b"
+ ],
+ "auth": false
+ },
+ {
+ "port": 15092,
+ "sigalgs": [
+ "gostr34102012_512c"
+ ],
+ "auth": false
+ }
+ ],
+ "user": [
+ {
+ "sigalg": "gostr34102012_512a",
+ "key": [
+ "-----BEGIN PRIVATE KEY-----",
+ "MGgCAQAwIQYIKoUDBwEBAQIwFQYJKoUDBwECAQIBBggqhQMHAQECAwRAErXiIIvv",
+ "u2tngjox1+6GflZUoLcNwGdwXATDeKxhnOwg1rb9elc0mbvIocXRnRmwbXGytlLW",
+ "vpbSqadDor4P1A==",
+ "-----END PRIVATE KEY-----"
+ ],
+ "cert": [
+ "-----BEGIN CERTIFICATE-----",
+ "MIIFCTCCBLagAwIBAgIQAdv7vv6FK+AAAOmsAAUAATAKBggqhQMHAQEDAjCB6jEs",
+ "MCoGA1UECQwj0YPQuy7QntGC0YDQsNC00L3QsNGPLCAy0JEg0YHRgtGALjExCzAJ",
+ "BgNVBAYTAlJVMRkwFwYDVQQHDBDQsy4g0JzQvtGB0LrQstCwMTAwLgYDVQQLDCfQ",
+ "o9C00L7RgdGC0L7QstC10YDRj9GO0YnQuNC5INGG0LXQvdGC0YAxLzAtBgNVBAoM",
+ "JtCi0LXRgdGC0L7QstGL0Lkg0KPQpiDQmNC90YTQvtCi0LXQmtChMS8wLQYDVQQD",
+ "DCbQotC10YHRgtC+0LLRi9C5INCj0KYg0JjQvdGE0L7QotC10JrQoTAeFw0yNTA3",
+ "MjMxMDQ2MDBaFw0yNTEyMDkyMDU5NTlaMBMxETAPBgNVBAMMCE5ldyBVc2VyMIGq",
+ "MCEGCCqFAwcBAQECMBUGCSqFAwcBAgECAQYIKoUDBwEBAgMDgYQABIGAsTeeRPKQ",
+ "veMIzP3UKIBfANrihEAOblFCPkxdOm2TEVCMkNcgC945xSnBMx3oEe+OVDqUOZPq",
+ "hDP6j886saIUWwnkIvuP7WoBe1QEh23y31n7SwCe0JaqGDLg9OVGtk2qUQBFP3Y3",
+ "LK4Yy+oe3Qj1CG4rnxIOOL5uMmbP09AH/W2BCQAwMDA1MDAwMaOCArUwggKxMB0G",
+ "A1UdDgQWBBTGivt2al/MErN1WJ0vmHZ5ZWrdCTAdBgNVHSAEFjAUMAgGBiqFA2Rx",
+ "ATAIBgYqhQNkcQIwGQYFKoUDZG8EEAwOVmlQTmV0IENTUCA0LjQwgbMGBSqFA2Rw",
+ "BIGpMIGmDA5WaVBOZXQgQ1NQIDQuNAwm0KLQtdGB0YLQvtCy0YvQuSDQo9CmINCY",
+ "0L3RhNC+0KLQtdCa0KEMNtCX0LDQutC70Y7Rh9C10L3QuNC1IOKEljE0OS8zLzIv",
+ "MS0yMDU5INC+0YIgMTcuMDguMjAyMgw00JfQsNC60LvRjtGH0LXQvdC40LUg4oSW",
+ "IDE0OS83LzYtMjUyINC+0YIgMDQuMDcuMjAyMzA+BggrBgEFBQcBAQQyMDAwLgYI",
+ "KwYBBQUHMAKGImh0dHA6Ly90ZXN0Y2VydC5pbmZvdGVjcy5ydS9DQS5kZXIwNAYD",
+ "VR0fBC0wKzApoCegJYYjaHR0cDovL3Rlc3RjZXJ0LmluZm90ZWNzLnJ1L1NPUy5j",
+ "cmwwggEoBgNVHSMEggEfMIIBG4AUZIMCNzuDIxnzogrocUY6fz89Ib+hgfCkge0w",
+ "geoxLDAqBgNVBAkMI9GD0Lsu0J7RgtGA0LDQtNC90LDRjywgMtCRINGB0YLRgC4x",
+ "MQswCQYDVQQGEwJSVTEZMBcGA1UEBwwQ0LMuINCc0L7RgdC60LLQsDEwMC4GA1UE",
+ "Cwwn0KPQtNC+0YHRgtC+0LLQtdGA0Y/RjtGJ0LjQuSDRhtC10L3RgtGAMS8wLQYD",
+ "VQQKDCbQotC10YHRgtC+0LLRi9C5INCj0KYg0JjQvdGE0L7QotC10JrQoTEvMC0G",
+ "A1UEAwwm0KLQtdGB0YLQvtCy0YvQuSDQo9CmINCY0L3RhNC+0KLQtdCa0KGCEAHb",
+ "Qj5MiT5wAADNpgAFAAEwCgYIKoUDBwEBAwIDQQDwFJsxJveNXoba8l5PjptqW6Vp",
+ "+cKOYP0NI1vKIWI91WCp2XxicRHKDoRJgyIGj1zR+D+ddQFMOGn4eeUQSvsE",
+ "-----END CERTIFICATE-----"
+ ]
+ }
+ ]
+ }
+]
\ No newline at end of file
--- /dev/null
+#include <openssl/ec.h>
+#include <openssl/bn.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "gost_lcl.h"
+
+#define T(e) \
+ if (!(e)) { \
+ ERR_print_errors_fp(stderr); \
+ OpenSSLDie(__FILE__, __LINE__, #e); \
+ }
+
+#define cRED "\033[1;31m"
+#define cGREEN "\033[1;32m"
+#define cNORM "\033[m"
+
+static EVP_PKEY *load_private_key(int key_nid, int param_nid, const char *pk,
+ const char *pub)
+{
+ EVP_PKEY_CTX *ctx;
+
+ T(ctx = EVP_PKEY_CTX_new_id(key_nid, NULL));
+ T(EVP_PKEY_paramgen_init(ctx));
+ T(EVP_PKEY_CTX_ctrl(ctx, -1, -1, EVP_PKEY_CTRL_GOST_PARAMSET, param_nid,
+ NULL));
+ EVP_PKEY *key = NULL;
+ T((EVP_PKEY_paramgen(ctx, &key)) == 1);
+ EVP_PKEY_CTX_free(ctx);
+
+ EC_KEY *ec;
+ T(ec = EVP_PKEY_get0(key));
+
+ const int len = EVP_PKEY_bits(key) / 8;
+ BN_CTX *bc;
+ T(bc = BN_CTX_secure_new());
+ BN_CTX_start(bc);
+ const EC_GROUP *group = EC_KEY_get0_group(ec);
+ EC_POINT *pkey = NULL;
+ if (pk) {
+ /* Read private key. */
+ BIGNUM *d = NULL;
+
+ T(d = BN_lebin2bn((const unsigned char *)pk, len, NULL));
+ T(EC_KEY_set_private_key(ec, d));
+
+ /* Compute public key. */
+ T(pkey = EC_POINT_new(group));
+ T(EC_POINT_mul(group, pkey, d, NULL, NULL, bc));
+ BN_free(d);
+ T(EC_KEY_set_public_key(ec, pkey));
+ } else {
+ /* Read public key. */
+ BIGNUM *x, *y;
+
+ T(x = BN_lebin2bn((const unsigned char *)pub, len, NULL));
+ T(y = BN_lebin2bn((const unsigned char *)pub + len, len, NULL));
+ EC_POINT *xy = EC_POINT_new(group);
+ T(EC_POINT_set_affine_coordinates(group, xy, x, y, bc));
+ BN_free(x);
+ BN_free(y);
+ T(EC_KEY_set_public_key(ec, xy));
+ EC_POINT_free(xy);
+ }
+
+#ifdef DEBUG
+ BIO *bp = BIO_new_fd(1, BIO_NOCLOSE);
+ if (pk)
+ PEM_write_bio_PrivateKey(bp, key, NULL, NULL, 0, NULL, NULL);
+ PEM_write_bio_PUBKEY(bp, key);
+ BIO_free(bp);
+#endif
+
+ /* Verify public key. */
+ if (pk && pub) {
+ BIGNUM *x, *y;
+
+ T(x = BN_lebin2bn((const unsigned char *)pub, len, NULL));
+ T(y = BN_lebin2bn((const unsigned char *)pub + len, len, NULL));
+ EC_POINT *xy = EC_POINT_new(group);
+ T(EC_POINT_set_affine_coordinates(group, xy, x, y, bc));
+ BN_free(x);
+ BN_free(y);
+ if (EC_POINT_cmp(group, pkey, xy, bc) == 0)
+ printf("Public key %08x matches private key %08x\n",
+ *(int *)pub, *(int *)pk);
+ else
+ {
+ printf(cRED "Public key mismatch!" cNORM "\n");
+ exit(1);
+ }
+ EC_POINT_free(xy);
+ }
+ EC_POINT_free(pkey);
+ BN_CTX_end(bc);
+ BN_CTX_free(bc);
+
+ return key;
+}
+
+int main()
+{
+ OpenSSL_add_all_algorithms();
+
+ const char client_private_key[] =
+ "\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04"
+ "\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04";
+
+ const char server_private_key[] =
+ "\xB6\x6B\x18\xAC\xD9\x25\x59\x02\x19\xB8\x8D\xF3\xC4\xE8\xD2\x64"
+ "\x84\x84\x84\x84\x84\x84\x84\x84\x84\x84\x84\x84\x84\x84\x84\x04";
+
+ const char server_public_key[] =
+ "\xF8\x55\xF9\x3A\xE4\x0B\xC3\xDD\x2B\xCF\xDB\xAC\x99\xD4\xC3\xF9"
+ "\xD6\xCF\x16\xED\xB8\x1F\x87\xC6\x84\x68\xB6\x1B\xAF\x2E\xF6\xB2"
+ "\x0C\x18\x4E\xD5\xEC\xB5\x46\x2B\x1E\x18\x7C\x7E\xCB\x84\x40\xAF"
+ "\x41\xD7\x28\xAA\x45\x84\x2F\xC7\xDB\xD2\xC4\x74\x74\x85\x9F\xD2";
+
+ const char client_public_key[] =
+ "\x9E\x44\x41\x7A\x31\x6B\x95\xC5\x4B\xC0\x04\x63\x05\xFA\x60\x9C"
+ "\x85\xE5\x05\x78\x2D\x26\x1B\xA9\x87\xBF\xF8\xC7\x4B\xEE\x51\xD8"
+ "\x3B\xF9\xE8\x35\xB9\x33\x18\x2C\x70\xF4\xDE\x50\x04\x75\xB1\x36"
+ "\xBC\xE4\xD3\x48\xC3\x05\x19\x0A\x60\x8E\xC1\xB1\x28\x70\x56\xEB";
+
+ EVP_PKEY *client_key = load_private_key(NID_id_GostR3410_2012_256,
+ NID_id_tc26_gost_3410_2012_256_paramSetA,
+ client_private_key, client_public_key);
+ EVP_PKEY *server_key = load_private_key(NID_id_GostR3410_2012_256,
+ NID_id_tc26_gost_3410_2012_256_paramSetA,
+ server_private_key, server_public_key);
+
+ unsigned char expected_result[] = {0xD5, 0x56, 0xB0, 0xBC, 0x8F, 0x86, 0xE1, 0x46,
+ 0x6C, 0xF1, 0x30, 0xD9, 0xE7, 0xDB, 0x80, 0x69,
+ 0x73, 0xC1, 0x8E, 0xE0, 0x73, 0x8C, 0x33, 0xC6,
+ 0x73, 0xE0, 0x16, 0x17, 0x70, 0xE3, 0x6B, 0x80};
+
+ unsigned char *client_result = NULL, *server_result = NULL;
+ size_t client_result_len = 0, server_result_len = 0;
+ uint8_t ukm = 1;
+ int ret = 1;
+
+ if (!internal_compute_ecdh(NULL, &client_result_len, &ukm, 1,
+ EC_KEY_get0_public_key(EVP_PKEY_get0(server_key)),
+ EVP_PKEY_get0(client_key)))
+ goto exit;
+
+ if (!internal_compute_ecdh(NULL, &server_result_len, &ukm, 1,
+ EC_KEY_get0_public_key(EVP_PKEY_get0(client_key)),
+ EVP_PKEY_get0(server_key)))
+ goto exit;
+
+ if ((client_result = OPENSSL_malloc(client_result_len)) == NULL)
+ goto exit;
+
+ if ((server_result = OPENSSL_malloc(server_result_len)) == NULL)
+ goto exit;
+
+ if (!internal_compute_ecdh(client_result, &client_result_len, &ukm, 1,
+ EC_KEY_get0_public_key(EVP_PKEY_get0(server_key)),
+ EVP_PKEY_get0(client_key))) {
+ printf(cRED "ECDH compute client key internal error!" cNORM "\n");
+ goto exit;
+ }
+
+ if (!internal_compute_ecdh(server_result, &server_result_len, &ukm, 1,
+ EC_KEY_get0_public_key(EVP_PKEY_get0(client_key)),
+ EVP_PKEY_get0(server_key))) {
+ printf(cRED "ECDH compute server key internal error!" cNORM "\n");
+ goto exit;
+ }
+
+ if (client_result_len != server_result_len
+ || memcmp(client_result, server_result, client_result_len)) {
+ printf(cRED "client key and server key mismatch!" cNORM "\n");
+ goto exit;
+ }
+
+ printf(cGREEN "client ECDH and server ECDH match!" cNORM "\n");
+
+ if (memcmp(client_result, expected_result, client_result_len / 2)) {
+ printf(cRED "Reference ECDHE and computed ECDHE mismatch!" cNORM "\n");
+ goto exit;
+ }
+
+ printf(cGREEN "Reference ECDHE and computed ECDHE match!" cNORM "\n");
+
+ ret = 0;
+exit:
+
+ EVP_PKEY_free(client_key);
+ EVP_PKEY_free(server_key);
+ OPENSSL_free(server_result);
+ OPENSSL_free(client_result);
+
+ return ret;
+}
\ No newline at end of file
fprintf(f, "\n");
}
+static int expect_eq(const char *test_name, int ret, const unsigned char *result,
+ const unsigned char *expected, size_t len)
+{
+ if (ret <= 0) {
+ ERR_print_errors_fp(stderr);
+ return 1;
+ } else {
+ hexdump(stdout, test_name, result, len);
+ if (memcmp(result, expected, len) != 0) {
+ fprintf(stdout, "ERROR! %s test failed\n", test_name);
+ return 2;
+ }
+ }
+ return 0;
+}
+
+static int initialize_openssl(ENGINE **eng)
+{
+#ifdef _MSC_VER
+ _putenv_s("OPENSSL_ENGINES", ENGINE_DIR);
+#else
+ setenv("OPENSSL_ENGINES", ENGINE_DIR, 0);
+#endif
+ OPENSSL_add_all_algorithms_conf();
+ ERR_load_crypto_strings();
+ T(*eng = ENGINE_by_id("gost"));
+ T(ENGINE_init(*eng));
+ T(ENGINE_set_default(*eng, ENGINE_METHOD_ALL));
+ return 0;
+}
+
+static void cleanup_openssl(ENGINE *eng)
+{
+ ENGINE_finish(eng);
+ ENGINE_free(eng);
+}
+
int main(void)
{
const unsigned char shared_key[] = {
};
unsigned char kdf_label[] = { 0x26, 0xBD, 0xB8, 0x78 };
- unsigned char kdf_seed[] =
- { 0xAF, 0x21, 0x43, 0x41, 0x45, 0x65, 0x63, 0x78 };
+ unsigned char kdf_seed[] = {
+ 0xAF, 0x21, 0x43, 0x41, 0x45, 0x65, 0x63, 0x78
+ };
const unsigned char kdf_etalon[] = {
0x22, 0xB6, 0x83, 0x78, 0x45, 0xC6, 0xBE, 0xF6,
0x5E, 0xA7, 0x16, 0x72, 0xB2, 0x65, 0x83, 0x10,
0x4e, 0x5b, 0xf0, 0xff, 0x64, 0x1a, 0x19, 0xff,
};
+ const unsigned char kroot_kuzn_s[] = {
+ 0x58, 0x16, 0x88, 0xD7, 0x6E, 0xFE, 0x12, 0x2B,
+ 0xB5, 0x5F, 0x62, 0xB3, 0x8E, 0xF0, 0x1B, 0xCC,
+ 0x8C, 0x88, 0xDB, 0x83, 0xE9, 0xEA, 0x4D, 0x55,
+ 0xD3, 0x89, 0x8C, 0x53, 0x72, 0x1F, 0xC3, 0x84
+ };
+
+ const unsigned char tlstree_kuzn_s_etalon[] = {
+ 0xE1, 0xC5, 0x9B, 0x41, 0x69, 0xD8, 0x96, 0x10,
+ 0x7F, 0x78, 0x45, 0x68, 0x93, 0xA3, 0x75, 0x1E,
+ 0x15, 0x73, 0x54, 0x3D, 0xAD, 0x8C, 0xB7, 0x40,
+ 0x69, 0xE6, 0x81, 0x4A, 0x51, 0x3B, 0xBB, 0x1C
+ };
+
+ unsigned char kroot_magma_l[] = {
+ 0xDF, 0x66, 0x60, 0x1E, 0xDD, 0xD6, 0x4E, 0x96,
+ 0x1D, 0xFC, 0x7D, 0xD0, 0x21, 0x2E, 0xF2, 0x25,
+ 0xC0, 0x05, 0x33, 0xE6, 0xDA, 0xA4, 0xAD, 0x24,
+ 0x18, 0x5E, 0xBE, 0xB2, 0x24, 0xB5, 0x46, 0xB8
+ };
+
+ unsigned char tlstree_magma_l_etalon[] = {
+ 0xBD, 0x00, 0x9F, 0xFC, 0x04, 0xA0, 0x52, 0x9E,
+ 0x60, 0x78, 0xEB, 0xA5, 0xA0, 0x7A, 0xDE, 0x74,
+ 0x93, 0x7F, 0xF3, 0xA1, 0xAB, 0x75, 0xF7, 0xAE,
+ 0x05, 0x19, 0x04, 0x78, 0x51, 0x9B, 0x6D, 0xF3
+ };
+
unsigned char buf[32 + 16];
int ret = 0, err = 0;
int outlen = 40;
unsigned char tlsseq[8];
unsigned char out[32];
-#ifdef _MSC_VER
- _putenv_s("OPENSSL_ENGINES", ENGINE_DIR);
-#else
- setenv("OPENSSL_ENGINES", ENGINE_DIR, 0);
-#endif
- OPENSSL_add_all_algorithms_conf();
- ERR_load_crypto_strings();
ENGINE *eng;
- T(eng = ENGINE_by_id("gost"));
- T(ENGINE_init(eng));
- T(ENGINE_set_default(eng, ENGINE_METHOD_ALL));
+ if (initialize_openssl(&eng) != 0) {
+ return 1;
+ }
memset(buf, 0, sizeof(buf));
-
memset(kroot, 0xFF, 32);
memset(tlsseq, 0, 8);
tlsseq[7] = 63;
ret = gost_kexp15(shared_key, 32,
NID_magma_ctr, magma_key,
NID_magma_mac, mac_magma_key, magma_iv, 4, buf, &outlen);
-
- if (ret <= 0) {
- ERR_print_errors_fp(stderr);
- err = 1;
- } else {
- hexdump(stdout, "Magma key export", buf, 40);
- if (memcmp(buf, magma_export, 40) != 0) {
- fprintf(stdout, "ERROR! test failed\n");
- err = 2;
- }
- }
+ err = expect_eq("Magma key export", ret, buf, magma_export, 40);
+ if (err)
+ goto cleanup;
ret = gost_kimp15(magma_export, 40,
NID_magma_ctr, magma_key,
NID_magma_mac, mac_magma_key, magma_iv, 4, buf);
-
- if (ret <= 0) {
- ERR_print_errors_fp(stderr);
- err = 3;
- } else {
- hexdump(stdout, "Magma key import", buf, 32);
- if (memcmp(buf, shared_key, 32) != 0) {
- fprintf(stdout, "ERROR! test failed\n");
- err = 4;
- }
- }
+ err = expect_eq("Magma key import", ret, buf, shared_key, 32);
+ if (err)
+ goto cleanup;
ret = gost_kdftree2012_256(kdf_result, 64, kdftree_key, 32, kdf_label, 4,
- kdf_seed, 8, 1);
- if (ret <= 0) {
- ERR_print_errors_fp(stderr);
- err = 5;
- } else {
- hexdump(stdout, "KDF TREE", kdf_result, 64);
- if (memcmp(kdf_result, kdf_etalon, 64) != 0) {
- fprintf(stdout, "ERROR! test failed\n");
- err = 6;
- }
- }
-
- ret = gost_tlstree(NID_grasshopper_cbc, kroot, out, tlsseq);
- if (ret <= 0) {
- ERR_print_errors_fp(stderr);
- err = 7;
- } else {
- hexdump(stdout, "Gost TLSTREE - grasshopper", out, 32);
- if (memcmp(out, tlstree_gh_etalon, 32) != 0) {
- fprintf(stdout, "ERROR! test failed\n");
- err = 8;
- }
- }
-
- ENGINE_finish(eng);
- ENGINE_free(eng);
-
+ kdf_seed, 8, 1);
+ err = expect_eq("KDF TREE", ret, kdf_result, kdf_etalon, 64);
+ if (err)
+ goto cleanup;
+
+ ret = gost_tlstree(NID_grasshopper_cbc, kroot, out, tlsseq, TLSTREE_MODE_NONE);
+ err = expect_eq("Gost TLSTREE - grasshopper", ret, out, tlstree_gh_etalon, 32);
+ if (err)
+ goto cleanup;
+
+ tlsseq[7] = 7;
+ ret = gost_tlstree(NID_kuznyechik_mgm, kroot_kuzn_s, out, tlsseq, TLSTREE_MODE_S);
+ err = expect_eq("Gost TLSTREE - kuznyechik", ret, out, tlstree_kuzn_s_etalon, 32);
+ if (err)
+ goto cleanup;
+
+ tlsseq[7] = 7;
+ ret = gost_tlstree(NID_magma_mgm, kroot_magma_l, out, tlsseq, TLSTREE_MODE_L);
+ err = expect_eq("Gost TLSTREE - magma", ret, out, tlstree_magma_l_etalon, 32);
+ if (err)
+ goto cleanup;
+
+cleanup:
+ cleanup_openssl(eng);
return err;
-}
+}
\ No newline at end of file
0xa7, 0x92, 0x80, 0x69, 0xaa, 0x10, 0xfd, 0x10
};
+const unsigned char mg_tlstree_key[32] = {
+ 0xEB, 0xD2, 0x71, 0xDE, 0x19, 0xFE, 0xE1, 0x8B,
+ 0xB1, 0x99, 0x8F, 0x69, 0xAF, 0x5B, 0x6A, 0xE1,
+ 0x89, 0x58, 0xE8, 0xD3, 0x70, 0x2F, 0x12, 0xFB,
+ 0xB5, 0xB0, 0x3F, 0x6F, 0xD6, 0x91, 0xFE, 0xFA
+};
+
+const unsigned char mg_tlstree_seqnum[8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+const unsigned char mg_tlstree_nonce[8] = {
+ 0x18, 0xFB, 0x03, 0x8D, 0xBF, 0x72, 0x41, 0xE6
+};
+
+const unsigned char mg_tlstree_adata[5] = {
+ 0x17, 0x03, 0x03, 0x00, 0x0B
+};
+
+const unsigned char mg_tlstree_pdata[3] = {
+ 0x01, 0x00, 0x15
+};
+
+const unsigned char mg_tlstree_e_cdata[3] = {
+ 0x46, 0x4A, 0xEE
+};
+
+const unsigned char mg_tlstree_e_tag[8] = {
+ 0xAD, 0x39, 0x1D, 0x97, 0x98, 0x71, 0x69, 0xF3
+};
static struct testcase {
const char *sn;
size_t ptext_len;
const unsigned char *expected;
const unsigned char *expected_tag;
+ const char *tlstree_mode;
+ const unsigned char *seqnum;
} testcases[] = {
{
.sn = SN_kuznyechik_mgm,
.plaintext = gh_pdata,
.ptext_len = sizeof(gh_pdata),
.expected = gh_e_cdata,
- .expected_tag = gh_e_tag
+ .expected_tag = gh_e_tag,
+ .tlstree_mode = NULL,
+ .seqnum = NULL
},
{
.sn = SN_magma_mgm,
.plaintext = mg_pdata,
.ptext_len = sizeof(mg_pdata),
.expected = mg_e_cdata,
- .expected_tag = mg_e_tag
+ .expected_tag = mg_e_tag,
+ .tlstree_mode = NULL,
+ .seqnum = NULL
+ },
+ {
+ .sn = SN_magma_mgm,
+ .key = mg_tlstree_key,
+ .nonce = mg_tlstree_nonce,
+ .nonce_len = sizeof(mg_tlstree_nonce),
+ .aad = mg_tlstree_adata,
+ .aad_len = sizeof(mg_tlstree_adata),
+ .plaintext = mg_tlstree_pdata,
+ .ptext_len = sizeof(mg_tlstree_pdata),
+ .expected = mg_tlstree_e_cdata,
+ .expected_tag = mg_tlstree_e_tag,
+ .tlstree_mode = "light",
+ .seqnum = mg_tlstree_seqnum
},
{ 0 }
};
static int test_block(const EVP_CIPHER *ciph, const char *name, const unsigned char *nonce, size_t nlen,
const unsigned char *aad, size_t alen, const unsigned char *ptext, size_t plen,
const unsigned char *exp_ctext, const unsigned char *exp_tag,
- const unsigned char * key, int small)
+ const unsigned char *key, const char *tlstree_mode,
+ const unsigned char *seqnum, int small)
{
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
unsigned char *c = alloca(plen);
EVP_EncryptInit_ex(ctx, ciph, NULL, NULL, NULL); // Set cipher type and mode
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, nlen, NULL); // Set IV length
EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce); // Initialise key and IV
+
+ if (seqnum && tlstree_mode) {
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_TLSTREE_PARAMS, 0, (void *)tlstree_mode);
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_TLSTREE, 0, (void *)seqnum);
+ }
+
memset(c, 0, plen);
if (!small) {
// test big chunks
EVP_DecryptInit_ex(ctx, ciph, NULL, NULL, NULL);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, nlen, NULL);
EVP_DecryptInit_ex(ctx, NULL, NULL, key, nonce);
+
+ if (seqnum && tlstree_mode) {
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_TLSTREE_PARAMS, 0, (void *)tlstree_mode);
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_TLSTREE, 0, (void *)seqnum);
+ }
+
memset(c, 0, plen);
if (!small) {
// test big chunks
for (small = 0; small <= 1; small++)
ret |= test_block(ciph, name, t->nonce, t->nonce_len,
t->aad, t->aad_len, t->plaintext, t->ptext_len,
- t->expected, t->expected_tag, t->key, small);
+ t->expected, t->expected_tag, t->key,
+ t->tlstree_mode, t->seqnum, small);
EVP_CIPHER_free(ciph_prov);
}
T(SSL_CTX_use_certificate(sctx, ck.cert));
T(SSL_CTX_use_PrivateKey(sctx, ck.pkey));
T(SSL_CTX_check_private_key(sctx));
+ T(SSL_CTX_set_min_proto_version(sctx, TLS1_2_VERSION));
+ T(SSL_CTX_set_max_proto_version(sctx, TLS1_2_VERSION));
T(cctx = SSL_CTX_new(TLS_client_method()));