#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#ifdef WOLFSSL_SYS_CA_CERTS
#ifdef _WIN32
#define _WINSOCKAPI_
#include <windows.h>
#include <wincrypt.h>
#undef _WINSOCKAPI_
#if !defined(__MINGW32__) && !defined(__MINGW64__)
#pragma comment(lib, "crypt32")
#endif
#endif
#if defined(__APPLE__)
#if defined(HAVE_SECURITY_SECTRUSTSETTINGS_H)
#include <Security/SecTrustSettings.h>
#endif
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
#include <CoreFoundation/CoreFoundation.h>
#endif
#endif
#endif
#if !defined(WOLFSSL_SSL_LOAD_INCLUDED)
#ifndef WOLFSSL_IGNORE_FILE_WARN
#warning ssl_load.c does not need to be compiled separately from ssl.c
#endif
#else
#include <wolfssl/wolfcrypt/logging.h>
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
#define CTX_HAVE_PSK(ctx) (ctx)->havePSK
#define SSL_HAVE_PSK(ssl) (ssl)->options.havePSK
#else
#define CTX_HAVE_PSK(ctx) 0
#define SSL_HAVE_PSK(ssl) 0
#endif
#ifdef NO_RSA
#define WOLFSSL_HAVE_RSA 0
#else
#define WOLFSSL_HAVE_RSA 1
#endif
#ifndef NO_CERTS
#define SSL_KEY_SZ(ssl) (ssl)->buffers.keySz
#else
#define SSL_KEY_SZ(ssl) 0
#endif
#ifdef HAVE_ANON
#define CTX_USE_ANON(ctx) (ctx)->useAnon
#else
#define CTX_USE_ANON(ctx) 0
#endif
#ifdef HAVE_PK_CALLBACKS
#define WOLFSSL_IS_PRIV_PK_SET(ctx, ssl) \
wolfSSL_CTX_IsPrivatePkSet(((ssl) == NULL) ? (ctx) : (ssl)->ctx)
#else
#define WOLFSSL_IS_PRIV_PK_SET(ctx, ssl) 0
#endif
#define WOLFSSL_HEAP(ctx, ssl) \
(((ctx) != NULL) ? (ctx)->heap : (((ssl) != NULL) ? (ssl)->heap : NULL))
#ifndef NO_CERTS
static int DataToDerBuffer(const unsigned char* buff, word32 len, int format,
int type, EncryptedInfo* info, void* heap, DerBuffer** der, int* algId)
{
int ret;
info->consumed = 0;
if (format == WOLFSSL_FILETYPE_PEM) {
#ifdef WOLFSSL_PEM_TO_DER
ret = PemToDer(buff, (long)(len), type, der, heap, info, algId);
if (ret != 0) {
FreeDer(der);
}
#else
(void)algId;
ret = NOT_COMPILED_IN;
#endif
}
else {
if ((info->consumed = wolfssl_der_length(buff, (int)len)) > 0) {
ret = 0;
}
else {
ret = ASN_PARSE_E;
}
if (info->consumed > (int)len) {
ret = ASN_PARSE_E;
}
if (ret == 0) {
ret = AllocCopyDer(der, buff, (word32)info->consumed, type, heap);
}
}
return ret;
}
static int ProcessUserCert(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer,
int type, int verify, byte* chainBuffer, word32* pIdx, word32 bufferSz)
{
int ret = 0;
word32 idx = *pIdx;
DerBuffer* der = *pDer;
if ((ret == 0) && ((idx + der->length + CERT_HEADER_SZ) > bufferSz)) {
WOLFSSL_MSG(" Cert Chain bigger than buffer. "
"Consider increasing MAX_CHAIN_DEPTH");
ret = BUFFER_E;
}
if (ret == 0) {
c32to24(der->length, &chainBuffer[idx]);
idx += CERT_HEADER_SZ;
XMEMCPY(&chainBuffer[idx], der->buffer, der->length);
idx += der->length;
if (type == CA_TYPE) {
ret = AddCA(cm, pDer, WOLFSSL_USER_CA, verify);
if (ret == 1) {
ret = 0;
}
}
}
*pIdx = idx;
return ret;
}
static int ProcessUserChainRetain(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
const byte* chainBuffer, word32 len, int cnt, int type, void* heap)
{
int ret = 0;
(void)cnt;
if (ssl != NULL) {
if (ssl->buffers.weOwnCertChain) {
FreeDer(&ssl->buffers.certChain);
}
ret = AllocCopyDer(&ssl->buffers.certChain, chainBuffer, len, type,
heap);
ssl->buffers.weOwnCertChain = (ret == 0);
ssl->buffers.certChainCnt = cnt;
}
else if (ctx != NULL) {
FreeDer(&ctx->certChain);
ret = AllocCopyDer(&ctx->certChain, chainBuffer, len, type, heap);
ctx->certChainCnt = cnt;
}
return ret;
}
static int ProcessUserChain(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
const unsigned char* buff, long sz, int format, int type, long* used,
EncryptedInfo* info, int verify)
{
int ret = 0;
void* heap = WOLFSSL_HEAP(ctx, ssl);
WOLFSSL_ENTER("ProcessUserChain");
if (info->consumed >= sz) {
WOLFSSL_MSG("Already consumed data");
}
else {
#ifndef WOLFSSL_SMALL_STACK
byte stackBuffer[FILE_BUFFER_SIZE];
#endif
StaticBuffer chain;
long consumed = info->consumed;
word32 idx = 0;
int gotOne = 0;
int cnt = 0;
long maxSz = (sz - consumed) + (CERT_HEADER_SZ * MAX_CHAIN_DEPTH);
#ifdef WOLFSSL_SMALL_STACK
static_buffer_init(&chain);
#else
static_buffer_init(&chain, stackBuffer, FILE_BUFFER_SIZE);
#endif
ret = static_buffer_set_size(&chain, (word32)maxSz, heap,
DYNAMIC_TYPE_FILE);
WOLFSSL_MSG("Processing Cert Chain");
while ((ret == 0) && (consumed < sz)) {
DerBuffer* part = NULL;
ret = DataToDerBuffer(buff + consumed, (word32)(sz - consumed),
format, type, info, heap, &part, NULL);
if (ret == 0) {
ret = ProcessUserCert(ctx->cm, &part, type, verify,
chain.buffer, &idx, (word32)maxSz);
}
if ((ret == WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER)) && gotOne) {
WOLFSSL_MSG("We got one good cert, so stuff at end ok");
ret = 0;
break;
}
FreeDer(&part);
if (ret == 0) {
consumed += info->consumed;
WOLFSSL_MSG(" Consumed another Cert in Chain");
gotOne |= (type != CA_TYPE);
cnt++;
}
}
if (used != NULL) {
*used = consumed;
}
if ((ret == 0) && (idx > 0)) {
ret = ProcessUserChainRetain(ctx, ssl, chain.buffer, idx, cnt, type,
heap);
}
static_buffer_free(&chain, heap, DYNAMIC_TYPE_FILE);
}
WOLFSSL_LEAVE("ProcessUserChain", ret);
return ret;
}
#ifndef NO_RSA
#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
(HAVE_FIPS_VERSION > 2))
static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int* keyFormat, int devId, byte* keyType, int* keySize)
{
int ret;
word32 idx;
int keySz = 0;
(void)devId;
idx = 0;
ret = wc_RsaPrivateKeyValidate(der->buffer, &idx, &keySz, der->length);
#ifdef WOLF_PRIVATE_KEY_ID
if ((ret != 0) && ((devId != INVALID_DEVID) ||
WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
word32 nSz;
idx = 0;
ret = wc_RsaPublicKeyDecode_ex(der->buffer, &idx, der->length, NULL,
&nSz, NULL, NULL);
if (ret == 0) {
keySz = (int)nSz;
}
}
#endif
if (ret == 0) {
int minRsaSz = ssl ? ssl->options.minRsaKeySz : ctx->minRsaKeySz;
*keyFormat = RSAk;
*keyType = rsa_sa_algo;
*keySize = keySz;
if (keySz < minRsaSz) {
WOLFSSL_MSG("Private Key size too small");
ret = RSA_KEY_SIZE_E;
}
if ((ssl != NULL) && (ssl->options.side == WOLFSSL_SERVER_END)) {
ssl->options.haveStaticECC = 0;
}
}
else if (*keyFormat == 0) {
WOLFSSL_MSG("Not an RSA key");
ret = 0;
}
return ret;
}
#else
static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType,
int* keySize)
{
int ret;
word32 idx;
WC_DECLARE_VAR(key, RsaKey, 1, 0);
WC_ALLOC_VAR_EX(key, RsaKey, 1, heap, DYNAMIC_TYPE_RSA,
return MEMORY_E);
ret = wc_InitRsaKey_ex(key, heap, devId);
if (ret == 0) {
idx = 0;
ret = wc_RsaPrivateKeyDecode(der->buffer, &idx, key, der->length);
#ifdef WOLF_PRIVATE_KEY_ID
if ((ret != 0) && ((devId != INVALID_DEVID) ||
WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
idx = 0;
ret = wc_RsaPublicKeyDecode(der->buffer, &idx, key, der->length);
}
#endif
if (ret == 0) {
int minRsaSz = ssl ? ssl->options.minRsaKeySz : ctx->minRsaKeySz;
int keySz = wc_RsaEncryptSize((RsaKey*)key);
*keyFormat = RSAk;
*keyType = rsa_sa_algo;
*keySize = keySz;
if (keySz < minRsaSz) {
WOLFSSL_MSG("Private Key size too small");
ret = RSA_KEY_SIZE_E;
}
if ((ssl != NULL) && (ssl->options.side == WOLFSSL_SERVER_END)) {
ssl->options.haveStaticECC = 0;
}
}
else if (*keyFormat == 0) {
WOLFSSL_MSG("Not an RSA key");
ret = 0;
}
wc_FreeRsaKey(key);
}
WC_FREE_VAR_EX(key, heap, DYNAMIC_TYPE_RSA);
return ret;
}
#endif
#endif
#ifdef HAVE_ECC
static int ProcessBufferTryDecodeEcc(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType,
int* keySize)
{
int ret = 0;
word32 idx;
WC_DECLARE_VAR(key, ecc_key, 1, 0);
WC_ALLOC_VAR_EX(key, ecc_key, 1, heap, DYNAMIC_TYPE_ECC,
return MEMORY_E);
if (wc_ecc_init_ex(key, heap, devId) == 0) {
idx = 0;
ret = wc_EccPrivateKeyDecode(der->buffer, &idx, key, der->length);
#ifdef WOLF_PRIVATE_KEY_ID
if ((ret != 0) && ((devId != INVALID_DEVID) ||
WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
idx = 0;
ret = wc_EccPublicKeyDecode(der->buffer, &idx, key, der->length);
}
#endif
#ifdef WOLFSSL_SM2
if (*keyFormat == SM2k) {
ret = wc_ecc_set_curve(key, WOLFSSL_SM2_KEY_BITS / 8,
ECC_SM2P256V1);
}
#endif
if (ret == 0) {
int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz;
int keySz = wc_ecc_size(key);
*keyFormat = ECDSAk;
#ifdef WOLFSSL_SM2
if (key->dp->id == ECC_SM2P256V1) {
*keyType = sm2_sa_algo;
}
else
#endif
{
*keyType = ecc_dsa_sa_algo;
}
*keySize = keySz;
if (keySz < minKeySz) {
WOLFSSL_MSG("ECC private key too small");
ret = ECC_KEY_SIZE_E;
}
if (ssl) {
ssl->options.haveStaticECC = 1;
}
else {
ctx->haveStaticECC = 1;
}
}
else if (*keyFormat == 0) {
WOLFSSL_MSG("Not an ECC key");
ret = 0;
}
wc_ecc_free(key);
}
WC_FREE_VAR_EX(key, heap, DYNAMIC_TYPE_ECC);
return ret;
}
#endif
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT)
static int ProcessBufferTryDecodeEd25519(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType,
int* keySize)
{
int ret;
word32 idx;
WC_DECLARE_VAR(key, ed25519_key, 1, 0);
WC_ALLOC_VAR_EX(key, ed25519_key, 1, heap, DYNAMIC_TYPE_ED25519,
return MEMORY_E);
ret = wc_ed25519_init_ex(key, heap, devId);
if (ret == 0) {
idx = 0;
ret = wc_Ed25519PrivateKeyDecode(der->buffer, &idx, key, der->length);
#ifdef WOLF_PRIVATE_KEY_ID
if ((ret != 0) && ((devId != INVALID_DEVID) ||
WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
idx = 0;
ret = wc_Ed25519PublicKeyDecode(der->buffer, &idx, key,
der->length);
}
#endif
if (ret == 0) {
int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz;
*keyFormat = ED25519k;
*keyType = ed25519_sa_algo;
*keySize = ED25519_KEY_SIZE;
if (ED25519_KEY_SIZE < minKeySz) {
WOLFSSL_MSG("ED25519 private key too small");
ret = ECC_KEY_SIZE_E;
}
if (ssl != NULL) {
#if !defined(WOLFSSL_NO_CLIENT_AUTH) && !defined(NO_ED25519_CLIENT_AUTH)
ssl->options.cacheMessages = 1;
#endif
}
}
else if (*keyFormat == 0) {
WOLFSSL_MSG("Not an Ed25519 key");
ret = 0;
}
wc_ed25519_free(key);
}
WC_FREE_VAR_EX(key, heap, DYNAMIC_TYPE_ED25519);
return ret;
}
#endif
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)
static int ProcessBufferTryDecodeEd448(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType,
int* keySize)
{
int ret;
word32 idx;
WC_DECLARE_VAR(key, ed448_key, 1, 0);
WC_ALLOC_VAR_EX(key, ed448_key, 1, heap, DYNAMIC_TYPE_ED448,
return MEMORY_E);
ret = wc_ed448_init_ex(key, heap, devId);
if (ret == 0) {
idx = 0;
ret = wc_Ed448PrivateKeyDecode(der->buffer, &idx, key, der->length);
#ifdef WOLF_PRIVATE_KEY_ID
if ((ret != 0) && ((devId != INVALID_DEVID) ||
WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
idx = 0;
ret = wc_Ed448PublicKeyDecode(der->buffer, &idx, key, der->length);
}
#endif
if (ret == 0) {
int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz;
*keyFormat = ED448k;
*keyType = ed448_sa_algo;
*keySize = ED448_KEY_SIZE;
if (ED448_KEY_SIZE < minKeySz) {
WOLFSSL_MSG("ED448 private key too small");
ret = ECC_KEY_SIZE_E;
}
#if !defined(WOLFSSL_NO_CLIENT_AUTH) && !defined(NO_ED448_CLIENT_AUTH)
if (ssl != NULL) {
ssl->options.cacheMessages = 1;
}
#endif
}
else if (*keyFormat == 0) {
WOLFSSL_MSG("Not an Ed448 key");
ret = 0;
}
wc_ed448_free(key);
}
WC_FREE_VAR_EX(key, heap, DYNAMIC_TYPE_ED448);
return ret;
}
#endif
#if defined(HAVE_FALCON)
static int ProcessBufferTryDecodeFalcon(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int* keyFormat, void* heap, byte* keyType, int* keySize)
{
int ret;
falcon_key* key;
key = (falcon_key*)XMALLOC(sizeof(falcon_key), heap, DYNAMIC_TYPE_FALCON);
if (key == NULL) {
return MEMORY_E;
}
ret = wc_falcon_init(key);
if (ret == 0) {
if ((*keyFormat == FALCON_LEVEL1k) || ((*keyFormat == 0) &&
((der->length == FALCON_LEVEL1_KEY_SIZE) ||
(der->length == FALCON_LEVEL1_PRV_KEY_SIZE)))) {
ret = wc_falcon_set_level(key, 1);
}
else if ((*keyFormat == FALCON_LEVEL5k) || ((*keyFormat == 0) &&
((der->length == FALCON_LEVEL5_KEY_SIZE) ||
(der->length == FALCON_LEVEL5_PRV_KEY_SIZE)))) {
ret = wc_falcon_set_level(key, 5);
}
else {
wc_falcon_free(key);
ret = ALGO_ID_E;
}
}
if (ret == 0) {
ret = wc_falcon_import_private_only(der->buffer, der->length, key);
if (ret == 0) {
int minKeySz = ssl ? ssl->options.minFalconKeySz :
ctx->minFalconKeySz;
if (*keyFormat == FALCON_LEVEL1k) {
*keyType = falcon_level1_sa_algo;
*keySize = FALCON_LEVEL1_KEY_SIZE;
}
else {
*keyType = falcon_level5_sa_algo;
*keySize = FALCON_LEVEL5_KEY_SIZE;
}
if (*keySize < minKeySz) {
WOLFSSL_MSG("Falcon private key too small");
ret = FALCON_KEY_SIZE_E;
}
}
else if (*keyFormat == 0) {
WOLFSSL_MSG("Not a Falcon key");
ret = 0;
}
wc_falcon_free(key);
}
else if ((ret == WC_NO_ERR_TRACE(ALGO_ID_E)) && (*keyFormat == 0)) {
WOLFSSL_MSG("Not a Falcon key");
ret = 0;
}
XFREE(key, heap, DYNAMIC_TYPE_FALCON);
return ret;
}
#endif
#if defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
!defined(WOLFSSL_DILITHIUM_NO_ASN1)
static int ProcessBufferTryDecodeDilithium(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int* keyFormat, void* heap, byte* keyType, int* keySize)
{
int ret;
word32 idx;
dilithium_key* key;
int keyFormatTemp = 0;
int keyTypeTemp = 0;
int keySizeTemp = 0;
key = (dilithium_key*)XMALLOC(sizeof(dilithium_key), heap,
DYNAMIC_TYPE_DILITHIUM);
if (key == NULL) {
return MEMORY_E;
}
ret = wc_dilithium_init(key);
if (ret == 0) {
idx = 0;
ret = wc_Dilithium_PrivateKeyDecode(der->buffer, &idx, key,
der->length);
if (ret == 0) {
ret = dilithium_get_oid_sum(key, &keyFormatTemp);
if (ret == 0) {
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
if (keyFormatTemp == DILITHIUM_LEVEL2k) {
keyTypeTemp = dilithium_level2_sa_algo;
keySizeTemp = DILITHIUM_LEVEL2_KEY_SIZE;
}
else if (keyFormatTemp == DILITHIUM_LEVEL3k) {
keyTypeTemp = dilithium_level3_sa_algo;
keySizeTemp = DILITHIUM_LEVEL3_KEY_SIZE;
}
else if (keyFormatTemp == DILITHIUM_LEVEL5k) {
keyTypeTemp = dilithium_level5_sa_algo;
keySizeTemp = DILITHIUM_LEVEL5_KEY_SIZE;
}
else
#endif
if (keyFormatTemp == ML_DSA_LEVEL2k) {
keyTypeTemp = dilithium_level2_sa_algo;
keySizeTemp = ML_DSA_LEVEL2_KEY_SIZE;
}
else if (keyFormatTemp == ML_DSA_LEVEL3k) {
keyTypeTemp = dilithium_level3_sa_algo;
keySizeTemp = ML_DSA_LEVEL3_KEY_SIZE;
}
else if (keyFormatTemp == ML_DSA_LEVEL5k) {
keyTypeTemp = dilithium_level5_sa_algo;
keySizeTemp = ML_DSA_LEVEL5_KEY_SIZE;
}
else {
ret = ALGO_ID_E;
}
}
if (ret == 0) {
int minKeySz = ssl ? ssl->options.minDilithiumKeySz :
ctx->minDilithiumKeySz;
if (keySizeTemp < minKeySz) {
WOLFSSL_MSG("Dilithium private key too small");
ret = DILITHIUM_KEY_SIZE_E;
}
}
if (ret == 0) {
*keyFormat = keyFormatTemp;
*keyType = keyTypeTemp;
*keySize = keySizeTemp;
}
}
else if (*keyFormat == 0) {
WOLFSSL_MSG("Not a Dilithium key");
ret = 0;
}
wc_dilithium_free(key);
}
XFREE(key, heap, DYNAMIC_TYPE_DILITHIUM);
return ret;
}
#endif
static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int* keyFormat, void* heap, int type)
{
int ret = 0;
int devId = wolfSSL_CTX_GetDevId(ctx, ssl);
byte* keyType = NULL;
int* keySz = NULL;
int matchAnyKey = 0;
(void)heap;
(void)devId;
(void)type;
if ((der == NULL) || (keyFormat == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (ctx == NULL) && (ssl == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
#ifdef WOLFSSL_DUAL_ALG_CERTS
if (type == ALT_PRIVATEKEY_TYPE) {
if (ssl != NULL) {
keyType = &ssl->buffers.altKeyType;
keySz = &ssl->buffers.altKeySz;
}
else {
keyType = &ctx->altPrivateKeyType;
keySz = &ctx->altPrivateKeySz;
}
}
else
#endif
if (ssl != NULL) {
keyType = &ssl->buffers.keyType;
keySz = &ssl->buffers.keySz;
}
else {
keyType = &ctx->privateKeyType;
keySz = &ctx->privateKeySz;
}
}
#ifndef NO_RSA
if ((ret == 0) && ((*keyFormat == 0) || (*keyFormat == RSAk))) {
#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \
(HAVE_FIPS_VERSION > 2))
ret = ProcessBufferTryDecodeRsa(ctx, ssl, der, keyFormat, devId,
keyType, keySz);
#else
ret = ProcessBufferTryDecodeRsa(ctx, ssl, der, keyFormat, heap, devId,
keyType, keySz);
#endif
matchAnyKey = 1;
}
#ifdef WC_RSA_PSS
if((ret == 0) && (*keyFormat == RSAPSSk)) {
matchAnyKey = 1;
}
#endif
#endif
#ifdef HAVE_ECC
if ((ret == 0) && ((*keyFormat == 0) || (*keyFormat == ECDSAk)
#ifdef WOLFSSL_SM2
|| (*keyFormat == SM2k)
#endif
)) {
ret = ProcessBufferTryDecodeEcc(ctx, ssl, der, keyFormat, heap, devId,
keyType, keySz);
matchAnyKey = 1;
}
#endif
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT)
if ((ret == 0) && ((*keyFormat == 0 || *keyFormat == ED25519k))) {
ret = ProcessBufferTryDecodeEd25519(ctx, ssl, der, keyFormat, heap,
devId, keyType, keySz);
matchAnyKey = 1;
}
#endif
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)
if ((ret == 0) && ((*keyFormat == 0 || *keyFormat == ED448k))) {
ret = ProcessBufferTryDecodeEd448(ctx, ssl, der, keyFormat, heap, devId,
keyType, keySz);
matchAnyKey = 1;
}
#endif
#if defined(HAVE_FALCON)
if ((ret == 0) && ((*keyFormat == 0) || (*keyFormat == FALCON_LEVEL1k) ||
(*keyFormat == FALCON_LEVEL5k))) {
ret = ProcessBufferTryDecodeFalcon(ctx, ssl, der, keyFormat, heap,
keyType, keySz);
matchAnyKey = 1;
}
#endif
#if defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
!defined(WOLFSSL_DILITHIUM_NO_ASN1)
if ((ret == 0) &&
((*keyFormat == 0) ||
(*keyFormat == ML_DSA_LEVEL2k) ||
(*keyFormat == ML_DSA_LEVEL3k) ||
(*keyFormat == ML_DSA_LEVEL5k)
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
|| (*keyFormat == DILITHIUM_LEVEL2k)
|| (*keyFormat == DILITHIUM_LEVEL3k)
|| (*keyFormat == DILITHIUM_LEVEL5k)
#endif
)) {
ret = ProcessBufferTryDecodeDilithium(ctx, ssl, der, keyFormat, heap,
keyType, keySz);
matchAnyKey = 1;
}
#endif
if ((ret == 0) &&
((*keyFormat == 0) || ((*keyFormat != 0) && (matchAnyKey == 0)))) {
WOLFSSL_MSG("Not a supported key type");
ret = WOLFSSL_BAD_FILE;
}
return ret;
}
#if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED)
static int ProcessBufferPrivPkcs8Dec(EncryptedInfo* info, DerBuffer* der,
void* heap)
{
int ret = 0;
word32 algId;
int passwordSz = NAME_SZ;
WC_DECLARE_VAR(password, char, NAME_SZ, 0);
(void)heap;
#ifdef WOLFSSL_SMALL_STACK
password = (char*)XMALLOC(passwordSz, heap, DYNAMIC_TYPE_STRING);
if (password == NULL) {
ret = MEMORY_E;
}
#endif
if (ret == 0) {
ret = info->passwd_cb(password, passwordSz, PEM_PASS_READ,
info->passwd_userdata);
}
if (ret >= 0) {
passwordSz = ret;
#ifdef WOLFSSL_CHECK_MEM_ZERO
wc_MemZero_Add("ProcessBuffer password", password, passwordSz);
#endif
ret = ToTraditionalEnc(der->buffer, der->length, password, passwordSz,
&algId);
}
if (ret >= 0) {
ForceZero(der->buffer + ret, der->length - (word32)ret);
der->length = (word32)ret;
}
#ifdef WOLFSSL_SMALL_STACK
if (password != NULL)
#endif
{
ForceZero(password, (word32)passwordSz);
}
#ifdef WOLFSSL_SMALL_STACK
XFREE(password, heap, DYNAMIC_TYPE_STRING);
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
wc_MemZero_Check(password, NAME_SZ);
#endif
return ret;
}
#endif
static int ProcessBufferPrivKeyHandleDer(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer** der, int type)
{
int ret = 0;
(void)type;
#ifdef WOLFSSL_DUAL_ALG_CERTS
if (type == ALT_PRIVATEKEY_TYPE) {
if (ssl != NULL) {
if (ssl->buffers.weOwnAltKey) {
FreeDer(&ssl->buffers.altKey);
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
FreeDer(&ssl->buffers.altKeyMask);
#endif
}
ssl->buffers.altKeyId = 0;
ssl->buffers.altKeyLabel = 0;
ssl->buffers.altKeyDevId = INVALID_DEVID;
ssl->buffers.altKey = *der;
#ifdef WOLFSSL_CHECK_MEM_ZERO
wc_MemZero_Add("SSL Buffers key", (*der)->buffer, (*der)->length);
#endif
ssl->buffers.weOwnAltKey = 1;
}
else if (ctx != NULL) {
FreeDer(&ctx->altPrivateKey);
ctx->altPrivateKeyId = 0;
ctx->altPrivateKeyLabel = 0;
ctx->altPrivateKeyDevId = INVALID_DEVID;
ctx->altPrivateKey = *der;
#ifdef WOLFSSL_CHECK_MEM_ZERO
wc_MemZero_Add("CTX private key", (*der)->buffer, (*der)->length);
#endif
}
}
else
#endif
if (ssl != NULL) {
if (ssl->buffers.weOwnKey) {
FreeDer(&ssl->buffers.key);
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
FreeDer(&ssl->buffers.keyMask);
#endif
}
ssl->buffers.keyId = 0;
ssl->buffers.keyLabel = 0;
ssl->buffers.keyDevId = INVALID_DEVID;
ssl->buffers.key = *der;
#ifdef WOLFSSL_CHECK_MEM_ZERO
wc_MemZero_Add("SSL Buffers key", (*der)->buffer, (*der)->length);
#endif
ssl->buffers.weOwnKey = 1;
}
else if (ctx != NULL) {
FreeDer(&ctx->privateKey);
ctx->privateKeyId = 0;
ctx->privateKeyLabel = 0;
ctx->privateKeyDevId = INVALID_DEVID;
ctx->privateKey = *der;
#ifdef WOLFSSL_CHECK_MEM_ZERO
wc_MemZero_Add("CTX private key", (*der)->buffer, (*der)->length);
#endif
}
return ret;
}
static int ProcessBufferPrivateKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int format, EncryptedInfo* info, void* heap, int type,
int algId)
{
int ret;
(void)info;
(void)format;
ret = ProcessBufferPrivKeyHandleDer(ctx, ssl, &der, type);
if (ret == 0) {
ret = ProcessBufferTryDecode(ctx, ssl, der, &algId, heap, type);
}
#if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED)
if (((ret != 0) || (algId == 0)) && (format != WOLFSSL_FILETYPE_PEM) &&
(info->passwd_cb != NULL) && (algId == 0)) {
ret = ProcessBufferPrivPkcs8Dec(info, der, heap);
if (ret >= 0) {
ret = ProcessBufferTryDecode(ctx, ssl, der, &algId, heap, type);
}
}
#endif
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
{
int blindRet = 0;
#ifdef WOLFSSL_DUAL_ALG_CERTS
if (type == ALT_PRIVATEKEY_TYPE) {
if (ssl != NULL) {
blindRet = wolfssl_priv_der_blind(ssl->rng, ssl->buffers.altKey,
&ssl->buffers.altKeyMask);
}
else {
blindRet = wolfssl_priv_der_blind(NULL, ctx->altPrivateKey,
&ctx->altPrivateKeyMask);
}
}
else
#endif
if (ssl != NULL) {
blindRet = wolfssl_priv_der_blind(ssl->rng, ssl->buffers.key,
&ssl->buffers.keyMask);
}
else {
blindRet = wolfssl_priv_der_blind(NULL, ctx->privateKey,
&ctx->privateKeyMask);
}
if (ret == 0 && blindRet != 0)
ret = blindRet;
}
#endif
if ((ret == 0) && (algId == 0)) {
#ifdef OPENSSL_EXTRA
if (info->passwd_cb) {
WOLFSSL_EVPerr(0, -WOLFSSL_EVP_R_BAD_DECRYPT_E);
}
#endif
WOLFSSL_ERROR(WOLFSSL_BAD_FILE);
ret = WOLFSSL_BAD_FILE;
}
return ret;
}
static void wolfssl_set_have_from_key_oid(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
int keyOID)
{
switch (keyOID) {
case ECDSAk:
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
case SM2k:
#endif
#ifdef HAVE_ED25519
case ED25519k:
#endif
#ifdef HAVE_ED448
case ED448k:
#endif
if (ssl != NULL) {
ssl->options.haveECC = 1;
}
else {
ctx->haveECC = 1;
}
break;
#ifndef NO_RSA
case RSAk:
#ifdef WC_RSA_PSS
case RSAPSSk:
#endif
if (ssl != NULL) {
ssl->options.haveRSA = 1;
}
else {
ctx->haveRSA = 1;
}
break;
#endif
#ifdef HAVE_FALCON
case FALCON_LEVEL1k:
case FALCON_LEVEL5k:
if (ssl != NULL) {
ssl->options.haveFalconSig = 1;
}
else {
ctx->haveFalconSig = 1;
}
break;
#endif
#ifdef HAVE_DILITHIUM
case ML_DSA_LEVEL2k:
case ML_DSA_LEVEL3k:
case ML_DSA_LEVEL5k:
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
case DILITHIUM_LEVEL2k:
case DILITHIUM_LEVEL3k:
case DILITHIUM_LEVEL5k:
#endif
if (ssl != NULL) {
ssl->options.haveDilithiumSig = 1;
}
else {
ctx->haveDilithiumSig = 1;
}
break;
#endif
default:
WOLFSSL_MSG("Cert key not supported");
break;
}
}
static void ProcessBufferCertSetHave(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DecodedCert* cert)
{
if (ssl != NULL) {
ssl->options.haveECDSAsig = 0;
ssl->options.haveFalconSig = 0;
ssl->options.haveDilithiumSig = 0;
}
switch (cert->signatureOID) {
case CTC_SHAwECDSA:
case CTC_SHA256wECDSA:
case CTC_SHA384wECDSA:
case CTC_SHA512wECDSA:
#ifdef HAVE_ED25519
case CTC_ED25519:
#endif
#ifdef HAVE_ED448
case CTC_ED448:
#endif
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
case CTC_SM3wSM2:
#endif
WOLFSSL_MSG("ECDSA/ED25519/ED448 cert signature");
if (ssl) {
ssl->options.haveECDSAsig = 1;
}
else if (ctx) {
ctx->haveECDSAsig = 1;
}
break;
#ifdef HAVE_FALCON
case CTC_FALCON_LEVEL1:
case CTC_FALCON_LEVEL5:
WOLFSSL_MSG("Falcon cert signature");
if (ssl) {
ssl->options.haveFalconSig = 1;
}
else if (ctx) {
ctx->haveFalconSig = 1;
}
break;
#endif
#ifdef HAVE_DILITHIUM
case CTC_ML_DSA_LEVEL2:
case CTC_ML_DSA_LEVEL3:
case CTC_ML_DSA_LEVEL5:
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
case CTC_DILITHIUM_LEVEL2:
case CTC_DILITHIUM_LEVEL3:
case CTC_DILITHIUM_LEVEL5:
#endif
WOLFSSL_MSG("Dilithium cert signature");
if (ssl) {
ssl->options.haveDilithiumSig = 1;
}
else if (ctx) {
ctx->haveDilithiumSig = 1;
}
break;
#endif
default:
WOLFSSL_MSG("Cert signature not supported");
break;
}
#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \
defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || !defined(NO_RSA)
#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448)
if (ssl != NULL) {
ssl->pkCurveOID = cert->pkCurveOID;
}
else if (ctx) {
ctx->pkCurveOID = cert->pkCurveOID;
}
#endif
#ifndef WC_STRICT_SIG
if ((ctx != NULL) || (ssl != NULL)) {
wolfssl_set_have_from_key_oid(ctx, ssl, (int)cert->keyOID);
}
#else
if (ssl != NULL) {
ssl->options.haveECC = ssl->options.haveECDSAsig;
}
else if (ctx) {
ctx->haveECC = ctx->haveECDSAsig;
}
#endif
#endif
}
#define CHECK_KEY_SZ(min, max, keySz, err) \
(((min) < 0) || ((keySz) < (min)) || ((keySz) > (max))) ? (err) : 0
static int ProcessBufferCertPublicKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DecodedCert* cert, int checkKeySz)
{
int ret = 0;
byte keyType = 0;
int keySz = 0;
#ifndef NO_RSA
word32 idx;
#endif
if (ctx == NULL && ssl == NULL) {
return BAD_FUNC_ARG;
}
switch (cert->keyOID) {
#ifndef NO_RSA
#ifdef WC_RSA_PSS
case RSAPSSk:
#endif
case RSAk:
keyType = rsa_sa_algo;
idx = 0;
ret = wc_RsaPublicKeyDecode_ex(cert->publicKey, &idx,
cert->pubKeySize, NULL, (word32*)&keySz, NULL, NULL);
if ((ret == 0) && checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minRsaKeySz :
ctx->minRsaKeySz, RSA_MAX_SIZE / 8, keySz, RSA_KEY_SIZE_E);
}
#ifdef WC_RSA_PSS
if (ssl) {
ssl->useRsaPss = cert->keyOID == RSAPSSk;
}
if (ctx) {
ctx->useRsaPss = cert->keyOID == RSAPSSk;
}
#endif
break;
#endif
#ifdef HAVE_ECC
case ECDSAk:
keyType = ecc_dsa_sa_algo;
#ifdef WOLFSSL_CUSTOM_CURVES
if ((cert->pkCurveOID == 0) && (cert->pkCurveSize != 0)) {
keySz = cert->pkCurveSize;
}
else
#endif
{
keySz = wc_ecc_get_curve_size_from_id(wc_ecc_get_oid(
cert->pkCurveOID, NULL, NULL));
}
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
ctx->minEccKeySz, (MAX_ECC_BITS + 7) / 8, keySz,
ECC_KEY_SIZE_E);
}
break;
#endif
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
case SM2k:
keyType = sm2_sa_algo;
keySz = WOLFSSL_SM2_KEY_BITS / 8;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
ctx->minEccKeySz, (MAX_ECC_BITS + 7) / 8, keySz,
ECC_KEY_SIZE_E);
}
break;
#endif
#ifdef HAVE_ED25519
case ED25519k:
keyType = ed25519_sa_algo;
keySz = ED25519_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
ctx->minEccKeySz, ED25519_KEY_SIZE, keySz, ECC_KEY_SIZE_E);
}
break;
#endif
#ifdef HAVE_ED448
case ED448k:
keyType = ed448_sa_algo;
keySz = ED448_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
ctx->minEccKeySz, ED448_KEY_SIZE, keySz, ECC_KEY_SIZE_E);
}
break;
#endif
#if defined(HAVE_FALCON)
case FALCON_LEVEL1k:
keyType = falcon_level1_sa_algo;
keySz = FALCON_LEVEL1_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minFalconKeySz :
ctx->minFalconKeySz, FALCON_MAX_KEY_SIZE, keySz,
FALCON_KEY_SIZE_E);
}
break;
case FALCON_LEVEL5k:
keyType = falcon_level5_sa_algo;
keySz = FALCON_LEVEL5_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minFalconKeySz :
ctx->minFalconKeySz, FALCON_MAX_KEY_SIZE, keySz,
FALCON_KEY_SIZE_E);
}
break;
#endif
#if defined(HAVE_DILITHIUM)
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
case DILITHIUM_LEVEL2k:
keyType = dilithium_level2_sa_algo;
keySz = DILITHIUM_LEVEL2_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz :
ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz,
DILITHIUM_KEY_SIZE_E);
}
break;
case DILITHIUM_LEVEL3k:
keyType = dilithium_level3_sa_algo;
keySz = DILITHIUM_LEVEL3_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz :
ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz,
DILITHIUM_KEY_SIZE_E);
}
break;
case DILITHIUM_LEVEL5k:
keyType = dilithium_level5_sa_algo;
keySz = DILITHIUM_LEVEL5_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz :
ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz,
DILITHIUM_KEY_SIZE_E);
}
break;
#endif
case ML_DSA_LEVEL2k:
keyType = dilithium_level2_sa_algo;
keySz = ML_DSA_LEVEL2_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz :
ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz,
DILITHIUM_KEY_SIZE_E);
}
break;
case ML_DSA_LEVEL3k:
keyType = dilithium_level3_sa_algo;
keySz = ML_DSA_LEVEL3_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz :
ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz,
DILITHIUM_KEY_SIZE_E);
}
break;
case ML_DSA_LEVEL5k:
keyType = dilithium_level5_sa_algo;
keySz = ML_DSA_LEVEL5_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz :
ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz,
DILITHIUM_KEY_SIZE_E);
}
break;
#endif
default:
WOLFSSL_MSG("No key size check done on public key in certificate");
break;
}
if (ssl != NULL) {
ssl->buffers.keyType = keyType;
ssl->buffers.keySz = keySz;
}
else {
ctx->privateKeyType = keyType;
ctx->privateKeySz = keySz;
}
return ret;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
static int ProcessBufferCertAltPublicKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DecodedCert* cert, int checkKeySz)
{
int ret = 0;
void* heap = WOLFSSL_HEAP(ctx, ssl);
byte keyType = 0;
int keySz = 0;
#ifndef NO_RSA
word32 idx;
#endif
switch (cert->sapkiOID) {
case 0:
if (cert->sapkiLen != 0) {
ret = NOT_COMPILED_IN;
}
break;
#ifndef NO_RSA
#ifdef WC_RSA_PSS
case RSAPSSk:
#endif
case RSAk:
keyType = rsa_sa_algo;
idx = 0;
ret = wc_RsaPublicKeyDecode_ex(cert->sapkiDer, &idx,
cert->sapkiLen, NULL, (word32*)&keySz, NULL, NULL);
if ((ret == 0) && checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minRsaKeySz :
ctx->minRsaKeySz, RSA_MAX_SIZE / 8, keySz, RSA_KEY_SIZE_E);
}
break;
#endif
#ifdef HAVE_ECC
case ECDSAk:
{
WC_DECLARE_VAR(temp_key, ecc_key, 1, 0);
keyType = ecc_dsa_sa_algo;
WC_ALLOC_VAR_EX(temp_key, ecc_key, 1, heap, DYNAMIC_TYPE_ECC,
ret=MEMORY_E);
if (ret == 0) {
ret = wc_ecc_init_ex(temp_key, heap, INVALID_DEVID);
if (ret == 0) {
idx = 0;
ret = wc_EccPublicKeyDecode(cert->sapkiDer, &idx, temp_key,
cert->sapkiLen);
if (ret == 0) {
keySz = wc_ecc_size(temp_key);
}
wc_ecc_free(temp_key);
}
}
WC_FREE_VAR_EX(temp_key, heap, DYNAMIC_TYPE_ECC);
if ((ret == 0) && checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
ctx->minEccKeySz, (MAX_ECC_BITS + 7) / 8, keySz,
ECC_KEY_SIZE_E);
}
break;
}
#endif
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
case SM2k:
keyType = sm2_sa_algo;
keySz = WOLFSSL_SM2_KEY_BITS / 8;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
ctx->minEccKeySz, (MAX_ECC_BITS + 7) / 8, keySz,
ECC_KEY_SIZE_E);
}
break;
#endif
#ifdef HAVE_ED25519
case ED25519k:
keyType = ed25519_sa_algo;
keySz = ED25519_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
ctx->minEccKeySz, ED25519_KEY_SIZE, keySz, ECC_KEY_SIZE_E);
}
break;
#endif
#ifdef HAVE_ED448
case ED448k:
keyType = ed448_sa_algo;
keySz = ED448_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minEccKeySz :
ctx->minEccKeySz, ED448_KEY_SIZE, keySz, ECC_KEY_SIZE_E);
}
break;
#endif
#if defined(HAVE_FALCON)
case FALCON_LEVEL1k:
keyType = falcon_level1_sa_algo;
keySz = FALCON_LEVEL1_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minFalconKeySz :
ctx->minFalconKeySz, FALCON_MAX_KEY_SIZE, keySz,
FALCON_KEY_SIZE_E);
}
break;
case FALCON_LEVEL5k:
keyType = falcon_level5_sa_algo;
keySz = FALCON_LEVEL5_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minFalconKeySz :
ctx->minFalconKeySz, FALCON_MAX_KEY_SIZE, keySz,
FALCON_KEY_SIZE_E);
}
break;
#endif
#if defined(HAVE_DILITHIUM)
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
case DILITHIUM_LEVEL2k:
keyType = dilithium_level2_sa_algo;
keySz = DILITHIUM_LEVEL2_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz :
ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz,
DILITHIUM_KEY_SIZE_E);
}
break;
case DILITHIUM_LEVEL3k:
keyType = dilithium_level3_sa_algo;
keySz = DILITHIUM_LEVEL3_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz :
ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz,
DILITHIUM_KEY_SIZE_E);
}
break;
case DILITHIUM_LEVEL5k:
keyType = dilithium_level5_sa_algo;
keySz = DILITHIUM_LEVEL5_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz :
ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz,
DILITHIUM_KEY_SIZE_E);
}
break;
#endif
case ML_DSA_LEVEL2k:
keyType = dilithium_level2_sa_algo;
keySz = ML_DSA_LEVEL2_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz :
ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz,
DILITHIUM_KEY_SIZE_E);
}
break;
case ML_DSA_LEVEL3k:
keyType = dilithium_level3_sa_algo;
keySz = ML_DSA_LEVEL3_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz :
ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz,
DILITHIUM_KEY_SIZE_E);
}
break;
case ML_DSA_LEVEL5k:
keyType = dilithium_level5_sa_algo;
keySz = ML_DSA_LEVEL5_KEY_SIZE;
if (checkKeySz) {
ret = CHECK_KEY_SZ(ssl ? ssl->options.minDilithiumKeySz :
ctx->minDilithiumKeySz, DILITHIUM_MAX_KEY_SIZE, keySz,
DILITHIUM_KEY_SIZE_E);
}
break;
#endif
default:
ret = NOT_COMPILED_IN;
WOLFSSL_MSG("No alt key size check done on certificate");
break;
}
if (ssl != NULL) {
ssl->buffers.altKeyType = (byte)keyType;
ssl->buffers.altKeySz = keySz;
}
else if (ctx != NULL) {
ctx->altPrivateKeyType = (byte)keyType;
ctx->altPrivateKeySz = keySz;
}
return ret;
}
#endif
static int ProcessBufferCert(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der)
{
int ret = 0;
void* heap = WOLFSSL_HEAP(ctx, ssl);
#if defined(HAVE_RPK)
RpkState* rpkState = ssl ? &ssl->options.rpkState : &ctx->rpkState;
#endif
WC_DECLARE_VAR(cert, DecodedCert, 1, 0);
WC_ALLOC_VAR_EX(cert, DecodedCert, 1, heap, DYNAMIC_TYPE_DCERT,
ret=MEMORY_E);
if (WC_VAR_OK(cert))
{
int devId = wolfSSL_CTX_GetDevId(ctx, ssl);
WOLFSSL_MSG("Checking cert signature type");
InitDecodedCert_ex(cert, der->buffer, der->length, heap, devId);
if (DecodeToKey(cert, 0) < 0) {
WOLFSSL_MSG("Decode to key failed");
ret = WOLFSSL_BAD_FILE;
}
if (ret == 0) {
int checkKeySz = 1;
#if defined(HAVE_RPK)
rpkState->isRPKLoaded = cert->isRPK;
#endif
ProcessBufferCertSetHave(ctx, ssl, cert);
if ((ssl != NULL) && ssl->options.verifyNone) {
checkKeySz = 0;
}
else if ((ssl == NULL) && (ctx != NULL) && ctx->verifyNone) {
checkKeySz = 0;
}
ret = ProcessBufferCertPublicKey(ctx, ssl, cert, checkKeySz);
#ifdef WOLFSSL_DUAL_ALG_CERTS
if (ret == 0) {
ret = ProcessBufferCertAltPublicKey(ctx, ssl, cert, checkKeySz);
}
#endif
}
}
FreeDecodedCert(cert);
WC_FREE_VAR_EX(cert, heap, DYNAMIC_TYPE_DCERT);
return ret;
}
static int ProcessBufferCertHandleDer(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int type, int verify)
{
int ret = 0;
if (type == CA_TYPE) {
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
word32 derLen;
byte* derBuf;
if (ctx->doAppleNativeCertValidationFlag == 1) {
WOLFSSL_MSG("ANCV Test: copy DER CA cert");
derLen = der->length;
derBuf = (byte*)XMALLOC(derLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (derBuf == NULL) {
return MEMORY_E;
}
XMEMCPY(derBuf, der->buffer, derLen);
}
else {
(void)derLen;
(void)derBuf;
}
#endif
ret = AddCA(ctx->cm, &der, WOLFSSL_USER_CA, verify);
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
if (ret == 1 && ctx->doAppleNativeCertValidationFlag == 1) {
WOLFSSL_MSG("ANCV Test: Appending CA to cert list");
ret = wolfSSL_TestAppleNativeCertValidation_AppendCA(ctx, derBuf,
(int)derLen);
if (ret == WOLFSSL_SUCCESS) {
WOLFSSL_MSG("ANCV Test: Clearing CA table");
ret = wolfSSL_CertManagerUnloadCAs(ctx->cm);
if (ret == WOLFSSL_SUCCESS) {
ret = 0;
}
}
XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
if (ret == 1) {
ret = 0;
}
}
#ifdef WOLFSSL_TRUST_PEER_CERT
else if (type == TRUSTED_PEER_TYPE) {
WOLFSSL_CERT_MANAGER* cm;
if (ctx != NULL) {
cm = ctx->cm;
}
else {
SSL_CM_WARNING(ssl);
cm = SSL_CM(ssl);
}
ret = AddTrustedPeer(cm, &der, verify);
if (ret != 1) {
WOLFSSL_MSG("Error adding trusted peer");
}
}
#endif
else if (type == CERT_TYPE) {
if (ssl != NULL) {
if (ssl->buffers.weOwnCert) {
FreeDer(&ssl->buffers.certificate);
#ifdef KEEP_OUR_CERT
wolfSSL_X509_free(ssl->ourCert);
ssl->ourCert = NULL;
#endif
}
ssl->buffers.certificate = der;
#ifdef KEEP_OUR_CERT
ssl->keepCert = 1;
#endif
ssl->buffers.weOwnCert = 1;
}
else if (ctx != NULL) {
FreeDer(&ctx->certificate);
#ifdef KEEP_OUR_CERT
if (ctx->ownOurCert) {
wolfSSL_X509_free(ctx->ourCert);
}
ctx->ourCert = NULL;
#endif
ctx->certificate = der;
}
}
else {
FreeDer(&der);
ret = WOLFSSL_BAD_CERTTYPE;
}
return ret;
}
static int ProcessBufferCertTypes(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
const unsigned char* buff, long sz, DerBuffer* der, int format, int type,
int verify)
{
int ret;
(void)buff;
(void)sz;
(void)format;
ret = ProcessBufferCertHandleDer(ctx, ssl, der, type, verify);
if ((ret == 0) && (type == CERT_TYPE)) {
ret = ProcessBufferCert(ctx, ssl, der);
}
#if !defined(NO_WOLFSSL_CM_VERIFY) && (!defined(NO_WOLFSSL_CLIENT) || \
!defined(WOLFSSL_NO_CLIENT_AUTH))
if ((ret < 0) && ((type == CA_TYPE) || (type == CERT_TYPE))) {
if ((ctx != NULL) && (ctx->cm != NULL) &&
(ctx->cm->verifyCallback != NULL)) {
ret = CM_VerifyBuffer_ex(ctx->cm, buff, sz, format, ret);
if (ret == 0) {
ret = WOLFSSL_FATAL_ERROR;
}
if (ret == 1) {
ret = 0;
}
}
}
#endif
return ret;
}
static int ProcessBufferResetSuites(WOLFSSL_CTX* ctx, WOLFSSL* ssl, int type)
{
int ret = 0;
if (ssl != NULL) {
if (ssl->options.side == WOLFSSL_SERVER_END) {
if (AllocateSuites(ssl) != 0) {
ret = WOLFSSL_FATAL_ERROR;
}
else {
InitSuites(ssl->suites, ssl->version, ssl->buffers.keySz,
WOLFSSL_HAVE_RSA, SSL_HAVE_PSK(ssl), ssl->options.haveDH,
ssl->options.haveECDSAsig, ssl->options.haveECC, TRUE,
ssl->options.haveStaticECC,
ssl->options.useAnon, TRUE,
TRUE, TRUE, TRUE, ssl->options.side);
}
}
}
else if ((type == CERT_TYPE) && (ctx->method->side == WOLFSSL_SERVER_END)) {
if (AllocateCtxSuites(ctx) != 0) {
ret = WOLFSSL_FATAL_ERROR;
}
else {
InitSuites(ctx->suites, ctx->method->version, ctx->privateKeySz,
WOLFSSL_HAVE_RSA, CTX_HAVE_PSK(ctx), ctx->haveDH,
ctx->haveECDSAsig, ctx->haveECC, TRUE, ctx->haveStaticECC,
CTX_USE_ANON(ctx),
TRUE, TRUE, TRUE, TRUE, ctx->method->side);
}
}
return ret;
}
#ifndef WOLFSSL_DUAL_ALG_CERTS
#define IS_PRIVKEY_TYPE(type) ((type) == PRIVATEKEY_TYPE)
#else
#define IS_PRIVKEY_TYPE(type) (((type) == PRIVATEKEY_TYPE) || \
((type) == ALT_PRIVATEKEY_TYPE))
#endif
int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, long sz,
int format, int type, WOLFSSL* ssl, long* used, int userChain, int verify,
const char *source_name)
{
DerBuffer* der = NULL;
int ret = 0;
void* heap = WOLFSSL_HEAP(ctx, ssl);
WC_DECLARE_VAR(info, EncryptedInfo, 1, 0);
int algId = 0;
#ifdef WOLFSSL_DEBUG_CERTIFICATE_LOADS
long usedAtStart = used ? *used : 0L;
#else
(void)source_name;
#endif
WOLFSSL_ENTER("ProcessBuffer");
if ((format != WOLFSSL_FILETYPE_ASN1) && (format != WOLFSSL_FILETYPE_PEM)) {
ret = WOLFSSL_BAD_FILETYPE;
}
if ((ret == 0) && (ctx == NULL) && (ssl == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (ctx == NULL) && (type == CA_TYPE)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (type == CHAIN_CERT_TYPE)) {
ret = BAD_FUNC_ARG;
}
#ifdef WOLFSSL_SMALL_STACK
if (ret == 0) {
info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), heap,
DYNAMIC_TYPE_ENCRYPTEDINFO);
if (info == NULL) {
ret = MEMORY_E;
}
}
#endif
if (ret == 0) {
XMEMSET(info, 0, sizeof(EncryptedInfo));
#if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED)
if (ctx != NULL) {
info->passwd_cb = ctx->passwd_cb;
info->passwd_userdata = ctx->passwd_userdata;
}
#endif
ret = DataToDerBuffer(buff, (word32)sz, format, type, info, heap, &der,
&algId);
if (used != NULL) {
*used = info->consumed;
}
#ifdef WOLFSSL_SMALL_STACK
if (ret != 0) {
XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO);
}
#endif
}
if ((ret == 0) && IS_PRIVKEY_TYPE(type)) {
ret = ProcessBufferPrivateKey(ctx, ssl, der, format, info, heap, type,
algId);
WC_FREE_VAR_EX(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO);
}
else if (ret == 0) {
if (userChain) {
ret = ProcessUserChain(ctx, ssl, buff, sz, format, type, used, info,
verify);
if (ret == WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER)) {
unsigned long pemErr = 0;
CLEAR_ASN_NO_PEM_HEADER_ERROR(pemErr);
ret = 0;
}
#ifdef WOLFSSL_DEBUG_CERTIFICATE_LOADS
if (ret < 0) {
#ifdef NO_ERROR_STRINGS
WOLFSSL_DEBUG_PRINTF(
"ERROR: ProcessUserChain: certificate from %s at offset %ld"
" rejected with code %d\n",
source_name, usedAtStart, ret);
#else
WOLFSSL_DEBUG_PRINTF(
"ERROR: ProcessUserChain: certificate from %s at offset %ld"
" rejected with code %d: %s\n",
source_name, usedAtStart, ret,
wolfSSL_ERR_reason_error_string(ret));
#endif
}
#endif
}
WC_FREE_VAR_EX(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO);
if (ret == 0) {
ret = ProcessBufferCertTypes(ctx, ssl, buff, sz, der, format, type,
verify);
#ifdef WOLFSSL_DEBUG_CERTIFICATE_LOADS
if (ret < 0) {
#ifdef NO_ERROR_STRINGS
WOLFSSL_DEBUG_PRINTF(
"ERROR: ProcessBufferCertTypes: certificate from %s at"
" offset %ld rejected with code %d\n",
source_name, usedAtStart, ret);
#else
WOLFSSL_DEBUG_PRINTF(
"ERROR: ProcessBufferCertTypes: certificate from %s at"
" offset %ld rejected with code %d: %s\n",
source_name, usedAtStart, ret,
wolfSSL_ERR_reason_error_string(ret));
#endif
}
#endif
}
else {
FreeDer(&der);
}
}
if ((ret == 0) && ((type == PRIVATEKEY_TYPE) || (type == CERT_TYPE))) {
ret = ProcessBufferResetSuites(ctx, ssl, type);
}
if (ret == 0) {
ret = 1;
}
else if (ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) {
ret = 0;
}
WOLFSSL_LEAVE("ProcessBuffer", ret);
return ret;
}
#if defined(WOLFSSL_WPAS) && defined(HAVE_CRL)
static int ProcessChainBufferCRL(WOLFSSL_CTX* ctx, const unsigned char* buff,
long sz, long* consumed)
{
int ret;
DerBuffer* der = NULL;
EncryptedInfo info;
WOLFSSL_MSG("Trying a CRL");
ret = PemToDer(buff, sz, CRL_TYPE, &der, NULL, &info, NULL);
if (ret == 0) {
WOLFSSL_MSG(" Processed a CRL");
wolfSSL_CertManagerLoadCRLBuffer(ctx->cm, der->buffer, der->length,
WOLFSSL_FILETYPE_ASN1);
FreeDer(&der);
*consumed = info.consumed;
}
return ret;
}
#endif
static int ProcessChainBuffer(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
const unsigned char* buff, long sz, int type, int verify,
const char *source_name)
{
int ret = 0;
long used = 0;
int gotOne = 0;
WOLFSSL_MSG("Processing CA PEM file");
while ((ret >= 0) && (used < sz)) {
long consumed = used;
ret = ProcessBuffer(ctx, buff + used, sz - used, WOLFSSL_FILETYPE_PEM,
type, ssl, &consumed, 0, verify, source_name);
if (ret == WC_NO_ERR_TRACE(MEMORY_E)) {
gotOne = 0;
}
else if (ret < 0) {
#if defined(WOLFSSL_WPAS) && defined(HAVE_CRL)
if (ProcessChainBufferCRL(ctx, buff + used, sz - used,
&consumed) == 0) {
ret = 0;
}
else
#endif
if (consumed > 0) {
WOLFSSL_ERROR(ret);
WOLFSSL_MSG("CA Parse failed, with progress in file.");
WOLFSSL_MSG("Search for other certs in file");
if (used + consumed < sz) {
ret = 0;
}
}
else {
WOLFSSL_MSG("CA Parse failed, no progress in file.");
WOLFSSL_MSG("Do not continue search for other certs in file");
}
}
else {
WOLFSSL_MSG(" Processed a CA");
gotOne = 1;
}
used += consumed;
}
if (gotOne) {
WOLFSSL_MSG("Processed at least one valid CA. Other stuff OK");
ret = 1;
}
return ret;
}
#define GET_VERIFY_SETTING_CTX(ctx) \
((ctx) && (ctx)->verifyNone ? NO_VERIFY : VERIFY)
#define GET_VERIFY_SETTING_SSL(ssl) \
((ssl)->options.verifyNone ? NO_VERIFY : VERIFY)
#ifndef NO_FILESYSTEM
int ProcessFile(WOLFSSL_CTX* ctx, const char* fname, int format, int type,
WOLFSSL* ssl, int userChain, WOLFSSL_CRL* crl, int verify)
{
int ret = 0;
#ifndef WOLFSSL_SMALL_STACK
byte stackBuffer[FILE_BUFFER_SIZE];
#endif
StaticBuffer content;
long sz = 0;
void* heap = WOLFSSL_HEAP(ctx, ssl);
(void)crl;
(void)heap;
#ifdef WOLFSSL_SMALL_STACK
static_buffer_init(&content);
#else
static_buffer_init(&content, stackBuffer, FILE_BUFFER_SIZE);
#endif
ret = wolfssl_read_file_static(fname, &content, heap, DYNAMIC_TYPE_FILE,
&sz);
if ((ret == 0) && (type == DETECT_CERT_TYPE) &&
(format != WOLFSSL_FILETYPE_PEM)) {
WOLFSSL_MSG_CERT_LOG("Cannot detect certificate type when not PEM");
ret = WOLFSSL_BAD_CERTTYPE;
}
if ((ret == 0) && (type == DETECT_CERT_TYPE)) {
#if !defined(NO_CODING) && !defined(WOLFSSL_NO_PEM)
const char* header = NULL;
const char* footer = NULL;
#ifdef HAVE_CRL
WOLFSSL_MSG_CERT("Detecting cert type... (including CRL_TYPE)");
#else
WOLFSSL_MSG_CERT("Detecting cert type... (HAVE_CRL not defined)");
#endif
if (wc_PemGetHeaderFooter(CA_TYPE, &header, &footer) == 0 &&
(XSTRNSTR((char*)content.buffer, header, (word32)sz) != NULL)) {
type = CA_TYPE;
WOLFSSL_MSG_CERT_LOG_EX("Detected cert type CA_TYPE = %d:", type);
}
#ifdef HAVE_CRL
else if (wc_PemGetHeaderFooter(CRL_TYPE, &header, &footer) == 0 &&
(XSTRNSTR((char*)content.buffer, header, (word32)sz) != NULL)) {
type = CRL_TYPE;
WOLFSSL_MSG_CERT_LOG_EX("Detected cert type CRL_TYPE = %d:", type);
}
#endif
else if (wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer) == 0 &&
(XSTRNSTR((char*)content.buffer, header, (word32)sz) !=
NULL)) {
type = CERT_TYPE;
WOLFSSL_MSG_CERT_LOG_EX("Detected cert type CERT_TYPE = %d:", type);
}
else
#endif
{
WOLFSSL_MSG_CERT_LOG("Failed to detect certificate type");
#ifdef WOLFSSL_DEBUG_CERTIFICATE_LOADS
WOLFSSL_DEBUG_PRINTF(
"ERROR: ProcessFile: Failed to detect certificate type"
" of \"%s\"\n",
fname);
#endif
ret = WOLFSSL_BAD_CERTTYPE;
}
}
if (ret == 0) {
if (((type == CA_TYPE) || (type == TRUSTED_PEER_TYPE)) &&
(format == WOLFSSL_FILETYPE_PEM)) {
WOLFSSL_MSG_CERT("Processing cert chain buffer...");
ret = ProcessChainBuffer(ctx, ssl, content.buffer, sz, type,
verify, fname);
}
#ifdef HAVE_CRL
else if (type == CRL_TYPE) {
WOLFSSL_MSG_CERT("Loading CRL...");
ret = BufferLoadCRL(crl, content.buffer, sz, format, verify);
}
#endif
#ifdef WOLFSSL_DUAL_ALG_CERTS
else if (type == PRIVATEKEY_TYPE) {
long consumed = 0;
ret = ProcessBuffer(ctx, content.buffer, sz, format, type, ssl,
&consumed, userChain, verify, fname);
if ((ret == 1) && (consumed < sz)) {
ret = ProcessBuffer(ctx, content.buffer + consumed,
sz - consumed, format, ALT_PRIVATEKEY_TYPE, ssl, NULL, 0,
verify, fname);
}
}
#endif
else {
ret = ProcessBuffer(ctx, content.buffer, sz, format, type, ssl,
NULL, userChain, verify, fname);
}
}
static_buffer_free(&content, heap, DYNAMIC_TYPE_FILE);
return ret;
}
#ifndef NO_WOLFSSL_DIR
static int wolfssl_ctx_load_path_file(WOLFSSL_CTX* ctx, const char* name,
int verify, int flags, int* failCount, int* successCount)
{
int ret;
ret = ProcessFile(ctx, name, WOLFSSL_FILETYPE_PEM, CA_TYPE, NULL, 0, NULL,
verify);
if (ret != 1) {
if ((flags & WOLFSSL_LOAD_FLAG_IGNORE_ERR) ||
((flags & WOLFSSL_LOAD_FLAG_PEM_CA_ONLY) &&
(ret == WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER)))) {
unsigned long err = 0;
CLEAR_ASN_NO_PEM_HEADER_ERROR(err);
#if defined(WOLFSSL_QT)
ret = 1;
#endif
}
else {
WOLFSSL_ERROR(ret);
WOLFSSL_MSG("Load CA file failed, continuing");
(*failCount)++;
}
}
else {
#if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS)
ret = wolfSSL_CTX_trust_peer_cert(ctx, name, WOLFSSL_FILETYPE_PEM);
if (ret != 1) {
WOLFSSL_MSG("wolfSSL_CTX_trust_peer_cert error. "
"Ignoring this error.");
}
#endif
(*successCount)++;
}
return ret;
}
static int wolfssl_ctx_load_path(WOLFSSL_CTX* ctx, const char* path,
word32 flags, int verify, int successCount)
{
int ret = 1;
char* name = NULL;
int fileRet;
int failCount = 0;
WC_DECLARE_VAR(readCtx, ReadDirCtx, 1, 0);
WC_ALLOC_VAR_EX(readCtx, ReadDirCtx, 1, ctx->heap, DYNAMIC_TYPE_DIRCTX,
ret=MEMORY_E);
if (ret == 1) {
fileRet = wc_ReadDirFirst(readCtx, path, &name);
while ((fileRet == 0) && (name != NULL)) {
WOLFSSL_MSG(name);
ret = wolfssl_ctx_load_path_file(ctx, name, verify, (int)flags,
&failCount, &successCount);
fileRet = wc_ReadDirNext(readCtx, path, &name);
}
wc_ReadDirClose(readCtx);
(void)ret;
if (fileRet != WC_READDIR_NOFILE) {
ret = fileRet;
#if defined(WOLFSSL_QT) || defined(WOLFSSL_IGNORE_BAD_CERT_PATH)
if ((ret == WC_NO_ERR_TRACE(BAD_PATH_ERROR)) &&
(flags & WOLFSSL_LOAD_FLAG_IGNORE_BAD_PATH_ERR)) {
ret = 1;
}
else {
WOLFSSL_ERROR(ret);
}
#endif
}
else if ((successCount == 0) || (failCount > 0)) {
#if defined(WOLFSSL_QT)
if (!(flags & WOLFSSL_LOAD_FLAG_IGNORE_ZEROFILE))
#endif
{
ret = 0;
}
}
else {
ret = 1;
}
WC_FREE_VAR_EX(readCtx, ctx->heap, DYNAMIC_TYPE_DIRCTX);
}
return ret;
}
#endif
int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX* ctx, const char* file,
const char* path, word32 flags)
{
int ret = 1;
#ifndef NO_WOLFSSL_DIR
int successCount = 0;
#endif
int verify = WOLFSSL_VERIFY_DEFAULT;
WOLFSSL_MSG("wolfSSL_CTX_load_verify_locations_ex");
if ((ctx == NULL) || ((file == NULL) && (path == NULL))) {
ret = 0;
}
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
if (ret == 1) {
WOLFSSL_MSG("ANCV Test: Loading system CA certs");
wolfSSL_CTX_load_system_CA_certs(ctx);
}
#endif
if (ret == 1) {
verify = GET_VERIFY_SETTING_CTX(ctx);
if (flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) {
verify = VERIFY_SKIP_DATE;
}
if (file != NULL) {
#ifdef WOLFSSL_PEM_TO_DER
ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CA_TYPE, NULL, 0,
NULL, verify);
#else
ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_ASN1, CA_TYPE, NULL,
0, NULL, verify);
#endif
#ifndef NO_WOLFSSL_DIR
if (ret == 1) {
successCount++;
}
#endif
#if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS)
#ifdef WOLFSSL_PEM_TO_DER
ret = wolfSSL_CTX_trust_peer_cert(ctx, file, WOLFSSL_FILETYPE_PEM);
#else
ret = wolfSSL_CTX_trust_peer_cert(ctx, file, WOLFSSL_FILETYPE_ASN1);
#endif
if (ret != 1) {
WOLFSSL_MSG("wolfSSL_CTX_trust_peer_cert error");
}
#endif
}
}
if ((ret == 1) && (path != NULL)) {
#ifndef NO_WOLFSSL_DIR
ret = wolfssl_ctx_load_path(ctx, path, flags, verify, successCount);
#else
ret = NOT_COMPILED_IN;
(void)flags;
#endif
}
return ret;
}
WOLFSSL_ABI
int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
const char* path)
{
int ret = wolfSSL_CTX_load_verify_locations_ex(ctx, file, path,
WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS);
return WS_RETURN_CODE(ret, 0);
}
int wolfSSL_CTX_load_verify_locations_compat(WOLFSSL_CTX* ctx, const char* file,
const char* path)
{
int ret = wolfSSL_CTX_load_verify_locations_ex(ctx, file, path,
WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS | WOLFSSL_LOAD_FLAG_IGNORE_ERR);
return WS_RETURN_CODE(ret, 0);
}
#ifdef WOLFSSL_TRUST_PEER_CERT
int wolfSSL_CTX_trust_peer_cert(WOLFSSL_CTX* ctx, const char* file, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_trust_peer_cert");
if ((ctx == NULL) || (file == NULL)) {
ret = 0;
}
else {
ret = ProcessFile(ctx, file, format, TRUSTED_PEER_TYPE, NULL, 0, NULL,
GET_VERIFY_SETTING_CTX(ctx));
}
return ret;
}
int wolfSSL_trust_peer_cert(WOLFSSL* ssl, const char* file, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_trust_peer_cert");
if ((ssl == NULL) || (file == NULL)) {
ret = 0;
}
else {
ret = ProcessFile(NULL, file, format, TRUSTED_PEER_TYPE, ssl, 0, NULL,
GET_VERIFY_SETTING_SSL(ssl));
}
return ret;
}
#endif
#ifdef WOLFSSL_DER_LOAD
int wolfSSL_CTX_der_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_der_load_verify_locations");
if ((ctx == NULL) || (file == NULL)) {
ret = 0;
}
else {
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
WOLFSSL_MSG("ANCV Test: loading system CA certs");
wolfSSL_CTX_load_system_CA_certs(ctx);
#endif
ret = ProcessFile(ctx, file, format, CA_TYPE, NULL, 0, NULL,
GET_VERIFY_SETTING_CTX(ctx));
}
return WS_RC(ret);
}
#endif
WOLFSSL_ABI
int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX* ctx, const char* file,
int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_file");
ret = ProcessFile(ctx, file, format, CERT_TYPE, NULL, 0, NULL,
GET_VERIFY_SETTING_CTX(ctx));
return WS_RC(ret);
}
WOLFSSL_ABI
int wolfSSL_CTX_use_PrivateKey_file(WOLFSSL_CTX* ctx, const char* file,
int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_file");
ret = ProcessFile(ctx, file, format, PRIVATEKEY_TYPE, NULL, 0, NULL,
GET_VERIFY_SETTING_CTX(ctx));
return WS_RC(ret);
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
int wolfSSL_CTX_use_AltPrivateKey_file(WOLFSSL_CTX* ctx, const char* file,
int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_file");
ret = ProcessFile(ctx, file, format, ALT_PRIVATEKEY_TYPE, NULL, 0, NULL,
GET_VERIFY_SETTING_CTX(ctx));
return WS_RC(ret);
}
#endif
WOLFSSL_ABI
int wolfSSL_CTX_use_certificate_chain_file(WOLFSSL_CTX* ctx, const char* file)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file");
#ifdef WOLFSSL_PEM_TO_DER
ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, NULL, 1, NULL,
GET_VERIFY_SETTING_CTX(ctx));
#else
ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, NULL, 1,
NULL, GET_VERIFY_SETTING_CTX(ctx));
#endif
return WS_RC(ret);
}
int wolfSSL_CTX_use_certificate_chain_file_format(WOLFSSL_CTX* ctx,
const char* file, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file_format");
ret = ProcessFile(ctx, file, format, CERT_TYPE, NULL, 1, NULL,
GET_VERIFY_SETTING_CTX(ctx));
return WS_RC(ret);
}
#endif
#ifdef WOLFSSL_SYS_CA_CERTS
#ifdef USE_WINDOWS_API
static int LoadSystemCaCertsWindows(WOLFSSL_CTX* ctx, byte* loaded)
{
int ret = 1;
word32 i;
HANDLE handle = NULL;
PCCERT_CONTEXT certCtx = NULL;
LPCSTR storeNames[2] = {"ROOT", "CA"};
HCRYPTPROV_LEGACY hProv = (HCRYPTPROV_LEGACY)NULL;
if ((ctx == NULL) || (loaded == NULL)) {
ret = 0;
}
for (i = 0; (ret == 1) && (i < sizeof(storeNames)/sizeof(*storeNames));
++i) {
handle = CertOpenSystemStoreA(hProv, storeNames[i]);
if (handle != NULL) {
while ((certCtx = CertEnumCertificatesInStore(handle, certCtx))
!= NULL) {
if (certCtx->dwCertEncodingType == X509_ASN_ENCODING) {
if (ProcessBuffer(ctx, certCtx->pbCertEncoded,
certCtx->cbCertEncoded, WOLFSSL_FILETYPE_ASN1,
CA_TYPE, NULL, NULL, 0,
GET_VERIFY_SETTING_CTX(ctx),
storeNames[i]) == 1) {
*loaded = 1;
}
}
}
}
else {
WOLFSSL_MSG_EX("Failed to open cert store %s.", storeNames[i]);
}
if (handle != NULL && !CertCloseStore(handle, 0)) {
WOLFSSL_MSG_EX("Failed to close cert store %s.", storeNames[i]);
ret = 0;
}
}
return ret;
}
#elif defined(__APPLE__)
#if defined(HAVE_SECURITY_SECTRUSTSETTINGS_H) \
&& !defined(WOLFSSL_APPLE_NATIVE_CERT_VALIDATION)
static int LoadSystemCaCertsMac(WOLFSSL_CTX* ctx, byte* loaded)
{
int ret = 1;
word32 i;
const unsigned int trustDomains[] = {
kSecTrustSettingsDomainUser,
kSecTrustSettingsDomainAdmin,
kSecTrustSettingsDomainSystem
};
CFArrayRef certs;
OSStatus stat;
CFIndex numCerts;
CFDataRef der;
CFIndex j;
if ((ctx == NULL) || (loaded == NULL)) {
ret = 0;
}
for (i = 0; (ret == 1) && (i < sizeof(trustDomains)/sizeof(*trustDomains));
++i) {
stat = SecTrustSettingsCopyCertificates(
(SecTrustSettingsDomain)trustDomains[i], &certs);
if (stat == errSecSuccess) {
numCerts = CFArrayGetCount(certs);
for (j = 0; j < numCerts; ++j) {
der = SecCertificateCopyData((SecCertificateRef)
CFArrayGetValueAtIndex(certs, j));
if (der != NULL) {
if (ProcessBuffer(ctx, CFDataGetBytePtr(der),
CFDataGetLength(der), WOLFSSL_FILETYPE_ASN1,
CA_TYPE, NULL, NULL, 0,
GET_VERIFY_SETTING_CTX(ctx),
"MacOSX trustDomains") == 1) {
*loaded = 1;
}
CFRelease(der);
}
}
CFRelease(certs);
}
else if (stat == errSecNoTrustSettings) {
WOLFSSL_MSG_EX("No trust settings for domain %d, moving to next "
"domain.", trustDomains[i]);
}
else {
WOLFSSL_MSG_EX("SecTrustSettingsCopyCertificates failed with"
" status %d.", stat);
ret = 0;
break;
}
}
return ret;
}
#endif
#elif !defined(NO_FILESYSTEM)
static const char* systemCaDirs[] = {
#if defined(__ANDROID__) || defined(ANDROID)
"/system/etc/security/cacerts"
#else
"/etc/ssl/certs",
"/etc/pki/ca-trust/source/anchors",
"/etc/pki/tls/certs"
#endif
};
const char** wolfSSL_get_system_CA_dirs(word32* num)
{
const char** ret;
if (num == NULL) {
ret = NULL;
}
else {
ret = systemCaDirs;
*num = sizeof(systemCaDirs)/sizeof(*systemCaDirs);
}
return ret;
}
static int LoadSystemCaCertsNix(WOLFSSL_CTX* ctx, byte* loaded) {
int ret = 1;
word32 i;
if ((ctx == NULL) || (loaded == NULL)) {
ret = 0;
}
for (i = 0; (ret == 1) && (i < sizeof(systemCaDirs)/sizeof(*systemCaDirs));
++i) {
WOLFSSL_MSG_EX("Attempting to load system CA certs from %s.",
systemCaDirs[i]);
if (wolfSSL_CTX_load_verify_locations_ex(ctx, NULL, systemCaDirs[i],
WOLFSSL_LOAD_FLAG_IGNORE_ERR) != 1) {
WOLFSSL_MSG_EX("Failed to load CA certs from %s, trying "
"next possible location.", systemCaDirs[i]);
}
else {
WOLFSSL_MSG_EX("Loaded CA certs from %s.",
systemCaDirs[i]);
*loaded = 1;
break;
}
}
return ret;
}
#endif
int wolfSSL_CTX_load_system_CA_certs(WOLFSSL_CTX* ctx)
{
int ret;
byte loaded = 0;
WOLFSSL_ENTER("wolfSSL_CTX_load_system_CA_certs");
#ifdef USE_WINDOWS_API
ret = LoadSystemCaCertsWindows(ctx, &loaded);
#elif defined(__APPLE__)
#if defined(HAVE_SECURITY_SECTRUSTSETTINGS_H) \
&& !defined(WOLFSSL_APPLE_NATIVE_CERT_VALIDATION)
ret = LoadSystemCaCertsMac(ctx, &loaded);
#elif defined(WOLFSSL_APPLE_NATIVE_CERT_VALIDATION)
ctx->doAppleNativeCertValidationFlag = 1;
ret = 1;
loaded = 1;
#if FIPS_VERSION_GE(2,0)
#warning "Cryptographic operations may occur outside the FIPS module boundary" \
"Please review FIPS claims for cryptography on this Apple device"
#endif
#else
#error "WOLFSSL_SYS_CA_CERTS on Apple devices requires Security.framework" \
" header files to be detected, or a manual override with" \
" WOLFSSL_APPLE_NATIVE_CERT_VALIDATION"
#endif
#else
ret = LoadSystemCaCertsNix(ctx, &loaded);
#endif
if ((ret == 1) && (!loaded)) {
ret = WOLFSSL_BAD_PATH;
}
WOLFSSL_LEAVE("wolfSSL_CTX_load_system_CA_certs", ret);
return ret;
}
#endif
#ifdef OPENSSL_EXTRA
int wolfSSL_use_PrivateKey(WOLFSSL* ssl, WOLFSSL_EVP_PKEY* pkey)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_PrivateKey");
if ((ssl == NULL) || (pkey == NULL)) {
ret = 0;
}
else {
ret = wolfSSL_use_PrivateKey_buffer(ssl, (unsigned char*)pkey->pkey.ptr,
pkey->pkey_sz, WOLFSSL_FILETYPE_ASN1);
}
return ret;
}
int wolfSSL_use_PrivateKey_ASN1(int pri, WOLFSSL* ssl, const unsigned char* der,
long derSz)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_PrivateKey_ASN1");
(void)pri;
if ((ssl == NULL) || (der == NULL)) {
ret = 0;
}
else {
ret = wolfSSL_use_PrivateKey_buffer(ssl, der, derSz,
WOLFSSL_FILETYPE_ASN1);
}
return ret;
}
int wolfSSL_CTX_use_PrivateKey_ASN1(int pri, WOLFSSL_CTX* ctx,
unsigned char* der, long derSz)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_ASN1");
(void)pri;
if ((ctx == NULL) || (der == NULL)) {
ret = 0;
}
else {
ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, derSz,
WOLFSSL_FILETYPE_ASN1);
}
return ret;
}
#ifndef NO_RSA
int wolfSSL_use_RSAPrivateKey_ASN1(WOLFSSL* ssl, unsigned char* der, long derSz)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_RSAPrivateKey_ASN1");
if ((ssl == NULL) || (der == NULL)) {
ret = 0;
}
else {
ret = wolfSSL_use_PrivateKey_buffer(ssl, der, derSz,
WOLFSSL_FILETYPE_ASN1);
}
return ret;
}
#endif
int wolfSSL_use_certificate(WOLFSSL* ssl, WOLFSSL_X509* x509)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_certificate");
if ((ssl == NULL) || (x509 == NULL) || (x509->derCert == NULL)) {
ret = 0;
}
else {
long idx = 0;
ret = ProcessBuffer(NULL, x509->derCert->buffer, x509->derCert->length,
WOLFSSL_FILETYPE_ASN1, CERT_TYPE, ssl, &idx, 0,
GET_VERIFY_SETTING_SSL(ssl),
"x509 buffer");
}
return WS_RC(ret);
}
#endif
int wolfSSL_use_certificate_ASN1(WOLFSSL* ssl, const unsigned char* der,
int derSz)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_certificate_ASN1");
if ((ssl == NULL) || (der == NULL)) {
ret = 0;
}
else {
long idx = 0;
ret = ProcessBuffer(NULL, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE,
ssl, &idx, 0, GET_VERIFY_SETTING_SSL(ssl),
"asn1 buffer");
}
return WS_RC(ret);
}
#ifndef NO_FILESYSTEM
WOLFSSL_ABI
int wolfSSL_use_certificate_file(WOLFSSL* ssl, const char* file, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_certificate_file");
if (ssl == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 0, NULL,
GET_VERIFY_SETTING_SSL(ssl));
ret = WS_RC(ret);
}
return ret;
}
WOLFSSL_ABI
int wolfSSL_use_PrivateKey_file(WOLFSSL* ssl, const char* file, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_PrivateKey_file");
if (ssl == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = ProcessFile(ssl->ctx, file, format, PRIVATEKEY_TYPE, ssl, 0, NULL,
GET_VERIFY_SETTING_SSL(ssl));
ret = WS_RC(ret);
}
return ret;
}
WOLFSSL_ABI
int wolfSSL_use_certificate_chain_file(WOLFSSL* ssl, const char* file)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file");
if (ssl == NULL) {
ret = BAD_FUNC_ARG;
}
else {
#ifdef WOLFSSL_PEM_TO_DER
ret = ProcessFile(ssl->ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, ssl,
1, NULL, GET_VERIFY_SETTING_SSL(ssl));
#else
ret = ProcessFile(ssl->ctx, file, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, ssl,
1, NULL, GET_VERIFY_SETTING_SSL(ssl));
#endif
ret = WS_RC(ret);
}
return ret;
}
int wolfSSL_use_certificate_chain_file_format(WOLFSSL* ssl, const char* file,
int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file_format");
if (ssl == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 1, NULL,
GET_VERIFY_SETTING_SSL(ssl));
ret = WS_RC(ret);
}
return ret;
}
#endif
#ifdef OPENSSL_EXTRA
#ifndef NO_FILESYSTEM
int wolfSSL_CTX_use_RSAPrivateKey_file(WOLFSSL_CTX* ctx,const char* file,
int format)
{
WOLFSSL_ENTER("wolfSSL_CTX_use_RSAPrivateKey_file");
return wolfSSL_CTX_use_PrivateKey_file(ctx, file, format);
}
int wolfSSL_use_RSAPrivateKey_file(WOLFSSL* ssl, const char* file, int format)
{
WOLFSSL_ENTER("wolfSSL_use_RSAPrivateKey_file");
return wolfSSL_use_PrivateKey_file(ssl, file, format);
}
#endif
#endif
int wolfSSL_CTX_load_verify_buffer_ex(WOLFSSL_CTX* ctx, const unsigned char* in,
long sz, int format, int userChain, word32 flags)
{
int ret;
int verify;
WOLFSSL_ENTER("wolfSSL_CTX_load_verify_buffer_ex");
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
if (ctx != NULL) {
WOLFSSL_MSG("ANCV Test: loading system CA certs");
wolfSSL_CTX_load_system_CA_certs(ctx);
}
#endif
verify = GET_VERIFY_SETTING_CTX(ctx);
if (flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) {
verify = VERIFY_SKIP_DATE;
}
if (format == WOLFSSL_FILETYPE_PEM) {
ret = ProcessChainBuffer(ctx, NULL, in, sz, CA_TYPE, verify,
"PEM buffer");
}
else {
ret = ProcessBuffer(ctx, in, sz, format, CA_TYPE, NULL, NULL,
userChain, verify, "buffer");
}
#if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS)
if (ret == 1) {
ret = wolfSSL_CTX_trust_peer_buffer(ctx, in, sz, format);
}
#endif
WOLFSSL_LEAVE("wolfSSL_CTX_load_verify_buffer_ex", ret);
return ret;
}
int wolfSSL_CTX_load_verify_buffer(WOLFSSL_CTX* ctx, const unsigned char* in,
long sz, int format)
{
return wolfSSL_CTX_load_verify_buffer_ex(ctx, in, sz, format, 0,
WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS);
}
int wolfSSL_CTX_load_verify_chain_buffer_format(WOLFSSL_CTX* ctx,
const unsigned char* in, long sz, int format)
{
return wolfSSL_CTX_load_verify_buffer_ex(ctx, in, sz, format, 1,
WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS);
}
#ifdef WOLFSSL_TRUST_PEER_CERT
int wolfSSL_CTX_trust_peer_buffer(WOLFSSL_CTX* ctx, const unsigned char* in,
long sz, int format)
{
int ret;
int verify;
WOLFSSL_ENTER("wolfSSL_CTX_trust_peer_buffer");
if ((ctx == NULL) || (in == NULL) || (sz < 0)) {
ret = BAD_FUNC_ARG;
}
else {
#if WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY
verify = VERIFY_SKIP_DATE;
#else
verify = GET_VERIFY_SETTING_CTX(ctx);
#endif
if (format == WOLFSSL_FILETYPE_PEM) {
ret = ProcessChainBuffer(ctx, NULL, in, sz, TRUSTED_PEER_TYPE,
verify, "peer");
}
else {
ret = ProcessBuffer(ctx, in, sz, format, TRUSTED_PEER_TYPE, NULL,
NULL, 0, verify, "peer");
}
}
return ret;
}
#endif
int wolfSSL_CTX_use_certificate_buffer(WOLFSSL_CTX* ctx,
const unsigned char* in, long sz, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_buffer");
ret = ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 0,
GET_VERIFY_SETTING_CTX(ctx), "buffer");
WOLFSSL_LEAVE("wolfSSL_CTX_use_certificate_buffer", ret);
return ret;
}
int wolfSSL_CTX_use_PrivateKey_buffer(WOLFSSL_CTX* ctx, const unsigned char* in,
long sz, int format)
{
int ret;
long consumed = 0;
WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_buffer");
ret = ProcessBuffer(ctx, in, sz, format, PRIVATEKEY_TYPE, NULL, &consumed,
0, GET_VERIFY_SETTING_CTX(ctx), "key buffer");
#ifdef WOLFSSL_DUAL_ALG_CERTS
if ((ret == 1) && (consumed < sz)) {
ret = ProcessBuffer(ctx, in + consumed, sz - consumed, format,
ALT_PRIVATEKEY_TYPE, NULL, NULL, 0, GET_VERIFY_SETTING_CTX(ctx),
"key buffer");
}
#endif
(void)consumed;
WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_buffer", ret);
return ret;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
int wolfSSL_CTX_use_AltPrivateKey_buffer(WOLFSSL_CTX* ctx,
const unsigned char* in, long sz, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_buffer");
ret = ProcessBuffer(ctx, in, sz, format, ALT_PRIVATEKEY_TYPE, NULL,
NULL, 0, GET_VERIFY_SETTING_CTX(ctx), "alt key buffer");
WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_buffer", ret);
return ret;
}
#endif
#ifdef WOLF_PRIVATE_KEY_ID
int wolfSSL_CTX_use_PrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id,
long sz, int devId)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_Id");
FreeDer(&ctx->privateKey);
if (AllocCopyDer(&ctx->privateKey, id, (word32)sz, PRIVATEKEY_TYPE,
ctx->heap) != 0) {
ret = 0;
}
if (ret == 1) {
ctx->privateKeyId = 1;
ctx->privateKeyLabel = 0;
if (devId != INVALID_DEVID) {
ctx->privateKeyDevId = devId;
}
else {
ctx->privateKeyDevId = ctx->devId;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
ret = wolfSSL_CTX_use_AltPrivateKey_Id(ctx, id, sz, devId);
#endif
}
WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_Id", ret);
return ret;
}
int wolfSSL_CTX_use_PrivateKey_id(WOLFSSL_CTX* ctx, const unsigned char* id,
long sz, int devId, long keySz)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_id");
ret = wolfSSL_CTX_use_PrivateKey_Id(ctx, id, sz, devId);
if (ret == 1) {
ctx->privateKeySz = (int)keySz;
}
WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_id", ret);
return ret;
}
int wolfSSL_CTX_use_PrivateKey_Label(WOLFSSL_CTX* ctx, const char* label,
int devId)
{
int ret = 1;
word32 sz = (word32)XSTRLEN(label) + 1;
WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_Label");
FreeDer(&ctx->privateKey);
if (AllocCopyDer(&ctx->privateKey, (const byte*)label, (word32)sz,
PRIVATEKEY_TYPE, ctx->heap) != 0) {
ret = 0;
}
if (ret == 1) {
ctx->privateKeyId = 0;
ctx->privateKeyLabel = 1;
if (devId != INVALID_DEVID) {
ctx->privateKeyDevId = devId;
}
else {
ctx->privateKeyDevId = ctx->devId;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
ret = wolfSSL_CTX_use_AltPrivateKey_Label(ctx, label, devId);
#endif
}
WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_Label", ret);
return ret;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
int wolfSSL_CTX_use_AltPrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id,
long sz, int devId)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_Id");
if ((ctx == NULL) || (id == NULL)) {
ret = 0;
}
if (ret == 1) {
FreeDer(&ctx->altPrivateKey);
if (AllocDer(&ctx->altPrivateKey, (word32)sz, ALT_PRIVATEKEY_TYPE,
ctx->heap) != 0) {
ret = 0;
}
}
if (ret == 1) {
XMEMCPY(ctx->altPrivateKey->buffer, id, sz);
ctx->altPrivateKeyId = 1;
if (devId != INVALID_DEVID) {
ctx->altPrivateKeyDevId = devId;
}
else {
ctx->altPrivateKeyDevId = ctx->devId;
}
}
WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_Id", ret);
return ret;
}
int wolfSSL_CTX_use_AltPrivateKey_id(WOLFSSL_CTX* ctx, const unsigned char* id,
long sz, int devId, long keySz)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_id");
ret = wolfSSL_CTX_use_AltPrivateKey_Id(ctx, id, sz, devId);
if (ret == 1) {
ctx->altPrivateKeySz = (word32)keySz;
}
WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_id", ret);
return ret;
}
int wolfSSL_CTX_use_AltPrivateKey_Label(WOLFSSL_CTX* ctx, const char* label,
int devId)
{
int ret = 1;
word32 sz;
WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_Label");
if ((ctx == NULL) || (label == NULL)) {
ret = 0;
}
if (ret == 1) {
sz = (word32)XSTRLEN(label) + 1;
FreeDer(&ctx->altPrivateKey);
if (AllocDer(&ctx->altPrivateKey, (word32)sz, ALT_PRIVATEKEY_TYPE,
ctx->heap) != 0) {
ret = 0;
}
}
if (ret == 1) {
XMEMCPY(ctx->altPrivateKey->buffer, label, sz);
ctx->altPrivateKeyLabel = 1;
if (devId != INVALID_DEVID) {
ctx->altPrivateKeyDevId = devId;
}
else {
ctx->altPrivateKeyDevId = ctx->devId;
}
}
WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_Label", ret);
return ret;
}
#endif
#endif
#if defined(WOLF_CRYPTO_CB) && !defined(NO_CERTS)
static int wolfSSL_CTX_use_certificate_ex(WOLFSSL_CTX* ctx,
const char *label, const unsigned char *id, int idLen, int devId)
{
int ret;
byte *certData = NULL;
word32 certDataLen = 0;
word32 labelLen = 0;
int certFormat = 0;
WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_ex");
if (label != NULL) {
labelLen = (word32)XSTRLEN(label);
}
ret = wc_CryptoCb_GetCert(devId, label, labelLen, id, idLen,
&certData, &certDataLen, &certFormat, ctx->heap);
if (ret != 0) {
ret = WOLFSSL_FAILURE;
goto exit;
}
ret = ProcessBuffer(ctx, certData, certDataLen, certFormat,
CERT_TYPE, NULL, NULL, 0, GET_VERIFY_SETTING_CTX(ctx),
label ? label : "cert buffer");
exit:
XFREE(certData, ctx->heap, DYNAMIC_TYPE_CERT);
return ret;
}
int wolfSSL_CTX_use_certificate_label(WOLFSSL_CTX* ctx,
const char *label, int devId)
{
if ((ctx == NULL) || (label == NULL)) {
return WOLFSSL_FAILURE;
}
return wolfSSL_CTX_use_certificate_ex(ctx, label, NULL, 0, devId);
}
int wolfSSL_CTX_use_certificate_id(WOLFSSL_CTX* ctx,
const unsigned char *id, int idLen, int devId)
{
if ((ctx == NULL) || (id == NULL) || (idLen <= 0)) {
return WOLFSSL_FAILURE;
}
return wolfSSL_CTX_use_certificate_ex(ctx, NULL, id, idLen, devId);
}
#endif
int wolfSSL_CTX_use_certificate_chain_buffer_format(WOLFSSL_CTX* ctx,
const unsigned char* in, long sz, int format)
{
WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_buffer_format");
return ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 1,
GET_VERIFY_SETTING_CTX(ctx), "cert chain buffer");
}
int wolfSSL_CTX_use_certificate_chain_buffer(WOLFSSL_CTX* ctx,
const unsigned char* in, long sz)
{
#ifdef WOLFSSL_PEM_TO_DER
return wolfSSL_CTX_use_certificate_chain_buffer_format(ctx, in, sz,
WOLFSSL_FILETYPE_PEM);
#else
return wolfSSL_CTX_use_certificate_chain_buffer_format(ctx, in, sz,
WOLFSSL_FILETYPE_ASN1);
#endif
}
int wolfSSL_use_certificate_buffer(WOLFSSL* ssl, const unsigned char* in,
long sz, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_certificate_buffer");
if (ssl == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = ProcessBuffer(ssl->ctx, in, sz, format, CERT_TYPE, ssl, NULL, 0,
GET_VERIFY_SETTING_SSL(ssl), "cert buffer");
}
return ret;
}
int wolfSSL_use_PrivateKey_buffer(WOLFSSL* ssl, const unsigned char* in,
long sz, int format)
{
int ret;
long consumed = 0;
WOLFSSL_ENTER("wolfSSL_use_PrivateKey_buffer");
if (ssl == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = ProcessBuffer(ssl->ctx, in, sz, format, PRIVATEKEY_TYPE, ssl,
&consumed, 0, GET_VERIFY_SETTING_SSL(ssl), "key buffer");
#ifdef WOLFSSL_DUAL_ALG_CERTS
if ((ret == 1) && (consumed < sz)) {
ret = ProcessBuffer(ssl->ctx, in + consumed, sz - consumed, format,
ALT_PRIVATEKEY_TYPE, ssl, NULL, 0, GET_VERIFY_SETTING_SSL(ssl),
"key buffer");
}
#endif
}
return ret;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
int wolfSSL_use_AltPrivateKey_buffer(WOLFSSL* ssl, const unsigned char* in,
long sz, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_AltPrivateKey_buffer");
ret = ProcessBuffer(ssl->ctx, in, sz, format, ALT_PRIVATEKEY_TYPE, ssl,
NULL, 0, GET_VERIFY_SETTING_SSL(ssl), "alt key buffer");
WOLFSSL_LEAVE("wolfSSL_use_AltPrivateKey_buffer", ret);
return ret;
}
#endif
#ifdef WOLF_PRIVATE_KEY_ID
int wolfSSL_use_PrivateKey_Id(WOLFSSL* ssl, const unsigned char* id,
long sz, int devId)
{
int ret = 1;
if (ssl->buffers.weOwnKey) {
FreeDer(&ssl->buffers.key);
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
FreeDer(&ssl->buffers.keyMask);
#endif
}
if (AllocCopyDer(&ssl->buffers.key, id, (word32)sz, PRIVATEKEY_TYPE,
ssl->heap) != 0) {
ret = 0;
}
if (ret == 1) {
ssl->buffers.weOwnKey = 1;
ssl->buffers.keyId = 1;
ssl->buffers.keyLabel = 0;
if (devId != INVALID_DEVID) {
ssl->buffers.keyDevId = devId;
}
else {
ssl->buffers.keyDevId = ssl->devId;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
ret = wolfSSL_use_AltPrivateKey_Id(ssl, id, sz, devId);
#endif
}
return ret;
}
int wolfSSL_use_PrivateKey_id(WOLFSSL* ssl, const unsigned char* id,
long sz, int devId, long keySz)
{
int ret = wolfSSL_use_PrivateKey_Id(ssl, id, sz, devId);
if (ret == 1) {
ssl->buffers.keySz = (int)keySz;
}
return ret;
}
int wolfSSL_use_PrivateKey_Label(WOLFSSL* ssl, const char* label, int devId)
{
int ret = 1;
word32 sz = (word32)XSTRLEN(label) + 1;
if (ssl->buffers.weOwnKey) {
FreeDer(&ssl->buffers.key);
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
FreeDer(&ssl->buffers.keyMask);
#endif
}
if (AllocCopyDer(&ssl->buffers.key, (const byte*)label, (word32)sz,
PRIVATEKEY_TYPE, ssl->heap) != 0) {
ret = 0;
}
if (ret == 1) {
ssl->buffers.weOwnKey = 1;
ssl->buffers.keyId = 0;
ssl->buffers.keyLabel = 1;
if (devId != INVALID_DEVID) {
ssl->buffers.keyDevId = devId;
}
else {
ssl->buffers.keyDevId = ssl->devId;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
ret = wolfSSL_use_AltPrivateKey_Label(ssl, label, devId);
#endif
}
return ret;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
int wolfSSL_use_AltPrivateKey_Id(WOLFSSL* ssl, const unsigned char* id, long sz,
int devId)
{
int ret = 1;
if ((ssl == NULL) || (id == NULL)) {
ret = 0;
}
if (ret == 1) {
if (ssl->buffers.weOwnAltKey) {
FreeDer(&ssl->buffers.altKey);
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
FreeDer(&ssl->buffers.altKeyMask);
#endif
}
if (AllocDer(&ssl->buffers.altKey, (word32)sz, ALT_PRIVATEKEY_TYPE,
ssl->heap) == 0) {
ret = 0;
}
}
if (ret == 1) {
XMEMCPY(ssl->buffers.altKey->buffer, id, sz);
ssl->buffers.weOwnAltKey = 1;
ssl->buffers.altKeyId = 1;
if (devId != INVALID_DEVID) {
ssl->buffers.altKeyDevId = devId;
}
else {
ssl->buffers.altKeyDevId = ssl->devId;
}
}
return ret;
}
int wolfSSL_use_AltPrivateKey_id(WOLFSSL* ssl, const unsigned char* id, long sz,
int devId, long keySz)
{
int ret = wolfSSL_use_AltPrivateKey_Id(ssl, id, sz, devId);
if (ret == 1) {
ssl->buffers.altKeySz = (word32)keySz;
}
return ret;
}
int wolfSSL_use_AltPrivateKey_Label(WOLFSSL* ssl, const char* label, int devId)
{
int ret = 1;
word32 sz;
if ((ssl == NULL) || (label == NULL)) {
ret = 0;
}
if (ret == 1) {
sz = (word32)XSTRLEN(label) + 1;
if (ssl->buffers.weOwnAltKey) {
FreeDer(&ssl->buffers.altKey);
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
FreeDer(&ssl->buffers.altKeyMask);
#endif
}
if (AllocDer(&ssl->buffers.altKey, (word32)sz, ALT_PRIVATEKEY_TYPE,
ssl->heap) == 0) {
ret = 0;
}
}
if (ret == 1) {
XMEMCPY(ssl->buffers.altKey->buffer, label, sz);
ssl->buffers.weOwnAltKey = 1;
ssl->buffers.altKeyLabel = 1;
if (devId != INVALID_DEVID) {
ssl->buffers.altKeyDevId = devId;
}
else {
ssl->buffers.altKeyDevId = ssl->devId;
}
}
return ret;
}
#endif
#endif
int wolfSSL_use_certificate_chain_buffer_format(WOLFSSL* ssl,
const unsigned char* in, long sz, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_certificate_chain_buffer_format");
if (ssl == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = ProcessBuffer(ssl->ctx, in, sz, format, CERT_TYPE, ssl, NULL, 1,
GET_VERIFY_SETTING_SSL(ssl), "cert chain buffer");
}
return ret;
}
int wolfSSL_use_certificate_chain_buffer(WOLFSSL* ssl, const unsigned char* in,
long sz)
{
#ifdef WOLFSSL_PEM_TO_DER
return wolfSSL_use_certificate_chain_buffer_format(ssl, in, sz,
WOLFSSL_FILETYPE_PEM);
#else
return wolfSSL_use_certificate_chain_buffer_format(ssl, in, sz,
WOLFSSL_FILETYPE_ASN1);
#endif
}
#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \
defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \
defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \
defined(WOLFSSL_HAPROXY)
static int wolfssl_add_to_chain(DerBuffer** chain, int weOwn, const byte* cert,
word32 certSz, void* heap)
{
int res = 1;
int ret;
DerBuffer* oldChain = *chain;
DerBuffer* newChain = NULL;
word32 len = 0;
if (oldChain != NULL) {
len = oldChain->length;
}
if ((len > WOLFSSL_MAX_32BIT - CERT_HEADER_SZ) ||
(certSz > WOLFSSL_MAX_32BIT - CERT_HEADER_SZ - len)) {
WOLFSSL_MSG("wolfssl_add_to_chain overflow");
res = 0;
}
if (res == 1) {
ret = AllocDer(&newChain, len + CERT_HEADER_SZ + certSz, CERT_TYPE,
heap);
if (ret != 0) {
WOLFSSL_MSG("AllocDer error");
res = 0;
}
}
if (res == 1) {
if (oldChain != NULL) {
XMEMCPY(newChain->buffer, oldChain->buffer, len);
}
c32to24(certSz, newChain->buffer + len);
XMEMCPY(newChain->buffer + len + CERT_HEADER_SZ, cert, certSz);
if (weOwn) {
FreeDer(chain);
}
*chain = newChain;
}
return res;
}
#endif
#ifdef OPENSSL_EXTRA
static int wolfssl_ctx_add_to_chain(WOLFSSL_CTX* ctx, const byte* der,
int derSz)
{
int res = 1;
int ret;
DerBuffer* derBuffer = NULL;
ret = AllocCopyDer(&derBuffer, der, (word32)derSz, CERT_TYPE, ctx->heap);
if (ret != 0) {
WOLFSSL_MSG("Memory Error");
res = 0;
}
if (res == 1) {
res = AddCA(ctx->cm, &derBuffer, WOLFSSL_USER_CA,
GET_VERIFY_SETTING_CTX(ctx));
if (res != 1) {
res = 0;
}
}
if (res == 1) {
res = wolfssl_add_to_chain(&ctx->certChain, 1, der, (word32)derSz,
ctx->heap);
#ifdef WOLFSSL_TLS13
ctx->certChainCnt++;
#endif
}
return res;
}
long wolfSSL_CTX_add_extra_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509)
{
int ret = 1;
int derSz = 0;
const byte* der = NULL;
WOLFSSL_ENTER("wolfSSL_CTX_add_extra_chain_cert");
if ((ctx == NULL) || (x509 == NULL)) {
WOLFSSL_MSG("Bad Argument");
ret = 0;
}
if (ret == 1) {
der = wolfSSL_X509_get_der(x509, &derSz);
if ((der == NULL) || (derSz <= 0)) {
WOLFSSL_MSG("Error getting X509 DER");
ret = 0;
}
}
if ((ret == 1) && (ctx->certificate == NULL)) {
WOLFSSL_ENTER("wolfSSL_use_certificate_chain_buffer_format");
ret = ProcessBuffer(ctx, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE,
NULL, NULL, 1, GET_VERIFY_SETTING_CTX(ctx), "extra chain buffer");
if (ret != 1) {
ret = 0;
}
}
else if (ret == 1) {
ret = wolfssl_ctx_add_to_chain(ctx, der, derSz);
}
if (ret == 1) {
wolfSSL_X509_free(x509);
x509 = NULL;
}
WOLFSSL_LEAVE("wolfSSL_CTX_add_extra_chain_cert", ret);
return ret;
}
#endif
#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \
defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \
defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \
defined(WOLFSSL_HAPROXY)
int wolfSSL_CTX_use_certificate(WOLFSSL_CTX *ctx, WOLFSSL_X509 *x)
{
int res = 1;
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_use_certificate");
if ((ctx == NULL) || (x == NULL) || (x->derCert == NULL)) {
WOLFSSL_MSG("Bad parameter");
res = 0;
}
if (res == 1) {
FreeDer(&ctx->certificate);
ret = AllocCopyDer(&ctx->certificate, x->derCert->buffer,
x->derCert->length, CERT_TYPE, ctx->heap);
if (ret != 0) {
res = 0;
}
}
#ifdef KEEP_OUR_CERT
if (res == 1) {
if ((ctx->ourCert != NULL) && ctx->ownOurCert) {
wolfSSL_X509_free(ctx->ourCert);
}
#ifndef WOLFSSL_X509_STORE_CERTS
ctx->ourCert = x;
if (wolfSSL_X509_up_ref(x) != 1) {
res = 0;
}
#else
ctx->ourCert = wolfSSL_X509_d2i_ex(NULL, x->derCert->buffer,
x->derCert->length, ctx->heap);
if (ctx->ourCert == NULL) {
res = 0;
}
#endif
ctx->ownOurCert = 1;
}
#endif
if (res == 1) {
wolfssl_set_have_from_key_oid(ctx, NULL, x->pubKeyOID);
}
return res;
}
int wolfSSL_CTX_add0_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_add0_chain_cert");
ret = wolfSSL_CTX_add1_chain_cert(ctx, x509);
if (ret == 1) {
wolfSSL_X509_free(x509);
x509 = NULL;
}
return ret;
}
int wolfSSL_CTX_add1_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_CTX_add1_chain_cert");
if ((ctx == NULL) || (x509 == NULL) || (x509->derCert == NULL)) {
ret = 0;
}
if ((ret == 1) && (ctx->certificate == NULL)) {
ret = wolfSSL_CTX_use_certificate(ctx, x509);
}
else if ((ret == 1) && ((ret = wolfSSL_X509_up_ref(x509)) == 1)) {
ret = wolfSSL_CTX_load_verify_buffer(ctx, x509->derCert->buffer,
x509->derCert->length, WOLFSSL_FILETYPE_ASN1);
if (ret == 1) {
ret = wolfssl_add_to_chain(&ctx->certChain, 1,
x509->derCert->buffer, x509->derCert->length, ctx->heap);
}
if ((ret == 1) && (ctx->x509Chain == NULL)) {
ctx->x509Chain = wolfSSL_sk_X509_new_null();
if (ctx->x509Chain == NULL) {
WOLFSSL_MSG("wolfSSL_sk_X509_new_null error");
ret = 0;
}
}
if (ret == 1) {
ret = wolfSSL_sk_X509_push(ctx->x509Chain, x509) > 0
? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
}
if (ret != 1) {
wolfSSL_X509_free(x509);
x509 = NULL;
}
}
return WS_RC(ret);
}
#ifdef KEEP_OUR_CERT
int wolfSSL_add0_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_add0_chain_cert");
if ((ssl == NULL) || (x509 == NULL) || (x509->derCert == NULL)) {
ret = 0;
}
if ((ret == 1) && (ssl->buffers.certificate == NULL)) {
ret = wolfSSL_use_certificate(ssl, x509);
if (ret == 1) {
if (ssl->buffers.weOwnCert) {
wolfSSL_X509_free(ssl->ourCert);
}
ssl->ourCert = x509;
ssl->buffers.weOwnCert = 1;
}
}
else if (ret == 1) {
ret = wolfssl_add_to_chain(&ssl->buffers.certChain,
ssl->buffers.weOwnCertChain, x509->derCert->buffer,
x509->derCert->length, ssl->heap);
if (ret == 1) {
ssl->buffers.weOwnCertChain = 1;
if (ssl->ourCertChain == NULL) {
ssl->ourCertChain = wolfSSL_sk_X509_new_null();
if (ssl->ourCertChain == NULL) {
WOLFSSL_MSG("wolfSSL_sk_X509_new_null error");
ret = 0;
}
}
}
if (ret == 1) {
ret = wolfSSL_sk_X509_push(ssl->ourCertChain, x509) > 0
? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
}
}
return WS_RC(ret);
}
int wolfSSL_add1_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_add1_chain_cert");
if ((ssl == NULL) || (x509 == NULL) || (x509->derCert == NULL)) {
ret = 0;
}
if ((ret == 1) && ((ret == wolfSSL_X509_up_ref(x509)) == 1)) {
if ((ret = wolfSSL_add0_chain_cert(ssl, x509)) != 1) {
wolfSSL_X509_free(x509);
x509 = NULL;
}
}
return ret;
}
#endif
#endif
#ifdef OPENSSL_EXTRA
int wolfSSL_CTX_use_PrivateKey(WOLFSSL_CTX *ctx, WOLFSSL_EVP_PKEY *pkey)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey");
if ((ctx == NULL) || (pkey == NULL) || (pkey->pkey.ptr == NULL)) {
ret = 0;
}
if (ret == 1) {
switch (pkey->type) {
#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA)
case WC_EVP_PKEY_RSA:
WOLFSSL_MSG("populating RSA key");
ret = PopulateRSAEvpPkeyDer(pkey);
break;
#endif
#if !defined(HAVE_SELFTEST) && (defined(WOLFSSL_KEY_GEN) || \
defined(WOLFSSL_CERT_GEN)) && !defined(NO_DSA)
case WC_EVP_PKEY_DSA:
break;
#endif
#ifdef HAVE_ECC
case WC_EVP_PKEY_EC:
WOLFSSL_MSG("populating ECC key");
ret = ECC_populate_EVP_PKEY(pkey, pkey->ecc);
break;
#endif
default:
ret = 0;
}
}
if (ret == 1) {
ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx,
(const unsigned char*)pkey->pkey.ptr, pkey->pkey_sz,
WOLFSSL_FILETYPE_ASN1);
}
return ret;
}
#endif
#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \
defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT)
int wolfSSL_CTX_use_certificate_ASN1(WOLFSSL_CTX *ctx, int derSz,
const unsigned char *der)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_ASN1");
if ((ctx == NULL) || (der == NULL)) {
ret = 0;
}
if ((ret == 1) && (wolfSSL_CTX_use_certificate_buffer(ctx, der, derSz,
WOLFSSL_FILETYPE_ASN1) != 1)) {
ret = 0;
}
return ret;
}
#if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA)
int wolfSSL_CTX_use_RSAPrivateKey(WOLFSSL_CTX* ctx, WOLFSSL_RSA* rsa)
{
int ret = 1;
int derSize = 0;
unsigned char* der = NULL;
unsigned char* p;
WOLFSSL_ENTER("wolfSSL_CTX_use_RSAPrivateKey");
if ((ctx == NULL) || (rsa == NULL)) {
WOLFSSL_MSG("one or more inputs were NULL");
ret = BAD_FUNC_ARG;
}
if ((ret == 1) && ((derSize = wolfSSL_i2d_RSAPrivateKey(rsa, NULL)) <= 0)) {
ret = 0;
}
if (ret == 1) {
der = (unsigned char*)XMALLOC((size_t)derSize, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (der == NULL) {
WOLFSSL_MSG("Malloc failure");
ret = MEMORY_E;
}
}
if (ret == 1) {
p = der;
if ((derSize = wolfSSL_i2d_RSAPrivateKey(rsa, &p)) <= 0) {
WOLFSSL_MSG("wolfSSL_i2d_RSAPrivateKey() failure");
ret = 0;
}
}
if (ret == 1) {
ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, derSize,
SSL_FILETYPE_ASN1);
if (ret != WOLFSSL_SUCCESS) {
WOLFSSL_MSG("wolfSSL_CTX_USE_PrivateKey_buffer() failure");
ret = 0;
}
}
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
#endif
#endif
#endif
#ifdef OPENSSL_EXTRA
int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx)
{
int ret;
#if defined(XGETENV) && !defined(NO_GETENV)
char* certDir = NULL;
char* certFile = NULL;
word32 flags = 0;
#elif !defined(WOLFSSL_SYS_CA_CERTS)
(void)ctx;
#endif
WOLFSSL_ENTER("wolfSSL_CTX_set_default_verify_paths");
#if defined(XGETENV) && !defined(NO_GETENV)
certDir = wc_strdup_ex(XGETENV("SSL_CERT_DIR"), DYNAMIC_TYPE_TMP_BUFFER);
certFile = wc_strdup_ex(XGETENV("SSL_CERT_FILE"), DYNAMIC_TYPE_TMP_BUFFER);
flags = WOLFSSL_LOAD_FLAG_PEM_CA_ONLY;
if ((certDir != NULL) || (certFile != NULL)) {
if (certDir != NULL) {
flags |= WOLFSSL_LOAD_FLAG_IGNORE_ERR;
}
ret = wolfSSL_CTX_load_verify_locations_ex(ctx, certFile, certDir,
flags);
if (ret != 1) {
WOLFSSL_MSG_EX("Failed to load CA certs from SSL_CERT_FILE: %s"
" SSL_CERT_DIR: %s. Error: %d", certFile,
certDir, ret);
ret = 0;
}
}
else
#endif
{
#ifdef NO_FILESYSTEM
WOLFSSL_MSG("wolfSSL_CTX_set_default_verify_paths not supported"
" with NO_FILESYSTEM enabled");
ret = WOLFSSL_FATAL_ERROR;
#elif defined(WOLFSSL_SYS_CA_CERTS)
ret = wolfSSL_CTX_load_system_CA_certs(ctx);
if (ret == WC_NO_ERR_TRACE(WOLFSSL_BAD_PATH)) {
ret = 1;
}
#else
ret = 1;
#endif
}
#if defined(XGETENV) && !defined(NO_GETENV)
XFREE(certFile, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(certDir, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
WOLFSSL_LEAVE("wolfSSL_CTX_set_default_verify_paths", ret);
return ret;
}
#endif
#ifndef NO_DH
static int wolfssl_set_tmp_dh(WOLFSSL* ssl, unsigned char* p, int pSz,
unsigned char* g, int gSz)
{
int ret = 1;
if (((word16)pSz < ssl->options.minDhKeySz) ||
((word16)pSz > ssl->options.maxDhKeySz)) {
ret = DH_KEY_SIZE_E;
}
if ((ret == 1) && (ssl->options.side == WOLFSSL_CLIENT_END)) {
ret = SIDE_ERROR;
}
if (ret == 1) {
#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
!defined(HAVE_SELFTEST)
ssl->options.dhKeyTested = 0;
ssl->options.dhDoKeyTest = 1;
#endif
if (ssl->buffers.weOwnDH) {
XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap,
DYNAMIC_TYPE_PUBLIC_KEY);
XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap,
DYNAMIC_TYPE_PUBLIC_KEY);
}
ssl->buffers.serverDH_P.buffer = p;
ssl->buffers.serverDH_G.buffer = g;
ssl->buffers.serverDH_P.length = (unsigned int)pSz;
ssl->buffers.serverDH_G.length = (unsigned int)gSz;
ssl->buffers.weOwnDH = 1;
ssl->options.haveDH = 1;
}
if ((ret == 1) && (AllocateSuites(ssl) != 0)) {
ssl->buffers.serverDH_P.buffer = NULL;
ssl->buffers.serverDH_G.buffer = NULL;
ret = 0;
}
if (ret == 1) {
InitSuites(ssl->suites, ssl->version, SSL_KEY_SZ(ssl),
WOLFSSL_HAVE_RSA, SSL_HAVE_PSK(ssl), ssl->options.haveDH,
ssl->options.haveECDSAsig, ssl->options.haveECC, TRUE,
ssl->options.haveStaticECC,
ssl->options.useAnon, TRUE,
TRUE, TRUE, TRUE, ssl->options.side);
}
return ret;
}
int wolfSSL_SetTmpDH(WOLFSSL* ssl, const unsigned char* p, int pSz,
const unsigned char* g, int gSz)
{
int ret = 1;
byte* pAlloc = NULL;
byte* gAlloc = NULL;
WOLFSSL_ENTER("wolfSSL_SetTmpDH");
if ((ssl == NULL) || (p == NULL) || (g == NULL)) {
ret = 0;
}
if (ret == 1) {
pAlloc = (byte*)XMALLOC((size_t)pSz, ssl->heap,
DYNAMIC_TYPE_PUBLIC_KEY);
gAlloc = (byte*)XMALLOC((size_t)gSz, ssl->heap,
DYNAMIC_TYPE_PUBLIC_KEY);
if ((pAlloc == NULL) || (gAlloc == NULL)) {
ret = MEMORY_E;
}
}
if (ret == 1) {
XMEMCPY(pAlloc, p, (size_t)pSz);
XMEMCPY(gAlloc, g, (size_t)gSz);
ret = wolfssl_set_tmp_dh(ssl, pAlloc, pSz, gAlloc, gSz);
}
if (ret != 1 && ssl != NULL) {
XFREE(pAlloc, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
XFREE(gAlloc, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
}
WOLFSSL_LEAVE("wolfSSL_SetTmpDH", ret);
return ret;
}
#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
!defined(HAVE_SELFTEST)
static int wolfssl_check_dh_key(unsigned char* p, int pSz, unsigned char* g,
int gSz)
{
WC_RNG rng;
int ret = 0;
WC_DECLARE_VAR(checkKey, DhKey, 1, 0);
WC_ALLOC_VAR_EX(checkKey, DhKey, 1, NULL, DYNAMIC_TYPE_DH,
ret=MEMORY_E);
if ((ret == 0) && ((ret = wc_InitRng(&rng)) == 0)) {
if ((ret = wc_InitDhKey(checkKey)) == 0) {
ret = wc_DhSetCheckKey(checkKey, p, (word32)pSz, g, (word32)gSz,
NULL, 0, 0, &rng);
wc_FreeDhKey(checkKey);
}
wc_FreeRng(&rng);
}
WC_FREE_VAR_EX(checkKey, NULL, DYNAMIC_TYPE_DH);
return WC_TO_WS_RC(ret);
}
#endif
static int wolfssl_ctx_set_tmp_dh(WOLFSSL_CTX* ctx, unsigned char* p, int pSz,
unsigned char* g, int gSz)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_CTX_SetTmpDH");
if (((word16)pSz < ctx->minDhKeySz) || ((word16)pSz > ctx->maxDhKeySz)) {
ret = DH_KEY_SIZE_E;
}
#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \
!defined(HAVE_SELFTEST)
if (ret == 1) {
ret = wolfssl_check_dh_key(p, pSz, g, gSz);
ctx->dhKeyTested = (ret == 1);
}
#endif
if (ret == 1) {
XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
ctx->serverDH_P.buffer = p;
ctx->serverDH_G.buffer = g;
ctx->serverDH_P.length = (unsigned int)pSz;
ctx->serverDH_G.length = (unsigned int)gSz;
ctx->haveDH = 1;
}
WOLFSSL_LEAVE("wolfSSL_CTX_SetTmpDH", 0);
return ret;
}
int wolfSSL_CTX_SetTmpDH(WOLFSSL_CTX* ctx, const unsigned char* p, int pSz,
const unsigned char* g, int gSz)
{
int ret = 1;
byte* pAlloc = NULL;
byte* gAlloc = NULL;
if ((ctx == NULL) || (p == NULL) || (g == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 1) {
pAlloc = (byte*)XMALLOC((size_t)pSz, ctx->heap,
DYNAMIC_TYPE_PUBLIC_KEY);
gAlloc = (byte*)XMALLOC((size_t)gSz, ctx->heap,
DYNAMIC_TYPE_PUBLIC_KEY);
if ((pAlloc == NULL) || (gAlloc == NULL)) {
ret = MEMORY_E;
}
}
if (ret == 1) {
XMEMCPY(pAlloc, p, (size_t)pSz);
XMEMCPY(gAlloc, g, (size_t)gSz);
ret = wolfssl_ctx_set_tmp_dh(ctx, pAlloc, pSz, gAlloc, gSz);
}
if ((ret != 1) && (ctx != NULL)) {
XFREE(pAlloc, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
XFREE(gAlloc, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
}
return ret;
}
#ifdef OPENSSL_EXTRA
long wolfSSL_set_tmp_dh(WOLFSSL *ssl, WOLFSSL_DH *dh)
{
int ret = 1;
byte* p = NULL;
byte* g = NULL;
int pSz = 0;
int gSz = 0;
WOLFSSL_ENTER("wolfSSL_set_tmp_dh");
if ((ssl == NULL) || (dh == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 1) {
pSz = wolfSSL_BN_bn2bin(dh->p, NULL);
gSz = wolfSSL_BN_bn2bin(dh->g, NULL);
if ((pSz <= 0) || (gSz <= 0)) {
ret = WOLFSSL_FATAL_ERROR;
}
}
if (ret == 1) {
p = (byte*)XMALLOC((size_t)pSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
g = (byte*)XMALLOC((size_t)gSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
if ((p == NULL) || (g == NULL)) {
ret = MEMORY_E;
}
}
if (ret == 1) {
pSz = wolfSSL_BN_bn2bin(dh->p, p);
gSz = wolfSSL_BN_bn2bin(dh->g, g);
if ((pSz <= 0) || (gSz <= 0)) {
ret = WOLFSSL_FATAL_ERROR;
}
}
if (ret == 1) {
ret = wolfssl_set_tmp_dh(ssl, p, pSz, g, gSz);
}
if ((ret != 1) && (ssl != NULL)) {
XFREE(p, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
XFREE(g, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
}
return ret;
}
long wolfSSL_CTX_set_tmp_dh(WOLFSSL_CTX* ctx, WOLFSSL_DH* dh)
{
int ret = 1;
int pSz = 0;
int gSz = 0;
byte* p = NULL;
byte* g = NULL;
WOLFSSL_ENTER("wolfSSL_CTX_set_tmp_dh");
if ((ctx == NULL) || (dh == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 1) {
pSz = wolfSSL_BN_bn2bin(dh->p, NULL);
gSz = wolfSSL_BN_bn2bin(dh->g, NULL);
if ((pSz <= 0) || (gSz <= 0)) {
ret = WOLFSSL_FATAL_ERROR;
}
}
if (ret == 1) {
p = (byte*)XMALLOC((size_t)pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
g = (byte*)XMALLOC((size_t)gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
if ((p == NULL) || (g == NULL)) {
ret = MEMORY_E;
}
}
if (ret == 1) {
pSz = wolfSSL_BN_bn2bin(dh->p, p);
gSz = wolfSSL_BN_bn2bin(dh->g, g);
if ((pSz < 0) && (gSz < 0)) {
ret = WOLFSSL_FATAL_ERROR;
}
}
if (ret == 1) {
ret = wolfssl_ctx_set_tmp_dh(ctx, p, pSz, g, gSz);
}
if ((ret != 1) && (ctx != NULL)) {
XFREE(p, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
XFREE(g, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
}
return ret;
}
#endif
#ifndef NO_CERTS
static int ws_ctx_ssl_set_tmp_dh(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
const unsigned char* buf, long sz, int format)
{
DerBuffer* der = NULL;
int res = 1;
int ret;
word32 pSz = MAX_DH_SIZE;
word32 gSz = MAX_DH_SIZE;
byte* p = NULL;
byte* g = NULL;
void* heap = WOLFSSL_HEAP(ctx, ssl);
if (((ctx == NULL) && (ssl == NULL)) || (buf == NULL)) {
res = BAD_FUNC_ARG;
}
if ((res == 1) && (format != WOLFSSL_FILETYPE_ASN1)) {
if (format != WOLFSSL_FILETYPE_PEM) {
res = WOLFSSL_BAD_FILETYPE;
}
#ifndef WOLFSSL_PEM_TO_DER
else {
res = NOT_COMPILED_IN;
}
#endif
}
if ((res == 1) && (format != WOLFSSL_FILETYPE_PEM)) {
ret = AllocDer(&der, 0, DH_PARAM_TYPE, heap);
if (ret == 0) {
der->buffer = (byte*)buf;
der->length = (word32)sz;
}
else {
res = ret;
}
}
if (res == 1) {
p = (byte*)XMALLOC(pSz, heap, DYNAMIC_TYPE_PUBLIC_KEY);
g = (byte*)XMALLOC(gSz, heap, DYNAMIC_TYPE_PUBLIC_KEY);
if ((p == NULL) || (g == NULL)) {
res = MEMORY_E;
}
}
#ifdef WOLFSSL_PEM_TO_DER
if ((res == 1) && (format == WOLFSSL_FILETYPE_PEM)) {
ret = PemToDer(buf, sz, DH_PARAM_TYPE, &der, heap, NULL, NULL);
if (ret < 0) {
ret = PemToDer(buf, sz, X942_PARAM_TYPE, &der, heap, NULL, NULL);
}
#if defined(WOLFSSL_WPAS) && !defined(NO_DSA)
if (ret < 0) {
ret = PemToDer(buf, sz, DSA_PARAM_TYPE, &der, heap, NULL, NULL);
}
#endif
if (ret < 0) {
res = ret;
}
}
#endif
if (res == 1) {
if (wc_DhParamsLoad(der->buffer, der->length, p, &pSz, g, &gSz) < 0) {
res = WOLFSSL_BAD_FILETYPE;
}
else if (ssl != NULL) {
res = wolfssl_set_tmp_dh(ssl, p, (int)pSz, g, (int)gSz);
}
else {
res = wolfssl_ctx_set_tmp_dh(ctx, p, (int)pSz, g, (int)gSz);
}
}
FreeDer(&der);
if (res != 1) {
XFREE(p, heap, DYNAMIC_TYPE_PUBLIC_KEY);
XFREE(g, heap, DYNAMIC_TYPE_PUBLIC_KEY);
}
return res;
}
int wolfSSL_SetTmpDH_buffer(WOLFSSL* ssl, const unsigned char* buf, long sz,
int format)
{
return ws_ctx_ssl_set_tmp_dh(NULL, ssl, buf, sz, format);
}
int wolfSSL_CTX_SetTmpDH_buffer(WOLFSSL_CTX* ctx, const unsigned char* buf,
long sz, int format)
{
return ws_ctx_ssl_set_tmp_dh(ctx, NULL, buf, sz, format);
}
#ifndef NO_FILESYSTEM
static int ws_ctx_ssl_set_tmp_dh_file(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
const char* fname, int format)
{
int res = 1;
int ret;
#ifndef WOLFSSL_SMALL_STACK
byte stackBuffer[FILE_BUFFER_SIZE];
#endif
StaticBuffer dhFile;
long sz = 0;
void* heap = WOLFSSL_HEAP(ctx, ssl);
#ifdef WOLFSSL_SMALL_STACK
static_buffer_init(&dhFile);
#else
static_buffer_init(&dhFile, stackBuffer, FILE_BUFFER_SIZE);
#endif
if (((ctx == NULL) && (ssl == NULL)) || (fname == NULL)) {
res = BAD_FUNC_ARG;
}
if (res == 1) {
ret = wolfssl_read_file_static(fname, &dhFile, heap, DYNAMIC_TYPE_FILE,
&sz);
if (ret != 0) {
res = ret;
}
}
if (res == 1) {
if (ssl != NULL) {
res = wolfSSL_SetTmpDH_buffer(ssl, dhFile.buffer, sz, format);
}
else {
res = wolfSSL_CTX_SetTmpDH_buffer(ctx, dhFile.buffer, sz, format);
}
}
static_buffer_free(&dhFile, heap, DYNAMIC_TYPE_FILE);
return res;
}
int wolfSSL_SetTmpDH_file(WOLFSSL* ssl, const char* fname, int format)
{
return ws_ctx_ssl_set_tmp_dh_file(NULL, ssl, fname, format);
}
int wolfSSL_CTX_SetTmpDH_file(WOLFSSL_CTX* ctx, const char* fname, int format)
{
return ws_ctx_ssl_set_tmp_dh_file(ctx, NULL, fname, format);
}
#endif
#endif
#endif
#endif