Files
wolfssl/src/ssl_load.c
Tobias Frauenschläger 9a58301ab1 Fix PQC and hybrid certificate regressions
Due to recent changes in the logic to decode private keys and to parse
the TLS1.3 CertificateVerify message, some regressions regarding PQC
private keys and hybrid certificates have been introduced:
* Decoding PQC private keys fails as the PKCS8 header of a decoded DER
  file is now already removed before parsing the key.
* The key size wasn't properly stored in the context for PQC keys after
  decoding a certificate (always the maximum size)
* The two 16-bit size values in case of a hybrid signature in the
  CertificateVerify message have been incorrectly decoded as 32-bit
  values instead of 16-bit values. This resulted in wrong values,
  leading to segmentation faults.

All three regressions are fixed with the changes in this commit.

Signed-off-by: Tobias Frauenschläger <t.frauenschlaeger@me.com>
2024-05-23 16:01:28 +02:00

5840 lines
183 KiB
C

/* ssl_load.c
*
* Copyright (C) 2006-2023 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
/*
* WOLFSSL_SYS_CA_CERTS
* Enables ability to load system CA certs from the OS via
* wolfSSL_CTX_load_system_CA_certs.
*/
#ifdef WOLFSSL_SYS_CA_CERTS
#ifdef _WIN32
#include <windows.h>
#include <wincrypt.h>
/* mingw gcc does not support pragma comment, and the
* linking with crypt32 is handled in configure.ac */
#if !defined(__MINGW32__) && !defined(__MINGW64__)
#pragma comment(lib, "crypt32")
#endif
#endif
#if defined(__APPLE__) && defined(HAVE_SECURITY_SECTRUSTSETTINGS_H)
#include <Security/SecTrustSettings.h>
#endif
#endif /* WOLFSSL_SYS_CA_CERTS */
#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
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
/* PSK field of context when it exists. */
#define CTX_HAVE_PSK(ctx) (ctx)->havePSK
/* PSK field of ssl when it exists. */
#define SSL_HAVE_PSK(ssl) (ssl)->options.havePSK
#else
/* Have PSK value when no field. */
#define CTX_HAVE_PSK(ctx) 0
/* Have PSK value when no field. */
#define SSL_HAVE_PSK(ssl) 0
#endif
#ifdef NO_RSA
/* Boolean for RSA available. */
#define WOLFSSL_HAVE_RSA 0
#else
/* Boolean for RSA available. */
#define WOLFSSL_HAVE_RSA 1
#endif
#ifndef NO_CERTS
/* Private key size from ssl. */
#define SSL_KEY_SZ(ssl) (ssl)->buffers.keySz
#else
/* Private key size not available. */
#define SSL_KEY_SZ(ssl) 0
#endif
#ifdef HAVE_ANON
/* Anonymous ciphersuite allowed field in context. */
#define CTX_USE_ANON(ctx) (ctx)->useAnon
#else
/* Anonymous ciphersuite allowed field not in context. */
#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
/* Get the heap from the context or the ssl depending on which is available. */
#define WOLFSSL_HEAP(ctx, ssl) \
(((ctx) != NULL) ? (ctx)->heap : (((ssl) != NULL) ? (ssl)->heap : NULL))
#ifndef NO_CERTS
/* Get DER encoding from data in a buffer as a DerBuffer.
*
* @param [in] buff Buffer containing data.
* @param [in] len Length of data in buffer.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @param [in] type Type of data:
* CERT_TYPE, CA_TYPE, TRUSTED_PEER_TYPE,
* PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE.
* @param [in, out] info Info for encryption.
* @param [in] heap Dynamic memory allocation hint.
* @param [out] der Holds DER encoded data.
* @param [out] algId Algorithm identifier for private keys.
* @return 0 on success.
* @return NOT_COMPILED_IN when format is PEM and PEM not supported.
* @return ASN_PARSE_E when format is ASN.1 and invalid DER encoding.
* @return MEMORY_E when dynamic memory allocation fails.
*/
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;
/* Data in buffer has PEM format - extract DER data. */
if (format == WOLFSSL_FILETYPE_PEM) {
#ifdef WOLFSSL_PEM_TO_DER
ret = PemToDer(buff, len, type, der, heap, info, algId);
if (ret != 0) {
FreeDer(der);
}
#else
ret = NOT_COMPILED_IN;
#endif
}
/* Data in buffer is ASN.1 format - get first SEQ or OCT into der. */
else {
int length;
word32 inOutIdx = 0;
/* Get length of SEQ including header. */
if ((info->consumed = wolfssl_der_length(buff, (int)len)) > 0) {
ret = 0;
}
/* Private keys may be wrapped in OCT when PKCS#8 wrapper removed.
* TODO: is this really needed? */
else if ((type == PRIVATEKEY_TYPE) &&
(GetOctetString(buff, &inOutIdx, &length, len) >= 0)) {
/* Include octet string DER header. */
info->consumed = length + inOutIdx;
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;
}
/* Process a user's certificate.
*
* Puts the 3-byte length before certificate data as required for TLS.
* CA certificates are added to the certificate manager.
*
* @param [in] cm Certificate manager.
* @param [in, out] pDer DER encoded data.
* @param [in] type Type of data. Valid values:
* CERT_TYPE, CA_TYPE or TRUSTED_PEER_TYPE.
* @param [in] verify How to verify certificate.
* @param [out] chainBuffer Buffer to hold chain of certificates.
* @param [in, out] pIdx On in, current index into chainBuffer.
* On out, index after certificate added.
* @param [in] bufferSz Size of buffer in bytes.
* @return 0 on success.
* @return BUFFER_E if chain buffer not big enough to hold certificate.
*/
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;
/* Check there is space for certificate in chainBuffer. */
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) {
/* 3-byte length. */
c32to24(der->length, &chainBuffer[idx]);
idx += CERT_HEADER_SZ;
/* Add complete DER encoded certificate. */
XMEMCPY(&chainBuffer[idx], der->buffer, der->length);
idx += der->length;
if (type == CA_TYPE) {
/* Add CA to certificate manager */
ret = AddCA(cm, pDer, WOLFSSL_USER_CA, verify);
if (ret == 1) {
ret = 0;
}
}
}
/* Update the index into chainBuffer. */
*pIdx = idx;
return ret;
}
/* Store the certificate chain buffer aganst WOLFSSL_CTX or WOLFSSL object.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] chainBuffer Buffer containing chain of certificates.
* @param [in] len Length, in bytes, of data in buffer.
* @param [in] cnt Number of certificates in chain.
* @param [in] type Type of data. Valid values:
* CERT_TYPE, CA_TYPE or CHAIN_CERT_TYPE.
* @param [in] heap Dynamic memory allocation hint.
* @return 0 on success.
* @return MEMORY_E when dynamic memory allocation fails.
*/
static int ProcessUserChainRetain(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
const byte* chainBuffer, word32 len, int cnt, int type, void* heap)
{
int ret = 0;
(void)cnt;
/* Store in SSL object if available. */
if (ssl != NULL) {
/* Dispose of old chain if not reference to context's. */
if (ssl->buffers.weOwnCertChain) {
FreeDer(&ssl->buffers.certChain);
}
/* Allocate and copy the buffer into SSL object. */
ret = AllocCopyDer(&ssl->buffers.certChain, chainBuffer, len, type,
heap);
ssl->buffers.weOwnCertChain = (ret == 0);
#ifdef WOLFSSL_TLS13
/* Update count of certificates in chain. */
ssl->buffers.certChainCnt = cnt;
#endif
}
/* Store in SSL context object if available. */
else if (ctx != NULL) {
/* Dispose of old chain and allocate and copy in new chain. */
FreeDer(&ctx->certChain);
/* Allocate and copy the buffer into SSL context object. */
ret = AllocCopyDer(&ctx->certChain, chainBuffer, len, type, heap);
#ifdef WOLFSSL_TLS13
/* Update count of certificates in chain. */
ctx->certChainCnt = cnt;
#endif
}
return ret;
}
/* Process user cert chain to pass during the TLS handshake.
*
* If not a certificate type then data is ignored.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] buff Buffer holding certificates.
* @param [in] sz Length of data in buffer.
* @param [in] format Format of the certificate:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1
* @param [in] type Type of certificate:
* CA_TYPE, CERT_TYPE or CHAIN_CERT_TYPE
* @param [out] used Number of bytes from buff used.
* @param [in, out] info Encryption information.
* @param [in] verify How to verify certificate.
* @return 0 on success.
* @return BAD_FUNC_ARG when type is CA_TYPE and ctx is NULL.
* @return MEMORY_E when dynamic memory allocation fails.
*/
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");
/* Validate parameters. */
if ((type == CA_TYPE) && (ctx == NULL)) {
WOLFSSL_MSG("Need context for CA load");
ret = BAD_FUNC_ARG;
}
/* Ignore non-certificate types. */
if ((ret == 0) && (type != CERT_TYPE) && (type != CHAIN_CERT_TYPE) &&
(type != CA_TYPE)) {
WOLFSSL_MSG("File type not a certificate");
}
/* Check we haven't consumed all the data. */
else if ((ret == 0) && (info->consumed >= sz)) {
WOLFSSL_MSG("Already consumed data");
}
else if (ret == 0) {
#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;
/* Calculate max possible size, including max headers */
long maxSz = (sz - consumed) + (CERT_HEADER_SZ * MAX_CHAIN_DEPTH);
/* Setup buffer to hold chain. */
#ifdef WOLFSSL_SMALL_STACK
static_buffer_init(&chain);
#else
static_buffer_init(&chain, stackBuffer, FILE_BUFFER_SIZE);
#endif
/* Make buffer big enough to support maximum size. */
ret = static_buffer_set_size(&chain, (word32)maxSz, heap,
DYNAMIC_TYPE_FILE);
WOLFSSL_MSG("Processing Cert Chain");
/* Keep parsing certificates will data available. */
while ((ret == 0) && (consumed < sz)) {
DerBuffer* part = NULL;
/* Get a certificate as DER. */
ret = DataToDerBuffer(buff + consumed, (word32)(sz - consumed),
format, type, info, heap, &part, NULL);
if (ret == 0) {
/* Process the user certificate. */
ret = ProcessUserCert(ctx->cm, &part, type, verify,
chain.buffer, &idx, (word32)maxSz);
}
/* PEM may have trailing data that can be ignored. */
if ((ret == ASN_NO_PEM_HEADER) && gotOne) {
WOLFSSL_MSG("We got one good cert, so stuff at end ok");
ret = 0;
break;
}
/* Certificate data handled. */
FreeDer(&part);
if (ret == 0) {
/* Update consumed length. */
consumed += info->consumed;
WOLFSSL_MSG(" Consumed another Cert in Chain");
/* Update whether we got a user certificate. */
gotOne |= (type != CA_TYPE);
/* Update count of certificates added to chain. */
cnt++;
}
}
if (used != NULL) {
/* Return the total consumed length. */
*used = consumed;
}
/* Check whether there is data in the chain buffer. */
if ((ret == 0) && (idx > 0)) {
/* Put the chain buffer against the SSL or SSL context object. */
ret = ProcessUserChainRetain(ctx, ssl, chain.buffer, idx, cnt, type,
heap);
}
/* Dispose of chain buffer. */
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))
/* See if DER data is an RSA private key.
*
* Checks size meets minimum RSA key size.
* This implementation uses less dynamic memory.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] der DER encoding.
* @param [in, out] keyFormat On in, expected format. 0 means unknown.
* @param [in] devId Device identifier.
* @param [out] keyType Type of key.
* @param [out] keySize Size of key.
* @return 0 on success or not an RSA key and format unknown.
* @return RSA_KEY_SIZE_E when key size doesn't meet minimum required.
*/
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;
/* Validate we have an RSA private key and get key size. */
idx = 0;
ret = wc_RsaPrivateKeyValidate(der->buffer, &idx, &keySz, der->length);
#ifdef WOLF_PRIVATE_KEY_ID
/* If that didn't work then maybe a public key if device ID or callback. */
if ((ret != 0) && ((devId != INVALID_DEVID) ||
WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
word32 nSz;
/* Decode as an RSA public key. */
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) {
/* Get the minimum RSA key size from SSL or SSL context object. */
int minRsaSz = ssl ? ssl->options.minRsaKeySz : ctx->minRsaKeySz;
/* Format, type and size are known. */
*keyFormat = RSAk;
*keyType = rsa_sa_algo;
*keySize = keySz;
/* Check that the size of the RSA key is enough. */
if (keySz < minRsaSz) {
WOLFSSL_MSG("Private Key size too small");
ret = RSA_KEY_SIZE_E;
}
/* No static ECC key possible. */
if ((ssl != NULL) && (ssl->options.side == WOLFSSL_SERVER_END)) {
ssl->options.haveStaticECC = 0;
}
}
/* Not an RSA key but check whether we know what it is. */
else if (*keyFormat == 0) {
WOLFSSL_MSG("Not an RSA key");
/* Format unknown so keep trying. */
ret = 0;
}
return ret;
}
#else
/* See if DER data is an RSA private key.
*
* Checks size meets minimum RSA key size.
* This implementation uses more dynamic memory but supports older FIPS.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] der DER encoding.
* @param [in, out] keyFormat On in, expected format. 0 means unknown.
* @param [in] heap Dynamic memory allocation hint.
* @param [in] devId Device identifier.
* @param [out] keyType Type of key.
* @param [out] keySize Size of key.
* @return 0 on success or not an RSA key and format unknown.
* @return RSA_KEY_SIZE_E when key size doesn't meet minimum required.
*/
static int ProcessBufferTryDecodeRsa(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType,
int* keySize)
{
int ret;
word32 idx;
/* make sure RSA key can be used */
#ifdef WOLFSSL_SMALL_STACK
RsaKey* key;
#else
RsaKey key[1];
#endif
#ifdef WOLFSSL_SMALL_STACK
/* Allocate an RSA key to parse into so we can get size. */
key = (RsaKey*)XMALLOC(sizeof(RsaKey), heap, DYNAMIC_TYPE_RSA);
if (key == NULL)
return MEMORY_E;
#endif
/* Initialize the RSA key. */
ret = wc_InitRsaKey_ex(key, heap, devId);
if (ret == 0) {
/* Check we have an RSA private key. */
idx = 0;
ret = wc_RsaPrivateKeyDecode(der->buffer, &idx, key, der->length);
#ifdef WOLF_PRIVATE_KEY_ID
/* If that didn't work then maybe a public key if device ID or callback.
*/
if ((ret != 0) && ((devId != INVALID_DEVID) ||
WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
/* If that didn't work then maybe a public key if device ID or
* callback. */
idx = 0;
ret = wc_RsaPublicKeyDecode(der->buffer, &idx, key, der->length);
}
#endif
if (ret == 0) {
/* Get the minimum RSA key size from SSL or SSL context object. */
int minRsaSz = ssl ? ssl->options.minRsaKeySz : ctx->minRsaKeySz;
int keySz = wc_RsaEncryptSize((RsaKey*)key);
/* Format is known. */
*keyFormat = RSAk;
*keyType = rsa_sa_algo;
*keySize = keySz;
/* Check that the size of the RSA key is enough. */
if (keySz < minRsaSz) {
WOLFSSL_MSG("Private Key size too small");
ret = RSA_KEY_SIZE_E;
}
/* No static ECC key possible. */
if ((ssl != NULL) && (ssl->options.side == WOLFSSL_SERVER_END)) {
ssl->options.haveStaticECC = 0;
}
}
/* Not an RSA key but check whether we know what it is. */
else if (*keyFormat == 0) {
WOLFSSL_MSG("Not an RSA key");
/* Format unknown so keep trying. */
ret = 0;
}
/* Free dynamically allocated data in key. */
wc_FreeRsaKey(key);
}
#ifdef WOLFSSL_SMALL_STACK
/* Dispose of allocated key. */
XFREE(key, heap, DYNAMIC_TYPE_RSA);
#endif
return ret;
}
#endif
#endif /* !NO_RSA */
#ifdef HAVE_ECC
/* See if DER data is an ECC private key.
*
* Checks size meets minimum ECC key size.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] der DER encoding.
* @param [in, out] keyFormat On in, expected format. 0 means unknown.
* @param [in] heap Dynamic memory allocation hint.
* @param [in] devId Device identifier.
* @param [out] keyType Type of key.
* @param [out] keySize Size of key.
* @return 0 on success or not an ECC key and format unknown.
* @return ECC_KEY_SIZE_E when ECC key size doesn't meet minimum required.
*/
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;
/* make sure ECC key can be used */
#ifdef WOLFSSL_SMALL_STACK
ecc_key* key;
#else
ecc_key key[1];
#endif
#ifdef WOLFSSL_SMALL_STACK
/* Allocate an ECC key to parse into. */
key = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, DYNAMIC_TYPE_ECC);
if (key == NULL)
return MEMORY_E;
#endif
/* Initialize ECC key. */
if (wc_ecc_init_ex(key, heap, devId) == 0) {
/* Decode as an ECC private key. */
idx = 0;
ret = wc_EccPrivateKeyDecode(der->buffer, &idx, key, der->length);
#ifdef WOLF_PRIVATE_KEY_ID
/* If that didn't work then maybe a public key if device ID or callback.
*/
if ((ret != 0) && ((devId != INVALID_DEVID) ||
WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
/* Decode as an ECC public key. */
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) {
/* Get the minimum ECC key size from SSL or SSL context object. */
int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz;
int keySz = wc_ecc_size(key);
/* Format is known. */
*keyFormat = ECDSAk;
#ifdef WOLFSSL_SM2
if (key->dp->id == ECC_SM2P256V1) {
*keyType = sm2_sa_algo;
}
else
#endif
{
*keyType = ecc_dsa_sa_algo;
}
*keySize = keySz;
/* Check that the size of the ECC key is enough. */
if (keySz < minKeySz) {
WOLFSSL_MSG("ECC private key too small");
ret = ECC_KEY_SIZE_E;
}
/* Static ECC key possible. */
if (ssl) {
ssl->options.haveStaticECC = 1;
}
else {
ctx->haveStaticECC = 1;
}
}
/* Not an ECC key but check whether we know what it is. */
else if (*keyFormat == 0) {
WOLFSSL_MSG("Not an ECC key");
/* Format unknown so keep trying. */
ret = 0;
}
/* Free dynamically allocated data in key. */
wc_ecc_free(key);
}
#ifdef WOLFSSL_SMALL_STACK
/* Dispose of allocated key. */
XFREE(key, heap, DYNAMIC_TYPE_ECC);
#endif
return ret;
}
#endif /* HAVE_ECC */
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT)
/* See if DER data is an Ed25519 private key.
*
* Checks size meets minimum ECC key size.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] der DER encoding.
* @param [in, out] keyFormat On in, expected format. 0 means unknown.
* @param [in] heap Dynamic memory allocation hint.
* @param [in] devId Device identifier.
* @param [out] keyType Type of key.
* @param [out] keySize Size of key.
* @return 0 on success or not an Ed25519 key and format unknown.
* @return ECC_KEY_SIZE_E when key size doesn't meet minimum required.
*/
static int ProcessBufferTryDecodeEd25519(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType,
int* keySize)
{
int ret;
word32 idx;
/* make sure Ed25519 key can be used */
#ifdef WOLFSSL_SMALL_STACK
ed25519_key* key;
#else
ed25519_key key[1];
#endif
#ifdef WOLFSSL_SMALL_STACK
/* Allocate an Ed25519 key to parse into. */
key = (ed25519_key*)XMALLOC(sizeof(ed25519_key), heap,
DYNAMIC_TYPE_ED25519);
if (key == NULL)
return MEMORY_E;
#endif
/* Initialize Ed25519 key. */
ret = wc_ed25519_init_ex(key, heap, devId);
if (ret == 0) {
/* Decode as an Ed25519 private key. */
idx = 0;
ret = wc_Ed25519PrivateKeyDecode(der->buffer, &idx, key, der->length);
#ifdef WOLF_PRIVATE_KEY_ID
/* If that didn't work then maybe a public key if device ID or callback.
*/
if ((ret != 0) && ((devId != INVALID_DEVID) ||
WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
/* Decode as an Ed25519 public key. */
idx = 0;
ret = wc_Ed25519PublicKeyDecode(der->buffer, &idx, key,
der->length);
}
#endif
if (ret == 0) {
/* Get the minimum ECC key size from SSL or SSL context object. */
int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz;
/* Format is known. */
*keyFormat = ED25519k;
*keyType = ed25519_sa_algo;
*keySize = ED25519_KEY_SIZE;
/* Check that the size of the ECC key is enough. */
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)
/* Ed25519 requires caching enabled for tracking message
* hash used in EdDSA_Update for signing */
ssl->options.cacheMessages = 1;
#endif
}
}
/* Not an Ed25519 key but check whether we know what it is. */
else if (*keyFormat == 0) {
WOLFSSL_MSG("Not an Ed25519 key");
/* Format unknown so keep trying. */
ret = 0;
}
/* Free dynamically allocated data in key. */
wc_ed25519_free(key);
}
#ifdef WOLFSSL_SMALL_STACK
/* Dispose of allocated key. */
XFREE(key, heap, DYNAMIC_TYPE_ED25519);
#endif
return ret;
}
#endif /* HAVE_ED25519 && HAVE_ED25519_KEY_IMPORT */
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)
/* See if DER data is an Ed448 private key.
*
* Checks size meets minimum ECC key size.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] der DER encoding.
* @param [in, out] keyFormat On in, expected format. 0 means unknown.
* @param [in] heap Dynamic memory allocation hint.
* @param [in] devId Device identifier.
* @param [out] keyType Type of key.
* @param [out] keySize Size of key.
* @return 0 on success or not an Ed448 key and format unknown.
* @return ECC_KEY_SIZE_E when key size doesn't meet minimum required.
*/
static int ProcessBufferTryDecodeEd448(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int* keyFormat, void* heap, int devId, byte* keyType,
int* keySize)
{
int ret;
word32 idx;
/* make sure Ed448 key can be used */
#ifdef WOLFSSL_SMALL_STACK
ed448_key* key = NULL;
#else
ed448_key key[1];
#endif
#ifdef WOLFSSL_SMALL_STACK
/* Allocate an Ed448 key to parse into. */
key = (ed448_key*)XMALLOC(sizeof(ed448_key), heap, DYNAMIC_TYPE_ED448);
if (key == NULL)
return MEMORY_E;
#endif
/* Initialize Ed448 key. */
ret = wc_ed448_init_ex(key, heap, devId);
if (ret == 0) {
/* Decode as an Ed448 private key. */
idx = 0;
ret = wc_Ed448PrivateKeyDecode(der->buffer, &idx, key, der->length);
#ifdef WOLF_PRIVATE_KEY_ID
/* If that didn't work then maybe a public key if device ID or callback.
*/
if ((ret != 0) && ((devId != INVALID_DEVID) ||
WOLFSSL_IS_PRIV_PK_SET(ctx, ssl))) {
/* Decode as an Ed448 public key. */
idx = 0;
ret = wc_Ed448PublicKeyDecode(der->buffer, &idx, key, der->length);
}
#endif
if (ret == 0) {
/* Get the minimum ECC key size from SSL or SSL context object. */
int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz;
/* Format is known. */
*keyFormat = ED448k;
*keyType = ed448_sa_algo;
*keySize = ED448_KEY_SIZE;
/* Check that the size of the ECC key is enough. */
if (ED448_KEY_SIZE < minKeySz) {
WOLFSSL_MSG("ED448 private key too small");
ret = ECC_KEY_SIZE_E;
}
if (ssl != NULL) {
/* Ed448 requires caching enabled for tracking message
* hash used in EdDSA_Update for signing */
ssl->options.cacheMessages = 1;
}
}
/* Not an Ed448 key but check whether we know what it is. */
else if (*keyFormat == 0) {
WOLFSSL_MSG("Not an Ed448 key");
/* Format unknown so keep trying. */
ret = 0;
}
/* Free dynamically allocated data in key. */
wc_ed448_free(key);
}
#ifdef WOLFSSL_SMALL_STACK
/* Dispose of allocated key. */
XFREE(key, heap, DYNAMIC_TYPE_ED448);
#endif
return ret;
}
#endif /* HAVE_ED448 && HAVE_ED448_KEY_IMPORT */
#if defined(HAVE_PQC)
#if defined(HAVE_FALCON)
/* See if DER data is an Falcon private key.
*
* Checks size meets minimum Falcon key size.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] der DER encoding.
* @param [in, out] keyFormat On in, expected format. 0 means unknown.
* @param [in] heap Dynamic memory allocation hint.
* @param [in] devId Device identifier.
* @param [out] keyType Type of key.
* @param [out] keySize Size of key.
* @return 0 on success or not an Falcon key and format unknown.
* @return FALCON_KEY_SIZE_E when key size doesn't meet minimum required.
*/
static int ProcessBufferTryDecodeFalcon(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int* keyFormat, void* heap, byte* keyType, int* keySize)
{
int ret;
falcon_key* key;
/* Allocate a Falcon key to parse into. */
key = (falcon_key*)XMALLOC(sizeof(falcon_key), heap, DYNAMIC_TYPE_FALCON);
if (key == NULL) {
return MEMORY_E;
}
/* Initialize Falcon key. */
ret = wc_falcon_init(key);
if (ret == 0) {
/* Set up key to parse the format specified. */
if (*keyFormat == FALCON_LEVEL1k) {
ret = wc_falcon_set_level(key, 1);
}
else if (*keyFormat == FALCON_LEVEL5k) {
ret = wc_falcon_set_level(key, 5);
}
else {
/* What if *keyformat is 0? We might want to do something more
* graceful here. */
/* TODO: get the size of the private key for different formats and
* compare with DER length. */
wc_falcon_free(key);
ret = ALGO_ID_E;
}
}
if (ret == 0) {
/* Decode as a Falcon private key. */
ret = wc_falcon_import_private_only(der->buffer, der->length, key);
if (ret == 0) {
/* Get the minimum Falcon key size from SSL or SSL context object.
*/
int minKeySz = ssl ? ssl->options.minFalconKeySz :
ctx->minFalconKeySz;
/* Format is known. */
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;
}
/* Check that the size of the Falcon key is enough. */
if (*keySize < minKeySz) {
WOLFSSL_MSG("Falcon private key too small");
ret = FALCON_KEY_SIZE_E;
}
}
/* Not a Falcon key but check whether we know what it is. */
else if (*keyFormat == 0) {
WOLFSSL_MSG("Not a Falcon key");
/* Format unknown so keep trying. */
ret = 0;
}
/* Free dynamically allocated data in key. */
wc_falcon_free(key);
}
/* Dispose of allocated key. */
XFREE(key, heap, DYNAMIC_TYPE_FALCON);
return ret;
}
#endif
#if defined(HAVE_DILITHIUM)
/* See if DER data is an Dilithium private key.
*
* Checks size meets minimum Falcon key size.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] der DER encoding.
* @param [in, out] keyFormat On in, expected format. 0 means unknown.
* @param [in] heap Dynamic memory allocation hint.
* @param [in] devId Device identifier.
* @param [out] keyType Type of key.
* @param [out] keySize Size of key.
* @return 0 on success or not a Dilithium key and format unknown.
* @return DILITHIUM_KEY_SIZE_E when key size doesn't meet minimum required.
*/
static int ProcessBufferTryDecodeDilithium(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int* keyFormat, void* heap, byte* keyType, int* keySize)
{
int ret;
dilithium_key* key;
/* Allocate a Dilithium key to parse into. */
key = (dilithium_key*)XMALLOC(sizeof(dilithium_key), heap,
DYNAMIC_TYPE_DILITHIUM);
if (key == NULL) {
return MEMORY_E;
}
/* Initialize Dilithium key. */
ret = wc_dilithium_init(key);
if (ret == 0) {
/* Set up key to parse the format specified. */
if (*keyFormat == DILITHIUM_LEVEL2k) {
ret = wc_dilithium_set_level(key, 2);
}
else if (*keyFormat == DILITHIUM_LEVEL3k) {
ret = wc_dilithium_set_level(key, 3);
}
else if (*keyFormat == DILITHIUM_LEVEL5k) {
ret = wc_dilithium_set_level(key, 5);
}
else {
/* What if *keyformat is 0? We might want to do something more
* graceful here. */
/* TODO: get the size of the private key for different formats and
* compare with DER length. */
wc_dilithium_free(key);
ret = ALGO_ID_E;
}
}
if (ret == 0) {
/* Decode as a Dilithium private key. */
ret = wc_dilithium_import_private_only(der->buffer, der->length, key);
if (ret == 0) {
/* Get the minimum Dilithium key size from SSL or SSL context
* object. */
int minKeySz = ssl ? ssl->options.minDilithiumKeySz :
ctx->minDilithiumKeySz;
/* Format is known. */
if (*keyFormat == DILITHIUM_LEVEL2k) {
*keyType = dilithium_level2_sa_algo;
*keySize = DILITHIUM_LEVEL2_KEY_SIZE;
}
else if (*keyFormat == DILITHIUM_LEVEL3k) {
*keyType = dilithium_level3_sa_algo;
*keySize = DILITHIUM_LEVEL3_KEY_SIZE;
}
else if (*keyFormat == DILITHIUM_LEVEL5k) {
*keyType = dilithium_level5_sa_algo;
*keySize = DILITHIUM_LEVEL5_KEY_SIZE;
}
/* Check that the size of the Dilithium key is enough. */
if (*keySize < minKeySz) {
WOLFSSL_MSG("Dilithium private key too small");
ret = DILITHIUM_KEY_SIZE_E;
}
}
/* Not a Dilithium key but check whether we know what it is. */
else if (*keyFormat == 0) {
WOLFSSL_MSG("Not a Dilithium key");
/* Format unknown so keep trying. */
ret = 0;
}
/* Free dynamically allocated data in key. */
wc_dilithium_free(key);
}
/* Dispose of allocated key. */
XFREE(key, heap, DYNAMIC_TYPE_DILITHIUM);
return ret;
}
#endif /* HAVE_DILITHIUM */
#endif /* HAVE_PQC */
/* Try to decode DER data is a known private key.
*
* Checks size meets minimum for key type.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] der DER encoding.
* @param [in, out] keyFormat On in, expected format. 0 means unknown.
* @param [in] heap Dynamic memory allocation hint.
* @param [out] type Type of key:
* PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE.
* @return 0 on success.
* @return BAD_FUNC_ARG when der or keyFormat is NULL.
* @return BAD_FUNC_ARG when ctx and ssl are NULL.
* @return WOLFSSL_BAD_FILE when unable to identify the key format.
*/
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;
(void)heap;
(void)devId;
(void)type;
/* Validate parameters. */
if ((der == NULL) || (keyFormat == NULL)) {
ret = BAD_FUNC_ARG;
}
/* Must have an SSL context or SSL object to use. */
if ((ret == 0) && (ctx == NULL) && (ssl == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
/* Determine where to put key type and size in SSL or context object. */
#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
/* Type is PRIVATEKEY_TYPE. */
if (ssl != NULL) {
keyType = &ssl->buffers.keyType;
keySz = &ssl->buffers.keySz;
}
else {
keyType = &ctx->privateKeyType;
keySz = &ctx->privateKeySz;
}
}
#ifndef NO_RSA
/* Try RSA if key format is RSA or yet unknown. */
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
}
#endif
#ifdef HAVE_ECC
/* Try ECC if key format is ECDSA or SM2, or yet unknown. */
if ((ret == 0) && ((*keyFormat == 0) || (*keyFormat == ECDSAk)
#ifdef WOLFSSL_SM2
|| (*keyFormat == SM2k)
#endif
)) {
ret = ProcessBufferTryDecodeEcc(ctx, ssl, der, keyFormat, heap, devId,
keyType, keySz);
}
#endif /* HAVE_ECC */
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT)
/* Try Ed25519 if key format is Ed25519 or yet unknown. */
if ((ret == 0) && ((*keyFormat == 0 || *keyFormat == ED25519k))) {
ret = ProcessBufferTryDecodeEd25519(ctx, ssl, der, keyFormat, heap,
devId, keyType, keySz);
}
#endif /* HAVE_ED25519 && HAVE_ED25519_KEY_IMPORT */
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)
/* Try Ed448 if key format is Ed448 or yet unknown. */
if ((ret == 0) && ((*keyFormat == 0 || *keyFormat == ED448k))) {
ret = ProcessBufferTryDecodeEd448(ctx, ssl, der, keyFormat, heap, devId,
keyType, keySz);
}
#endif /* HAVE_ED448 && HAVE_ED448_KEY_IMPORT */
#if defined(HAVE_PQC)
#if defined(HAVE_FALCON)
/* Try Falcon if key format is Falcon level 1k or 5k or yet unknown. */
if ((ret == 0) && ((*keyFormat == 0) || (*keyFormat == FALCON_LEVEL1k) ||
(*keyFormat == FALCON_LEVEL5k))) {
ret = ProcessBufferTryDecodeFalcon(ctx, ssl, der, keyFormat, heap,
keyType, keySz);
}
#endif /* HAVE_FALCON */
#if defined(HAVE_DILITHIUM)
/* Try Falcon if key format is Dilithium level 2k, 3k or 5k or yet unknown.
*/
if ((ret == 0) && ((*keyFormat == 0) || (*keyFormat == DILITHIUM_LEVEL2k) ||
(*keyFormat == DILITHIUM_LEVEL3k) ||
(*keyFormat == DILITHIUM_LEVEL5k))) {
ret = ProcessBufferTryDecodeDilithium(ctx, ssl, der, keyFormat, heap,
keyType, keySz);
}
#endif /* HAVE_DILITHIUM */
#endif /* HAVE_PQC */
/* Check we know the format. */
if ((ret == 0) && (*keyFormat == 0)) {
WOLFSSL_MSG("Not a supported key type");
/* Not supported key format. */
ret = WOLFSSL_BAD_FILE;
}
return ret;
}
#if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED)
/* Decrypt PKCS#8 private key.
*
* @param [in] info Encryption information.
* @param [in] der DER encoded data.
* @param [in] heap Dynamic memory allocation hint.
* @return 0 on success.
* @return MEMORY_E when dynamic memory allocation fails.
*/
static int ProcessBufferPrivPkcs8Dec(EncryptedInfo* info, DerBuffer* der,
void* heap)
{
int ret = 0;
word32 algId;
int passwordSz = NAME_SZ;
#ifndef WOLFSSL_SMALL_STACK
char password[NAME_SZ];
#else
char* password;
#endif
(void)heap;
#ifdef WOLFSSL_SMALL_STACK
/* Allocate memory for password. */
password = (char*)XMALLOC(passwordSz, heap, DYNAMIC_TYPE_STRING);
if (password == NULL) {
ret = MEMORY_E;
}
#endif
if (ret == 0) {
/* Get password. */
ret = info->passwd_cb(password, passwordSz, PEM_PASS_READ,
info->passwd_userdata);
}
if (ret >= 0) {
/* Returned value is password size. */
passwordSz = ret;
#ifdef WOLFSSL_CHECK_MEM_ZERO
wc_MemZero_Add("ProcessBuffer password", password, passwordSz);
#endif
/* Decrypt PKCS#8 private key inline and get algorithm id. */
ret = ToTraditionalEnc(der->buffer, der->length, password, passwordSz,
&algId);
}
if (ret >= 0) {
/* Zero out encrypted data not overwritten. */
ForceZero(der->buffer + ret, der->length - ret);
/* Set decrypted data length. */
der->length = (word32)ret;
}
/* Ensure password is zeroized. */
ForceZero(password, (word32)passwordSz);
#ifdef WOLFSSL_SMALL_STACK
/* Dispose of password memory. */
XFREE(password, heap, DYNAMIC_TYPE_STRING);
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
wc_MemZero_Check(password, NAME_SZ);
#endif
return ret;
}
#endif /* WOLFSSL_ENCRYPTED_KEYS && !NO_PWDBASED */
/* Put the DER into the SSL or SSL context object.
*
* Precondition: ctx or ssl is not NULL.
* Precondition: Must be a private key type.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] der DER encoding.
* @return 0 on success.
*/
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) {
/* Put in alternate private key fields of objects. */
if (ssl != NULL) {
/* Dispose of previous key if not context's. */
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;
/* Store key by reference and own it. */
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) {
/* Dispose of previous key. */
FreeDer(&ctx->altPrivateKey);
ctx->altPrivateKeyId = 0;
ctx->altPrivateKeyLabel = 0;
ctx->altPrivateKeyDevId = INVALID_DEVID;
/* Store key by reference. */
ctx->altPrivateKey = *der;
#ifdef WOLFSSL_CHECK_MEM_ZERO
wc_MemZero_Add("CTX private key", (*der)->buffer, (*der)->length);
#endif
}
}
else
#endif /* WOLFSSL_DUAL_ALG_CERTS */
if (ssl != NULL) {
/* Dispose of previous key if not context's. */
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;
/* Store key by reference and own it. */
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) {
/* Dispose of previous key. */
FreeDer(&ctx->privateKey);
ctx->privateKeyId = 0;
ctx->privateKeyLabel = 0;
ctx->privateKeyDevId = INVALID_DEVID;
/* Store key by reference. */
ctx->privateKey = *der;
#ifdef WOLFSSL_CHECK_MEM_ZERO
wc_MemZero_Add("CTX private key", (*der)->buffer, (*der)->length);
#endif
}
return ret;
}
/* Decode private key.
*
* Precondition: ctx or ssl is not NULL.
* Precondition: Must be a private key type.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] der DER encoding.
* @param [in] format Original format of data.
* @param [in] info Encryption information.
* @param [in] heap Dynamic memory allocation hint.
* @param [in] type Type of data:
* PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE.
* @param [in] algId Algorithm id of key.
* @return 0 on success.
* @return WOLFSSL_BAD_FILE when not able to decode.
*/
static int ProcessBufferPrivateKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int format, EncryptedInfo* info, void* heap, int type,
int algId)
{
int ret;
#if (defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED)) || \
defined(HAVE_PKCS8)
word32 p8AlgId = 0;
#endif
(void)info;
(void)format;
#ifdef HAVE_PKCS8
/* Try and remove PKCS8 header and get algorithm id. */
ret = ToTraditional_ex(der->buffer, der->length, &p8AlgId);
if (ret > 0) {
/* Header stripped inline. */
der->length = (word32)ret;
algId = p8AlgId;
}
#endif
/* Put the data into the SSL or SSL context object. */
ret = ProcessBufferPrivKeyHandleDer(ctx, ssl, &der, type);
if (ret == 0) {
/* Try to decode the DER data. */
ret = ProcessBufferTryDecode(ctx, ssl, der, &algId, heap, type);
}
#if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED)
/* If private key type PKCS8 header wasn't already removed (algId == 0). */
if (((ret != 0) || (algId == 0)) && (format != WOLFSSL_FILETYPE_PEM) &&
(info->passwd_cb != NULL) && (algId == 0)) {
/* Try to decrypt DER data as a PKCS#8 private key. */
ret = ProcessBufferPrivPkcs8Dec(info, der, heap);
if (ret >= 0) {
/* Try to decode decrypted data. */
ret = ProcessBufferTryDecode(ctx, ssl, der, &algId, heap, type);
}
}
#endif /* WOLFSSL_ENCRYPTED_KEYS && !NO_PWDBASED */
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
#ifdef WOLFSSL_DUAL_ALG_CERTS
if (type == ALT_PRIVATEKEY_TYPE) {
if (ssl != NULL) {
ret = wolfssl_priv_der_blind(ssl->rng, ssl->buffers.altKey,
&ssl->buffers.altKeyMask);
}
else {
ret = wolfssl_priv_der_blind(NULL, ctx->altPrivateKey,
&ctx->altPrivateKeyMask);
}
}
else
#endif
if (ssl != NULL) {
ret = wolfssl_priv_der_blind(ssl->rng, ssl->buffers.key,
&ssl->buffers.keyMask);
}
else {
ret = wolfssl_priv_der_blind(NULL, ctx->privateKey,
&ctx->privateKeyMask);
}
#endif
/* Check if we were able to determine algorithm id. */
if ((ret == 0) && (algId == 0)) {
#ifdef OPENSSL_EXTRA
/* Decryption password is probably wrong. */
if (info->passwd_cb) {
EVPerr(0, EVP_R_BAD_DECRYPT);
}
#endif
WOLFSSL_ERROR(WOLFSSL_BAD_FILE);
/* Unable to decode DER data. */
ret = WOLFSSL_BAD_FILE;
}
return ret;
}
/* Use the key OID to determine have options.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] keyOID OID for public/private key.
*/
static void wolfssl_set_have_from_key_oid(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
int keyOID)
{
/* Set which private key algorithm available based on key OID. */
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_PQC
#ifdef HAVE_FALCON
case FALCON_LEVEL1k:
case FALCON_LEVEL5k:
if (ssl != NULL) {
ssl->options.haveFalconSig = 1;
}
else {
ctx->haveFalconSig = 1;
}
break;
#endif /* HAVE_FALCON */
#ifdef HAVE_DILITHIUM
case DILITHIUM_LEVEL2k:
case DILITHIUM_LEVEL3k:
case DILITHIUM_LEVEL5k:
if (ssl != NULL) {
ssl->options.haveDilithiumSig = 1;
}
else {
ctx->haveDilithiumSig = 1;
}
break;
#endif /* HAVE_DILITHIUM */
#endif /* HAVE_PQC */
default:
WOLFSSL_MSG("Cert key not supported");
break;
}
}
/* Set which private key algorithm we have against SSL or SSL context object.
*
* Precondition: ctx or ssl is not NULL.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] cert Decode certificate.
*/
static void ProcessBufferCertSetHave(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DecodedCert* cert)
{
if (ssl != NULL) {
/* Reset signatures we have in SSL. */
ssl->options.haveECDSAsig = 0;
ssl->options.haveFalconSig = 0;
ssl->options.haveDilithiumSig = 0;
}
/* Set which signature we have based on the type in the cert. */
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_PQC
#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_DILITHIUM_LEVEL2:
case CTC_DILITHIUM_LEVEL3:
case CTC_DILITHIUM_LEVEL5:
WOLFSSL_MSG("Dilithium cert signature");
if (ssl) {
ssl->options.haveDilithiumSig = 1;
}
else if (ctx) {
ctx->haveDilithiumSig = 1;
}
break;
#endif
#endif
default:
WOLFSSL_MSG("Cert signature not supported");
break;
}
#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \
(defined(HAVE_PQC) && defined(HAVE_LIBOQS)) || !defined(NO_RSA)
#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448)
/* Set the private key curve OID. */
if (ssl != NULL) {
ssl->pkCurveOID = cert->pkCurveOID;
}
else if (ctx) {
ctx->pkCurveOID = cert->pkCurveOID;
}
#endif
#ifndef WC_STRICT_SIG
wolfssl_set_have_from_key_oid(ctx, ssl, cert->keyOID);
#else
/* Set whether ECC is available based on signature available. */
if (ssl != NULL) {
ssl->options.haveECC = ssl->options.haveECDSAsig;
}
else if (ctx) {
ctx->haveECC = ctx->haveECDSAsig;
}
#endif /* !WC_STRICT_SIG */
#endif
}
/* Check key size is valid.
*
* Precondition: ctx or ssl is not NULL.
*
* @param [in] min Minimum key size.
* @param [in] max Maximum key size.
* @param [in] keySz Key size.
* @param [in] err Error value to return when key size is invalid.
* @return 0 on success.
* @return err when verifying and min is less than 0 or key size is invalid.
*/
#define CHECK_KEY_SZ(min, max, keySz, err) \
(((min) < 0) || ((keySz) < (min)) || ((keySz) > (max))) ? (err) : 0
/* Check public key in certificate.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] cert Certificate object.
* @return 0 on success.
* @return Non-zero when an error occurred.
*/
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
/* Get key size and check unless not verifying. */
switch (cert->keyOID) {
#ifndef NO_RSA
#ifdef WC_RSA_PSS
case RSAPSSk:
#endif
case RSAk:
keyType = rsa_sa_algo;
/* Determine RSA key size by parsing public key */
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);
}
break;
#endif /* !NO_RSA */
#ifdef HAVE_ECC
case ECDSAk:
keyType = ecc_dsa_sa_algo;
/* Determine ECC key size based on curve */
#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 /* HAVE_ECC */
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
case SM2k:
keyType = sm2_sa_algo;
/* Determine ECC key size based on curve */
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 /* HAVE_ED25519 */
#ifdef HAVE_ED25519
case ED25519k:
keyType = ed25519_sa_algo;
/* ED25519 is fixed key size */
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 /* HAVE_ED25519 */
#ifdef HAVE_ED448
case ED448k:
keyType = ed448_sa_algo;
/* ED448 is fixed key size */
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 /* HAVE_ED448 */
#if defined(HAVE_PQC)
#if defined(HAVE_FALCON)
case FALCON_LEVEL1k:
keyType = falcon_level1_sa_algo;
/* Falcon is fixed key size */
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;
/* Falcon is fixed key size */
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 /* HAVE_FALCON */
#if defined(HAVE_DILITHIUM)
case DILITHIUM_LEVEL2k:
keyType = dilithium_level2_sa_algo;
/* Dilithium is fixed key size */
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;
/* Dilithium is fixed key size */
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;
/* Dilithium is fixed key size */
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 /* HAVE_DILITHIUM */
#endif /* HAVE_PQC */
default:
WOLFSSL_MSG("No key size check done on public key in certificate");
break;
}
/* Store the type and key size as there may not be a private key set. */
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
/* Check alternative key size of cert. */
switch (cert->sapkiOID) {
/* No OID set. */
case 0:
if (cert->sapkiLen != 0) {
/* Have the alternative key data but no OID. */
ret = NOT_COMPILED_IN;
}
break;
#ifndef NO_RSA
#ifdef WC_RSA_PSS
case RSAPSSk:
#endif
case RSAk:
keyType = rsa_sa_algo;
/* Determine RSA key size by parsing public key */
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 /* !NO_RSA */
#ifdef HAVE_ECC
case ECDSAk:
{
#ifdef WOLFSSL_SMALL_STACK
ecc_key* temp_key = NULL;
#else
ecc_key temp_key[1];
#endif
keyType = ecc_dsa_sa_algo;
#ifdef WOLFSSL_SMALL_STACK
temp_key = (ecc_key*)XMALLOC(sizeof(ecc_key), heap,
DYNAMIC_TYPE_ECC);
if (temp_key == NULL) {
ret = MEMORY_E;
}
#endif
/* Determine ECC key size. We have to decode the sapki for
* that. */
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);
}
}
#ifdef WOLFSSL_SMALL_STACK
XFREE(temp_key, heap, DYNAMIC_TYPE_ECC);
#endif
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 /* HAVE_ECC */
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
case SM2k:
keyType = sm2_sa_algo;
/* Determine ECC key size based on curve */
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 /* HAVE_ED25519 */
#ifdef HAVE_ED25519
case ED25519k:
keyType = ed25519_sa_algo;
/* ED25519 is fixed key size */
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 /* HAVE_ED25519 */
#ifdef HAVE_ED448
case ED448k:
keyType = ed448_sa_algo;
/* ED448 is fixed key size */
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 /* HAVE_ED448 */
#if defined(HAVE_PQC)
#if defined(HAVE_FALCON)
case FALCON_LEVEL1k:
keyType = falcon_level1_sa_algo;
/* Falcon is fixed key size */
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;
/* Falcon is fixed key size */
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 /* HAVE_FALCON */
#if defined(HAVE_DILITHIUM)
case DILITHIUM_LEVEL2k:
keyType = dilithium_level2_sa_algo;
/* Dilithium is fixed key size */
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;
/* Dilithium is fixed key size */
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;
/* Dilithium is fixed key size */
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 /* HAVE_DILITHIUM */
#endif /* HAVE_PQC */
default:
/* In this case, there was an OID that we didn't recognize.
* This is an error. Use not compiled in because likely the
* given algorithm was not enabled. */
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 /* WOLFSSL_DUAL_ALG_CERTS */
/* Parse the certificate and pull out information for TLS handshake.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] der DER encoded X509 certificate.
* @return 0 on success.
* @return MEMORY_E when dynamic memory allocation fails.
* @return WOLFSSL_BAD_FILE when decoding certificate fails.
*/
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
#ifdef WOLFSSL_SMALL_STACK
DecodedCert* cert;
#else
DecodedCert cert[1];
#endif
#ifdef WOLFSSL_SMALL_STACK
/* Allocate memory for certificate to be decoded into. */
cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), heap, DYNAMIC_TYPE_DCERT);
if (cert == NULL) {
ret = MEMORY_E;
}
if (ret == 0)
#endif
{
/* Get device id from SSL context or SSL object. */
int devId = wolfSSL_CTX_GetDevId(ctx, ssl);
WOLFSSL_MSG("Checking cert signature type");
/* Initialize certificate object. */
InitDecodedCert_ex(cert, der->buffer, der->length, heap, devId);
/* Decode up to and including public key. */
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)
/* Store whether the crtificate is a raw public key. */
rpkState->isRPKLoaded = cert->isRPK;
#endif /* HAVE_RPK */
/* Set which private key algorithm we have. */
ProcessBufferCertSetHave(ctx, ssl, cert);
/* Don't check if verification is disabled for SSL. */
if ((ssl != NULL) && ssl->options.verifyNone) {
checkKeySz = 0;
}
/* Don't check if no SSL object verification is disabled for SSL
* context. */
else if ((ssl == NULL) && ctx->verifyNone) {
checkKeySz = 0;
}
/* Check public key size. */
ret = ProcessBufferCertPublicKey(ctx, ssl, cert, checkKeySz);
#ifdef WOLFSSL_DUAL_ALG_CERTS
if (ret == 0) {
ret = ProcessBufferCertAltPublicKey(ctx, ssl, cert, checkKeySz);
}
#endif
}
}
/* Dispose of dynamic memory in certificate object. */
FreeDecodedCert(cert);
#ifdef WOLFSSL_SMALL_STACK
/* Dispose of certificate object. */
XFREE(cert, heap, DYNAMIC_TYPE_DCERT);
#endif
return ret;
}
/* Handle storing the DER encoding of the certificate.
*
* Do not free der outside of this function.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] der DER encoded certificate.
* @param [in] type Type of data:
* CERT_TYPE, CA_TYPE or TRUSTED_PEER_TYPE.
* @param [in] verify What verification to do.
* @return 0 on success.
* @return BAD_FUNC_ARG when type is CA_TYPE and ctx is NULL.
* @return WOLFSSL_BAD_CERTTYPE when data type is not supported.
*/
static int ProcessBufferCertHandleDer(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
DerBuffer* der, int type, int verify)
{
int ret = 0;
/* CA certificate to verify with. */
if (type == CA_TYPE) {
/* verify CA unless user set to no verify */
ret = AddCA(ctx->cm, &der, WOLFSSL_USER_CA, verify);
if (ret == 1) {
ret = 0;
}
}
#ifdef WOLFSSL_TRUST_PEER_CERT
/* Trusted certificate to verify peer with. */
else if (type == TRUSTED_PEER_TYPE) {
WOLFSSL_CERT_MANAGER* cm;
/* Get certificate manager to add certificate to. */
if (ctx != NULL) {
cm = ctx->cm;
}
else {
SSL_CM_WARNING(ssl);
cm = SSL_CM(ssl);
}
/* Add certificate as a trusted peer. */
ret = AddTrustedPeer(cm, &der, verify);
if (ret != 1) {
WOLFSSL_MSG("Error adding trusted peer");
}
}
#endif /* WOLFSSL_TRUST_PEER_CERT */
/* Leaf certificate - our certificate. */
else if (type == CERT_TYPE) {
if (ssl != NULL) {
/* Free previous certificate if we own it. */
if (ssl->buffers.weOwnCert) {
FreeDer(&ssl->buffers.certificate);
#ifdef KEEP_OUR_CERT
/* Dispose of X509 version of certificate. */
wolfSSL_X509_free(ssl->ourCert);
ssl->ourCert = NULL;
#endif
}
/* Store certificate as ours. */
ssl->buffers.certificate = der;
#ifdef KEEP_OUR_CERT
ssl->keepCert = 1; /* hold cert for ssl lifetime */
#endif
/* We have to free the certificate buffer. */
ssl->buffers.weOwnCert = 1;
/* ourCert is created on demand. */
}
else if (ctx != NULL) {
/* Free previous certificate. */
FreeDer(&ctx->certificate); /* Make sure previous is free'd */
#ifdef KEEP_OUR_CERT
/* Dispose of X509 version of certificate if we own it. */
if (ctx->ownOurCert) {
wolfSSL_X509_free(ctx->ourCert);
}
ctx->ourCert = NULL;
#endif
/* Store certificate as ours. */
ctx->certificate = der;
/* ourCert is created on demand. */
}
}
else {
/* Dispose of DER buffer. */
FreeDer(&der);
/* Not a certificate type supported. */
ret = WOLFSSL_BAD_CERTTYPE;
}
return ret;
}
/* Process certificate based on type.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] buff Buffer holding original data.
* @param [in] sz Size of data in buffer.
* @param [in] der DER encoding of certificate.
* @param [in] format Format of data.
* @param [in] type Type of data:
* CERT_TYPE, CA_TYPE or TRUSTED_PEER_TYPE.
* @param [in] verify What verification to do.
* @return 0 on success.
* @return WOLFSSL_FATAL_ERROR on failure.
*/
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)) {
/* Process leaf certificate. */
ret = ProcessBufferCert(ctx, ssl, der);
}
#if !defined(NO_WOLFSSL_CM_VERIFY) && (!defined(NO_WOLFSSL_CLIENT) || \
!defined(WOLFSSL_NO_CLIENT_AUTH))
/* Hand bad CA or user certificate to callback. */
if ((ret < 0) && ((type == CA_TYPE) || (type == CERT_TYPE))) {
/* Check for verification callback that may override error. */
if ((ctx != NULL) && (ctx->cm != NULL) &&
(ctx->cm->verifyCallback != NULL)) {
/* Verify and use callback. */
ret = CM_VerifyBuffer_ex(ctx->cm, buff, sz, format, ret);
/* Convert error. */
if (ret == 0) {
ret = WOLFSSL_FATAL_ERROR;
}
if (ret == 1) {
ret = 0;
}
}
}
#endif /* NO_WOLFSSL_CM_VERIFY */
return ret;
}
/* Reset the cipher suites based on updated private key or certificate.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] type Type of certificate.
* @return 0 on success.
* @return WOLFSSL_FATAL_ERROR when allocation fails.
*/
static int ProcessBufferResetSuites(WOLFSSL_CTX* ctx, WOLFSSL* ssl, int type)
{
int ret = 0;
/* Reset suites of SSL object. */
if (ssl != NULL) {
if (ssl->options.side == WOLFSSL_SERVER_END) {
/* Allocate memory for suites. */
if (AllocateSuites(ssl) != 0) {
ret = WOLFSSL_FATAL_ERROR;
}
else {
/* Determine cipher suites based on what we have. */
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.haveFalconSig,
ssl->options.haveDilithiumSig, ssl->options.useAnon, TRUE,
ssl->options.side);
}
}
}
/* Reset suites of SSL context object. */
else if ((type == CERT_TYPE) && (ctx->method->side == WOLFSSL_SERVER_END)) {
/* Allocate memory for suites. */
if (AllocateCtxSuites(ctx) != 0) {
ret = WOLFSSL_FATAL_ERROR;
}
else {
/* Determine cipher suites based on what we have. */
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->haveFalconSig, ctx->haveDilithiumSig, CTX_USE_ANON(ctx),
TRUE, ctx->method->side);
}
}
return ret;
}
#ifndef WOLFSSL_DUAL_ALG_CERTS
/* Determine whether the type is for a private key. */
#define IS_PRIVKEY_TYPE(type) ((type) == PRIVATEKEY_TYPE)
#else
/* Determine whether the type is for a private key. */
#define IS_PRIVKEY_TYPE(type) (((type) == PRIVATEKEY_TYPE) || \
((type) == ALT_PRIVATEKEY_TYPE))
#endif
/* Process a buffer of data.
*
* Data type is a private key or a certificate.
* The format can be ASN.1 (DER) or PEM.
*
* @param [in, out] ctx SSL context object.
* @param [in] buff Buffer holding data.
* @param [in] sz Size of data in buffer.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @param [in] type Type of data:
* CERT_TYPE, CA_TYPE, TRUSTED_PEER_TYPE,
* PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE.
* @param [in, out] ssl SSL object.
* @param [out] used Number of bytes consumed.
* @param [in[ userChain Whether this certificate is for user's chain.
* @param [in] verify How to verify certificate.
* @return 1 on success.
* @return Less than 1 on failure.
*/
int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, long sz,
int format, int type, WOLFSSL* ssl, long* used, int userChain, int verify)
{
DerBuffer* der = NULL;
int ret = 0;
void* heap = WOLFSSL_HEAP(ctx, ssl);
#ifdef WOLFSSL_SMALL_STACK
EncryptedInfo* info = NULL;
#else
EncryptedInfo info[1];
#endif
int algId = 0;
WOLFSSL_ENTER("ProcessBuffer");
/* Check data format is supported. */
if ((format != WOLFSSL_FILETYPE_ASN1) && (format != WOLFSSL_FILETYPE_PEM)) {
ret = WOLFSSL_BAD_FILETYPE;
}
/* Need an object to store certificate into. */
if ((ret == 0) && (ctx == NULL) && (ssl == NULL)) {
ret = BAD_FUNC_ARG;
}
/* CA certificates go into the SSL context object. */
if ((ret == 0) && (ctx == NULL) && (type == CA_TYPE)) {
ret = BAD_FUNC_ARG;
}
/* This API does not handle CHAIN_CERT_TYPE */
if ((ret == 0) && (type == CHAIN_CERT_TYPE)) {
ret = BAD_FUNC_ARG;
}
#ifdef WOLFSSL_SMALL_STACK
if (ret == 0) {
/* Allocate memory for encryption information. */
info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), heap,
DYNAMIC_TYPE_ENCRYPTEDINFO);
if (info == NULL) {
ret = MEMORY_E;
}
}
#endif
if (ret == 0) {
/* Initialize encryption information. */
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
/* Get the DER data for a private key or certificate. */
ret = DataToDerBuffer(buff, (word32)sz, format, type, info, heap, &der,
&algId);
if (used != NULL) {
/* Update to amount used/consumed. */
*used = info->consumed;
}
#ifdef WOLFSSL_SMALL_STACK
if (ret != 0) {
/* Info no longer needed as loading failed. */
XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO);
}
#endif
}
if ((ret == 0) && IS_PRIVKEY_TYPE(type)) {
/* Process the private key. */
ret = ProcessBufferPrivateKey(ctx, ssl, der, format, info, heap, type,
algId);
#ifdef WOLFSSL_SMALL_STACK
/* Info no longer needed - keep max memory usage down. */
XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO);
#endif
}
else if (ret == 0) {
/* Processing a cerificate. */
if (userChain) {
/* Take original buffer and add to user chain to send in TLS
* handshake. */
ret = ProcessUserChain(ctx, ssl, buff, sz, format, type, used, info,
verify);
/* Additional chain is optional */
if (ret == ASN_NO_PEM_HEADER) {
unsigned long pemErr = 0;
CLEAR_ASN_NO_PEM_HEADER_ERROR(pemErr);
ret = 0;
}
}
#ifdef WOLFSSL_SMALL_STACK
/* Info no longer needed - keep max memory usage down. */
XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO);
#endif
if (ret == 0) {
/* Process the different types of certificates. */
ret = ProcessBufferCertTypes(ctx, ssl, buff, sz, der, format, type,
verify);
}
else {
FreeDer(&der);
}
}
/* Reset suites if this is a private key or user certificate. */
if ((ret == 0) && ((type == PRIVATEKEY_TYPE) || (type == CERT_TYPE))) {
ret = ProcessBufferResetSuites(ctx, ssl, type);
}
/* Convert return code. */
if (ret == 0) {
ret = 1;
}
else if (ret == WOLFSSL_FATAL_ERROR) {
ret = 0;
}
WOLFSSL_LEAVE("ProcessBuffer", ret);
return ret;
}
#if defined(WOLFSSL_WPAS) && defined(HAVE_CRL)
/* Try to parse data as a PEM CRL.
*
* @param [in] ctx SSL context object.
* @param [in] buff Buffer containing potential CRL in PEM format.
* @param [in] sz Amount of data in buffer remaining.
* @param [out] consumed Number of bytes in buffer was the CRL.
* @return 0 on success.
*/
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
/* Process all chain certificates (and CRLs) in the PEM data.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] buff Buffer containing PEM data.
* @param [in] sz Size of data in buffer.
* @param [in] type Type of data.
* @param [in] verify How to verify certificate.
* @return 1 on success.
* @return 0 on failure.
* @return MEMORY_E when dynamic memory allocation fails.
*/
static int ProcessChainBuffer(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
const unsigned char* buff, long sz, int type, int verify)
{
int ret = 0;
long used = 0;
int gotOne = 0;
WOLFSSL_MSG("Processing CA PEM file");
/* Keep processing file while no errors and data to parse. */
while ((ret >= 0) && (used < sz)) {
long consumed = 0;
/* Process the buffer. */
ret = ProcessBuffer(ctx, buff + used, sz - used, WOLFSSL_FILETYPE_PEM,
type, ssl, &consumed, 0, verify);
/* Memory allocation failure is fatal. */
if (ret == MEMORY_E) {
gotOne = 0;
}
/* Other error parsing. */
else if (ret < 0) {
#if defined(WOLFSSL_WPAS) && defined(HAVE_CRL)
/* Try parsing a CRL. */
if (ProcessChainBufferCRL(ctx, buff + used, sz - used,
&consumed) == 0) {
ret = 0;
}
else
#endif
/* Check whether we made progress. */
if (consumed > 0) {
WOLFSSL_ERROR(ret);
WOLFSSL_MSG("CA Parse failed, with progress in file.");
WOLFSSL_MSG("Search for other certs in file");
/* Check if we have more data to parse to recover. */
if (used + consumed < sz) {
ret = 0;
}
}
else {
/* No progress in parsing being made - stop here. */
WOLFSSL_MSG("CA Parse failed, no progress in file.");
WOLFSSL_MSG("Do not continue search for other certs in file");
}
}
else {
/* Got a certificate out. */
WOLFSSL_MSG(" Processed a CA");
gotOne = 1;
}
/* Update used count. */
used += consumed;
}
/* May have other unparsable data but did we get a certificate? */
if (gotOne) {
WOLFSSL_MSG("Processed at least one valid CA. Other stuff OK");
ret = 1;
}
return ret;
}
/* Get verify settings for AddCA from SSL context. */
#define GET_VERIFY_SETTING_CTX(ctx) \
((ctx) && (ctx)->verifyNone ? NO_VERIFY : VERIFY)
/* Get verify settings for AddCA from SSL. */
#define GET_VERIFY_SETTING_SSL(ssl) \
((ssl)->options.verifyNone ? NO_VERIFY : VERIFY)
#ifndef NO_FILESYSTEM
/* Process data from a file as private keys, CRL or certificates.
*
* @param [in, out] ctx SSL context object.
* @param [in] fname Name of file to read.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @param [in] type Type of data:
* CERT_TYPE, CA_TYPE, TRUSTED_PEER_TYPE,
* PRIVATEKEY_TYPE or ALT_PRIVATEKEY_TYPE.
* @param [in, out] ssl SSL object.
* @param [in] userChain Whether file contains chain of certificates.
* @param [in, out] crl CRL object to load data into.
* @param [in] verify How to verify certificates.
* @return 1 on success.
* @return WOLFSSL_BAD_FILE when reading the file fails.
* @return WOLFSSL_BAD_CERTTYPE when unable to detect certificate type.
*/
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
/* Read file into static buffer. */
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("Cannot detect certificate type when not PEM");
ret = WOLFSSL_BAD_CERTTYPE;
}
/* Try to detect type by parsing cert header and footer. */
if ((ret == 0) && (type == DETECT_CERT_TYPE)) {
#if !defined(NO_CODING) && !defined(WOLFSSL_NO_PEM)
const char* header = NULL;
const char* footer = NULL;
/* Look for CA header and footer - same as CERT_TYPE. */
if (wc_PemGetHeaderFooter(CA_TYPE, &header, &footer) == 0 &&
(XSTRNSTR((char*)content.buffer, header, (word32)sz) != NULL)) {
type = CA_TYPE;
}
#ifdef HAVE_CRL
/* Look for CRL header and footer. */
else if (wc_PemGetHeaderFooter(CRL_TYPE, &header, &footer) == 0 &&
(XSTRNSTR((char*)content.buffer, header, (word32)sz) != NULL)) {
type = CRL_TYPE;
}
#endif
/* Look for cert header and footer - same as CA_TYPE. */
else if (wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer) == 0 &&
(XSTRNSTR((char*)content.buffer, header, (word32)sz) !=
NULL)) {
type = CERT_TYPE;
}
else
#endif
{
/* Not a header that we support. */
WOLFSSL_MSG("Failed to detect certificate type");
ret = WOLFSSL_BAD_CERTTYPE;
}
}
if (ret == 0) {
/* When CA or trusted peer and PEM - process as a chain buffer. */
if (((type == CA_TYPE) || (type == TRUSTED_PEER_TYPE)) &&
(format == WOLFSSL_FILETYPE_PEM)) {
ret = ProcessChainBuffer(ctx, ssl, content.buffer, sz, type,
verify);
}
#ifdef HAVE_CRL
else if (type == CRL_TYPE) {
/* Load the CRL. */
ret = BufferLoadCRL(crl, content.buffer, sz, format, verify);
}
#endif
#ifdef WOLFSSL_DUAL_ALG_CERTS
else if (type == PRIVATEKEY_TYPE) {
/* When support for dual algorithm certificates is enabled, the
* private key file may contain both the primary and the
* alternative private key. Hence, we have to parse both of them.
*/
long consumed = 0;
ret = ProcessBuffer(ctx, content.buffer, sz, format, type, ssl,
&consumed, userChain, verify);
if ((ret == 1) && (consumed < sz)) {
ret = ProcessBuffer(ctx, content.buffer + consumed,
sz - consumed, format, ALT_PRIVATEKEY_TYPE, ssl, NULL, 0,
verify);
}
}
#endif
else {
/* Load all other certificate types. */
ret = ProcessBuffer(ctx, content.buffer, sz, format, type, ssl,
NULL, userChain, verify);
}
}
/* Dispose of dynamically allocated data. */
static_buffer_free(&content, heap, DYNAMIC_TYPE_FILE);
return ret;
}
#ifndef NO_WOLFSSL_DIR
/* Load file when filename is in the path.
*
* @param [in, out] ctx SSL context object.
* @param [in] name Name of file.
* @param [in] verify How to verify a certificate.
* @param [in] flags Flags representing options for loading.
* @param [in, out] failCount Number of files that failed to load.
* @param [in, out] successCount Number of files successfully loaded.
* @return 1 on success.
* @return Not 1 when loading PEM certificate failed.
*/
static int wolfssl_ctx_load_path_file(WOLFSSL_CTX* ctx, const char* name,
int verify, int flags, int* failCount, int* successCount)
{
int ret;
/* Attempt to load file as a CA. */
ret = ProcessFile(ctx, name, WOLFSSL_FILETYPE_PEM, CA_TYPE, NULL, 0, NULL,
verify);
if (ret != 1) {
/* When ignoring errors or loading PEM only and no PEM. don't fail. */
if ((flags & WOLFSSL_LOAD_FLAG_IGNORE_ERR) ||
((flags & WOLFSSL_LOAD_FLAG_PEM_CA_ONLY) &&
(ret == 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");
/* Add to fail count. */
(*failCount)++;
}
}
else {
#if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS)
/* Try loading as a trusted peer certificate. */
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
/* Add to success count. */
(*successCount)++;
}
return ret;
}
/* Load PEM formatted CA files from a path.
*
* @param [in, out] ctx SSL context object.
* @param [in] path Path to directory to read.
* @param [in] flags Flags representing options for loading.
* @param [in] verify How to verify a certificate.
* @param [in] successCount Number of files successfully loaded.
* @return 1 on success.
* @return 0 on failure.
* @return MEMORY_E when dynamic memory allocation fails.
*/
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;
#ifdef WOLFSSL_SMALL_STACK
ReadDirCtx* readCtx;
#else
ReadDirCtx readCtx[1];
#endif
#ifdef WOLFSSL_SMALL_STACK
/* Allocate memory for directory reading context. */
readCtx = (ReadDirCtx*)XMALLOC(sizeof(ReadDirCtx), ctx->heap,
DYNAMIC_TYPE_DIRCTX);
if (readCtx == NULL) {
ret = MEMORY_E;
}
#endif
if (ret == 1) {
/* Get name of first file in path. */
fileRet = wc_ReadDirFirst(readCtx, path, &name);
/* While getting filename doesn't fail and name returned, process file.
*/
while ((fileRet == 0) && (name != NULL)) {
WOLFSSL_MSG(name);
/* Load file. */
ret = wolfssl_ctx_load_path_file(ctx, name, verify, (int)flags,
&failCount, &successCount);
/* Get next filenmae. */
fileRet = wc_ReadDirNext(readCtx, path, &name);
}
/* Cleanup directory reading context. */
wc_ReadDirClose(readCtx);
/* When not WOLFSSL_QT, ret is always overwritten. */
(void)ret;
/* Return real directory read failure error codes. */
if (fileRet != WC_READDIR_NOFILE) {
ret = fileRet;
#if defined(WOLFSSL_QT) || defined(WOLFSSL_IGNORE_BAD_CERT_PATH)
/* Ignore bad path error when flag set. */
if ((ret == BAD_PATH_ERROR) &&
(flags & WOLFSSL_LOAD_FLAG_IGNORE_BAD_PATH_ERR)) {
/* QSslSocket always loads certs in system folder
* when it is initialized.
* Compliant with OpenSSL when flag set.
*/
ret = 1;
}
else {
/* qssl socket wants to know errors. */
WOLFSSL_ERROR(ret);
}
#endif
}
/* Report failure if no files successfully loaded or there were
* failures. */
else if ((successCount == 0) || (failCount > 0)) {
/* Use existing error code if exists. */
#if defined(WOLFSSL_QT)
/* Compliant with OpenSSL when flag set. */
if (!(flags & WOLFSSL_LOAD_FLAG_IGNORE_ZEROFILE))
#endif
{
/* Return 0 when no files loaded. */
ret = 0;
}
}
else {
/* We loaded something so it is a success. */
ret = 1;
}
#ifdef WOLFSSL_SMALL_STACK
/* Dispose of dynamically allocated memory. */
XFREE(readCtx, ctx->heap, DYNAMIC_TYPE_DIRCTX);
#endif
}
return ret;
}
#endif
/* Load a file and/or files in path
*
* No c_rehash.
*
* @param [in, out] ctx SSL context object.
* @param [in] file Name of file to load. May be NULL.
* @param [in] path Path to directory containing PEM CA files.
* May be NULL.
* @param [in] flags Flags representing options for loading.
* @return 1 on success.
* @return 0 on failure.
* @return NOT_COMPILED_IN when directory reading not supported and path is
* not NULL.
* @return Other negative on error.
*/
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");
/* Validate parameters. */
if ((ctx == NULL) || ((file == NULL) && (path == NULL))) {
ret = 0;
}
if (ret == 1) {
/* Get setting on how to verify certificates. */
verify = GET_VERIFY_SETTING_CTX(ctx);
/* Overwrite setting when flag set. */
if (flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) {
verify = VERIFY_SKIP_DATE;
}
if (file != NULL) {
/* Load the PEM formatted CA file. */
ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CA_TYPE, NULL, 0,
NULL, verify);
#ifndef NO_WOLFSSL_DIR
if (ret == 1) {
/* Include success in overall count. */
successCount++;
}
#endif
#if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS)
/* Load CA as a trusted peer certificate. */
ret = wolfSSL_CTX_trust_peer_cert(ctx, file, WOLFSSL_FILETYPE_PEM);
if (ret != 1) {
WOLFSSL_MSG("wolfSSL_CTX_trust_peer_cert error");
}
#endif
}
}
if ((ret == 1) && (path != NULL)) {
#ifndef NO_WOLFSSL_DIR
/* Load CA files form path. */
ret = wolfssl_ctx_load_path(ctx, path, flags, verify, successCount);
#else
/* Loading a path not supported. */
ret = NOT_COMPILED_IN;
(void)flags;
#endif
}
return ret;
}
/* Load a file and/or files in path
*
* No c_rehash.
*
* @param [in, out] ctx SSL context object.
* @param [in] file Name of file to load. May be NULL.
* @param [in] path Path to directory containing PEM CA files.
* May be NULL.
* @return 1 on success.
* @return 0 on failure.
*/
WOLFSSL_ABI
int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
const char* path)
{
/* Load using default flags/options. */
int ret = wolfSSL_CTX_load_verify_locations_ex(ctx, file, path,
WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS);
/* Return 1 on success or 0 on failure. */
return WS_RETURN_CODE(ret, 0);
}
#ifdef WOLFSSL_SYS_CA_CERTS
#ifdef USE_WINDOWS_API
/* Load CA certificate from Windows store.
*
* Assumes loaded is 0.
*
* @param [in, out] ctx SSL context object.
* @param [out] loaded Whether CA certificates were loaded.
* @return 1 on success.
* @return 0 on failure.
*/
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)) == 1) {
/*
* Set "loaded" as long as we've loaded one CA
* cert.
*/
*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)
/* Manually obtains certificates from the system trust store and loads them
* directly into wolfSSL "the old way".
*
* As of MacOS 14.0 we are still able to use this method to access system
* certificates. Accessibility of this API is indicated by the presence of the
* Security/SecTrustSettings.h header. In the likely event that Apple removes
* access to this API on Macs, this function should be removed and the
* DoAppleNativeCertValidation() routine should be used for all devices.
*
* Assumes loaded is 0.
*
* @param [in, out] ctx SSL context object.
* @param [out] loaded Whether CA certificates were loaded.
* @return 1 on success.
* @return 0 on failure.
*/
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)) == 1) {
/*
* Set "loaded" as long as we've loaded one CA
* cert.
*/
*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 /* defined(HAVE_SECURITY_SECTRUSTSETTINGS_H) */
#else
/* Potential system CA certs directories on Linux/Unix distros. */
static const char* systemCaDirs[] = {
#if defined(__ANDROID__) || defined(ANDROID)
"/system/etc/security/cacerts" /* Android */
#else
"/etc/ssl/certs", /* Debian, Ubuntu, Gentoo, others */
"/etc/pki/ca-trust/source/anchors", /* Fedora, RHEL */
"/etc/pki/tls/certs" /* Older RHEL */
#endif
};
/* Get CA directory list.
*
* @param [out] num Number of CA directories.
* @return CA directory list.
* @return NULL when num is NULL.
*/
const char** wolfSSL_get_system_CA_dirs(word32* num)
{
const char** ret;
/* Validate parameters. */
if (num == NULL) {
ret = NULL;
}
else {
ret = systemCaDirs;
*num = sizeof(systemCaDirs)/sizeof(*systemCaDirs);
}
return ret;
}
/* Load CA certificate from default system directories.
*
* Assumes loaded is 0.
*
* @param [in, out] ctx SSL context object.
* @param [out] loaded Whether CA certificates were loaded.
* @return 1 on success.
* @return 0 on failure.
*/
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]);
/*
* We want to keep trying to load more CA certs even if one cert in
* the directory is bad and can't be used (e.g. if one is expired),
* so we use WOLFSSL_LOAD_FLAG_IGNORE_ERR.
*/
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;
/* Stop searching after we've loaded one directory. */
break;
}
}
return ret;
}
#endif
/* Load CA certificates from system defined locations.
*
* @param [in, out] ctx SSL context object.
* @return 1 on success.
* @return 0 on failure.
* @return WOLFSSL_BAD_PATH when no error but no certificates loaded.
*/
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)
/* As of MacOS 14.0 we are still able to access system certificates and
* load them manually into wolfSSL "the old way". Accessibility of this API
* is indicated by the presence of the Security/SecTrustSettings.h header */
ret = LoadSystemCaCertsMac(ctx, &loaded);
#elif defined(WOLFSSL_APPLE_NATIVE_CERT_VALIDATION)
/* For other Apple devices, Apple has removed the ability to obtain
* certificates from the trust store, so we can't use wolfSSL's built-in
* certificate validation mechanisms anymore. We instead must call into the
* Security Framework APIs to authenticate peer certificates when received.
* (see src/internal.c:DoAppleNativeCertValidation()).
* Thus, there is no CA "loading" required, but to keep behavior consistent
* with the current API (not using system CA certs unless this function has
* been called), we simply set a flag indicating that the new apple trust
* verification routine should be used later */
ctx->doAppleNativeCertValidationFlag = 1;
ret = 1;
loaded = 1;
#if FIPS_VERSION_GE(2,0) /* Gate back to cert 3389 FIPS modules */
#warning "Cryptographic operations may occur outside the FIPS module boundary" \
"Please review FIPS claims for cryptography on this Apple device"
#endif /* FIPS_VERSION_GE(2,0) */
#else
/* HAVE_SECURITY_SECXXX_H macros are set by autotools or CMake when searching
* system for the required SDK headers. If building with user_settings.h, you
* will need to manually define WOLFSSL_APPLE_NATIVE_CERT_VALIDATION
* and ensure the appropriate Security.framework headers and libraries are
* visible to your compiler */
#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 we didn't fail but didn't load then we error out. */
if ((ret == 1) && (!loaded)) {
ret = WOLFSSL_BAD_PATH;
}
WOLFSSL_LEAVE("wolfSSL_CTX_load_system_CA_certs", ret);
return ret;
}
#endif /* WOLFSSL_SYS_CA_CERTS */
#ifdef WOLFSSL_TRUST_PEER_CERT
/* Load a trusted peer certificate into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] file Name of peer certificate file.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 when ctx or file is NULL.
*/
int wolfSSL_CTX_trust_peer_cert(WOLFSSL_CTX* ctx, const char* file, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_trust_peer_cert");
/* Validate parameters. */
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;
}
/* Load a trusted peer certificate into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] file Name of peer certificate file.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 when ssl or file is NULL.
*/
int wolfSSL_trust_peer_cert(WOLFSSL* ssl, const char* file, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_trust_peer_cert");
/* Validate parameters. */
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 /* WOLFSSL_TRUST_PEER_CERT */
#ifdef WOLFSSL_DER_LOAD
/* Load a CA certificate into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] file Name of peer certificate file.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
*/
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");
/* Validate parameters. */
if ((ctx == NULL) || (file == NULL)) {
ret = 0;
}
else {
ret = ProcessFile(ctx, file, format, CA_TYPE, NULL, 0, NULL,
GET_VERIFY_SETTING_CTX(ctx));
}
/* Return 1 on success or 0 on failure. */
return WS_RC(ret);
}
#endif /* WOLFSSL_DER_LOAD */
/* Load a user certificate into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] file Name of user certificate file.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
*/
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 1 on success or 0 on failure. */
return WS_RC(ret);
}
/* Load a private key into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] file Name of private key file.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
*/
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 1 on success or 0 on failure. */
return WS_RC(ret);
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
/* Load an alternative private key into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] file Name of private key file.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
*/
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 1 on success or 0 on failure. */
return WS_RC(ret);
}
#endif /* WOLFSSL_DUAL_ALG_CERTS */
/* Load a PEM certificate chain into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] file Name of PEM certificate chain file.
* @return 1 on success.
* @return 0 on failure.
*/
WOLFSSL_ABI
int wolfSSL_CTX_use_certificate_chain_file(WOLFSSL_CTX* ctx, const char* file)
{
int ret;
/* process up to MAX_CHAIN_DEPTH plus subject cert */
WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file");
ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, NULL, 1, NULL,
GET_VERIFY_SETTING_CTX(ctx));
/* Return 1 on success or 0 on failure. */
return WS_RC(ret);
}
/* Load certificate chain into SSL context.
*
* Processes up to MAX_CHAIN_DEPTH plus subject cert.
*
* @param [in, out] ctx SSL context object.
* @param [in] file Name of private key file.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
*/
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 1 on success or 0 on failure. */
return WS_RC(ret);
}
#endif /* NO_FILESYSTEM */
#ifdef OPENSSL_EXTRA
/* Load a private key into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] pkey EVP private key.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_use_PrivateKey(WOLFSSL* ssl, WOLFSSL_EVP_PKEY* pkey)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_PrivateKey");
/* Validate parameters. */
if ((ssl == NULL) || (pkey == NULL)) {
ret = 0;
}
else {
/* Get DER encoded key data from EVP private key. */
ret = wolfSSL_use_PrivateKey_buffer(ssl, (unsigned char*)pkey->pkey.ptr,
pkey->pkey_sz, WOLFSSL_FILETYPE_ASN1);
}
return ret;
}
/* Load a DER encoded private key in a buffer into SSL.
*
* @param [in] pri Indicates type of private key. Ignored.
* @param [in, out] ssl SSL object.
* @param [in] der Buffer holding DER encoded private key.
* @param [in] derSz Size of data in bytes.
* @return 1 on success.
* @return 0 on failure.
*/
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;
/* Validate parameters. */
if ((ssl == NULL) || (der == NULL)) {
ret = 0;
}
else {
ret = wolfSSL_use_PrivateKey_buffer(ssl, der, derSz,
WOLFSSL_FILETYPE_ASN1);
}
return ret;
}
/* Load a DER encoded private key in a buffer into SSL context.
*
* @param [in] pri Indicates type of private key. Ignored.
* @param [in, out] ctx SSL context object.
* @param [in] der Buffer holding DER encoded private key.
* @param [in] derSz Size of data in bytes.
* @return 1 on success.
* @return 0 on failure.
*/
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;
/* Validate parameters. */
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
/* Load a DER encoded RSA private key in a buffer into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] der Buffer holding DER encoded RSA private key.
* @param [in] derSz Size of data in bytes.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_use_RSAPrivateKey_ASN1(WOLFSSL* ssl, unsigned char* der, long derSz)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_RSAPrivateKey_ASN1");
/* Validate parameters. */
if ((ssl == NULL) || (der == NULL)) {
ret = 0;
}
else {
ret = wolfSSL_use_PrivateKey_buffer(ssl, der, derSz,
WOLFSSL_FILETYPE_ASN1);
}
return ret;
}
#endif
/* Load a certificate into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] x509 X509 certificate object.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_use_certificate(WOLFSSL* ssl, WOLFSSL_X509* x509)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_certificate");
/* Validate parameters. */
if ((ssl == NULL) || (x509 == NULL) || (x509->derCert == NULL)) {
ret = 0;
}
else {
long idx = 0;
/* Get DER encoded certificate data from X509 object. */
ret = ProcessBuffer(NULL, x509->derCert->buffer, x509->derCert->length,
WOLFSSL_FILETYPE_ASN1, CERT_TYPE, ssl, &idx, 0,
GET_VERIFY_SETTING_SSL(ssl));
}
/* Return 1 on success or 0 on failure. */
return WS_RC(ret);
}
#endif /* OPENSSL_EXTRA */
/* Load a DER encoded certificate in a buffer into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] der Buffer holding DER encoded certificate.
* @param [in] derSz Size of data in bytes.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_use_certificate_ASN1(WOLFSSL* ssl, const unsigned char* der,
int derSz)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_certificate_ASN1");
/* Validate parameters. */
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));
}
/* Return 1 on success or 0 on failure. */
return WS_RC(ret);
}
#ifndef NO_FILESYSTEM
/* Load a certificate from a file into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] file Name of file.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
* @return BAD_FUNC_ARG when ssl is NULL.
*/
WOLFSSL_ABI
int wolfSSL_use_certificate_file(WOLFSSL* ssl, const char* file, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_certificate_file");
/* Validate parameters. */
if (ssl == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 0, NULL,
GET_VERIFY_SETTING_SSL(ssl));
/* Return 1 on success or 0 on failure. */
ret = WS_RC(ret);
}
return ret;
}
/* Load a private key from a file into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] file Name of file.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
* @return BAD_FUNC_ARG when ssl is NULL.
*/
WOLFSSL_ABI
int wolfSSL_use_PrivateKey_file(WOLFSSL* ssl, const char* file, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_PrivateKey_file");
/* Validate parameters. */
if (ssl == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = ProcessFile(ssl->ctx, file, format, PRIVATEKEY_TYPE, ssl, 0, NULL,
GET_VERIFY_SETTING_SSL(ssl));
/* Return 1 on success or 0 on failure. */
ret = WS_RC(ret);
}
return ret;
}
/* Load a PEM encoded certificate chain from a file into SSL.
*
* Process up to MAX_CHAIN_DEPTH plus subject cert.
*
* @param [in, out] ssl SSL object.
* @param [in] file Name of file.
* @return 1 on success.
* @return 0 on failure.
* @return BAD_FUNC_ARG when ssl is NULL.
*/
WOLFSSL_ABI
int wolfSSL_use_certificate_chain_file(WOLFSSL* ssl, const char* file)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file");
/* Validate parameters. */
if (ssl == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = ProcessFile(ssl->ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, ssl,
1, NULL, GET_VERIFY_SETTING_SSL(ssl));
/* Return 1 on success or 0 on failure. */
ret = WS_RC(ret);
}
return ret;
}
/* Load a certificate chain from a file into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] file Name of file.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
* @return BAD_FUNC_ARG when ssl is NULL.
*/
int wolfSSL_use_certificate_chain_file_format(WOLFSSL* ssl, const char* file,
int format)
{
int ret;
/* process up to MAX_CHAIN_DEPTH plus subject cert */
WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file_format");
/* Validate parameters. */
if (ssl == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 1, NULL,
GET_VERIFY_SETTING_SSL(ssl));
/* Return 1 on success or 0 on failure. */
ret = WS_RC(ret);
}
return ret;
}
#endif /* !NO_FILESYSTEM */
#ifdef OPENSSL_EXTRA
#ifndef NO_FILESYSTEM
/* Load an RSA private key from a file into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] file Name of file.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
*/
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);
}
/* Load an RSA private key from a file into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] file Name of file.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
* @return BAD_FUNC_ARG when ssl is NULL.
*/
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 /* NO_FILESYSTEM */
#endif /* OPENSSL_EXTRA */
/* Load a buffer of certificate/s into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] in Buffer holding certificate or private key.
* @param [in] sz Length of data in buffer in bytes.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @param [in] userChain Whether file contains chain of certificates.
* @param [in] flags Flags representing options for loading.
* @return 1 on success.
* @return 0 on failure.
* @return Negative on error.
*/
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");
/* Get setting on how to verify certificates. */
verify = GET_VERIFY_SETTING_CTX(ctx);
/* Overwrite setting when flag set. */
if (flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) {
verify = VERIFY_SKIP_DATE;
}
/* When PEM, treat as certificate chain of CA certificates. */
if (format == WOLFSSL_FILETYPE_PEM) {
ret = ProcessChainBuffer(ctx, NULL, in, sz, CA_TYPE, verify);
}
/* When DER, load the CA certificate. */
else {
ret = ProcessBuffer(ctx, in, sz, format, CA_TYPE, NULL, NULL,
userChain, verify);
}
#if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS)
if (ret == 1) {
/* Load certificate/s as trusted peer certificate. */
ret = wolfSSL_CTX_trust_peer_buffer(ctx, in, sz, format);
}
#endif
WOLFSSL_LEAVE("wolfSSL_CTX_load_verify_buffer_ex", ret);
return ret;
}
/* Load a buffer of certificate/s into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] in Buffer holding certificate or private key.
* @param [in] sz Length of data in buffer in bytes.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
* @return Negative on error.
*/
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);
}
/* Load a buffer of certificate chain into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] in Buffer holding certificate chain.
* @param [in] sz Length of data in buffer in bytes.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
* @return Negative on error.
*/
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
/* Load a buffer of certificate/s into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] in Buffer holding certificate/s.
* @param [in] sz Length of data in buffer in bytes.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
* @return BAD_FUNC_ARG when ctx or in is NULL, or sz is less than zero.
*/
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");
/* Validate parameters. */
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
/* When PEM, treat as certificate chain of trusted peer certificates. */
if (format == WOLFSSL_FILETYPE_PEM) {
ret = ProcessChainBuffer(ctx, NULL, in, sz, TRUSTED_PEER_TYPE,
verify);
}
/* When DER, load the trusted peer certificate. */
else {
ret = ProcessBuffer(ctx, in, sz, format, TRUSTED_PEER_TYPE, NULL,
NULL, 0, verify);
}
}
return ret;
}
#endif /* WOLFSSL_TRUST_PEER_CERT */
/* Load a certificate in a buffer into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] in Buffer holding certificate.
* @param [in] sz Size of data in bytes.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
* @return Negative on error.
*/
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));
WOLFSSL_LEAVE("wolfSSL_CTX_use_certificate_buffer", ret);
return ret;
}
/* Load a private key in a buffer into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] in Buffer holding private key.
* @param [in] sz Size of data in bytes.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
* @return Negative on error.
*/
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));
#ifdef WOLFSSL_DUAL_ALG_CERTS
if ((ret == 1) && (consumed < sz)) {
/* When support for dual algorithm certificates is enabled, the
* buffer may contain both the primary and the alternative
* private key. Hence, we have to parse both of them.
*/
ret = ProcessBuffer(ctx, in + consumed, sz - consumed, format,
ALT_PRIVATEKEY_TYPE, NULL, NULL, 0, GET_VERIFY_SETTING_CTX(ctx));
}
#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));
WOLFSSL_LEAVE("wolfSSL_CTX_use_AltPrivateKey_buffer", ret);
return ret;
}
#endif /* WOLFSSL_DUAL_ALG_CERTS */
#ifdef WOLF_PRIVATE_KEY_ID
/* Load the id of a private key into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] id Buffer holding id.
* @param [in] sz Size of data in bytes.
* @param [in] devId Device identifier.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_CTX_use_PrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id,
long sz, int devId)
{
int ret = 1;
/* Dispose of old private key and allocate and copy in id. */
FreeDer(&ctx->privateKey);
if (AllocCopyDer(&ctx->privateKey, id, (word32)sz, PRIVATEKEY_TYPE,
ctx->heap) != 0) {
ret = 0;
}
if (ret == 1) {
/* Private key is an id. */
ctx->privateKeyId = 1;
ctx->privateKeyLabel = 0;
/* Set private key device id to be one passed in or for SSL context. */
if (devId != INVALID_DEVID) {
ctx->privateKeyDevId = devId;
}
else {
ctx->privateKeyDevId = ctx->devId;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
/* Set the ID for the alternative key, too. User can still override that
* afterwards. */
ret = wolfSSL_CTX_use_AltPrivateKey_Id(ctx, id, sz, devId);
#endif
}
return ret;
}
/* Load the id of a private key into SSL context and set key size.
*
* @param [in, out] ctx SSL context object.
* @param [in] id Buffer holding id.
* @param [in] sz Size of data in bytes.
* @param [in] devId Device identifier.
* @param [in] keySz Size of key.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_CTX_use_PrivateKey_id(WOLFSSL_CTX* ctx, const unsigned char* id,
long sz, int devId, long keySz)
{
int ret = wolfSSL_CTX_use_PrivateKey_Id(ctx, id, sz, devId);
if (ret == 1) {
/* Set the key size which normally is calculated during decoding. */
ctx->privateKeySz = (int)keySz;
}
return ret;
}
/* Load the label name of a private key into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] label Buffer holding label.
* @param [in] devId Device identifier.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_CTX_use_PrivateKey_Label(WOLFSSL_CTX* ctx, const char* label,
int devId)
{
int ret = 1;
word32 sz = (word32)XSTRLEN(label) + 1;
/* Dispose of old private key and allocate and copy in label. */
FreeDer(&ctx->privateKey);
if (AllocCopyDer(&ctx->privateKey, (const byte*)label, (word32)sz,
PRIVATEKEY_TYPE, ctx->heap) != 0) {
ret = 0;
}
if (ret == 1) {
/* Private key is a label. */
ctx->privateKeyId = 0;
ctx->privateKeyLabel = 1;
/* Set private key device id to be one passed in or for SSL context. */
if (devId != INVALID_DEVID) {
ctx->privateKeyDevId = devId;
}
else {
ctx->privateKeyDevId = ctx->devId;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
/* Set the ID for the alternative key, too. User can still override that
* afterwards. */
ret = wolfSSL_CTX_use_AltPrivateKey_Label(ctx, label, devId);
#endif
}
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;
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;
}
}
return ret;
}
int wolfSSL_CTX_use_AltPrivateKey_id(WOLFSSL_CTX* ctx, const unsigned char* id,
long sz, int devId, long keySz)
{
int ret = wolfSSL_CTX_use_AltPrivateKey_Id(ctx, id, sz, devId);
if (ret == 1) {
ctx->altPrivateKeySz = (word32)keySz;
}
return ret;
}
int wolfSSL_CTX_use_AltPrivateKey_Label(WOLFSSL_CTX* ctx, const char* label,
int devId)
{
int ret = 1;
word32 sz;
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;
}
}
return ret;
}
#endif /* WOLFSSL_DUAL_ALG_CERTS */
#endif /* WOLF_PRIVATE_KEY_ID */
/* Load a certificate chain in a buffer into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] in Buffer holding DER encoded certificate chain.
* @param [in] sz Size of data in bytes.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
* @return Negative on error.
*/
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));
}
/* Load a PEM encoded certificate chain in a buffer into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] in Buffer holding DER encoded certificate chain.
* @param [in] sz Size of data in bytes.
* @return 1 on success.
* @return 0 on failure.
* @return Negative on error.
*/
int wolfSSL_CTX_use_certificate_chain_buffer(WOLFSSL_CTX* ctx,
const unsigned char* in, long sz)
{
return wolfSSL_CTX_use_certificate_chain_buffer_format(ctx, in, sz,
WOLFSSL_FILETYPE_PEM);
}
/* Load a user certificate in a buffer into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] in Buffer holding user certificate.
* @param [in] sz Size of data in bytes.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
* @return BAD_FUNC_ARG when ssl is NULL.
*/
int wolfSSL_use_certificate_buffer(WOLFSSL* ssl, const unsigned char* in,
long sz, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_use_certificate_buffer");
/* Validate parameters. */
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));
}
return ret;
}
/* Load a private key in a buffer into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] in Buffer holding private key.
* @param [in] sz Size of data in bytes.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
* @return BAD_FUNC_ARG when ssl is NULL.
*/
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");
/* Validate parameters. */
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));
#ifdef WOLFSSL_DUAL_ALG_CERTS
if ((ret == 1) && (consumed < sz)) {
/* When support for dual algorithm certificates is enabled, the
* buffer may contain both the primary and the alternative
* private key. Hence, we have to parse both of them.
*/
ret = ProcessBuffer(ssl->ctx, in + consumed, sz - consumed, format,
ALT_PRIVATEKEY_TYPE, ssl, NULL, 0, GET_VERIFY_SETTING_SSL(ssl));
}
#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));
WOLFSSL_LEAVE("wolfSSL_use_AltPrivateKey_buffer", ret);
return ret;
}
#endif /* WOLFSSL_DUAL_ALG_CERTS */
#ifdef WOLF_PRIVATE_KEY_ID
/* Load the id of a private key into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] id Buffer holding id.
* @param [in] sz Size of data in bytes.
* @param [in] devId Device identifier.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_use_PrivateKey_Id(WOLFSSL* ssl, const unsigned char* id,
long sz, int devId)
{
int ret = 1;
/* Dispose of old private key if owned and allocate and copy in id. */
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) {
/* Buffer now ours. */
ssl->buffers.weOwnKey = 1;
/* Private key is an id. */
ssl->buffers.keyId = 1;
ssl->buffers.keyLabel = 0;
/* Set private key device id to be one passed in or for SSL. */
if (devId != INVALID_DEVID) {
ssl->buffers.keyDevId = devId;
}
else {
ssl->buffers.keyDevId = ssl->devId;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
/* Set the ID for the alternative key, too. User can still override that
* afterwards. */
ret = wolfSSL_use_AltPrivateKey_Id(ssl, id, sz, devId);
#endif
}
return ret;
}
/* Load the id of a private key into SSL and set key size.
*
* @param [in, out] ssl SSL object.
* @param [in] id Buffer holding id.
* @param [in] sz Size of data in bytes.
* @param [in] devId Device identifier.
* @param [in] keySz Size of key.
* @return 1 on success.
* @return 0 on failure.
*/
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) {
/* Set the key size which normally is calculated during decoding. */
ssl->buffers.keySz = (int)keySz;
}
return ret;
}
/* Load the label name of a private key into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] label Buffer holding label.
* @param [in] devId Device identifier.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_use_PrivateKey_Label(WOLFSSL* ssl, const char* label, int devId)
{
int ret = 1;
word32 sz = (word32)XSTRLEN(label) + 1;
/* Dispose of old private key if owned and allocate and copy in label. */
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) {
/* Buffer now ours. */
ssl->buffers.weOwnKey = 1;
/* Private key is a label. */
ssl->buffers.keyId = 0;
ssl->buffers.keyLabel = 1;
/* Set private key device id to be one passed in or for SSL. */
if (devId != INVALID_DEVID) {
ssl->buffers.keyDevId = devId;
}
else {
ssl->buffers.keyDevId = ssl->devId;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
/* Set the label for the alternative key, too. User can still override
* that afterwards. */
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 /* WOLFSSL_DUAL_ALG_CERTS */
#endif /* WOLF_PRIVATE_KEY_ID */
/* Load a certificate chain in a buffer into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] in Buffer holding DER encoded certificate chain.
* @param [in] sz Size of data in bytes.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
* @return BAD_FUNC_ARG when ssl is NULL.
*/
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");
/* Validate parameters. */
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));
}
return ret;
}
/* Load a PEM encoded certificate chain in a buffer into SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] in Buffer holding DER encoded certificate chain.
* @param [in] sz Size of data in bytes.
* @return 1 on success.
* @return 0 on failure.
* @return Negative on error.
*/
int wolfSSL_use_certificate_chain_buffer(WOLFSSL* ssl, const unsigned char* in,
long sz)
{
return wolfSSL_use_certificate_chain_buffer_format(ssl, in, sz,
WOLFSSL_FILETYPE_PEM);
}
#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \
defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \
defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \
defined(WOLFSSL_HAPROXY)
/* Add certificate to chain.
*
* @param [in, out] chain Buffer holding encoded certificate for TLS.
* @param [in] weOwn Indicates we need to free chain if repleced.
* @param [in] cert Buffer holding DER encoded certificate.
* @param [in] certSz Size of DER encoded certificate in bytes.
* @param [in] heap Dynamic memory allocation hint.
* @return 1 on success.
* @return 0 on failure.
*/
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) {
/* Get length of previous chain. */
len = oldChain->length;
}
/* Allocate DER buffer bug enough to hold old and new certificates. */
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) {
/* Place old chain in new buffer. */
XMEMCPY(newChain->buffer, oldChain->buffer, len);
}
/* Append length and DER encoded certificate. */
c32to24(certSz, newChain->buffer + len);
XMEMCPY(newChain->buffer + len + CERT_HEADER_SZ, cert, certSz);
/* Dispose of old chain if we own it. */
if (weOwn) {
FreeDer(chain);
}
/* Replace chain. */
*chain = newChain;
}
return res;
}
#endif
#ifdef OPENSSL_EXTRA
/* Add a certificate to end of chain sent in TLS handshake.
*
* @param [in, out] ctx SSL context.
* @param [in] der Buffer holding DER encoded certificate.
* @param [in] derSz Size of data in buffer.
* @return 1 on success.
* @return 0 on failure.
*/
static int wolfssl_ctx_add_to_chain(WOLFSSL_CTX* ctx, const byte* der,
int derSz)
{
int res = 1;
int ret;
DerBuffer* derBuffer = NULL;
/* Create a DER buffer from DER encoding. */
ret = AllocCopyDer(&derBuffer, der, (word32)derSz, CERT_TYPE, ctx->heap);
if (ret != 0) {
WOLFSSL_MSG("Memory Error");
res = 0;
}
if (res == 1) {
/* Add a user CA certificate to the certificate manager. */
res = AddCA(ctx->cm, &derBuffer, WOLFSSL_USER_CA,
GET_VERIFY_SETTING_CTX(ctx));
if (res != 1) {
res = 0;
}
}
if (res == 1) {
/* Add chain to DER buffer. */
res = wolfssl_add_to_chain(&ctx->certChain, 1, der, (word32)derSz, ctx->heap);
#ifdef WOLFSSL_TLS13
/* Update count of certificates. */
ctx->certChainCnt++;
#endif
}
return res;
}
/* Add a certificate to chain sent in TLS handshake.
*
* @param [in, out] ctx SSL context.
* @param [in] x509 X509 certificate object.
* @return 1 on success.
* @return 0 on failure.
*/
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");
/* Validate parameters. */
if ((ctx == NULL) || (x509 == NULL)) {
WOLFSSL_MSG("Bad Argument");
ret = 0;
}
if (ret == 1) {
/* Get the DER encoding of the certificate from the X509 object. */
der = wolfSSL_X509_get_der(x509, &derSz);
/* Validate buffer. */
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");
/* Process buffer makes first certificate the leaf. */
ret = ProcessBuffer(ctx, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE,
NULL, NULL, 1, GET_VERIFY_SETTING_CTX(ctx));
if (ret != 1) {
ret = 0;
}
}
else if (ret == 1) {
/* Add certificate to existing chain. */
ret = wolfssl_ctx_add_to_chain(ctx, der, derSz);
}
if (ret == 1) {
/* On success WOLFSSL_X509 memory is responsibility of SSL context. */
wolfSSL_X509_free(x509);
}
WOLFSSL_LEAVE("wolfSSL_CTX_add_extra_chain_cert", ret);
return ret;
}
#endif /* OPENSSL_EXTRA */
#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \
defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \
defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \
defined(WOLFSSL_HAPROXY)
/* Load a certificate into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] x509 X509 certificate object.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_CTX_use_certificate(WOLFSSL_CTX *ctx, WOLFSSL_X509 *x)
{
int res = 1;
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_use_certificate");
/* Validate parameters. */
if ((ctx == NULL) || (x == NULL) || (x->derCert == NULL)) {
WOLFSSL_MSG("Bad parameter");
res = 0;
}
if (res == 1) {
/* Replace certificate buffer with one holding the new certificate. */
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) {
/* Dispose of our certificate if it is ours. */
if ((ctx->ourCert != NULL) && ctx->ownOurCert) {
wolfSSL_X509_free(ctx->ourCert);
}
#ifndef WOLFSSL_X509_STORE_CERTS
/* Keep a reference to the new certificate. */
ctx->ourCert = x;
if (wolfSSL_X509_up_ref(x) != 1) {
res = 0;
}
#else
/* Keep a copy of the new certificate. */
ctx->ourCert = wolfSSL_X509_d2i_ex(NULL, x->derCert->buffer,
x->derCert->length, ctx->heap);
if (ctx->ourCert == NULL) {
res = 0;
}
#endif
/* Now own our certificate. */
ctx->ownOurCert = 1;
}
#endif
if (res == 1) {
/* Set have options based on public key OID. */
wolfssl_set_have_from_key_oid(ctx, NULL, x->pubKeyOID);
}
return res;
}
/* Add the certificate to the chain in the SSL context and own the X509 object.
*
* @param [in, out] ctx SSL context object.
* @param [in] x509 X509 certificate object.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_CTX_add0_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_add0_chain_cert");
/* Add certificate to chain and copy or up reference it. */
ret = wolfSSL_CTX_add1_chain_cert(ctx, x509);
if (ret == 1) {
/* Down reference or free original now as we own certificate. */
wolfSSL_X509_free(x509);
}
return ret;
}
/* Add the certificate to the chain in the SSL context.
*
* X509 object copied or up referenced.
*
* @param [in, out] ctx SSL context object.
* @param [in] x509 X509 certificate object.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_CTX_add1_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_CTX_add1_chain_cert");
/* Validate parameters. */
if ((ctx == NULL) || (x509 == NULL) || (x509->derCert == NULL)) {
ret = 0;
}
/* Check if we already have set a certificate. */
if ((ret == 1) && (ctx->certificate == NULL)) {
/* Use the certificate. */
ret = wolfSSL_CTX_use_certificate(ctx, x509);
}
/* Increate reference count as we will store it. */
else if ((ret == 1) && ((ret = wolfSSL_X509_up_ref(x509)) == 1)) {
/* Load the DER encoding. */
ret = wolfSSL_CTX_load_verify_buffer(ctx, x509->derCert->buffer,
x509->derCert->length, WOLFSSL_FILETYPE_ASN1);
if (ret == 1) {
/* Add DER encoding to chain. */
ret = wolfssl_add_to_chain(&ctx->certChain, 1,
x509->derCert->buffer, x509->derCert->length, ctx->heap);
}
/* Store cert in stack to free it later. */
if ((ret == 1) && (ctx->x509Chain == NULL)) {
/* Create a stack for certificates. */
ctx->x509Chain = wolfSSL_sk_X509_new_null();
if (ctx->x509Chain == NULL) {
WOLFSSL_MSG("wolfSSL_sk_X509_new_null error");
ret = 0;
}
}
if (ret == 1) {
/* Push the X509 object onto stack. */
ret = wolfSSL_sk_X509_push(ctx->x509Chain, x509);
}
if (ret != 1) {
/* Decrease reference count on error as we didn't store it. */
wolfSSL_X509_free(x509);
}
}
return WS_RC(ret);
}
#ifdef KEEP_OUR_CERT
/* Add the certificate to the chain in the SSL and own the X509 object.
*
* @param [in, out] ssl SSL object.
* @param [in] x509 X509 certificate object.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_add0_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_add0_chain_cert");
/* Validate parameters. */
if ((ssl == NULL) || (ssl->ctx == NULL) || (x509 == NULL) ||
(x509->derCert == NULL)) {
ret = 0;
}
/* Check if we already have set a certificate. */
if ((ret == 1) && (ssl->buffers.certificate == NULL)) {
/* Use the certificate. */
ret = wolfSSL_use_certificate(ssl, x509);
if (ret == 1) {
/* Dispose of old certificate if we own it. */
if (ssl->buffers.weOwnCert) {
wolfSSL_X509_free(ssl->ourCert);
}
/* Store cert to free it later. */
ssl->ourCert = x509;
ssl->buffers.weOwnCert = 1;
}
}
else if (ret == 1) {
/* Add DER encoding to chain. */
ret = wolfssl_add_to_chain(&ssl->buffers.certChain,
ssl->buffers.weOwnCertChain, x509->derCert->buffer,
x509->derCert->length, ssl->heap);
if (ret == 1) {
/* We now own cert chain. */
ssl->buffers.weOwnCertChain = 1;
/* Create a stack to put certificate into. */
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) {
/* Push X509 object onto stack to be freed. */
ret = wolfSSL_sk_X509_push(ssl->ourCertChain, x509);
if (ret != 1) {
/* Free it now on error. */
wolfSSL_X509_free(x509);
}
}
}
return WS_RC(ret);
}
/* Add the certificate to the chain in the SSL.
*
* X509 object is up referenced.
*
* @param [in, out] ssl SSL object.
* @param [in] x509 X509 certificate object.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_add1_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_add1_chain_cert");
/* Validate parameters. */
if ((ssl == NULL) || (ssl->ctx == NULL) || (x509 == NULL) ||
(x509->derCert == NULL)) {
ret = 0;
}
/* Increase reference count on X509 object before adding. */
if ((ret == 1) && ((ret == wolfSSL_X509_up_ref(x509)) == 1)) {
/* Add this to the chain. */
if ((ret = wolfSSL_add0_chain_cert(ssl, x509)) != 1) {
/* Decrease reference count on error as not stored. */
wolfSSL_X509_free(x509);
}
}
return ret;
}
#endif /* KEEP_OUR_CERT */
#endif /* OPENSSL_EXTRA, HAVE_LIGHTY, WOLFSSL_MYSQL_COMPATIBLE, HAVE_STUNNEL,
WOLFSSL_NGINX, HAVE_POCO_LIB, WOLFSSL_HAPROXY */
#ifdef OPENSSL_EXTRA
/* Load a private key into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] pkey EVP private key.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_CTX_use_PrivateKey(WOLFSSL_CTX *ctx, WOLFSSL_EVP_PKEY *pkey)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey");
/* Validate parameters. */
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 EVP_PKEY_RSA:
WOLFSSL_MSG("populating RSA key");
ret = PopulateRSAEvpPkeyDer(pkey);
break;
#endif /* (WOLFSSL_KEY_GEN || OPENSSL_EXTRA) && !NO_RSA */
#if !defined(HAVE_SELFTEST) && (defined(WOLFSSL_KEY_GEN) || \
defined(WOLFSSL_CERT_GEN)) && !defined(NO_DSA)
case EVP_PKEY_DSA:
break;
#endif /* !HAVE_SELFTEST && (WOLFSSL_KEY_GEN || WOLFSSL_CERT_GEN) &&
* !NO_DSA */
#ifdef HAVE_ECC
case EVP_PKEY_EC:
WOLFSSL_MSG("populating ECC key");
ret = ECC_populate_EVP_PKEY(pkey, pkey->ecc);
break;
#endif
default:
ret = 0;
}
}
if (ret == 1) {
/* ptr for WOLFSSL_EVP_PKEY struct is expected to be DER format */
ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx,
(const unsigned char*)pkey->pkey.ptr, pkey->pkey_sz,
SSL_FILETYPE_ASN1);
}
return ret;
}
#endif /* OPENSSL_EXTRA */
#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \
defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT)
/* Load a DER encoded certificate in a buffer into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] der Buffer holding DER encoded certificate.
* @param [in] derSz Size of data in bytes.
* @return 1 on success.
* @return 0 on failure.
*/
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");
/* Validate parameters. */
if ((ctx == NULL) || (der == NULL)) {
ret = 0;
}
/* Load DER encoded cerificate into SSL context. */
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)
/* Load an RSA private key into SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] rsa RSA private key.
* @return 1 on success.
* @return 0 on failure.
* @return BAD_FUNC_ARG when ctx or rsa is NULL.
* @return MEMORY_E when dynamic memory allocation fails.
*/
int wolfSSL_CTX_use_RSAPrivateKey(WOLFSSL_CTX* ctx, WOLFSSL_RSA* rsa)
{
int ret = 1;
int derSize;
unsigned char* der = NULL;
unsigned char* p;
WOLFSSL_ENTER("wolfSSL_CTX_use_RSAPrivateKey");
/* Validate parameters. */
if ((ctx == NULL) || (rsa == NULL)) {
WOLFSSL_MSG("one or more inputs were NULL");
ret = BAD_FUNC_ARG;
}
/* Get DER encoding size. */
if ((ret == 1) && ((derSize = wolfSSL_i2d_RSAPrivateKey(rsa, NULL)) <= 0)) {
ret = 0;
}
if (ret == 1) {
/* Allocate memory to hold DER encoding.. */
der = (unsigned char*)XMALLOC(derSize, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (der == NULL) {
WOLFSSL_MSG("Malloc failure");
ret = MEMORY_E;
}
}
if (ret == 1) {
/* Pointer passed in is modified.. */
p = der;
/* Encode the RSA key as DER into buffer and get size. */
if ((derSize = wolfSSL_i2d_RSAPrivateKey(rsa, &p)) <= 0) {
WOLFSSL_MSG("wolfSSL_i2d_RSAPrivateKey() failure");
ret = 0;
}
}
if (ret == 1) {
/* Load DER encoded cerificate into SSL context. */
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;
}
}
/* Dispos of dynamically allocated data. */
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
#endif /* WOLFSSL_KEY_GEN && !NO_RSA */
#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */
#endif /* !NO_CERTS */
#ifdef OPENSSL_EXTRA
/* Use the default paths to look for CA certificate.
*
* This is an OpenSSL compatibility layer function, but it doesn't mirror
* the exact functionality of its OpenSSL counterpart. We don't support the
* notion of an "OpenSSL directory". This function will attempt to load the
* environment variables SSL_CERT_DIR and SSL_CERT_FILE, if either are
* found, they will be loaded. Otherwise, it will act as a wrapper around
* our native wolfSSL_CTX_load_system_CA_certs function. This function does
* conform to OpenSSL's return value conventions.
*
* @param [in] ctx SSL context object.
* @return 1 on success.
* @return 0 on failure.
* @return WOLFSSL_FATAL_ERROR when using a filesystem is not supported.
*/
int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx)
{
int ret;
#ifdef XGETENV
char* certDir;
char* certFile;
word32 flags;
#elif !defined(WOLFSSL_SYS_CA_CERTS)
(void)ctx;
#endif
WOLFSSL_ENTER("wolfSSL_CTX_set_default_verify_paths");
#ifdef XGETENV
certDir = XGETENV("SSL_CERT_DIR");
certFile = XGETENV("SSL_CERT_FILE");
flags = WOLFSSL_LOAD_FLAG_PEM_CA_ONLY;
if ((certDir != NULL) || (certFile != NULL)) {
if (certDir != NULL) {
/* We want to keep trying to load more CA certs even if one cert in
* the directory is bad and can't be used (e.g. if one is
* expired), so we use WOLFSSL_LOAD_FLAG_IGNORE_ERR.
*/
flags |= WOLFSSL_LOAD_FLAG_IGNORE_ERR;
}
/* Load CA certificates from environment variable locations. */
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)
/* Load the system CA certificates. */
ret = wolfSSL_CTX_load_system_CA_certs(ctx);
if (ret == WOLFSSL_BAD_PATH) {
/* OpenSSL doesn't treat the lack of a system CA cert directory as a
* failure. We do the same here.
*/
ret = 1;
}
#else
/* OpenSSL's implementation of this API does not require loading the
system CA cert directory. Allow skipping this without erroring out. */
ret = 1;
#endif
}
WOLFSSL_LEAVE("wolfSSL_CTX_set_default_verify_paths", ret);
return ret;
}
#endif /* OPENSSL_EXTRA */
#ifndef NO_DH
/* Set the temporary DH parameters against the SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] p Buffer holding prime.
* @param [in] pSz Length of prime in bytes.
* @param [in] g Buffer holding generator.
* @param [in] gSz Length of generator in bytes.
* @return 1 on success.
* @return 0 on failure.
* @return DH_KEY_SIZE_E when the prime is too short or long.
* @return SIDE_ERROR when the SSL is for a client.
*/
static int wolfssl_set_tmp_dh(WOLFSSL* ssl, unsigned char* p, int pSz,
unsigned char* g, int gSz)
{
int ret = 1;
/* Check the size of the prime meets the requirements of the SSL. */
if (((word16)pSz < ssl->options.minDhKeySz) ||
((word16)pSz > ssl->options.maxDhKeySz)) {
ret = DH_KEY_SIZE_E;
}
/* Only able to set DH parameters on server. */
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)
/* New DH parameters not tested for validity. */
ssl->options.dhKeyTested = 0;
/* New DH parameters must be tested for validity before use. */
ssl->options.dhDoKeyTest = 1;
#endif
/* Dispose of old DH parameters if we own it. */
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);
}
/* Assign the buffers and lengths to SSL. */
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;
/* We own the buffers. */
ssl->buffers.weOwnDH = 1;
/* We have a DH parameters to use. */
ssl->options.haveDH = 1;
}
/* Allocate space for cipher suites. */
if ((ret == 1) && (AllocateSuites(ssl) != 0)) {
ret = 0;
}
if (ret == 1) {
/* Reset the cipher suites based on having a DH parameters now. */
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.haveFalconSig,
ssl->options.haveDilithiumSig, ssl->options.useAnon, TRUE,
ssl->options.side);
}
return ret;
}
/* Set the temporary DH parameters against the SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] p Buffer holding prime.
* @param [in] pSz Length of prime in bytes.
* @param [in] g Buffer holding generator.
* @param [in] gSz Length of generator in bytes.
* @return 1 on success.
* @return 0 on failure.
* @return DH_KEY_SIZE_E when the prime is too short or long.
* @return SIDE_ERROR when the SSL is for a client.
* @return MEMORY_E when dynamic memory allocation fails.
*/
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");
/* Validate parameters. */
if ((ssl == NULL) || (p == NULL) || (g == NULL)) {
ret = 0;
}
if (ret == 1) {
/* Allocate buffers for p and g to be assigned into SSL. */
pAlloc = (byte*)XMALLOC(pSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
gAlloc = (byte*)XMALLOC(gSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
if ((pAlloc == NULL) || (gAlloc == NULL)) {
XFREE(pAlloc, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
XFREE(gAlloc, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
ret = MEMORY_E;
}
}
if (ret == 1) {
/* Copy p and g into allocated buffers. */
XMEMCPY(pAlloc, p, pSz);
XMEMCPY(gAlloc, g, gSz);
/* Set the buffers into SSL. */
ret = wolfssl_set_tmp_dh(ssl, pAlloc, pSz, gAlloc, gSz);
}
if (ret != 1) {
/* Free the allocated buffers if not assigned into SSL. */
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)
/* Check the DH parameters is valid.
*
* @param [in] p Buffer holding prime.
* @param [in] pSz Length of prime in bytes.
* @param [in] g Buffer holding generator.
* @param [in] gSz Length of generator in bytes.
* @return 1 on success.
* @return DH_CHECK_PUB_E when p is not a prime.
* @return BAD_FUNC_ARG when p or g is NULL, or pSz or gSz is 0.
* @return MEMORY_E when dynamic memory allocation fails.
*/
static int wolfssl_check_dh_key(unsigned char* p, int pSz, unsigned char* g,
int gSz)
{
WC_RNG rng;
int ret = 0;
#ifndef WOLFSSL_SMALL_STACK
DhKey checkKey[1];
#else
DhKey *checkKey;
#endif
#ifdef WOLFSSL_SMALL_STACK
checkKey = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH);
if (checkKey == NULL) {
ret = MEMORY_E;
}
#endif
/* Initialize a new random number generator. */
if ((ret == 0) && ((ret = wc_InitRng(&rng)) == 0)) {
/* Initialize a DH object. */
if ((ret = wc_InitDhKey(checkKey)) == 0) {
/* Check DH parameters. */
ret = wc_DhSetCheckKey(checkKey, p, (word32)pSz, g, gSz, NULL, 0, 0, &rng);
/* Dispose of DH object. */
wc_FreeDhKey(checkKey);
}
/* Dispose of random number generator. */
wc_FreeRng(&rng);
}
#ifdef WOLFSSL_SMALL_STACK
/* Dispose of dynamically allocated data. */
XFREE(checkKey, NULL, DYNAMIC_TYPE_DH);
#endif
/* Convert wolfCrypt return code to 1 on success and ret on failure. */
return WC_TO_WS_RC(ret);
}
#endif
/* Set the temporary DH parameters against the SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] p Buffer holding prime.
* @param [in] pSz Length of prime in bytes.
* @param [in] g Buffer holding generator.
* @param [in] gSz Length of generator in bytes.
* @return 1 on success.
* @return 0 on failure.
* @return DH_KEY_SIZE_E when the prime is too short or long.
* @return SIDE_ERROR when the SSL is for a client.
* @return BAD_FUNC_ARG when ctx, p or g is NULL.
* @return DH_CHECK_PUB_E when p is not a prime.
* @return MEMORY_E when dynamic memory allocation fails.
*/
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");
/* Check the size of the prime meets the requirements of the SSL context. */
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) {
/* Test DH parameters for validity. */
ret = wolfssl_check_dh_key(p, pSz, g, gSz);
/* Record as whether tested based on result of validity test. */
ctx->dhKeyTested = (ret == 1);
}
#endif
if (ret == 1) {
/* Dispose of old DH parameters. */
XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
/* Assign the buffers and lengths to SSL context. */
ctx->serverDH_P.buffer = p;
ctx->serverDH_G.buffer = g;
ctx->serverDH_P.length = (unsigned int)pSz;
ctx->serverDH_G.length = (unsigned int)gSz;
/* We have a DH parameters to use. */
ctx->haveDH = 1;
}
WOLFSSL_LEAVE("wolfSSL_CTX_SetTmpDH", 0);
return ret;
}
/* Set the temporary DH parameters against the SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] p Buffer holding prime.
* @param [in] pSz Length of prime in bytes.
* @param [in] g Buffer holding generator.
* @param [in] gSz Length of generator in bytes.
* @return 1 on success.
* @return 0 on failure.
* @return DH_KEY_SIZE_E when the prime is too short or long.
* @return SIDE_ERROR when the SSL is for a client.
* @return BAD_FUNC_ARG when ctx, p or g is NULL.
* @return DH_CHECK_PUB_E when p is not a prime.
*/
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;
/* Validate parameters. */
if ((ctx == NULL) || (p == NULL) || (g == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 1) {
/* Allocate buffers for p and g to be assigned into SSL context. */
pAlloc = (byte*)XMALLOC(pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
gAlloc = (byte*)XMALLOC(gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
if ((pAlloc == NULL) || (gAlloc == NULL)) {
XFREE(pAlloc, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
pAlloc = NULL;
XFREE(gAlloc, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
gAlloc = NULL;
ret = MEMORY_E;
}
}
if (ret == 1) {
/* Copy p and g into allocated buffers. */
XMEMCPY(pAlloc, p, pSz);
XMEMCPY(gAlloc, g, gSz);
/* Set the buffers into SSL context. */
ret = wolfssl_ctx_set_tmp_dh(ctx, pAlloc, pSz, gAlloc, gSz);
}
if (ret != 1) {
/* Free the allocated buffers if not assigned into SSL context. */
if (pAlloc)
XFREE(pAlloc, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
if (gAlloc)
XFREE(gAlloc, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
}
return ret;
}
#ifdef OPENSSL_EXTRA
/* Set the temporary DH parameters against the SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] dh DH object.
* @return 1 on success.
* @return 0 on failure.
* @return WOLFSSL_FATAL_ERROR on failure.
* @return BAD_FUNC_ARG when ssl or dh is NULL.
* @return DH_KEY_SIZE_E when the prime is too short or long.
* @return SIDE_ERROR when the SSL is for a client.
*/
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");
/* Validate parameters. */
if ((ssl == NULL) || (dh == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 1) {
/* Get needed size for p and g. */
pSz = wolfSSL_BN_bn2bin(dh->p, NULL);
gSz = wolfSSL_BN_bn2bin(dh->g, NULL);
/* Validate p and g size. */
if ((pSz <= 0) || (gSz <= 0)) {
ret = WOLFSSL_FATAL_ERROR;
}
}
if (ret == 1) {
/* Allocate buffers for p and g to be assigned into SSL. */
p = (byte*)XMALLOC(pSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
g = (byte*)XMALLOC(gSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
if ((p == NULL) || (g == NULL)) {
ret = MEMORY_E;
}
}
if (ret == 1) {
/* Encode p and g and get sizes. */
pSz = wolfSSL_BN_bn2bin(dh->p, p);
gSz = wolfSSL_BN_bn2bin(dh->g, g);
/* Check encoding worked. */
if ((pSz <= 0) || (gSz <= 0)) {
ret = WOLFSSL_FATAL_ERROR;
}
}
if (ret == 1) {
/* Set the buffers into SSL. */
ret = wolfssl_set_tmp_dh(ssl, p, pSz, g, gSz);
}
if (ret != 1) {
/* Free the allocated buffers if not assigned into SSL. */
XFREE(p, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
XFREE(g, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
}
return ret;
}
/* Set the temporary DH parameters object against the SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] dh DH object.
* @return 1 on success.
* @return 0 on failure.
* @return DH_KEY_SIZE_E when the prime is too short or long.
* @return SIDE_ERROR when the SSL is for a client.
* @return BAD_FUNC_ARG when ctx, p or g is NULL.
* @return DH_CHECK_PUB_E when p is not a prime.
*/
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");
/* Validate parameters. */
if ((ctx == NULL) || (dh == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 1) {
/* Get needed size for p and g. */
pSz = wolfSSL_BN_bn2bin(dh->p, NULL);
gSz = wolfSSL_BN_bn2bin(dh->g, NULL);
/* Validate p and g size. */
if ((pSz <= 0) || (gSz <= 0)) {
ret = WOLFSSL_FATAL_ERROR;
}
}
if (ret == 1) {
/* Allocate buffers for p and g to be assigned into SSL. */
p = (byte*)XMALLOC(pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
g = (byte*)XMALLOC(gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
if ((p == NULL) || (g == NULL)) {
ret = MEMORY_E;
}
}
if (ret == 1) {
/* Encode p and g and get sizes. */
pSz = wolfSSL_BN_bn2bin(dh->p, p);
gSz = wolfSSL_BN_bn2bin(dh->g, g);
/* Check encoding worked. */
if ((pSz < 0) && (gSz < 0)) {
ret = WOLFSSL_FATAL_ERROR;
}
}
if (ret == 1) {
/* Set the buffers into SSL context. */
ret = wolfssl_ctx_set_tmp_dh(ctx, p, pSz, g, gSz);
}
if (ret != 1) {
/* Free the allocated buffers if not assigned into SSL. */
XFREE(p, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
XFREE(g, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
}
return ret;
}
#endif /* OPENSSL_EXTRA */
#ifndef NO_CERTS
/* Set the temporary DH parameters against the SSL context or SSL.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] buf Buffer holding encoded DH parameters.
* @param [in] sz Size of encoded DH parameters.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return 0 on failure.
* @return BAD_FUNC_ARG when ctx and ssl NULL or buf is NULL.
* @return NOT_COMPLED_IN when format is PEM but PEM is not supported.
* @return WOLFSSL_BAD_FILETYPE if format is not supported.
*/
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;
/* p and g size to allocate set to maximum valid size. */
word32 pSz = MAX_DH_SIZE;
word32 gSz = MAX_DH_SIZE;
byte* p = NULL;
byte* g = NULL;
void* heap = WOLFSSL_HEAP(ctx, ssl);
/* Validate parameters. */
if (((ctx == NULL) && (ssl == NULL)) || (buf == NULL)) {
res = BAD_FUNC_ARG;
}
/* Check format is supported. */
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
}
/* PemToDer allocates its own DER buffer. */
if ((res == 1) && (format != WOLFSSL_FILETYPE_PEM)) {
/* Create an empty DER buffer. */
ret = AllocDer(&der, 0, DH_PARAM_TYPE, heap);
if (ret == 0) {
/* Assign encoded DH parameters to DER buffer. */
der->buffer = (byte*)buf;
der->length = (word32)sz;
}
else {
res = ret;
}
}
if (res == 1) {
/* Allocate enough memory to p and g to support valid use cases. */
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)) {
/* Convert from PEM to DER. */
/* Try converting DH parameters from PEM to DER. */
ret = PemToDer(buf, sz, DH_PARAM_TYPE, &der, heap, NULL, NULL);
if (ret < 0) {
/* Otherwise, try converting X9.43 format DH parameters. */
ret = PemToDer(buf, sz, X942_PARAM_TYPE, &der, heap, NULL, NULL);
}
#if defined(WOLFSSL_WPAS) && !defined(NO_DSA)
if (ret < 0) {
/* Otherwise, try converting DSA parameters. */
ret = PemToDer(buf, sz, DSA_PARAM_TYPE, &der, heap, NULL, NULL);
}
#endif /* WOLFSSL_WPAS && !NO_DSA */
if (ret < 0) {
/* Return error from conversion. */
res = ret;
}
}
#endif /* WOLFSSL_PEM_TO_DER */
if (res == 1) {
/* Get the p and g from the DER encoded parameters. */
if (wc_DhParamsLoad(der->buffer, der->length, p, &pSz, g, &gSz) < 0) {
res = WOLFSSL_BAD_FILETYPE;
}
else if (ssl != NULL) {
/* Set p and g into SSL. */
res = wolfssl_set_tmp_dh(ssl, p, (int)pSz, g, gSz);
}
else {
/* Set p and g into SSL context. */
res = wolfssl_ctx_set_tmp_dh(ctx, p, (int)pSz, g, gSz);
}
}
/* Dispose of the DER buffer. */
FreeDer(&der);
if (res != 1) {
/* Free the allocated buffers if not assigned into SSL or context. */
XFREE(p, heap, DYNAMIC_TYPE_PUBLIC_KEY);
XFREE(g, heap, DYNAMIC_TYPE_PUBLIC_KEY);
}
return res;
}
/* Set the temporary DH parameters against the SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] buf Buffer holding encoded DH parameters.
* @param [in] sz Size of encoded DH parameters.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return BAD_FUNC_ARG when ssl or buf is NULL.
* @return NOT_COMPLED_IN when format is PEM but PEM is not supported.
* @return WOLFSSL_BAD_FILETYPE if format is not supported.
*/
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);
}
/* Set the temporary DH parameters against the SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] buf Buffer holding encoded DH parameters.
* @param [in] sz Size of encoded DH parameters.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return BAD_FUNC_ARG when ctx or buf is NULL.
* @return NOT_COMPLED_IN when format is PEM but PEM is not supported.
* @return WOLFSSL_BAD_FILETYPE if format is not supported.
*/
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
/* Set the temporary DH parameters file against the SSL context or SSL.
*
* @param [in, out] ctx SSL context object.
* @param [in, out] ssl SSL object.
* @param [in] fname Name of file to load.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return BAD_FUNC_ARG when ctx and ssl NULL or fname is NULL.
* @return NOT_COMPLED_IN when format is PEM but PEM is not supported.
* @return WOLFSSL_BAD_FILETYPE if format is not supported.
*/
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);
/* Setup buffer to hold file contents. */
#ifdef WOLFSSL_SMALL_STACK
static_buffer_init(&dhFile);
#else
static_buffer_init(&dhFile, stackBuffer, FILE_BUFFER_SIZE);
#endif
/* Validate parameters. */
if (((ctx == NULL) && (ssl == NULL)) || (fname == NULL)) {
res = BAD_FUNC_ARG;
}
if (res == 1) {
/* Read file into static buffer. */
ret = wolfssl_read_file_static(fname, &dhFile, heap, DYNAMIC_TYPE_FILE,
&sz);
if (ret != 0) {
res = ret;
}
}
if (res == 1) {
if (ssl != NULL) {
/* Set encoded DH parameters into SSL. */
res = wolfSSL_SetTmpDH_buffer(ssl, dhFile.buffer, sz, format);
}
else {
/* Set encoded DH parameters into SSL context. */
res = wolfSSL_CTX_SetTmpDH_buffer(ctx, dhFile.buffer, sz, format);
}
}
/* Dispose of any dynamically allocated data. */
static_buffer_free(&dhFile, heap, DYNAMIC_TYPE_FILE);
return res;
}
/* Set the temporary DH parameters file against the SSL.
*
* @param [in, out] ssl SSL object.
* @param [in] fname Name of file to load.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return BAD_FUNC_ARG when ssl or fname is NULL.
* @return NOT_COMPLED_IN when format is PEM but PEM is not supported.
* @return WOLFSSL_BAD_FILETYPE if format is not supported.
*/
int wolfSSL_SetTmpDH_file(WOLFSSL* ssl, const char* fname, int format)
{
return ws_ctx_ssl_set_tmp_dh_file(NULL, ssl, fname, format);
}
/* Set the temporary DH parameters file against the SSL context.
*
* @param [in, out] ctx SSL context object.
* @param [in] fname Name of file to load.
* @param [in] format Format of data:
* WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1.
* @return 1 on success.
* @return BAD_FUNC_ARG when ctx or fname is NULL.
* @return NOT_COMPLED_IN when format is PEM but PEM is not supported.
* @return WOLFSSL_BAD_FILETYPE if format is not supported.
*/
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 /* NO_FILESYSTEM */
#endif /* NO_CERTS */
#endif /* !NO_DH */
#endif /* !WOLFSSL_SSL_LOAD_INCLUDED */