mirror of https://github.com/wolfSSL/wolfssl.git
5925 lines
186 KiB
C
5925 lines
186 KiB
C
/* ssl_load.c
|
|
*
|
|
* Copyright (C) 2006-2024 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
|
|
(void)algId;
|
|
ret = NOT_COMPILED_IN;
|
|
#endif
|
|
}
|
|
/* Data in buffer is ASN.1 format - get first SEQ or OCT into der. */
|
|
else {
|
|
/* Get length of SEQ including header. */
|
|
if ((info->consumed = wolfssl_der_length(buff, (int)len)) > 0) {
|
|
ret = 0;
|
|
}
|
|
else {
|
|
ret = ASN_PARSE_E;
|
|
}
|
|
|
|
if (info->consumed > (int)len) {
|
|
ret = ASN_PARSE_E;
|
|
}
|
|
if (ret == 0) {
|
|
ret = AllocCopyDer(der, buff, (word32)info->consumed, type, heap);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* 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");
|
|
|
|
/* Check we haven't consumed all the data. */
|
|
if (info->consumed >= sz) {
|
|
WOLFSSL_MSG("Already consumed data");
|
|
}
|
|
else {
|
|
#ifndef WOLFSSL_SMALL_STACK
|
|
byte stackBuffer[FILE_BUFFER_SIZE];
|
|
#endif
|
|
StaticBuffer chain;
|
|
long consumed = info->consumed;
|
|
word32 idx = 0;
|
|
int gotOne = 0;
|
|
int cnt = 0;
|
|
/* 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 == WC_NO_ERR_TRACE(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_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) || ((*keyFormat == 0) &&
|
|
((der->length == FALCON_LEVEL1_KEY_SIZE) ||
|
|
(der->length == FALCON_LEVEL1_PRV_KEY_SIZE)))) {
|
|
ret = wc_falcon_set_level(key, 1);
|
|
}
|
|
else if ((*keyFormat == FALCON_LEVEL5k) || ((*keyFormat == 0) &&
|
|
((der->length == FALCON_LEVEL5_KEY_SIZE) ||
|
|
(der->length == FALCON_LEVEL5_PRV_KEY_SIZE)))) {
|
|
ret = wc_falcon_set_level(key, 5);
|
|
}
|
|
else {
|
|
wc_falcon_free(key);
|
|
ret = ALGO_ID_E;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* 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);
|
|
}
|
|
else if ((ret == WC_NO_ERR_TRACE(ALGO_ID_E)) && (*keyFormat == 0)) {
|
|
WOLFSSL_MSG("Not a Falcon key");
|
|
/* Format unknown so keep trying. */
|
|
ret = 0;
|
|
}
|
|
|
|
/* Dispose of allocated key. */
|
|
XFREE(key, heap, DYNAMIC_TYPE_FALCON);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#if defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
!defined(WOLFSSL_DILITHIUM_NO_ASN1)
|
|
/* 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;
|
|
word32 idx;
|
|
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) || ((*keyFormat == 0) &&
|
|
((der->length == DILITHIUM_LEVEL2_KEY_SIZE) ||
|
|
(der->length == DILITHIUM_LEVEL2_PRV_KEY_SIZE)))) {
|
|
ret = wc_dilithium_set_level(key, 2);
|
|
}
|
|
else if ((*keyFormat == DILITHIUM_LEVEL3k) || ((*keyFormat == 0) &&
|
|
((der->length == DILITHIUM_LEVEL3_KEY_SIZE) ||
|
|
(der->length == DILITHIUM_LEVEL3_PRV_KEY_SIZE)))) {
|
|
ret = wc_dilithium_set_level(key, 3);
|
|
}
|
|
else if ((*keyFormat == DILITHIUM_LEVEL5k) || ((*keyFormat == 0) &&
|
|
((der->length == DILITHIUM_LEVEL5_KEY_SIZE) ||
|
|
(der->length == DILITHIUM_LEVEL5_PRV_KEY_SIZE)))) {
|
|
ret = wc_dilithium_set_level(key, 5);
|
|
}
|
|
else {
|
|
wc_dilithium_free(key);
|
|
ret = ALGO_ID_E;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Decode as a Dilithium private key. */
|
|
idx = 0;
|
|
ret = wc_Dilithium_PrivateKeyDecode(der->buffer, &idx, key, der->length);
|
|
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);
|
|
}
|
|
else if ((ret == WC_NO_ERR_TRACE(ALGO_ID_E)) && (*keyFormat == 0)) {
|
|
WOLFSSL_MSG("Not a Dilithium key");
|
|
/* Format unknown so keep trying. */
|
|
ret = 0;
|
|
}
|
|
|
|
/* Dispose of allocated key. */
|
|
XFREE(key, heap, DYNAMIC_TYPE_DILITHIUM);
|
|
return ret;
|
|
}
|
|
#endif /* HAVE_DILITHIUM */
|
|
|
|
/* 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_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) && !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
!defined(WOLFSSL_DILITHIUM_NO_ASN1)
|
|
/* 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 */
|
|
|
|
/* 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;
|
|
}
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
if (password != NULL)
|
|
#endif
|
|
{
|
|
/* 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;
|
|
|
|
(void)info;
|
|
(void)format;
|
|
|
|
/* 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) {
|
|
WOLFSSL_EVPerr(0, -WOLFSSL_EVP_R_BAD_DECRYPT_E);
|
|
}
|
|
#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_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 */
|
|
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_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
|
|
default:
|
|
WOLFSSL_MSG("Cert signature not supported");
|
|
break;
|
|
}
|
|
|
|
#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \
|
|
defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || !defined(NO_RSA)
|
|
#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448)
|
|
/* 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
|
|
if ((ctx != NULL) || (ssl != NULL)) {
|
|
wolfssl_set_have_from_key_oid(ctx, ssl, (int)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_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 */
|
|
|
|
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_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 */
|
|
|
|
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 certificate. */
|
|
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 == WC_NO_ERR_TRACE(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 == WC_NO_ERR_TRACE(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 == WC_NO_ERR_TRACE(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 == WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER)))) {
|
|
unsigned long err = 0;
|
|
CLEAR_ASN_NO_PEM_HEADER_ERROR(err);
|
|
#if defined(WOLFSSL_QT)
|
|
ret = 1;
|
|
#endif
|
|
}
|
|
else {
|
|
WOLFSSL_ERROR(ret);
|
|
WOLFSSL_MSG("Load CA file failed, continuing");
|
|
/* 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 filename. */
|
|
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 == WC_NO_ERR_TRACE(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);
|
|
}
|
|
|
|
/* Load a file and/or files in path, with OpenSSL-compatible semantics.
|
|
*
|
|
* 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.
|
|
*/
|
|
int wolfSSL_CTX_load_verify_locations_compat(WOLFSSL_CTX* ctx, const char* file,
|
|
const char* path)
|
|
{
|
|
/* 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), and we
|
|
* want to return success if any were successfully loaded (mimicking
|
|
* OpenSSL SSL_CTX_load_verify_locations() semantics), so we use
|
|
* WOLFSSL_LOAD_FLAG_IGNORE_ERR. OpenSSL (as of v3.3.2) actually
|
|
* returns success even if no certs are loaded (e.g. because the
|
|
* supplied "path" doesn't exist or access is prohibited), and only
|
|
* returns failure if the "file" is non-null and fails to load.
|
|
*
|
|
* Note that if a file is supplied and can't be successfully loaded, the
|
|
* overall call fails and the path is never even evaluated. This is
|
|
* consistent with OpenSSL behavior.
|
|
*/
|
|
|
|
int ret = wolfSSL_CTX_load_verify_locations_ex(ctx, file, path,
|
|
WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS | WOLFSSL_LOAD_FLAG_IGNORE_ERR);
|
|
|
|
/* 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 */
|
|
|
|
#if defined(WOLF_CRYPTO_CB) && !defined(NO_CERTS)
|
|
|
|
static int wolfSSL_CTX_use_certificate_ex(WOLFSSL_CTX* ctx,
|
|
const char *label, const unsigned char *id, int idLen, int devId)
|
|
{
|
|
int ret;
|
|
byte *certData = NULL;
|
|
word32 certDataLen = 0;
|
|
word32 labelLen = 0;
|
|
|
|
WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_ex");
|
|
|
|
if (label != NULL) {
|
|
labelLen = (word32)XSTRLEN(label);
|
|
}
|
|
|
|
ret = wc_CryptoCb_GetCert(devId, (const sword8 *)label,
|
|
labelLen, id, idLen, &certData, &certDataLen, ctx->heap);
|
|
if (ret != 0) {
|
|
ret = WOLFSSL_FAILURE;
|
|
goto exit;
|
|
}
|
|
|
|
ret = ProcessBuffer(ctx, certData, certDataLen, WOLFSSL_FILETYPE_ASN1,
|
|
CERT_TYPE, NULL, NULL, 0, GET_VERIFY_SETTING_CTX(ctx));
|
|
|
|
exit:
|
|
if (certData != NULL) {
|
|
XFREE(certData, ctx->heap, DYNAMIC_TYPE_CERT);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Load the label name of a certificate into the 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_certificate_label(WOLFSSL_CTX* ctx,
|
|
const char *label, int devId)
|
|
{
|
|
if ((ctx == NULL) || (label == NULL)) {
|
|
return WOLFSSL_FAILURE;
|
|
}
|
|
|
|
return wolfSSL_CTX_use_certificate_ex(ctx, label, NULL, 0, devId);
|
|
}
|
|
|
|
/* Load the id of a certificate into SSL context.
|
|
*
|
|
* @param [in, out] ctx SSL context object.
|
|
* @param [in] id Buffer holding id.
|
|
* @param [in] idLen Size of data in bytes.
|
|
* @param [in] devId Device identifier.
|
|
* @return 1 on success.
|
|
* @return 0 on failure.
|
|
*/
|
|
int wolfSSL_CTX_use_certificate_id(WOLFSSL_CTX* ctx,
|
|
const unsigned char *id, int idLen, int devId)
|
|
{
|
|
if ((ctx == NULL) || (id == NULL) || (idLen <= 0)) {
|
|
return WOLFSSL_FAILURE;
|
|
}
|
|
|
|
return wolfSSL_CTX_use_certificate_ex(ctx, NULL, id, idLen, devId);
|
|
}
|
|
|
|
#endif /* if defined(WOLF_CRYPTO_CB) && !defined(NO_CERTS) */
|
|
|
|
/* 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);
|
|
}
|
|
/* Increase 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) > 0
|
|
? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
|
|
}
|
|
|
|
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) || (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) > 0
|
|
? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
|
|
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) || (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 WC_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 WC_EVP_PKEY_DSA:
|
|
break;
|
|
#endif /* !HAVE_SELFTEST && (WOLFSSL_KEY_GEN || WOLFSSL_CERT_GEN) &&
|
|
* !NO_DSA */
|
|
#ifdef HAVE_ECC
|
|
case WC_EVP_PKEY_EC:
|
|
WOLFSSL_MSG("populating ECC key");
|
|
ret = ECC_populate_EVP_PKEY(pkey, pkey->ecc);
|
|
break;
|
|
#endif
|
|
default:
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
if (ret == 1) {
|
|
/* 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,
|
|
WOLFSSL_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 certificate 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 certificate 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;
|
|
#if defined(XGETENV) && !defined(NO_GETENV)
|
|
char* certDir = NULL;
|
|
char* certFile = NULL;
|
|
word32 flags = 0;
|
|
#elif !defined(WOLFSSL_SYS_CA_CERTS)
|
|
(void)ctx;
|
|
#endif
|
|
|
|
WOLFSSL_ENTER("wolfSSL_CTX_set_default_verify_paths");
|
|
|
|
#if defined(XGETENV) && !defined(NO_GETENV)
|
|
/* // NOLINTBEGIN(concurrency-mt-unsafe) */
|
|
certDir = wc_strdup_ex(XGETENV("SSL_CERT_DIR"), DYNAMIC_TYPE_TMP_BUFFER);
|
|
certFile = wc_strdup_ex(XGETENV("SSL_CERT_FILE"), DYNAMIC_TYPE_TMP_BUFFER);
|
|
flags = WOLFSSL_LOAD_FLAG_PEM_CA_ONLY;
|
|
|
|
if ((certDir != NULL) || (certFile != NULL)) {
|
|
if (certDir != NULL) {
|
|
/* 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;
|
|
}
|
|
}
|
|
/* // NOLINTEND(concurrency-mt-unsafe) */
|
|
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 == WC_NO_ERR_TRACE(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
|
|
}
|
|
|
|
#if defined(XGETENV) && !defined(NO_GETENV)
|
|
XFREE(certFile, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
XFREE(certDir, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
WOLFSSL_LEAVE("wolfSSL_CTX_set_default_verify_paths", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* 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)) {
|
|
ssl->buffers.serverDH_P.buffer = NULL;
|
|
ssl->buffers.serverDH_G.buffer = NULL;
|
|
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((size_t)pSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
|
|
gAlloc = (byte*)XMALLOC((size_t)gSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
|
|
if ((pAlloc == NULL) || (gAlloc == NULL)) {
|
|
/* Memory will be freed below in the (ret != 1) block */
|
|
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 && ssl != NULL) {
|
|
/* 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, (word32)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((size_t)pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
|
|
gAlloc = (byte*)XMALLOC((size_t)gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
|
|
if ((pAlloc == NULL) || (gAlloc == NULL)) {
|
|
ret = MEMORY_E;
|
|
}
|
|
}
|
|
|
|
if (ret == 1) {
|
|
/* 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) && (ctx != NULL)) {
|
|
/* Free the allocated buffers if not assigned into SSL context. */
|
|
XFREE(pAlloc, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY);
|
|
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 sizes of 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) && (ssl != NULL)) {
|
|
/* 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 sizes of 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) && (ctx != NULL)) {
|
|
/* 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, (int)gSz);
|
|
}
|
|
else {
|
|
/* Set p and g into SSL context. */
|
|
res = wolfssl_ctx_set_tmp_dh(ctx, p, (int)pSz, g, (int)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 */
|
|
|