mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-04 00:00:14 -04:00
Merge branch 'openssl-3.0'
This provides compatibility changes for OpenSSL 3.0.
This commit is contained in:
commit
9aa7e126b2
2
.github/workflows/linux.yml
vendored
2
.github/workflows/linux.yml
vendored
@ -87,7 +87,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
test: [ botan, wolfssl, openssl, gcrypt ]
|
||||
test: [ botan, wolfssl, openssl, openssl-3, gcrypt ]
|
||||
leak-detective: [ no, yes ]
|
||||
env:
|
||||
LEAK_DETECTIVE: ${{ matrix.leak-detective || 'no' }}
|
||||
|
@ -1480,7 +1480,6 @@ ADD_PLUGIN([acert], [s charon])
|
||||
ADD_PLUGIN([pubkey], [s charon pki cmd aikgen])
|
||||
ADD_PLUGIN([pkcs1], [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen fuzz])
|
||||
ADD_PLUGIN([pkcs7], [s charon scepclient pki scripts nm cmd])
|
||||
ADD_PLUGIN([pkcs8], [s charon scepclient pki scripts manager medsrv attest nm cmd])
|
||||
ADD_PLUGIN([pkcs12], [s charon scepclient pki scripts cmd])
|
||||
ADD_PLUGIN([pgp], [s charon])
|
||||
ADD_PLUGIN([dnskey], [s charon pki])
|
||||
@ -1493,6 +1492,7 @@ ADD_PLUGIN([openssl], [s charon scepclient pki scripts manager meds
|
||||
ADD_PLUGIN([wolfssl], [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
|
||||
ADD_PLUGIN([gcrypt], [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
|
||||
ADD_PLUGIN([botan], [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
|
||||
ADD_PLUGIN([pkcs8], [s charon scepclient pki scripts manager medsrv attest nm cmd])
|
||||
ADD_PLUGIN([af-alg], [s charon scepclient pki scripts medsrv attest nm cmd aikgen])
|
||||
ADD_PLUGIN([fips-prf], [s charon nm cmd])
|
||||
ADD_PLUGIN([gmp], [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen fuzz])
|
||||
|
@ -89,6 +89,46 @@ build_tss2()
|
||||
cd -
|
||||
}
|
||||
|
||||
build_openssl()
|
||||
{
|
||||
SSL_REV=3.0.2
|
||||
SSL_PKG=openssl-$SSL_REV
|
||||
SSL_DIR=$DEPS_BUILD_DIR/$SSL_PKG
|
||||
SSL_SRC=https://www.openssl.org/source/$SSL_PKG.tar.gz
|
||||
SSL_INS=$DEPS_PREFIX/ssl
|
||||
SSL_OPT="shared no-tls no-dtls no-ssl3 no-zlib no-comp no-idea no-psk no-srp
|
||||
no-stdio no-tests enable-rfc3779 enable-ec_nistp_64_gcc_128"
|
||||
|
||||
if test -d "$SSL_DIR"; then
|
||||
return
|
||||
fi
|
||||
|
||||
# insist on compiling with gcc and debug information as symbols are otherwise not found
|
||||
if test "$LEAK_DETECTIVE" = "yes"; then
|
||||
SSL_OPT="$SSL_OPT CC=gcc -d"
|
||||
fi
|
||||
|
||||
echo "$ build_openssl()"
|
||||
|
||||
curl -L $SSL_SRC | tar xz -C $DEPS_BUILD_DIR &&
|
||||
cd $SSL_DIR &&
|
||||
./config --prefix=$SSL_INS --openssldir=$SSL_INS --libdir=lib $SSL_OPT &&
|
||||
make -j4 >/dev/null &&
|
||||
sudo make install_sw >/dev/null &&
|
||||
sudo ldconfig || exit $?
|
||||
cd -
|
||||
}
|
||||
|
||||
use_custom_openssl()
|
||||
{
|
||||
CFLAGS="$CFLAGS -I$DEPS_PREFIX/ssl/include"
|
||||
export LDFLAGS="$LDFLAGS -L$DEPS_PREFIX/ssl/lib"
|
||||
export LD_LIBRARY_PATH="$DEPS_PREFIX/ssl/lib:$LD_LIBRARY_PATH"
|
||||
if test "$1" = "build-deps"; then
|
||||
build_openssl
|
||||
fi
|
||||
}
|
||||
|
||||
: ${BUILD_DIR=$PWD}
|
||||
: ${DEPS_BUILD_DIR=$BUILD_DIR/..}
|
||||
: ${DEPS_PREFIX=/usr/local}
|
||||
@ -114,6 +154,10 @@ openssl*)
|
||||
CONFIG="--disable-defaults --enable-pki --enable-openssl --enable-pem"
|
||||
export TESTS_PLUGINS="test-vectors pem openssl!"
|
||||
DEPS="libssl-dev"
|
||||
if test "$TEST" = "openssl-3"; then
|
||||
DEPS=""
|
||||
use_custom_openssl $1
|
||||
fi
|
||||
;;
|
||||
gcrypt)
|
||||
CONFIG="--disable-defaults --enable-pki --enable-gcrypt --enable-pkcs1 --enable-pkcs8"
|
||||
@ -184,6 +228,7 @@ all|coverage|sonarcloud)
|
||||
build_wolfssl
|
||||
build_tss2
|
||||
fi
|
||||
use_custom_openssl $1
|
||||
;;
|
||||
win*)
|
||||
CONFIG="--disable-defaults --enable-svc --enable-ikev2
|
||||
|
@ -19,6 +19,7 @@ libstrongswan_openssl_la_SOURCES = \
|
||||
openssl_plugin.h openssl_plugin.c \
|
||||
openssl_util.c openssl_util.h \
|
||||
openssl_crypter.c openssl_crypter.h \
|
||||
openssl_engine.c openssl_engine.h \
|
||||
openssl_hasher.c openssl_hasher.h \
|
||||
openssl_sha1_prf.c openssl_sha1_prf.h \
|
||||
openssl_diffie_hellman.c openssl_diffie_hellman.h \
|
||||
|
@ -15,8 +15,6 @@
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL
|
||||
|
||||
#include "openssl_aead.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
@ -363,5 +361,3 @@ aead_t *openssl_aead_create(encryption_algorithm_t algo,
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
@ -18,9 +18,15 @@
|
||||
|
||||
#ifndef OPENSSL_NO_DH
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
#include <openssl/param_build.h>
|
||||
#include <openssl/core_names.h>
|
||||
#endif
|
||||
|
||||
#include "openssl_diffie_hellman.h"
|
||||
#include "openssl_util.h"
|
||||
|
||||
@ -49,6 +55,17 @@ struct private_openssl_diffie_hellman_t {
|
||||
*/
|
||||
diffie_hellman_group_t group;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
/**
|
||||
* Diffie Hellman key
|
||||
*/
|
||||
EVP_PKEY *key;
|
||||
|
||||
/**
|
||||
* Other public value
|
||||
*/
|
||||
EVP_PKEY *pub;
|
||||
#else
|
||||
/**
|
||||
* Diffie Hellman object
|
||||
*/
|
||||
@ -58,21 +75,35 @@ struct private_openssl_diffie_hellman_t {
|
||||
* Other public value
|
||||
*/
|
||||
BIGNUM *pub_key;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Shared secret
|
||||
*/
|
||||
chunk_t shared_secret;
|
||||
|
||||
/**
|
||||
* True if shared secret is computed
|
||||
*/
|
||||
bool computed;
|
||||
};
|
||||
|
||||
METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
|
||||
private_openssl_diffie_hellman_t *this)
|
||||
{
|
||||
return this->group;
|
||||
}
|
||||
|
||||
METHOD(diffie_hellman_t, get_my_public_value, bool,
|
||||
private_openssl_diffie_hellman_t *this, chunk_t *value)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
chunk_t pub;
|
||||
|
||||
pub.len = EVP_PKEY_get1_encoded_public_key(this->key, &pub.ptr);
|
||||
if (pub.len != 0)
|
||||
{
|
||||
*value = chunk_clone(pub);
|
||||
OPENSSL_free(pub.ptr);
|
||||
return value->len != 0;
|
||||
}
|
||||
return FALSE;
|
||||
#else
|
||||
const BIGNUM *pubkey;
|
||||
|
||||
*value = chunk_alloc(DH_size(this->dh));
|
||||
@ -80,49 +111,148 @@ METHOD(diffie_hellman_t, get_my_public_value, bool,
|
||||
DH_get0_key(this->dh, &pubkey, NULL);
|
||||
BN_bn2bin(pubkey, value->ptr + value->len - BN_num_bytes(pubkey));
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
METHOD(diffie_hellman_t, get_shared_secret, bool,
|
||||
private_openssl_diffie_hellman_t *this, chunk_t *secret)
|
||||
{
|
||||
if (!this->computed)
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
if (!this->shared_secret.len &&
|
||||
!openssl_compute_shared_key(this->key, this->pub, &this->shared_secret))
|
||||
{
|
||||
DBG1(DBG_LIB, "DH shared secret computation failed");
|
||||
return FALSE;
|
||||
}
|
||||
/* shared secret should requires a len according the DH group */
|
||||
*secret = chunk_alloc(DH_size(this->dh));
|
||||
memset(secret->ptr, 0, secret->len);
|
||||
memcpy(secret->ptr + secret->len - this->shared_secret.len,
|
||||
this->shared_secret.ptr, this->shared_secret.len);
|
||||
*secret = chunk_clone(this->shared_secret);
|
||||
return TRUE;
|
||||
#else
|
||||
int len;
|
||||
|
||||
if (!this->shared_secret.len)
|
||||
{
|
||||
this->shared_secret = chunk_alloc(DH_size(this->dh));
|
||||
memset(this->shared_secret.ptr, 0xFF, this->shared_secret.len);
|
||||
len = DH_compute_key(this->shared_secret.ptr, this->pub_key, this->dh);
|
||||
if (len < 0)
|
||||
{
|
||||
DBG1(DBG_LIB, "DH shared secret computation failed");
|
||||
chunk_clear(&this->shared_secret);
|
||||
return FALSE;
|
||||
}
|
||||
this->shared_secret.len = len;
|
||||
}
|
||||
/* shared secret requires a length according to the DH group */
|
||||
*secret = chunk_copy_pad(chunk_alloc(DH_size(this->dh)),
|
||||
this->shared_secret, 0);
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
METHOD(diffie_hellman_t, set_other_public_value, bool,
|
||||
private_openssl_diffie_hellman_t *this, chunk_t value)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (!diffie_hellman_verify_value(this->group, value))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BN_bin2bn(value.ptr, value.len, this->pub_key);
|
||||
chunk_clear(&this->shared_secret);
|
||||
this->shared_secret.ptr = malloc(DH_size(this->dh));
|
||||
memset(this->shared_secret.ptr, 0xFF, this->shared_secret.len);
|
||||
len = DH_compute_key(this->shared_secret.ptr, this->pub_key, this->dh);
|
||||
if (len < 0)
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
if (!this->pub)
|
||||
{
|
||||
DBG1(DBG_LIB, "DH shared secret computation failed");
|
||||
this->pub = EVP_PKEY_new();
|
||||
}
|
||||
if (EVP_PKEY_copy_parameters(this->pub, this->key) <= 0 ||
|
||||
EVP_PKEY_set1_encoded_public_key(this->pub, value.ptr, value.len) <= 0)
|
||||
{
|
||||
DBG1(DBG_LIB, "DH public value is malformed");
|
||||
return FALSE;
|
||||
}
|
||||
this->shared_secret.len = len;
|
||||
this->computed = TRUE;
|
||||
#else
|
||||
if (!BN_bin2bn(value.ptr, value.len, this->pub_key))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
chunk_clear(&this->shared_secret);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
|
||||
/**
|
||||
* Calculate the public key for the given private key and DH parameters.
|
||||
* Setting only the private key and generating the public key interanlly is
|
||||
* not supported anymore with OpenSSL 3.0.0.
|
||||
*/
|
||||
static BIGNUM *calculate_public_key(BIGNUM *priv, const BIGNUM *g,
|
||||
const BIGNUM *p)
|
||||
{
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BIGNUM *pub = BN_new();
|
||||
|
||||
BN_set_flags(priv, BN_FLG_CONSTTIME);
|
||||
/* pub = g^priv mod p */
|
||||
if (!ctx || ! pub || !BN_mod_exp(pub, g, priv, p, ctx))
|
||||
{
|
||||
BN_free(pub);
|
||||
pub = NULL;
|
||||
}
|
||||
BN_CTX_free(ctx);
|
||||
return pub;
|
||||
}
|
||||
|
||||
METHOD(diffie_hellman_t, set_private_value, bool,
|
||||
private_openssl_diffie_hellman_t *this, chunk_t value)
|
||||
{
|
||||
BIGNUM *priv, *g = NULL, *p = NULL, *pub = NULL;
|
||||
OSSL_PARAM_BLD *bld = NULL;
|
||||
OSSL_PARAM *params = NULL;
|
||||
EVP_PKEY *key = NULL;
|
||||
EVP_PKEY_CTX *ctx = NULL;
|
||||
bool ret = FALSE;
|
||||
|
||||
priv = BN_bin2bn(value.ptr, value.len, NULL);
|
||||
if (EVP_PKEY_get_bn_param(this->key, OSSL_PKEY_PARAM_FFC_G, &g) <= 0 ||
|
||||
EVP_PKEY_get_bn_param(this->key, OSSL_PKEY_PARAM_FFC_P, &p) <= 0)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
pub = calculate_public_key(priv, g, p);
|
||||
bld = OSSL_PARAM_BLD_new();
|
||||
if (pub && bld &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, priv) &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY, pub))
|
||||
{
|
||||
params = OSSL_PARAM_BLD_to_param(bld);
|
||||
}
|
||||
ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL);
|
||||
if (!params || !ctx ||
|
||||
EVP_PKEY_fromdata_init(ctx) <= 0 ||
|
||||
EVP_PKEY_fromdata(ctx, &key, EVP_PKEY_KEYPAIR, params) <= 0)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
EVP_PKEY_free(this->key);
|
||||
this->key = key;
|
||||
ret = TRUE;
|
||||
|
||||
error:
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OSSL_PARAM_free(params);
|
||||
OSSL_PARAM_BLD_free(bld);
|
||||
BN_free(pub);
|
||||
BN_free(p);
|
||||
BN_free(g);
|
||||
BN_free(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
METHOD(diffie_hellman_t, set_private_value, bool,
|
||||
private_openssl_diffie_hellman_t *this, chunk_t value)
|
||||
{
|
||||
@ -136,56 +266,23 @@ METHOD(diffie_hellman_t, set_private_value, bool,
|
||||
return FALSE;
|
||||
}
|
||||
chunk_clear(&this->shared_secret);
|
||||
this->computed = FALSE;
|
||||
return DH_generate_key(this->dh);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
|
||||
private_openssl_diffie_hellman_t *this)
|
||||
{
|
||||
return this->group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the modulus in modulo table
|
||||
*/
|
||||
static status_t set_modulus(private_openssl_diffie_hellman_t *this)
|
||||
{
|
||||
BIGNUM *p, *g;
|
||||
|
||||
diffie_hellman_params_t *params = diffie_hellman_get_params(this->group);
|
||||
if (!params)
|
||||
{
|
||||
return NOT_FOUND;
|
||||
}
|
||||
p = BN_bin2bn(params->prime.ptr, params->prime.len, NULL);
|
||||
g = BN_bin2bn(params->generator.ptr, params->generator.len, NULL);
|
||||
if (!DH_set0_pqg(this->dh, p, NULL, g))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
if (params->exp_len != params->prime.len)
|
||||
{
|
||||
#if defined(OPENSSL_IS_BORINGSSL) && \
|
||||
(!defined(BORINGSSL_API_VERSION) || BORINGSSL_API_VERSION < 11)
|
||||
this->dh->priv_length = params->exp_len * 8;
|
||||
#else
|
||||
if (!DH_set_length(this->dh, params->exp_len * 8))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
METHOD(diffie_hellman_t, destroy, void,
|
||||
private_openssl_diffie_hellman_t *this)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
EVP_PKEY_free(this->key);
|
||||
EVP_PKEY_free(this->pub);
|
||||
#else
|
||||
BN_clear_free(this->pub_key);
|
||||
DH_free(this->dh);
|
||||
#endif
|
||||
chunk_clear(&this->shared_secret);
|
||||
free(this);
|
||||
}
|
||||
@ -197,7 +294,8 @@ openssl_diffie_hellman_t *openssl_diffie_hellman_create(
|
||||
diffie_hellman_group_t group, ...)
|
||||
{
|
||||
private_openssl_diffie_hellman_t *this;
|
||||
const BIGNUM *privkey;
|
||||
BIGNUM *g, *p;
|
||||
int priv_len = 0;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
@ -210,50 +308,105 @@ openssl_diffie_hellman_t *openssl_diffie_hellman_create(
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.group = group,
|
||||
);
|
||||
|
||||
this->dh = DH_new();
|
||||
if (!this->dh)
|
||||
{
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this->group = group;
|
||||
this->computed = FALSE;
|
||||
this->pub_key = BN_new();
|
||||
this->shared_secret = chunk_empty;
|
||||
|
||||
if (group == MODP_CUSTOM)
|
||||
{
|
||||
chunk_t g, p;
|
||||
chunk_t g_chunk, p_chunk;
|
||||
|
||||
VA_ARGS_GET(group, g, p);
|
||||
if (!DH_set0_pqg(this->dh, BN_bin2bn(p.ptr, p.len, NULL), NULL,
|
||||
BN_bin2bn(g.ptr, g.len, NULL)))
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
VA_ARGS_GET(group, g_chunk, p_chunk);
|
||||
g = BN_bin2bn(g_chunk.ptr, g_chunk.len, NULL);
|
||||
p = BN_bin2bn(p_chunk.ptr, p_chunk.len, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* find a modulus according to group */
|
||||
if (set_modulus(this) != SUCCESS)
|
||||
diffie_hellman_params_t *params = diffie_hellman_get_params(group);
|
||||
if (!params)
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
g = BN_bin2bn(params->generator.ptr, params->generator.len, NULL);
|
||||
p = BN_bin2bn(params->prime.ptr, params->prime.len, NULL);
|
||||
if (params->exp_len != params->prime.len)
|
||||
{
|
||||
priv_len = params->exp_len * 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* generate my public and private values */
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
OSSL_PARAM_BLD *bld;
|
||||
OSSL_PARAM *params = NULL;
|
||||
EVP_PKEY_CTX *ctx;
|
||||
|
||||
/* if we abandoned MODP_CUSTOM, we could set OSSL_PKEY_PARAM_GROUP_NAME,
|
||||
* which wouldn't require the first ctx/key for the parameters */
|
||||
bld = OSSL_PARAM_BLD_new();
|
||||
if (bld &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) &&
|
||||
(!priv_len ||
|
||||
OSSL_PARAM_BLD_push_int(bld, OSSL_PKEY_PARAM_DH_PRIV_LEN, priv_len)))
|
||||
{
|
||||
params = OSSL_PARAM_BLD_to_param(bld);
|
||||
}
|
||||
OSSL_PARAM_BLD_free(bld);
|
||||
BN_free(g);
|
||||
BN_free(p);
|
||||
|
||||
ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL);
|
||||
if (!params || !ctx ||
|
||||
EVP_PKEY_fromdata_init(ctx) <= 0 ||
|
||||
EVP_PKEY_fromdata(ctx, &this->key, EVP_PKEY_KEY_PARAMETERS, params) <= 0)
|
||||
{
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OSSL_PARAM_free(params);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
OSSL_PARAM_free(params);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
|
||||
ctx = EVP_PKEY_CTX_new(this->key, NULL);
|
||||
if (!ctx ||
|
||||
EVP_PKEY_keygen_init(ctx) <= 0 ||
|
||||
EVP_PKEY_generate(ctx, &this->key) <= 0)
|
||||
{
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
#else /* OPENSSL_VERSION_NUMBER */
|
||||
this->dh = DH_new();
|
||||
this->pub_key = BN_new();
|
||||
if (!DH_set0_pqg(this->dh, p, NULL, g))
|
||||
{
|
||||
BN_free(g);
|
||||
BN_free(p);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
if (priv_len)
|
||||
{
|
||||
#if defined(OPENSSL_IS_BORINGSSL) && \
|
||||
(!defined(BORINGSSL_API_VERSION) || BORINGSSL_API_VERSION < 11)
|
||||
this->dh->priv_length = priv_len;
|
||||
#else
|
||||
if (!DH_set_length(this->dh, priv_len))
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (!DH_generate_key(this->dh))
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
DH_get0_key(this->dh, NULL, &privkey);
|
||||
DBG2(DBG_LIB, "size of DH secret exponent: %d bits", BN_num_bits(privkey));
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,15 @@
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x1010000fL
|
||||
#include <openssl/bn.h>
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/param_build.h>
|
||||
#include <openssl/core_names.h>
|
||||
#endif
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
#define EVP_PKEY_set1_encoded_public_key EVP_PKEY_set1_tls_encodedpoint
|
||||
#define EVP_PKEY_get1_encoded_public_key EVP_PKEY_get1_tls_encodedpoint
|
||||
#endif
|
||||
|
||||
#include "openssl_ec_diffie_hellman.h"
|
||||
@ -51,6 +60,11 @@ struct private_openssl_ec_diffie_hellman_t {
|
||||
*/
|
||||
EVP_PKEY *key;
|
||||
|
||||
/**
|
||||
* Public key provided by peer
|
||||
*/
|
||||
EVP_PKEY *pub;
|
||||
|
||||
/**
|
||||
* EC group
|
||||
*/
|
||||
@ -186,50 +200,35 @@ error:
|
||||
METHOD(diffie_hellman_t, set_other_public_value, bool,
|
||||
private_openssl_ec_diffie_hellman_t *this, chunk_t value)
|
||||
{
|
||||
EVP_PKEY *pub = NULL;
|
||||
|
||||
chunk_clear(&this->shared_secret);
|
||||
this->computed = FALSE;
|
||||
|
||||
if (!diffie_hellman_verify_value(this->group, value))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pub = EVP_PKEY_new();
|
||||
if (!pub)
|
||||
if (!this->pub)
|
||||
{
|
||||
goto error;
|
||||
this->pub = EVP_PKEY_new();
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x1010000fL
|
||||
if (!chunk2ecp(this->ec_group, value, pub))
|
||||
if (!chunk2ecp(this->ec_group, value, this->pub))
|
||||
{
|
||||
DBG1(DBG_LIB, "ECDH public value is malformed");
|
||||
goto error;
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
/* OpenSSL expects the pubkey in the format specified in section 2.3.4 of
|
||||
* SECG SEC 1, i.e. prefixed with 0x04 to indicate an uncompressed point */
|
||||
value = chunk_cata("cc", chunk_from_chars(0x04), value);
|
||||
if (EVP_PKEY_copy_parameters(pub, this->key) <= 0 ||
|
||||
EVP_PKEY_set1_tls_encodedpoint(pub, value.ptr, value.len) <= 0)
|
||||
if (EVP_PKEY_copy_parameters(this->pub, this->key) <= 0 ||
|
||||
EVP_PKEY_set1_encoded_public_key(this->pub, value.ptr, value.len) <= 0)
|
||||
{
|
||||
DBG1(DBG_LIB, "ECDH public value is malformed");
|
||||
goto error;
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!openssl_compute_shared_key(this->key, pub, &this->shared_secret))
|
||||
{
|
||||
DBG1(DBG_LIB, "ECDH shared secret computation failed");
|
||||
goto error;
|
||||
}
|
||||
this->computed = TRUE;
|
||||
|
||||
error:
|
||||
EVP_PKEY_free(pub);
|
||||
return this->computed;
|
||||
chunk_clear(&this->shared_secret);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(diffie_hellman_t, get_my_public_value, bool,
|
||||
@ -242,7 +241,7 @@ METHOD(diffie_hellman_t, get_my_public_value, bool,
|
||||
|
||||
/* OpenSSL returns the pubkey in the format specified in section 2.3.4 of
|
||||
* SECG SEC 1, i.e. prefixed with 0x04 to indicate an uncompressed point */
|
||||
pub.len = EVP_PKEY_get1_tls_encodedpoint(this->key, &pub.ptr);
|
||||
pub.len = EVP_PKEY_get1_encoded_public_key(this->key, &pub.ptr);
|
||||
if (pub.len != 0)
|
||||
{
|
||||
*value = chunk_clone(chunk_skip(pub, 1));
|
||||
@ -253,59 +252,13 @@ METHOD(diffie_hellman_t, get_my_public_value, bool,
|
||||
#endif
|
||||
}
|
||||
|
||||
METHOD(diffie_hellman_t, set_private_value, bool,
|
||||
private_openssl_ec_diffie_hellman_t *this, chunk_t value)
|
||||
{
|
||||
EC_KEY *key = NULL;
|
||||
EC_POINT *pub = NULL;
|
||||
BIGNUM *priv = NULL;
|
||||
bool ret = FALSE;
|
||||
|
||||
priv = BN_bin2bn(value.ptr, value.len, NULL);
|
||||
if (!priv)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
pub = EC_POINT_new(this->ec_group);
|
||||
if (!pub)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (EC_POINT_mul(this->ec_group, pub, priv, NULL, NULL, NULL) != 1)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
key = EC_KEY_new();
|
||||
if (!key || !EC_KEY_set_group(key, this->ec_group))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (EC_KEY_set_private_key(key, priv) != 1)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (EC_KEY_set_public_key(key, pub) != 1)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (EVP_PKEY_set1_EC_KEY(this->key, key) != 1)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
ret = TRUE;
|
||||
|
||||
error:
|
||||
EC_POINT_free(pub);
|
||||
BN_free(priv);
|
||||
EC_KEY_free(key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
METHOD(diffie_hellman_t, get_shared_secret, bool,
|
||||
private_openssl_ec_diffie_hellman_t *this, chunk_t *secret)
|
||||
{
|
||||
if (!this->computed)
|
||||
if (!this->shared_secret.len &&
|
||||
!openssl_compute_shared_key(this->key, this->pub, &this->shared_secret))
|
||||
{
|
||||
DBG1(DBG_LIB, "ECDH shared secret computation failed");
|
||||
return FALSE;
|
||||
}
|
||||
*secret = chunk_clone(this->shared_secret);
|
||||
@ -318,15 +271,6 @@ METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
|
||||
return this->group;
|
||||
}
|
||||
|
||||
METHOD(diffie_hellman_t, destroy, void,
|
||||
private_openssl_ec_diffie_hellman_t *this)
|
||||
{
|
||||
EC_GROUP_free(this->ec_group);
|
||||
EVP_PKEY_free(this->key);
|
||||
chunk_clear(&this->shared_secret);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
@ -360,21 +304,151 @@ int openssl_ecdh_group_to_nid(diffie_hellman_group_t group)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given private key as BIGNUM and calculate the corresponding public
|
||||
* key as EC_POINT.
|
||||
*/
|
||||
static bool get_keypair(EC_GROUP *group, chunk_t value, BIGNUM **priv,
|
||||
EC_POINT **pub)
|
||||
{
|
||||
*priv = BN_bin2bn(value.ptr, value.len, NULL);
|
||||
*pub = EC_POINT_new(group);
|
||||
return *priv && *pub &&
|
||||
EC_POINT_mul(group, *pub, *priv, NULL, NULL, NULL) == 1;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
|
||||
/**
|
||||
* Convert the given EC_POINT to a chunk.
|
||||
*/
|
||||
static bool ecp2chunk(EC_GROUP *group, EC_POINT *point, chunk_t *chunk)
|
||||
{
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
|
||||
if (ctx)
|
||||
{
|
||||
chunk->len = EC_POINT_point2buf(group, point,
|
||||
POINT_CONVERSION_UNCOMPRESSED,
|
||||
&chunk->ptr, ctx);
|
||||
}
|
||||
BN_CTX_free(ctx);
|
||||
return chunk->len;
|
||||
}
|
||||
|
||||
METHOD(diffie_hellman_t, set_private_value, bool,
|
||||
private_openssl_ec_diffie_hellman_t *this, chunk_t value)
|
||||
{
|
||||
BIGNUM *priv = NULL;
|
||||
EC_POINT *pub = NULL;
|
||||
chunk_t pub_chunk = chunk_empty;
|
||||
const char *name;
|
||||
OSSL_PARAM_BLD *bld;
|
||||
OSSL_PARAM *params = NULL;
|
||||
EVP_PKEY_CTX *ctx;
|
||||
EVP_PKEY *key = NULL;
|
||||
bool ret = FALSE;
|
||||
|
||||
if (!get_keypair(this->ec_group, value, &priv, &pub) ||
|
||||
!ecp2chunk(this->ec_group, pub, &pub_chunk))
|
||||
{
|
||||
EC_POINT_free(pub);
|
||||
BN_free(priv);
|
||||
return FALSE;
|
||||
}
|
||||
EC_POINT_free(pub);
|
||||
|
||||
name = OSSL_EC_curve_nid2name(openssl_ecdh_group_to_nid(this->group));
|
||||
bld = OSSL_PARAM_BLD_new();
|
||||
if (name && bld &&
|
||||
OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME,
|
||||
(char*)name, 0) &&
|
||||
OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY,
|
||||
pub_chunk.ptr, pub_chunk.len) &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, priv))
|
||||
{
|
||||
params = OSSL_PARAM_BLD_to_param(bld);
|
||||
}
|
||||
OSSL_PARAM_BLD_free(bld);
|
||||
chunk_free(&pub_chunk);
|
||||
BN_free(priv);
|
||||
|
||||
ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
|
||||
if (params && ctx &&
|
||||
EVP_PKEY_fromdata_init(ctx) > 0 &&
|
||||
EVP_PKEY_fromdata(ctx, &key, EVP_PKEY_KEYPAIR, params) > 0)
|
||||
{
|
||||
EVP_PKEY_free(this->key);
|
||||
this->key = key;
|
||||
ret = TRUE;
|
||||
}
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OSSL_PARAM_free(params);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
METHOD(diffie_hellman_t, set_private_value, bool,
|
||||
private_openssl_ec_diffie_hellman_t *this, chunk_t value)
|
||||
{
|
||||
EC_KEY *key = NULL;
|
||||
EC_POINT *pub = NULL;
|
||||
BIGNUM *priv = NULL;
|
||||
bool ret = FALSE;
|
||||
|
||||
if (!get_keypair(this->ec_group, value, &priv, &pub))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
key = EC_KEY_new();
|
||||
if (!key || !EC_KEY_set_group(key, this->ec_group))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (EC_KEY_set_private_key(key, priv) != 1)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (EC_KEY_set_public_key(key, pub) != 1)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (EVP_PKEY_set1_EC_KEY(this->key, key) != 1)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
ret = TRUE;
|
||||
|
||||
error:
|
||||
EC_POINT_free(pub);
|
||||
BN_free(priv);
|
||||
EC_KEY_free(key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
METHOD(diffie_hellman_t, destroy, void,
|
||||
private_openssl_ec_diffie_hellman_t *this)
|
||||
{
|
||||
EC_GROUP_free(this->ec_group);
|
||||
EVP_PKEY_free(this->key);
|
||||
EVP_PKEY_free(this->pub);
|
||||
chunk_clear(&this->shared_secret);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
openssl_ec_diffie_hellman_t *openssl_ec_diffie_hellman_create(diffie_hellman_group_t group)
|
||||
{
|
||||
private_openssl_ec_diffie_hellman_t *this;
|
||||
EC_KEY *key = NULL;
|
||||
int curve;
|
||||
|
||||
curve = openssl_ecdh_group_to_nid(group);
|
||||
if (curve)
|
||||
{
|
||||
key = EC_KEY_new_by_curve_name(curve);
|
||||
}
|
||||
if (!key)
|
||||
if (!curve)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -391,17 +465,25 @@ openssl_ec_diffie_hellman_t *openssl_ec_diffie_hellman_create(diffie_hellman_gro
|
||||
},
|
||||
},
|
||||
.group = group,
|
||||
.ec_group = EC_GROUP_dup(EC_KEY_get0_group(key)),
|
||||
);
|
||||
|
||||
/* generate an EC private (public) key */
|
||||
if (!EC_KEY_generate_key(key))
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
this->ec_group = EC_GROUP_new_by_curve_name(curve);
|
||||
this->key = EVP_EC_gen(OSSL_EC_curve_nid2name(curve));
|
||||
if (!this->key)
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
EC_KEY *key = EC_KEY_new_by_curve_name(curve);
|
||||
if (!key || !EC_KEY_generate_key(key))
|
||||
{
|
||||
EC_KEY_free(key);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this->ec_group = EC_GROUP_dup(EC_KEY_get0_group(key));
|
||||
this->key = EVP_PKEY_new();
|
||||
if (!this->key || !EVP_PKEY_assign_EC_KEY(this->key, key))
|
||||
{
|
||||
@ -409,6 +491,8 @@ openssl_ec_diffie_hellman_t *openssl_ec_diffie_hellman_create(diffie_hellman_gro
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ struct private_openssl_ec_private_key_t {
|
||||
/**
|
||||
* EC key object
|
||||
*/
|
||||
EC_KEY *ec;
|
||||
EVP_PKEY *key;
|
||||
|
||||
/**
|
||||
* TRUE if the key is from an OpenSSL ENGINE and might not be readable
|
||||
@ -59,25 +59,78 @@ struct private_openssl_ec_private_key_t {
|
||||
refcount_t ref;
|
||||
};
|
||||
|
||||
/* from ec public key */
|
||||
bool openssl_ec_fingerprint(EC_KEY *ec, cred_encoding_type_t type, chunk_t *fp);
|
||||
/* from openssl_ec_public_key */
|
||||
bool openssl_check_ec_key_curve(EVP_PKEY *key, int nid_curve);
|
||||
|
||||
/**
|
||||
* Build a DER encoded signature as in RFC 3279
|
||||
*/
|
||||
static bool build_der_signature(private_openssl_ec_private_key_t *this,
|
||||
int nid_hash, chunk_t data, chunk_t *signature)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
const EVP_MD *md;
|
||||
|
||||
md = EVP_get_digestbynid(nid_hash);
|
||||
if (!md)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
*signature = chunk_alloc(EVP_PKEY_size(this->key));
|
||||
ctx = EVP_MD_CTX_create();
|
||||
if (!ctx ||
|
||||
EVP_DigestSignInit(ctx, NULL, md, NULL, this->key) <= 0 ||
|
||||
EVP_DigestSignUpdate(ctx, data.ptr, data.len) <= 0 ||
|
||||
EVP_DigestSignFinal(ctx, signature->ptr, &signature->len) != 1)
|
||||
{
|
||||
chunk_free(signature);
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
return FALSE;
|
||||
}
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a signature as in RFC 4754
|
||||
*/
|
||||
static bool build_signature(private_openssl_ec_private_key_t *this,
|
||||
chunk_t hash, chunk_t *signature)
|
||||
int nid_hash, chunk_t data, chunk_t *signature)
|
||||
{
|
||||
const BIGNUM *r, *s;
|
||||
EVP_PKEY_CTX *ctx;
|
||||
ECDSA_SIG *sig;
|
||||
const BIGNUM *r, *s;
|
||||
const u_char *p;
|
||||
chunk_t der_sig;
|
||||
bool built = FALSE;
|
||||
|
||||
sig = ECDSA_do_sign(hash.ptr, hash.len, this->ec);
|
||||
if (!nid_hash)
|
||||
{ /* EVP_DigestSign*() has issues with NULL EVP_MD */
|
||||
der_sig = chunk_alloc(EVP_PKEY_size(this->key));
|
||||
ctx = EVP_PKEY_CTX_new(this->key, NULL);
|
||||
if (!ctx ||
|
||||
EVP_PKEY_sign_init(ctx) <= 0 ||
|
||||
EVP_PKEY_sign(ctx, der_sig.ptr, &der_sig.len, data.ptr, data.len) <= 0)
|
||||
{
|
||||
chunk_free(&der_sig);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return FALSE;
|
||||
}
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
}
|
||||
else if (!build_der_signature(this, nid_hash, data, &der_sig))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
/* extract r and s from the DER-encoded signature */
|
||||
p = der_sig.ptr;
|
||||
sig = d2i_ECDSA_SIG(NULL, &p, der_sig.len);
|
||||
chunk_free(&der_sig);
|
||||
if (sig)
|
||||
{
|
||||
ECDSA_SIG_get0(sig, &r, &s);
|
||||
/* concatenate BNs r/s to a signature chunk */
|
||||
built = openssl_bn_cat(EC_FIELD_ELEMENT_LEN(EC_KEY_get0_group(this->ec)),
|
||||
built = openssl_bn_cat((EVP_PKEY_bits(this->key) + 7) / 8,
|
||||
r, s, signature);
|
||||
ECDSA_SIG_free(sig);
|
||||
}
|
||||
@ -91,62 +144,13 @@ static bool build_curve_signature(private_openssl_ec_private_key_t *this,
|
||||
signature_scheme_t scheme, int nid_hash,
|
||||
int nid_curve, chunk_t data, chunk_t *signature)
|
||||
{
|
||||
const EC_GROUP *my_group;
|
||||
EC_GROUP *req_group;
|
||||
chunk_t hash;
|
||||
bool built;
|
||||
|
||||
req_group = EC_GROUP_new_by_curve_name(nid_curve);
|
||||
if (!req_group)
|
||||
if (!openssl_check_ec_key_curve(this->key, nid_curve))
|
||||
{
|
||||
DBG1(DBG_LIB, "signature scheme %N not supported in EC (required curve "
|
||||
"not supported)", signature_scheme_names, scheme);
|
||||
return FALSE;
|
||||
}
|
||||
my_group = EC_KEY_get0_group(this->ec);
|
||||
if (EC_GROUP_cmp(my_group, req_group, NULL) != 0)
|
||||
{
|
||||
DBG1(DBG_LIB, "signature scheme %N not supported by private key",
|
||||
DBG1(DBG_LIB, "signature scheme %N not supported by key",
|
||||
signature_scheme_names, scheme);
|
||||
return FALSE;
|
||||
}
|
||||
EC_GROUP_free(req_group);
|
||||
if (!openssl_hash_chunk(nid_hash, data, &hash))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
built = build_signature(this, hash, signature);
|
||||
chunk_free(&hash);
|
||||
return built;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a DER encoded signature as in RFC 3279
|
||||
*/
|
||||
static bool build_der_signature(private_openssl_ec_private_key_t *this,
|
||||
int hash_nid, chunk_t data, chunk_t *signature)
|
||||
{
|
||||
chunk_t hash, sig;
|
||||
int siglen = 0;
|
||||
bool built;
|
||||
|
||||
if (!openssl_hash_chunk(hash_nid, data, &hash))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
sig = chunk_alloc(ECDSA_size(this->ec));
|
||||
built = ECDSA_sign(0, hash.ptr, hash.len, sig.ptr, &siglen, this->ec) == 1;
|
||||
sig.len = siglen;
|
||||
if (built)
|
||||
{
|
||||
*signature = sig;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(sig.ptr);
|
||||
}
|
||||
free(hash.ptr);
|
||||
return built;
|
||||
return build_signature(this, nid_hash, data, signature);
|
||||
}
|
||||
|
||||
METHOD(private_key_t, sign, bool,
|
||||
@ -156,7 +160,7 @@ METHOD(private_key_t, sign, bool,
|
||||
switch (scheme)
|
||||
{
|
||||
case SIGN_ECDSA_WITH_NULL:
|
||||
return build_signature(this, data, signature);
|
||||
return build_signature(this, 0, data, signature);
|
||||
case SIGN_ECDSA_WITH_SHA1_DER:
|
||||
return build_der_signature(this, NID_sha1, data, signature);
|
||||
case SIGN_ECDSA_WITH_SHA256_DER:
|
||||
@ -192,7 +196,7 @@ METHOD(private_key_t, decrypt, bool,
|
||||
METHOD(private_key_t, get_keysize, int,
|
||||
private_openssl_ec_private_key_t *this)
|
||||
{
|
||||
return EC_GROUP_get_degree(EC_KEY_get0_group(this->ec));
|
||||
return EVP_PKEY_bits(this->key);
|
||||
}
|
||||
|
||||
METHOD(private_key_t, get_type, key_type_t,
|
||||
@ -206,12 +210,8 @@ METHOD(private_key_t, get_public_key, public_key_t*,
|
||||
{
|
||||
public_key_t *public;
|
||||
chunk_t key;
|
||||
u_char *p;
|
||||
|
||||
key = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL));
|
||||
p = key.ptr;
|
||||
i2d_EC_PUBKEY(this->ec, &p);
|
||||
|
||||
key = openssl_i2chunk(PUBKEY, this->key);
|
||||
public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA,
|
||||
BUILD_BLOB_ASN1_DER, key, BUILD_END);
|
||||
free(key.ptr);
|
||||
@ -222,20 +222,17 @@ METHOD(private_key_t, get_fingerprint, bool,
|
||||
private_openssl_ec_private_key_t *this, cred_encoding_type_t type,
|
||||
chunk_t *fingerprint)
|
||||
{
|
||||
return openssl_ec_fingerprint(this->ec, type, fingerprint);
|
||||
return openssl_fingerprint(this->key, type, fingerprint);
|
||||
}
|
||||
|
||||
METHOD(private_key_t, get_encoding, bool,
|
||||
private_openssl_ec_private_key_t *this, cred_encoding_type_t type,
|
||||
chunk_t *encoding)
|
||||
{
|
||||
u_char *p;
|
||||
|
||||
if (this->engine)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case PRIVKEY_ASN1_DER:
|
||||
@ -243,9 +240,7 @@ METHOD(private_key_t, get_encoding, bool,
|
||||
{
|
||||
bool success = TRUE;
|
||||
|
||||
*encoding = chunk_alloc(i2d_ECPrivateKey(this->ec, NULL));
|
||||
p = encoding->ptr;
|
||||
i2d_ECPrivateKey(this->ec, &p);
|
||||
*encoding = openssl_i2chunk(PrivateKey, this->key);
|
||||
|
||||
if (type == PRIVKEY_PEM)
|
||||
{
|
||||
@ -275,10 +270,10 @@ METHOD(private_key_t, destroy, void,
|
||||
{
|
||||
if (ref_put(&this->ref))
|
||||
{
|
||||
if (this->ec)
|
||||
if (this->key)
|
||||
{
|
||||
lib->encoding->clear_cache(lib->encoding, this->ec);
|
||||
EC_KEY_free(this->ec);
|
||||
lib->encoding->clear_cache(lib->encoding, this->key);
|
||||
EVP_PKEY_free(this->key);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
@ -287,7 +282,7 @@ METHOD(private_key_t, destroy, void,
|
||||
/**
|
||||
* Internal generic constructor
|
||||
*/
|
||||
static private_openssl_ec_private_key_t *create_empty(void)
|
||||
static private_openssl_ec_private_key_t *create_internal(EVP_PKEY *key)
|
||||
{
|
||||
private_openssl_ec_private_key_t *this;
|
||||
|
||||
@ -309,6 +304,7 @@ static private_openssl_ec_private_key_t *create_empty(void)
|
||||
},
|
||||
},
|
||||
.ref = 1,
|
||||
.key = key,
|
||||
);
|
||||
|
||||
return this;
|
||||
@ -320,16 +316,13 @@ static private_openssl_ec_private_key_t *create_empty(void)
|
||||
private_key_t *openssl_ec_private_key_create(EVP_PKEY *key, bool engine)
|
||||
{
|
||||
private_openssl_ec_private_key_t *this;
|
||||
EC_KEY *ec;
|
||||
|
||||
ec = EVP_PKEY_get1_EC_KEY(key);
|
||||
EVP_PKEY_free(key);
|
||||
if (!ec)
|
||||
if (EVP_PKEY_base_id(key) != EVP_PKEY_EC)
|
||||
{
|
||||
EVP_PKEY_free(key);
|
||||
return NULL;
|
||||
}
|
||||
this = create_empty();
|
||||
this->ec = ec;
|
||||
this = create_internal(key);
|
||||
this->engine = engine;
|
||||
return &this->public.key;
|
||||
}
|
||||
@ -341,6 +334,7 @@ openssl_ec_private_key_t *openssl_ec_private_key_gen(key_type_t type,
|
||||
va_list args)
|
||||
{
|
||||
private_openssl_ec_private_key_t *this;
|
||||
EVP_PKEY *key = NULL;
|
||||
u_int key_size = 0;
|
||||
|
||||
while (TRUE)
|
||||
@ -361,32 +355,58 @@ openssl_ec_private_key_t *openssl_ec_private_key_gen(key_type_t type,
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
this = create_empty();
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
switch (key_size)
|
||||
{
|
||||
case 256:
|
||||
this->ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
key = EVP_EC_gen("P-256");
|
||||
break;
|
||||
case 384:
|
||||
this->ec = EC_KEY_new_by_curve_name(NID_secp384r1);
|
||||
key = EVP_EC_gen("P-384");
|
||||
break;
|
||||
case 521:
|
||||
this->ec = EC_KEY_new_by_curve_name(NID_secp521r1);
|
||||
key = EVP_EC_gen("P-521");
|
||||
break;
|
||||
default:
|
||||
DBG1(DBG_LIB, "EC private key size %d not supported", key_size);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
if (EC_KEY_generate_key(this->ec) != 1)
|
||||
#else /* OPENSSL_VERSION_NUMBER */
|
||||
EC_KEY *ec;
|
||||
|
||||
switch (key_size)
|
||||
{
|
||||
case 256:
|
||||
ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
break;
|
||||
case 384:
|
||||
ec = EC_KEY_new_by_curve_name(NID_secp384r1);
|
||||
break;
|
||||
case 521:
|
||||
ec = EC_KEY_new_by_curve_name(NID_secp521r1);
|
||||
break;
|
||||
default:
|
||||
DBG1(DBG_LIB, "EC private key size %d not supported", key_size);
|
||||
return NULL;
|
||||
}
|
||||
if (ec && EC_KEY_generate_key(ec) == 1)
|
||||
{
|
||||
key = EVP_PKEY_new();
|
||||
if (!EVP_PKEY_assign_EC_KEY(key, ec))
|
||||
{
|
||||
EC_KEY_free(ec);
|
||||
EVP_PKEY_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
if (!key)
|
||||
{
|
||||
DBG1(DBG_LIB, "EC private key generation failed", key_size);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
/* encode as a named curve key (no parameters), uncompressed public key */
|
||||
EC_KEY_set_asn1_flag(this->ec, OPENSSL_EC_NAMED_CURVE);
|
||||
EC_KEY_set_conv_form(this->ec, POINT_CONVERSION_UNCOMPRESSED);
|
||||
this = create_internal(key);
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@ -397,7 +417,8 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type,
|
||||
va_list args)
|
||||
{
|
||||
private_openssl_ec_private_key_t *this;
|
||||
chunk_t par = chunk_empty, key = chunk_empty;
|
||||
chunk_t par = chunk_empty, blob = chunk_empty;
|
||||
EVP_PKEY *key = NULL;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
@ -407,7 +428,7 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type,
|
||||
par = va_arg(args, chunk_t);
|
||||
continue;
|
||||
case BUILD_BLOB_ASN1_DER:
|
||||
key = va_arg(args, chunk_t);
|
||||
blob = va_arg(args, chunk_t);
|
||||
continue;
|
||||
case BUILD_END:
|
||||
break;
|
||||
@ -417,36 +438,46 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type,
|
||||
break;
|
||||
}
|
||||
|
||||
this = create_empty();
|
||||
|
||||
if (par.ptr)
|
||||
{
|
||||
this->ec = d2i_ECParameters(NULL, (const u_char**)&par.ptr, par.len);
|
||||
if (!this->ec)
|
||||
/* for OpenSSL 3, the combination of d2i_KeyParams/d2i_PrivateKey, which
|
||||
* are intended to replace the functions below, does currently not work
|
||||
* because OpenSSL does not pass the internal EC_KEY that stores the
|
||||
* parameters from the first call to the call that parses the private
|
||||
* key. however, since parsing PKCS#8 is the only use case for this and
|
||||
* OpenSSL 3 parses this format directly, there isn't really any need
|
||||
* for it anyway */
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
EC_KEY *ec;
|
||||
|
||||
ec = d2i_ECParameters(NULL, (const u_char**)&par.ptr, par.len);
|
||||
if (ec && d2i_ECPrivateKey(&ec, (const u_char**)&blob.ptr, blob.len))
|
||||
{
|
||||
goto error;
|
||||
key = EVP_PKEY_new();
|
||||
if (!EVP_PKEY_assign_EC_KEY(key, ec))
|
||||
{
|
||||
EC_KEY_free(ec);
|
||||
EVP_PKEY_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
}
|
||||
if (!d2i_ECPrivateKey(&this->ec, (const u_char**)&key.ptr, key.len))
|
||||
else
|
||||
{
|
||||
goto error;
|
||||
EC_KEY_free(ec);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
this->ec = d2i_ECPrivateKey(NULL, (const u_char**)&key.ptr, key.len);
|
||||
if (!this->ec)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
key = d2i_PrivateKey(EVP_PKEY_EC, NULL, (const u_char**)&blob.ptr,
|
||||
blob.len);
|
||||
}
|
||||
if (!EC_KEY_check_key(this->ec))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
return &this->public;
|
||||
|
||||
error:
|
||||
destroy(this);
|
||||
return NULL;
|
||||
if (!key)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
this = create_internal(key);
|
||||
return &this->public;
|
||||
}
|
||||
#endif /* OPENSSL_NO_ECDSA */
|
||||
|
@ -27,6 +27,10 @@
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
#include <openssl/core_names.h>
|
||||
#endif
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
OPENSSL_KEY_FALLBACK(ECDSA_SIG, r, s)
|
||||
#endif
|
||||
@ -45,7 +49,7 @@ struct private_openssl_ec_public_key_t {
|
||||
/**
|
||||
* EC key object
|
||||
*/
|
||||
EC_KEY *ec;
|
||||
EVP_PKEY *key;
|
||||
|
||||
/**
|
||||
* reference counter
|
||||
@ -53,14 +57,48 @@ struct private_openssl_ec_public_key_t {
|
||||
refcount_t ref;
|
||||
};
|
||||
|
||||
/**
|
||||
* Verification of a DER encoded signature as in RFC 3279
|
||||
*/
|
||||
static bool verify_der_signature(private_openssl_ec_public_key_t *this,
|
||||
int nid_hash, chunk_t data, chunk_t signature)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
const EVP_MD *md;
|
||||
|
||||
/* remove any preceding 0-bytes from signature */
|
||||
while (signature.len && signature.ptr[0] == 0x00)
|
||||
{
|
||||
signature = chunk_skip(signature, 1);
|
||||
}
|
||||
md = EVP_get_digestbynid(nid_hash);
|
||||
if (!md)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
ctx = EVP_MD_CTX_create();
|
||||
if (!ctx ||
|
||||
EVP_DigestVerifyInit(ctx, NULL, md, NULL, this->key) <= 0 ||
|
||||
EVP_DigestVerifyUpdate(ctx, data.ptr, data.len) <= 0 ||
|
||||
EVP_DigestVerifyFinal(ctx, signature.ptr, signature.len) != 1)
|
||||
{
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
return FALSE;
|
||||
}
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verification of a signature as in RFC 4754
|
||||
*/
|
||||
static bool verify_signature(private_openssl_ec_public_key_t *this,
|
||||
chunk_t hash, chunk_t signature)
|
||||
int nid_hash, chunk_t data, chunk_t signature)
|
||||
{
|
||||
EVP_PKEY_CTX *ctx;
|
||||
BIGNUM *r, *s;
|
||||
ECDSA_SIG *sig;
|
||||
chunk_t der_sig;
|
||||
bool valid = FALSE;
|
||||
|
||||
sig = ECDSA_SIG_new();
|
||||
@ -77,13 +115,73 @@ static bool verify_signature(private_openssl_ec_public_key_t *this,
|
||||
}
|
||||
if (ECDSA_SIG_set0(sig, r, s))
|
||||
{
|
||||
valid = (ECDSA_do_verify(hash.ptr, hash.len, sig, this->ec) == 1);
|
||||
der_sig = openssl_i2chunk(ECDSA_SIG, sig);
|
||||
if (!nid_hash)
|
||||
{ /* EVP_DigestVerify*() has issues with NULL EVP_MD */
|
||||
ctx = EVP_PKEY_CTX_new(this->key, NULL);
|
||||
valid = ctx && EVP_PKEY_verify_init(ctx) > 0 &&
|
||||
EVP_PKEY_verify(ctx, der_sig.ptr, der_sig.len,
|
||||
data.ptr, data.len) > 0;
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
valid = verify_der_signature(this, nid_hash, data, der_sig);
|
||||
}
|
||||
chunk_free(&der_sig);
|
||||
}
|
||||
ECDSA_SIG_free(sig);
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the given key's curve matches a specific one. Also used by
|
||||
* private key.
|
||||
*/
|
||||
bool openssl_check_ec_key_curve(EVP_PKEY *key, int nid_curve)
|
||||
{
|
||||
EC_GROUP *req_group, *my_group = NULL;
|
||||
bool matches = FALSE;
|
||||
|
||||
req_group = EC_GROUP_new_by_curve_name(nid_curve);
|
||||
if (!req_group)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
char name[BUF_LEN];
|
||||
OSSL_PARAM params[] = {
|
||||
OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, name, sizeof(name)),
|
||||
OSSL_PARAM_END,
|
||||
};
|
||||
|
||||
if (!EVP_PKEY_get_group_name(key, name, sizeof(name), NULL))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
my_group = EC_GROUP_new_from_params(params, NULL, NULL);
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x1010000fL
|
||||
EC_KEY *ec = EVP_PKEY_get0_EC_KEY(key);
|
||||
my_group = EC_GROUP_dup(EC_KEY_get0_group(ec));
|
||||
#else
|
||||
EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key);
|
||||
my_group = EC_GROUP_dup(EC_KEY_get0_group(ec));
|
||||
EC_KEY_free(ec);
|
||||
#endif
|
||||
|
||||
if (EC_GROUP_cmp(my_group, req_group, NULL) == 0)
|
||||
{
|
||||
matches = TRUE;
|
||||
}
|
||||
|
||||
error:
|
||||
EC_GROUP_free(my_group);
|
||||
EC_GROUP_free(req_group);
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a RFC 4754 signature for a specified curve and hash algorithm
|
||||
*/
|
||||
@ -91,56 +189,13 @@ static bool verify_curve_signature(private_openssl_ec_public_key_t *this,
|
||||
signature_scheme_t scheme, int nid_hash,
|
||||
int nid_curve, chunk_t data, chunk_t signature)
|
||||
{
|
||||
const EC_GROUP *my_group;
|
||||
EC_GROUP *req_group;
|
||||
chunk_t hash;
|
||||
bool valid;
|
||||
|
||||
req_group = EC_GROUP_new_by_curve_name(nid_curve);
|
||||
if (!req_group)
|
||||
if (!openssl_check_ec_key_curve(this->key, nid_curve))
|
||||
{
|
||||
DBG1(DBG_LIB, "signature scheme %N not supported in EC (required curve "
|
||||
"not supported)", signature_scheme_names, scheme);
|
||||
return FALSE;
|
||||
}
|
||||
my_group = EC_KEY_get0_group(this->ec);
|
||||
if (EC_GROUP_cmp(my_group, req_group, NULL) != 0)
|
||||
{
|
||||
DBG1(DBG_LIB, "signature scheme %N not supported by private key",
|
||||
DBG1(DBG_LIB, "signature scheme %N not supported by key",
|
||||
signature_scheme_names, scheme);
|
||||
return FALSE;
|
||||
}
|
||||
EC_GROUP_free(req_group);
|
||||
if (!openssl_hash_chunk(nid_hash, data, &hash))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
valid = verify_signature(this, hash, signature);
|
||||
chunk_free(&hash);
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verification of a DER encoded signature as in RFC 3279
|
||||
*/
|
||||
static bool verify_der_signature(private_openssl_ec_public_key_t *this,
|
||||
int nid_hash, chunk_t data, chunk_t signature)
|
||||
{
|
||||
chunk_t hash;
|
||||
bool valid = FALSE;
|
||||
|
||||
/* remove any preceding 0-bytes from signature */
|
||||
while (signature.len && signature.ptr[0] == 0x00)
|
||||
{
|
||||
signature = chunk_skip(signature, 1);
|
||||
}
|
||||
if (openssl_hash_chunk(nid_hash, data, &hash))
|
||||
{
|
||||
valid = ECDSA_verify(0, hash.ptr, hash.len,
|
||||
signature.ptr, signature.len, this->ec) == 1;
|
||||
free(hash.ptr);
|
||||
}
|
||||
return valid;
|
||||
return verify_signature(this, nid_hash, data, signature);
|
||||
}
|
||||
|
||||
METHOD(public_key_t, get_type, key_type_t,
|
||||
@ -164,7 +219,7 @@ METHOD(public_key_t, verify, bool,
|
||||
case SIGN_ECDSA_WITH_SHA512_DER:
|
||||
return verify_der_signature(this, NID_sha512, data, signature);
|
||||
case SIGN_ECDSA_WITH_NULL:
|
||||
return verify_signature(this, data, signature);
|
||||
return verify_signature(this, 0, data, signature);
|
||||
case SIGN_ECDSA_256:
|
||||
return verify_curve_signature(this, scheme, NID_sha256,
|
||||
NID_X9_62_prime256v1, data, signature);
|
||||
@ -192,56 +247,14 @@ METHOD(public_key_t, encrypt, bool,
|
||||
METHOD(public_key_t, get_keysize, int,
|
||||
private_openssl_ec_public_key_t *this)
|
||||
{
|
||||
return EC_GROUP_get_degree(EC_KEY_get0_group(this->ec));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate fingerprint from a EC_KEY, also used in ec private key.
|
||||
*/
|
||||
bool openssl_ec_fingerprint(EC_KEY *ec, cred_encoding_type_t type, chunk_t *fp)
|
||||
{
|
||||
hasher_t *hasher;
|
||||
chunk_t key;
|
||||
u_char *p;
|
||||
|
||||
if (lib->encoding->get_cache(lib->encoding, type, ec, fp))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case KEYID_PUBKEY_SHA1:
|
||||
key = chunk_alloc(i2o_ECPublicKey(ec, NULL));
|
||||
p = key.ptr;
|
||||
i2o_ECPublicKey(ec, &p);
|
||||
break;
|
||||
case KEYID_PUBKEY_INFO_SHA1:
|
||||
key = chunk_alloc(i2d_EC_PUBKEY(ec, NULL));
|
||||
p = key.ptr;
|
||||
i2d_EC_PUBKEY(ec, &p);
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
|
||||
if (!hasher || !hasher->allocate_hash(hasher, key, fp))
|
||||
{
|
||||
DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed");
|
||||
DESTROY_IF(hasher);
|
||||
free(key.ptr);
|
||||
return FALSE;
|
||||
}
|
||||
hasher->destroy(hasher);
|
||||
free(key.ptr);
|
||||
lib->encoding->cache(lib->encoding, type, ec, *fp);
|
||||
return TRUE;
|
||||
return EVP_PKEY_bits(this->key);
|
||||
}
|
||||
|
||||
METHOD(public_key_t, get_fingerprint, bool,
|
||||
private_openssl_ec_public_key_t *this, cred_encoding_type_t type,
|
||||
chunk_t *fingerprint)
|
||||
{
|
||||
return openssl_ec_fingerprint(this->ec, type, fingerprint);
|
||||
return openssl_fingerprint(this->key, type, fingerprint);
|
||||
}
|
||||
|
||||
METHOD(public_key_t, get_encoding, bool,
|
||||
@ -249,11 +262,8 @@ METHOD(public_key_t, get_encoding, bool,
|
||||
chunk_t *encoding)
|
||||
{
|
||||
bool success = TRUE;
|
||||
u_char *p;
|
||||
|
||||
*encoding = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL));
|
||||
p = encoding->ptr;
|
||||
i2d_EC_PUBKEY(this->ec, &p);
|
||||
*encoding = openssl_i2chunk(PUBKEY, this->key);
|
||||
|
||||
if (type != PUBKEY_SPKI_ASN1_DER)
|
||||
{
|
||||
@ -279,21 +289,45 @@ METHOD(public_key_t, destroy, void,
|
||||
{
|
||||
if (ref_put(&this->ref))
|
||||
{
|
||||
if (this->ec)
|
||||
if (this->key)
|
||||
{
|
||||
lib->encoding->clear_cache(lib->encoding, this->ec);
|
||||
EC_KEY_free(this->ec);
|
||||
lib->encoding->clear_cache(lib->encoding, this->key);
|
||||
EVP_PKEY_free(this->key);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic private constructor
|
||||
* See header.
|
||||
*/
|
||||
static private_openssl_ec_public_key_t *create_empty()
|
||||
openssl_ec_public_key_t *openssl_ec_public_key_load(key_type_t type,
|
||||
va_list args)
|
||||
{
|
||||
private_openssl_ec_public_key_t *this;
|
||||
chunk_t blob = chunk_empty;
|
||||
EVP_PKEY *key;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
switch (va_arg(args, builder_part_t))
|
||||
{
|
||||
case BUILD_BLOB_ASN1_DER:
|
||||
blob = va_arg(args, chunk_t);
|
||||
continue;
|
||||
case BUILD_END:
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
key = d2i_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len);
|
||||
if (!key || EVP_PKEY_base_id(key) != EVP_PKEY_EC)
|
||||
{
|
||||
EVP_PKEY_free(key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
@ -311,47 +345,9 @@ static private_openssl_ec_public_key_t *create_empty()
|
||||
},
|
||||
},
|
||||
.ref = 1,
|
||||
.key = key,
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* See header.
|
||||
*/
|
||||
openssl_ec_public_key_t *openssl_ec_public_key_load(key_type_t type,
|
||||
va_list args)
|
||||
{
|
||||
private_openssl_ec_public_key_t *this;
|
||||
chunk_t blob = chunk_empty;
|
||||
|
||||
if (type != KEY_ECDSA)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
switch (va_arg(args, builder_part_t))
|
||||
{
|
||||
case BUILD_BLOB_ASN1_DER:
|
||||
blob = va_arg(args, chunk_t);
|
||||
continue;
|
||||
case BUILD_END:
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
this = create_empty();
|
||||
this->ec = d2i_EC_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len);
|
||||
if (!this->ec)
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
#endif /* OPENSSL_NO_ECDSA */
|
||||
|
||||
#endif /* OPENSSL_NO_ECDSA */
|
||||
|
214
src/libstrongswan/plugins/openssl/openssl_engine.c
Normal file
214
src/libstrongswan/plugins/openssl/openssl_engine.c
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2018 Tobias Brunner
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/* the ENGINE API has been deprecated with OpenSSL 3.0 (the provider API should
|
||||
* be used instead) */
|
||||
#define OPENSSL_SUPPRESS_DEPRECATED
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/opensslconf.h>
|
||||
|
||||
#include "openssl_engine.h"
|
||||
|
||||
#if !defined(OPENSSL_NO_ENGINE) && \
|
||||
(OPENSSL_VERSION_NUMBER < 0x30000000L || !defined(OPENSSL_NO_DEPRECATED))
|
||||
|
||||
#include <openssl/engine.h>
|
||||
|
||||
#include "openssl_ec_private_key.h"
|
||||
#include "openssl_ed_private_key.h"
|
||||
#include "openssl_rsa_private_key.h"
|
||||
|
||||
/**
|
||||
* Login to engine with a PIN specified for a keyid
|
||||
*/
|
||||
static bool login(ENGINE *engine, chunk_t keyid)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
shared_key_t *shared;
|
||||
identification_t *id;
|
||||
chunk_t key;
|
||||
char pin[64];
|
||||
bool found = FALSE, success = FALSE;
|
||||
|
||||
id = identification_create_from_encoding(ID_KEY_ID, keyid);
|
||||
enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
|
||||
SHARED_PIN, id, NULL);
|
||||
while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
|
||||
{
|
||||
found = TRUE;
|
||||
key = shared->get_key(shared);
|
||||
if (snprintf(pin, sizeof(pin),
|
||||
"%.*s", (int)key.len, key.ptr) >= sizeof(pin))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (ENGINE_ctrl_cmd_string(engine, "PIN", pin, 0))
|
||||
{
|
||||
success = TRUE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, "setting PIN on engine failed");
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
id->destroy(id);
|
||||
if (!found)
|
||||
{
|
||||
DBG1(DBG_CFG, "no PIN found for %#B", &keyid);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
private_key_t *openssl_private_key_connect(key_type_t type, va_list args)
|
||||
{
|
||||
char *engine_id = NULL;
|
||||
char keyname[BUF_LEN];
|
||||
chunk_t keyid = chunk_empty;
|
||||
EVP_PKEY *key;
|
||||
ENGINE *engine;
|
||||
int slot = -1;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
switch (va_arg(args, builder_part_t))
|
||||
{
|
||||
case BUILD_PKCS11_KEYID:
|
||||
keyid = va_arg(args, chunk_t);
|
||||
continue;
|
||||
case BUILD_PKCS11_SLOT:
|
||||
slot = va_arg(args, int);
|
||||
continue;
|
||||
case BUILD_PKCS11_MODULE:
|
||||
engine_id = va_arg(args, char*);
|
||||
continue;
|
||||
case BUILD_END:
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!keyid.len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(keyname, 0, sizeof(keyname));
|
||||
if (slot != -1)
|
||||
{
|
||||
snprintf(keyname, sizeof(keyname), "%d:", slot);
|
||||
}
|
||||
if (sizeof(keyname) - strlen(keyname) <= keyid.len * 2 + 1)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
chunk_to_hex(keyid, keyname + strlen(keyname), FALSE);
|
||||
|
||||
if (!engine_id)
|
||||
{
|
||||
engine_id = lib->settings->get_str(lib->settings,
|
||||
"%s.plugins.openssl.engine_id", "pkcs11", lib->ns);
|
||||
}
|
||||
engine = ENGINE_by_id(engine_id);
|
||||
if (!engine)
|
||||
{
|
||||
DBG2(DBG_LIB, "engine '%s' is not available", engine_id);
|
||||
return NULL;
|
||||
}
|
||||
if (!ENGINE_init(engine))
|
||||
{
|
||||
DBG1(DBG_LIB, "failed to initialize engine '%s'", engine_id);
|
||||
ENGINE_free(engine);
|
||||
return NULL;
|
||||
}
|
||||
ENGINE_free(engine);
|
||||
if (!login(engine, keyid))
|
||||
{
|
||||
DBG1(DBG_LIB, "login to engine '%s' failed", engine_id);
|
||||
ENGINE_finish(engine);
|
||||
return NULL;
|
||||
}
|
||||
key = ENGINE_load_private_key(engine, keyname, NULL, NULL);
|
||||
ENGINE_finish(engine);
|
||||
if (!key)
|
||||
{
|
||||
DBG1(DBG_LIB, "failed to load private key with ID '%s' from "
|
||||
"engine '%s'", keyname, engine_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (EVP_PKEY_base_id(key))
|
||||
{
|
||||
#ifndef OPENSSL_NO_RSA
|
||||
case EVP_PKEY_RSA:
|
||||
return openssl_rsa_private_key_create(key, TRUE);
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_ECDSA
|
||||
case EVP_PKEY_EC:
|
||||
return openssl_ec_private_key_create(key, TRUE);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC)
|
||||
case EVP_PKEY_ED25519:
|
||||
case EVP_PKEY_ED448:
|
||||
return openssl_ed_private_key_create(key, TRUE);
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
default:
|
||||
EVP_PKEY_free(key);
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
void openssl_engine_deinit()
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
ENGINE_cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
void openssl_engine_init()
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
/* activate support for hardware accelerators */
|
||||
ENGINE_load_builtin_engines();
|
||||
ENGINE_register_all_complete();
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* OPENSSL_NO_ENGINE */
|
||||
|
||||
private_key_t *openssl_private_key_connect(key_type_t type, va_list args)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void openssl_engine_deinit() {}
|
||||
|
||||
void openssl_engine_init() {}
|
||||
|
||||
#endif /* OPENSSL_NO_ENGINE */
|
53
src/libstrongswan/plugins/openssl/openssl_engine.h
Normal file
53
src/libstrongswan/plugins/openssl/openssl_engine.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Tobias Brunner, codelabs GmbH
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Compatibility code for legacy ENGINE support.
|
||||
*
|
||||
* @defgroup openssl_engine openssl_engine
|
||||
* @{ @ingroup openssl_p
|
||||
*/
|
||||
|
||||
#ifndef OPENSSL_ENGINE_H_
|
||||
#define OPENSSL_ENGINE_H_
|
||||
|
||||
#include <credentials/keys/private_key.h>
|
||||
|
||||
/**
|
||||
* Load a private key from a token/ENGINE.
|
||||
*
|
||||
* @param type key type to load
|
||||
* @param args build arguments
|
||||
*/
|
||||
private_key_t *openssl_private_key_connect(key_type_t type, va_list args);
|
||||
|
||||
/**
|
||||
* Initialize ENGINE support.
|
||||
*/
|
||||
void openssl_engine_init();
|
||||
|
||||
/**
|
||||
* Deinitialize ENGINE support.
|
||||
*/
|
||||
void openssl_engine_deinit();
|
||||
|
||||
#endif /** OPENSSL_ENGINE_H_ @}*/
|
@ -42,6 +42,10 @@
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
#include <openssl/core_names.h>
|
||||
#endif
|
||||
|
||||
#include "openssl_hmac.h"
|
||||
|
||||
#include <crypto/mac.h>
|
||||
@ -60,6 +64,19 @@ struct private_mac_t {
|
||||
*/
|
||||
mac_t public;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
/**
|
||||
* HMAC context
|
||||
*/
|
||||
EVP_MAC_CTX *hmac;
|
||||
|
||||
/**
|
||||
* Base context because EVP_MAC_init() does not reset the internal state if
|
||||
* no key is passed, so the above is a copy that's replaced with every
|
||||
* reset that does not change the key
|
||||
*/
|
||||
EVP_MAC_CTX *hmac_base;
|
||||
#else
|
||||
/**
|
||||
* Hasher to use
|
||||
*/
|
||||
@ -69,6 +86,7 @@ struct private_mac_t {
|
||||
* Current HMAC context
|
||||
*/
|
||||
HMAC_CTX *hmac;
|
||||
#endif
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
/**
|
||||
@ -84,16 +102,20 @@ struct private_mac_t {
|
||||
*/
|
||||
static bool reset(private_mac_t *this, chunk_t key)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
if (!key.len || EVP_MAC_init(this->hmac_base, key.ptr, key.len, NULL))
|
||||
{
|
||||
EVP_MAC_CTX_free(this->hmac);
|
||||
this->hmac = EVP_MAC_CTX_dup(this->hmac_base);
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
if (HMAC_Init_ex(this->hmac, key.ptr, key.len, this->hasher, NULL))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
#else /* OPENSSL_VERSION_NUMBER < 1.0 */
|
||||
HMAC_Init_ex(this->hmac, key.ptr, key.len, this->hasher, NULL);
|
||||
return TRUE;
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
METHOD(mac_t, set_key, bool,
|
||||
@ -104,46 +126,62 @@ METHOD(mac_t, set_key, bool,
|
||||
* use a lengthy string in case there is a limit in FIPS-mode */
|
||||
key = chunk_from_str("00000000000000000000000000000000");
|
||||
}
|
||||
return reset(this, key);
|
||||
}
|
||||
|
||||
METHOD(mac_t, get_mac, bool,
|
||||
private_mac_t *this, chunk_t data, uint8_t *out)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||
if (!HMAC_Update(this->hmac, data.ptr, data.len))
|
||||
if (!reset(this, key))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (out == NULL)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (!HMAC_Final(this->hmac, out, NULL))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
#else /* OPENSSL_VERSION_NUMBER < 1.0 */
|
||||
HMAC_Update(this->hmac, data.ptr, data.len);
|
||||
if (out == NULL)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
HMAC_Final(this->hmac, out, NULL);
|
||||
#endif
|
||||
return reset(this, chunk_empty);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(mac_t, get_mac_size, size_t,
|
||||
private_mac_t *this)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
return EVP_MAC_CTX_get_mac_size(this->hmac);
|
||||
#else
|
||||
return EVP_MD_size(this->hasher);
|
||||
#endif
|
||||
}
|
||||
|
||||
METHOD(mac_t, get_mac, bool,
|
||||
private_mac_t *this, chunk_t data, uint8_t *out)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
if (!EVP_MAC_update(this->hmac, data.ptr, data.len))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
if (!HMAC_Update(this->hmac, data.ptr, data.len))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
if (!out)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
if (!EVP_MAC_final(this->hmac, out, NULL, get_mac_size(this)))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
if (!HMAC_Final(this->hmac, out, NULL))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
return reset(this, chunk_empty);
|
||||
}
|
||||
|
||||
METHOD(mac_t, destroy, void,
|
||||
private_mac_t *this)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
EVP_MAC_CTX_free(this->hmac_base);
|
||||
EVP_MAC_CTX_free(this->hmac);
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
HMAC_CTX_free(this->hmac);
|
||||
#else
|
||||
HMAC_CTX_cleanup(&this->hmac_ctx);
|
||||
@ -172,21 +210,41 @@ static mac_t *hmac_create(hash_algorithm_t algo)
|
||||
.set_key = _set_key,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.hasher = EVP_get_digestbyname(name),
|
||||
);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
OSSL_PARAM params[] = {
|
||||
OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, name, 0),
|
||||
OSSL_PARAM_END,
|
||||
};
|
||||
EVP_MAC *mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
|
||||
|
||||
if (!mac)
|
||||
{
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
this->hmac_base = EVP_MAC_CTX_new(mac);
|
||||
EVP_MAC_free(mac);
|
||||
if (!this->hmac_base || !EVP_MAC_CTX_set_params(this->hmac_base, params))
|
||||
{
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
#else /* OPENSSL_VERSION_NUMBER */
|
||||
this->hasher = EVP_get_digestbyname(name);
|
||||
if (!this->hasher)
|
||||
{
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
this->hmac = HMAC_CTX_new();
|
||||
#else
|
||||
HMAC_CTX_init(&this->hmac_ctx);
|
||||
this->hmac = &this->hmac_ctx;
|
||||
#endif
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
/* make sure the underlying hash algorithm is supported */
|
||||
if (!set_key(this, chunk_empty))
|
||||
|
@ -25,9 +25,6 @@
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/crypto.h>
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
#include <openssl/engine.h>
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_ECDH
|
||||
#include <openssl/ec.h>
|
||||
#endif
|
||||
@ -38,6 +35,7 @@
|
||||
#include "openssl_plugin.h"
|
||||
#include "openssl_util.h"
|
||||
#include "openssl_crypter.h"
|
||||
#include "openssl_engine.h"
|
||||
#include "openssl_hasher.h"
|
||||
#include "openssl_sha1_prf.h"
|
||||
#include "openssl_diffie_hellman.h"
|
||||
@ -160,42 +158,27 @@ static thread_value_t *cleanup;
|
||||
*/
|
||||
static void cleanup_thread(void *arg)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
|
||||
CRYPTO_THREADID tid;
|
||||
|
||||
CRYPTO_THREADID_set_numeric(&tid, (u_long)(uintptr_t)arg);
|
||||
ERR_remove_thread_state(&tid);
|
||||
#else
|
||||
ERR_remove_state((u_long)(uintptr_t)arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread-ID callback function
|
||||
* Callback for thread ID
|
||||
*/
|
||||
static u_long id_function(void)
|
||||
static void threadid_function(CRYPTO_THREADID *threadid)
|
||||
{
|
||||
u_long id;
|
||||
|
||||
/* ensure the thread ID is never zero, otherwise OpenSSL might try to
|
||||
* acquire locks recursively */
|
||||
id = 1 + (u_long)thread_current_id();
|
||||
|
||||
/* cleanup a thread's state later if OpenSSL interacted with it */
|
||||
cleanup->set(cleanup, (void*)(uintptr_t)id);
|
||||
return id;
|
||||
CRYPTO_THREADID_set_numeric(threadid, id);
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
|
||||
/**
|
||||
* Callback for thread ID
|
||||
*/
|
||||
static void threadid_function(CRYPTO_THREADID *threadid)
|
||||
{
|
||||
CRYPTO_THREADID_set_numeric(threadid, id_function());
|
||||
}
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
/**
|
||||
* initialize OpenSSL for multi-threaded use
|
||||
*/
|
||||
@ -205,14 +188,9 @@ static void threading_init()
|
||||
|
||||
cleanup = thread_value_create(cleanup_thread);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
|
||||
CRYPTO_THREADID_set_callback(threadid_function);
|
||||
#else
|
||||
CRYPTO_set_id_callback(id_function);
|
||||
#endif
|
||||
|
||||
CRYPTO_set_locking_callback(locking_function);
|
||||
|
||||
CRYPTO_set_dynlock_create_callback(create_function);
|
||||
CRYPTO_set_dynlock_lock_callback(lock_function);
|
||||
CRYPTO_set_dynlock_destroy_callback(destroy_function);
|
||||
@ -336,157 +314,6 @@ static private_key_t *openssl_private_key_load(key_type_t type, va_list args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
/**
|
||||
* Login to engine with a PIN specified for a keyid
|
||||
*/
|
||||
static bool login(ENGINE *engine, chunk_t keyid)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
shared_key_t *shared;
|
||||
identification_t *id;
|
||||
chunk_t key;
|
||||
char pin[64];
|
||||
bool found = FALSE, success = FALSE;
|
||||
|
||||
id = identification_create_from_encoding(ID_KEY_ID, keyid);
|
||||
enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
|
||||
SHARED_PIN, id, NULL);
|
||||
while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
|
||||
{
|
||||
found = TRUE;
|
||||
key = shared->get_key(shared);
|
||||
if (snprintf(pin, sizeof(pin),
|
||||
"%.*s", (int)key.len, key.ptr) >= sizeof(pin))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (ENGINE_ctrl_cmd_string(engine, "PIN", pin, 0))
|
||||
{
|
||||
success = TRUE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, "setting PIN on engine failed");
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
id->destroy(id);
|
||||
if (!found)
|
||||
{
|
||||
DBG1(DBG_CFG, "no PIN found for %#B", &keyid);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
#endif /* OPENSSL_NO_ENGINE */
|
||||
|
||||
/**
|
||||
* Load private key via engine
|
||||
*/
|
||||
static private_key_t *openssl_private_key_connect(key_type_t type,
|
||||
va_list args)
|
||||
{
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
char *engine_id = NULL;
|
||||
char keyname[BUF_LEN];
|
||||
chunk_t keyid = chunk_empty;
|
||||
EVP_PKEY *key;
|
||||
ENGINE *engine;
|
||||
int slot = -1;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
switch (va_arg(args, builder_part_t))
|
||||
{
|
||||
case BUILD_PKCS11_KEYID:
|
||||
keyid = va_arg(args, chunk_t);
|
||||
continue;
|
||||
case BUILD_PKCS11_SLOT:
|
||||
slot = va_arg(args, int);
|
||||
continue;
|
||||
case BUILD_PKCS11_MODULE:
|
||||
engine_id = va_arg(args, char*);
|
||||
continue;
|
||||
case BUILD_END:
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!keyid.len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(keyname, 0, sizeof(keyname));
|
||||
if (slot != -1)
|
||||
{
|
||||
snprintf(keyname, sizeof(keyname), "%d:", slot);
|
||||
}
|
||||
if (sizeof(keyname) - strlen(keyname) <= keyid.len * 2 + 1)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
chunk_to_hex(keyid, keyname + strlen(keyname), FALSE);
|
||||
|
||||
if (!engine_id)
|
||||
{
|
||||
engine_id = lib->settings->get_str(lib->settings,
|
||||
"%s.plugins.openssl.engine_id", "pkcs11", lib->ns);
|
||||
}
|
||||
engine = ENGINE_by_id(engine_id);
|
||||
if (!engine)
|
||||
{
|
||||
DBG2(DBG_LIB, "engine '%s' is not available", engine_id);
|
||||
return NULL;
|
||||
}
|
||||
if (!ENGINE_init(engine))
|
||||
{
|
||||
DBG1(DBG_LIB, "failed to initialize engine '%s'", engine_id);
|
||||
ENGINE_free(engine);
|
||||
return NULL;
|
||||
}
|
||||
ENGINE_free(engine);
|
||||
if (!login(engine, keyid))
|
||||
{
|
||||
DBG1(DBG_LIB, "login to engine '%s' failed", engine_id);
|
||||
ENGINE_finish(engine);
|
||||
return NULL;
|
||||
}
|
||||
key = ENGINE_load_private_key(engine, keyname, NULL, NULL);
|
||||
ENGINE_finish(engine);
|
||||
if (!key)
|
||||
{
|
||||
DBG1(DBG_LIB, "failed to load private key with ID '%s' from "
|
||||
"engine '%s'", keyname, engine_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (EVP_PKEY_base_id(key))
|
||||
{
|
||||
#ifndef OPENSSL_NO_RSA
|
||||
case EVP_PKEY_RSA:
|
||||
return openssl_rsa_private_key_create(key, TRUE);
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_ECDSA
|
||||
case EVP_PKEY_EC:
|
||||
return openssl_ec_private_key_create(key, TRUE);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC)
|
||||
case EVP_PKEY_ED25519:
|
||||
case EVP_PKEY_ED448:
|
||||
return openssl_ed_private_key_create(key, TRUE);
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
default:
|
||||
EVP_PKEY_free(key);
|
||||
break;
|
||||
}
|
||||
#endif /* OPENSSL_NO_ENGINE */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
METHOD(plugin_t, get_name, char*,
|
||||
private_openssl_plugin_t *this)
|
||||
{
|
||||
@ -615,7 +442,8 @@ METHOD(plugin_t, get_features, int,
|
||||
PLUGIN_PROVIDE(XOF, XOF_SHAKE_128),
|
||||
PLUGIN_PROVIDE(XOF, XOF_SHAKE_256),
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_SHA1
|
||||
#if !defined(OPENSSL_NO_SHA1) && \
|
||||
(OPENSSL_VERSION_NUMBER < 0x30000000L || !defined(OPENSSL_NO_DEPRECATED))
|
||||
/* keyed sha1 hasher (aka prf) */
|
||||
PLUGIN_REGISTER(PRF, openssl_sha1_prf_create),
|
||||
PLUGIN_PROVIDE(PRF, PRF_KEYED_SHA1),
|
||||
@ -662,7 +490,7 @@ METHOD(plugin_t, get_features, int,
|
||||
PLUGIN_PROVIDE(KDF, KDF_PRF_PLUS),
|
||||
#endif
|
||||
#endif /* OPENSSL_NO_HMAC */
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_AES)) || \
|
||||
#if (!defined(OPENSSL_NO_AES)) || \
|
||||
(OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_CHACHA))
|
||||
/* AEAD (AES GCM since 1.0.1, ChaCha20-Poly1305 since 1.1.0) */
|
||||
PLUGIN_REGISTER(AEAD, openssl_aead_create),
|
||||
@ -722,10 +550,8 @@ METHOD(plugin_t, get_features, int,
|
||||
/* signature/encryption schemes */
|
||||
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_NULL),
|
||||
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_NULL),
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PSS),
|
||||
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PSS),
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_SHA1
|
||||
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA1),
|
||||
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA1),
|
||||
@ -886,6 +712,7 @@ METHOD(plugin_t, get_features, int,
|
||||
METHOD(plugin_t, destroy, void,
|
||||
private_openssl_plugin_t *this)
|
||||
{
|
||||
|
||||
/* OpenSSL 1.1.0 cleans up itself at exit and while OPENSSL_cleanup() exists we
|
||||
* can't call it as we couldn't re-initialize the library (as required by the
|
||||
* unit tests and the Android app) */
|
||||
@ -895,9 +722,7 @@ METHOD(plugin_t, destroy, void,
|
||||
OBJ_cleanup();
|
||||
#endif
|
||||
EVP_cleanup();
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
ENGINE_cleanup();
|
||||
#endif /* OPENSSL_NO_ENGINE */
|
||||
openssl_engine_deinit();
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
threading_cleanup();
|
||||
ERR_free_strings();
|
||||
@ -981,11 +806,7 @@ plugin_t *openssl_plugin_create()
|
||||
OPENSSL_config(NULL);
|
||||
#endif
|
||||
OpenSSL_add_all_algorithms();
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
/* activate support for hardware accelerators */
|
||||
ENGINE_load_builtin_engines();
|
||||
ENGINE_register_all_complete();
|
||||
#endif /* OPENSSL_NO_ENGINE */
|
||||
openssl_engine_init();
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
|
@ -31,6 +31,11 @@
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
#include <openssl/param_build.h>
|
||||
#include <openssl/core_names.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Public exponent to use for key generation.
|
||||
*/
|
||||
@ -41,6 +46,7 @@ OPENSSL_KEY_FALLBACK(RSA, key, n, e, d)
|
||||
OPENSSL_KEY_FALLBACK(RSA, factors, p, q)
|
||||
OPENSSL_KEY_FALLBACK(RSA, crt_params, dmp1, dmq1, iqmp)
|
||||
#define BN_secure_new() BN_new()
|
||||
#define BN_CTX_secure_new() BN_CTX_new()
|
||||
#endif
|
||||
|
||||
typedef struct private_openssl_rsa_private_key_t private_openssl_rsa_private_key_t;
|
||||
@ -55,9 +61,9 @@ struct private_openssl_rsa_private_key_t {
|
||||
openssl_rsa_private_key_t public;
|
||||
|
||||
/**
|
||||
* RSA object from OpenSSL
|
||||
* RSA key object
|
||||
*/
|
||||
RSA *rsa;
|
||||
EVP_PKEY *key;
|
||||
|
||||
/**
|
||||
* TRUE if the key is from an OpenSSL ENGINE and might not be readable
|
||||
@ -71,9 +77,7 @@ struct private_openssl_rsa_private_key_t {
|
||||
};
|
||||
|
||||
/* implemented in rsa public key */
|
||||
bool openssl_rsa_fingerprint(RSA *rsa, cred_encoding_type_t type, chunk_t *fp);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||
bool openssl_rsa_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, chunk_t *fp);
|
||||
|
||||
/**
|
||||
* Build RSA signature
|
||||
@ -84,20 +88,14 @@ static bool build_signature(private_openssl_rsa_private_key_t *this,
|
||||
{
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_MD_CTX *mctx = NULL;
|
||||
EVP_PKEY *key;
|
||||
bool success = FALSE;
|
||||
|
||||
mctx = EVP_MD_CTX_create();
|
||||
key = EVP_PKEY_new();
|
||||
if (!mctx || !key)
|
||||
if (!mctx)
|
||||
{
|
||||
goto error;
|
||||
return FALSE;
|
||||
}
|
||||
if (!EVP_PKEY_set1_RSA(key, this->rsa))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (EVP_DigestSignInit(mctx, &pctx, md, NULL, key) <= 0)
|
||||
if (EVP_DigestSignInit(mctx, &pctx, md, NULL, this->key) <= 0)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
@ -118,17 +116,31 @@ static bool build_signature(private_openssl_rsa_private_key_t *this,
|
||||
success = (EVP_DigestSignFinal(mctx, sig->ptr, &sig->len) == 1);
|
||||
|
||||
error:
|
||||
if (key)
|
||||
{
|
||||
EVP_PKEY_free(key);
|
||||
}
|
||||
if (mctx)
|
||||
{
|
||||
EVP_MD_CTX_destroy(mctx);
|
||||
}
|
||||
EVP_MD_CTX_destroy(mctx);
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an EMSA PKCS1 signature without hashing
|
||||
*/
|
||||
static bool build_plain_signature(private_openssl_rsa_private_key_t *this,
|
||||
chunk_t data, chunk_t *sig)
|
||||
{
|
||||
EVP_PKEY_CTX *ctx;
|
||||
|
||||
ctx = EVP_PKEY_CTX_new(this->key, NULL);
|
||||
if (!ctx ||
|
||||
EVP_PKEY_sign_init(ctx) <= 0 ||
|
||||
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0 ||
|
||||
EVP_PKEY_sign(ctx, sig->ptr, &sig->len, data.ptr, data.len) <= 0)
|
||||
{
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return FALSE;
|
||||
}
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an EMSA PKCS1 signature described in PKCS#1
|
||||
*/
|
||||
@ -137,12 +149,11 @@ static bool build_emsa_pkcs1_signature(private_openssl_rsa_private_key_t *this,
|
||||
{
|
||||
const EVP_MD *md;
|
||||
|
||||
*sig = chunk_alloc(RSA_size(this->rsa));
|
||||
*sig = chunk_alloc(EVP_PKEY_size(this->key));
|
||||
|
||||
if (type == NID_undef)
|
||||
{
|
||||
if (RSA_private_encrypt(data.len, data.ptr, sig->ptr, this->rsa,
|
||||
RSA_PKCS1_PADDING) == sig->len)
|
||||
if (build_plain_signature(this, data, sig))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
@ -173,7 +184,7 @@ static bool build_emsa_pss_signature(private_openssl_rsa_private_key_t *this,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*sig = chunk_alloc(RSA_size(this->rsa));
|
||||
*sig = chunk_alloc(EVP_PKEY_size(this->key));
|
||||
|
||||
md = openssl_get_md(params->hash);
|
||||
if (md && build_signature(this, md, params, data, sig))
|
||||
@ -184,80 +195,6 @@ static bool build_emsa_pss_signature(private_openssl_rsa_private_key_t *this,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#else /* OPENSSL_VERSION_NUMBER < 1.0 */
|
||||
|
||||
/**
|
||||
* Build an EMSA PKCS1 signature described in PKCS#1
|
||||
*/
|
||||
static bool build_emsa_pkcs1_signature(private_openssl_rsa_private_key_t *this,
|
||||
int type, chunk_t data, chunk_t *sig)
|
||||
{
|
||||
bool success = FALSE;
|
||||
|
||||
*sig = chunk_alloc(RSA_size(this->rsa));
|
||||
|
||||
if (type == NID_undef)
|
||||
{
|
||||
if (RSA_private_encrypt(data.len, data.ptr, sig->ptr, this->rsa,
|
||||
RSA_PKCS1_PADDING) == sig->len)
|
||||
{
|
||||
success = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EVP_MD_CTX *ctx = NULL;
|
||||
EVP_PKEY *key = NULL;
|
||||
const EVP_MD *hasher;
|
||||
u_int len;
|
||||
|
||||
hasher = EVP_get_digestbynid(type);
|
||||
if (!hasher)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
ctx = EVP_MD_CTX_create();
|
||||
key = EVP_PKEY_new();
|
||||
if (!ctx || !key)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (!EVP_PKEY_set1_RSA(key, this->rsa))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (!EVP_SignInit_ex(ctx, hasher, NULL))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (!EVP_SignUpdate(ctx, data.ptr, data.len))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (EVP_SignFinal(ctx, sig->ptr, &len, key))
|
||||
{
|
||||
success = TRUE;
|
||||
}
|
||||
|
||||
error:
|
||||
if (key)
|
||||
{
|
||||
EVP_PKEY_free(key);
|
||||
}
|
||||
if (ctx)
|
||||
{
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
}
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
free(sig->ptr);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
#endif /* OPENSSL_VERSION_NUMBER < 1.0 */
|
||||
|
||||
METHOD(private_key_t, get_type, key_type_t,
|
||||
private_openssl_rsa_private_key_t *this)
|
||||
{
|
||||
@ -294,10 +231,8 @@ METHOD(private_key_t, sign, bool,
|
||||
return build_emsa_pkcs1_signature(this, NID_sha1, data, signature);
|
||||
case SIGN_RSA_EMSA_PKCS1_MD5:
|
||||
return build_emsa_pkcs1_signature(this, NID_md5, data, signature);
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||
case SIGN_RSA_EMSA_PSS:
|
||||
return build_emsa_pss_signature(this, params, data, signature);
|
||||
#endif
|
||||
default:
|
||||
DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
|
||||
signature_scheme_names, scheme);
|
||||
@ -310,7 +245,6 @@ METHOD(private_key_t, decrypt, bool,
|
||||
void *params, chunk_t crypto, chunk_t *plain)
|
||||
{
|
||||
EVP_PKEY_CTX *ctx = NULL;
|
||||
EVP_PKEY *evp_key = NULL;
|
||||
chunk_t label = chunk_empty;
|
||||
hash_algorithm_t hash_alg = HASH_UNKNOWN;
|
||||
size_t len;
|
||||
@ -349,23 +283,11 @@ METHOD(private_key_t, decrypt, bool,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
evp_key = EVP_PKEY_new();
|
||||
if (!evp_key)
|
||||
{
|
||||
DBG1(DBG_LIB, "could not create EVP key");
|
||||
goto error;
|
||||
}
|
||||
if (EVP_PKEY_set1_RSA(evp_key, this->rsa) <= 0)
|
||||
{
|
||||
DBG1(DBG_LIB, "could not set EVP key to RSA key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ctx = EVP_PKEY_CTX_new(evp_key, NULL);
|
||||
ctx = EVP_PKEY_CTX_new(this->key, NULL);
|
||||
if (!ctx)
|
||||
{
|
||||
DBG1(DBG_LIB, "could not create EVP context");
|
||||
goto error;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_decrypt_init(ctx) <= 0)
|
||||
@ -410,7 +332,7 @@ METHOD(private_key_t, decrypt, bool,
|
||||
}
|
||||
|
||||
/* determine maximum plaintext size */
|
||||
len = RSA_size(this->rsa);
|
||||
len = EVP_PKEY_size(this->key);
|
||||
decrypted = malloc(len);
|
||||
|
||||
/* decrypt data */
|
||||
@ -424,33 +346,23 @@ METHOD(private_key_t, decrypt, bool,
|
||||
success = TRUE;
|
||||
|
||||
error:
|
||||
if (ctx)
|
||||
{
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
}
|
||||
if (evp_key)
|
||||
{
|
||||
EVP_PKEY_free(evp_key);
|
||||
}
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return success;
|
||||
}
|
||||
|
||||
METHOD(private_key_t, get_keysize, int,
|
||||
private_openssl_rsa_private_key_t *this)
|
||||
{
|
||||
return RSA_size(this->rsa) * 8;
|
||||
return EVP_PKEY_bits(this->key);
|
||||
}
|
||||
|
||||
METHOD(private_key_t, get_public_key, public_key_t*,
|
||||
private_openssl_rsa_private_key_t *this)
|
||||
{
|
||||
chunk_t enc;
|
||||
public_key_t *key;
|
||||
u_char *p;
|
||||
chunk_t enc;
|
||||
|
||||
enc = chunk_alloc(i2d_RSAPublicKey(this->rsa, NULL));
|
||||
p = enc.ptr;
|
||||
i2d_RSAPublicKey(this->rsa, &p);
|
||||
enc = openssl_i2chunk(PublicKey, this->key);
|
||||
key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
|
||||
BUILD_BLOB_ASN1_DER, enc, BUILD_END);
|
||||
free(enc.ptr);
|
||||
@ -461,15 +373,13 @@ METHOD(private_key_t, get_fingerprint, bool,
|
||||
private_openssl_rsa_private_key_t *this, cred_encoding_type_t type,
|
||||
chunk_t *fingerprint)
|
||||
{
|
||||
return openssl_rsa_fingerprint(this->rsa, type, fingerprint);
|
||||
return openssl_rsa_fingerprint(this->key, type, fingerprint);
|
||||
}
|
||||
|
||||
METHOD(private_key_t, get_encoding, bool,
|
||||
private_openssl_rsa_private_key_t *this, cred_encoding_type_t type,
|
||||
chunk_t *encoding)
|
||||
{
|
||||
u_char *p;
|
||||
|
||||
if (this->engine)
|
||||
{
|
||||
return FALSE;
|
||||
@ -481,9 +391,7 @@ METHOD(private_key_t, get_encoding, bool,
|
||||
{
|
||||
bool success = TRUE;
|
||||
|
||||
*encoding = chunk_alloc(i2d_RSAPrivateKey(this->rsa, NULL));
|
||||
p = encoding->ptr;
|
||||
i2d_RSAPrivateKey(this->rsa, &p);
|
||||
*encoding = openssl_i2chunk(PrivateKey, this->key);
|
||||
|
||||
if (type == PRIVKEY_PEM)
|
||||
{
|
||||
@ -513,10 +421,10 @@ METHOD(private_key_t, destroy, void,
|
||||
{
|
||||
if (ref_put(&this->ref))
|
||||
{
|
||||
if (this->rsa)
|
||||
if (this->key)
|
||||
{
|
||||
lib->encoding->clear_cache(lib->encoding, this->rsa);
|
||||
RSA_free(this->rsa);
|
||||
lib->encoding->clear_cache(lib->encoding, this->key);
|
||||
EVP_PKEY_free(this->key);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
@ -525,7 +433,7 @@ METHOD(private_key_t, destroy, void,
|
||||
/**
|
||||
* Internal generic constructor
|
||||
*/
|
||||
static private_openssl_rsa_private_key_t *create_empty()
|
||||
static private_openssl_rsa_private_key_t *create_internal(EVP_PKEY *key)
|
||||
{
|
||||
private_openssl_rsa_private_key_t *this;
|
||||
|
||||
@ -547,6 +455,7 @@ static private_openssl_rsa_private_key_t *create_empty()
|
||||
},
|
||||
},
|
||||
.ref = 1,
|
||||
.key = key,
|
||||
);
|
||||
|
||||
return this;
|
||||
@ -559,9 +468,9 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_gen(key_type_t type,
|
||||
va_list args)
|
||||
{
|
||||
private_openssl_rsa_private_key_t *this;
|
||||
EVP_PKEY *key = NULL;
|
||||
u_int key_size = 0;
|
||||
RSA *rsa = NULL;
|
||||
BIGNUM *e = NULL;
|
||||
BIGNUM *e;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
@ -583,29 +492,54 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_gen(key_type_t type,
|
||||
}
|
||||
e = BN_new();
|
||||
if (!e || !BN_set_word(e, PUBLIC_EXPONENT))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
rsa = RSA_new();
|
||||
if (!rsa || !RSA_generate_key_ex(rsa, key_size, e, NULL))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
this = create_empty();
|
||||
this->rsa = rsa;
|
||||
BN_free(e);
|
||||
return &this->public;
|
||||
|
||||
error:
|
||||
if (e)
|
||||
{
|
||||
BN_free(e);
|
||||
return NULL;
|
||||
}
|
||||
if (rsa)
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
/* EVP_RSA_gen() does not allow specifying the public exponent, the default
|
||||
* value is the same, but let's still use this more flexible approach */
|
||||
EVP_PKEY_CTX *ctx;
|
||||
|
||||
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
|
||||
if (!ctx ||
|
||||
EVP_PKEY_keygen_init(ctx) <= 0 ||
|
||||
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, key_size) <= 0 ||
|
||||
EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, e) <= 0 ||
|
||||
EVP_PKEY_keygen(ctx, &key) <= 0)
|
||||
{
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
#else /* OPENSSL_VERSION_NUMBER */
|
||||
RSA *rsa = RSA_new();
|
||||
|
||||
if (RSA_generate_key_ex(rsa, key_size, e, NULL))
|
||||
{
|
||||
key = EVP_PKEY_new();
|
||||
if (!EVP_PKEY_assign_RSA(key, rsa))
|
||||
{
|
||||
RSA_free(rsa);
|
||||
EVP_PKEY_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RSA_free(rsa);
|
||||
}
|
||||
return NULL;
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
if (!key)
|
||||
{
|
||||
BN_free(e);
|
||||
return NULL;
|
||||
}
|
||||
this = create_internal(key);
|
||||
BN_free(e);
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -614,16 +548,13 @@ error:
|
||||
private_key_t *openssl_rsa_private_key_create(EVP_PKEY *key, bool engine)
|
||||
{
|
||||
private_openssl_rsa_private_key_t *this;
|
||||
RSA *rsa;
|
||||
|
||||
rsa = EVP_PKEY_get1_RSA(key);
|
||||
EVP_PKEY_free(key);
|
||||
if (!rsa)
|
||||
if (EVP_PKEY_base_id(key) != EVP_PKEY_RSA)
|
||||
{
|
||||
EVP_PKEY_free(key);
|
||||
return NULL;
|
||||
}
|
||||
this = create_empty();
|
||||
this->rsa = rsa;
|
||||
this = create_internal(key);
|
||||
this->engine = engine;
|
||||
return &this->public.key;
|
||||
}
|
||||
@ -632,19 +563,13 @@ private_key_t *openssl_rsa_private_key_create(EVP_PKEY *key, bool engine)
|
||||
* Recover the primes from n, e and d using the algorithm described in
|
||||
* Appendix C of NIST SP 800-56B.
|
||||
*/
|
||||
static bool calculate_pq(BIGNUM *n, BIGNUM *e, BIGNUM *d,
|
||||
BIGNUM **p, BIGNUM **q)
|
||||
static bool calculate_pq(BN_CTX *ctx, BIGNUM *n, BIGNUM *e, BIGNUM *d,
|
||||
BIGNUM *p, BIGNUM *q)
|
||||
{
|
||||
BN_CTX *ctx;
|
||||
BIGNUM *k, *r, *g, *y, *n1, *x;
|
||||
int i, t, j;
|
||||
bool success = FALSE;
|
||||
|
||||
ctx = BN_CTX_new();
|
||||
if (!ctx)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
BN_CTX_start(ctx);
|
||||
k = BN_CTX_get(ctx);
|
||||
r = BN_CTX_get(ctx);
|
||||
@ -685,7 +610,7 @@ static bool calculate_pq(BIGNUM *n, BIGNUM *e, BIGNUM *d,
|
||||
}
|
||||
for (i = 0; i < 100; i++)
|
||||
{ /* generate random integer g in [0, n-1] */
|
||||
if (!BN_pseudo_rand_range(g, n))
|
||||
if (!BN_rand_range(g, n))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
@ -730,25 +655,19 @@ done:
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
*p = BN_secure_new();
|
||||
if (!BN_gcd(*p, y, n, ctx))
|
||||
if (!BN_gcd(p, y, n, ctx))
|
||||
{
|
||||
BN_clear_free(*p);
|
||||
goto error;
|
||||
}
|
||||
/* q = n/p */
|
||||
*q = BN_secure_new();
|
||||
if (!BN_div(*q, NULL, n, *p, ctx))
|
||||
if (!BN_div(q, NULL, n, p, ctx))
|
||||
{
|
||||
BN_clear_free(*p);
|
||||
BN_clear_free(*q);
|
||||
goto error;
|
||||
}
|
||||
success = TRUE;
|
||||
|
||||
error:
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
return success;
|
||||
}
|
||||
|
||||
@ -756,65 +675,31 @@ error:
|
||||
* Calculates dp = d (mod p-1) or dq = d (mod q-1) for the Chinese remainder
|
||||
* algorithm.
|
||||
*/
|
||||
static BIGNUM *dmodpq1(BIGNUM *d, BIGNUM *pq)
|
||||
static bool dmodpq1(BN_CTX *ctx, BIGNUM *d, BIGNUM *pq, BIGNUM *res)
|
||||
{
|
||||
BN_CTX *ctx;
|
||||
BIGNUM *res = NULL, *pq1;
|
||||
BIGNUM *pq1;
|
||||
|
||||
ctx = BN_CTX_new();
|
||||
if (!ctx)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
BN_CTX_start(ctx);
|
||||
pq1 = BN_CTX_get(ctx);
|
||||
/* p|q - 1 */
|
||||
if (!BN_sub(pq1, pq, BN_value_one()))
|
||||
/* p|q - 1
|
||||
* d (mod p|q -1) */
|
||||
if (!BN_sub(pq1, pq, BN_value_one()) ||
|
||||
!BN_mod(res, d, pq1, ctx))
|
||||
{
|
||||
goto error;
|
||||
BN_CTX_end(ctx);
|
||||
return FALSE;
|
||||
}
|
||||
/* d (mod p|q -1) */
|
||||
res = BN_secure_new();
|
||||
if (!BN_mod(res, d, pq1, ctx))
|
||||
{
|
||||
BN_clear_free(res);
|
||||
res = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
return res;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates qinv = q^-1 (mod p) for the Chinese remainder algorithm.
|
||||
*/
|
||||
static BIGNUM *qinv(BIGNUM *q, BIGNUM *p)
|
||||
static bool qinv(BN_CTX *ctx, BIGNUM *q, BIGNUM *p, BIGNUM *res)
|
||||
{
|
||||
BN_CTX *ctx;
|
||||
BIGNUM *res = NULL;
|
||||
|
||||
ctx = BN_CTX_new();
|
||||
if (!ctx)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
BN_CTX_start(ctx);
|
||||
/* q^-1 (mod p) */
|
||||
res = BN_secure_new();
|
||||
if (!BN_mod_inverse(res, q, p, ctx))
|
||||
{
|
||||
BN_clear_free(res);
|
||||
res = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
return res;
|
||||
return BN_mod_inverse(res, q, p, ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -824,6 +709,7 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_load(key_type_t type,
|
||||
va_list args)
|
||||
{
|
||||
private_openssl_rsa_private_key_t *this;
|
||||
EVP_PKEY *key = NULL;
|
||||
chunk_t blob, n, e, d, p, q, exp1, exp2, coeff;
|
||||
|
||||
blob = n = e = d = p = q = exp1 = exp2 = coeff = chunk_empty;
|
||||
@ -866,79 +752,126 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_load(key_type_t type,
|
||||
break;
|
||||
}
|
||||
|
||||
this = create_empty();
|
||||
if (blob.ptr)
|
||||
{
|
||||
this->rsa = d2i_RSAPrivateKey(NULL, (const u_char**)&blob.ptr, blob.len);
|
||||
if (this->rsa && RSA_check_key(this->rsa) == 1)
|
||||
{
|
||||
return &this->public;
|
||||
}
|
||||
key = d2i_PrivateKey(EVP_PKEY_RSA, NULL, (const u_char**)&blob.ptr,
|
||||
blob.len);
|
||||
}
|
||||
else if (n.ptr && e.ptr && d.ptr)
|
||||
{
|
||||
BIGNUM *bn_n, *bn_e, *bn_d, *bn_p, *bn_q;
|
||||
BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
|
||||
BN_CTX *ctx;
|
||||
BIGNUM *bn_n, *bn_e, *bn_d, *bn_p, *bn_q, *dmp1, *dmq1, *iqmp;
|
||||
|
||||
this->rsa = RSA_new();
|
||||
|
||||
bn_n = BN_bin2bn((const u_char*)n.ptr, n.len, NULL);
|
||||
bn_e = BN_bin2bn((const u_char*)e.ptr, e.len, NULL);
|
||||
bn_d = BN_bin2bn((const u_char*)d.ptr, d.len, NULL);
|
||||
if (!RSA_set0_key(this->rsa, bn_n, bn_e, bn_d))
|
||||
ctx = BN_CTX_secure_new();
|
||||
if (!ctx)
|
||||
{
|
||||
goto error;
|
||||
|
||||
}
|
||||
BN_CTX_start(ctx);
|
||||
bn_n = BN_CTX_get(ctx);
|
||||
bn_e = BN_CTX_get(ctx);
|
||||
bn_d = BN_CTX_get(ctx);
|
||||
bn_p = BN_CTX_get(ctx);
|
||||
bn_q = BN_CTX_get(ctx);
|
||||
dmp1 = BN_CTX_get(ctx);
|
||||
dmq1 = BN_CTX_get(ctx);
|
||||
iqmp = BN_CTX_get(ctx);
|
||||
|
||||
bn_n = BN_bin2bn((const u_char*)n.ptr, n.len, bn_n);
|
||||
bn_e = BN_bin2bn((const u_char*)e.ptr, e.len, bn_e);
|
||||
bn_d = BN_bin2bn((const u_char*)d.ptr, d.len, bn_d);
|
||||
if (p.ptr && q.ptr)
|
||||
{
|
||||
bn_p = BN_bin2bn((const u_char*)p.ptr, p.len, NULL);
|
||||
bn_q = BN_bin2bn((const u_char*)q.ptr, q.len, NULL);
|
||||
bn_p = BN_bin2bn((const u_char*)p.ptr, p.len, bn_p);
|
||||
bn_q = BN_bin2bn((const u_char*)q.ptr, q.len, bn_q);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!calculate_pq(bn_n, bn_e, bn_d, &bn_p, &bn_q))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (!RSA_set0_factors(this->rsa, bn_p, bn_q))
|
||||
else if (!calculate_pq(ctx, bn_n, bn_e, bn_d, bn_p, bn_q))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (exp1.ptr)
|
||||
{
|
||||
dmp1 = BN_bin2bn((const u_char*)exp1.ptr, exp1.len, NULL);
|
||||
dmp1 = BN_bin2bn((const u_char*)exp1.ptr, exp1.len, dmp1);
|
||||
}
|
||||
else
|
||||
else if (!dmodpq1(ctx, bn_d, bn_p, dmp1))
|
||||
{
|
||||
dmp1 = dmodpq1(bn_d, bn_p);
|
||||
goto error;
|
||||
}
|
||||
if (exp2.ptr)
|
||||
{
|
||||
dmq1 = BN_bin2bn((const u_char*)exp2.ptr, exp2.len, NULL);
|
||||
dmq1 = BN_bin2bn((const u_char*)exp2.ptr, exp2.len, dmq1);
|
||||
}
|
||||
else
|
||||
else if (!dmodpq1(ctx, bn_d, bn_q, dmq1))
|
||||
{
|
||||
dmq1 = dmodpq1(bn_d, bn_q);
|
||||
goto error;
|
||||
}
|
||||
if (coeff.ptr)
|
||||
{
|
||||
iqmp = BN_bin2bn((const u_char*)coeff.ptr, coeff.len, NULL);
|
||||
iqmp = BN_bin2bn((const u_char*)coeff.ptr, coeff.len, iqmp);
|
||||
}
|
||||
else
|
||||
else if (!qinv(ctx, bn_q, bn_p, iqmp))
|
||||
{
|
||||
iqmp = qinv(bn_q, bn_p);
|
||||
goto error;
|
||||
}
|
||||
if (RSA_set0_crt_params(this->rsa, dmp1, dmq1, iqmp) &&
|
||||
RSA_check_key(this->rsa) == 1)
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
OSSL_PARAM_BLD *bld;
|
||||
OSSL_PARAM *params = NULL;
|
||||
EVP_PKEY_CTX *pctx;
|
||||
|
||||
bld = OSSL_PARAM_BLD_new();
|
||||
if (bld &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, bn_n) &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, bn_e) &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, bn_d) &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR1, bn_p) &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR2, bn_q) &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT1, dmp1) &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT2, dmq1) &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, iqmp))
|
||||
{
|
||||
return &this->public;
|
||||
params = OSSL_PARAM_BLD_to_param(bld);
|
||||
}
|
||||
}
|
||||
OSSL_PARAM_BLD_free(bld);
|
||||
|
||||
pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
|
||||
if (!params || !pctx ||
|
||||
EVP_PKEY_fromdata_init(pctx) <= 0 ||
|
||||
EVP_PKEY_fromdata(pctx, &key, EVP_PKEY_KEYPAIR, params) <= 0)
|
||||
{
|
||||
key = NULL;
|
||||
}
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
OSSL_PARAM_free(params);
|
||||
#else /* OPENSSL_VERSION_NUMBER */
|
||||
RSA *rsa = RSA_new();
|
||||
if (!RSA_set0_key(rsa, BN_dup(bn_n), BN_dup(bn_e), BN_dup(bn_d)) ||
|
||||
!RSA_set0_factors(rsa, BN_dup(bn_p), BN_dup(bn_q)) ||
|
||||
!RSA_set0_crt_params(rsa, BN_dup(dmp1), BN_dup(dmq1), BN_dup(iqmp)) ||
|
||||
RSA_check_key(rsa) <= 0)
|
||||
{
|
||||
RSA_free(rsa);
|
||||
goto error;
|
||||
}
|
||||
key = EVP_PKEY_new();
|
||||
if (!EVP_PKEY_assign_RSA(key, rsa))
|
||||
{
|
||||
RSA_free(rsa);
|
||||
EVP_PKEY_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
error:
|
||||
destroy(this);
|
||||
return NULL;
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
if (!key)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
this = create_internal(key);
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
#endif /* OPENSSL_NO_RSA */
|
||||
|
@ -31,6 +31,11 @@
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
#include <openssl/param_build.h>
|
||||
#include <openssl/core_names.h>
|
||||
#endif
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
OPENSSL_KEY_FALLBACK(RSA, key, n, e, d)
|
||||
#endif
|
||||
@ -47,9 +52,9 @@ struct private_openssl_rsa_public_key_t {
|
||||
openssl_rsa_public_key_t public;
|
||||
|
||||
/**
|
||||
* RSA object from OpenSSL
|
||||
* RSA key object
|
||||
*/
|
||||
RSA *rsa;
|
||||
EVP_PKEY *key;
|
||||
|
||||
/**
|
||||
* reference counter
|
||||
@ -57,9 +62,6 @@ struct private_openssl_rsa_public_key_t {
|
||||
refcount_t ref;
|
||||
};
|
||||
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||
|
||||
/**
|
||||
* Verify RSA signature
|
||||
*/
|
||||
@ -69,8 +71,7 @@ static bool verify_signature(private_openssl_rsa_public_key_t *this,
|
||||
{
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_MD_CTX *mctx = NULL;
|
||||
EVP_PKEY *key;
|
||||
int rsa_size = RSA_size(this->rsa);
|
||||
int rsa_size = EVP_PKEY_size(this->key);
|
||||
bool valid = FALSE;
|
||||
|
||||
/* OpenSSL expects a signature of exactly RSA size (no leading 0x00) */
|
||||
@ -80,16 +81,11 @@ static bool verify_signature(private_openssl_rsa_public_key_t *this,
|
||||
}
|
||||
|
||||
mctx = EVP_MD_CTX_create();
|
||||
key = EVP_PKEY_new();
|
||||
if (!mctx || !key)
|
||||
if (!mctx)
|
||||
{
|
||||
goto error;
|
||||
return FALSE;
|
||||
}
|
||||
if (!EVP_PKEY_set1_RSA(key, this->rsa))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (EVP_DigestVerifyInit(mctx, &pctx, md, NULL, key) <= 0)
|
||||
if (EVP_DigestVerifyInit(mctx, &pctx, md, NULL, this->key) <= 0)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
@ -110,14 +106,7 @@ static bool verify_signature(private_openssl_rsa_public_key_t *this,
|
||||
valid = (EVP_DigestVerifyFinal(mctx, signature.ptr, signature.len) == 1);
|
||||
|
||||
error:
|
||||
if (key)
|
||||
{
|
||||
EVP_PKEY_free(key);
|
||||
}
|
||||
if (mctx)
|
||||
{
|
||||
EVP_MD_CTX_destroy(mctx);
|
||||
}
|
||||
EVP_MD_CTX_destroy(mctx);
|
||||
return valid;
|
||||
}
|
||||
|
||||
@ -128,7 +117,7 @@ static bool verify_plain_signature(private_openssl_rsa_public_key_t *this,
|
||||
chunk_t data, chunk_t signature)
|
||||
{
|
||||
char *buf;
|
||||
int len, rsa_size = RSA_size(this->rsa);
|
||||
size_t rsa_size = EVP_PKEY_size(this->key);
|
||||
bool valid = FALSE;
|
||||
|
||||
/* OpenSSL expects a signature of exactly RSA size (no leading 0x00) */
|
||||
@ -136,14 +125,39 @@ static bool verify_plain_signature(private_openssl_rsa_public_key_t *this,
|
||||
{
|
||||
signature = chunk_skip(signature, signature.len - rsa_size);
|
||||
}
|
||||
#if defined(OPENSSL_IS_BORINGSSL) && \
|
||||
(!defined(BORINGSSL_API_VERSION) || BORINGSSL_API_VERSION < 10)
|
||||
RSA *rsa = EVP_PKEY_get1_RSA(this->key);
|
||||
int len;
|
||||
|
||||
buf = malloc(rsa_size);
|
||||
len = RSA_public_decrypt(signature.len, signature.ptr, buf, this->rsa,
|
||||
len = RSA_public_decrypt(signature.len, signature.ptr, buf, rsa,
|
||||
RSA_PKCS1_PADDING);
|
||||
if (len != -1)
|
||||
{
|
||||
valid = chunk_equals_const(data, chunk_create(buf, len));
|
||||
}
|
||||
RSA_free(rsa);
|
||||
#else
|
||||
EVP_PKEY_CTX *ctx;
|
||||
size_t len = rsa_size;
|
||||
|
||||
ctx = EVP_PKEY_CTX_new(this->key, NULL);
|
||||
if (!ctx ||
|
||||
EVP_PKEY_verify_recover_init(ctx) <= 0 ||
|
||||
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
|
||||
{
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return FALSE;
|
||||
}
|
||||
buf = malloc(rsa_size);
|
||||
if (EVP_PKEY_verify_recover(ctx, buf, &len, signature.ptr, signature.len) > 0)
|
||||
{
|
||||
valid = chunk_equals_const(data, chunk_create(buf, len));
|
||||
}
|
||||
free(buf);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
#endif
|
||||
return valid;
|
||||
}
|
||||
|
||||
@ -180,85 +194,6 @@ static bool verify_emsa_pss_signature(private_openssl_rsa_public_key_t *this,
|
||||
return md && verify_signature(this, md, params, data, signature);
|
||||
}
|
||||
|
||||
#else /* OPENSSL_VERSION_NUMBER < 1.0 */
|
||||
|
||||
/**
|
||||
* Verification of an EMSA PKCS1 signature described in PKCS#1
|
||||
*/
|
||||
static bool verify_emsa_pkcs1_signature(private_openssl_rsa_public_key_t *this,
|
||||
int type, chunk_t data, chunk_t signature)
|
||||
{
|
||||
bool valid = FALSE;
|
||||
int rsa_size = RSA_size(this->rsa);
|
||||
|
||||
/* OpenSSL expects a signature of exactly RSA size (no leading 0x00) */
|
||||
if (signature.len > rsa_size)
|
||||
{
|
||||
signature = chunk_skip(signature, signature.len - rsa_size);
|
||||
}
|
||||
|
||||
if (type == NID_undef)
|
||||
{
|
||||
char *buf;
|
||||
int len;
|
||||
|
||||
buf = malloc(rsa_size);
|
||||
len = RSA_public_decrypt(signature.len, signature.ptr, buf, this->rsa,
|
||||
RSA_PKCS1_PADDING);
|
||||
if (len != -1)
|
||||
{
|
||||
valid = chunk_equals_const(data, chunk_create(buf, len));
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
EVP_PKEY *key;
|
||||
const EVP_MD *hasher;
|
||||
|
||||
hasher = EVP_get_digestbynid(type);
|
||||
if (!hasher)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ctx = EVP_MD_CTX_create();
|
||||
key = EVP_PKEY_new();
|
||||
|
||||
if (!ctx || !key)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (!EVP_PKEY_set1_RSA(key, this->rsa))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (!EVP_VerifyInit_ex(ctx, hasher, NULL))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (!EVP_VerifyUpdate(ctx, data.ptr, data.len))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
valid = (EVP_VerifyFinal(ctx, signature.ptr, signature.len, key) == 1);
|
||||
|
||||
error:
|
||||
if (key)
|
||||
{
|
||||
EVP_PKEY_free(key);
|
||||
}
|
||||
if (ctx)
|
||||
{
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
#endif /* OPENSSL_VERSION_NUMBER < 1.0 */
|
||||
|
||||
METHOD(public_key_t, get_type, key_type_t,
|
||||
private_openssl_rsa_public_key_t *this)
|
||||
{
|
||||
@ -295,10 +230,8 @@ METHOD(public_key_t, verify, bool,
|
||||
return verify_emsa_pkcs1_signature(this, NID_sha1, data, signature);
|
||||
case SIGN_RSA_EMSA_PKCS1_MD5:
|
||||
return verify_emsa_pkcs1_signature(this, NID_md5, data, signature);
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||
case SIGN_RSA_EMSA_PSS:
|
||||
return verify_emsa_pss_signature(this, params, data, signature);
|
||||
#endif
|
||||
default:
|
||||
DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
|
||||
signature_scheme_names, scheme);
|
||||
@ -311,7 +244,6 @@ METHOD(public_key_t, encrypt, bool,
|
||||
void *params, chunk_t plain, chunk_t *crypto)
|
||||
{
|
||||
EVP_PKEY_CTX *ctx = NULL;
|
||||
EVP_PKEY *evp_key = NULL;
|
||||
chunk_t label = chunk_empty;
|
||||
hash_algorithm_t hash_alg = HASH_UNKNOWN;
|
||||
size_t len;
|
||||
@ -350,23 +282,11 @@ METHOD(public_key_t, encrypt, bool,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
evp_key = EVP_PKEY_new();
|
||||
if (!evp_key)
|
||||
{
|
||||
DBG1(DBG_LIB, "could not create EVP key");
|
||||
goto error;
|
||||
}
|
||||
if (EVP_PKEY_set1_RSA(evp_key, this->rsa) <= 0)
|
||||
{
|
||||
DBG1(DBG_LIB, "could not set EVP key to RSA key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ctx = EVP_PKEY_CTX_new(evp_key, NULL);
|
||||
ctx = EVP_PKEY_CTX_new(this->key, NULL);
|
||||
if (!ctx)
|
||||
{
|
||||
DBG1(DBG_LIB, "could not create EVP context");
|
||||
goto error;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_encrypt_init(ctx) <= 0)
|
||||
@ -411,7 +331,7 @@ METHOD(public_key_t, encrypt, bool,
|
||||
}
|
||||
|
||||
/* determine maximum ciphertext size */
|
||||
len = RSA_size(this->rsa);
|
||||
len = EVP_PKEY_size(this->key);
|
||||
encrypted = malloc(len);
|
||||
|
||||
/* decrypt data */
|
||||
@ -425,78 +345,78 @@ METHOD(public_key_t, encrypt, bool,
|
||||
success = TRUE;
|
||||
|
||||
error:
|
||||
if (ctx)
|
||||
{
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
}
|
||||
if (evp_key)
|
||||
{
|
||||
EVP_PKEY_free(evp_key);
|
||||
}
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return success;
|
||||
}
|
||||
|
||||
METHOD(public_key_t, get_keysize, int,
|
||||
private_openssl_rsa_public_key_t *this)
|
||||
{
|
||||
return RSA_size(this->rsa) * 8;
|
||||
return EVP_PKEY_bits(this->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get n and e of the given RSA key (allocated).
|
||||
*/
|
||||
static bool get_n_and_e(EVP_PKEY *key, chunk_t *n, chunk_t *e)
|
||||
{
|
||||
const BIGNUM *cbn_n, *cbn_e;
|
||||
BIGNUM *bn_n = NULL, *bn_e = NULL;
|
||||
bool success = FALSE;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
if (EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_RSA_N, &bn_n) <= 0 ||
|
||||
EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_RSA_E, &bn_e) <= 0)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
cbn_n = bn_n;
|
||||
cbn_e = bn_e;
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x1010000fL
|
||||
RSA *rsa = EVP_PKEY_get0_RSA(key);
|
||||
RSA_get0_key(rsa, &cbn_n, &cbn_e, NULL);
|
||||
#else
|
||||
RSA *rsa = EVP_PKEY_get1_RSA(key);
|
||||
RSA_get0_key(rsa, &cbn_n, &cbn_e, NULL);
|
||||
RSA_free(rsa);
|
||||
#endif
|
||||
|
||||
*n = *e = chunk_empty;
|
||||
if (!openssl_bn2chunk(cbn_n, n) ||
|
||||
!openssl_bn2chunk(cbn_e, e))
|
||||
{
|
||||
chunk_free(n);
|
||||
chunk_free(e);
|
||||
goto error;
|
||||
}
|
||||
success = TRUE;
|
||||
|
||||
error:
|
||||
BN_free(bn_n);
|
||||
BN_free(bn_e);
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate fingerprint from a RSA key, also used in rsa private key.
|
||||
*/
|
||||
bool openssl_rsa_fingerprint(RSA *rsa, cred_encoding_type_t type, chunk_t *fp)
|
||||
bool openssl_rsa_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, chunk_t *fp)
|
||||
{
|
||||
hasher_t *hasher;
|
||||
chunk_t key;
|
||||
u_char *p;
|
||||
if (!openssl_fingerprint(key, type, fp))
|
||||
{
|
||||
chunk_t n = chunk_empty, e = chunk_empty;
|
||||
bool success = FALSE;
|
||||
|
||||
if (lib->encoding->get_cache(lib->encoding, type, rsa, fp))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case KEYID_PUBKEY_SHA1:
|
||||
key = chunk_alloc(i2d_RSAPublicKey(rsa, NULL));
|
||||
p = key.ptr;
|
||||
i2d_RSAPublicKey(rsa, &p);
|
||||
break;
|
||||
case KEYID_PUBKEY_INFO_SHA1:
|
||||
key = chunk_alloc(i2d_RSA_PUBKEY(rsa, NULL));
|
||||
p = key.ptr;
|
||||
i2d_RSA_PUBKEY(rsa, &p);
|
||||
break;
|
||||
default:
|
||||
if (get_n_and_e(key, &n, &e))
|
||||
{
|
||||
const BIGNUM *bn_n, *bn_e;
|
||||
chunk_t n = chunk_empty, e = chunk_empty;
|
||||
bool success = FALSE;
|
||||
|
||||
RSA_get0_key(rsa, &bn_n, &bn_e, NULL);
|
||||
if (openssl_bn2chunk(bn_n, &n) &&
|
||||
openssl_bn2chunk(bn_e, &e))
|
||||
{
|
||||
success = lib->encoding->encode(lib->encoding, type, rsa, fp,
|
||||
success = lib->encoding->encode(lib->encoding, type, key, fp,
|
||||
CRED_PART_RSA_MODULUS, n,
|
||||
CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
|
||||
}
|
||||
chunk_free(&n);
|
||||
chunk_free(&e);
|
||||
return success;
|
||||
}
|
||||
chunk_free(&n);
|
||||
chunk_free(&e);
|
||||
return success;
|
||||
}
|
||||
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
|
||||
if (!hasher || !hasher->allocate_hash(hasher, key, fp))
|
||||
{
|
||||
DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed");
|
||||
DESTROY_IF(hasher);
|
||||
free(key.ptr);
|
||||
return FALSE;
|
||||
}
|
||||
free(key.ptr);
|
||||
hasher->destroy(hasher);
|
||||
lib->encoding->cache(lib->encoding, type, rsa, *fp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -504,7 +424,7 @@ METHOD(public_key_t, get_fingerprint, bool,
|
||||
private_openssl_rsa_public_key_t *this, cred_encoding_type_t type,
|
||||
chunk_t *fingerprint)
|
||||
{
|
||||
return openssl_rsa_fingerprint(this->rsa, type, fingerprint);
|
||||
return openssl_rsa_fingerprint(this->key, type, fingerprint);
|
||||
}
|
||||
|
||||
METHOD(public_key_t, get_encoding, bool,
|
||||
@ -512,16 +432,13 @@ METHOD(public_key_t, get_encoding, bool,
|
||||
chunk_t *encoding)
|
||||
{
|
||||
bool success = FALSE;
|
||||
u_char *p;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case PUBKEY_SPKI_ASN1_DER:
|
||||
case PUBKEY_PEM:
|
||||
{
|
||||
*encoding = chunk_alloc(i2d_RSA_PUBKEY(this->rsa, NULL));
|
||||
p = encoding->ptr;
|
||||
i2d_RSA_PUBKEY(this->rsa, &p);
|
||||
*encoding = openssl_i2chunk(PUBKEY, this->key);
|
||||
success = TRUE;
|
||||
|
||||
if (type == PUBKEY_PEM)
|
||||
@ -537,19 +454,14 @@ METHOD(public_key_t, get_encoding, bool,
|
||||
}
|
||||
case PUBKEY_ASN1_DER:
|
||||
{
|
||||
*encoding = chunk_alloc(i2d_RSAPublicKey(this->rsa, NULL));
|
||||
p = encoding->ptr;
|
||||
i2d_RSAPublicKey(this->rsa, &p);
|
||||
*encoding = openssl_i2chunk(PublicKey, this->key);
|
||||
return TRUE;
|
||||
}
|
||||
default:
|
||||
{
|
||||
const BIGNUM *bn_n, *bn_e;
|
||||
chunk_t n = chunk_empty, e = chunk_empty;
|
||||
|
||||
RSA_get0_key(this->rsa, &bn_n, &bn_e, NULL);
|
||||
if (openssl_bn2chunk(bn_n, &n) &&
|
||||
openssl_bn2chunk(bn_e, &e))
|
||||
if (get_n_and_e(this->key, &n, &e))
|
||||
{
|
||||
success = lib->encoding->encode(lib->encoding, type, NULL,
|
||||
encoding, CRED_PART_RSA_MODULUS, n,
|
||||
@ -574,10 +486,10 @@ METHOD(public_key_t, destroy, void,
|
||||
{
|
||||
if (ref_put(&this->ref))
|
||||
{
|
||||
if (this->rsa)
|
||||
if (this->key)
|
||||
{
|
||||
lib->encoding->clear_cache(lib->encoding, this->rsa);
|
||||
RSA_free(this->rsa);
|
||||
lib->encoding->clear_cache(lib->encoding, this->key);
|
||||
EVP_PKEY_free(this->key);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
@ -586,7 +498,7 @@ METHOD(public_key_t, destroy, void,
|
||||
/**
|
||||
* Generic private constructor
|
||||
*/
|
||||
static private_openssl_rsa_public_key_t *create_empty()
|
||||
static private_openssl_rsa_public_key_t *create_internal(EVP_PKEY *key)
|
||||
{
|
||||
private_openssl_rsa_public_key_t *this;
|
||||
|
||||
@ -606,6 +518,7 @@ static private_openssl_rsa_public_key_t *create_empty()
|
||||
},
|
||||
},
|
||||
.ref = 1,
|
||||
.key = key,
|
||||
);
|
||||
|
||||
return this;
|
||||
@ -618,6 +531,7 @@ openssl_rsa_public_key_t *openssl_rsa_public_key_load(key_type_t type,
|
||||
va_list args)
|
||||
{
|
||||
private_openssl_rsa_public_key_t *this;
|
||||
EVP_PKEY *key = NULL;
|
||||
chunk_t blob, n, e;
|
||||
|
||||
n = e = blob = chunk_empty;
|
||||
@ -642,41 +556,98 @@ openssl_rsa_public_key_t *openssl_rsa_public_key_load(key_type_t type,
|
||||
break;
|
||||
}
|
||||
|
||||
this = create_empty();
|
||||
if (blob.ptr)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case KEY_ANY:
|
||||
this->rsa = d2i_RSA_PUBKEY(NULL, (const u_char**)&blob.ptr,
|
||||
blob.len);
|
||||
key = d2i_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len);
|
||||
if (key && EVP_PKEY_base_id(key) != EVP_PKEY_RSA)
|
||||
{
|
||||
EVP_PKEY_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
break;
|
||||
case KEY_RSA:
|
||||
this->rsa = d2i_RSAPublicKey(NULL, (const u_char**)&blob.ptr,
|
||||
blob.len);
|
||||
#if defined(OPENSSL_IS_BORINGSSL) && \
|
||||
(!defined(BORINGSSL_API_VERSION) || BORINGSSL_API_VERSION < 10)
|
||||
{
|
||||
RSA *rsa = d2i_RSAPublicKey(NULL, (const u_char**)&blob.ptr,
|
||||
blob.len);
|
||||
key = EVP_PKEY_new();
|
||||
if (!key || !EVP_PKEY_assign_RSA(key, rsa))
|
||||
{
|
||||
RSA_free(rsa);
|
||||
EVP_PKEY_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
key = d2i_PublicKey(EVP_PKEY_RSA, NULL, (const u_char**)&blob.ptr,
|
||||
blob.len);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (this->rsa)
|
||||
{
|
||||
return &this->public;
|
||||
}
|
||||
}
|
||||
else if (n.ptr && e.ptr && type == KEY_RSA)
|
||||
{
|
||||
BIGNUM *bn_n, *bn_e;
|
||||
|
||||
this->rsa = RSA_new();
|
||||
bn_n = BN_bin2bn((const u_char*)n.ptr, n.len, NULL);
|
||||
bn_e = BN_bin2bn((const u_char*)e.ptr, e.len, NULL);
|
||||
if (RSA_set0_key(this->rsa, bn_n, bn_e, NULL))
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
OSSL_PARAM_BLD *bld;
|
||||
OSSL_PARAM *params = NULL;
|
||||
EVP_PKEY_CTX *ctx;
|
||||
|
||||
bld = OSSL_PARAM_BLD_new();
|
||||
if (bld &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, bn_n) &&
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, bn_e))
|
||||
{
|
||||
return &this->public;
|
||||
params = OSSL_PARAM_BLD_to_param(bld);
|
||||
}
|
||||
OSSL_PARAM_BLD_free(bld);
|
||||
BN_free(bn_n);
|
||||
BN_free(bn_e);
|
||||
|
||||
ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
|
||||
if (!params || !ctx ||
|
||||
EVP_PKEY_fromdata_init(ctx) <= 0 ||
|
||||
EVP_PKEY_fromdata(ctx, &key, EVP_PKEY_PUBLIC_KEY, params) <= 0)
|
||||
{
|
||||
key = NULL;
|
||||
}
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OSSL_PARAM_free(params);
|
||||
#else /* OPENSSL_VERSION_NUMBER */
|
||||
RSA *rsa = RSA_new();
|
||||
|
||||
if (RSA_set0_key(rsa, bn_n, bn_e, NULL))
|
||||
{
|
||||
key = EVP_PKEY_new();
|
||||
if (!key || !EVP_PKEY_assign_RSA(key, rsa))
|
||||
{
|
||||
RSA_free(rsa);
|
||||
EVP_PKEY_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RSA_free(rsa);
|
||||
}
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
}
|
||||
destroy(this);
|
||||
return NULL;
|
||||
if (!key)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
this = create_internal(key);
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
#endif /* OPENSSL_NO_RSA */
|
||||
|
@ -13,9 +13,15 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/* direct access to the state and the SHA1_* API have been deprecated with
|
||||
* OpenSSL 3, so at some point this won't work anymore */
|
||||
#define OPENSSL_SUPPRESS_DEPRECATED
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/opensslconf.h>
|
||||
|
||||
#ifndef OPENSSL_NO_SHA1
|
||||
#if !defined(OPENSSL_NO_SHA1) && \
|
||||
(OPENSSL_VERSION_NUMBER < 0x30000000L || !defined(OPENSSL_NO_DEPRECATED))
|
||||
|
||||
#include "openssl_sha1_prf.h"
|
||||
|
||||
@ -43,14 +49,10 @@ struct private_openssl_sha1_prf_t {
|
||||
METHOD(prf_t, get_bytes, bool,
|
||||
private_openssl_sha1_prf_t *this, chunk_t seed, uint8_t *bytes)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||
if (!SHA1_Update(&this->ctx, seed.ptr, seed.len))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
#else /* OPENSSL_VERSION_NUMBER < 1.0 */
|
||||
SHA1_Update(&this->ctx, seed.ptr, seed.len);
|
||||
#endif
|
||||
|
||||
if (bytes)
|
||||
{
|
||||
@ -92,14 +94,10 @@ METHOD(prf_t, get_key_size, size_t,
|
||||
METHOD(prf_t, set_key, bool,
|
||||
private_openssl_sha1_prf_t *this, chunk_t key)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||
if (!SHA1_Init(&this->ctx))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
#else /* OPENSSL_VERSION_NUMBER < 1.0 */
|
||||
SHA1_Init(&this->ctx);
|
||||
#endif
|
||||
|
||||
if (key.len % 4)
|
||||
{
|
||||
@ -162,4 +160,4 @@ openssl_sha1_prf_t *openssl_sha1_prf_create(pseudo_random_function_t algo)
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
#endif /* OPENSSL_NO_SHA1 */
|
||||
#endif /* !OPENSSL_NO_SHA1 && SHA_LONG */
|
||||
|
@ -22,6 +22,11 @@
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
/* for EVP_PKEY_CTX_set_dh_pad */
|
||||
#include <openssl/dh.h>
|
||||
#endif
|
||||
|
||||
/* these were added with 1.1.0 when ASN1_OBJECT was made opaque */
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
#define OBJ_get0_data(o) ((o)->data)
|
||||
@ -48,6 +53,14 @@ bool openssl_compute_shared_key(EVP_PKEY *priv, EVP_PKEY *pub, chunk_t *shared)
|
||||
goto error;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
if (EVP_PKEY_base_id(priv) == EVP_PKEY_DH &&
|
||||
EVP_PKEY_CTX_set_dh_pad(ctx, 1) <= 0)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (EVP_PKEY_derive_set_peer(ctx, pub) <= 0)
|
||||
{
|
||||
goto error;
|
||||
@ -62,6 +75,7 @@ bool openssl_compute_shared_key(EVP_PKEY *priv, EVP_PKEY *pub, chunk_t *shared)
|
||||
|
||||
if (EVP_PKEY_derive(ctx, shared->ptr, &shared->len) <= 0)
|
||||
{
|
||||
chunk_clear(shared);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -72,6 +86,48 @@ error:
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
bool openssl_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, chunk_t *fp)
|
||||
{
|
||||
hasher_t *hasher;
|
||||
chunk_t enc;
|
||||
u_char *p;
|
||||
|
||||
if (lib->encoding->get_cache(lib->encoding, type, key, fp))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case KEYID_PUBKEY_SHA1:
|
||||
enc = chunk_alloc(i2d_PublicKey(key, NULL));
|
||||
p = enc.ptr;
|
||||
i2d_PublicKey(key, &p);
|
||||
break;
|
||||
case KEYID_PUBKEY_INFO_SHA1:
|
||||
enc = chunk_alloc(i2d_PUBKEY(key, NULL));
|
||||
p = enc.ptr;
|
||||
i2d_PUBKEY(key, &p);
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
|
||||
if (!hasher || !hasher->allocate_hash(hasher, enc, fp))
|
||||
{
|
||||
DBG1(DBG_LIB, "SHA1 not supported, fingerprinting failed");
|
||||
DESTROY_IF(hasher);
|
||||
free(enc.ptr);
|
||||
return FALSE;
|
||||
}
|
||||
free(enc.ptr);
|
||||
hasher->destroy(hasher);
|
||||
lib->encoding->cache(lib->encoding, type, key, *fp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
|
@ -46,6 +46,16 @@
|
||||
*/
|
||||
bool openssl_compute_shared_key(EVP_PKEY *priv, EVP_PKEY *pub, chunk_t *shared);
|
||||
|
||||
/**
|
||||
* Calculate a fingerprint from the given key (cached under it).
|
||||
*
|
||||
* @param key key object
|
||||
* @param type encoding type
|
||||
* @param fp allocated fingerprint
|
||||
* @return TRUE on success, FALSE otherwise
|
||||
*/
|
||||
bool openssl_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, chunk_t *fp);
|
||||
|
||||
/**
|
||||
* Creates a hash of a given type of a chunk of data.
|
||||
*
|
||||
|
@ -45,15 +45,15 @@ struct private_diffie_hellman_t {
|
||||
*/
|
||||
EVP_PKEY *key;
|
||||
|
||||
/**
|
||||
* Public key provided by peer
|
||||
*/
|
||||
EVP_PKEY *pub;
|
||||
|
||||
/**
|
||||
* Shared secret
|
||||
*/
|
||||
chunk_t shared_secret;
|
||||
|
||||
/**
|
||||
* True if shared secret is computed
|
||||
*/
|
||||
bool computed;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -75,33 +75,21 @@ static int map_key_type(diffie_hellman_group_t group)
|
||||
METHOD(diffie_hellman_t, set_other_public_value, bool,
|
||||
private_diffie_hellman_t *this, chunk_t value)
|
||||
{
|
||||
EVP_PKEY *pub;
|
||||
|
||||
if (!diffie_hellman_verify_value(this->group, value))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pub = EVP_PKEY_new_raw_public_key(map_key_type(this->group), NULL,
|
||||
value.ptr, value.len);
|
||||
if (!pub)
|
||||
EVP_PKEY_free(this->pub);
|
||||
this->pub = EVP_PKEY_new_raw_public_key(map_key_type(this->group), NULL,
|
||||
value.ptr, value.len);
|
||||
if (!this->pub)
|
||||
{
|
||||
DBG1(DBG_LIB, "%N public value is malformed",
|
||||
diffie_hellman_group_names, this->group);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
chunk_clear(&this->shared_secret);
|
||||
|
||||
if (!openssl_compute_shared_key(this->key, pub, &this->shared_secret))
|
||||
{
|
||||
DBG1(DBG_LIB, "%N shared secret computation failed",
|
||||
diffie_hellman_group_names, this->group);
|
||||
EVP_PKEY_free(pub);
|
||||
return FALSE;
|
||||
}
|
||||
this->computed = TRUE;
|
||||
EVP_PKEY_free(pub);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -141,8 +129,11 @@ METHOD(diffie_hellman_t, set_private_value, bool,
|
||||
METHOD(diffie_hellman_t, get_shared_secret, bool,
|
||||
private_diffie_hellman_t *this, chunk_t *secret)
|
||||
{
|
||||
if (!this->computed)
|
||||
if (!this->shared_secret.len &&
|
||||
!openssl_compute_shared_key(this->key, this->pub, &this->shared_secret))
|
||||
{
|
||||
DBG1(DBG_LIB, "%N shared secret computation failed",
|
||||
diffie_hellman_group_names, this->group);
|
||||
return FALSE;
|
||||
}
|
||||
*secret = chunk_clone(this->shared_secret);
|
||||
@ -159,6 +150,7 @@ METHOD(diffie_hellman_t, destroy, void,
|
||||
private_diffie_hellman_t *this)
|
||||
{
|
||||
EVP_PKEY_free(this->key);
|
||||
EVP_PKEY_free(this->pub);
|
||||
chunk_clear(&this->shared_secret);
|
||||
free(this);
|
||||
}
|
||||
|
@ -124,7 +124,8 @@ end:
|
||||
* Try to decrypt the given blob with multiple passwords using the given
|
||||
* pkcs5 object.
|
||||
*/
|
||||
static private_key_t *decrypt_private_key(pkcs5_t *pkcs5, chunk_t blob)
|
||||
static private_key_t *decrypt_private_key(key_type_t type, pkcs5_t *pkcs5,
|
||||
chunk_t blob)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
shared_key_t *shared;
|
||||
@ -140,7 +141,15 @@ static private_key_t *decrypt_private_key(pkcs5_t *pkcs5, chunk_t blob)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
private_key = parse_private_key(decrypted);
|
||||
/* do a quick check to validate whether the password was correct */
|
||||
if (!is_asn1(decrypted))
|
||||
{
|
||||
chunk_clear(&decrypted);
|
||||
continue;
|
||||
}
|
||||
private_key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
|
||||
type, BUILD_BLOB_ASN1_DER,
|
||||
decrypted, BUILD_END);
|
||||
if (private_key)
|
||||
{
|
||||
chunk_clear(&decrypted);
|
||||
@ -169,7 +178,7 @@ static const asn1Object_t encryptedPKIObjects[] = {
|
||||
* Load an encrypted private key from an ASN.1 encoded blob
|
||||
* Schemes per PKCS#5 (RFC 2898)
|
||||
*/
|
||||
static private_key_t *parse_encrypted_private_key(chunk_t blob)
|
||||
static private_key_t *parse_encrypted_private_key(key_type_t type, chunk_t blob)
|
||||
{
|
||||
asn1_parser_t *parser;
|
||||
chunk_t object;
|
||||
@ -195,7 +204,7 @@ static private_key_t *parse_encrypted_private_key(chunk_t blob)
|
||||
}
|
||||
case EPKINFO_ENCRYPTED_DATA:
|
||||
{
|
||||
key = decrypt_private_key(pkcs5, object);
|
||||
key = decrypt_private_key(type, pkcs5, object);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -230,7 +239,7 @@ private_key_t *pkcs8_private_key_load(key_type_t type, va_list args)
|
||||
break;
|
||||
}
|
||||
/* we don't know whether it is encrypted or not, try both ways */
|
||||
key = parse_encrypted_private_key(blob);
|
||||
key = parse_encrypted_private_key(type, blob);
|
||||
if (!key)
|
||||
{
|
||||
key = parse_private_key(blob);
|
||||
|
@ -177,6 +177,7 @@ END_TEST
|
||||
static struct {
|
||||
chunk_t key;
|
||||
chunk_t pkcs8;
|
||||
chunk_t spki;
|
||||
chunk_t pub;
|
||||
chunk_t fp_pk;
|
||||
chunk_t fp_spki;
|
||||
@ -252,6 +253,14 @@ static struct {
|
||||
0x4c,0xa9,0xa2,0x42,0xbe,0xdd,0xdb,0xf7,0xd3,0x28,0x07,0x10,0x88,0x53,0x15,0xb2,
|
||||
0x4f,0xb5,0x9d,0x47,0x9b,0xd6,0xc8,0xfe,0x5b,0xa2,0xd7,0xe1,0x13,0xca,0x0b,0xce,
|
||||
0x7a,0xed,0xa2,0x3e,0xd5,0x9b,0xb8,0x8b,0x4f,0x02,0x03,0x01,0x00,0x01),
|
||||
chunk_from_chars(
|
||||
0x30,0x68,0x02,0x61,0x00,0xd1,0x5d,0x98,0x97,0x95,0x98,0x19,0x87,0x20,0x3f,0x10,
|
||||
0xb0,0x05,0x36,0x1e,0x1b,0xcd,0xc8,0x93,0x66,0xd7,0x43,0xed,0x84,0xb0,0x3e,0x96,
|
||||
0xd3,0xe7,0x27,0x0e,0xc0,0xba,0xdf,0x7e,0x32,0x05,0xd3,0x08,0xd6,0x44,0xd5,0x01,
|
||||
0x2b,0x3e,0x5d,0xc0,0x37,0xae,0x4f,0xe0,0xea,0x8d,0x2c,0x42,0x4c,0xa9,0xa2,0x42,
|
||||
0xbe,0xdd,0xdb,0xf7,0xd3,0x28,0x07,0x10,0x88,0x53,0x15,0xb2,0x4f,0xb5,0x9d,0x47,
|
||||
0x9b,0xd6,0xc8,0xfe,0x5b,0xa2,0xd7,0xe1,0x13,0xca,0x0b,0xce,0x7a,0xed,0xa2,0x3e,
|
||||
0xd5,0x9b,0xb8,0x8b,0x4f,0x02,0x03,0x01,0x00,0x01),
|
||||
chunk_from_chars(
|
||||
0x06,0xad,0x82,0xc3,0x58,0x22,0xbb,0x79,0xb5,0xfc,0x48,0xdb,0xa0,0x3c,0x39,0x60,
|
||||
0x00,0x85,0x06,0xca),
|
||||
@ -351,6 +360,16 @@ static struct {
|
||||
0xb8,0x9d,0x07,0x84,0x03,0x68,0x6b,0x9f,0xbf,0xe5,0xd8,0x14,0x2a,0xe0,0xef,0xbd,
|
||||
0x1a,0x61,0x0d,0x3a,0xc8,0x67,0xcd,0x99,0x90,0xe3,0xe6,0x52,0x83,0x02,0x03,0x01,
|
||||
0x00,0x01),
|
||||
chunk_from_chars(
|
||||
0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xc0,0xbd,0x48,0x83,0xbc,0xea,0x0b,0x32,0x06,
|
||||
0x4b,0xf5,0x10,0x54,0x1b,0xba,0x88,0xc4,0x10,0x7e,0x47,0xec,0x0e,0xf9,0xb4,0xcf,
|
||||
0x9a,0x02,0xc6,0xb3,0xaf,0x35,0xc8,0xaf,0x78,0x1a,0xbc,0x37,0x1a,0x25,0x7a,0x37,
|
||||
0x24,0x73,0x53,0x9a,0xf0,0x44,0x64,0x5b,0x6b,0x64,0x4c,0xfa,0x83,0x3a,0x0f,0x77,
|
||||
0x5d,0x7b,0x21,0xa2,0x25,0x00,0x11,0xae,0x72,0x36,0x35,0xd9,0x0d,0xef,0x5a,0xdd,
|
||||
0x98,0x35,0x49,0xaf,0x44,0xa0,0x33,0x29,0xc0,0xca,0xf5,0x6f,0xfe,0xc1,0x06,0x4c,
|
||||
0x80,0x9a,0x54,0xbe,0x46,0x1a,0x96,0xb1,0xf3,0x29,0xb8,0x9d,0x07,0x84,0x03,0x68,
|
||||
0x6b,0x9f,0xbf,0xe5,0xd8,0x14,0x2a,0xe0,0xef,0xbd,0x1a,0x61,0x0d,0x3a,0xc8,0x67,
|
||||
0xcd,0x99,0x90,0xe3,0xe6,0x52,0x83,0x02,0x03,0x01,0x00,0x01),
|
||||
chunk_from_chars(
|
||||
0xda,0xab,0x50,0x22,0x4b,0x4f,0x3b,0xd0,0x82,0xc4,0xa4,0x14,0x06,0x64,0x0b,0x6f,
|
||||
0xad,0xbc,0x69,0xc0),
|
||||
@ -491,6 +510,20 @@ static struct {
|
||||
0x91,0xe2,0xfc,0x7b,0xea,0xb0,0x89,0x24,0xaa,0x00,0x29,0x8c,0x26,0x7c,0x94,0x54,
|
||||
0x74,0xe4,0x11,0xa8,0x04,0x6f,0x40,0xeb,0xaf,0xed,0xac,0x75,0x33,0x02,0x03,0x01,
|
||||
0x00,0x01),
|
||||
chunk_from_chars(
|
||||
0x30,0x81,0xc9,0x02,0x81,0xc1,0x00,0xba,0xe3,0x37,0x93,0x7e,0x42,0x13,0x3c,0xba,
|
||||
0x41,0xc1,0x7b,0xf0,0xcc,0x7a,0x44,0xc6,0x54,0xc8,0x77,0x01,0x70,0x2f,0x6e,0x4a,
|
||||
0xcf,0x2d,0x07,0xab,0x01,0xc0,0x43,0xab,0x8d,0x33,0xb3,0xd4,0xeb,0xe3,0x90,0xf6,
|
||||
0x01,0x03,0x75,0x03,0x1d,0xe8,0x06,0x40,0x15,0xfa,0x96,0x0b,0xd5,0x26,0x64,0xea,
|
||||
0x55,0x82,0x16,0x7b,0xd5,0x1e,0xaa,0x08,0xc7,0x30,0x1a,0x59,0xf8,0xd9,0xe3,0x9e,
|
||||
0x89,0xd9,0x92,0x2c,0x32,0x79,0x0e,0xb3,0x25,0xbc,0x1d,0x7c,0x59,0xde,0x05,0x47,
|
||||
0x8f,0x61,0x77,0xf5,0x4f,0xed,0x82,0x2c,0xf8,0x2a,0x3e,0x02,0xf3,0xc0,0x15,0x51,
|
||||
0xde,0x05,0xc4,0xfc,0x80,0x91,0xae,0x06,0x1b,0xd7,0x39,0x8e,0x9a,0x6d,0xb3,0x2f,
|
||||
0xb0,0xd0,0xc8,0x96,0xa6,0x88,0xb3,0x17,0xca,0x58,0xbe,0x38,0x2c,0x64,0x35,0x5a,
|
||||
0x29,0xb7,0xf8,0x74,0x3d,0xbb,0xec,0x90,0x01,0x04,0x64,0x3d,0x38,0x0f,0x87,0xce,
|
||||
0xd7,0xfc,0xd2,0x96,0x93,0x31,0x85,0x0d,0x2d,0xa5,0x91,0xe2,0xfc,0x7b,0xea,0xb0,
|
||||
0x89,0x24,0xaa,0x00,0x29,0x8c,0x26,0x7c,0x94,0x54,0x74,0xe4,0x11,0xa8,0x04,0x6f,
|
||||
0x40,0xeb,0xaf,0xed,0xac,0x75,0x33,0x02,0x03,0x01,0x00,0x01),
|
||||
chunk_from_chars(
|
||||
0x21,0x00,0x8c,0xe1,0x78,0x25,0x67,0x19,0xb7,0xd0,0xcb,0x13,0x01,0x7a,0xa3,0x71,
|
||||
0x67,0x46,0x96,0xf1),
|
||||
@ -671,6 +704,24 @@ static struct {
|
||||
0xde,0x54,0x7d,0x95,0xd6,0x4e,0x58,0x12,0x06,0x60,0x22,0x33,0xf2,0x19,0x67,0x65,
|
||||
0xdd,0xf3,0x42,0xb5,0x00,0x51,0x35,0xe5,0x62,0x4d,0x90,0x44,0xfb,0x7f,0x5b,0xb5,
|
||||
0xe5,0x02,0x03,0x01,0x00,0x01),
|
||||
chunk_from_chars(
|
||||
0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xba,0xbf,0x27,0x0b,0x22,0x59,0xd8,
|
||||
0x6f,0xff,0x26,0x5d,0x41,0x3d,0xb0,0x94,0x58,0x5d,0xc0,0x46,0xb6,0x77,0xa9,0x78,
|
||||
0x10,0x6d,0xe9,0xbf,0xca,0x6f,0x04,0xe1,0xda,0x85,0x12,0x1e,0xe0,0xa6,0xc7,0xa2,
|
||||
0x71,0x04,0x8b,0x6e,0x84,0xf9,0x86,0x2b,0xeb,0x72,0x01,0x72,0xc8,0x0a,0x83,0xa6,
|
||||
0xf7,0xc0,0xd6,0x76,0x1d,0x28,0x38,0xb5,0x7e,0x6c,0x8c,0x6a,0x13,0xf4,0xf1,0x7f,
|
||||
0xf2,0x79,0xae,0x73,0xba,0x1a,0x3f,0x30,0x65,0xb6,0x23,0xa7,0x94,0x34,0x29,0x87,
|
||||
0xce,0x06,0x99,0xee,0x85,0x10,0xce,0x08,0xe2,0x8d,0xd5,0x47,0xf3,0xc8,0xf0,0x18,
|
||||
0x41,0xc0,0x59,0x66,0x06,0xda,0xb6,0x18,0xd2,0xa3,0xa0,0xbd,0x3a,0x90,0x7f,0x37,
|
||||
0x39,0xdf,0x98,0x55,0xa2,0x19,0x5e,0x37,0xbc,0x86,0xf3,0x02,0xf8,0x68,0x49,0x53,
|
||||
0xf2,0x4b,0x3d,0x7a,0xe3,0x1d,0xa4,0x15,0x10,0xa6,0xce,0x8c,0xb8,0xfd,0x95,0x54,
|
||||
0xa2,0x50,0xa2,0xd9,0x35,0x12,0x56,0xae,0xbc,0x51,0x33,0x6d,0xb8,0x63,0x7c,0x26,
|
||||
0xab,0x19,0x01,0xa5,0xda,0xfa,0x4b,0xb6,0x57,0xd3,0x4b,0xdd,0xc0,0x62,0xc5,0x05,
|
||||
0xb7,0xc3,0x2e,0x1f,0x17,0xc8,0x09,0x87,0x12,0x37,0x21,0xd7,0x7a,0x53,0xb0,0x47,
|
||||
0x60,0xa2,0xb5,0x23,0x3b,0x99,0xdf,0xea,0x8b,0x94,0xea,0x9d,0x53,0x5d,0x02,0x52,
|
||||
0xf7,0x29,0xfb,0x63,0xb0,0xff,0x27,0x5e,0xde,0x54,0x7d,0x95,0xd6,0x4e,0x58,0x12,
|
||||
0x06,0x60,0x22,0x33,0xf2,0x19,0x67,0x65,0xdd,0xf3,0x42,0xb5,0x00,0x51,0x35,0xe5,
|
||||
0x62,0x4d,0x90,0x44,0xfb,0x7f,0x5b,0xb5,0xe5,0x02,0x03,0x01,0x00,0x01),
|
||||
chunk_from_chars(
|
||||
0x4f,0xe8,0x82,0xee,0xaa,0x2c,0x7b,0x3f,0x3a,0xf1,0xb4,0xe1,0xe3,0x85,0xd4,0xb1,
|
||||
0xb4,0x34,0x5c,0x2d),
|
||||
@ -708,9 +759,17 @@ START_TEST(test_load)
|
||||
pubkey = privkey->get_public_key(privkey);
|
||||
ck_assert(pubkey != NULL);
|
||||
ck_assert(pubkey->get_encoding(pubkey, PUBKEY_SPKI_ASN1_DER, &encoding));
|
||||
ck_assert_chunk_eq(keys[_i].pub, encoding);
|
||||
ck_assert_chunk_eq(keys[_i].spki, encoding);
|
||||
chunk_free(&encoding);
|
||||
|
||||
if (!pubkey->get_encoding(pubkey, PUBKEY_ASN1_DER, &encoding))
|
||||
{
|
||||
warn("PUBKEY_ASN1_DER encoding not supported, ignored");
|
||||
}
|
||||
else
|
||||
{
|
||||
ck_assert_chunk_eq(keys[_i].pub, encoding);
|
||||
chunk_free(&encoding);
|
||||
}
|
||||
ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp));
|
||||
ck_assert_chunk_eq(keys[_i].fp_pk, fp);
|
||||
ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_INFO_SHA1, &fp));
|
||||
|
@ -245,23 +245,29 @@ Suite *stream_suite_create()
|
||||
{
|
||||
Suite *s;
|
||||
TCase *tc;
|
||||
int count = countof(services);
|
||||
|
||||
if (getenv("TESTS_NO_IPV6"))
|
||||
{
|
||||
count--;
|
||||
}
|
||||
|
||||
s = suite_create("stream");
|
||||
|
||||
tc = tcase_create("sync");
|
||||
tcase_add_loop_test(tc, test_sync, 0, countof(services));
|
||||
tcase_add_loop_test(tc, test_sync, 0, count);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("async");
|
||||
tcase_add_loop_test(tc, test_async, 0, countof(services));
|
||||
tcase_add_loop_test(tc, test_async, 0, count);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("all");
|
||||
tcase_add_loop_test(tc, test_all, 0, countof(services));
|
||||
tcase_add_loop_test(tc, test_all, 0, count);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("concurrency");
|
||||
tcase_add_loop_test(tc, test_concurrency, 0, countof(services));
|
||||
tcase_add_loop_test(tc, test_concurrency, 0, count);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
|
@ -456,23 +456,45 @@ static void collect_failure_info(array_t *failures, char *name, int i)
|
||||
array_insert(failures, -1, &failure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Context data to collect warnings
|
||||
*/
|
||||
typedef struct {
|
||||
char *name;
|
||||
int i;
|
||||
array_t *warnings;
|
||||
} warning_ctx_t;
|
||||
|
||||
/**
|
||||
* Callback to collect warnings
|
||||
*/
|
||||
CALLBACK(warning_cb, void,
|
||||
warning_ctx_t *ctx, const char *msg, const char *file, const int line)
|
||||
{
|
||||
failure_t warning = {
|
||||
.name = ctx->name,
|
||||
.i = ctx->i,
|
||||
.file = file,
|
||||
.line = line,
|
||||
};
|
||||
|
||||
strncpy(warning.msg, msg, sizeof(warning.msg) - 1);
|
||||
warning.msg[sizeof(warning.msg)-1] = 0;
|
||||
array_insert(ctx->warnings, -1, &warning);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect warning information, add failure_t to array
|
||||
*/
|
||||
static bool collect_warning_info(array_t *warnings, char *name, int i)
|
||||
{
|
||||
failure_t warning = {
|
||||
warning_ctx_t ctx = {
|
||||
.name = name,
|
||||
.i = i,
|
||||
.warnings = warnings,
|
||||
};
|
||||
|
||||
warning.line = test_warning_get(warning.msg, sizeof(warning.msg),
|
||||
&warning.file);
|
||||
if (warning.line)
|
||||
{
|
||||
array_insert(warnings, -1, &warning);
|
||||
}
|
||||
return warning.line;
|
||||
return test_warnings_get(warning_cb, &ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,19 +50,26 @@ static backtrace_t *failure_backtrace;
|
||||
static bool worker_failed;
|
||||
|
||||
/**
|
||||
* Warning message buf
|
||||
* Warning information
|
||||
*/
|
||||
static char warning_buf[4096];
|
||||
typedef struct {
|
||||
/** Warning message */
|
||||
char msg[BUF_LEN];
|
||||
/** Source file warning was issued */
|
||||
const char *file;
|
||||
/** Line of source warning was issued */
|
||||
int line;
|
||||
} warning_info_t;
|
||||
|
||||
/**
|
||||
* Source file warning was issued
|
||||
* Warnings that occurred
|
||||
*/
|
||||
static const char *warning_file;
|
||||
static warning_info_t warnings[3];
|
||||
|
||||
/**
|
||||
* Line of source file warning was issued
|
||||
* Current warning index
|
||||
*/
|
||||
static int warning_line;
|
||||
static int warning_idx = -1;
|
||||
|
||||
/**
|
||||
* See header.
|
||||
@ -442,11 +449,16 @@ void test_warn_msg(const char *file, int line, char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (++warning_idx >= countof(warnings))
|
||||
{
|
||||
return;
|
||||
}
|
||||
va_start(args, fmt);
|
||||
vsnprintf(warning_buf, sizeof(warning_buf), fmt, args);
|
||||
warning_line = line;
|
||||
warning_file = file;
|
||||
vsnprintf(warnings[warning_idx].msg, sizeof(warnings[warning_idx].msg),
|
||||
fmt, args);
|
||||
va_end(args);
|
||||
warnings[warning_idx].file = file;
|
||||
warnings[warning_idx].line = line;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -479,20 +491,22 @@ int test_failure_get(char *msg, int len, const char **file)
|
||||
/**
|
||||
* See header.
|
||||
*/
|
||||
int test_warning_get(char *msg, int len, const char **file)
|
||||
bool test_warnings_get(void (*cb)(void *ctx, const char *msg, const char *file,
|
||||
const int line), void *ctx)
|
||||
{
|
||||
int line = warning_line;
|
||||
int i;
|
||||
|
||||
if (!line)
|
||||
if (warning_idx < 0)
|
||||
{
|
||||
return 0;
|
||||
return FALSE;
|
||||
}
|
||||
for (i = 0; i <= warning_idx && i < countof(warnings); i++)
|
||||
{
|
||||
cb(ctx, warnings[i].msg, warnings[i].file, warnings[i].line);
|
||||
}
|
||||
strncpy(msg, warning_buf, len - 1);
|
||||
msg[len - 1] = 0;
|
||||
*file = warning_file;
|
||||
/* reset state */
|
||||
warning_line = 0;
|
||||
return line;
|
||||
warning_idx = -1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -219,6 +219,18 @@ void test_setup_timeout(int s);
|
||||
*/
|
||||
int test_failure_get(char *msg, int len, const char **file);
|
||||
|
||||
/**
|
||||
* Get info about warnings if any were issued during the test. Resets the
|
||||
* warning state.
|
||||
*
|
||||
* @param cb callback that receives a custom context object, message,
|
||||
* source file and line of each warning
|
||||
* @param ctx context object
|
||||
* @return TRUE if any warnings were issued
|
||||
*/
|
||||
bool test_warnings_get(void (*cb)(void *ctx, const char *msg, const char *file,
|
||||
const int line), void *ctx);
|
||||
|
||||
/**
|
||||
* Get info about a warning if one was issued during the test. Resets the
|
||||
* warning state.
|
||||
|
@ -597,6 +597,29 @@ static char *whitelist[] = {
|
||||
"RAND_DRBG_get0_master",
|
||||
"RAND_DRBG_get0_private",
|
||||
"RAND_DRBG_get0_public",
|
||||
/* OpenSSL 3.0 caches even more static stuff */
|
||||
"ERR_set_debug",
|
||||
"ERR_set_error",
|
||||
"EVP_DigestSignInit",
|
||||
"EVP_DigestVerifyInit",
|
||||
"EVP_PKEY_encrypt_init",
|
||||
"EVP_PKEY_decrypt_init",
|
||||
"EVP_PKEY_derive_init",
|
||||
"EVP_PKEY_sign_init",
|
||||
"EVP_ASYM_CIPHER_fetch",
|
||||
"EVP_CIPHER_fetch",
|
||||
"EVP_KDF_fetch",
|
||||
"EVP_KEYEXCH_fetch",
|
||||
"EVP_KEYMGMT_fetch",
|
||||
"EVP_MAC_fetch",
|
||||
"EVP_MD_fetch",
|
||||
"EVP_SIGNATURE_fetch",
|
||||
"OSSL_DECODER_do_all_provided",
|
||||
"OSSL_ENCODER_do_all_provided",
|
||||
"OSSL_PROVIDER_try_load",
|
||||
"OSSL_PROVIDER_load",
|
||||
"RAND_get0_private",
|
||||
"RAND_get0_public",
|
||||
/* We get this via libcurl and OpenSSL 1.1.1 */
|
||||
"CRYPTO_get_ex_new_index",
|
||||
/* OpenSSL libssl */
|
||||
|
Loading…
x
Reference in New Issue
Block a user