#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#ifndef WOLFSSL_ASN_ORIG_INCLUDED
#ifndef WOLFSSL_IGNORE_FILE_WARN
#warning asn_orig.c does not need to be compiled separately from asn.c
#endif
#else
static int SkipObjectId(const byte* input, word32* inOutIdx, word32 maxIdx);
#ifndef NO_DSA
static WC_INLINE void FreeTmpDsas(byte** tmps, void* heap, int ints);
#endif
#ifndef NO_CERTS
static int GetCertHeader(DecodedCert* cert);
static int GetDate(DecodedCert* cert, int dateType, int verify, int maxIdx);
static int GetValidity(DecodedCert* cert, int verify, int maxIdx);
#endif
static word32 SetOctetString8Bit(word32 len, byte* output);
static word32 SetDigest(const byte* digest, word32 digSz, byte* output);
#ifndef NO_CERTS
static void AddAltName(DecodedCert* cert, DNS_entry* dnsEntry);
#if defined(WOLFSSL_SEP)
static int DecodeSepHwAltName(DecodedCert* cert, const byte* input, word32* idxIn, word32 sz);
#endif
static int DecodeConstructedOtherName(DecodedCert* cert, const byte* input, word32* idx, word32 sz, int oid);
#ifdef WOLFSSL_CERT_GEN
#ifdef WOLFSSL_CERT_REQ
static word32 SetPrintableString(word32 len, byte* output);
static word32 SetUTF8String(word32 len, byte* output);
#endif
static int CopyValidity(byte* output, Cert* cert);
static int SetExtensions(byte* out, word32 outSz, int *IdxInOut, const byte* ext, int extSz);
static int SetExtensionsHeader(byte* out, word32 outSz, word32 extSz);
static int SetCaWithPathLen(byte* out, word32 outSz, byte pathLen);
static int SetCaEx(byte* out, word32 outSz, byte isCa);
static int SetCa(byte* out, word32 outSz);
static int SetBC(byte* out, word32 outSz);
#ifdef WOLFSSL_CERT_EXT
static int SetOidValue(byte* out, word32 outSz, const byte *oid, word32 oidSz, byte *in, word32 inSz);
static int SetSKID(byte* output, word32 outSz, const byte *input, word32 length);
static int SetAKID(byte* output, word32 outSz, byte *input, word32 length, byte rawAkid);
static int SetKeyUsage(byte* output, word32 outSz, word16 input);
static int SetOjectIdValue(byte* output, word32 outSz, word32* idx, const byte* oid, word32 oidSz);
#ifndef IGNORE_NETSCAPE_CERT_TYPE
static int SetNsCertType(Cert* cert, byte* output, word32 outSz, byte input);
#endif
static int SetCRLInfo(Cert* cert, byte* output, word32 outSz, byte* input, int inSz);
#endif
#ifdef WOLFSSL_ALT_NAMES
static int SetAltNames(byte *output, word32 outSz, const byte *input, word32 length, int critical);
#endif
#ifdef WOLFSSL_CERT_REQ
static word32 SetReqAttribSingle(byte* output, word32* idx, char* attr, word32 attrSz, const byte* oid, word32 oidSz, byte printable, word32 extSz);
static int SetReqAttrib(byte* output, Cert* cert, word32 extSz);
#ifdef WOLFSSL_CUSTOM_OID
static int SetCustomObjectId(Cert* cert, byte* output, word32 outSz, CertOidField* custom);
#endif
#endif
#endif
#endif
#if defined(HAVE_ECC) || !defined(NO_DSA)
static word32 is_leading_bit_set(const byte* input, word32 sz);
static word32 trim_leading_zeros(const byte** input, word32 sz);
#endif
#ifdef HAVE_ECC
#ifdef WOLFSSL_CUSTOM_CURVES
static int ASNToHexString(const byte* input, word32* inOutIdx, char** out, word32 inSz, void* heap, int heapType);
static int EccKeyParamCopy(char** dst, char* src, void* heap);
#endif
#endif
#if (defined(HAVE_OCSP) || defined(HAVE_CRL)) && !defined(WOLFCRYPT_ONLY)
static int GetBasicDate(const byte* source, word32* idx, byte* date, byte* format, int maxIdx);
#endif
#if defined(HAVE_OCSP) && !defined(WOLFCRYPT_ONLY)
static int GetEnumerated(const byte* input, word32* inOutIdx, int *value, int sz);
#endif
int GetObjectId(const byte* input, word32* inOutIdx, word32* oid,
word32 oidType, word32 maxIdx)
{
int ret, length;
WOLFSSL_ENTER("GetObjectId");
ret = GetASNObjectId(input, inOutIdx, &length, maxIdx);
if (ret != 0)
return ret;
return GetOID(input, inOutIdx, oid, oidType, length);
}
static int SkipObjectId(const byte* input, word32* inOutIdx, word32 maxIdx)
{
word32 idx = *inOutIdx;
int length;
int ret;
ret = GetASNObjectId(input, &idx, &length, maxIdx);
if (ret != 0)
return ret;
idx += (word32)length;
*inOutIdx = idx;
return 0;
}
static int GetAlgoIdImpl(const byte* input, word32* inOutIdx, word32* oid,
word32 oidType, word32 maxIdx, byte *absentParams)
{
int length;
word32 idx = *inOutIdx;
int ret;
*oid = 0;
WOLFSSL_ENTER("GetAlgoId");
if (GetSequence(input, &idx, &length, maxIdx) < 0)
return ASN_PARSE_E;
if (GetObjectId(input, &idx, oid, oidType, maxIdx) < 0)
return ASN_OBJECT_ID_E;
if (idx < maxIdx) {
word32 localIdx = idx;
byte tag;
if (GetASNTag(input, &localIdx, &tag, maxIdx) == 0) {
if (tag == ASN_TAG_NULL) {
ret = GetASNNull(input, &idx, maxIdx);
if (ret != 0)
return ret;
if (absentParams != NULL) {
*absentParams = FALSE;
}
}
}
}
*inOutIdx = idx;
return 0;
}
#ifndef NO_RSA
static int _RsaPrivateKeyDecode(const byte* input, word32* inOutIdx,
RsaKey* key, int* keySz, word32 inSz)
{
int version, length;
word32 algId = 0;
int i;
if (inOutIdx == NULL || input == NULL || (key == NULL && keySz == NULL)) {
return BAD_FUNC_ARG;
}
if (ToTraditionalInline_ex(input, inOutIdx, inSz, &algId) < 0) {
}
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
if (GetMyVersion(input, inOutIdx, &version, inSz) < 0)
return ASN_PARSE_E;
if (key == NULL) {
if (GetASNInt(input, inOutIdx, keySz, inSz) < 0) {
return ASN_PARSE_E;
}
*inOutIdx += (word32)*keySz;
for (i = 1; i < RSA_INTS; i++) {
if (SkipInt(input, inOutIdx, inSz) < 0) {
return ASN_RSA_KEY_E;
}
}
}
else {
key->type = RSA_PRIVATE;
#ifdef WOLFSSL_CHECK_MEM_ZERO
mp_memzero_add("Decode RSA key d", &key->d);
mp_memzero_add("Decode RSA key p", &key->p);
mp_memzero_add("Decode RSA key q", &key->q);
#if (defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || \
!defined(RSA_LOW_MEM)) && !defined(WOLFSSL_RSA_PUBLIC_ONLY)
mp_memzero_add("Decode RSA key dP", &key->dP);
mp_memzero_add("Decode RSA key dQ", &key->dQ);
mp_memzero_add("Decode RSA key u", &key->u);
#endif
#endif
for (i = 0; i < RSA_INT_CNT; i++) {
if (GetInt(GetRsaInt(key, i), input, inOutIdx, inSz) < 0) {
for (i--; i >= 0; i--) {
mp_clear(GetRsaInt(key, i));
}
return ASN_RSA_KEY_E;
}
}
#if RSA_INT_CNT != RSA_MAX_INT_CNT
for (; i < RSA_MAX_INT_CNT; i++) {
if (SkipInt(input, inOutIdx, inSz) < 0) {
for (i = RSA_INT_CNT - 1; i >= 0; i--) {
mp_clear(GetRsaInt(key, i));
}
return ASN_RSA_KEY_E;
}
}
#endif
#if defined(WOLFSSL_XILINX_CRYPT) || defined(WOLFSSL_CRYPTOCELL)
if (wc_InitRsaHw(key) != 0) {
return BAD_STATE_E;
}
#endif
}
return 0;
}
#endif
int ToTraditionalInline_ex2(const byte* input, word32* inOutIdx, word32 sz,
word32* algId, word32* eccOid)
{
word32 idx;
int version, length;
int ret;
byte tag;
if (input == NULL || inOutIdx == NULL)
return BAD_FUNC_ARG;
idx = *inOutIdx;
if (GetSequence(input, &idx, &length, sz) < 0)
return ASN_PARSE_E;
if (GetMyVersion(input, &idx, &version, sz) < 0)
return ASN_PARSE_E;
if (GetAlgoId(input, &idx, algId, oidKeyType, sz) < 0)
return ASN_PARSE_E;
if (GetASNTag(input, &idx, &tag, sz) < 0)
return ASN_PARSE_E;
idx = idx - 1;
#if defined(WC_RSA_PSS) && !defined(NO_RSA)
if (*algId == RSAPSSk && tag == (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
word32 seqIdx = idx;
int seqLen;
enum wc_HashType hash = WC_HASH_TYPE_NONE;
int mgf = -1;
int saltLen = 0;
if (GetSequence(input, &idx, &seqLen, sz) < 0) {
return ASN_PARSE_E;
}
ret = DecodeRsaPssParams(input + seqIdx,
seqLen + idx - seqIdx, &hash, &mgf, &saltLen);
if (ret != 0) {
return ASN_PARSE_E;
}
idx += seqLen;
}
#endif
if (tag == ASN_OBJECT_ID) {
if ((*algId == ECDSAk) && (eccOid != NULL)) {
if (GetObjectId(input, &idx, eccOid, oidCurveType, sz) < 0)
return ASN_PARSE_E;
}
else {
if (SkipObjectId(input, &idx, sz) < 0)
return ASN_PARSE_E;
}
}
ret = GetOctetString(input, &idx, &length, sz);
if (ret < 0) {
if (ret == WC_NO_ERR_TRACE(BUFFER_E))
return ASN_PARSE_E;
WOLFSSL_MSG("Couldn't find Octet string");
length = 0;
}
*inOutIdx = idx;
return length;
}
#if defined(HAVE_PKCS8)
int wc_CreatePKCS8Key(byte* out, word32* outSz, byte* key, word32 keySz,
int algoID, const byte* curveOID, word32 oidSz)
{
word32 keyIdx = 0;
word32 tmpSz = 0;
word32 sz;
word32 tmpAlgId = 0;
if (out == NULL && outSz != NULL) {
*outSz = keySz + MAX_SEQ_SZ + MAX_VERSION_SZ + MAX_ALGO_SZ
+ MAX_LENGTH_SZ + MAX_LENGTH_SZ + 2;
if (curveOID != NULL)
*outSz += oidSz + MAX_LENGTH_SZ + 1;
WOLFSSL_MSG("Checking size of PKCS8");
return WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
WOLFSSL_ENTER("wc_CreatePKCS8Key");
if (key == NULL || out == NULL || outSz == NULL) {
return BAD_FUNC_ARG;
}
if (curveOID != NULL) {
sz = keySz + MAX_SEQ_SZ + MAX_VERSION_SZ + MAX_ALGO_SZ + MAX_LENGTH_SZ +
MAX_LENGTH_SZ + 3 + oidSz + MAX_LENGTH_SZ;
if ((keySz > sz) || (oidSz > sz) || (*outSz < sz))
return BUFFER_E;
}
else {
oidSz = 0;
sz= keySz + MAX_SEQ_SZ + MAX_VERSION_SZ + MAX_ALGO_SZ + MAX_LENGTH_SZ +
MAX_LENGTH_SZ + 2;
if ((keySz > sz) || (*outSz < sz))
return BUFFER_E;
}
if (ToTraditionalInline_ex(key, &keyIdx, keySz, &tmpAlgId) >= 0) {
(void)tmpAlgId;
return ASN_PARSE_E;
}
keyIdx = MAX_SEQ_SZ;
sz = (word32)SetMyVersion(PKCS8v0, out + keyIdx, 0);
tmpSz += sz; keyIdx += sz;
sz = 0;
if (curveOID != NULL && oidSz > 0) {
byte buf[MAX_LENGTH_SZ];
sz = SetLength(oidSz, buf);
sz += 1;
}
sz = (word32)SetAlgoID(algoID, out + keyIdx, oidKeyType, (int)(oidSz + sz));
tmpSz += sz; keyIdx += sz;
if (curveOID != NULL && oidSz > 0) {
sz = (word32)SetObjectId((int)oidSz, out + keyIdx);
keyIdx += sz; tmpSz += sz;
XMEMCPY(out + keyIdx, curveOID, oidSz);
keyIdx += oidSz; tmpSz += oidSz;
}
sz = (word32)SetOctetString(keySz, out + keyIdx);
keyIdx += sz; tmpSz += sz;
XMEMCPY(out + keyIdx, key, keySz);
tmpSz += keySz;
sz = SetSequence(tmpSz, out);
XMEMMOVE(out + sz, out + MAX_SEQ_SZ, tmpSz);
*outSz = tmpSz + sz;
return (int)(tmpSz + sz);
}
#endif
#ifndef NO_PWDBASED
#ifdef HAVE_PKCS8
int DecryptContent(byte* input, word32 sz, const char* password, int passwordSz)
{
word32 inOutIdx = 0, seqEnd, oid, shaOid = 0, seqPkcs5End = sz;
int ret = 0, first, second, length = 0, version, saltSz, id = 0;
int iterations = 0, keySz = 0;
#ifdef WOLFSSL_SMALL_STACK
byte* salt = NULL;
byte* cbcIv = NULL;
#else
byte salt[MAX_SALT_SIZE];
byte cbcIv[MAX_IV_SIZE];
#endif
byte tag;
if (passwordSz < 0) {
WOLFSSL_MSG("Bad password size");
return BAD_FUNC_ARG;
}
if (GetAlgoId(input, &inOutIdx, &oid, oidIgnoreType, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
first = input[inOutIdx - 2];
second = input[inOutIdx - 1];
if (CheckAlgo(first, second, &id, &version, NULL) < 0) {
ERROR_OUT(ASN_INPUT_E, exit_dc);
}
if (version == PKCS5v2) {
if (GetSequence(input, &inOutIdx, &length, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
seqPkcs5End = inOutIdx + length;
if (GetAlgoId(input, &inOutIdx, &oid, oidKdfType, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
if (oid != PBKDF2_OID) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
}
if (GetSequence(input, &inOutIdx, &length, sz) <= 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
seqEnd = inOutIdx + (word32)length;
ret = GetOctetString(input, &inOutIdx, &saltSz, seqEnd);
if (ret < 0)
goto exit_dc;
if (saltSz > MAX_SALT_SIZE) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
WC_ALLOC_VAR_EX(salt, byte, MAX_SALT_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER,
ERROR_OUT(MEMORY_E,exit_dc));
XMEMCPY(salt, &input[inOutIdx], (size_t)saltSz);
inOutIdx += (word32)saltSz;
if (GetShortInt(input, &inOutIdx, &iterations, seqEnd) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
if (seqEnd > inOutIdx) {
word32 localIdx = inOutIdx;
if (GetASNTag(input, &localIdx, &tag, seqEnd) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
if (tag == ASN_INTEGER &&
GetShortInt(input, &inOutIdx, &keySz, seqEnd) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
}
if (seqEnd > inOutIdx) {
if (GetAlgoId(input, &inOutIdx, &oid, oidHmacType, seqEnd) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
shaOid = oid;
}
WC_ALLOC_VAR_EX(cbcIv, byte, MAX_IV_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER,
ERROR_OUT(MEMORY_E,exit_dc));
if (version == PKCS5v2) {
if (GetAlgoId(input, &inOutIdx, &oid, oidBlkType, seqPkcs5End) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
if (CheckAlgoV2((int)oid, &id, NULL) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
if (shaOid == 0)
shaOid = oid;
ret = GetOctetString(input, &inOutIdx, &length, seqPkcs5End);
if (ret < 0)
goto exit_dc;
if (length > MAX_IV_SIZE) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
XMEMCPY(cbcIv, &input[inOutIdx], (size_t)length);
inOutIdx += (word32)length;
}
if (GetASNTag(input, &inOutIdx, &tag, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
if (tag != (ASN_CONTEXT_SPECIFIC | 0) && tag != ASN_OCTET_STRING) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
if (GetLength(input, &inOutIdx, &length, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
ret = wc_CryptKey(password, passwordSz, salt, saltSz, iterations, id,
input + inOutIdx, length, version, cbcIv, 0, (int)shaOid);
exit_dc:
WC_FREE_VAR_EX(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (ret == 0) {
XMEMMOVE(input, input + inOutIdx, (size_t)length);
ret = length;
}
return ret;
}
#endif
#ifdef HAVE_PKCS12
int EncryptContent(byte* input, word32 inputSz, byte* out, word32* outSz,
const char* password, int passwordSz, int vPKCS, int vAlgo,
int encAlgId, byte* salt, word32 saltSz, int itt, int hmacOid,
WC_RNG* rng, void* heap)
{
word32 sz;
word32 inOutIdx = 0;
word32 tmpIdx = 0;
word32 totalSz = 0;
word32 seqSz;
word32 innerSz;
int ret;
int version, id = PBE_NONE, blockSz = 0;
#ifdef WOLFSSL_SMALL_STACK
byte* saltTmp = NULL;
byte* cbcIv = NULL;
#else
byte saltTmp[MAX_SALT_SIZE];
byte cbcIv[MAX_IV_SIZE];
#endif
byte seq[MAX_SEQ_SZ];
byte shr[MAX_SHORT_SZ];
word32 maxShr = MAX_SHORT_SZ;
word32 algoSz;
const byte* algoName;
(void)encAlgId;
(void)hmacOid;
(void)heap;
(void)EncryptContentPBES2;
WOLFSSL_ENTER("EncryptContent");
if (CheckAlgo(vPKCS, vAlgo, &id, &version, &blockSz) < 0)
return ASN_INPUT_E;
if (version == PKCS5v2) {
WOLFSSL_MSG("PKCS#5 version 2 not supported yet");
return BAD_FUNC_ARG;
}
if (saltSz > MAX_SALT_SIZE)
return ASN_PARSE_E;
if (outSz == NULL) {
return BAD_FUNC_ARG;
}
sz = wc_PkcsPad(NULL, inputSz, (word32)blockSz);
totalSz = ASN_TAG_SZ;
totalSz += SetLength(sz, seq);
totalSz += sz;
algoName = OidFromId((word32)id, oidPBEType, &algoSz);
if (algoName == NULL) {
WOLFSSL_MSG("Unknown Algorithm");
return 0;
}
innerSz = (word32)SetObjectId((int)algoSz, seq);
innerSz += algoSz;
if (salt == NULL || saltSz == 0) {
sz = 8;
}
else {
sz = saltSz;
}
seqSz = SetOctetString(sz, seq);
seqSz += sz;
tmpIdx = 0;
ret = SetShortInt(shr, &tmpIdx, (word32)itt, maxShr);
if (ret >= 0) {
seqSz += (word32)ret;
}
else {
return ret;
}
innerSz += seqSz + SetSequence(seqSz, seq);
totalSz += innerSz + SetSequence(innerSz, seq);
if (out == NULL) {
*outSz = totalSz;
return WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
inOutIdx = 0;
if (totalSz > *outSz)
return BUFFER_E;
inOutIdx += SetSequence(innerSz, out + inOutIdx);
inOutIdx += (word32)SetObjectId((int)algoSz, out + inOutIdx);
XMEMCPY(out + inOutIdx, algoName, algoSz);
inOutIdx += algoSz;
inOutIdx += SetSequence(seqSz, out + inOutIdx);
if (salt == NULL || saltSz == 0) {
saltSz = 8;
WC_ALLOC_VAR_EX(saltTmp, byte, saltSz, heap, DYNAMIC_TYPE_TMP_BUFFER,
return MEMORY_E);
salt = saltTmp;
if ((ret = wc_RNG_GenerateBlock(rng, saltTmp, saltSz)) != 0) {
WOLFSSL_MSG("Error generating random salt");
WC_FREE_VAR_EX(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
}
inOutIdx += SetOctetString(saltSz, out + inOutIdx);
if (saltSz + inOutIdx > *outSz) {
WC_FREE_VAR_EX(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
return BUFFER_E;
}
XMEMCPY(out + inOutIdx, salt, saltSz);
inOutIdx += saltSz;
ret = SetShortInt(out, &inOutIdx, (word32)itt, *outSz);
if (ret < 0) {
WC_FREE_VAR_EX(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
if (inOutIdx + 1 > *outSz) {
WC_FREE_VAR_EX(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
return BUFFER_E;
}
out[inOutIdx++] = ASN_CONTEXT_SPECIFIC | 0;
sz = wc_PkcsPad(NULL, inputSz, (word32)blockSz);
if (sz + inOutIdx > *outSz) {
WC_FREE_VAR_EX(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
return BUFFER_E;
}
inOutIdx += SetLength(sz, out + inOutIdx);
XMEMCPY(out + inOutIdx, input, inputSz);
sz = wc_PkcsPad(out + inOutIdx, inputSz, (word32)blockSz);
#ifdef WOLFSSL_SMALL_STACK
cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (cbcIv == NULL) {
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
#endif
if ((ret = wc_CryptKey(password, passwordSz, salt, (int)saltSz, itt, id,
out + inOutIdx, (int)sz, version, cbcIv, 1, 0)) < 0) {
WC_FREE_VAR_EX(cbcIv, heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
WC_FREE_VAR_EX(cbcIv, heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
(void)rng;
return (int)(inOutIdx + sz);
}
#endif
#endif
#ifndef NO_RSA
#if defined(WOLFSSL_RENESAS_TSIP_TLS) || defined(WOLFSSL_RENESAS_FSPSM_TLS)
static int RsaPublicKeyDecodeRawIndex(const byte* input, word32* inOutIdx,
word32 inSz, word32* key_n,
word32* key_n_len, word32* key_e,
word32* key_e_len)
{
int ret = 0;
int length = 0;
#if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
byte b;
#endif
if (input == NULL || inOutIdx == NULL)
return BAD_FUNC_ARG;
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
#if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
if ((*inOutIdx + 1) > inSz)
return BUFFER_E;
b = input[*inOutIdx];
if (b != ASN_INTEGER) {
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
if (SkipObjectId(input, inOutIdx, inSz) < 0)
return ASN_PARSE_E;
if (*inOutIdx >= inSz) {
return BUFFER_E;
}
if (input[*inOutIdx] == ASN_TAG_NULL) {
ret = GetASNNull(input, inOutIdx, inSz);
if (ret != 0)
return ret;
}
ret = CheckBitString(input, inOutIdx, NULL, inSz, 1, NULL);
if (ret != 0)
return ret;
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
}
#endif
ret = GetASNInt(input, inOutIdx, &length, inSz);
*key_n += *inOutIdx;
if (ret < 0) {
return ASN_RSA_KEY_E;
}
if (key_n_len)
*key_n_len = length;
*inOutIdx += length;
ret = GetASNInt(input, inOutIdx, &length, inSz);
*key_e += *inOutIdx;
if (ret < 0) {
return ASN_RSA_KEY_E;
}
if (key_e_len)
*key_e_len = length;
return ret;
}
#endif
int wc_RsaPublicKeyDecode_ex(const byte* input, word32* inOutIdx, word32 inSz,
const byte** n, word32* nSz, const byte** e, word32* eSz)
{
int ret = 0;
int length = 0;
int firstLen = 0;
word32 seqEndIdx = inSz;
#if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
word32 localIdx;
byte tag;
#endif
if (input == NULL || inOutIdx == NULL)
return BAD_FUNC_ARG;
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
#if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
localIdx = *inOutIdx;
if (GetASNTag(input, &localIdx, &tag, inSz) < 0)
return BUFFER_E;
if (tag != ASN_INTEGER) {
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
if (SkipObjectId(input, inOutIdx, inSz) < 0)
return ASN_PARSE_E;
if (*inOutIdx >= inSz) {
return BUFFER_E;
}
localIdx = *inOutIdx;
if (GetASNTag(input, &localIdx, &tag, inSz) < 0)
return ASN_PARSE_E;
if (tag == ASN_TAG_NULL) {
ret = GetASNNull(input, inOutIdx, inSz);
if (ret != 0)
return ret;
}
#ifdef WC_RSA_PSS
else if (tag == (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
*inOutIdx += length;
}
#endif
ret = CheckBitString(input, inOutIdx, NULL, inSz, 1, NULL);
if (ret != 0)
return ret;
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
seqEndIdx = *inOutIdx + (word32)length;
}
#endif
ret = GetASNInt(input, inOutIdx, &firstLen, seqEndIdx);
if (ret < 0) {
return ASN_RSA_KEY_E;
}
if (nSz)
*nSz = (word32)firstLen;
if (n)
*n = &input[*inOutIdx];
*inOutIdx += (word32)firstLen;
ret = GetASNInt(input, inOutIdx, &length, seqEndIdx);
if (ret < 0) {
return ASN_RSA_KEY_E;
}
if (eSz)
*eSz = (word32)length;
if (e)
*e = &input[*inOutIdx];
*inOutIdx += (word32)length;
if (firstLen <= MAX_VERSION_SZ && *inOutIdx < seqEndIdx) {
return ASN_RSA_KEY_E;
}
return ret;
}
#endif
#ifndef NO_DH
int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz)
{
int ret = 0;
int length;
#ifdef WOLFSSL_DH_EXTRA
#if !defined(HAVE_FIPS) || \
(defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))
word32 oid = 0, temp = 0;
#endif
#endif
WOLFSSL_ENTER("wc_DhKeyDecode");
if (inOutIdx == NULL)
return BAD_FUNC_ARG;
if (key == NULL)
return BAD_FUNC_ARG;
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
#ifdef WOLFSSL_DH_EXTRA
#if !defined(HAVE_FIPS) || \
(defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))
temp = *inOutIdx;
#endif
#endif
if (GetInt(&key->p, input, inOutIdx, inSz) < 0) {
ret = ASN_DH_KEY_E;
}
if (ret == 0 && GetInt(&key->g, input, inOutIdx, inSz) < 0) {
mp_clear(&key->p);
ret = ASN_DH_KEY_E;
}
#ifdef WOLFSSL_DH_EXTRA
#if !defined(HAVE_FIPS) || \
(defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))
if (ret == WC_NO_ERR_TRACE(ASN_DH_KEY_E)) {
*inOutIdx = temp;
if (GetASNInt(input, inOutIdx, &length, inSz) == 0) {
*inOutIdx += (word32)length;
}
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
ret = GetObjectId(input, inOutIdx, &oid, oidKeyType, inSz);
if (oid != DHk || ret < 0)
return ASN_DH_KEY_E;
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
if (GetInt(&key->p, input, inOutIdx, inSz) < 0) {
return ASN_DH_KEY_E;
}
if (ret == 0 && GetInt(&key->g, input, inOutIdx, inSz) < 0) {
mp_clear(&key->p);
return ASN_DH_KEY_E;
}
}
temp = *inOutIdx;
ret = (CheckBitString(input, inOutIdx, &length, inSz, 0, NULL) == 0);
if (ret > 0) {
if (GetInt(&key->pub, input, inOutIdx, inSz) == 0) {
WOLFSSL_MSG("Found Public Key");
ret = 0;
}
} else {
*inOutIdx = temp;
ret = (GetOctetString(input, inOutIdx, &length, inSz) >= 0);
if (ret > 0) {
if (GetInt(&key->priv, input, inOutIdx, inSz) == 0) {
WOLFSSL_MSG("Found Private Key");
ret = mp_exptmod(&key->g, &key->priv, &key->p, &key->pub);
}
} else {
*inOutIdx = temp;
ret = 0;
}
}
#endif
#endif
WOLFSSL_LEAVE("wc_DhKeyDecode", ret);
return ret;
}
#ifdef WOLFSSL_DH_EXTRA
int wc_DhKeyToDer(DhKey* key, byte* output, word32* outSz, int exportPriv)
{
int ret, privSz = 0, pubSz = 0;
word32 keySz, idx, len, total;
if (key == NULL || outSz == NULL) {
return BAD_FUNC_ARG;
}
if (exportPriv) {
privSz = SetASNIntMP(&key->priv, -1, NULL);
if (privSz < 0)
return privSz;
idx = 1 + SetLength((word32)privSz, NULL) +
(word32)privSz;
}
else {
pubSz = SetASNIntMP(&key->pub, -1, NULL);
if (pubSz < 0)
return pubSz;
idx = SetBitString((word32)pubSz, 0, NULL) + (word32)pubSz;
}
keySz = idx;
total = 0;
ret = wc_DhParamsToDer(key, NULL, &total);
if (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E))
return ret;
idx += total;
idx += (word32)SetObjectId(sizeof(keyDhOid), NULL);
idx += (word32)sizeof(keyDhOid);
len = idx - keySz;
idx += SetSequence(len, NULL);
if (exportPriv) {
idx += 3;
}
total = idx + SetSequence(idx, NULL);
if (output == NULL) {
*outSz = total;
return WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
if (total > *outSz) {
return BUFFER_E;
}
total = idx;
idx = SetSequence(total, output);
if (exportPriv) {
idx += (word32)SetMyVersion(0, output + idx, 0);
}
idx += SetSequence(len, output + idx);
idx += (word32)SetObjectId(sizeof(keyDhOid), output + idx);
XMEMCPY(output + idx, keyDhOid, sizeof(keyDhOid));
idx += sizeof(keyDhOid);
total = *outSz - idx;
ret = wc_DhParamsToDer(key, output + idx, &total);
if (ret < 0)
return ret;
idx += total;
if (exportPriv) {
idx += (word32)SetOctetString((word32)privSz, output + idx);
idx += (word32)SetASNIntMP(&key->priv, -1, output + idx);
}
else {
idx += (word32)SetBitString((word32)pubSz, 0, output + idx);
idx += (word32)SetASNIntMP(&key->pub, -1, output + idx);
}
*outSz = idx;
return (int)idx;
}
int wc_DhParamsToDer(DhKey* key, byte* output, word32* outSz)
{
int ret;
word32 idx, total;
if (key == NULL || outSz == NULL) {
return BAD_FUNC_ARG;
}
ret = SetASNIntMP(&key->g, -1, NULL);
if (ret < 0)
return ret;
idx = (word32)ret;
ret = SetASNIntMP(&key->p, -1, NULL);
if (ret < 0)
return ret;
idx += (word32)ret;
total = idx;
idx += SetSequence(idx, NULL);
if (output == NULL) {
*outSz = idx;
return WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
if (idx > *outSz) {
return BUFFER_E;
}
idx = SetSequence(total, output);
ret = SetASNIntMP(&key->p, -1, output + idx);
if (ret < 0)
return ret;
idx += (word32)ret;
ret = SetASNIntMP(&key->g, -1, output + idx);
if (ret < 0)
return ret;
idx += (word32)ret;
*outSz = idx;
return (int)idx;
}
#endif
int wc_DhParamsLoad(const byte* input, word32 inSz, byte* p, word32* pInOutSz,
byte* g, word32* gInOutSz)
{
word32 idx = 0;
int ret;
int length;
if (GetSequence(input, &idx, &length, inSz) <= 0)
return ASN_PARSE_E;
ret = GetASNInt(input, &idx, &length, inSz);
if (ret != 0)
return ret;
if (length <= (int)*pInOutSz) {
XMEMCPY(p, &input[idx], (size_t)length);
*pInOutSz = (word32)length;
}
else {
return BUFFER_E;
}
idx += (word32)length;
ret = GetASNInt(input, &idx, &length, inSz);
if (ret != 0)
return ret;
if (length <= (int)*gInOutSz) {
XMEMCPY(g, &input[idx], (size_t)length);
*gInOutSz = (word32)length;
}
else {
return BUFFER_E;
}
return 0;
}
#endif
#ifndef NO_DSA
int wc_DsaPublicKeyDecode(const byte* input, word32* inOutIdx, DsaKey* key,
word32 inSz)
{
int length;
int ret = 0;
word32 oid;
word32 maxIdx;
if (input == NULL || inOutIdx == NULL || key == NULL)
return BAD_FUNC_ARG;
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
maxIdx = (word32)(*inOutIdx + (word32)length);
if (GetInt(&key->p, input, inOutIdx, maxIdx) < 0 ||
GetInt(&key->q, input, inOutIdx, maxIdx) < 0 ||
GetInt(&key->g, input, inOutIdx, maxIdx) < 0 ||
GetInt(&key->y, input, inOutIdx, maxIdx) < 0 )
ret = ASN_DH_KEY_E;
if (ret != 0) {
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
ret = GetObjectId(input, inOutIdx, &oid, oidIgnoreType, inSz);
if (ret != 0)
return ret;
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
if (GetInt(&key->p, input, inOutIdx, inSz) < 0 ||
GetInt(&key->q, input, inOutIdx, inSz) < 0 ||
GetInt(&key->g, input, inOutIdx, inSz) < 0)
return ASN_DH_KEY_E;
if (CheckBitString(input, inOutIdx, &length, inSz, 0, NULL) < 0)
return ASN_PARSE_E;
if (GetInt(&key->y, input, inOutIdx, inSz) < 0 )
return ASN_DH_KEY_E;
ret = 0;
}
key->type = DSA_PUBLIC;
return ret;
}
int wc_DsaPrivateKeyDecode(const byte* input, word32* inOutIdx, DsaKey* key,
word32 inSz)
{
int length, version, ret = 0, temp = 0;
word32 algId = 0;
if (input == NULL || inOutIdx == NULL || key == NULL) {
return BAD_FUNC_ARG;
}
if (ToTraditionalInline_ex(input, inOutIdx, inSz, &algId) < 0) {
}
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
temp = (int)*inOutIdx;
ret = GetInt(&key->p, input, inOutIdx, inSz);
if (ret < 0) {
mp_clear(&key->p);
ret = ASN_PARSE_E;
}
else {
ret = GetInt(&key->q, input, inOutIdx, inSz);
if (ret < 0) {
mp_clear(&key->p);
mp_clear(&key->q);
ret = ASN_PARSE_E;
}
else {
ret = GetInt(&key->g, input, inOutIdx, inSz);
if (ret < 0) {
mp_clear(&key->p);
mp_clear(&key->q);
mp_clear(&key->g);
ret = ASN_PARSE_E;
}
else {
ret = GetOctetString(input, inOutIdx, &length, inSz);
if (ret < 0) {
mp_clear(&key->p);
mp_clear(&key->q);
mp_clear(&key->g);
ret = ASN_PARSE_E;
}
else {
ret = GetInt(&key->y, input, inOutIdx, inSz);
if (ret < 0) {
mp_clear(&key->p);
mp_clear(&key->q);
mp_clear(&key->g);
mp_clear(&key->y);
ret = ASN_PARSE_E;
}
}
}
}
}
if (ret == WC_NO_ERR_TRACE(ASN_PARSE_E)) {
*inOutIdx = (word32)temp;
if (GetMyVersion(input, inOutIdx, &version, inSz) < 0)
return ASN_PARSE_E;
if (GetInt(&key->p, input, inOutIdx, inSz) < 0 ||
GetInt(&key->q, input, inOutIdx, inSz) < 0 ||
GetInt(&key->g, input, inOutIdx, inSz) < 0 ||
GetInt(&key->y, input, inOutIdx, inSz) < 0 ||
GetInt(&key->x, input, inOutIdx, inSz) < 0 )
return ASN_DH_KEY_E;
}
key->type = DSA_PRIVATE;
return 0;
}
static WC_INLINE void FreeTmpDsas(byte** tmps, void* heap, int ints)
{
int i;
for (i = 0; i < ints; i++)
XFREE(tmps[i], heap, DYNAMIC_TYPE_DSA);
(void)heap;
}
#if !defined(HAVE_SELFTEST) && (defined(WOLFSSL_KEY_GEN) || \
defined(WOLFSSL_CERT_GEN))
int wc_SetDsaPublicKey(byte* output, DsaKey* key, int outLen, int with_header)
{
#ifdef WOLFSSL_SMALL_STACK
byte* p = NULL;
byte* g = NULL;
byte* q = NULL;
byte* y = NULL;
#else
byte p[MAX_DSA_INT_SZ];
byte g[MAX_DSA_INT_SZ];
byte q[MAX_DSA_INT_SZ];
byte y[MAX_DSA_INT_SZ];
#endif
byte innerSeq[MAX_SEQ_SZ];
byte outerSeq[MAX_SEQ_SZ];
byte bitString[1 + MAX_LENGTH_SZ + 1];
int pSz, gSz, qSz, ySz;
word32 idx, innerSeqSz, outerSeqSz, bitStringSz = 0;
WOLFSSL_ENTER("wc_SetDsaPublicKey");
if (output == NULL || key == NULL || outLen < MAX_SEQ_SZ) {
return BAD_FUNC_ARG;
}
WC_ALLOC_VAR_EX(p, byte, MAX_DSA_INT_SZ, key->heap,
DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
if ((pSz = SetASNIntMP(&key->p, MAX_DSA_INT_SZ, p)) < 0) {
WOLFSSL_MSG("SetASNIntMP Error with p");
WC_FREE_VAR_EX(p, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
return pSz;
}
WC_ALLOC_VAR_EX(q, byte, MAX_DSA_INT_SZ, key->heap,
DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
if ((qSz = SetASNIntMP(&key->q, MAX_DSA_INT_SZ, q)) < 0) {
WOLFSSL_MSG("SetASNIntMP Error with q");
WC_FREE_VAR_EX(p, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(q, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
return qSz;
}
WC_ALLOC_VAR_EX(g, byte, MAX_DSA_INT_SZ, key->heap,
DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
if ((gSz = SetASNIntMP(&key->g, MAX_DSA_INT_SZ, g)) < 0) {
WOLFSSL_MSG("SetASNIntMP Error with g");
WC_FREE_VAR_EX(p, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(q, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(g, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
return gSz;
}
WC_ALLOC_VAR_EX(y, byte, MAX_DSA_INT_SZ, key->heap,
DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
if ((ySz = SetASNIntMP(&key->y, MAX_DSA_INT_SZ, y)) < 0) {
WOLFSSL_MSG("SetASNIntMP Error with y");
WC_FREE_VAR_EX(p, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(q, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(g, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(y, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
return ySz;
}
if (with_header) {
word32 algoSz;
#ifdef WOLFSSL_SMALL_STACK
byte* algo = NULL;
algo = (byte*)XMALLOC(MAX_ALGO_SZ, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (algo == NULL) {
XFREE(p, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(q, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(g, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(y, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
#else
byte algo[MAX_ALGO_SZ];
#endif
innerSeqSz = SetSequence((word32)(pSz + qSz + gSz), innerSeq);
algoSz = SetAlgoID(DSAk, algo, oidKeyType, 0);
bitStringSz = SetBitString((word32)ySz, 0, bitString);
outerSeqSz = SetSequence(algoSz + innerSeqSz +
(word32)(pSz + qSz + gSz), outerSeq);
idx = SetSequence(algoSz + innerSeqSz + (word32)(pSz + qSz + gSz) +
bitStringSz + (word32)ySz + outerSeqSz, output);
if ((idx + algoSz + bitStringSz + innerSeqSz +
(word32)(pSz + qSz + gSz + ySz)) > (word32)outLen)
{
WC_FREE_VAR_EX(p, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(q, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(g, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(y, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(algo, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WOLFSSL_MSG("Error, output size smaller than outlen");
return BUFFER_E;
}
XMEMCPY(output + idx, outerSeq, outerSeqSz);
idx += outerSeqSz;
XMEMCPY(output + idx, algo, algoSz);
idx += algoSz;
WC_FREE_VAR_EX(algo, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
} else {
innerSeqSz = SetSequence((word32)(pSz + qSz + gSz + ySz), innerSeq);
if ((innerSeqSz + (word32)(pSz + qSz + gSz + ySz)) > (word32)outLen) {
WC_FREE_VAR_EX(p, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(q, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(g, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(y, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WOLFSSL_MSG("Error, output size smaller than outlen");
return BUFFER_E;
}
idx = 0;
}
XMEMCPY(output + idx, innerSeq, innerSeqSz);
idx += innerSeqSz;
XMEMCPY(output + idx, p, (size_t)pSz);
idx += (word32)pSz;
XMEMCPY(output + idx, q, (size_t)qSz);
idx += (word32)qSz;
XMEMCPY(output + idx, g, (size_t)gSz);
idx += (word32)gSz;
if (bitStringSz > 0) {
XMEMCPY(output + idx, bitString, bitStringSz);
idx += bitStringSz;
}
XMEMCPY(output + idx, y, (size_t)ySz);
idx += (word32)ySz;
WC_FREE_VAR_EX(p, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(q, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(g, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(y, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
return (int)idx;
}
#endif
static int DsaKeyIntsToDer(DsaKey* key, byte* output, word32* inLen,
int ints, int includeVersion)
{
word32 seqSz = 0, verSz = 0, intTotalLen = 0, outLen, j;
word32 sizes[DSA_INTS];
int i, ret = 0;
byte seq[MAX_SEQ_SZ];
byte ver[MAX_VERSION_SZ];
byte* tmps[DSA_INTS];
if (ints > DSA_INTS || inLen == NULL)
return BAD_FUNC_ARG;
XMEMSET(sizes, 0, sizeof(sizes));
for (i = 0; i < ints; i++)
tmps[i] = NULL;
for (i = 0; i < ints; i++) {
int mpSz;
mp_int* keyInt = GetDsaInt(key, i);
word32 rawLen = (word32)mp_unsigned_bin_size(keyInt) + 1;
tmps[i] = (byte*)XMALLOC(rawLen + MAX_SEQ_SZ, key->heap,
DYNAMIC_TYPE_DSA);
if (tmps[i] == NULL) {
ret = MEMORY_E;
break;
}
mpSz = SetASNIntMP(keyInt, -1, tmps[i]);
if (mpSz < 0) {
ret = mpSz;
break;
}
sizes[i] = (word32)mpSz;
intTotalLen += (word32)mpSz;
}
if (ret != 0) {
FreeTmpDsas(tmps, key->heap, ints);
return ret;
}
if (includeVersion)
verSz = (word32)SetMyVersion(0, ver, FALSE);
seqSz = SetSequence(verSz + intTotalLen, seq);
outLen = seqSz + verSz + intTotalLen;
if (output == NULL) {
*inLen = outLen;
FreeTmpDsas(tmps, key->heap, ints);
return WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
if (outLen > *inLen) {
FreeTmpDsas(tmps, key->heap, ints);
return BAD_FUNC_ARG;
}
*inLen = outLen;
XMEMCPY(output, seq, seqSz);
j = seqSz;
if (includeVersion) {
XMEMCPY(output + j, ver, verSz);
j += verSz;
}
for (i = 0; i < ints; i++) {
XMEMCPY(output + j, tmps[i], sizes[i]);
j += sizes[i];
}
FreeTmpDsas(tmps, key->heap, ints);
return (int)outLen;
}
#endif
#ifndef NO_CERTS
static int GetCertHeader(DecodedCert* cert)
{
int ret = 0, len;
if (GetSequence(cert->source, &cert->srcIdx, &len, cert->maxIdx) < 0)
return ASN_PARSE_E;
cert->maxIdx = (word32)len + cert->srcIdx;
cert->certBegin = cert->srcIdx;
if (GetSequence(cert->source, &cert->srcIdx, &len, cert->maxIdx) < 0)
return ASN_PARSE_E;
cert->sigIndex = (word32)len + cert->srcIdx;
if (cert->sigIndex > cert->maxIdx)
return ASN_PARSE_E;
if (GetExplicitVersion(cert->source, &cert->srcIdx, &cert->version,
cert->sigIndex) < 0)
return ASN_PARSE_E;
ret = wc_GetSerialNumber(cert->source, &cert->srcIdx, cert->serial,
&cert->serialSz, cert->sigIndex);
if (ret < 0) {
return ret;
}
return ret;
}
#endif
#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT)
static int SetEccPublicKey(byte* output, ecc_key* key, int outLen,
int with_header, int comp)
{
int ret;
word32 idx = 0, curveSz, algoSz, pubSz, bitStringSz;
byte bitString[1 + MAX_LENGTH_SZ + 1];
byte algo[MAX_ALGO_SZ];
pubSz = key->dp ? (word32)key->dp->size : MAX_ECC_BYTES;
if (comp)
pubSz = 1 + pubSz;
else
pubSz = 1 + 2 * pubSz;
if (output != NULL && pubSz > (word32)outLen) {
return BUFFER_E;
}
if (with_header) {
ret = SetCurve(key, NULL, 0);
if (ret <= 0) {
return ret;
}
curveSz = (word32)ret;
ret = 0;
algoSz = SetAlgoID(ECDSAk, algo, oidKeyType, (int)curveSz);
bitStringSz = SetBitString(pubSz, 0, bitString);
idx = SetSequence(pubSz + curveSz + bitStringSz + algoSz, NULL);
if (output != NULL &&
curveSz + algoSz + bitStringSz + idx + pubSz > (word32)outLen) {
return BUFFER_E;
}
idx = SetSequence(pubSz + curveSz + bitStringSz + algoSz,
output);
if (output)
XMEMCPY(output + idx, algo, algoSz);
idx += algoSz;
if (output)
(void)SetCurve(key, output + idx, curveSz);
idx += curveSz;
if (output)
XMEMCPY(output + idx, bitString, bitStringSz);
idx += bitStringSz;
}
if (output) {
PRIVATE_KEY_UNLOCK();
ret = wc_ecc_export_x963_ex(key, output + idx, &pubSz, comp);
PRIVATE_KEY_LOCK();
if (ret != 0) {
return ret;
}
}
idx += pubSz;
return (int)idx;
}
#endif
#ifdef WC_ENABLE_ASYM_KEY_EXPORT
int SetAsymKeyDerPublic(const byte* pubKey, word32 pubKeyLen,
byte* output, word32 outLen, int keyType, int withHeader)
{
int ret = 0;
word32 idx = 0;
word32 seqDataSz = 0;
word32 sz;
if (pubKey == NULL){
return BAD_FUNC_ARG;
}
if (output != NULL && outLen == 0) {
return BUFFER_E;
}
if (withHeader) {
word32 algoSz = SetAlgoID(keyType, NULL, oidKeyType, 0);
word32 bitStringSz = SetBitString(pubKeyLen, 0, NULL);
seqDataSz = algoSz + bitStringSz + pubKeyLen;
sz = SetSequence(seqDataSz, NULL) + seqDataSz;
}
else {
sz = pubKeyLen;
}
if (output != NULL && sz > outLen) {
ret = BUFFER_E;
}
if (ret == 0 && output != NULL && withHeader) {
idx = SetSequence(seqDataSz, output);
idx += SetAlgoID(keyType, output + idx, oidKeyType, 0);
idx += SetBitString(pubKeyLen, 0, output + idx);
}
if (ret == 0 && output != NULL) {
XMEMCPY(output + idx, pubKey, pubKeyLen);
idx += pubKeyLen;
sz = idx;
}
if (ret == 0) {
ret = (int)sz;
}
return ret;
}
#endif
#if !defined(NO_RSA) && !defined(NO_CERTS)
static int StoreRsaKey(DecodedCert* cert, const byte* source, word32* srcIdx,
word32 maxIdx)
{
int length;
int pubLen;
word32 pubIdx;
if (CheckBitString(source, srcIdx, &pubLen, maxIdx, 1, NULL) != 0)
return ASN_PARSE_E;
pubIdx = *srcIdx;
if (GetSequence(source, srcIdx, &length, pubIdx + (word32)pubLen) < 0)
return ASN_PARSE_E;
#if defined(WOLFSSL_RENESAS_TSIP_TLS) || defined(WOLFSSL_RENESAS_FSPSM_TLS)
cert->sigCtx.CertAtt.pubkey_n_start =
cert->sigCtx.CertAtt.pubkey_e_start = pubIdx;
#endif
cert->pubKeySize = (word32)pubLen;
cert->publicKey = source + pubIdx;
#ifdef WOLFSSL_MAXQ10XX_TLS
cert->publicKeyIndex = pubIdx;
#endif
*srcIdx += (word32)length;
#ifdef HAVE_OCSP
return CalcHashId_ex(cert->publicKey, cert->pubKeySize,
cert->subjectKeyHash, HashIdAlg(cert->signatureOID));
#else
return 0;
#endif
}
#endif
#if defined(HAVE_ECC) && !defined(NO_CERTS)
static int StoreEccKey(DecodedCert* cert, const byte* source, word32* srcIdx,
word32 maxIdx, const byte* pubKey, word32 pubKeyLen)
{
int ret;
word32 localIdx;
byte* publicKey;
byte tag;
int length;
if (pubKey == NULL) {
return BAD_FUNC_ARG;
}
localIdx = *srcIdx;
if (GetASNTag(source, &localIdx, &tag, maxIdx) < 0)
return ASN_PARSE_E;
if (tag != (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
if (GetObjectId(source, srcIdx, &cert->pkCurveOID, oidCurveType,
maxIdx) < 0)
return ASN_PARSE_E;
if ((ret = CheckCurve(cert->pkCurveOID)) < 0)
return ECC_CURVE_OID_E;
#if defined(WOLFSSL_RENESAS_FSPSM_TLS) || defined(WOLFSSL_RENESAS_TSIP_TLS)
cert->sigCtx.CertAtt.curve_id = ret;
#else
(void)ret;
#endif
ret = CheckBitString(source, srcIdx, &length, maxIdx, 1, NULL);
if (ret != 0)
return ret;
#if defined(WOLFSSL_RENESAS_FSPSM_TLS) || defined(WOLFSSL_RENESAS_TSIP_TLS)
cert->sigCtx.CertAtt.pubkey_n_start =
cert->sigCtx.CertAtt.pubkey_e_start = (*srcIdx + 1);
cert->sigCtx.CertAtt.pubkey_n_len = ((length - 1) >> 1);
cert->sigCtx.CertAtt.pubkey_e_start +=
cert->sigCtx.CertAtt.pubkey_n_len;
cert->sigCtx.CertAtt.pubkey_e_len =
cert->sigCtx.CertAtt.pubkey_n_len;
#endif
#ifdef WOLFSSL_MAXQ10XX_TLS
cert->publicKeyIndex = *srcIdx + 1;
#endif
#ifdef HAVE_OCSP
ret = CalcHashId_ex(source + *srcIdx, (word32)length,
cert->subjectKeyHash, HashIdAlg(cert->signatureOID));
if (ret != 0)
return ret;
#endif
*srcIdx += (word32)length;
}
publicKey = (byte*)XMALLOC(pubKeyLen, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
if (publicKey == NULL)
return MEMORY_E;
XMEMCPY(publicKey, pubKey, pubKeyLen);
cert->publicKey = publicKey;
cert->pubKeyStored = 1;
cert->pubKeySize = pubKeyLen;
return 0;
}
#endif
#ifndef NO_CERTS
#if !defined(NO_DSA)
static int ParseDsaKey(const byte* source, word32* srcIdx, word32 maxIdx,
void* heap)
{
int ret;
int length;
(void)heap;
ret = GetSequence(source, srcIdx, &length, maxIdx);
if (ret < 0)
return ret;
ret = SkipInt(source, srcIdx, maxIdx);
if (ret != 0)
return ret;
ret = SkipInt(source, srcIdx, maxIdx);
if (ret != 0)
return ret;
ret = SkipInt(source, srcIdx, maxIdx);
if (ret != 0)
return ret;
ret = CheckBitString(source, srcIdx, &length, maxIdx, 1, NULL);
if (ret != 0)
return ret;
ret = GetASNInt(source, srcIdx, &length, maxIdx);
if (ret != 0)
return ASN_PARSE_E;
*srcIdx += (word32)length;
return 0;
}
#endif
#endif
static int GetCertName(DecodedCert* cert, char* full, byte* hash, int nameType,
const byte* input, word32* inOutIdx, word32 maxIdx)
{
int length;
int dummy;
int ret;
word32 idx;
word32 srcIdx = *inOutIdx;
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
!defined(WOLFCRYPT_ONLY)
WOLFSSL_X509_NAME* dName = NULL;
#endif
WOLFSSL_MSG("Getting Cert Name");
if (CalcHashId_ex(input + *inOutIdx, maxIdx - *inOutIdx, hash,
HashIdAlg(cert->signatureOID)) != 0) {
return ASN_PARSE_E;
}
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
!defined(WOLFCRYPT_ONLY)
dName = wolfSSL_X509_NAME_new_ex(cert->heap);
if (dName == NULL) {
return MEMORY_E;
}
#endif
if (GetSequence(input, &srcIdx, &length, maxIdx) < 0) {
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
!defined(WOLFCRYPT_ONLY)
wolfSSL_X509_NAME_free(dName);
#endif
return ASN_PARSE_E;
}
#if defined(HAVE_PKCS7) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_ISSUER) {
cert->issuerRaw = &input[srcIdx];
cert->issuerRawLen = length;
}
#endif
#if !defined(IGNORE_NAME_CONSTRAINTS) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectRaw = &input[srcIdx];
cert->subjectRawLen = length;
}
#endif
length += (int)srcIdx;
idx = 0;
while (srcIdx < (word32)length) {
byte b = 0;
byte joint[3];
byte tooBig = FALSE;
int oidSz;
const char* copy = NULL;
int copyLen = 0;
int strLen = 0;
byte id = 0;
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
int nid = WC_NID_undef;
int enc;
#endif
if (GetSet(input, &srcIdx, &dummy, maxIdx) < 0) {
WOLFSSL_MSG("Cert name lacks set header, trying sequence");
}
if (GetSequence(input, &srcIdx, &dummy, maxIdx) <= 0) {
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
!defined(WOLFCRYPT_ONLY)
wolfSSL_X509_NAME_free(dName);
#endif
return ASN_PARSE_E;
}
ret = GetASNObjectId(input, &srcIdx, &oidSz, maxIdx);
if (ret != 0) {
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
!defined(WOLFCRYPT_ONLY)
wolfSSL_X509_NAME_free(dName);
#endif
return ret;
}
if ((srcIdx + sizeof(joint)) > (word32)maxIdx) {
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
!defined(WOLFCRYPT_ONLY)
wolfSSL_X509_NAME_free(dName);
#endif
return ASN_PARSE_E;
}
XMEMCPY(joint, &input[srcIdx], sizeof(joint));
if (joint[0] == 0x55 && joint[1] == 0x04) {
srcIdx += 3;
id = joint[2];
if (GetHeader(input, &b, &srcIdx, &strLen, maxIdx, 1) < 0) {
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
!defined(WOLFCRYPT_ONLY)
wolfSSL_X509_NAME_free(dName);
#endif
return ASN_PARSE_E;
}
#ifndef WOLFSSL_NO_ASN_STRICT
if (strLen < 1) {
WOLFSSL_MSG("Non conforming DirectoryString of length 0 was"
" found");
WOLFSSL_MSG("Use WOLFSSL_NO_ASN_STRICT if wanting to allow"
" empty DirectoryString's");
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
!defined(WOLFCRYPT_ONLY)
wolfSSL_X509_NAME_free(dName);
#endif
return ASN_PARSE_E;
}
#endif
if (id == ASN_COMMON_NAME) {
if (nameType == ASN_SUBJECT) {
cert->subjectCN = (char *)&input[srcIdx];
cert->subjectCNLen = strLen;
cert->subjectCNEnc = (char)b;
}
#if (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)) && \
defined(WOLFSSL_HAVE_ISSUER_NAMES)
else if (nameType == ASN_ISSUER) {
cert->issuerCN = (char*)&input[srcIdx];
cert->issuerCNLen = strLen;
cert->issuerCNEnc = (char)b;
}
#endif
copy = WOLFSSL_COMMON_NAME;
copyLen = sizeof(WOLFSSL_COMMON_NAME) - 1;
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_commonName;
#endif
}
#ifdef WOLFSSL_CERT_NAME_ALL
else if (id == ASN_NAME) {
copy = WOLFSSL_NAME;
copyLen = sizeof(WOLFSSL_NAME) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectN = (char*)&input[srcIdx];
cert->subjectNLen = strLen;
cert->subjectNEnc = b;
}
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_name;
#endif
}
else if (id == ASN_INITIALS) {
copy = WOLFSSL_INITIALS;
copyLen = sizeof(WOLFSSL_INITIALS) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectI = (char*)&input[srcIdx];
cert->subjectILen = strLen;
cert->subjectIEnc = b;
}
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_initials;
#endif
}
else if (id == ASN_GIVEN_NAME) {
copy = WOLFSSL_GIVEN_NAME;
copyLen = sizeof(WOLFSSL_GIVEN_NAME) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectGN = (char*)&input[srcIdx];
cert->subjectGNLen = strLen;
cert->subjectGNEnc = b;
}
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_givenName;
#endif
}
else if (id == ASN_DNQUALIFIER) {
copy = WOLFSSL_DNQUALIFIER;
copyLen = sizeof(WOLFSSL_DNQUALIFIER) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectDNQ = (char*)&input[srcIdx];
cert->subjectDNQLen = strLen;
cert->subjectDNQEnc = b;
}
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_dnQualifier;
#endif
}
#endif
else if (id == ASN_SUR_NAME) {
copy = WOLFSSL_SUR_NAME;
copyLen = sizeof(WOLFSSL_SUR_NAME) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectSN = (char*)&input[srcIdx];
cert->subjectSNLen = strLen;
cert->subjectSNEnc = (char)b;
}
#if defined(WOLFSSL_HAVE_ISSUER_NAMES)
else if (nameType == ASN_ISSUER) {
cert->issuerSN = (char*)&input[srcIdx];
cert->issuerSNLen = strLen;
cert->issuerSNEnc = (char)b;
}
#endif
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_surname;
#endif
}
else if (id == ASN_COUNTRY_NAME) {
copy = WOLFSSL_COUNTRY_NAME;
copyLen = sizeof(WOLFSSL_COUNTRY_NAME) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectC = (char*)&input[srcIdx];
cert->subjectCLen = strLen;
cert->subjectCEnc = (char)b;
}
#if defined(WOLFSSL_HAVE_ISSUER_NAMES)
else if (nameType == ASN_ISSUER) {
cert->issuerC = (char*)&input[srcIdx];
cert->issuerCLen = strLen;
cert->issuerCEnc = (char)b;
}
#endif
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_countryName;
#endif
}
else if (id == ASN_LOCALITY_NAME) {
copy = WOLFSSL_LOCALITY_NAME;
copyLen = sizeof(WOLFSSL_LOCALITY_NAME) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectL = (char*)&input[srcIdx];
cert->subjectLLen = strLen;
cert->subjectLEnc = (char)b;
}
#if defined(WOLFSSL_HAVE_ISSUER_NAMES)
else if (nameType == ASN_ISSUER) {
cert->issuerL = (char*)&input[srcIdx];
cert->issuerLLen = strLen;
cert->issuerLEnc = (char)b;
}
#endif
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_localityName;
#endif
}
else if (id == ASN_STATE_NAME) {
copy = WOLFSSL_STATE_NAME;
copyLen = sizeof(WOLFSSL_STATE_NAME) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectST = (char*)&input[srcIdx];
cert->subjectSTLen = strLen;
cert->subjectSTEnc = (char)b;
}
#if defined(WOLFSSL_HAVE_ISSUER_NAMES)
else if (nameType == ASN_ISSUER) {
cert->issuerST = (char*)&input[srcIdx];
cert->issuerSTLen = strLen;
cert->issuerSTEnc = (char)b;
}
#endif
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_stateOrProvinceName;
#endif
}
else if (id == ASN_ORG_NAME) {
copy = WOLFSSL_ORG_NAME;
copyLen = sizeof(WOLFSSL_ORG_NAME) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectO = (char*)&input[srcIdx];
cert->subjectOLen = strLen;
cert->subjectOEnc = (char)b;
}
#if defined(WOLFSSL_HAVE_ISSUER_NAMES)
else if (nameType == ASN_ISSUER) {
cert->issuerO = (char*)&input[srcIdx];
cert->issuerOLen = strLen;
cert->issuerOEnc = (char)b;
}
#endif
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_organizationName;
#endif
}
else if (id == ASN_ORGUNIT_NAME) {
copy = WOLFSSL_ORGUNIT_NAME;
copyLen = sizeof(WOLFSSL_ORGUNIT_NAME) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectOU = (char*)&input[srcIdx];
cert->subjectOULen = strLen;
cert->subjectOUEnc = (char)b;
}
#if defined(WOLFSSL_HAVE_ISSUER_NAMES)
else if (nameType == ASN_ISSUER) {
cert->issuerOU = (char*)&input[srcIdx];
cert->issuerOULen = strLen;
cert->issuerOUEnc = (char)b;
}
#endif
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_organizationalUnitName;
#endif
}
else if (id == ASN_SERIAL_NUMBER) {
copy = WOLFSSL_SERIAL_NUMBER;
copyLen = sizeof(WOLFSSL_SERIAL_NUMBER) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectSND = (char*)&input[srcIdx];
cert->subjectSNDLen = strLen;
cert->subjectSNDEnc = (char)b;
}
#if defined(WOLFSSL_HAVE_ISSUER_NAMES)
else if (nameType == ASN_ISSUER) {
cert->issuerSND = (char*)&input[srcIdx];
cert->issuerSNDLen = strLen;
cert->issuerSNDEnc = (char)b;
}
#endif
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_serialNumber;
#endif
}
else if (id == ASN_USER_ID) {
copy = WOLFSSL_USER_ID;
copyLen = sizeof(WOLFSSL_USER_ID) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectUID = (char*)&input[srcIdx];
cert->subjectUIDLen = strLen;
cert->subjectUIDEnc = (char)b;
}
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_userId;
#endif
}
#ifdef WOLFSSL_CERT_EXT
else if (id == ASN_STREET_ADDR) {
copy = WOLFSSL_STREET_ADDR_NAME;
copyLen = sizeof(WOLFSSL_STREET_ADDR_NAME) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectStreet = (char*)&input[srcIdx];
cert->subjectStreetLen = strLen;
cert->subjectStreetEnc = (char)b;
}
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_streetAddress;
#endif
}
else if (id == ASN_BUS_CAT) {
copy = WOLFSSL_BUS_CAT;
copyLen = sizeof(WOLFSSL_BUS_CAT) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectBC = (char*)&input[srcIdx];
cert->subjectBCLen = strLen;
cert->subjectBCEnc = (char)b;
}
#endif
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_businessCategory;
#endif
}
else if (id == ASN_POSTAL_CODE) {
copy = WOLFSSL_POSTAL_NAME;
copyLen = sizeof(WOLFSSL_POSTAL_NAME) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectPC = (char*)&input[srcIdx];
cert->subjectPCLen = strLen;
cert->subjectPCEnc = (char)b;
}
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_postalCode;
#endif
}
#endif
}
#ifdef WOLFSSL_CERT_EXT
else if ((srcIdx + ASN_JOI_PREFIX_SZ + 2 <= (word32)maxIdx) &&
(0 == XMEMCMP(&input[srcIdx], ASN_JOI_PREFIX,
ASN_JOI_PREFIX_SZ)) &&
((input[srcIdx+ASN_JOI_PREFIX_SZ] == ASN_JOI_C) ||
(input[srcIdx+ASN_JOI_PREFIX_SZ] == ASN_JOI_ST)))
{
srcIdx += ASN_JOI_PREFIX_SZ;
id = input[srcIdx++];
b = input[srcIdx++];
if (GetLength(input, &srcIdx, &strLen,
maxIdx) < 0) {
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
!defined(WOLFCRYPT_ONLY)
wolfSSL_X509_NAME_free(dName);
#endif
return ASN_PARSE_E;
}
if (id == ASN_JOI_C) {
copy = WOLFSSL_JOI_C;
copyLen = sizeof(WOLFSSL_JOI_C) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectJC = (char*)&input[srcIdx];
cert->subjectJCLen = strLen;
cert->subjectJCEnc = (char)b;
}
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_jurisdictionCountryName;
#endif
}
else if (id == ASN_JOI_ST) {
copy = WOLFSSL_JOI_ST;
copyLen = sizeof(WOLFSSL_JOI_ST) - 1;
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectJS = (char*)&input[srcIdx];
cert->subjectJSLen = strLen;
cert->subjectJSEnc = (char)b;
}
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_jurisdictionStateOrProvinceName;
#endif
}
if ((strLen + copyLen) > (int)(WC_ASN_NAME_MAX - idx)) {
WOLFSSL_MSG("ASN Name too big, skipping");
tooBig = TRUE;
}
}
#endif
else {
byte email = FALSE;
byte pilot = FALSE;
if (joint[0] == 0x2a && joint[1] == 0x86) {
id = ASN_EMAIL_NAME;
email = TRUE;
}
if (joint[0] == 0x9 && joint[1] == 0x92) {
id = input[srcIdx + (word32)oidSz - 1];
if (id == 0x01)
id = ASN_USER_ID;
pilot = TRUE;
}
srcIdx += (word32)oidSz + 1;
if (GetLength(input, &srcIdx, &strLen, maxIdx) < 0) {
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
!defined(WOLFCRYPT_ONLY)
wolfSSL_X509_NAME_free(dName);
#endif
return ASN_PARSE_E;
}
if (strLen > (int)(WC_ASN_NAME_MAX - idx)) {
WOLFSSL_MSG("ASN name too big, skipping");
tooBig = TRUE;
}
if (email) {
copyLen = sizeof(WOLFSSL_EMAIL_ADDR) - 1;
if ((copyLen + strLen) > (int)(WC_ASN_NAME_MAX - idx)) {
WOLFSSL_MSG("ASN name too big, skipping");
tooBig = TRUE;
}
else {
copy = WOLFSSL_EMAIL_ADDR;
}
#if !defined(IGNORE_NAME_CONSTRAINTS) || \
defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)
if (nameType == ASN_SUBJECT) {
cert->subjectEmail = (char*)&input[srcIdx];
cert->subjectEmailLen = strLen;
}
#if defined(WOLFSSL_HAVE_ISSUER_NAMES) && \
(defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT))
else if (nameType == ASN_ISSUER) {
cert->issuerEmail = (char*)&input[srcIdx];
cert->issuerEmailLen = strLen;
}
#endif
#endif
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_emailAddress;
#endif
}
if (pilot) {
switch (id) {
case ASN_USER_ID:
copy = WOLFSSL_USER_ID;
copyLen = sizeof(WOLFSSL_USER_ID) - 1;
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_userId;
#endif
break;
case ASN_DOMAIN_COMPONENT:
copy = WOLFSSL_DOMAIN_COMPONENT;
copyLen = sizeof(WOLFSSL_DOMAIN_COMPONENT) - 1;
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_domainComponent;
#endif
break;
case ASN_RFC822_MAILBOX:
copy = WOLFSSL_RFC822_MAILBOX;
copyLen = sizeof(WOLFSSL_RFC822_MAILBOX) - 1;
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_rfc822Mailbox;
#endif
break;
case ASN_FAVOURITE_DRINK:
copy = WOLFSSL_FAVOURITE_DRINK;
copyLen = sizeof(WOLFSSL_FAVOURITE_DRINK) - 1;
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_favouriteDrink;
#endif
break;
case ASN_CONTENT_TYPE:
copy = WOLFSSL_CONTENT_TYPE;
copyLen = sizeof(WOLFSSL_CONTENT_TYPE) - 1;
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
nid = WC_NID_pkcs9_contentType;
#endif
break;
default:
WOLFSSL_MSG("Unknown pilot attribute type");
#if (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL)) && \
!defined(WOLFCRYPT_ONLY)
wolfSSL_X509_NAME_free(dName);
#endif
return ASN_PARSE_E;
}
}
}
if ((copyLen + strLen) > (int)(WC_ASN_NAME_MAX - idx))
{
WOLFSSL_MSG("ASN Name too big, skipping");
tooBig = TRUE;
}
if ((copy != NULL) && !tooBig) {
XMEMCPY(&full[idx], copy, (size_t)copyLen);
idx += (word32)copyLen;
XMEMCPY(&full[idx], &input[srcIdx], (size_t)strLen);
idx += (word32)strLen;
}
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
!defined(WOLFCRYPT_ONLY)
switch (b) {
case CTC_UTF8:
enc = WOLFSSL_MBSTRING_UTF8;
break;
case CTC_PRINTABLE:
enc = WOLFSSL_V_ASN1_PRINTABLESTRING;
break;
default:
WOLFSSL_MSG("Unknown encoding type, using UTF8 by default");
enc = WOLFSSL_MBSTRING_UTF8;
}
if (nid != WC_NID_undef) {
if (wolfSSL_X509_NAME_add_entry_by_NID(dName, nid, enc,
&input[srcIdx], strLen, -1, -1) !=
WOLFSSL_SUCCESS) {
wolfSSL_X509_NAME_free(dName);
return ASN_PARSE_E;
}
}
#endif
srcIdx += (word32)strLen;
}
full[idx++] = 0;
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
!defined(WOLFCRYPT_ONLY)
if (nameType == ASN_ISSUER) {
#if (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY)) &&\
(defined(HAVE_PKCS7) || defined(WOLFSSL_CERT_EXT))
dName->rawLen = min(cert->issuerRawLen, WC_ASN_NAME_MAX);
XMEMCPY(dName->raw, cert->issuerRaw, dName->rawLen);
#endif
cert->issuerName = dName;
}
else {
#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
dName->rawLen = min(cert->subjectRawLen, WC_ASN_NAME_MAX);
XMEMCPY(dName->raw, cert->subjectRaw, dName->rawLen);
#endif
cert->subjectName = dName;
}
#endif
*inOutIdx = srcIdx;
return 0;
}
int GetName(DecodedCert* cert, int nameType, int maxIdx)
{
char* full;
byte* hash;
int length;
word32 localIdx;
byte tag;
WOLFSSL_MSG("Getting Name");
if (nameType == ASN_ISSUER) {
full = cert->issuer;
hash = cert->issuerHash;
}
else {
full = cert->subject;
hash = cert->subjectHash;
}
if (cert->srcIdx >= (word32)maxIdx) {
return BUFFER_E;
}
localIdx = cert->srcIdx;
if (GetASNTag(cert->source, &localIdx, &tag, (word32)maxIdx) < 0) {
return ASN_PARSE_E;
}
if (tag == ASN_OBJECT_ID) {
WOLFSSL_MSG("Trying optional prefix...");
if (SkipObjectId(cert->source, &cert->srcIdx, (word32)maxIdx) < 0)
return ASN_PARSE_E;
WOLFSSL_MSG("Got optional prefix");
}
localIdx = cert->srcIdx;
if (GetASNTag(cert->source, &localIdx, &tag, (word32)maxIdx) < 0) {
return ASN_PARSE_E;
}
localIdx = cert->srcIdx + 1;
if (GetLength(cert->source, &localIdx, &length, (word32)maxIdx) < 0) {
return ASN_PARSE_E;
}
length += (int)(localIdx - cert->srcIdx);
return GetCertName(cert, full, hash, nameType, cert->source, &cert->srcIdx,
cert->srcIdx + (word32)length);
}
static int GetDateInfo(const byte* source, word32* idx, const byte** pDate,
byte* pFormat, int* pLength, word32 maxIdx)
{
int length;
byte format;
if (source == NULL || idx == NULL)
return BAD_FUNC_ARG;
if (*idx+1 > maxIdx)
return BUFFER_E;
format = source[*idx];
*idx += 1;
if (format != ASN_UTC_TIME && format != ASN_GENERALIZED_TIME) {
WOLFSSL_ERROR_VERBOSE(ASN_TIME_E);
return ASN_TIME_E;
}
if (GetLength(source, idx, &length, maxIdx) < 0)
return ASN_PARSE_E;
if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE)
return ASN_DATE_SZ_E;
if (pFormat)
*pFormat = format;
if (pDate)
*pDate = &source[*idx];
if (pLength)
*pLength = length;
*idx += (word32)length;
return 0;
}
#ifndef NO_CERTS
static int GetDate(DecodedCert* cert, int dateType, int verify, int maxIdx)
{
int ret, length;
const byte *datePtr = NULL;
byte date[MAX_DATE_SIZE];
byte format;
word32 startIdx = 0;
if (dateType == ASN_BEFORE)
cert->beforeDate = &cert->source[cert->srcIdx];
else
cert->afterDate = &cert->source[cert->srcIdx];
startIdx = cert->srcIdx;
ret = GetDateInfo(cert->source, &cert->srcIdx, &datePtr, &format,
&length, (word32)maxIdx);
if (ret < 0)
return ret;
XMEMSET(date, 0, MAX_DATE_SIZE);
XMEMCPY(date, datePtr, (size_t)length);
if (dateType == ASN_BEFORE)
cert->beforeDateLen = (int)(cert->srcIdx - startIdx);
else
cert->afterDateLen = (int)(cert->srcIdx - startIdx);
#ifndef NO_ASN_TIME_CHECK
if (verify != NO_VERIFY && verify != VERIFY_SKIP_DATE &&
(! AsnSkipDateCheck) &&
!XVALIDATE_DATE(date, format, dateType, length)) {
if (dateType == ASN_BEFORE) {
WOLFSSL_ERROR_VERBOSE(ASN_BEFORE_DATE_E);
return ASN_BEFORE_DATE_E;
}
else {
WOLFSSL_ERROR_VERBOSE(ASN_AFTER_DATE_E);
return ASN_AFTER_DATE_E;
}
}
#else
(void)verify;
#endif
return 0;
}
static int GetValidity(DecodedCert* cert, int verify, int maxIdx)
{
int length;
int badDate = 0;
if (GetSequence(cert->source, &cert->srcIdx, &length, (word32)maxIdx) < 0)
return ASN_PARSE_E;
maxIdx = (int)cert->srcIdx + length;
if (GetDate(cert, ASN_BEFORE, verify, maxIdx) < 0)
badDate = ASN_BEFORE_DATE_E;
if (GetDate(cert, ASN_AFTER, verify, maxIdx) < 0)
return ASN_AFTER_DATE_E;
if (badDate != 0)
return badDate;
return 0;
}
#endif
#ifndef NO_CERTS
static int GetSigAlg(DecodedCert* cert, word32* sigOid, word32 maxIdx)
{
int length;
word32 endSeqIdx;
if (GetSequence(cert->source, &cert->srcIdx, &length, maxIdx) < 0)
return ASN_PARSE_E;
endSeqIdx = cert->srcIdx + (word32)length;
if (GetObjectId(cert->source, &cert->srcIdx, sigOid, oidSigType,
maxIdx) < 0) {
return ASN_OBJECT_ID_E;
}
if (cert->srcIdx != endSeqIdx) {
#ifdef WC_RSA_PSS
if (*sigOid == CTC_RSASSAPSS) {
word32 tmpIdx = cert->srcIdx;
byte tag;
int len;
WOLFSSL_MSG("Cert sigAlg is RSASSA-PSS; decoding params");
if (GetHeader(cert->source, &tag, &tmpIdx, &len, endSeqIdx, 0) < 0) {
return ASN_PARSE_E;
}
cert->sigParamsIndex = cert->srcIdx;
cert->sigParamsLength = (word32)((tmpIdx - cert->srcIdx) + len);
}
else
#endif
if (endSeqIdx - cert->srcIdx != 2)
return ASN_PARSE_E;
else {
byte tag;
if (GetASNTag(cert->source, &cert->srcIdx, &tag, endSeqIdx) != 0)
return ASN_PARSE_E;
if (tag != ASN_TAG_NULL)
return ASN_PARSE_E;
}
}
cert->srcIdx = endSeqIdx;
return 0;
}
#endif
#ifndef NO_CERTS
int wc_GetPubX509(DecodedCert* cert, int verify, int* badDate)
{
int ret;
if (cert == NULL || badDate == NULL)
return BAD_FUNC_ARG;
*badDate = 0;
if ( (ret = GetCertHeader(cert)) < 0)
return ret;
WOLFSSL_MSG("Got Cert Header");
#ifdef WOLFSSL_CERT_REQ
if (!cert->isCSR) {
#endif
if ((ret = GetSigAlg(cert, &cert->signatureOID, cert->sigIndex)) < 0)
return ret;
WOLFSSL_MSG("Got Algo ID");
if ( (ret = GetName(cert, ASN_ISSUER, (int)cert->sigIndex)) < 0)
return ret;
if ( (ret = GetValidity(cert, verify, (int)cert->sigIndex)) < 0)
*badDate = ret;
#ifdef WOLFSSL_CERT_REQ
}
#endif
if ( (ret = GetName(cert, ASN_SUBJECT, (int)cert->sigIndex)) < 0)
return ret;
WOLFSSL_MSG("Got Subject Name");
return ret;
}
int DecodeToKey(DecodedCert* cert, int verify)
{
int badDate = 0;
int ret;
#if defined(HAVE_RPK)
ret = GetCertKey(cert, cert->source, &cert->srcIdx, cert->maxIdx);
if (ret == 0) {
WOLFSSL_MSG("Raw Public Key certificate found and parsed");
cert->isRPK = 1;
return ret;
}
#endif
if ( (ret = wc_GetPubX509(cert, verify, &badDate)) < 0)
return ret;
#ifdef WOLFSSL_CERT_REQ
if (cert->isCSR)
cert->selfSigned = 1;
else
#endif
{
cert->selfSigned = XMEMCMP(cert->issuerHash, cert->subjectHash,
KEYID_SIZE) == 0 ? 1 : 0;
}
ret = GetCertKey(cert, cert->source, &cert->srcIdx, cert->maxIdx);
if (ret != 0)
return ret;
WOLFSSL_MSG("Got Key");
if (badDate != 0)
return badDate;
return ret;
}
static int GetSignature(DecodedCert* cert)
{
int length;
int ret;
ret = CheckBitString(cert->source, &cert->srcIdx, &length, cert->maxIdx, 1,
NULL);
if (ret != 0)
return ret;
cert->sigLength = (word32)length;
cert->signature = &cert->source[cert->srcIdx];
cert->srcIdx += cert->sigLength;
if (cert->srcIdx != cert->maxIdx)
return ASN_PARSE_E;
return 0;
}
#endif
static word32 SetOctetString8Bit(word32 len, byte* output)
{
output[0] = ASN_OCTET_STRING;
output[1] = (byte)len;
return 2;
}
static word32 SetDigest(const byte* digest, word32 digSz, byte* output)
{
word32 idx = SetOctetString8Bit(digSz, output);
XMEMCPY(&output[idx], digest, digSz);
return idx + digSz;
}
static word32 SetAlgoIDImpl(int algoOID, byte* output, int type, int curveSz,
byte absentParams)
{
word32 tagSz, idSz, seqSz, algoSz = 0;
const byte* algoName = 0;
byte ID_Length[1 + MAX_LENGTH_SZ];
byte seqArray[MAX_SEQ_SZ + 1];
word32 length = 0;
tagSz = ((type == oidHashType ||
(type == oidSigType && !IsSigAlgoECC((word32)algoOID)) ||
(type == oidKeyType && algoOID == RSAk)) &&
(absentParams == FALSE)) ? 2U : 0U;
algoName = OidFromId((word32)algoOID, (word32)type, &algoSz);
if (algoName == NULL) {
WOLFSSL_MSG("Unknown Algorithm");
return 0;
}
idSz = (word32)SetObjectId((int)algoSz, ID_Length);
seqSz = SetSequence(idSz + algoSz + tagSz + (word32)curveSz, seqArray);
if (algoOID == DSAk && output) {
XMEMCPY(output, ID_Length, idSz);
XMEMCPY(output + idSz, algoName, algoSz);
if (tagSz == 2)
SetASNNull(&output[seqSz + idSz + algoSz]);
}
else if (output) {
XMEMCPY(output, seqArray, seqSz);
XMEMCPY(output + seqSz, ID_Length, idSz);
XMEMCPY(output + seqSz + idSz, algoName, algoSz);
if (tagSz == 2)
SetASNNull(&output[seqSz + idSz + algoSz]);
}
if (algoOID == DSAk)
length = idSz + algoSz + tagSz;
else
length = seqSz + idSz + algoSz + tagSz;
return length;
}
word32 wc_EncodeSignature(byte* out, const byte* digest, word32 digSz,
int hashOID)
{
byte digArray[MAX_ENCODED_DIG_SZ];
byte algoArray[MAX_ALGO_SZ];
byte seqArray[MAX_SEQ_SZ];
word32 encDigSz, algoSz, seqSz;
encDigSz = SetDigest(digest, digSz, digArray);
algoSz = SetAlgoID(hashOID, algoArray, oidHashType, 0);
seqSz = SetSequence(encDigSz + algoSz, seqArray);
XMEMCPY(out, seqArray, seqSz);
XMEMCPY(out + seqSz, algoArray, algoSz);
XMEMCPY(out + seqSz + algoSz, digArray, encDigSz);
return encDigSz + algoSz + seqSz;
}
#ifndef NO_CERTS
static void AddAltName(DecodedCert* cert, DNS_entry* dnsEntry)
{
#if (defined(WOLFSSL_ASN_ALL) || defined(OPENSSL_EXTRA)) && \
!defined(WOLFSSL_ALT_NAMES_NO_REV)
dnsEntry->next = NULL;
if (cert->altNames == NULL) {
cert->altNames = dnsEntry;
}
else {
DNS_entry* temp = cert->altNames;
for (; (temp->next != NULL); temp = temp->next);
temp->next = dnsEntry;
}
#else
dnsEntry->next = cert->altNames;
cert->altNames = dnsEntry;
#endif
}
#if defined(WOLFSSL_SEP)
static int DecodeSepHwAltName(DecodedCert* cert, const byte* input,
word32* idxIn, word32 sz)
{
word32 idx = *idxIn;
int strLen;
int ret;
byte tag;
if (cert->hwType != NULL) {
WOLFSSL_MSG("\tAlready seen Hardware Module Name");
return ASN_PARSE_E;
}
if (GetASNTag(input, &idx, &tag, sz) < 0) {
return ASN_PARSE_E;
}
if (tag != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) {
WOLFSSL_MSG("\twrong type");
return ASN_PARSE_E;
}
if (GetLength(input, &idx, &strLen, sz) < 0) {
WOLFSSL_MSG("\tfail: str len");
return ASN_PARSE_E;
}
if (GetSequence(input, &idx, &strLen, sz) < 0) {
WOLFSSL_MSG("\tBad Sequence");
return ASN_PARSE_E;
}
ret = GetASNObjectId(input, &idx, &strLen, sz);
if (ret != 0) {
WOLFSSL_MSG("\tbad OID");
return ret;
}
cert->hwType = (byte*)XMALLOC((size_t)strLen, cert->heap,
DYNAMIC_TYPE_X509_EXT);
if (cert->hwType == NULL) {
WOLFSSL_MSG("\tOut of Memory");
return MEMORY_E;
}
XMEMCPY(cert->hwType, &input[idx], (size_t)strLen);
cert->hwTypeSz = strLen;
idx += (word32)strLen;
ret = GetOctetString(input, &idx, &strLen, sz);
if (ret < 0) {
XFREE(cert->hwType, cert->heap, DYNAMIC_TYPE_X509_EXT);
cert->hwType = NULL;
return ret;
}
cert->hwSerialNum = (byte*)XMALLOC((size_t)strLen + 1, cert->heap,
DYNAMIC_TYPE_X509_EXT);
if (cert->hwSerialNum == NULL) {
WOLFSSL_MSG("\tOut of Memory");
XFREE(cert->hwType, cert->heap, DYNAMIC_TYPE_X509_EXT);
cert->hwType = NULL;
return MEMORY_E;
}
XMEMCPY(cert->hwSerialNum, &input[idx], (size_t)strLen);
cert->hwSerialNum[strLen] = '\0';
cert->hwSerialNumSz = strLen;
idx += (word32)strLen;
*idxIn = idx;
return 0;
}
#endif
static int DecodeConstructedOtherName(DecodedCert* cert, const byte* input,
word32* idx, word32 sz, int oid)
{
int ret = 0;
int strLen = 0;
byte tag;
DNS_entry* dnsEntry = NULL;
if (GetASNTag(input, idx, &tag, sz) < 0) {
ret = ASN_PARSE_E;
}
if (ret == 0 && (tag != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED))) {
ret = ASN_PARSE_E;
}
if (ret == 0 && (GetLength(input, idx, &strLen, sz) < 0)) {
ret = ASN_PARSE_E;
}
if (ret == 0) {
dnsEntry = AltNameNew(cert->heap);
if (dnsEntry == NULL) {
WOLFSSL_MSG("\tOut of Memory");
return MEMORY_E;
}
switch (oid) {
#ifdef WOLFSSL_FPKI
case FASCN_OID:
ret = GetOctetString(input, idx, &strLen, sz);
if (ret > 0) {
ret = 0;
}
break;
#endif
case UPN_OID:
if (GetASNTag(input, idx, &tag, sz) < 0) {
ret = ASN_PARSE_E;
}
if (ret == 0 &&
tag != ASN_PRINTABLE_STRING && tag != ASN_UTF8STRING &&
tag != ASN_IA5_STRING) {
WOLFSSL_MSG("Was expecting a string for UPN");
ret = ASN_PARSE_E;
}
if (ret == 0 && (GetLength(input, idx, &strLen, sz) < 0)) {
WOLFSSL_MSG("Was expecting a string for UPN");
ret = ASN_PARSE_E;
}
break;
default:
WOLFSSL_MSG("Unknown constructed other name, skipping");
XFREE(dnsEntry, cert->heap, DYNAMIC_TYPE_ALTNAME);
dnsEntry = NULL;
}
}
if (ret == 0 && dnsEntry != NULL) {
dnsEntry->type = ASN_OTHER_TYPE;
dnsEntry->len = strLen;
dnsEntry->name = (char*)XMALLOC((size_t)strLen + 1, cert->heap,
DYNAMIC_TYPE_ALTNAME);
#ifdef WOLFSSL_FPKI
dnsEntry->oidSum = oid;
#endif
if (dnsEntry->name == NULL) {
WOLFSSL_MSG("\tOut of Memory");
ret = MEMORY_E;
}
else {
dnsEntry->nameStored = 1;
XMEMCPY((void *)(wc_ptr_t)dnsEntry->name, &input[*idx],
(size_t)strLen);
((char *)(wc_ptr_t)dnsEntry->name)[strLen] = '\0';
AddAltName(cert, dnsEntry);
}
}
if (ret == 0) {
*idx += (word32)strLen;
}
else {
XFREE(dnsEntry, cert->heap, DYNAMIC_TYPE_ALTNAME);
}
return ret;
}
static int DecodeAltNames(const byte* input, word32 sz, DecodedCert* cert)
{
word32 idx = 0;
int length = 0;
word32 numNames = 0;
WOLFSSL_ENTER("DecodeAltNames");
if (GetSequence(input, &idx, &length, sz) < 0) {
WOLFSSL_MSG("\tBad Sequence");
return ASN_PARSE_E;
}
if (length == 0) {
WOLFSSL_ERROR_VERBOSE(ASN_PARSE_E);
return ASN_PARSE_E;
}
#ifdef OPENSSL_ALL
cert->extSubjAltNameSrc = input;
cert->extSubjAltNameSz = sz;
#endif
cert->weOwnAltNames = 1;
while (length > 0) {
byte current_byte;
if (idx >= (word32)sz) {
WOLFSSL_MSG("\tBad Index");
return BUFFER_E;
}
numNames++;
if (numNames > WOLFSSL_MAX_ALT_NAMES) {
WOLFSSL_MSG("\tToo many subject alternative names");
return ASN_ALT_NAME_E;
}
current_byte = input[idx++];
length--;
if (current_byte == (ASN_CONTEXT_SPECIFIC | ASN_DNS_TYPE)) {
DNS_entry* dnsEntry;
int strLen;
word32 lenStartIdx = idx;
if (GetLength(input, &idx, &strLen, sz) < 0) {
WOLFSSL_MSG("\tfail: str length");
return ASN_PARSE_E;
}
length -= (int)(idx - lenStartIdx);
dnsEntry = AltNameNew(cert->heap);
if (dnsEntry == NULL) {
WOLFSSL_MSG("\tOut of Memory");
return MEMORY_E;
}
dnsEntry->type = ASN_DNS_TYPE;
dnsEntry->name = (char*)XMALLOC((size_t)strLen + 1, cert->heap,
DYNAMIC_TYPE_ALTNAME);
if (dnsEntry->name == NULL) {
WOLFSSL_MSG("\tOut of Memory");
XFREE(dnsEntry, cert->heap, DYNAMIC_TYPE_ALTNAME);
return MEMORY_E;
}
dnsEntry->nameStored = 1;
dnsEntry->len = strLen;
XMEMCPY((void *)(wc_ptr_t)dnsEntry->name, &input[idx],
(size_t)strLen);
((char *)(wc_ptr_t)dnsEntry->name)[strLen] = '\0';
AddAltName(cert, dnsEntry);
if (strLen > length) {
return ASN_PARSE_E;
}
length -= strLen;
idx += (word32)strLen;
}
#ifndef IGNORE_NAME_CONSTRAINTS
else if (current_byte ==
(ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | ASN_DIR_TYPE)) {
DNS_entry* dirEntry;
int strLen;
word32 lenStartIdx = idx;
if (GetLength(input, &idx, &strLen, sz) < 0) {
WOLFSSL_MSG("\tfail: str length");
return ASN_PARSE_E;
}
if (GetSequence(input, &idx, &strLen, sz) < 0) {
WOLFSSL_MSG("\tfail: seq length");
return ASN_PARSE_E;
}
length -= (int)(idx - lenStartIdx);
dirEntry = AltNameNew(cert->heap);
if (dirEntry == NULL) {
WOLFSSL_MSG("\tOut of Memory");
return MEMORY_E;
}
dirEntry->type = ASN_DIR_TYPE;
dirEntry->name = (char*)XMALLOC((size_t)strLen + 1, cert->heap,
DYNAMIC_TYPE_ALTNAME);
if (dirEntry->name == NULL) {
WOLFSSL_MSG("\tOut of Memory");
XFREE(dirEntry, cert->heap, DYNAMIC_TYPE_ALTNAME);
return MEMORY_E;
}
dirEntry->nameStored = 1;
dirEntry->len = strLen;
XMEMCPY((void *)(wc_ptr_t)dirEntry->name, &input[idx],
(size_t)strLen);
((char *)(wc_ptr_t)dirEntry->name)[strLen] = '\0';
dirEntry->next = cert->altDirNames;
cert->altDirNames = dirEntry;
if (strLen > length) {
return ASN_PARSE_E;
}
length -= strLen;
idx += (word32)strLen;
}
else if (current_byte == (ASN_CONTEXT_SPECIFIC | ASN_RFC822_TYPE)) {
DNS_entry* emailEntry;
int strLen;
word32 lenStartIdx = idx;
if (GetLength(input, &idx, &strLen, sz) < 0) {
WOLFSSL_MSG("\tfail: str length");
return ASN_PARSE_E;
}
length -= (int)(idx - lenStartIdx);
emailEntry = AltNameNew(cert->heap);
if (emailEntry == NULL) {
WOLFSSL_MSG("\tOut of Memory");
return MEMORY_E;
}
emailEntry->nameStored = 1;
emailEntry->type = ASN_RFC822_TYPE;
emailEntry->name = (char*)XMALLOC((size_t)strLen + 1, cert->heap,
DYNAMIC_TYPE_ALTNAME);
if (emailEntry->name == NULL) {
WOLFSSL_MSG("\tOut of Memory");
XFREE(emailEntry, cert->heap, DYNAMIC_TYPE_ALTNAME);
return MEMORY_E;
}
emailEntry->len = strLen;
XMEMCPY((void *)(wc_ptr_t)emailEntry->name, &input[idx],
(size_t)strLen);
((char *)(wc_ptr_t)emailEntry->name)[strLen] = '\0';
emailEntry->next = cert->altEmailNames;
cert->altEmailNames = emailEntry;
if (strLen > length) {
return ASN_PARSE_E;
}
length -= strLen;
idx += (word32)strLen;
}
else if (current_byte == (ASN_CONTEXT_SPECIFIC | ASN_URI_TYPE)) {
DNS_entry* uriEntry;
int strLen;
word32 lenStartIdx = idx;
WOLFSSL_MSG("\tPutting URI into list but not using");
if (GetLength(input, &idx, &strLen, sz) < 0) {
WOLFSSL_MSG("\tfail: str length");
return ASN_PARSE_E;
}
length -= (int)(idx - lenStartIdx);
if ((word32)strLen + idx > sz) {
return BUFFER_E;
}
#if !defined(WOLFSSL_NO_ASN_STRICT) && !defined(WOLFSSL_FPKI)
{
word32 i;
for (i = 0; i < (word32)strLen; i++) {
if (input[idx + i] == ':') {
break;
}
if (input[idx + i] == '/') {
WOLFSSL_MSG("\tAlt Name must be absolute URI");
WOLFSSL_ERROR_VERBOSE(ASN_ALT_NAME_E);
return ASN_ALT_NAME_E;
}
}
if (i == 0 || i == (word32)strLen) {
WOLFSSL_MSG("\tEmpty or malformed URI");
WOLFSSL_ERROR_VERBOSE(ASN_ALT_NAME_E);
return ASN_ALT_NAME_E;
}
if (input[idx + i] != ':') {
WOLFSSL_MSG("\tAlt Name must be absolute URI");
WOLFSSL_ERROR_VERBOSE(ASN_ALT_NAME_E);
return ASN_ALT_NAME_E;
}
}
#endif
uriEntry = AltNameNew(cert->heap);
if (uriEntry == NULL) {
WOLFSSL_MSG("\tOut of Memory");
return MEMORY_E;
}
uriEntry->nameStored = 1;
uriEntry->type = ASN_URI_TYPE;
uriEntry->name = (char*)XMALLOC((size_t)strLen + 1, cert->heap,
DYNAMIC_TYPE_ALTNAME);
if (uriEntry->name == NULL) {
WOLFSSL_MSG("\tOut of Memory");
XFREE(uriEntry, cert->heap, DYNAMIC_TYPE_ALTNAME);
return MEMORY_E;
}
uriEntry->len = strLen;
XMEMCPY((void *)(wc_ptr_t)uriEntry->name, &input[idx],
(size_t)strLen);
((char *)(wc_ptr_t)uriEntry->name)[strLen] = '\0';
AddAltName(cert, uriEntry);
if (strLen > length) {
return ASN_PARSE_E;
}
length -= strLen;
idx += (word32)strLen;
}
#ifdef WOLFSSL_IP_ALT_NAME
else if (current_byte == (ASN_CONTEXT_SPECIFIC | ASN_IP_TYPE)) {
DNS_entry* ipAddr;
int strLen;
word32 lenStartIdx = idx;
WOLFSSL_MSG("Decoding Subject Alt. Name: IP Address");
if (GetLength(input, &idx, &strLen, sz) < 0) {
WOLFSSL_MSG("\tfail: str length");
return ASN_PARSE_E;
}
length -= (idx - lenStartIdx);
if (strLen + idx > sz) {
return BUFFER_E;
}
ipAddr = AltNameNew(cert->heap);
if (ipAddr == NULL) {
WOLFSSL_MSG("\tOut of Memory");
return MEMORY_E;
}
ipAddr->nameStored = 1;
ipAddr->type = ASN_IP_TYPE;
ipAddr->name = (char*)XMALLOC((size_t)strLen + 1, cert->heap,
DYNAMIC_TYPE_ALTNAME);
if (ipAddr->name == NULL) {
WOLFSSL_MSG("\tOut of Memory");
XFREE(ipAddr, cert->heap, DYNAMIC_TYPE_ALTNAME);
return MEMORY_E;
}
ipAddr->len = strLen;
XMEMCPY((void *)(wc_ptr_t)ipAddr->name, &input[idx], strLen);
((char *)(wc_ptr_t)ipAddr->name)[strLen] = '\0';
if (GenerateDNSEntryIPString(ipAddr, cert->heap) != 0) {
WOLFSSL_MSG("\tOut of Memory for IP string");
XFREE((void *)(wc_ptr_t)ipAddr->name, cert->heap,
DYNAMIC_TYPE_ALTNAME);
XFREE(ipAddr, cert->heap, DYNAMIC_TYPE_ALTNAME);
return MEMORY_E;
}
AddAltName(cert, ipAddr);
if (strLen > length) {
return ASN_PARSE_E;
}
length -= strLen;
idx += (word32)strLen;
}
#endif
#ifdef WOLFSSL_RID_ALT_NAME
else if (current_byte == (ASN_CONTEXT_SPECIFIC | ASN_RID_TYPE)) {
DNS_entry* rid;
int strLen;
word32 lenStartIdx = idx;
WOLFSSL_MSG("Decoding Subject Alt. Name: Registered Id");
if (GetLength(input, &idx, &strLen, sz) < 0) {
WOLFSSL_MSG("\tfail: str length");
return ASN_PARSE_E;
}
length -= (idx - lenStartIdx);
if (strLen + idx > sz) {
return BUFFER_E;
}
rid = AltNameNew(cert->heap);
if (rid == NULL) {
WOLFSSL_MSG("\tOut of Memory");
return MEMORY_E;
}
rid->type = ASN_RID_TYPE;
rid->name = (char*)XMALLOC((size_t)strLen + 1, cert->heap,
DYNAMIC_TYPE_ALTNAME);
if (rid->name == NULL) {
WOLFSSL_MSG("\tOut of Memory");
XFREE(rid, cert->heap, DYNAMIC_TYPE_ALTNAME);
return MEMORY_E;
}
rid->nameStored = 1;
rid->len = strLen;
XMEMCPY((void *)(wc_ptr_t)rid->name, &input[idx], strLen);
((char *)(wc_ptr_t)rid->name)[strLen] = '\0';
if (GenerateDNSEntryRIDString(rid, cert->heap) != 0) {
WOLFSSL_MSG("\tOut of Memory for registered Id string");
XFREE((void *)(wc_ptr_t)rid->name, cert->heap,
DYNAMIC_TYPE_ALTNAME);
XFREE(rid, cert->heap, DYNAMIC_TYPE_ALTNAME);
return MEMORY_E;
}
AddAltName(cert, rid);
if (strLen > length) {
return ASN_PARSE_E;
}
length -= strLen;
idx += (word32)strLen;
}
#endif
#endif
else if (current_byte ==
(ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | ASN_OTHER_TYPE)) {
int strLen;
word32 lenStartIdx = idx;
word32 oid = 0;
int ret = 0;
if (GetLength(input, &idx, &strLen, sz) < 0) {
WOLFSSL_MSG("\tfail: other name length");
return ASN_PARSE_E;
}
if ((int)((word32)strLen + idx - lenStartIdx) > length) {
return ASN_PARSE_E;
}
length -= (int)(((word32)strLen + idx - lenStartIdx));
if (GetObjectId(input, &idx, &oid, oidCertAltNameType, sz) < 0) {
WOLFSSL_MSG("\tbad OID");
return ASN_PARSE_E;
}
switch (oid) {
#ifdef WOLFSSL_SEP
case HW_NAME_OID:
ret = DecodeSepHwAltName(cert, input, &idx, sz);
if (ret != 0)
return ret;
break;
#endif
#ifdef WOLFSSL_FPKI
case FASCN_OID:
case UPN_OID:
ret = DecodeConstructedOtherName(cert, input, &idx, sz,
oid);
if (ret != 0)
return ret;
break;
#endif
default:
WOLFSSL_MSG("\tUnsupported other name type, skipping");
if (GetLength(input, &idx, &strLen, sz) < 0) {
if (DecodeConstructedOtherName(cert, input, &idx, sz,
(int)oid) != 0) {
WOLFSSL_MSG("\tfail: unsupported other name length");
return ASN_PARSE_E;
}
}
else {
idx += (word32)strLen;
}
}
(void)ret;
}
else {
int strLen;
word32 lenStartIdx = idx;
WOLFSSL_MSG("\tUnsupported name type, skipping");
if (GetLength(input, &idx, &strLen, sz) < 0) {
WOLFSSL_MSG("\tfail: unsupported name length");
return ASN_PARSE_E;
}
if ((int)((word32)strLen + idx - lenStartIdx) > length) {
return ASN_PARSE_E;
}
length -= (int)((word32)strLen + idx - lenStartIdx);
idx += (word32)strLen;
}
}
return 0;
}
int DecodeBasicCaConstraint(const byte* input, int sz, byte *isCa,
word16 *pathLength, byte *pathLengthSet)
{
word32 idx = 0;
int length = 0;
int ret;
WOLFSSL_ENTER("DecodeBasicCaConstraint");
if (GetSequence(input, &idx, &length, (word32)sz) < 0) {
WOLFSSL_MSG("\tfail: bad SEQUENCE");
return ASN_PARSE_E;
}
if (length == 0)
return 0;
ret = GetBoolean(input, &idx, (word32)sz);
if (ret < 0) {
WOLFSSL_MSG("\tfail: constraint not valid BOOLEAN, set default FALSE");
ret = 0;
}
*isCa = ret ? 1 : 0;
if (idx >= (word32)sz) {
return 0;
}
ret = GetInteger16Bit(input, &idx, (word32)sz);
if (ret < 0)
return ret;
else if (ret > WOLFSSL_MAX_PATH_LEN) {
WOLFSSL_ERROR_VERBOSE(ASN_PATHLEN_SIZE_E);
return ASN_PATHLEN_SIZE_E;
}
*pathLength = (word16)ret;
*pathLengthSet = 1;
return 0;
}
static int DecodeCrlDist(const byte* input, word32 sz, DecodedCert* cert)
{
word32 idx = 0, localIdx;
int length = 0;
byte tag = 0;
WOLFSSL_ENTER("DecodeCrlDist");
cert->extCrlInfoRaw = input;
cert->extCrlInfoRawSz = (int)sz;
if (GetSequence(input, &idx, &length, sz) < 0)
return ASN_PARSE_E;
if (GetSequence(input, &idx, &length, sz) < 0)
return ASN_PARSE_E;
localIdx = idx;
if (GetASNTag(input, &localIdx, &tag, sz) == 0 &&
tag == (ASN_CONSTRUCTED | DISTRIBUTION_POINT))
{
idx++;
if (GetLength(input, &idx, &length, sz) < 0)
return ASN_PARSE_E;
localIdx = idx;
if (GetASNTag(input, &localIdx, &tag, sz) == 0 &&
tag == (ASN_CONSTRUCTED | CRLDP_FULL_NAME))
{
idx++;
if (GetLength(input, &idx, &length, sz) < 0)
return ASN_PARSE_E;
localIdx = idx;
if (GetASNTag(input, &localIdx, &tag, sz) == 0 &&
tag == GENERALNAME_URI)
{
idx++;
if (GetLength(input, &idx, &length, sz) < 0)
return ASN_PARSE_E;
cert->extCrlInfoSz = length;
cert->extCrlInfo = input + idx;
idx += (word32)length;
}
else
idx += (word32)length;
}
else {
idx += (word32)length;
}
}
localIdx = idx;
if (idx < (word32)sz &&
GetASNTag(input, &localIdx, &tag, sz) == 0 &&
tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1))
{
idx++;
if (GetLength(input, &idx, &length, sz) < 0)
return ASN_PARSE_E;
idx += (word32)length;
}
localIdx = idx;
if (idx < (word32)sz &&
GetASNTag(input, &localIdx, &tag, sz) == 0 &&
tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 2))
{
idx++;
if (GetLength(input, &idx, &length, sz) < 0)
return ASN_PARSE_E;
idx += (word32)length;
}
if (idx < (word32)sz)
{
WOLFSSL_MSG("\tThere are more CRL Distribution Point records, "
"but we only use the first one.");
}
return 0;
}
static int DecodeAuthInfo(const byte* input, word32 sz, DecodedCert* cert)
{
word32 idx = 0;
int length = 0;
byte b = 0;
word32 oid;
int aiaIdx;
WOLFSSL_ENTER("DecodeAuthInfo");
if (GetSequence(input, &idx, &length, sz) < 0)
return ASN_PARSE_E;
while ((idx < (word32)sz)) {
if (GetSequence(input, &idx, &length, sz) < 0)
return ASN_PARSE_E;
oid = 0;
if (GetObjectId(input, &idx, &oid, oidCertAuthInfoType, sz) < 0) {
return ASN_PARSE_E;
}
if (GetASNTag(input, &idx, &b, sz) < 0)
return ASN_PARSE_E;
if (GetLength(input, &idx, &length, sz) < 0)
return ASN_PARSE_E;
if (b == GENERALNAME_URI) {
aiaIdx = cert->extAuthInfoListSz;
if (aiaIdx < WOLFSSL_MAX_AIA_ENTRIES) {
cert->extAuthInfoList[aiaIdx].method = oid;
cert->extAuthInfoList[aiaIdx].uri = input + idx;
cert->extAuthInfoList[aiaIdx].uriSz = (word32)length;
cert->extAuthInfoListSz++;
}
else {
cert->extAuthInfoListOverflow = 1;
WOLFSSL_MSG("AIA list overflow");
}
}
if (b == GENERALNAME_URI && oid == AIA_OCSP_OID &&
cert->extAuthInfo == NULL) {
cert->extAuthInfoSz = length;
cert->extAuthInfo = input + idx;
}
#ifdef WOLFSSL_ASN_CA_ISSUER
else if ((b == GENERALNAME_URI) && oid == AIA_CA_ISSUER_OID &&
cert->extAuthInfoCaIssuer == NULL)
{
cert->extAuthInfoCaIssuerSz = length;
cert->extAuthInfoCaIssuer = input + idx;
}
#endif
idx += (word32)length;
}
return 0;
}
int DecodeAuthKeyId(const byte* input, word32 sz, const byte **extAuthKeyId,
word32 *extAuthKeyIdSz, const byte **extAuthKeyIdIssuer,
word32 *extAuthKeyIdIssuerSz, const byte **extAuthKeyIdIssuerSN,
word32 *extAuthKeyIdIssuerSNSz)
{
word32 idx = 0;
int length = 0;
byte tag;
WOLFSSL_ENTER("DecodeAuthKeyId");
if (extAuthKeyId)
*extAuthKeyId = NULL;
if (extAuthKeyIdSz)
*extAuthKeyIdSz = 0;
if (extAuthKeyIdIssuer)
*extAuthKeyIdIssuer = NULL;
if (extAuthKeyIdIssuerSz)
*extAuthKeyIdIssuerSz = 0;
if (extAuthKeyIdIssuerSN)
*extAuthKeyIdIssuerSN = NULL;
if (extAuthKeyIdIssuerSNSz)
*extAuthKeyIdIssuerSNSz = 0;
if (GetSequence(input, &idx, &length, sz) < 0) {
WOLFSSL_MSG("\tfail: should be a SEQUENCE");
return ASN_PARSE_E;
}
if (GetASNTag(input, &idx, &tag, sz) < 0) {
return ASN_PARSE_E;
}
if (tag != (ASN_CONTEXT_SPECIFIC | 0)) {
WOLFSSL_MSG("\tinfo: OPTIONAL item 0, not available");
return 0;
}
if (GetLength(input, &idx, &length, sz) <= 0) {
WOLFSSL_MSG("\tfail: extension data length");
return ASN_PARSE_E;
}
if (extAuthKeyIdSz)
*extAuthKeyIdSz = length;
if (extAuthKeyId)
*extAuthKeyId = &input[idx];
return 0;
}
int DecodeKeyUsage(const byte* input, word32 sz, word16 *extKeyUsage)
{
word32 idx = 0;
int length;
int ret;
WOLFSSL_ENTER("DecodeKeyUsage");
ret = CheckBitString(input, &idx, &length, sz, 0, NULL);
if (ret != 0)
return ret;
if (length == 0 || length > 2)
return ASN_PARSE_E;
*extKeyUsage = (word16)(input[idx]);
if (length == 2)
*extKeyUsage |= (word16)(input[idx+1] << 8);
return 0;
}
int DecodeExtKeyUsage(const byte* input, word32 sz,
const byte **extExtKeyUsageSrc, word32 *extExtKeyUsageSz,
word32 *extExtKeyUsageCount, byte *extExtKeyUsage,
byte *extExtKeyUsageSsh)
{
word32 idx = 0, oid;
int length, ret;
WOLFSSL_ENTER("DecodeExtKeyUsage");
(void) extExtKeyUsageSrc;
(void) extExtKeyUsageSz;
(void) extExtKeyUsageCount;
(void) extExtKeyUsageSsh;
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
*extExtKeyUsageSrc = NULL;
*extExtKeyUsageSz = 0;
*extExtKeyUsageCount = 0;
#endif
*extExtKeyUsage = 0;
#ifdef WOLFSSL_WOLFSSH
*extExtKeyUsageSsh = 0;
#endif
if (GetSequence(input, &idx, &length, sz) < 0) {
WOLFSSL_MSG("\tfail: should be a SEQUENCE");
return ASN_PARSE_E;
}
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
*extExtKeyUsageSrc = input + idx;
*extExtKeyUsageSz = length;
#endif
while (idx < (word32)sz) {
ret = GetObjectId(input, &idx, &oid, oidCertKeyUseType, sz);
if (ret == WC_NO_ERR_TRACE(ASN_UNKNOWN_OID_E))
continue;
else if (ret < 0)
return ret;
switch (oid) {
case EKU_ANY_OID:
*extExtKeyUsage |= EXTKEYUSE_ANY;
break;
case EKU_SERVER_AUTH_OID:
*extExtKeyUsage |= EXTKEYUSE_SERVER_AUTH;
break;
case EKU_CLIENT_AUTH_OID:
*extExtKeyUsage |= EXTKEYUSE_CLIENT_AUTH;
break;
case EKU_CODESIGNING_OID:
*extExtKeyUsage |= EXTKEYUSE_CODESIGN;
break;
case EKU_EMAILPROTECT_OID:
*extExtKeyUsage |= EXTKEYUSE_EMAILPROT;
break;
case EKU_TIMESTAMP_OID:
*extExtKeyUsage |= EXTKEYUSE_TIMESTAMP;
break;
case EKU_OCSP_SIGN_OID:
*extExtKeyUsage |= EXTKEYUSE_OCSP_SIGN;
break;
#ifdef WOLFSSL_WOLFSSH
case EKU_SSH_CLIENT_AUTH_OID:
*extExtKeyUsageSsh |= EXTKEYUSE_SSH_CLIENT_AUTH;
break;
case EKU_SSH_MSCL_OID:
*extExtKeyUsageSsh |= EXTKEYUSE_SSH_MSCL;
break;
case EKU_SSH_KP_CLIENT_AUTH_OID:
*extExtKeyUsageSsh |= EXTKEYUSE_SSH_KP_CLIENT_AUTH;
break;
#endif
default:
break;
}
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
(*extExtKeyUsageCount)++;
#endif
}
return 0;
}
#ifndef IGNORE_NAME_CONSTRAINTS
static int DecodeSubtree(const byte* input, word32 sz, Base_entry** head,
word32 limit, void* heap)
{
word32 idx = 0;
int ret = 0;
word32 cnt = 0;
(void)heap;
while (idx < (word32)sz) {
int seqLength, strLength;
word32 nameIdx;
byte b, bType;
if (limit > 0) {
cnt++;
if (cnt > limit) {
WOLFSSL_MSG("too many name constraints");
return ASN_NAME_INVALID_E;
}
}
if (GetSequence(input, &idx, &seqLength, sz) < 0) {
WOLFSSL_MSG("\tfail: should be a SEQUENCE");
return ASN_PARSE_E;
}
if (idx >= (word32)sz) {
WOLFSSL_MSG("\tfail: expecting tag");
return ASN_PARSE_E;
}
nameIdx = idx;
b = input[nameIdx++];
if (GetLength(input, &nameIdx, &strLength, sz) <= 0) {
WOLFSSL_MSG("\tinvalid length");
return ASN_PARSE_E;
}
bType = (byte)(b & ASN_TYPE_MASK);
if (bType == ASN_DNS_TYPE || bType == ASN_RFC822_TYPE ||
bType == ASN_DIR_TYPE || bType == ASN_IP_TYPE ||
bType == ASN_URI_TYPE) {
Base_entry* entry;
if (b & ASN_CONSTRUCTED) {
if (GetSequence(input, &nameIdx, &strLength, sz) < 0) {
WOLFSSL_MSG("\tfail: constructed be a SEQUENCE");
return ASN_PARSE_E;
}
}
entry = (Base_entry*)XMALLOC(sizeof(Base_entry), heap,
DYNAMIC_TYPE_ALTNAME);
if (entry == NULL) {
WOLFSSL_MSG("allocate error");
return MEMORY_E;
}
entry->name = (char*)XMALLOC((size_t)strLength+1, heap,
DYNAMIC_TYPE_ALTNAME);
if (entry->name == NULL) {
WOLFSSL_MSG("allocate error");
XFREE(entry, heap, DYNAMIC_TYPE_ALTNAME);
return MEMORY_E;
}
XMEMCPY(entry->name, &input[nameIdx], (size_t)strLength);
entry->name[strLength] = '\0';
entry->nameSz = strLength;
entry->type = bType;
entry->next = *head;
*head = entry;
}
idx += (word32)seqLength;
}
return ret;
}
static int DecodeNameConstraints(const byte* input, word32 sz,
DecodedCert* cert)
{
word32 idx = 0;
int length = 0;
WOLFSSL_ENTER("DecodeNameConstraints");
if (GetSequence(input, &idx, &length, sz) < 0) {
WOLFSSL_MSG("\tfail: should be a SEQUENCE");
return ASN_PARSE_E;
}
while (idx < (word32)sz) {
byte b = input[idx++];
Base_entry** subtree = NULL;
if (GetLength(input, &idx, &length, sz) <= 0) {
WOLFSSL_MSG("\tinvalid length");
return ASN_PARSE_E;
}
if (b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0))
subtree = &cert->permittedNames;
else if (b == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1))
subtree = &cert->excludedNames;
else {
WOLFSSL_MSG("\tinvalid subtree");
return ASN_PARSE_E;
}
if (DecodeSubtree(input + idx, (word32)length, subtree,
WOLFSSL_MAX_NAME_CONSTRAINTS, cert->heap) < 0) {
WOLFSSL_MSG("\terror parsing subtree");
return ASN_PARSE_E;
}
idx += (word32)length;
}
return 0;
}
#endif
#if defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)
static int DecodeCertPolicy(const byte* input, word32 sz, DecodedCert* cert)
{
word32 idx = 0;
word32 oldIdx;
int policy_length = 0;
int ret;
int total_length = 0;
#if defined(WOLFSSL_CERT_EXT) && !defined(WOLFSSL_DUP_CERTPOL)
int i;
#endif
WOLFSSL_ENTER("DecodeCertPolicy");
if (cert == NULL)
return BAD_FUNC_ARG;
#if defined(WOLFSSL_CERT_EXT)
cert->extCertPoliciesNb = 0;
#endif
if (GetSequence(input, &idx, &total_length, sz) < 0) {
WOLFSSL_MSG("\tGet CertPolicy total seq failed");
return ASN_PARSE_E;
}
if (total_length > (int)(sz - idx)) {
WOLFSSL_MSG("\tCertPolicy length mismatch");
return ASN_PARSE_E;
}
do {
int length = 0;
if (GetSequence(input, &idx, &policy_length, sz) < 0) {
WOLFSSL_MSG("\tGet CertPolicy seq failed");
return ASN_PARSE_E;
}
oldIdx = idx;
ret = GetASNObjectId(input, &idx, &length, sz);
if (ret != 0)
return ret;
policy_length -= (int)(idx - oldIdx);
if (length > 0) {
if (length > (int)(sz - idx)) {
WOLFSSL_MSG("\tCertPolicy length exceeds input buffer");
return ASN_PARSE_E;
}
#ifdef WOLFSSL_SEP
if (cert->deviceType == NULL) {
cert->deviceType = (byte*)XMALLOC((size_t)length, cert->heap,
DYNAMIC_TYPE_X509_EXT);
if (cert->deviceType == NULL) {
WOLFSSL_MSG("\tCouldn't alloc memory for deviceType");
return MEMORY_E;
}
cert->deviceTypeSz = length;
XMEMCPY(cert->deviceType, input + idx, (size_t)length);
}
#endif
#ifdef WOLFSSL_CERT_EXT
if (DecodePolicyOID(cert->extCertPolicies[
cert->extCertPoliciesNb], MAX_CERTPOL_SZ,
input + idx, length) <= 0) {
WOLFSSL_MSG("\tCouldn't decode CertPolicy");
WOLFSSL_ERROR_VERBOSE(ASN_PARSE_E);
return ASN_PARSE_E;
}
#ifndef WOLFSSL_DUP_CERTPOL
for (i = 0; i < cert->extCertPoliciesNb; i++) {
if (XMEMCMP(cert->extCertPolicies[i],
cert->extCertPolicies[cert->extCertPoliciesNb],
MAX_CERTPOL_SZ) == 0) {
WOLFSSL_MSG("Duplicate policy OIDs not allowed");
WOLFSSL_MSG("Use WOLFSSL_DUP_CERTPOL if wanted");
WOLFSSL_ERROR_VERBOSE(CERTPOLICIES_E);
return CERTPOLICIES_E;
}
}
#endif
cert->extCertPoliciesNb++;
#endif
}
idx += (word32)policy_length;
} while((int)idx < total_length
#ifdef WOLFSSL_CERT_EXT
&& cert->extCertPoliciesNb < MAX_CERTPOL_NB
#endif
);
WOLFSSL_LEAVE("DecodeCertPolicy", 0);
return 0;
}
#endif
#ifdef WOLFSSL_SUBJ_DIR_ATTR
static int DecodeSubjDirAttr(const byte* input, word32 sz, DecodedCert* cert)
{
word32 idx = 0;
int length = 0;
int ret = 0;
WOLFSSL_ENTER("DecodeSubjDirAttr");
#ifdef OPENSSL_ALL
cert->extSubjDirAttrSrc = input;
cert->extSubjDirAttrSz = sz;
#endif
if (GetSequence(input, &idx, &length, sz) < 0)
return ASN_PARSE_E;
if (length == 0) {
WOLFSSL_ERROR_VERBOSE(ASN_PARSE_E);
return ASN_PARSE_E;
}
while (idx < (word32)sz) {
word32 oid;
if (GetSequence(input, &idx, &length, sz) < 0)
return ASN_PARSE_E;
if (GetObjectId(input, &idx, &oid, oidSubjDirAttrType, sz) < 0)
return ASN_PARSE_E;
if (GetSet(input, &idx, &length, sz) < 0)
return ASN_PARSE_E;
if (oid == SDA_COC_OID) {
byte tag;
if (GetHeader(input, &tag, &idx, &length, sz, 1) < 0)
return ASN_PARSE_E;
if (length != COUNTRY_CODE_LEN)
return ASN_PARSE_E;
if (tag == ASN_PRINTABLE_STRING) {
XMEMCPY(cert->countryOfCitizenship,
input + idx, COUNTRY_CODE_LEN);
cert->countryOfCitizenship[COUNTRY_CODE_LEN] = 0;
}
}
idx += length;
}
return ret;
}
#endif
static int DecodeCertExtensions(DecodedCert* cert)
{
int ret = 0;
word32 idx = 0;
word32 sz = (word32)cert->extensionsSz;
const byte* input = cert->extensions;
int length;
word32 oid;
byte critical = 0;
byte criticalFail = 0;
byte tag = 0;
WOLFSSL_ENTER("DecodeCertExtensions");
if (input == NULL || sz == 0)
return BAD_FUNC_ARG;
#ifdef WOLFSSL_CERT_REQ
if (!cert->isCSR)
#endif
{
if (GetASNTag(input, &idx, &tag, sz) < 0) {
return ASN_PARSE_E;
}
if (tag != ASN_EXTENSIONS) {
WOLFSSL_MSG("\tfail: should be an EXTENSIONS");
return ASN_PARSE_E;
}
if (GetLength(input, &idx, &length, sz) < 0) {
WOLFSSL_MSG("\tfail: invalid length");
return ASN_PARSE_E;
}
}
if (GetSequence(input, &idx, &length, sz) < 0) {
WOLFSSL_MSG("\tfail: should be a SEQUENCE (1)");
return ASN_PARSE_E;
}
while (idx < (word32)sz) {
word32 localIdx;
if (GetSequence(input, &idx, &length, sz) < 0) {
WOLFSSL_MSG("\tfail: should be a SEQUENCE");
return ASN_PARSE_E;
}
oid = 0;
if ((ret = GetObjectId(input, &idx, &oid, oidCertExtType, sz)) < 0) {
WOLFSSL_MSG("\tfail: OBJECT ID");
return ret;
}
critical = 0;
if ((idx + 1) > (word32)sz) {
WOLFSSL_MSG("\tfail: malformed buffer");
return BUFFER_E;
}
localIdx = idx;
if (GetASNTag(input, &localIdx, &tag, sz) == 0) {
if (tag == ASN_BOOLEAN) {
ret = GetBoolean(input, &idx, sz);
if (ret < 0) {
WOLFSSL_MSG("\tfail: critical boolean");
return ret;
}
critical = (byte)ret;
}
}
ret = GetOctetString(input, &idx, &length, sz);
if (ret < 0) {
WOLFSSL_MSG("\tfail: bad OCTET STRING");
return ret;
}
ret = DecodeExtensionType(input + idx, (word32)length, oid, critical,
cert, NULL);
if (ret == WC_NO_ERR_TRACE(ASN_CRIT_EXT_E)) {
ret = 0;
criticalFail = 1;
}
if (ret < 0)
goto end;
idx += (word32)length;
}
ret = criticalFail ? ASN_CRIT_EXT_E : 0;
end:
return ret;
}
#if defined(WOLFSSL_SMALL_CERT_VERIFY) || defined(OPENSSL_EXTRA)
static int CheckCertSignature_ex(const byte* cert, word32 certSz, void* heap,
void* cm, const byte* pubKey, word32 pubKeySz, int pubKeyOID, int req)
{
#if !defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_NO_MALLOC)
SignatureCtx sigCtx[1];
#else
SignatureCtx* sigCtx;
#endif
byte hash[KEYID_SIZE];
Signer* ca = NULL;
word32 idx = 0;
int len;
word32 tbsCertIdx = 0;
word32 sigIndex = 0;
word32 signatureOID = 0;
word32 oid = 0;
word32 issuerIdx = 0;
word32 issuerSz = 0;
#ifndef NO_SKID
int extLen = 0;
word32 extIdx = 0;
word32 extEndIdx = 0;
int extAuthKeyIdSet = 0;
#endif
int ret = 0;
word32 localIdx;
byte tag;
const byte* sigParams = NULL;
word32 sigParamsSz = 0;
if (cert == NULL) {
return BAD_FUNC_ARG;
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
sigCtx = (SignatureCtx*)XMALLOC(sizeof(*sigCtx), heap, DYNAMIC_TYPE_SIGNATURE);
if (sigCtx == NULL)
return MEMORY_E;
#endif
InitSignatureCtx(sigCtx, heap, INVALID_DEVID);
if (GetSequence(cert, &idx, &len, certSz) < 0)
ret = ASN_PARSE_E;
if (ret == 0) {
tbsCertIdx = idx;
if (GetSequence(cert, &idx, &len, certSz) < 0)
ret = ASN_PARSE_E;
}
if (ret == 0) {
sigIndex = len + idx;
if ((idx + 1) > certSz)
ret = BUFFER_E;
}
if (ret == 0) {
localIdx = idx;
if (GetASNTag(cert, &localIdx, &tag, certSz) == 0) {
if (tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) {
idx++;
if (GetLength(cert, &idx, &len, certSz) < 0)
ret = ASN_PARSE_E;
idx += len;
}
}
}
if (ret == 0) {
if (GetASNHeader(cert, ASN_INTEGER, &idx, &len, certSz) < 0)
ret = ASN_PARSE_E;
}
if (ret == 0) {
idx += len;
if (!req) {
if (GetAlgoId(cert, &idx, &signatureOID, oidSigType, certSz) < 0)
ret = ASN_PARSE_E;
#ifdef WC_RSA_PSS
else if (signatureOID == CTC_RSASSAPSS) {
int start = idx;
sigParams = cert + idx;
if (GetSequence(cert, &idx, &len, certSz) < 0)
ret = ASN_PARSE_E;
if (ret == 0) {
idx += len;
sigParamsSz = idx - start;
}
}
#endif
}
}
if (ret == 0) {
issuerIdx = idx;
if (GetSequence(cert, &idx, &len, certSz) < 0)
ret = ASN_PARSE_E;
}
if (ret == 0) {
issuerSz = len + idx - issuerIdx;
}
#ifndef NO_SKID
if (!req && ret == 0) {
idx += len;
if (GetSequence(cert, &idx, &len, certSz) < 0)
ret = ASN_PARSE_E;
}
if (!req && ret == 0) {
idx += len;
if (GetSequence(cert, &idx, &len, certSz) < 0)
ret = ASN_PARSE_E;
}
if (ret == 0) {
idx += len;
if (GetSequence(cert, &idx, &len, certSz) < 0)
ret = ASN_PARSE_E;
}
if (req && ret == 0) {
idx += len;
if (GetASNHeader_ex(cert,
ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED, &idx,
&len, certSz, 1) < 0)
ret = ASN_PARSE_E;
}
if (!req) {
if (ret == 0) {
idx += len;
if ((idx + 1) > certSz)
ret = BUFFER_E;
}
if (ret == 0) {
localIdx = idx;
if (GetASNTag(cert, &localIdx, &tag, certSz) == 0) {
if (tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) {
idx++;
if (GetLength(cert, &idx, &len, certSz) < 0)
ret = ASN_PARSE_E;
idx += len;
}
}
}
if (ret == 0) {
if ((idx + 1) > certSz)
ret = BUFFER_E;
}
if (ret == 0) {
localIdx = idx;
if (GetASNTag(cert, &localIdx, &tag, certSz) == 0) {
if (tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 2)) {
idx++;
if (GetLength(cert, &idx, &len, certSz) < 0)
ret = ASN_PARSE_E;
idx += len;
}
}
}
if (ret == 0) {
if ((idx + 1) > certSz)
ret = BUFFER_E;
}
localIdx = idx;
if (ret == 0 && GetASNTag(cert, &localIdx, &tag, certSz) == 0 &&
tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 3)) {
idx++;
if (GetLength(cert, &idx, &extLen, certSz) < 0)
ret = ASN_PARSE_E;
if (ret == 0) {
if (GetSequence(cert, &idx, &extLen, certSz) < 0)
ret = ASN_PARSE_E;
}
if (ret == 0) {
extEndIdx = idx + extLen;
while (ret == 0 && idx < extEndIdx) {
if (GetSequence(cert, &idx, &len, certSz) < 0)
ret = ASN_PARSE_E;
if (ret == 0) {
extIdx = idx;
if (GetObjectId(cert, &extIdx, &oid, oidCertExtType,
certSz) < 0) {
ret = ASN_PARSE_E;
}
if (ret == 0) {
if ((extIdx + 1) > certSz)
ret = BUFFER_E;
}
}
if (ret == 0) {
localIdx = extIdx;
if (GetASNTag(cert, &localIdx, &tag, certSz) == 0 &&
tag == ASN_BOOLEAN) {
if (GetBoolean(cert, &extIdx, certSz) < 0)
ret = ASN_PARSE_E;
}
}
if (ret == 0) {
if (GetOctetString(cert, &extIdx, &extLen, certSz) < 0)
ret = ASN_PARSE_E;
}
if (ret == 0) {
switch (oid) {
case AUTH_KEY_OID:
if (GetSequence(cert, &extIdx, &extLen, certSz) < 0)
ret = ASN_PARSE_E;
if (ret == 0 && (extIdx + 1) >= certSz)
ret = BUFFER_E;
if (ret == 0 &&
GetASNTag(cert, &extIdx, &tag, certSz) == 0 &&
tag == (ASN_CONTEXT_SPECIFIC | 0)) {
if (GetLength(cert, &extIdx, &extLen, certSz) <= 0)
ret = ASN_PARSE_E;
if (ret == 0) {
extAuthKeyIdSet = 1;
ret = GetHashId(cert + extIdx, extLen,
hash, HashIdAlg(signatureOID));
}
}
break;
default:
break;
}
}
idx += len;
}
}
}
}
else if (ret == 0) {
idx += len;
}
if (ret == 0 && pubKey == NULL) {
if (extAuthKeyIdSet)
ca = GetCA(cm, hash);
if (ca == NULL) {
ret = CalcHashId_ex(cert + issuerIdx, issuerSz, hash,
HashIdAlg(signatureOID));
if (ret == 0)
ca = GetCAByName(cm, hash);
}
}
#else
if (ret == 0 && pubKey == NULL) {
ret = CalcHashId_ex(cert + issuerIdx, issuerSz, hash,
HashIdAlg(signatureOID));
if (ret == 0)
ca = GetCA(cm, hash);
}
#endif
if (ca == NULL && pubKey == NULL)
ret = ASN_NO_SIGNER_E;
if (ret == 0) {
idx = sigIndex;
if (GetAlgoId(cert, &idx, &oid, oidSigType, certSz) < 0)
ret = ASN_PARSE_E;
#ifdef WC_RSA_PSS
else if (signatureOID == CTC_RSASSAPSS) {
word32 sz = idx;
const byte* params = cert + idx;
if (GetSequence(cert, &idx, &len, certSz) < 0)
ret = ASN_PARSE_E;
if (ret == 0) {
idx += len;
sz = idx - sz;
if (req) {
if ((sz != sigParamsSz) ||
(XMEMCMP(sigParams, params, sz) != 0)) {
ret = ASN_PARSE_E;
}
}
else {
sigParams = params;
sigParamsSz = sz;
}
}
}
#endif
if (req)
signatureOID = oid;
}
if (ret == 0) {
if (oid != signatureOID)
ret = ASN_SIG_OID_E;
}
if (ret == 0) {
if (CheckBitString(cert, &idx, &len, certSz, 1, NULL) < 0)
ret = ASN_PARSE_E;
}
if (ret == 0) {
if (pubKey != NULL) {
ret = ConfirmSignature(sigCtx, cert + tbsCertIdx,
sigIndex - tbsCertIdx, pubKey, pubKeySz, pubKeyOID,
cert + idx, len, signatureOID, sigParams, sigParamsSz, NULL);
}
else {
ret = ConfirmSignature(sigCtx, cert + tbsCertIdx,
sigIndex - tbsCertIdx, ca->publicKey, ca->pubKeySize,
ca->keyOID, cert + idx, len, signatureOID, sigParams,
sigParamsSz, NULL);
}
if (ret != 0) {
WOLFSSL_ERROR_VERBOSE(ret);
WOLFSSL_MSG("Confirm signature failed");
}
}
FreeSignatureCtx(sigCtx);
WC_FREE_VAR_EX(sigCtx, heap, DYNAMIC_TYPE_SIGNATURE);
return ret;
}
#endif
#endif
int wc_GetSerialNumber(const byte* input, word32* inOutIdx,
byte* serial, int* serialSz, word32 maxIdx)
{
int result = 0;
int ret;
WOLFSSL_ENTER("wc_GetSerialNumber");
if (serial == NULL || input == NULL || serialSz == NULL) {
return BAD_FUNC_ARG;
}
if ((*inOutIdx+1) > maxIdx) {
WOLFSSL_MSG("Bad idx first");
return BUFFER_E;
}
ret = GetASNInt(input, inOutIdx, serialSz, maxIdx);
if (ret != 0)
return ret;
if (*serialSz > EXTERNAL_SERIAL_SIZE || *serialSz <= 0) {
WOLFSSL_MSG("Serial size bad");
WOLFSSL_ERROR_VERBOSE(ASN_PARSE_E);
return ASN_PARSE_E;
}
XMEMCPY(serial, &input[*inOutIdx], (size_t)*serialSz);
*inOutIdx += (word32)*serialSz;
return result;
}
#ifndef NO_CERTS
#if !defined(NO_RSA) && \
(defined(WOLFSSL_KEY_TO_DER) || defined(WOLFSSL_CERT_GEN))
static int SetRsaPublicKey(byte* output, RsaKey* key, int outLen,
int with_header)
{
int nSz, eSz;
word32 seqSz, algoSz = 0, headSz = 0, bitStringSz = 0, idx;
byte seq[MAX_SEQ_SZ];
byte headSeq[MAX_SEQ_SZ];
byte bitString[1 + MAX_LENGTH_SZ + 1];
byte algo[MAX_ALGO_SZ];
if (key == NULL) {
return BAD_FUNC_ARG;
}
nSz = SetASNIntMP(&key->n, MAX_RSA_INT_SZ, NULL);
if (nSz < 0)
return nSz;
eSz = SetASNIntMP(&key->e, MAX_RSA_INT_SZ, NULL);
if (eSz < 0)
return eSz;
seqSz = SetSequence((word32)(nSz + eSz), seq);
if (with_header) {
algoSz = SetAlgoID(RSAk, algo, oidKeyType, 0);
bitStringSz = SetBitString(seqSz + (word32)(nSz + eSz), 0, bitString);
headSz = SetSequence((word32)(nSz + eSz) + seqSz + bitStringSz + algoSz,
headSeq);
}
if (output == NULL) {
return (int)(headSz + algoSz + bitStringSz + seqSz) + nSz + eSz;
}
if (((int)(headSz + algoSz + bitStringSz + seqSz) + nSz + eSz) > outLen) {
return BUFFER_E;
}
idx = 0;
if (with_header) {
XMEMCPY(output + idx, headSeq, headSz);
idx += headSz;
XMEMCPY(output + idx, algo, algoSz);
idx += algoSz;
XMEMCPY(output + idx, bitString, bitStringSz);
idx += bitStringSz;
}
XMEMCPY(output + idx, seq, seqSz);
idx += seqSz;
nSz = SetASNIntMP(&key->n, nSz, output + idx);
idx += (word32)nSz;
eSz = SetASNIntMP(&key->e, eSz, output + idx);
idx += (word32)eSz;
return (int)idx;
}
#endif
#endif
#if !defined(NO_RSA) && defined(WOLFSSL_KEY_TO_DER)
int wc_RsaKeyToDer(RsaKey* key, byte* output, word32 inLen)
{
int ret = 0, i;
int mpSz;
word32 seqSz = 0, verSz = 0, intTotalLen = 0, outLen = 0;
byte seq[MAX_SEQ_SZ];
byte ver[MAX_VERSION_SZ];
mp_int* keyInt;
#ifndef WOLFSSL_NO_MALLOC
word32 rawLen;
byte* tmps[RSA_INTS];
word32 sizes[RSA_INTS];
#endif
if (key == NULL)
return BAD_FUNC_ARG;
if (key->type != RSA_PRIVATE)
return BAD_FUNC_ARG;
#ifndef WOLFSSL_NO_MALLOC
for (i = 0; i < RSA_INTS; i++)
tmps[i] = NULL;
#endif
for (i = 0; i < RSA_INTS; i++) {
keyInt = GetRsaInt(key, i);
ret = mp_unsigned_bin_size(keyInt);
if (ret < 0)
break;
#ifndef WOLFSSL_NO_MALLOC
rawLen = (word32)ret + 1;
ret = 0;
if (output != NULL) {
tmps[i] = (byte*)XMALLOC(rawLen + MAX_SEQ_SZ, key->heap,
DYNAMIC_TYPE_RSA);
if (tmps[i] == NULL) {
ret = MEMORY_E;
break;
}
}
mpSz = SetASNIntMP(keyInt, MAX_RSA_INT_SZ, tmps[i]);
#else
ret = 0;
mpSz = SetASNIntMP(keyInt, MAX_RSA_INT_SZ, NULL);
#endif
if (mpSz < 0) {
ret = mpSz;
break;
}
#ifndef WOLFSSL_NO_MALLOC
sizes[i] = (word32)mpSz;
#endif
intTotalLen += (word32)mpSz;
}
if (ret == 0) {
ret = SetMyVersion(0, ver, FALSE);
}
if (ret >= 0) {
verSz = (word32)ret;
ret = 0;
seqSz = SetSequence(verSz + intTotalLen, seq);
outLen = seqSz + verSz + intTotalLen;
if (output != NULL && outLen > inLen)
ret = BUFFER_E;
}
if (ret == 0 && output != NULL) {
word32 j;
XMEMCPY(output, seq, seqSz);
j = seqSz;
XMEMCPY(output + j, ver, verSz);
j += verSz;
for (i = 0; i < RSA_INTS; i++) {
#ifndef WOLFSSL_NO_MALLOC
XMEMCPY(output + j, tmps[i], sizes[i]);
j += sizes[i];
#else
keyInt = GetRsaInt(key, i);
ret = mp_unsigned_bin_size(keyInt);
if (ret < 0)
break;
ret = 0;
mpSz = SetASNIntMP(keyInt, MAX_RSA_INT_SZ, output + j);
if (mpSz < 0) {
ret = mpSz;
break;
}
j += mpSz;
#endif
}
}
#ifndef WOLFSSL_NO_MALLOC
for (i = 0; i < RSA_INTS; i++) {
if (tmps[i])
XFREE(tmps[i], key->heap, DYNAMIC_TYPE_RSA);
}
#endif
if (ret == 0)
ret = (int)outLen;
return ret;
}
#endif
#ifndef NO_CERTS
#ifdef WOLFSSL_CERT_GEN
#ifdef WOLFSSL_CERT_REQ
static word32 SetPrintableString(word32 len, byte* output)
{
output[0] = ASN_PRINTABLE_STRING;
return SetLength(len, output + 1) + 1;
}
static word32 SetUTF8String(word32 len, byte* output)
{
output[0] = ASN_UTF8STRING;
return SetLength(len, output + 1) + 1;
}
#endif
static int CopyValidity(byte* output, Cert* cert)
{
word32 seqSz;
WOLFSSL_ENTER("CopyValidity");
seqSz = SetSequence((word32)(cert->beforeDateSz + cert->afterDateSz),
output);
if (output) {
XMEMCPY(output + seqSz, cert->beforeDate, (size_t)cert->beforeDateSz);
XMEMCPY(output + seqSz + cert->beforeDateSz, cert->afterDate,
(size_t)cert->afterDateSz);
}
return (int)seqSz + cert->beforeDateSz + cert->afterDateSz;
}
static int SetExtensions(byte* out, word32 outSz, int *IdxInOut,
const byte* ext, int extSz)
{
if (out == NULL || IdxInOut == NULL || ext == NULL)
return BAD_FUNC_ARG;
if (outSz < (word32)(*IdxInOut+extSz))
return BUFFER_E;
XMEMCPY(&out[*IdxInOut], ext, (size_t)extSz);
*IdxInOut += extSz;
return *IdxInOut;
}
static int SetExtensionsHeader(byte* out, word32 outSz, word32 extSz)
{
byte sequence[MAX_SEQ_SZ];
byte len[MAX_LENGTH_SZ];
word32 seqSz, lenSz, idx = 0;
if (out == NULL)
return BAD_FUNC_ARG;
if (outSz < 3)
return BUFFER_E;
seqSz = SetSequence(extSz, sequence);
lenSz = SetLength(extSz+seqSz, len);
if (outSz < (word32)(lenSz+seqSz+1))
return BUFFER_E;
out[idx++] = ASN_EXTENSIONS;
XMEMCPY(&out[idx], len, lenSz);
idx += lenSz;
XMEMCPY(&out[idx], sequence, seqSz);
idx += seqSz;
return (int)idx;
}
static int SetCaWithPathLen(byte* out, word32 outSz, byte pathLen)
{
const byte caPathLenBasicConstASN1[] = {
0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x04,
0x08, 0x30, 0x06, 0x01, 0x01, 0xFF, 0x02, 0x01,
0x00
};
if (out == NULL)
return BAD_FUNC_ARG;
if (outSz < sizeof(caPathLenBasicConstASN1))
return BUFFER_E;
XMEMCPY(out, caPathLenBasicConstASN1, sizeof(caPathLenBasicConstASN1));
out[sizeof(caPathLenBasicConstASN1)-1] = pathLen;
return (int)sizeof(caPathLenBasicConstASN1);
}
static int SetCaEx(byte* out, word32 outSz, byte isCa)
{
const byte caBasicConstASN1[] = {
0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04,
0x05, 0x30, 0x03, 0x01, 0x01, 0xff
};
if (out == NULL)
return BAD_FUNC_ARG;
if (outSz < sizeof(caBasicConstASN1))
return BUFFER_E;
XMEMCPY(out, caBasicConstASN1, sizeof(caBasicConstASN1));
if (!isCa) {
out[sizeof(caBasicConstASN1)-1] = isCa;
}
return (int)sizeof(caBasicConstASN1);
}
static int SetCa(byte* out, word32 outSz)
{
return SetCaEx(out, outSz, 1);
}
static int SetBC(byte* out, word32 outSz)
{
const byte BasicConstASN1[] = {
0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04,
0x02, 0x30, 0x00
};
if (out == NULL)
return BAD_FUNC_ARG;
if (outSz < sizeof(BasicConstASN1))
return BUFFER_E;
XMEMCPY(out, BasicConstASN1, sizeof(BasicConstASN1));
return (int)sizeof(BasicConstASN1);
}
#ifdef WOLFSSL_CERT_EXT
static int SetOidValue(byte* out, word32 outSz, const byte *oid, word32 oidSz,
byte *in, word32 inSz)
{
word32 idx = 0;
if (out == NULL || oid == NULL || in == NULL)
return BAD_FUNC_ARG;
if (inSz >= ASN_LONG_LENGTH)
return BAD_FUNC_ARG;
if (oidSz >= ASN_LONG_LENGTH)
return BAD_FUNC_ARG;
if (inSz + oidSz + 1 >= ASN_LONG_LENGTH)
return BAD_FUNC_ARG;
if (outSz < 3)
return BUFFER_E;
idx = SetSequence(inSz + oidSz + 1, out);
if ((idx + inSz + oidSz + 1) > outSz)
return BUFFER_E;
XMEMCPY(out+idx, oid, oidSz);
idx += oidSz;
out[idx++] = (byte)inSz;
XMEMCPY(out+idx, in, inSz);
return (int)(idx+inSz);
}
static int SetSKID(byte* output, word32 outSz, const byte *input, word32 length)
{
byte skid_len[1 + MAX_LENGTH_SZ];
byte skid_enc_len[MAX_LENGTH_SZ];
word32 idx = 0, skid_lenSz, skid_enc_lenSz;
const byte skid_oid[] = { 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04 };
if (output == NULL || input == NULL)
return BAD_FUNC_ARG;
skid_lenSz = SetOctetString(length, skid_len);
skid_enc_lenSz = SetLength(length + skid_lenSz, skid_enc_len);
if (outSz < 3)
return BUFFER_E;
idx = SetSequence(length + (word32)sizeof(skid_oid) + skid_lenSz +
skid_enc_lenSz, output);
if ((length + sizeof(skid_oid) + skid_lenSz + skid_enc_lenSz) > outSz)
return BUFFER_E;
XMEMCPY(output+idx, skid_oid, sizeof(skid_oid));
idx += sizeof(skid_oid);
XMEMCPY(output+idx, skid_enc_len, skid_enc_lenSz);
idx += skid_enc_lenSz;
XMEMCPY(output+idx, skid_len, skid_lenSz);
idx += skid_lenSz;
XMEMCPY(output+idx, input, length);
idx += length;
return (int)idx;
}
static int SetAKID(byte* output, word32 outSz, byte *input, word32 length,
byte rawAkid)
{
int enc_valSz;
byte enc_val_buf[MAX_KID_SZ];
byte* enc_val;
const byte akid_oid[] = { 0x06, 0x03, 0x55, 0x1d, 0x23 };
const byte akid_cs[] = { 0x80 };
word32 inSeqSz, idx;
(void)rawAkid;
if (output == NULL || input == NULL)
return BAD_FUNC_ARG;
#ifdef WOLFSSL_AKID_NAME
if (rawAkid) {
enc_val = input;
enc_valSz = length;
}
else
#endif
{
enc_val = enc_val_buf;
enc_valSz = (int)length + 3 + (int)sizeof(akid_cs);
if (enc_valSz > (int)sizeof(enc_val_buf))
return BAD_FUNC_ARG;
enc_valSz = SetOidValue(enc_val, (word32)enc_valSz, akid_cs,
sizeof(akid_cs), input, length);
if (enc_valSz <= 0)
return enc_valSz;
}
inSeqSz = (word32)sizeof(akid_oid) +
SetOctetString((word32)enc_valSz, NULL) + (word32)enc_valSz;
if (SetSequence(inSeqSz, NULL) + inSeqSz > outSz)
return BAD_FUNC_ARG;
idx = SetSequence(inSeqSz, output);
XMEMCPY(output + idx, akid_oid, sizeof(akid_oid));
idx += sizeof(akid_oid);
idx += SetOctetString((word32)enc_valSz, output + idx);
XMEMCPY(output + idx, enc_val, (size_t)enc_valSz);
return (int)idx + enc_valSz;
}
static int SetKeyUsage(byte* output, word32 outSz, word16 input)
{
byte ku[5];
word32 idx;
const byte keyusage_oid[] = { 0x06, 0x03, 0x55, 0x1d, 0x0f,
0x01, 0x01, 0xff, 0x04};
if (output == NULL)
return BAD_FUNC_ARG;
idx = SetBitString16Bit(input, ku);
return SetOidValue(output, outSz, keyusage_oid, sizeof(keyusage_oid),
ku, idx);
}
static int SetOjectIdValue(byte* output, word32 outSz, word32* idx,
const byte* oid, word32 oidSz)
{
if (*idx + 2 + oidSz >= outSz)
return ASN_PARSE_E;
*idx += (word32)SetObjectId((int)oidSz, &output[*idx]);
XMEMCPY(&output[*idx], oid, oidSz);
*idx += oidSz;
return 0;
}
static int SetExtKeyUsage(Cert* cert, byte* output, word32 outSz, byte input)
{
word32 idx = 0, oidListSz = 0, totalSz;
int ret = 0;
const byte extkeyusage_oid[] = { 0x06, 0x03, 0x55, 0x1d, 0x25 };
if (output == NULL)
return BAD_FUNC_ARG;
totalSz = 2 + sizeof(extkeyusage_oid) + 4;
idx = totalSz;
if (input & EXTKEYUSE_ANY) {
ret |= SetOjectIdValue(output, outSz, &idx,
extExtKeyUsageAnyOid, sizeof(extExtKeyUsageAnyOid));
}
else {
if (input & EXTKEYUSE_SERVER_AUTH)
ret |= SetOjectIdValue(output, outSz, &idx,
extExtKeyUsageServerAuthOid, sizeof(extExtKeyUsageServerAuthOid));
if (input & EXTKEYUSE_CLIENT_AUTH)
ret |= SetOjectIdValue(output, outSz, &idx,
extExtKeyUsageClientAuthOid, sizeof(extExtKeyUsageClientAuthOid));
if (input & EXTKEYUSE_CODESIGN)
ret |= SetOjectIdValue(output, outSz, &idx,
extExtKeyUsageCodeSigningOid, sizeof(extExtKeyUsageCodeSigningOid));
if (input & EXTKEYUSE_EMAILPROT)
ret |= SetOjectIdValue(output, outSz, &idx,
extExtKeyUsageEmailProtectOid, sizeof(extExtKeyUsageEmailProtectOid));
if (input & EXTKEYUSE_TIMESTAMP)
ret |= SetOjectIdValue(output, outSz, &idx,
extExtKeyUsageTimestampOid, sizeof(extExtKeyUsageTimestampOid));
if (input & EXTKEYUSE_OCSP_SIGN)
ret |= SetOjectIdValue(output, outSz, &idx,
extExtKeyUsageOcspSignOid, sizeof(extExtKeyUsageOcspSignOid));
#ifdef WOLFSSL_EKU_OID
if (input & EXTKEYUSE_USER) {
int i, sz;
for (i = 0; i < CTC_MAX_EKU_NB; i++) {
sz = cert->extKeyUsageOIDSz[i];
if (sz > 0) {
ret |= SetOjectIdValue(output, outSz, &idx,
cert->extKeyUsageOID[i], sz);
}
}
}
#endif
}
if (ret != 0)
return ASN_PARSE_E;
oidListSz = idx - totalSz;
totalSz = idx - 2;
idx = SetSequence(totalSz, output);
XMEMCPY(&output[idx], extkeyusage_oid, sizeof(extkeyusage_oid));
idx += sizeof(extkeyusage_oid);
idx += SetOctetString(totalSz - idx, &output[idx]);
idx += SetSequence(oidListSz, &output[idx]);
idx += oidListSz;
(void)cert;
return (int)idx;
}
#ifndef IGNORE_NETSCAPE_CERT_TYPE
static int SetNsCertType(Cert* cert, byte* output, word32 outSz, byte input)
{
word32 idx;
byte unusedBits = 0;
byte nsCertType = input;
word32 totalSz;
word32 bitStrSz;
const byte nscerttype_oid[] = { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x86, 0xF8, 0x42, 0x01, 0x01 };
if (cert == NULL || output == NULL ||
input == 0)
return BAD_FUNC_ARG;
totalSz = sizeof(nscerttype_oid);
for (;(input & 1) == 0; input >>= 1)
unusedBits++;
bitStrSz = SetBitString(1, unusedBits, NULL) + 1;
totalSz += SetOctetString(bitStrSz, NULL) + bitStrSz;
if (SetSequence(totalSz, NULL) + totalSz > outSz)
return BAD_FUNC_ARG;
idx = SetSequence(totalSz, output);
XMEMCPY(&output[idx], nscerttype_oid, sizeof(nscerttype_oid));
idx += sizeof(nscerttype_oid);
idx += SetOctetString(bitStrSz, &output[idx]);
idx += SetBitString(1, unusedBits, &output[idx]);
output[idx++] = nsCertType;
return (int)idx;
}
#endif
static int SetCRLInfo(Cert* cert, byte* output, word32 outSz, byte* input,
int inSz)
{
word32 idx;
word32 totalSz;
const byte crlinfo_oid[] = { 0x06, 0x03, 0x55, 0x1D, 0x1F };
if (cert == NULL || output == NULL ||
input == 0 || inSz <= 0)
return BAD_FUNC_ARG;
totalSz = (word32)sizeof(crlinfo_oid) + SetOctetString((word32)inSz, NULL) +
(word32)inSz;
if (SetSequence(totalSz, NULL) + totalSz > outSz)
return BAD_FUNC_ARG;
idx = SetSequence(totalSz, output);
XMEMCPY(&output[idx], crlinfo_oid, sizeof(crlinfo_oid));
idx += sizeof(crlinfo_oid);
idx += SetOctetString((word32)inSz, &output[idx]);
XMEMCPY(&output[idx], input, (size_t)inSz);
idx += (word32)inSz;
return (int)idx;
}
static int SetCertificatePolicies(byte *output,
word32 outputSz,
char input[MAX_CERTPOL_NB][MAX_CERTPOL_SZ],
word16 nb_certpol,
void* heap)
{
byte oid[MAX_OID_SZ];
byte der_oid[MAX_CERTPOL_NB][MAX_OID_SZ];
byte out[MAX_CERTPOL_SZ];
word32 oidSz;
word32 outSz;
word32 i = 0;
word32 der_oidSz[MAX_CERTPOL_NB];
int ret;
const byte certpol_oid[] = { 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04 };
const byte oid_oid[] = { 0x06 };
if (output == NULL || input == NULL || nb_certpol > MAX_CERTPOL_NB)
return BAD_FUNC_ARG;
for (i = 0; i < nb_certpol; i++) {
oidSz = sizeof(oid);
XMEMSET(oid, 0, oidSz);
ret = EncodePolicyOID(oid, &oidSz, input[i], heap);
if (ret != 0)
return ret;
ret = SetOidValue(der_oid[i], MAX_OID_SZ, oid_oid,
sizeof(oid_oid), oid, oidSz);
if (ret <= 0)
return ret;
else
der_oidSz[i] = (word32)ret;
}
for (i = 0, outSz = 2; i < nb_certpol; i++) {
XMEMCPY(out+outSz, der_oid[i], der_oidSz[i]);
outSz += der_oidSz[i];
}
ret = (int)SetSequence(outSz-2, out);
if (ret <= 0)
return ret;
return SetOidValue(output, outputSz, certpol_oid, sizeof(certpol_oid),
out, outSz);
}
#endif
#ifdef WOLFSSL_ALT_NAMES
static int SetAltNames(byte *output, word32 outSz,
const byte *input, word32 length, int critical)
{
byte san_len[1 + MAX_LENGTH_SZ];
const byte san_oid[] = { 0x06, 0x03, 0x55, 0x1d, 0x11 };
const byte san_crit[] = { 0x01, 0x01, 0xff };
word32 seqSz, san_lenSz, idx = 0;
if (output == NULL || input == NULL)
return BAD_FUNC_ARG;
if (outSz < length)
return BUFFER_E;
san_lenSz = SetOctetString(length, san_len);
seqSz = length + (word32)sizeof(san_oid) + san_lenSz;
if (critical)
seqSz += sizeof(san_crit);
if (outSz < 1 + ASN_LEN_ENC_LEN(seqSz))
return BUFFER_E;
idx = SetSequence(seqSz, output);
if (idx + seqSz > outSz)
return BUFFER_E;
XMEMCPY(output+idx, san_oid, sizeof(san_oid));
idx += sizeof(san_oid);
if (critical) {
XMEMCPY(output+idx, san_crit, sizeof(san_crit));
idx += sizeof(san_crit);
}
XMEMCPY(output+idx, san_len, san_lenSz);
idx += san_lenSz;
XMEMCPY(output+idx, input, length);
idx += length;
return (int)idx;
}
#endif
#endif
#if defined(WOLFSSL_CERT_GEN) || defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
static int EncodeName(EncodedName* name, const char* nameStr,
byte nameTag, byte type, byte emailTag, CertName* cname)
{
word32 idx = 0;
byte firstLen[1 + MAX_LENGTH_SZ];
byte secondLen[MAX_LENGTH_SZ];
byte sequence[MAX_SEQ_SZ];
byte set[MAX_SET_SZ];
word32 strLen;
word32 thisLen;
word32 firstSz, secondSz, seqSz, setSz;
if (nameStr == NULL) {
name->used = 0;
return 0;
}
thisLen = strLen = (word32)XSTRLEN(nameStr);
#ifdef WOLFSSL_CUSTOM_OID
if (type == ASN_CUSTOM_NAME) {
if (cname == NULL || cname->custom.oidSz == 0) {
name->used = 0;
return 0;
}
thisLen = strLen = (word32)cname->custom.valSz;
}
#else
(void)cname;
#endif
if (strLen == 0) {
name->used = 0;
return 0;
}
if (type == ASN_COUNTRY_NAME && strLen != CTC_COUNTRY_SIZE) {
WOLFSSL_MSG("Country code size error");
WOLFSSL_ERROR_VERBOSE(ASN_COUNTRY_SIZE_E);
return ASN_COUNTRY_SIZE_E;
}
secondSz = SetLength(strLen, secondLen);
thisLen += secondSz;
switch (type) {
case ASN_EMAIL_NAME:
thisLen += (int)sizeof(attrEmailOid);
firstSz = (int)sizeof(attrEmailOid);
break;
case ASN_DOMAIN_COMPONENT:
thisLen += (int)sizeof(dcOid);
firstSz = (int)sizeof(dcOid);
break;
case ASN_USER_ID:
thisLen += (int)sizeof(uidOid);
firstSz = (int)sizeof(uidOid);
break;
case ASN_RFC822_MAILBOX:
thisLen += (int)sizeof(rfc822Mlbx);
firstSz = (int)sizeof(rfc822Mlbx);
break;
case ASN_FAVOURITE_DRINK:
thisLen += (int)sizeof(fvrtDrk);
firstSz = (int)sizeof(fvrtDrk);
break;
#ifdef WOLFSSL_CUSTOM_OID
case ASN_CUSTOM_NAME:
thisLen += cname->custom.oidSz;
firstSz = cname->custom.oidSz;
break;
#endif
#ifdef WOLFSSL_CERT_REQ
case ASN_CONTENT_TYPE:
thisLen += (int)sizeof(attrPkcs9ContentTypeOid);
firstSz = (int)sizeof(attrPkcs9ContentTypeOid);
break;
#endif
default:
thisLen += DN_OID_SZ;
firstSz = DN_OID_SZ;
}
thisLen++;
firstSz = (word32)SetObjectId((int)firstSz, firstLen);
thisLen += firstSz;
seqSz = SetSequence(thisLen, sequence);
thisLen += seqSz;
setSz = SetSet(thisLen, set);
thisLen += setSz;
if (thisLen > (int)sizeof(name->encoded)) {
return BUFFER_E;
}
idx = 0;
XMEMCPY(name->encoded, set, setSz);
idx += setSz;
XMEMCPY(name->encoded + idx, sequence, seqSz);
idx += seqSz;
XMEMCPY(name->encoded + idx, firstLen, firstSz);
idx += firstSz;
switch (type) {
case ASN_EMAIL_NAME:
XMEMCPY(name->encoded + idx, attrEmailOid, sizeof(attrEmailOid));
idx += (int)sizeof(attrEmailOid);
name->encoded[idx++] = emailTag;
break;
case ASN_DOMAIN_COMPONENT:
XMEMCPY(name->encoded + idx, dcOid, sizeof(dcOid)-1);
idx += (int)sizeof(dcOid)-1;
name->encoded[idx++] = type;
name->encoded[idx++] = nameTag;
break;
case ASN_USER_ID:
XMEMCPY(name->encoded + idx, uidOid, sizeof(uidOid));
idx += (int)sizeof(uidOid);
name->encoded[idx++] = nameTag;
break;
case ASN_RFC822_MAILBOX:
XMEMCPY(name->encoded + idx, rfc822Mlbx, sizeof(rfc822Mlbx));
idx += (int)sizeof(rfc822Mlbx);
name->encoded[idx++] = nameTag;
break;
case ASN_FAVOURITE_DRINK:
XMEMCPY(name->encoded + idx, fvrtDrk, sizeof(fvrtDrk));
idx += (int)sizeof(fvrtDrk);
name->encoded[idx++] = nameTag;
break;
#ifdef WOLFSSL_CUSTOM_OID
case ASN_CUSTOM_NAME:
XMEMCPY(name->encoded + idx, cname->custom.oid,
cname->custom.oidSz);
idx += cname->custom.oidSz;
name->encoded[idx++] = nameTag;
break;
#endif
#ifdef WOLFSSL_CERT_REQ
case ASN_CONTENT_TYPE:
XMEMCPY(name->encoded + idx, attrPkcs9ContentTypeOid,
sizeof(attrPkcs9ContentTypeOid));
idx += (int)sizeof(attrPkcs9ContentTypeOid);
name->encoded[idx++] = nameTag;
break;
#endif
default:
name->encoded[idx++] = 0x55;
name->encoded[idx++] = 0x04;
name->encoded[idx++] = type;
name->encoded[idx++] = nameTag;
}
XMEMCPY(name->encoded + idx, secondLen, secondSz);
idx += secondSz;
XMEMCPY(name->encoded + idx, nameStr, strLen);
idx += strLen;
name->type = type;
name->totalLen = (int)idx;
name->used = 1;
return (int)idx;
}
#endif
#ifdef WOLFSSL_CERT_GEN
int SetNameEx(byte* output, word32 outputSz, CertName* name, void* heap)
{
int ret;
int i;
word32 idx, totalBytes = 0;
WC_DECLARE_VAR(names, EncodedName, NAME_ENTRIES, 0);
#ifdef WOLFSSL_MULTI_ATTRIB
EncodedName addNames[CTC_MAX_ATTRIB];
int j, type;
#endif
if (output == NULL || name == NULL)
return BAD_FUNC_ARG;
if (outputSz < 3)
return BUFFER_E;
WC_ALLOC_VAR_EX(names, EncodedName, NAME_ENTRIES, NULL,
DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
for (i = 0; i < NAME_ENTRIES; i++) {
const char* nameStr = GetOneCertName(name, i);
ret = EncodeName(&names[i], nameStr, (byte)GetNameType(name, i),
GetCertNameId(i), ASN_IA5_STRING, name);
if (ret < 0) {
WC_FREE_VAR_EX(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
WOLFSSL_MSG("EncodeName failed");
return BUFFER_E;
}
totalBytes += (word32)ret;
}
#ifdef WOLFSSL_MULTI_ATTRIB
for (i = 0; i < CTC_MAX_ATTRIB; i++) {
if (name->name[i].sz > 0) {
ret = EncodeName(&addNames[i], name->name[i].value,
(byte)name->name[i].type, (byte)name->name[i].id,
ASN_IA5_STRING, NULL);
if (ret < 0) {
WC_FREE_VAR_EX(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
WOLFSSL_MSG("EncodeName on multiple attributes failed");
return BUFFER_E;
}
totalBytes += (word32)ret;
}
else {
addNames[i].used = 0;
}
}
#endif
idx = SetSequence(totalBytes, output);
totalBytes += idx;
if (totalBytes > WC_ASN_NAME_MAX) {
WC_FREE_VAR_EX(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
WOLFSSL_MSG("Total Bytes is greater than WC_ASN_NAME_MAX");
return BUFFER_E;
}
for (i = 0; i < NAME_ENTRIES; i++) {
#ifdef WOLFSSL_MULTI_ATTRIB
type = GetCertNameId(i);
for (j = 0; j < CTC_MAX_ATTRIB; j++) {
if (name->name[j].sz > 0 && type == name->name[j].id) {
if (outputSz < idx + (word32)addNames[j].totalLen) {
WC_FREE_VAR_EX(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
WOLFSSL_MSG("Not enough space left for DC value");
return BUFFER_E;
}
XMEMCPY(output + idx, addNames[j].encoded,
(size_t)addNames[j].totalLen);
idx += (word32)addNames[j].totalLen;
}
}
#endif
if (names[i].used) {
if (outputSz < idx + (word32)names[i].totalLen) {
WC_FREE_VAR_EX(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return BUFFER_E;
}
XMEMCPY(output + idx, names[i].encoded, (size_t)names[i].totalLen);
idx += (word32)names[i].totalLen;
}
}
WC_FREE_VAR_EX(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
(void)heap;
return (int)totalBytes;
}
static int SetValidity(byte* output, int daysValid)
{
#ifndef NO_ASN_TIME
byte before[MAX_DATE_SIZE];
byte after[MAX_DATE_SIZE];
word32 beforeSz, afterSz, seqSz;
time_t now;
time_t then;
struct tm* tmpTime;
struct tm* expandedTime;
struct tm localTime;
#if defined(NEED_TMP_TIME)
struct tm tmpTimeStorage;
tmpTime = &tmpTimeStorage;
#else
tmpTime = NULL;
#endif
(void)tmpTime;
now = wc_Time(0);
before[0] = ASN_GENERALIZED_TIME;
beforeSz = SetLength(ASN_GEN_TIME_SZ, before + 1) + 1;
then = now - 86400;
expandedTime = XGMTIME(&then, tmpTime);
if (ValidateGmtime(expandedTime)) {
WOLFSSL_MSG("XGMTIME failed");
return 0;
}
localTime = *expandedTime;
localTime.tm_year += 1900;
localTime.tm_mon += 1;
SetTime(&localTime, before + beforeSz);
beforeSz += ASN_GEN_TIME_SZ;
after[0] = ASN_GENERALIZED_TIME;
afterSz = SetLength(ASN_GEN_TIME_SZ, after + 1) + 1;
then = now + (daysValid * (time_t)86400);
expandedTime = XGMTIME(&then, tmpTime);
if (ValidateGmtime(expandedTime)) {
WOLFSSL_MSG("XGMTIME failed");
return 0;
}
localTime = *expandedTime;
localTime.tm_year += 1900;
localTime.tm_mon += 1;
SetTime(&localTime, after + afterSz);
afterSz += ASN_GEN_TIME_SZ;
seqSz = SetSequence(beforeSz + afterSz, output);
XMEMCPY(output + seqSz, before, beforeSz);
XMEMCPY(output + seqSz + beforeSz, after, afterSz);
return (int)(seqSz + beforeSz + afterSz);
#else
(void)output;
(void)daysValid;
return NOT_COMPILED_IN;
#endif
}
static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey,
WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key,
ed448_key* ed448Key, falcon_key* falconKey,
dilithium_key* dilithiumKey, sphincs_key* sphincsKey)
{
int ret;
if (cert == NULL || der == NULL || rng == NULL)
return BAD_FUNC_ARG;
if (rsaKey == NULL && eccKey == NULL && ed25519Key == NULL &&
dsaKey == NULL && ed448Key == NULL && falconKey == NULL &&
dilithiumKey == NULL && sphincsKey == NULL) {
return PUBLIC_KEY_E;
}
XMEMSET(der, 0, sizeof(DerCert));
der->versionSz = SetMyVersion((word32)cert->version, der->version, TRUE);
if (cert->serialSz == 0) {
cert->serialSz = CTC_GEN_SERIAL_SZ;
ret = wc_RNG_GenerateBlock(rng, cert->serial, (word32)cert->serialSz);
if (ret != 0)
return ret;
cert->serial[0] &= 0x7f;
}
der->serialSz = SetSerialNumber(cert->serial, (word32)cert->serialSz,
der->serial, sizeof(der->serial),
CTC_SERIAL_SIZE);
if (der->serialSz < 0)
return der->serialSz;
der->sigAlgoSz = (int)SetAlgoID(cert->sigType, der->sigAlgo, oidSigType, 0);
if (der->sigAlgoSz <= 0)
return ALGO_ID_E;
#ifndef NO_RSA
if (cert->keyType == RSA_KEY) {
if (rsaKey == NULL)
return PUBLIC_KEY_E;
der->publicKeySz = SetRsaPublicKey(der->publicKey, rsaKey,
sizeof(der->publicKey), 1);
}
#endif
#ifdef HAVE_ECC
if (cert->keyType == ECC_KEY) {
if (eccKey == NULL)
return PUBLIC_KEY_E;
der->publicKeySz = SetEccPublicKey(der->publicKey, eccKey,
sizeof(der->publicKey), 1, 0);
}
#endif
#if !defined(NO_DSA) && !defined(HAVE_SELFTEST)
if (cert->keyType == DSA_KEY) {
if (dsaKey == NULL)
return PUBLIC_KEY_E;
der->publicKeySz = wc_SetDsaPublicKey(der->publicKey, dsaKey,
sizeof(der->publicKey), 1);
}
#endif
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT)
if (cert->keyType == ED25519_KEY) {
if (ed25519Key == NULL)
return PUBLIC_KEY_E;
der->publicKeySz = wc_Ed25519PublicKeyToDer(ed25519Key, der->publicKey,
(word32)sizeof(der->publicKey), 1);
}
#endif
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT)
if (cert->keyType == ED448_KEY) {
if (ed448Key == NULL)
return PUBLIC_KEY_E;
der->publicKeySz = wc_Ed448PublicKeyToDer(ed448Key, der->publicKey,
(word32)sizeof(der->publicKey), 1);
}
#endif
#if defined(HAVE_FALCON)
if ((cert->keyType == FALCON_LEVEL1_KEY) ||
(cert->keyType == FALCON_LEVEL5_KEY)) {
if (falconKey == NULL)
return PUBLIC_KEY_E;
der->publicKeySz =
wc_Falcon_PublicKeyToDer(falconKey, der->publicKey,
(word32)sizeof(der->publicKey), 1);
}
#endif
#if defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_ASN1)
if ((cert->keyType == ML_DSA_LEVEL2_KEY) ||
(cert->keyType == ML_DSA_LEVEL3_KEY) ||
(cert->keyType == ML_DSA_LEVEL5_KEY)
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
|| (cert->keyType == DILITHIUM_LEVEL2_KEY)
|| (cert->keyType == DILITHIUM_LEVEL3_KEY)
|| (cert->keyType == DILITHIUM_LEVEL5_KEY)
#endif
) {
if (dilithiumKey == NULL)
return PUBLIC_KEY_E;
der->publicKeySz =
wc_Dilithium_PublicKeyToDer(dilithiumKey, der->publicKey,
(word32)sizeof(der->publicKey), 1);
}
#endif
#if defined(HAVE_SPHINCS)
if ((cert->keyType == SPHINCS_FAST_LEVEL1_KEY) ||
(cert->keyType == SPHINCS_FAST_LEVEL3_KEY) ||
(cert->keyType == SPHINCS_FAST_LEVEL5_KEY) ||
(cert->keyType == SPHINCS_SMALL_LEVEL1_KEY) ||
(cert->keyType == SPHINCS_SMALL_LEVEL3_KEY) ||
(cert->keyType == SPHINCS_SMALL_LEVEL5_KEY)) {
if (sphincsKey == NULL)
return PUBLIC_KEY_E;
der->publicKeySz =
wc_Sphincs_PublicKeyToDer(sphincsKey, der->publicKey,
(word32)sizeof(der->publicKey), 1);
}
#endif
if (der->publicKeySz <= 0)
return PUBLIC_KEY_E;
der->validitySz = 0;
if (cert->beforeDateSz && cert->afterDateSz) {
der->validitySz = CopyValidity(der->validity, cert);
if (der->validitySz <= 0)
return DATE_E;
}
if (der->validitySz == 0) {
der->validitySz = SetValidity(der->validity, cert->daysValid);
if (der->validitySz <= 0)
return DATE_E;
}
#if defined(WOLFSSL_CERT_EXT) || defined(OPENSSL_EXTRA)
if (XSTRLEN((const char*)cert->sbjRaw) > 0) {
word32 idx;
der->subjectSz = (int)min((word32)sizeof(der->subject),
(word32)XSTRLEN((const char*)cert->sbjRaw));
idx = SetSequence((word32)der->subjectSz, der->subject);
if ((word32)der->subjectSz + idx > (word32)sizeof(der->subject)) {
return SUBJECT_E;
}
XMEMCPY((char*)der->subject + idx, (const char*)cert->sbjRaw,
(size_t)der->subjectSz);
der->subjectSz += (int)idx;
}
else
#endif
{
der->subjectSz = SetNameEx(der->subject, sizeof(der->subject),
&cert->subject, cert->heap);
}
if (der->subjectSz <= 0)
return SUBJECT_E;
#if defined(WOLFSSL_CERT_EXT) || defined(OPENSSL_EXTRA)
if (XSTRLEN((const char*)cert->issRaw) > 0) {
word32 idx;
der->issuerSz = (int)min((word32)sizeof(der->issuer),
(word32)XSTRLEN((const char*)cert->issRaw));
idx = SetSequence((word32)der->issuerSz, der->issuer);
if ((word32)der->issuerSz + idx > (word32)sizeof(der->issuer)) {
return ISSUER_E;
}
XMEMCPY((char*)der->issuer + idx, (const char*)cert->issRaw,
(size_t)der->issuerSz);
der->issuerSz += (int)idx;
}
else
#endif
{
der->issuerSz = SetNameEx(der->issuer, sizeof(der->issuer),
cert->selfSigned ? &cert->subject : &cert->issuer, cert->heap);
}
if (der->issuerSz <= 0)
return ISSUER_E;
der->extensionsSz = 0;
if ((cert->isCA) && (cert->pathLenSet)
#ifdef WOLFSSL_CERT_EXT
&& ((cert->keyUsage & KEYUSE_KEY_CERT_SIGN) || (!cert->keyUsage))
#endif
) {
der->caSz = SetCaWithPathLen(der->ca, sizeof(der->ca), cert->pathLen);
if (der->caSz <= 0)
return CA_TRUE_E;
der->extensionsSz += der->caSz;
}
#ifdef WOLFSSL_ALLOW_ENCODING_CA_FALSE
else if (cert->isCaSet) {
der->caSz = SetCaEx(der->ca, sizeof(der->ca), cert->isCA);
if (der->caSz <= 0)
return EXTENSIONS_E;
der->extensionsSz += der->caSz;
}
#endif
else if (cert->isCA) {
der->caSz = SetCa(der->ca, sizeof(der->ca));
if (der->caSz <= 0)
return CA_TRUE_E;
der->extensionsSz += der->caSz;
}
else if (cert->basicConstSet) {
der->caSz = SetBC(der->ca, sizeof(der->ca));
if (der->caSz <= 0)
return EXTENSIONS_E;
der->extensionsSz += der->caSz;
}
else
der->caSz = 0;
#ifdef WOLFSSL_ALT_NAMES
if (cert->altNamesSz) {
der->altNamesSz = SetAltNames(der->altNames, sizeof(der->altNames),
cert->altNames, (word32)cert->altNamesSz,
cert->altNamesCrit);
if (der->altNamesSz <= 0)
return ALT_NAME_E;
der->extensionsSz += der->altNamesSz;
}
else
der->altNamesSz = 0;
#endif
#ifdef WOLFSSL_CERT_EXT
if (cert->skidSz) {
if (cert->skidSz > (int)min(CTC_MAX_SKID_SIZE, sizeof(der->skid)))
return SKID_E;
der->skidSz = SetSKID(der->skid, sizeof(der->skid),
cert->skid, (word32)cert->skidSz);
if (der->skidSz <= 0)
return SKID_E;
der->extensionsSz += der->skidSz;
}
else
der->skidSz = 0;
if (cert->akidSz) {
if ((
#ifdef WOLFSSL_AKID_NAME
!cert->rawAkid &&
#endif
cert->akidSz > (int)min(CTC_MAX_AKID_SIZE, sizeof(der->akid)))
#ifdef WOLFSSL_AKID_NAME
|| (cert->rawAkid && cert->akidSz > (int)sizeof(der->akid))
#endif
)
return AKID_E;
der->akidSz = SetAKID(der->akid, sizeof(der->akid), cert->akid,
(word32)cert->akidSz,
#ifdef WOLFSSL_AKID_NAME
cert->rawAkid
#else
0
#endif
);
if (der->akidSz <= 0)
return AKID_E;
der->extensionsSz += der->akidSz;
}
else
der->akidSz = 0;
if (cert->keyUsage != 0){
der->keyUsageSz = SetKeyUsage(der->keyUsage, sizeof(der->keyUsage),
cert->keyUsage);
if (der->keyUsageSz <= 0)
return KEYUSAGE_E;
der->extensionsSz += der->keyUsageSz;
}
else
der->keyUsageSz = 0;
if (cert->extKeyUsage != 0){
der->extKeyUsageSz = SetExtKeyUsage(cert, der->extKeyUsage,
sizeof(der->extKeyUsage), cert->extKeyUsage);
if (der->extKeyUsageSz <= 0)
return EXTKEYUSAGE_E;
der->extensionsSz += der->extKeyUsageSz;
}
else
der->extKeyUsageSz = 0;
#ifndef IGNORE_NETSCAPE_CERT_TYPE
if (cert->nsCertType != 0) {
der->nsCertTypeSz = SetNsCertType(cert, der->nsCertType,
sizeof(der->nsCertType), cert->nsCertType);
if (der->nsCertTypeSz <= 0)
return EXTENSIONS_E;
der->extensionsSz += der->nsCertTypeSz;
}
else
der->nsCertTypeSz = 0;
#endif
if (cert->crlInfoSz > 0) {
der->crlInfoSz = SetCRLInfo(cert, der->crlInfo, sizeof(der->crlInfo),
cert->crlInfo, cert->crlInfoSz);
if (der->crlInfoSz <= 0)
return EXTENSIONS_E;
der->extensionsSz += der->crlInfoSz;
}
else
der->crlInfoSz = 0;
if (cert->certPoliciesNb != 0) {
der->certPoliciesSz = SetCertificatePolicies(der->certPolicies,
sizeof(der->certPolicies),
cert->certPolicies,
cert->certPoliciesNb,
cert->heap);
if (der->certPoliciesSz <= 0)
return CERTPOLICIES_E;
der->extensionsSz += der->certPoliciesSz;
}
else
der->certPoliciesSz = 0;
#endif
if (der->extensionsSz > 0) {
der->extensionsSz = SetExtensionsHeader(der->extensions,
sizeof(der->extensions),
(word32)der->extensionsSz);
if (der->extensionsSz <= 0)
return EXTENSIONS_E;
if (der->caSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->ca, der->caSz);
if (ret == 0)
return EXTENSIONS_E;
}
#ifdef WOLFSSL_ALT_NAMES
if (der->altNamesSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->altNames, der->altNamesSz);
if (ret <= 0)
return EXTENSIONS_E;
}
#endif
#ifdef WOLFSSL_CERT_EXT
if (der->skidSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->skid, der->skidSz);
if (ret <= 0)
return EXTENSIONS_E;
}
if (der->akidSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->akid, der->akidSz);
if (ret <= 0)
return EXTENSIONS_E;
}
if (der->crlInfoSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->crlInfo, der->crlInfoSz);
if (ret <= 0)
return EXTENSIONS_E;
}
if (der->keyUsageSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->keyUsage, der->keyUsageSz);
if (ret <= 0)
return EXTENSIONS_E;
}
if (der->extKeyUsageSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->extKeyUsage, der->extKeyUsageSz);
if (ret <= 0)
return EXTENSIONS_E;
}
#ifndef IGNORE_NETSCAPE_CERT_TYPE
if (der->nsCertTypeSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->nsCertType, der->nsCertTypeSz);
if (ret <= 0)
return EXTENSIONS_E;
}
#endif
if (der->certPoliciesSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->certPolicies, der->certPoliciesSz);
if (ret <= 0)
return EXTENSIONS_E;
}
#endif
}
der->total = der->versionSz + der->serialSz + der->sigAlgoSz +
der->publicKeySz + der->validitySz + der->subjectSz + der->issuerSz +
der->extensionsSz;
return 0;
}
static int WriteCertBody(DerCert* der, byte* buf)
{
word32 idx;
idx = SetSequence((word32)der->total, buf);
XMEMCPY(buf + idx, der->version, (size_t)der->versionSz);
idx += (word32)der->versionSz;
XMEMCPY(buf + idx, der->serial, (size_t)der->serialSz);
idx += (word32)der->serialSz;
XMEMCPY(buf + idx, der->sigAlgo, (size_t)der->sigAlgoSz);
idx += (word32)der->sigAlgoSz;
XMEMCPY(buf + idx, der->issuer, (size_t)der->issuerSz);
idx += (word32)der->issuerSz;
XMEMCPY(buf + idx, der->validity, (size_t)der->validitySz);
idx += (word32)der->validitySz;
XMEMCPY(buf + idx, der->subject, (size_t)der->subjectSz);
idx += (word32)der->subjectSz;
XMEMCPY(buf + idx, der->publicKey, (size_t)der->publicKeySz);
idx += (word32)der->publicKeySz;
if (der->extensionsSz) {
XMEMCPY(buf + idx, der->extensions,
min((word32)der->extensionsSz,
(word32)sizeof(der->extensions)));
idx += (word32)der->extensionsSz;
}
return (int)idx;
}
int AddSignature(byte* buf, int bodySz, const byte* sig, int sigSz,
int sigAlgoType)
{
byte seq[MAX_SEQ_SZ];
word32 idx, seqSz;
if ((bodySz < 0) || (sigSz < 0))
return BUFFER_E;
idx = (word32)bodySz;
idx += SetAlgoID(sigAlgoType, buf ? buf + idx : NULL, oidSigType, 0);
idx += SetBitString((word32)sigSz, 0, buf ? buf + idx : NULL);
if (buf)
XMEMCPY(buf + idx, sig, (size_t)sigSz);
idx += (word32)sigSz;
seqSz = SetSequence(idx, seq);
if (buf) {
XMEMMOVE(buf + seqSz, buf, idx);
XMEMCPY(buf, seq, seqSz);
}
return (int)(idx + seqSz);
}
static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz,
RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng,
DsaKey* dsaKey, ed25519_key* ed25519Key,
ed448_key* ed448Key, falcon_key* falconKey,
dilithium_key* dilithiumKey, sphincs_key* sphincsKey)
{
int ret;
WC_DECLARE_VAR(der, DerCert, 1, 0);
if (derBuffer == NULL)
return BAD_FUNC_ARG;
if (eccKey)
cert->keyType = ECC_KEY;
else if (rsaKey)
cert->keyType = RSA_KEY;
else if (dsaKey)
cert->keyType = DSA_KEY;
else if (ed25519Key)
cert->keyType = ED25519_KEY;
else if (ed448Key)
cert->keyType = ED448_KEY;
#ifdef HAVE_FALCON
else if ((falconKey != NULL) && (falconKey->level == 1))
cert->keyType = FALCON_LEVEL1_KEY;
else if ((falconKey != NULL) && (falconKey->level == 5))
cert->keyType = FALCON_LEVEL5_KEY;
#endif
#ifdef HAVE_DILITHIUM
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
else if ((dilithiumKey != NULL) &&
(dilithiumKey->params->level == WC_ML_DSA_44_DRAFT)) {
cert->keyType = DILITHIUM_LEVEL2_KEY;
}
else if ((dilithiumKey != NULL) &&
(dilithiumKey->params->level == WC_ML_DSA_65_DRAFT)) {
cert->keyType = DILITHIUM_LEVEL3_KEY;
}
else if ((dilithiumKey != NULL) &&
(dilithiumKey->params->level == WC_ML_DSA_87_DRAFT)) {
cert->keyType = DILITHIUM_LEVEL5_KEY;
}
#endif
else if ((dilithiumKey != NULL) &&
(dilithiumKey->params->level == WC_ML_DSA_44)) {
cert->keyType = ML_DSA_LEVEL2_KEY;
}
else if ((dilithiumKey != NULL) &&
(dilithiumKey->params->level == WC_ML_DSA_65)) {
cert->keyType = ML_DSA_LEVEL3_KEY;
}
else if ((dilithiumKey != NULL) &&
(dilithiumKey->params->level == WC_ML_DSA_87)) {
cert->keyType = ML_DSA_LEVEL5_KEY;
}
#endif
#ifdef HAVE_SPHINCS
else if ((sphincsKey != NULL) && (sphincsKey->level == 1)
&& (sphincsKey->optim == FAST_VARIANT))
cert->keyType = SPHINCS_FAST_LEVEL1_KEY;
else if ((sphincsKey != NULL) && (sphincsKey->level == 3)
&& (sphincsKey->optim == FAST_VARIANT))
cert->keyType = SPHINCS_FAST_LEVEL3_KEY;
else if ((sphincsKey != NULL) && (sphincsKey->level == 5)
&& (sphincsKey->optim == FAST_VARIANT))
cert->keyType = SPHINCS_FAST_LEVEL5_KEY;
else if ((sphincsKey != NULL) && (sphincsKey->level == 1)
&& (sphincsKey->optim == SMALL_VARIANT))
cert->keyType = SPHINCS_SMALL_LEVEL1_KEY;
else if ((sphincsKey != NULL) && (sphincsKey->level == 3)
&& (sphincsKey->optim == SMALL_VARIANT))
cert->keyType = SPHINCS_SMALL_LEVEL3_KEY;
else if ((sphincsKey != NULL) && (sphincsKey->level == 5)
&& (sphincsKey->optim == SMALL_VARIANT))
cert->keyType = SPHINCS_SMALL_LEVEL5_KEY;
#endif
else
return BAD_FUNC_ARG;
WC_ALLOC_VAR_EX(der, DerCert, 1, cert->heap, DYNAMIC_TYPE_TMP_BUFFER,
return MEMORY_E);
ret = EncodeCert(cert, der, rsaKey, eccKey, rng, dsaKey, ed25519Key,
ed448Key, falconKey, dilithiumKey, sphincsKey);
if (ret == 0) {
if (der->total + MAX_SEQ_SZ * 2 > (int)derSz)
ret = BUFFER_E;
else
ret = cert->bodySz = WriteCertBody(der, derBuffer);
}
WC_FREE_VAR_EX(der, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
#ifdef WOLFSSL_CERT_REQ
static word32 SetReqAttribSingle(byte* output, word32* idx, char* attr,
word32 attrSz, const byte* oid, word32 oidSz, byte printable,
word32 extSz)
{
word32 totalSz = 0;
word32 seqSz = 0;
word32 setSz = 0;
word32 strSz = 0;
byte seq[MAX_SEQ_SZ];
byte set[MAX_SET_SZ];
byte str[MAX_PRSTR_SZ];
totalSz = (word32)SetObjectId((int)oidSz, NULL);
totalSz += oidSz;
if (extSz > 0) {
totalSz += setSz = SetSet(extSz, set);
totalSz += seqSz = SetSequence(totalSz + extSz, seq);
totalSz += extSz;
}
else {
if (printable) {
strSz = SetPrintableString(attrSz, str);
totalSz += strSz;
}
else {
totalSz += strSz = SetUTF8String(attrSz, str);
}
totalSz += setSz = SetSet(strSz + attrSz, set);
totalSz += seqSz = SetSequence(totalSz + attrSz, seq);
totalSz += attrSz;
}
if (oid) {
XMEMCPY(&output[*idx], seq, seqSz);
*idx += seqSz;
*idx += (word32)SetObjectId((int)oidSz, output + *idx);
XMEMCPY(&output[*idx], oid, oidSz);
*idx += oidSz;
XMEMCPY(&output[*idx], set, setSz);
*idx += setSz;
if (strSz > 0) {
XMEMCPY(&output[*idx], str, strSz);
*idx += strSz;
if (attrSz > 0) {
XMEMCPY(&output[*idx], attr, attrSz);
*idx += attrSz;
}
}
}
return totalSz;
}
static int SetReqAttrib(byte* output, Cert* cert, word32 extSz)
{
word32 sz = 0;
word32 setSz = 0;
output[0] = ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED;
sz++;
if (cert->challengePw[0]) {
setSz += SetReqAttribSingle(output, &sz, NULL,
(word32)XSTRLEN(cert->challengePw), NULL,
sizeof(attrChallengePasswordOid),
(byte)cert->challengePwPrintableString, 0);
}
if (cert->unstructuredName[0]) {
setSz += SetReqAttribSingle(output, &sz, NULL,
(word32)XSTRLEN(cert->unstructuredName), NULL,
sizeof(attrUnstructuredNameOid), 1, 0);
}
if (extSz) {
setSz += SetReqAttribSingle(output, &sz, NULL, 0, NULL,
sizeof(attrExtensionRequestOid), 1, extSz);
}
sz += SetLength(setSz, &output[sz]);
if (sz + setSz - extSz > MAX_ATTRIB_SZ) {
WOLFSSL_MSG("Attribute Buffer is not big enough!");
return REQ_ATTRIBUTE_E;
}
if (cert->challengePw[0]) {
SetReqAttribSingle(output, &sz, cert->challengePw,
(word32)XSTRLEN(cert->challengePw),
&attrChallengePasswordOid[0],
sizeof(attrChallengePasswordOid),
(byte)cert->challengePwPrintableString, 0);
}
if (cert->unstructuredName[0]) {
SetReqAttribSingle(output, &sz, cert->unstructuredName,
(word32)XSTRLEN(cert->unstructuredName),
&attrUnstructuredNameOid[0],
sizeof(attrUnstructuredNameOid), 1, 0);
}
if (extSz) {
SetReqAttribSingle(output, &sz, NULL, 0, &attrExtensionRequestOid[0],
sizeof(attrExtensionRequestOid), 1, extSz);
}
return (int)sz;
}
#ifdef WOLFSSL_CUSTOM_OID
static int SetCustomObjectId(Cert* cert, byte* output, word32 outSz,
CertOidField* custom)
{
int idx = 0, cust_lenSz, cust_oidSz;
if (cert == NULL || output == NULL || custom == NULL) {
return BAD_FUNC_ARG;
}
if (custom->oid == NULL || custom->oidSz <= 0) {
return 0;
}
cust_lenSz = SetOctetString(custom->valSz, NULL);
cust_oidSz = SetObjectId(custom->oidSz, NULL);
if ((word32)(custom->valSz + custom->oidSz + cust_lenSz + cust_oidSz) >
outSz) {
return BUFFER_E;
}
idx = SetSequence(custom->valSz + custom->oidSz + cust_lenSz + cust_oidSz,
output);
idx += SetObjectId(custom->oidSz, output+idx);
XMEMCPY(output+idx, custom->oid, custom->oidSz);
idx += custom->oidSz;
idx += SetOctetString(custom->valSz, output+idx);
XMEMCPY(output+idx, custom->val, custom->valSz);
idx += custom->valSz;
return idx;
}
#endif
static int EncodeCertReq(Cert* cert, DerCert* der, RsaKey* rsaKey,
DsaKey* dsaKey, ecc_key* eccKey,
ed25519_key* ed25519Key, ed448_key* ed448Key,
falcon_key* falconKey, dilithium_key* dilithiumKey,
sphincs_key* sphincsKey)
{
int ret;
(void)eccKey;
(void)ed25519Key;
(void)ed448Key;
(void)falconKey;
(void)dilithiumKey;
(void)sphincsKey;
if (cert == NULL || der == NULL)
return BAD_FUNC_ARG;
if (rsaKey == NULL && eccKey == NULL && ed25519Key == NULL &&
dsaKey == NULL && ed448Key == NULL && falconKey == NULL &&
dilithiumKey == NULL && sphincsKey == NULL) {
return PUBLIC_KEY_E;
}
XMEMSET(der, 0, sizeof(DerCert));
der->versionSz = SetMyVersion((word32)cert->version, der->version, FALSE);
#if defined(WOLFSSL_CERT_EXT) || defined(OPENSSL_EXTRA)
if (XSTRLEN((const char*)cert->sbjRaw) > 0) {
int idx;
der->subjectSz = (int)min(sizeof(der->subject),
(word32)XSTRLEN((const char*)cert->sbjRaw));
idx = (int)SetSequence((word32)der->subjectSz, der->subject);
if (der->subjectSz + idx > (int)sizeof(der->subject)) {
return SUBJECT_E;
}
XMEMCPY((char*)der->subject + idx, (const char*)cert->sbjRaw,
(size_t)der->subjectSz);
der->subjectSz += idx;
}
else
#endif
{
der->subjectSz = SetNameEx(der->subject, sizeof(der->subject),
&cert->subject, cert->heap);
}
if (der->subjectSz <= 0)
return SUBJECT_E;
#ifndef NO_RSA
if (cert->keyType == RSA_KEY) {
if (rsaKey == NULL)
return PUBLIC_KEY_E;
der->publicKeySz = SetRsaPublicKey(der->publicKey, rsaKey,
sizeof(der->publicKey), 1);
}
#endif
#if !defined(NO_DSA) && !defined(HAVE_SELFTEST)
if (cert->keyType == DSA_KEY) {
if (dsaKey == NULL)
return PUBLIC_KEY_E;
der->publicKeySz = wc_SetDsaPublicKey(der->publicKey, dsaKey,
sizeof(der->publicKey), 1);
}
#endif
#ifdef HAVE_ECC
if (cert->keyType == ECC_KEY) {
if (eccKey == NULL)
return PUBLIC_KEY_E;
der->publicKeySz = SetEccPublicKey(der->publicKey, eccKey,
sizeof(der->publicKey), 1, 0);
}
#endif
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT)
if (cert->keyType == ED25519_KEY) {
if (ed25519Key == NULL)
return PUBLIC_KEY_E;
der->publicKeySz = wc_Ed25519PublicKeyToDer(ed25519Key, der->publicKey,
(word32)sizeof(der->publicKey), 1);
}
#endif
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT)
if (cert->keyType == ED448_KEY) {
if (ed448Key == NULL)
return PUBLIC_KEY_E;
der->publicKeySz = wc_Ed448PublicKeyToDer(ed448Key, der->publicKey,
(word32)sizeof(der->publicKey), 1);
}
#endif
#if defined(HAVE_FALCON)
if ((cert->keyType == FALCON_LEVEL1_KEY) ||
(cert->keyType == FALCON_LEVEL5_KEY)) {
if (falconKey == NULL)
return PUBLIC_KEY_E;
der->publicKeySz = wc_Falcon_PublicKeyToDer(falconKey,
der->publicKey, (word32)sizeof(der->publicKey), 1);
}
#endif
#if defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_ASN1)
if ((cert->keyType == ML_DSA_LEVEL2_KEY) ||
(cert->keyType == ML_DSA_LEVEL3_KEY) ||
(cert->keyType == ML_DSA_LEVEL5_KEY)
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
|| (cert->keyType == DILITHIUM_LEVEL2_KEY)
|| (cert->keyType == DILITHIUM_LEVEL3_KEY)
|| (cert->keyType == DILITHIUM_LEVEL5_KEY)
#endif
) {
if (dilithiumKey == NULL)
return PUBLIC_KEY_E;
der->publicKeySz = wc_Dilithium_PublicKeyToDer(dilithiumKey,
der->publicKey, (word32)sizeof(der->publicKey), 1);
}
#endif
#if defined(HAVE_SPHINCS)
if ((cert->keyType == SPHINCS_FAST_LEVEL1_KEY) ||
(cert->keyType == SPHINCS_FAST_LEVEL3_KEY) ||
(cert->keyType == SPHINCS_FAST_LEVEL5_KEY) ||
(cert->keyType == SPHINCS_SMALL_LEVEL1_KEY) ||
(cert->keyType == SPHINCS_SMALL_LEVEL3_KEY) ||
(cert->keyType == SPHINCS_SMALL_LEVEL5_KEY)) {
if (sphincsKey == NULL)
return PUBLIC_KEY_E;
der->publicKeySz = wc_Sphincs_PublicKeyToDer(sphincsKey,
der->publicKey, (word32)sizeof(der->publicKey), 1);
}
#endif
if (der->publicKeySz <= 0)
return PUBLIC_KEY_E;
der->extensionsSz = 0;
if ((cert->isCA) && (cert->pathLenSet)
#ifdef WOLFSSL_CERT_EXT
&& ((cert->keyUsage & KEYUSE_KEY_CERT_SIGN) || (!cert->keyUsage))
#endif
) {
der->caSz = SetCaWithPathLen(der->ca, sizeof(der->ca), cert->pathLen);
if (der->caSz <= 0)
return CA_TRUE_E;
der->extensionsSz += der->caSz;
}
#ifdef WOLFSSL_ALLOW_ENCODING_CA_FALSE
else if (cert->isCaSet) {
der->caSz = SetCaEx(der->ca, sizeof(der->ca), cert->isCA);
if (der->caSz <= 0)
return EXTENSIONS_E;
der->extensionsSz += der->caSz;
}
#endif
else if (cert->isCA) {
der->caSz = SetCa(der->ca, sizeof(der->ca));
if (der->caSz <= 0)
return CA_TRUE_E;
der->extensionsSz += der->caSz;
}
else if (cert->basicConstSet) {
der->caSz = SetBC(der->ca, sizeof(der->ca));
if (der->caSz <= 0)
return EXTENSIONS_E;
der->extensionsSz += der->caSz;
}
else
der->caSz = 0;
#ifdef WOLFSSL_ALT_NAMES
if (cert->altNamesSz) {
der->altNamesSz = SetAltNames(der->altNames, sizeof(der->altNames),
cert->altNames, (word32)cert->altNamesSz,
cert->altNamesCrit);
if (der->altNamesSz <= 0)
return ALT_NAME_E;
der->extensionsSz += der->altNamesSz;
}
else
der->altNamesSz = 0;
#endif
#ifdef WOLFSSL_CERT_EXT
if (cert->skidSz) {
if (cert->skidSz > (int)min(CTC_MAX_SKID_SIZE, sizeof(der->skid)))
return SKID_E;
der->skidSz = SetSKID(der->skid, sizeof(der->skid),
cert->skid, (word32)cert->skidSz);
if (der->skidSz <= 0)
return SKID_E;
der->extensionsSz += der->skidSz;
}
else
der->skidSz = 0;
if (cert->keyUsage != 0) {
der->keyUsageSz = SetKeyUsage(der->keyUsage, sizeof(der->keyUsage),
cert->keyUsage);
if (der->keyUsageSz <= 0)
return KEYUSAGE_E;
der->extensionsSz += der->keyUsageSz;
}
else
der->keyUsageSz = 0;
if (cert->extKeyUsage != 0) {
der->extKeyUsageSz = SetExtKeyUsage(cert, der->extKeyUsage,
sizeof(der->extKeyUsage), cert->extKeyUsage);
if (der->extKeyUsageSz <= 0)
return EXTKEYUSAGE_E;
der->extensionsSz += der->extKeyUsageSz;
}
else
der->extKeyUsageSz = 0;
#endif
#ifdef WOLFSSL_CUSTOM_OID
ret = SetCustomObjectId(cert, der->extCustom,
sizeof(der->extCustom), &cert->extCustom);
if (ret < 0)
return ret;
der->extCustomSz = ret;
der->extensionsSz += der->extCustomSz;
#endif
if (der->extensionsSz > 0) {
der->extensionsSz = (int)SetSequence((word32)der->extensionsSz,
der->extensions);
if (der->extensionsSz <= 0)
return EXTENSIONS_E;
if (der->caSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->ca, der->caSz);
if (ret <= 0)
return EXTENSIONS_E;
}
#ifdef WOLFSSL_ALT_NAMES
if (der->altNamesSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->altNames, der->altNamesSz);
if (ret <= 0)
return EXTENSIONS_E;
}
#endif
#ifdef WOLFSSL_CERT_EXT
if (der->skidSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->skid, der->skidSz);
if (ret <= 0)
return EXTENSIONS_E;
}
if (der->akidSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->akid, der->akidSz);
if (ret <= 0)
return EXTENSIONS_E;
}
if (der->keyUsageSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->keyUsage, der->keyUsageSz);
if (ret <= 0)
return EXTENSIONS_E;
}
if (der->extKeyUsageSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->extKeyUsage, der->extKeyUsageSz);
if (ret <= 0)
return EXTENSIONS_E;
}
#ifdef WOLFSSL_CUSTOM_OID
if (der->extCustomSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->extCustom, der->extCustomSz);
if (ret <= 0)
return EXTENSIONS_E;
}
#endif
#endif
}
der->attribSz = SetReqAttrib(der->attrib, cert, (word32)der->extensionsSz);
if (der->attribSz <= 0)
return REQ_ATTRIBUTE_E;
der->total = der->versionSz + der->subjectSz + der->publicKeySz +
der->extensionsSz + der->attribSz;
return 0;
}
static int WriteCertReqBody(DerCert* der, byte* buf)
{
int idx;
idx = (int)SetSequence((word32)der->total, buf);
if (buf)
XMEMCPY(buf + idx, der->version, (size_t)der->versionSz);
idx += der->versionSz;
if (buf)
XMEMCPY(buf + idx, der->subject, (size_t)der->subjectSz);
idx += der->subjectSz;
if (buf)
XMEMCPY(buf + idx, der->publicKey, (size_t)der->publicKeySz);
idx += der->publicKeySz;
if (buf)
XMEMCPY(buf + idx, der->attrib, (size_t)der->attribSz);
idx += der->attribSz;
if (der->extensionsSz) {
if (buf)
XMEMCPY(buf + idx, der->extensions, min((word32)der->extensionsSz,
sizeof(der->extensions)));
idx += der->extensionsSz;
}
return idx;
}
static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz,
RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey,
ed25519_key* ed25519Key, ed448_key* ed448Key,
falcon_key* falconKey, dilithium_key* dilithiumKey,
sphincs_key* sphincsKey)
{
int ret;
WC_DECLARE_VAR(der, DerCert, 1, 0);
if (eccKey)
cert->keyType = ECC_KEY;
else if (rsaKey)
cert->keyType = RSA_KEY;
else if (dsaKey)
cert->keyType = DSA_KEY;
else if (ed25519Key)
cert->keyType = ED25519_KEY;
else if (ed448Key)
cert->keyType = ED448_KEY;
#ifdef HAVE_FALCON
else if ((falconKey != NULL) && (falconKey->level == 1))
cert->keyType = FALCON_LEVEL1_KEY;
else if ((falconKey != NULL) && (falconKey->level == 5))
cert->keyType = FALCON_LEVEL5_KEY;
#endif
#ifdef HAVE_DILITHIUM
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
else if ((dilithiumKey != NULL) &&
(dilithiumKey->params->level == WC_ML_DSA_44_DRAFT)) {
cert->keyType = DILITHIUM_LEVEL2_KEY;
}
else if ((dilithiumKey != NULL) &&
(dilithiumKey->params->level == WC_ML_DSA_65_DRAFT)) {
cert->keyType = DILITHIUM_LEVEL3_KEY;
}
else if ((dilithiumKey != NULL) &&
(dilithiumKey->params->level == WC_ML_DSA_87_DRAFT)) {
cert->keyType = DILITHIUM_LEVEL5_KEY;
}
#endif
else if ((dilithiumKey != NULL) &&
(dilithiumKey->params->level == WC_ML_DSA_44)) {
cert->keyType = ML_DSA_LEVEL2_KEY;
}
else if ((dilithiumKey != NULL) &&
(dilithiumKey->params->level == WC_ML_DSA_65)) {
cert->keyType = ML_DSA_LEVEL3_KEY;
}
else if ((dilithiumKey != NULL) &&
(dilithiumKey->params->level == WC_ML_DSA_87)) {
cert->keyType = ML_DSA_LEVEL5_KEY;
}
#endif
#ifdef HAVE_SPHINCS
else if ((sphincsKey != NULL) && (sphincsKey->level == 1)
&& (sphincsKey->optim == FAST_VARIANT))
cert->keyType = SPHINCS_FAST_LEVEL1_KEY;
else if ((sphincsKey != NULL) && (sphincsKey->level == 3)
&& (sphincsKey->optim == FAST_VARIANT))
cert->keyType = SPHINCS_FAST_LEVEL3_KEY;
else if ((sphincsKey != NULL) && (sphincsKey->level == 5)
&& (sphincsKey->optim == FAST_VARIANT))
cert->keyType = SPHINCS_FAST_LEVEL5_KEY;
else if ((sphincsKey != NULL) && (sphincsKey->level == 1)
&& (sphincsKey->optim == SMALL_VARIANT))
cert->keyType = SPHINCS_SMALL_LEVEL1_KEY;
else if ((sphincsKey != NULL) && (sphincsKey->level == 3)
&& (sphincsKey->optim == SMALL_VARIANT))
cert->keyType = SPHINCS_SMALL_LEVEL3_KEY;
else if ((sphincsKey != NULL) && (sphincsKey->level == 5)
&& (sphincsKey->optim == SMALL_VARIANT))
cert->keyType = SPHINCS_SMALL_LEVEL5_KEY;
#endif
else
return BAD_FUNC_ARG;
WC_ALLOC_VAR_EX(der, DerCert, 1, cert->heap, DYNAMIC_TYPE_TMP_BUFFER,
return MEMORY_E);
ret = EncodeCertReq(cert, der, rsaKey, dsaKey, eccKey, ed25519Key, ed448Key,
falconKey, dilithiumKey, sphincsKey);
if (ret == 0) {
if (der->total + MAX_SEQ_SZ * 2 > (int)derSz)
ret = BUFFER_E;
else
ret = cert->bodySz = WriteCertReqBody(der, derBuffer);
}
WC_FREE_VAR_EX(der, cert->heap, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
#endif
#endif
#endif
#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL))
int StoreDHparams(byte* out, word32* outLen, mp_int* p, mp_int* g)
{
word32 idx = 0;
word32 total;
WOLFSSL_ENTER("StoreDHparams");
if (out == NULL) {
WOLFSSL_MSG("Null buffer error");
return BUFFER_E;
}
idx = SetASNIntMP(g, -1, NULL);
idx += SetASNIntMP(p, -1, NULL);
total = idx;
idx += SetSequence(idx, NULL);
if (idx > *outLen) {
return BUFFER_E;
}
idx = SetSequence(total, out);
idx += SetASNIntMP(p, -1, out + idx);
idx += SetASNIntMP(g, -1, out + idx);
*outLen = idx;
return 0;
}
#endif
#if defined(HAVE_ECC) || !defined(NO_DSA)
int StoreECC_DSA_Sig(byte* out, word32* outLen, mp_int* r, mp_int* s)
{
word32 idx = 0;
int rSz;
int sSz;
int headerSz = 4;
int rLeadingZero = mp_leading_bit(r);
int sLeadingZero = mp_leading_bit(s);
int rLen = mp_unsigned_bin_size(r);
int sLen = mp_unsigned_bin_size(s);
if (*outLen < (word32)((rLen + rLeadingZero + sLen + sLeadingZero +
headerSz + 2)))
return BUFFER_E;
idx = SetSequence((word32)(rLen + rLeadingZero + sLen + sLeadingZero +
headerSz), out);
rSz = SetASNIntMP(r, (int)(*outLen - idx), &out[idx]);
if (rSz < 0)
return rSz;
idx += (word32)rSz;
sSz = SetASNIntMP(s, (int)(*outLen - idx), &out[idx]);
if (sSz < 0)
return sSz;
idx += (word32)sSz;
*outLen = idx;
return 0;
}
static word32 is_leading_bit_set(const byte* input, word32 sz)
{
byte c = 0;
if (sz > 0)
c = input[0];
return (c & 0x80) != 0;
}
static word32 trim_leading_zeros(const byte** input, word32 sz)
{
int i;
word32 leadingZeroCount = 0;
const byte* tmp = *input;
for (i=0; i<(int)sz; i++) {
if (tmp[i] != 0)
break;
leadingZeroCount++;
}
if (sz > 0 && leadingZeroCount == sz) {
leadingZeroCount--;
}
*input += leadingZeroCount;
sz -= leadingZeroCount;
return sz;
}
int StoreECC_DSA_Sig_Bin(byte* out, word32* outLen, const byte* r, word32 rLen,
const byte* s, word32 sLen)
{
int ret;
word32 idx;
word32 headerSz = 4;
word32 rAddLeadZero, sAddLeadZero;
if ((out == NULL) || (outLen == NULL) || (r == NULL) || (s == NULL))
return BAD_FUNC_ARG;
rLen = trim_leading_zeros(&r, rLen);
sLen = trim_leading_zeros(&s, sLen);
rAddLeadZero = is_leading_bit_set(r, rLen);
sAddLeadZero = is_leading_bit_set(s, sLen);
if (*outLen < (rLen + rAddLeadZero + sLen + sAddLeadZero +
headerSz + 2))
return BUFFER_E;
idx = SetSequence(rLen+rAddLeadZero + sLen+sAddLeadZero + headerSz, out);
ret = SetASNInt((int)rLen, (byte)(rAddLeadZero ? 0x80U : 0x00U), &out[idx]);
if (ret < 0)
return ret;
idx += (word32)ret;
XMEMCPY(&out[idx], r, rLen);
idx += rLen;
ret = SetASNInt((int)sLen, (byte)(sAddLeadZero ? 0x80U : 0x00U), &out[idx]);
if (ret < 0)
return ret;
idx += (word32)ret;
XMEMCPY(&out[idx], s, sLen);
idx += sLen;
*outLen = idx;
return 0;
}
int DecodeECC_DSA_Sig_Bin(const byte* sig, word32 sigLen, byte* r, word32* rLen,
byte* s, word32* sLen)
{
int ret;
word32 idx = 0;
int len = 0;
if (GetSequence(sig, &idx, &len, sigLen) < 0) {
return ASN_ECC_KEY_E;
}
#ifndef NO_STRICT_ECDSA_LEN
if (sigLen != idx + (word32)len) {
return ASN_ECC_KEY_E;
}
#else
if ((word32)len > (sigLen - idx)) {
return ASN_ECC_KEY_E;
}
#endif
ret = GetASNInt(sig, &idx, &len, sigLen);
if (ret != 0)
return ret;
if (rLen) {
if (*rLen >= (word32)len)
*rLen = (word32)len;
else {
return BUFFER_E;
}
}
if (r)
XMEMCPY(r, (byte*)sig + idx, (size_t)len);
idx += (word32)len;
ret = GetASNInt(sig, &idx, &len, sigLen);
if (ret != 0)
return ret;
if (sLen) {
if (*sLen >= (word32)len)
*sLen = (word32)len;
else {
return BUFFER_E;
}
}
if (s)
XMEMCPY(s, (byte*)sig + idx, (size_t)len);
#ifndef NO_STRICT_ECDSA_LEN
if (idx + (word32)len != sigLen) {
ret = ASN_ECC_KEY_E;
}
#endif
return ret;
}
int DecodeECC_DSA_Sig_Ex(const byte* sig, word32 sigLen, mp_int* r, mp_int* s,
int init)
{
word32 idx = 0;
int len = 0;
if (GetSequence(sig, &idx, &len, sigLen) < 0) {
return ASN_ECC_KEY_E;
}
#ifndef NO_STRICT_ECDSA_LEN
if (sigLen != idx + (word32)len) {
return ASN_ECC_KEY_E;
}
#else
if ((word32)len > (sigLen - idx)) {
return ASN_ECC_KEY_E;
}
#endif
if (GetIntPositive(r, sig, &idx, sigLen, init) < 0) {
return ASN_ECC_KEY_E;
}
if (GetIntPositive(s, sig, &idx, sigLen, init) < 0) {
mp_clear(r);
return ASN_ECC_KEY_E;
}
#ifndef NO_STRICT_ECDSA_LEN
if (idx != sigLen) {
mp_clear(r);
mp_clear(s);
return ASN_ECC_KEY_E;
}
#endif
return 0;
}
#endif
#ifdef HAVE_ECC
WOLFSSL_ABI
int wc_EccPrivateKeyDecode(const byte* input, word32* inOutIdx, ecc_key* key,
word32 inSz)
{
word32 oidSum;
int version, length;
int privSz, pubSz = 0;
byte b;
int ret = 0;
int curve_id = ECC_CURVE_DEF;
#ifdef WOLFSSL_SMALL_STACK
byte* priv;
byte* pub = NULL;
#else
byte priv[ECC_MAXSIZE+1];
byte pub[2*(ECC_MAXSIZE+1)];
#endif
word32 algId = 0;
byte* pubData = NULL;
if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0)
return BAD_FUNC_ARG;
if (ToTraditionalInline_ex(input, inOutIdx, inSz, &algId) < 0) {
}
else {
curve_id = wc_ecc_get_oid(algId, NULL, NULL);
}
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
if (GetMyVersion(input, inOutIdx, &version, inSz) < 0)
return ASN_PARSE_E;
if (*inOutIdx >= inSz)
return ASN_PARSE_E;
b = input[*inOutIdx];
*inOutIdx += 1;
if (b != 4 && b != 6 && b != 7)
return ASN_PARSE_E;
if (GetLength(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
privSz = length;
if (privSz > ECC_MAXSIZE)
return BUFFER_E;
WC_ALLOC_VAR_EX(priv, byte, privSz, key->heap, DYNAMIC_TYPE_TMP_BUFFER,
return MEMORY_E);
XMEMCPY(priv, &input[*inOutIdx], (size_t)privSz);
*inOutIdx += (word32)length;
if ((*inOutIdx + 1) < inSz) {
b = input[*inOutIdx];
if (b == ECC_PREFIX_0) {
*inOutIdx += 1;
if (GetLength(input, inOutIdx, &length, inSz) <= 0)
ret = ASN_PARSE_E;
else {
ret = GetObjectId(input, inOutIdx, &oidSum, oidIgnoreType,
inSz);
if (ret == 0) {
if ((ret = CheckCurve(oidSum)) < 0)
ret = ECC_CURVE_OID_E;
else {
curve_id = ret;
ret = 0;
}
}
}
}
}
if (ret == 0 && (*inOutIdx + 1) < inSz) {
b = input[*inOutIdx];
*inOutIdx += 1;
if (b != ECC_PREFIX_1) {
ret = ASN_ECC_KEY_E;
}
else if (GetLength(input, inOutIdx, &length, inSz) <= 0) {
ret = ASN_PARSE_E;
}
else {
ret = CheckBitString(input, inOutIdx, &length, inSz, 0, NULL);
if (ret == 0) {
pubSz = length;
if (pubSz > 2*(ECC_MAXSIZE+1))
ret = BUFFER_E;
else {
WC_ALLOC_VAR_EX(pub, byte, pubSz, key->heap,
DYNAMIC_TYPE_TMP_BUFFER, ret=MEMORY_E);
if (WC_VAR_OK(pub))
{
XMEMCPY(pub, &input[*inOutIdx], (size_t)pubSz);
*inOutIdx += (word32)length;
pubData = pub;
}
}
}
}
}
if (ret == 0) {
ret = wc_ecc_import_private_key_ex(priv, (word32)privSz, pubData,
(word32)pubSz, key, curve_id);
}
WC_FREE_VAR_EX(priv, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(pub, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
#ifdef WOLFSSL_CUSTOM_CURVES
static int ASNToHexString(const byte* input, word32* inOutIdx, char** out,
word32 inSz, void* heap, int heapType)
{
int len;
int i;
char* str;
word32 localIdx;
byte tag;
if (*inOutIdx >= inSz) {
return BUFFER_E;
}
localIdx = *inOutIdx;
if (GetASNTag(input, &localIdx, &tag, inSz) == 0 && tag == ASN_INTEGER) {
if (GetASNInt(input, inOutIdx, &len, inSz) < 0)
return ASN_PARSE_E;
}
else {
if (GetOctetString(input, inOutIdx, &len, inSz) < 0)
return ASN_PARSE_E;
}
str = (char*)XMALLOC((size_t)len * 2 + 1, heap, heapType);
if (str == NULL) {
return MEMORY_E;
}
for (i=0; i<len; i++)
ByteToHexStr(input[*inOutIdx + (word32)i], str + i*2);
str[len*2] = '\0';
*inOutIdx += (word32)len;
*out = str;
(void)heap;
(void)heapType;
return 0;
}
static int EccKeyParamCopy(char** dst, char* src, void* heap)
{
int ret = 0;
#ifdef WOLFSSL_ECC_CURVE_STATIC
word32 length;
#endif
if (dst == NULL || src == NULL)
return BAD_FUNC_ARG;
#ifndef WOLFSSL_ECC_CURVE_STATIC
*dst = src;
#else
length = (int)XSTRLEN(src) + 1;
if (length > MAX_ECC_STRING) {
WOLFSSL_MSG("ECC Param too large for buffer");
ret = BUFFER_E;
}
else {
XSTRNCPY(*dst, src, MAX_ECC_STRING);
}
XFREE(src, heap, DYNAMIC_TYPE_ECC_BUFFER);
#endif
(void)heap;
return ret;
}
#endif
WOLFSSL_ABI
int wc_EccPublicKeyDecode(const byte* input, word32* inOutIdx,
ecc_key* key, word32 inSz)
{
int ret;
int version, length;
int curve_id = ECC_CURVE_DEF;
word32 oidSum, localIdx;
byte tag, isPrivFormat = 0;
if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0)
return BAD_FUNC_ARG;
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
if (GetMyVersion(input, inOutIdx, &version, inSz) >= 0) {
isPrivFormat = 1;
if (*inOutIdx >= inSz)
return ASN_PARSE_E;
tag = input[*inOutIdx];
*inOutIdx += 1;
if (tag != 4 && tag != 6 && tag != 7)
return ASN_PARSE_E;
if (GetLength(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
if (length > ECC_MAXSIZE)
return BUFFER_E;
*inOutIdx += (word32)length;
if (*inOutIdx >= inSz)
return ASN_PARSE_E;
tag = input[*inOutIdx];
*inOutIdx += 1;
if (tag != ECC_PREFIX_0)
return ASN_ECC_KEY_E;
if (GetLength(input, inOutIdx, &length, inSz) <= 0)
return ASN_PARSE_E;
}
else {
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
ret = SkipObjectId(input, inOutIdx, inSz);
if (ret != 0)
return ret;
}
if (*inOutIdx >= inSz) {
return BUFFER_E;
}
localIdx = *inOutIdx;
if (GetASNTag(input, &localIdx, &tag, inSz) == 0 &&
tag == (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
#ifdef WOLFSSL_CUSTOM_CURVES
ecc_set_type* curve;
int len;
char* point = NULL;
ret = 0;
curve = (ecc_set_type*)XMALLOC(sizeof(*curve), key->heap,
DYNAMIC_TYPE_ECC_BUFFER);
if (curve == NULL)
ret = MEMORY_E;
if (ret == 0) {
static const char customName[] = "Custom";
XMEMSET(curve, 0, sizeof(*curve));
#ifndef WOLFSSL_ECC_CURVE_STATIC
curve->name = customName;
#else
XMEMCPY((void*)curve->name, customName, sizeof(customName));
#endif
curve->id = ECC_CURVE_CUSTOM;
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
ret = ASN_PARSE_E;
}
if (ret == 0) {
GetInteger7Bit(input, inOutIdx, inSz);
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
ret = ASN_PARSE_E;
}
if (ret == 0) {
char* p = NULL;
SkipObjectId(input, inOutIdx, inSz);
ret = ASNToHexString(input, inOutIdx, &p, inSz,
key->heap, DYNAMIC_TYPE_ECC_BUFFER);
if (ret == 0) {
#ifndef WOLFSSL_ECC_CURVE_STATIC
ret = EccKeyParamCopy((char**)&curve->prime, p, key->heap);
#else
const char *_tmp_ptr = &curve->prime[0];
ret = EccKeyParamCopy((char**)&_tmp_ptr, p, key->heap);
#endif
}
}
if (ret == 0) {
curve->size = (int)XSTRLEN(curve->prime) / 2;
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
ret = ASN_PARSE_E;
}
if (ret == 0) {
char* af = NULL;
ret = ASNToHexString(input, inOutIdx, &af, inSz,
key->heap, DYNAMIC_TYPE_ECC_BUFFER);
if (ret == 0) {
#ifndef WOLFSSL_ECC_CURVE_STATIC
ret = EccKeyParamCopy((char**)&curve->Af, af, key->heap);
#else
const char *_tmp_ptr = &curve->Af[0];
ret = EccKeyParamCopy((char**)&_tmp_ptr, af, key->heap);
#endif
}
}
if (ret == 0) {
char* bf = NULL;
ret = ASNToHexString(input, inOutIdx, &bf, inSz,
key->heap, DYNAMIC_TYPE_ECC_BUFFER);
if (ret == 0) {
#ifndef WOLFSSL_ECC_CURVE_STATIC
ret = EccKeyParamCopy((char**)&curve->Bf, bf, key->heap);
#else
const char *_tmp_ptr = &curve->Bf[0];
ret = EccKeyParamCopy((char**)&_tmp_ptr, bf, key->heap);
#endif
}
}
if (ret == 0) {
localIdx = *inOutIdx;
if (*inOutIdx < inSz && GetASNTag(input, &localIdx, &tag, inSz)
== 0 && tag == ASN_BIT_STRING) {
len = 0;
ret = GetASNHeader(input, ASN_BIT_STRING, inOutIdx, &len, inSz);
if (ret > 0)
ret = 0;
*inOutIdx += (word32)len;
}
}
if (ret == 0) {
ret = ASNToHexString(input, inOutIdx, (char**)&point, inSz,
key->heap, DYNAMIC_TYPE_ECC_BUFFER);
if (ret == 0 && (int)XSTRLEN(point) < (curve->size * 4) + 2) {
XFREE(point, key->heap, DYNAMIC_TYPE_ECC_BUFFER);
ret = BUFFER_E;
}
}
if (ret == 0) {
#ifndef WOLFSSL_ECC_CURVE_STATIC
curve->Gx = (const char*)XMALLOC((size_t)curve->size * 2 + 2,
key->heap, DYNAMIC_TYPE_ECC_BUFFER);
curve->Gy = (const char*)XMALLOC((size_t)curve->size * 2 + 2,
key->heap, DYNAMIC_TYPE_ECC_BUFFER);
if (curve->Gx == NULL || curve->Gy == NULL) {
XFREE(point, key->heap, DYNAMIC_TYPE_ECC_BUFFER);
ret = MEMORY_E;
}
#else
if (curve->size * 2 + 2 > MAX_ECC_STRING) {
WOLFSSL_MSG("curve size is too large to fit in buffer");
ret = BUFFER_E;
}
#endif
}
if (ret == 0) {
char* o = NULL;
XMEMCPY((char*)curve->Gx, point + 2, (size_t)curve->size * 2);
XMEMCPY((char*)curve->Gy, point + curve->size * 2 + 2,
(size_t)curve->size * 2);
((char*)curve->Gx)[curve->size * 2] = '\0';
((char*)curve->Gy)[curve->size * 2] = '\0';
XFREE(point, key->heap, DYNAMIC_TYPE_ECC_BUFFER);
ret = ASNToHexString(input, inOutIdx, &o, inSz,
key->heap, DYNAMIC_TYPE_ECC_BUFFER);
if (ret == 0) {
#ifndef WOLFSSL_ECC_CURVE_STATIC
ret = EccKeyParamCopy((char**)&curve->order, o, key->heap);
#else
const char *_tmp_ptr = &curve->order[0];
ret = EccKeyParamCopy((char**)&_tmp_ptr, o, key->heap);
#endif
}
}
if (ret == 0) {
curve->cofactor = GetInteger7Bit(input, inOutIdx, inSz);
#ifndef WOLFSSL_ECC_CURVE_STATIC
curve->oid = NULL;
#else
XMEMSET((void*)curve->oid, 0, sizeof(curve->oid));
#endif
curve->oidSz = 0;
curve->oidSum = 0;
if (wc_ecc_set_custom_curve(key, curve) < 0) {
ret = ASN_PARSE_E;
}
key->deallocSet = 1;
curve = NULL;
}
if (curve != NULL)
wc_ecc_free_curve(curve, key->heap);
if (ret < 0)
return ret;
#else
return ASN_PARSE_E;
#endif
}
else {
ret = GetObjectId(input, inOutIdx, &oidSum, oidIgnoreType, inSz);
if (ret != 0)
return ret;
if ((ret = CheckCurve(oidSum)) < 0)
return ECC_CURVE_OID_E;
else {
curve_id = ret;
}
}
if (isPrivFormat) {
if (*inOutIdx >= inSz)
return ASN_PARSE_E;
tag = input[*inOutIdx];
*inOutIdx += 1;
if (tag != ECC_PREFIX_1)
return ASN_ECC_KEY_E;
if (GetLength(input, inOutIdx, &length, inSz) <= 0)
return ASN_PARSE_E;
}
ret = CheckBitString(input, inOutIdx, &length, inSz, 1, NULL);
if (ret != 0)
return ret;
if (wc_ecc_import_x963_ex(input + *inOutIdx, (word32)length, key,
curve_id) != 0) {
return ASN_ECC_KEY_E;
}
*inOutIdx += (word32)length;
return 0;
}
#ifdef HAVE_ECC_KEY_EXPORT
int wc_BuildEccKeyDer(ecc_key* key, byte* output, word32 *inLen,
int pubIn, int curveIn)
{
byte curve[MAX_ALGO_SZ+2];
byte ver[MAX_VERSION_SZ];
byte seq[MAX_SEQ_SZ];
int ret, curveSz, verSz;
word32 totalSz;
int privHdrSz = ASN_ECC_HEADER_SZ;
int pubHdrSz = ASN_ECC_CONTEXT_SZ + ASN_ECC_HEADER_SZ;
#ifdef WOLFSSL_NO_MALLOC
byte prv[MAX_ECC_BYTES + ASN_ECC_HEADER_SZ + MAX_SEQ_SZ];
byte pub[(MAX_ECC_BYTES * 2) + 1 + ASN_ECC_CONTEXT_SZ +
ASN_ECC_HEADER_SZ + MAX_SEQ_SZ];
#else
byte *prv = NULL, *pub = NULL;
#endif
word32 idx = 0, prvidx = 0, pubidx = 0, curveidx = 0;
word32 seqSz, privSz, pubSz = ECC_BUFSIZE;
if (key == NULL || (output == NULL && inLen == NULL))
return BAD_FUNC_ARG;
if (curveIn) {
curve[curveidx++] = ECC_PREFIX_0;
curveidx++ ;
curveSz = SetCurve(key, curve+curveidx, MAX_ALGO_SZ);
if (curveSz < 0)
return curveSz;
curve[1] = (byte)curveSz;
curveidx += (word32)curveSz;
}
privSz = (word32)key->dp->size;
#ifdef WOLFSSL_QNX_CAAM
if (key->blackKey > 0 && key->blackKey != CAAM_BLACK_KEY_ECB) {
privSz = privSz + WC_CAAM_MAC_SZ;
}
#endif
#ifndef WOLFSSL_NO_MALLOC
prv = (byte*)XMALLOC(privSz + (word32)privHdrSz + MAX_SEQ_SZ,
key->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (prv == NULL) {
return MEMORY_E;
}
#else
if (sizeof(prv) < privSz + privHdrSz + MAX_SEQ_SZ) {
return BUFFER_E;
}
#endif
if (privSz < ASN_LONG_LENGTH) {
prvidx += SetOctetString8Bit(privSz, &prv[prvidx]);
}
else {
prvidx += SetOctetString(privSz, &prv[prvidx]);
}
ret = wc_ecc_export_private_only(key, prv + prvidx, &privSz);
if (ret < 0) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(prv, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ret;
}
prvidx += privSz;
if (pubIn) {
PRIVATE_KEY_UNLOCK();
ret = wc_ecc_export_x963(key, NULL, &pubSz);
PRIVATE_KEY_LOCK();
if (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(prv, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ret;
}
#ifndef WOLFSSL_NO_MALLOC
pub = (byte*)XMALLOC(pubSz + (word32)pubHdrSz + MAX_SEQ_SZ,
key->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (pub == NULL) {
XFREE(prv, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
#else
if (sizeof(pub) < pubSz + pubHdrSz + MAX_SEQ_SZ) {
return BUFFER_E;
}
#endif
pub[pubidx++] = ECC_PREFIX_1;
if (pubSz > 128)
pubidx += SetLength(pubSz + ASN_ECC_CONTEXT_SZ + 2, pub+pubidx);
else
pubidx += SetLength(pubSz + ASN_ECC_CONTEXT_SZ + 1, pub+pubidx);
pubidx += SetBitString(pubSz, 0, pub + pubidx);
PRIVATE_KEY_UNLOCK();
ret = wc_ecc_export_x963(key, pub + pubidx, &pubSz);
PRIVATE_KEY_LOCK();
if (ret != 0) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(prv, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(pub, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ret;
}
pubidx += pubSz;
}
verSz = SetMyVersion(1, ver, FALSE);
seqSz = SetSequence((word32)verSz + prvidx + pubidx + curveidx, seq);
totalSz = prvidx + pubidx + curveidx + (word32)verSz + seqSz;
if (output == NULL) {
*inLen = totalSz;
#ifndef WOLFSSL_NO_MALLOC
XFREE(prv, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (pubIn) {
XFREE(pub, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
return WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
if (inLen != NULL && totalSz > *inLen) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(prv, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (pubIn) {
XFREE(pub, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
return BAD_FUNC_ARG;
}
XMEMCPY(output + idx, seq, seqSz);
idx = seqSz;
XMEMCPY(output + idx, ver, (size_t)verSz);
idx += (word32)verSz;
XMEMCPY(output + idx, prv, prvidx);
idx += prvidx;
#ifndef WOLFSSL_NO_MALLOC
XFREE(prv, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
XMEMCPY(output + idx, curve, curveidx);
idx += curveidx;
if (pubIn) {
XMEMCPY(output + idx, pub, pubidx);
#ifndef WOLFSSL_NO_MALLOC
XFREE(pub, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
}
return (int)totalSz;
}
#endif
#endif
#if (defined(HAVE_OCSP) || defined(HAVE_CRL)) && !defined(WOLFCRYPT_ONLY)
static int GetBasicDate(const byte* source, word32* idx, byte* date,
byte* format, int maxIdx)
{
int ret, length;
const byte *datePtr = NULL;
WOLFSSL_ENTER("GetBasicDate");
ret = GetDateInfo(source, idx, &datePtr, format, &length, maxIdx);
if (ret < 0)
return ret;
XMEMCPY(date, datePtr, length);
return 0;
}
#endif
#if defined(HAVE_OCSP) && !defined(WOLFCRYPT_ONLY)
static int GetEnumerated(const byte* input, word32* inOutIdx, int *value,
int sz)
{
word32 idx = *inOutIdx;
word32 len;
byte tag;
WOLFSSL_ENTER("GetEnumerated");
*value = 0;
if (GetASNTag(input, &idx, &tag, sz) < 0)
return ASN_PARSE_E;
if (tag != ASN_ENUMERATED)
return ASN_PARSE_E;
if ((int)idx >= sz)
return BUFFER_E;
len = input[idx++];
if (len > 4 || (int)(len + idx) > sz)
return ASN_PARSE_E;
while (len--) {
*value = *value << 8 | input[idx++];
}
*inOutIdx = idx;
return *value;
}
#ifdef HAVE_OCSP_RESPONDER
WC_MAYBE_UNUSED static int EncodeCertID(OcspEntry* entry, byte* out,
word32* outSz)
{
(void)entry;
(void)out;
(void)outSz;
return NOT_COMPILED_IN;
}
#endif
static int OcspDecodeCertIDInt(const byte* input, word32* inOutIdx, word32 inSz,
OcspEntry* entry)
{
int length;
word32 oid;
int ret;
int expectedDigestSz;
ret = GetAlgoId(input, inOutIdx, &oid, oidHashType, inSz);
if (ret < 0)
return ret;
entry->hashAlgoOID = oid;
expectedDigestSz = wc_HashGetDigestSize(wc_OidGetHash((int)oid));
if (expectedDigestSz <= 0)
return ASN_SIG_HASH_E;
ret = GetOctetString(input, inOutIdx, &length, inSz);
if (ret < 0)
return ret;
if (length != expectedDigestSz || length > (int)sizeof(entry->issuerHash))
return ASN_PARSE_E;
XMEMCPY(entry->issuerHash, input + *inOutIdx, length);
*inOutIdx += length;
ret = GetOctetString(input, inOutIdx, &length, inSz);
if (ret < 0)
return ret;
if (length != expectedDigestSz || length > (int)sizeof(entry->issuerKeyHash))
return ASN_PARSE_E;
XMEMCPY(entry->issuerKeyHash, input + *inOutIdx, length);
*inOutIdx += length;
if (wc_GetSerialNumber(input, inOutIdx, entry->status->serial,
&entry->status->serialSz, inSz) < 0)
return ASN_PARSE_E;
return 0;
}
#ifdef HAVE_OCSP_RESPONDER
WC_MAYBE_UNUSED static int EncodeSingleResponse(OcspEntry* single, byte* out,
word32* outSz, void* heap)
{
(void)single;
(void)out;
(void)outSz;
(void)heap;
return NOT_COMPILED_IN;
}
#endif
static int DecodeSingleResponse(byte* source, word32* ioIndex, word32 size,
int wrapperSz, OcspEntry* single)
{
word32 idx = *ioIndex, prevIndex, localIdx, certIdIdx;
int length;
int ret;
byte tag;
WOLFSSL_ENTER("DecodeSingleResponse");
prevIndex = idx;
if (GetSequence(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
certIdIdx = idx;
if (GetSequence(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
single->rawCertId = source + certIdIdx;
ret = OcspDecodeCertIDInt(source, &idx, size, single);
if (ret < 0)
return ASN_PARSE_E;
single->rawCertIdSize = idx - certIdIdx;
if (idx >= size)
return BUFFER_E;
switch (source[idx++])
{
case (ASN_CONTEXT_SPECIFIC | CERT_GOOD):
single->status->status = CERT_GOOD;
idx++;
break;
case (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | CERT_REVOKED):
single->status->status = CERT_REVOKED;
if (GetLength(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
idx += length;
break;
case (ASN_CONTEXT_SPECIFIC | CERT_UNKNOWN):
single->status->status = CERT_UNKNOWN;
idx++;
break;
default:
return ASN_PARSE_E;
}
if (idx >= size)
return BUFFER_E;
#ifdef WOLFSSL_OCSP_PARSE_STATUS
single->status->thisDateAsn = source + idx;
localIdx = 0;
if (GetDateInfo(single->status->thisDateAsn, &localIdx, NULL,
(byte*)&single->status->thisDateParsed.type,
&single->status->thisDateParsed.length, size - idx) < 0)
return ASN_PARSE_E;
if (idx + localIdx >= size)
return BUFFER_E;
XMEMCPY(single->status->thisDateParsed.data,
single->status->thisDateAsn + localIdx - single->status->thisDateParsed.length,
single->status->thisDateParsed.length);
#endif
if (GetBasicDate(source, &idx, single->status->thisDate,
&single->status->thisDateFormat, size) < 0)
return ASN_PARSE_E;
#ifndef NO_ASN_TIME_CHECK
#ifndef WOLFSSL_NO_OCSP_DATE_CHECK
if ((! AsnSkipDateCheck) && !XVALIDATE_DATE(single->status->thisDate,
single->status->thisDateFormat, ASN_BEFORE, MAX_DATE_SIZE))
return ASN_BEFORE_DATE_E;
#endif
#endif
localIdx = idx;
if (((int)(idx - prevIndex) < wrapperSz) &&
GetASNTag(source, &localIdx, &tag, size) == 0 &&
tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
{
idx++;
if (GetLength(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
#ifdef WOLFSSL_OCSP_PARSE_STATUS
single->status->nextDateAsn = source + idx;
localIdx = 0;
if (GetDateInfo(single->status->nextDateAsn, &localIdx, NULL,
(byte*)&single->status->nextDateParsed.type,
&single->status->nextDateParsed.length, size - idx) < 0)
return ASN_PARSE_E;
if (idx + localIdx >= size)
return BUFFER_E;
XMEMCPY(single->status->nextDateParsed.data,
single->status->nextDateAsn + localIdx - single->status->nextDateParsed.length,
single->status->nextDateParsed.length);
#endif
if (GetBasicDate(source, &idx, single->status->nextDate,
&single->status->nextDateFormat, size) < 0)
return ASN_PARSE_E;
#ifndef NO_ASN_TIME_CHECK
#ifndef WOLFSSL_NO_OCSP_DATE_CHECK
if ((! AsnSkipDateCheck) &&
!XVALIDATE_DATE(single->status->nextDate,
single->status->nextDateFormat, ASN_AFTER, MAX_DATE_SIZE))
return ASN_AFTER_DATE_E;
#endif
#endif
}
localIdx = idx;
if (((int)(idx - prevIndex) < wrapperSz) &&
GetASNTag(source, &localIdx, &tag, size) == 0 &&
tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1))
{
idx++;
if (GetLength(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
idx += length;
}
*ioIndex = idx;
return 0;
}
static int DecodeOcspRespExtensions(byte* source, word32* ioIndex,
OcspResponse* resp, word32 sz)
{
word32 idx = *ioIndex;
int length;
int ext_bound;
word32 oid;
int ret;
byte tag;
WOLFSSL_ENTER("DecodeOcspRespExtensions");
if ((idx + 1) > sz)
return BUFFER_E;
if (GetASNTag(source, &idx, &tag, sz) < 0)
return ASN_PARSE_E;
if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1))
return ASN_PARSE_E;
if (GetLength(source, &idx, &length, sz) < 0)
return ASN_PARSE_E;
if (GetSequence(source, &idx, &length, sz) < 0)
return ASN_PARSE_E;
ext_bound = idx + length;
while (idx < (word32)ext_bound) {
word32 localIdx;
if (GetSequence(source, &idx, &length, sz) < 0) {
WOLFSSL_MSG("\tfail: should be a SEQUENCE");
return ASN_PARSE_E;
}
oid = 0;
if (GetObjectId(source, &idx, &oid, oidOcspType, sz) < 0) {
WOLFSSL_MSG("\tfail: OBJECT ID");
return ASN_PARSE_E;
}
if ((idx + 1) > (word32)sz) {
WOLFSSL_MSG("\tfail: malformed buffer");
return BUFFER_E;
}
localIdx = idx;
if (GetASNTag(source, &localIdx, &tag, sz) == 0 && tag == ASN_BOOLEAN) {
WOLFSSL_MSG("\tfound optional critical flag, moving past");
ret = GetBoolean(source, &idx, sz);
if (ret < 0)
return ret;
}
ret = GetOctetString(source, &idx, &length, sz);
if (ret < 0)
return ret;
if (oid == OCSP_NONCE_OID) {
ret = GetOctetString(source, &idx, &length, sz);
if (ret < 0)
return ret;
resp->nonce = source + idx;
resp->nonceSz = length;
}
idx += length;
}
*ioIndex = idx;
return 0;
}
WC_MAYBE_UNUSED static int EncodeOcspRespExtensions(OcspResponse* resp,
byte* out, word32* outSz)
{
(void)resp;
(void)out;
(void)outSz;
return NOT_COMPILED_IN;
}
#ifdef HAVE_OCSP_RESPONDER
WC_MAYBE_UNUSED static int EncodeResponseData(OcspResponse* resp, byte* out,
word32* outSz)
{
(void)resp;
(void)out;
(void)outSz;
return NOT_COMPILED_IN;
}
#endif
static int DecodeResponseData(byte* source, word32* ioIndex,
OcspResponse* resp, word32 size)
{
word32 idx = *ioIndex, prev_idx, localIdx;
int length;
int version;
int ret;
byte tag;
int wrapperSz;
OcspEntry* single;
WOLFSSL_ENTER("DecodeResponseData");
resp->response = source + idx;
prev_idx = idx;
if (GetSequence(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
resp->responseSz = length + idx - prev_idx;
localIdx = idx;
if (GetASNTag(source, &localIdx, &tag, size) == 0 &&
tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED))
{
idx += 2;
if (GetMyVersion(source, &idx, &version, size) < 0)
return ASN_PARSE_E;
} else
version = 0;
localIdx = idx;
if (GetASNTag(source, &localIdx, &tag, size) != 0)
return ASN_PARSE_E;
resp->responderIdType = OCSP_RESPONDER_ID_INVALID;
if (tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1))
{
idx++;
if (GetLength(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
resp->responderIdType = OCSP_RESPONDER_ID_NAME;
ret = CalcHashId_ex(source + idx, length,
resp->responderId.nameHash, OCSP_RESPONDER_ID_HASH_TYPE);
if (ret != 0)
return ret;
idx += length;
}
else if (tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 2))
{
idx++;
if (GetLength(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
if (GetOctetString(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
if (length != OCSP_RESPONDER_ID_KEY_SZ)
return ASN_PARSE_E;
resp->responderIdType = OCSP_RESPONDER_ID_KEY;
XMEMCPY(resp->responderId.keyHash, source + idx, length);
idx += length;
}
if (resp->responderIdType == OCSP_RESPONDER_ID_INVALID)
return ASN_PARSE_E;
if (GetBasicDate(source, &idx, resp->producedDate,
&resp->producedDateFormat, size) < 0)
return ASN_PARSE_E;
if (GetSequence(source, &idx, &wrapperSz, size) < 0)
return ASN_PARSE_E;
localIdx = idx;
single = resp->single;
while (idx - localIdx < (word32)wrapperSz) {
ret = DecodeSingleResponse(source, &idx, size, wrapperSz, single);
if (ret < 0)
return ret;
if (idx - localIdx < (word32)wrapperSz) {
single->next = (OcspEntry*)XMALLOC(sizeof(OcspEntry), resp->heap,
DYNAMIC_TYPE_OCSP_ENTRY);
if (single->next == NULL) {
return MEMORY_E;
}
XMEMSET(single->next, 0, sizeof(OcspEntry));
single->next->status = (CertStatus*)XMALLOC(sizeof(CertStatus),
resp->heap, DYNAMIC_TYPE_OCSP_STATUS);
if (single->next->status == NULL) {
XFREE(single->next, resp->heap, DYNAMIC_TYPE_OCSP_ENTRY);
single->next = NULL;
return MEMORY_E;
}
XMEMSET(single->next->status, 0, sizeof(CertStatus));
single->next->isDynamic = 1;
single->next->ownStatus = 1;
single = single->next;
}
}
if (idx - prev_idx < resp->responseSz)
if (DecodeOcspRespExtensions(source, &idx, resp, size) < 0)
return ASN_PARSE_E;
*ioIndex = idx;
return 0;
}
#ifndef WOLFSSL_NO_OCSP_OPTIONAL_CERTS
static int DecodeCerts(byte* source,
word32* ioIndex, OcspResponse* resp, word32 size)
{
word32 idx = *ioIndex;
byte tag;
WOLFSSL_ENTER("DecodeCerts");
if (GetASNTag(source, &idx, &tag, size) < 0)
return ASN_PARSE_E;
if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC))
{
int length;
if (GetLength(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
if (GetSequence(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
resp->cert = source + idx;
resp->certSz = length;
idx += length;
}
*ioIndex = idx;
return 0;
}
#endif
#ifdef HAVE_OCSP_RESPONDER
WC_MAYBE_UNUSED static int EncodeBasicOcspResponse(OcspResponse* resp,
byte* out, word32* outSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng)
{
(void)resp;
(void)out;
(void)outSz;
(void)rsaKey;
(void)eccKey;
(void)rng;
return NOT_COMPILED_IN;
}
#endif
static int DecodeBasicOcspResponse(byte* source, word32* ioIndex,
OcspResponse* resp, word32 size, void* cm, void* heap, int noVerify,
int noVerifySignature)
{
int length;
word32 idx = *ioIndex;
#ifndef WOLFSSL_NO_OCSP_OPTIONAL_CERTS
word32 end_index;
#endif
int ret;
int sigLength;
int sigValid = 0;
WOLFSSL_ENTER("DecodeBasicOcspResponse");
(void)heap;
if (GetSequence(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
if (idx + length > size)
return ASN_INPUT_E;
#ifndef WOLFSSL_NO_OCSP_OPTIONAL_CERTS
end_index = idx + length;
#endif
if ((ret = DecodeResponseData(source, &idx, resp, size)) < 0)
return ret;
if (GetAlgoId(source, &idx, &resp->sigOID, oidSigType, size) < 0) {
return ASN_PARSE_E;
}
#ifdef WC_RSA_PSS
else if (resp->sigOID == CTC_RSASSAPSS) {
word32 sz;
int len;
byte* params;
sz = idx;
params = source + idx;
if (GetSequence(source, &idx, &len, size) < 0)
return ASN_PARSE_E;
if (ret == 0) {
idx += len;
resp->sigParams = params;
resp->sigParamsSz = idx - sz;
}
}
#endif
ret = CheckBitString(source, &idx, &sigLength, size, 1, NULL);
if (ret != 0)
return ret;
resp->sigSz = sigLength;
resp->sig = source + idx;
idx += sigLength;
#ifndef WOLFSSL_NO_OCSP_OPTIONAL_CERTS
if (idx < end_index)
{
if (DecodeCerts(source, &idx, resp, size) < 0)
return ASN_PARSE_E;
ret = OcspCheckCert(resp, noVerify, noVerifySignature,
(WOLFSSL_CERT_MANAGER*)cm, heap);
if (ret == 0) {
sigValid = 1;
}
else {
WOLFSSL_MSG("OCSP Internal cert can't verify the response\n");
ret = 0;
}
}
#endif
if (!noVerifySignature && !sigValid) {
Signer* ca;
SignatureCtx sigCtx;
ca = OcspFindSigner(resp, (WOLFSSL_CERT_MANAGER*)cm);
if (ca == NULL)
return ASN_NO_SIGNER_E;
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHECK
if (OcspRespCheck(resp, ca, cm) != 0)
return BAD_OCSP_RESPONDER;
#endif
InitSignatureCtx(&sigCtx, heap, INVALID_DEVID);
sigValid = ConfirmSignature(&sigCtx, resp->response,
resp->responseSz, ca->publicKey, ca->pubKeySize, ca->keyOID,
resp->sig, resp->sigSz, resp->sigOID, resp->sigParams,
resp->sigParamsSz, NULL);
if (sigValid != 0) {
WOLFSSL_MSG("\tOCSP Confirm signature failed");
return ASN_OCSP_CONFIRM_E;
}
(void)noVerify;
}
*ioIndex = idx;
return 0;
}
#ifdef HAVE_OCSP_RESPONDER
int OcspResponseEncode(OcspResponse* resp, byte* out, word32* outSz,
RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng)
{
(void)resp;
(void)out;
(void)outSz;
(void)rsaKey;
(void)eccKey;
(void)rng;
return NOT_COMPILED_IN;
}
#endif
int OcspResponseDecode(OcspResponse* resp, void* cm, void* heap,
int noVerifyCert, int noVerifySignature)
{
int ret;
int length = 0;
word32 idx = 0;
byte* source = resp->source;
word32 size = resp->maxIdx;
word32 oid;
byte tag;
WOLFSSL_ENTER("OcspResponseDecode");
if (GetSequence(source, &idx, &length, size) < 0) {
WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E);
return ASN_PARSE_E;
}
if (GetEnumerated(source, &idx, &resp->responseStatus, size) < 0) {
WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E);
return ASN_PARSE_E;
}
if (resp->responseStatus != OCSP_SUCCESSFUL) {
WOLFSSL_LEAVE("OcspResponseDecode", 0);
return 0;
}
if (idx >= size) {
WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E);
return ASN_PARSE_E;
}
if (GetASNTag(source, &idx, &tag, size) < 0) {
WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E);
return ASN_PARSE_E;
}
if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E);
return ASN_PARSE_E;
}
if (GetLength(source, &idx, &length, size) < 0) {
WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E);
return ASN_PARSE_E;
}
if (GetSequence(source, &idx, &length, size) < 0) {
WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E);
return ASN_PARSE_E;
}
if (GetObjectId(source, &idx, &oid, oidOcspType, size) < 0) {
WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E);
return ASN_PARSE_E;
}
if (oid != OCSP_BASIC_OID) {
WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E);
return ASN_PARSE_E;
}
ret = GetOctetString(source, &idx, &length, size);
if (ret < 0) {
WOLFSSL_LEAVE("OcspResponseDecode", ret);
return ret;
}
ret = DecodeBasicOcspResponse(source, &idx, resp, size, cm, heap,
noVerifyCert, noVerifySignature);
if (ret < 0) {
WOLFSSL_LEAVE("OcspResponseDecode", ret);
return ret;
}
WOLFSSL_LEAVE("OcspResponseDecode", 0);
return 0;
}
int EncodeOcspRequest(OcspRequest* req, byte* output, word32 size)
{
byte seqArray[5][MAX_SEQ_SZ];
byte algoArray[MAX_ALGO_SZ];
byte issuerArray[MAX_ENCODED_DIG_SZ];
byte issuerKeyArray[MAX_ENCODED_DIG_SZ];
byte snArray[MAX_SN_SZ];
byte extArray[MAX_OCSP_EXT_SZ];
word32 seqSz[5], algoSz, issuerSz, issuerKeySz, extSz, totalSz;
int i, snSz;
int keyIdSz;
WOLFSSL_ENTER("EncodeOcspRequest");
algoSz = SetAlgoID(req->hashAlg, algoArray, oidHashType, 0);
keyIdSz = wc_HashGetDigestSize(wc_OidGetHash(req->hashAlg));
if (keyIdSz <= 0 || keyIdSz > WC_MAX_DIGEST_SIZE)
return BAD_FUNC_ARG;
issuerSz = SetDigest(req->issuerHash, keyIdSz, issuerArray);
issuerKeySz = SetDigest(req->issuerKeyHash, keyIdSz, issuerKeyArray);
snSz = SetSerialNumber(req->serial, req->serialSz, snArray,
MAX_SN_SZ, MAX_SN_SZ);
extSz = 0;
if (snSz < 0)
return snSz;
if (req->nonceSz) {
extSz = EncodeOcspRequestExtensions(req, extArray + 2,
OCSP_NONCE_EXT_SZ);
extSz += SetExplicit(2, extSz, extArray, 0);
}
totalSz = algoSz + issuerSz + issuerKeySz + snSz;
for (i = 4; i >= 0; i--) {
seqSz[i] = SetSequence(totalSz, seqArray[i]);
totalSz += seqSz[i];
if (i == 2) totalSz += extSz;
}
if (output == NULL)
return totalSz;
if (totalSz > size)
return BUFFER_E;
totalSz = 0;
for (i = 0; i < 5; i++) {
XMEMCPY(output + totalSz, seqArray[i], seqSz[i]);
totalSz += seqSz[i];
}
XMEMCPY(output + totalSz, algoArray, algoSz);
totalSz += algoSz;
XMEMCPY(output + totalSz, issuerArray, issuerSz);
totalSz += issuerSz;
XMEMCPY(output + totalSz, issuerKeyArray, issuerKeySz);
totalSz += issuerKeySz;
XMEMCPY(output + totalSz, snArray, snSz);
totalSz += snSz;
if (extSz != 0) {
XMEMCPY(output + totalSz, extArray, extSz);
totalSz += extSz;
}
return totalSz;
}
#ifdef HAVE_OCSP_RESPONDER
int DecodeOcspRequest(OcspRequest* req, const byte* input, word32 size)
{
(void)req;
(void)input;
(void)size;
return NOT_COMPILED_IN;
}
#endif
#endif
int GetNameHash_ex(const byte* source, word32* idx, byte* hash, int maxIdx,
word32 sigOID)
{
int length;
int ret;
word32 dummy;
byte tag;
WOLFSSL_ENTER("GetNameHash");
dummy = *idx;
if (GetASNTag(source, &dummy, &tag, (word32)maxIdx) == 0 &&
tag == ASN_OBJECT_ID) {
WOLFSSL_MSG("Trying optional prefix...");
if (GetLength(source, idx, &length, (word32)maxIdx) < 0)
return ASN_PARSE_E;
*idx += (word32)length;
WOLFSSL_MSG("Got optional prefix");
}
dummy = *idx;
if (GetSequence(source, idx, &length, (word32)maxIdx) < 0)
return ASN_PARSE_E;
ret = CalcHashId_ex(source + dummy, (word32)length + *idx - dummy, hash,
HashIdAlg(sigOID));
*idx += (word32)length;
return ret;
}
#if defined(HAVE_CRL) && !defined(WOLFCRYPT_ONLY)
static int GetRevoked(RevokedCert* rcert, const byte* buff, word32* idx,
DecodedCRL* dcrl, word32 maxIdx)
{
int ret;
int len;
word32 end;
RevokedCert* rc;
#ifdef CRL_STATIC_REVOKED_LIST
int totalCerts = 0;
#endif
WOLFSSL_ENTER("GetRevoked");
if (GetSequence(buff, idx, &len, maxIdx) < 0)
return ASN_PARSE_E;
end = *idx + len;
#ifdef CRL_STATIC_REVOKED_LIST
totalCerts = dcrl->totalCerts;
if (totalCerts >= CRL_MAX_REVOKED_CERTS) {
return MEMORY_E;
}
rc = &rcert[totalCerts];
ret = wc_GetSerialNumber(buff, idx, rc->serialNumber, &rc->serialSz,maxIdx);
if (ret < 0) {
WOLFSSL_MSG("wc_GetSerialNumber error");
return ret;
}
#else
rc = (RevokedCert*)XMALLOC(sizeof(RevokedCert), dcrl->heap,
DYNAMIC_TYPE_REVOKED);
if (rc == NULL) {
WOLFSSL_MSG("Alloc Revoked Cert failed");
return MEMORY_E;
}
XMEMSET(rc, 0, sizeof(RevokedCert));
ret = wc_GetSerialNumber(buff, idx, rc->serialNumber, &rc->serialSz,maxIdx);
if (ret < 0) {
WOLFSSL_MSG("wc_GetSerialNumber error");
XFREE(rc, dcrl->heap, DYNAMIC_TYPE_REVOKED);
return ret;
}
rc->next = dcrl->certs;
dcrl->certs = rc;
(void)rcert;
#endif
dcrl->totalCerts++;
#ifndef NO_ASN_TIME
ret = GetBasicDate(buff, idx, rc->revDate, &rc->revDateFormat, maxIdx);
if (ret < 0) {
WOLFSSL_MSG("Expecting Date");
return ret;
}
#endif
rc->reasonCode = -1;
if (*idx < end) {
word32 extIdx = *idx;
int extLen;
byte tag;
if (GetASNTag(buff, &extIdx, &tag, end) == 0 &&
tag == (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
word32 seqIdx = extIdx - 1;
if (GetSequence(buff, &seqIdx, &extLen, end) >= 0) {
word32 extEnd = seqIdx + (word32)extLen;
#if defined(OPENSSL_EXTRA)
{
word32 rawStart = *idx;
word32 rawLen = end - rawStart;
rc->extensions = (byte*)XMALLOC(rawLen, dcrl->heap,
DYNAMIC_TYPE_REVOKED);
if (rc->extensions != NULL) {
XMEMCPY(rc->extensions, buff + rawStart, rawLen);
rc->extensionsSz = rawLen;
}
}
#endif
ParseCRL_ReasonCode(buff, seqIdx, extEnd, &rc->reasonCode);
}
}
}
*idx = end;
return 0;
}
static int GetCRL_Signature(const byte* source, word32* idx, DecodedCRL* dcrl,
int maxIdx)
{
int length;
int ret;
WOLFSSL_ENTER("GetCRL_Signature");
ret = CheckBitString(source, idx, &length, maxIdx, 1, NULL);
if (ret != 0)
return ret;
dcrl->sigLength = length;
dcrl->signature = (byte*)&source[*idx];
*idx += dcrl->sigLength;
return 0;
}
static int ParseCRL_CertList(RevokedCert* rcert, DecodedCRL* dcrl,
const byte* buf,word32* inOutIdx, int sz, int verify)
{
word32 oid, dateIdx, idx, checkIdx;
int length;
#ifdef WOLFSSL_NO_CRL_NEXT_DATE
int doNextDate = 1;
#endif
byte tag;
if (dcrl == NULL || inOutIdx == NULL || buf == NULL) {
return BAD_FUNC_ARG;
}
idx = *inOutIdx;
checkIdx = idx;
if (GetASNTag(buf, &checkIdx, &tag, sz) == 0 && tag == ASN_INTEGER) {
if (GetMyVersion(buf, &idx, &dcrl->version, sz) < 0)
return ASN_PARSE_E;
dcrl->version++;
}
if (GetAlgoId(buf, &idx, &oid, oidIgnoreType, sz) < 0) {
return ASN_PARSE_E;
}
#ifdef WC_RSA_PSS
else if (oid == CTC_RSASSAPSS) {
word32 tmpSz;
int len;
tmpSz = idx;
dcrl->sigParamsIndex = idx;
if (GetSequence(buf, &idx, &len, sz) < 0) {
dcrl->sigParamsIndex = 0;
return ASN_PARSE_E;
}
idx += len;
dcrl->sigParamsLength = idx - tmpSz;
}
#endif
checkIdx = idx;
if (GetSequence(buf, &checkIdx, &length, sz) < 0) {
return ASN_PARSE_E;
}
#ifdef OPENSSL_EXTRA
dcrl->issuerSz = length + (checkIdx - idx);
dcrl->issuer = (byte*)GetNameFromDer(buf + idx, (int)dcrl->issuerSz);
#endif
if (GetNameHash_ex(buf, &idx, dcrl->issuerHash, sz, oid) < 0)
return ASN_PARSE_E;
if (GetBasicDate(buf, &idx, dcrl->lastDate, &dcrl->lastDateFormat, sz) < 0)
return ASN_PARSE_E;
dateIdx = idx;
if (GetBasicDate(buf, &idx, dcrl->nextDate, &dcrl->nextDateFormat, sz) < 0)
{
#ifndef WOLFSSL_NO_CRL_NEXT_DATE
(void)dateIdx;
return ASN_PARSE_E;
#else
dcrl->nextDateFormat = ASN_OTHER_TYPE;
doNextDate = 0;
idx = dateIdx;
#endif
}
#ifdef WOLFSSL_NO_CRL_NEXT_DATE
if (doNextDate)
#endif
{
#if !defined(NO_ASN_TIME) && !defined(WOLFSSL_NO_CRL_DATE_CHECK)
if (verify != NO_VERIFY &&
(! AsnSkipDateCheck) &&
!XVALIDATE_DATE(dcrl->nextDate, dcrl->nextDateFormat, ASN_AFTER,
MAX_DATE_SIZE)) {
WOLFSSL_MSG("CRL after date is no longer valid");
WOLFSSL_ERROR_VERBOSE(CRL_CERT_DATE_ERR);
return CRL_CERT_DATE_ERR;
}
#else
(void)verify;
#endif
}
checkIdx = idx;
if ((idx != dcrl->sigIndex) && (GetASNTag(buf, &checkIdx, &tag, sz) == 0) &&
(tag != CRL_EXTENSIONS)) {
int len;
word32 tlen;
if (GetSequence(buf, &idx, &len, sz) < 0)
return ASN_PARSE_E;
tlen = (word32)len + idx;
if (tlen < idx)
return ASN_PARSE_E;
while (idx < tlen) {
if (GetRevoked(rcert, buf, &idx, dcrl, tlen) < 0)
return ASN_PARSE_E;
}
}
*inOutIdx = idx;
return 0;
}
#ifndef NO_SKID
static int ParseCRL_AuthKeyIdExt(const byte* input, int sz, DecodedCRL* dcrl)
{
word32 idx = 0;
int length = 0, ret = 0;
byte tag;
WOLFSSL_ENTER("ParseCRL_AuthKeyIdExt");
if (GetSequence(input, &idx, &length, sz) < 0) {
WOLFSSL_MSG("\tfail: should be a SEQUENCE");
return ASN_PARSE_E;
}
if (GetASNTag(input, &idx, &tag, sz) < 0) {
return ASN_PARSE_E;
}
if (tag != (ASN_CONTEXT_SPECIFIC | 0)) {
WOLFSSL_MSG("\tinfo: OPTIONAL item 0, not available");
return 0;
}
if (GetLength(input, &idx, &length, sz) <= 0) {
WOLFSSL_MSG("\tfail: extension data length");
return ASN_PARSE_E;
}
dcrl->extAuthKeyIdSet = 1;
ret = GetHashId(input + idx, length, dcrl->extAuthKeyId,
HashIdAlg(dcrl->signatureOID));
return ret;
}
#endif
static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf,
word32* inOutIdx, word32 sz)
{
int length;
word32 idx;
word32 ext_bound;
word32 oid;
byte tag;
WOLFSSL_ENTER("ParseCRL_Extensions");
(void)dcrl;
if (inOutIdx == NULL)
return BAD_FUNC_ARG;
idx = *inOutIdx;
if ((idx + 1) > sz)
return 0;
if (GetASNTag(buf, &idx, &tag, sz) < 0)
return 0;
if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
return 0;
if (GetLength(buf, &idx, &length, sz) < 0)
return ASN_PARSE_E;
if (GetSequence(buf, &idx, &length, sz) < 0)
return ASN_PARSE_E;
ext_bound = idx + length;
while (idx < (word32)ext_bound) {
word32 localIdx;
int ret;
if (GetSequence(buf, &idx, &length, sz) < 0) {
WOLFSSL_MSG("\tfail: should be a SEQUENCE");
return ASN_PARSE_E;
}
oid = 0;
if (GetObjectId(buf, &idx, &oid, oidCrlExtType, sz) < 0) {
WOLFSSL_MSG("\tfail: OBJECT ID");
return ASN_PARSE_E;
}
if ((idx + 1) > (word32)sz) {
WOLFSSL_MSG("\tfail: malformed buffer");
return BUFFER_E;
}
localIdx = idx;
if (GetASNTag(buf, &localIdx, &tag, sz) == 0 && tag == ASN_BOOLEAN) {
WOLFSSL_MSG("\tfound optional critical flag, moving past");
ret = GetBoolean(buf, &idx, sz);
if (ret < 0)
return ret;
}
ret = GetOctetString(buf, &idx, &length, sz);
if (ret < 0)
return ret;
if (oid == AUTH_KEY_OID) {
#ifndef NO_SKID
ret = ParseCRL_AuthKeyIdExt(buf + idx, length, dcrl);
if (ret < 0) {
WOLFSSL_MSG("\tcouldn't parse AuthKeyId extension");
return ret;
}
#endif
}
else if (oid == CRL_NUMBER_OID) {
localIdx = idx;
if (GetASNTag(buf, &localIdx, &tag, sz) == 0 &&
tag == ASN_INTEGER) {
word32 rawIdx = idx;
int rawLen = 0;
ret = GetASNInt(buf, &idx, &length, sz);
if (ret < 0) {
WOLFSSL_MSG("\tcouldn't parse CRL number extension");
return ret;
}
(void)GetASNHeader(buf, ASN_INTEGER,
&rawIdx, &rawLen, sz);
if (rawLen > 0 && (buf[rawIdx] & 0x80) != 0) {
WOLFSSL_MSG("CRL number is negative");
return ASN_PARSE_E;
}
if (length <= CRL_MAX_NUM_SZ) {
DECL_MP_INT_SIZE_DYN(m, CRL_MAX_NUM_SZ_BITS,
CRL_MAX_NUM_SZ_BITS);
NEW_MP_INT_SIZE(m, CRL_MAX_NUM_SZ_BITS, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
#ifdef MP_INT_SIZE_CHECK_NULL
if (m == NULL) {
ret = MEMORY_E;
}
#endif
if (ret == 0 && ((ret = INIT_MP_INT_SIZE(m, CRL_MAX_NUM_SZ
* CHAR_BIT)) != MP_OKAY)) {
ret = MP_INIT_E;
}
if (ret == MP_OKAY)
ret = mp_read_unsigned_bin(m, buf + idx, length);
if (ret != MP_OKAY)
ret = BUFFER_E;
if (ret == MP_OKAY && mp_toradix(m, (char*)dcrl->crlNumber,
MP_RADIX_HEX) != MP_OKAY)
ret = BUFFER_E;
if (ret == MP_OKAY) {
dcrl->crlNumberSet = 1;
}
FREE_MP_INT_SIZE(m, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (ret != MP_OKAY)
return ret;
} else {
WOLFSSL_MSG("CRL number exceeds limitation");
ret = BUFFER_E;
}
}
}
idx += length;
}
*inOutIdx = idx;
return 0;
}
int ParseCRL(RevokedCert* rcert, DecodedCRL* dcrl, const byte* buff, word32 sz,
int verify, void* cm)
{
Signer* ca = NULL;
SignatureCtx sigCtx;
int ret = 0;
int len;
word32 idx = 0;
const byte* sigParams = NULL;
int sigParamsSz = 0;
WOLFSSL_MSG("ParseCRL");
if (GetSequence(buff, &idx, &len, sz) < 0)
return ASN_PARSE_E;
dcrl->certBegin = idx;
sz = len + idx;
if (GetSequence(buff, &idx, &len, sz) < 0)
return ASN_PARSE_E;
dcrl->sigIndex = len + idx;
if (ParseCRL_CertList(rcert, dcrl, buff, &idx, dcrl->sigIndex, verify) < 0)
return ASN_PARSE_E;
if (ParseCRL_Extensions(dcrl, buff, &idx, dcrl->sigIndex) < 0)
return ASN_PARSE_E;
idx = dcrl->sigIndex;
if (GetAlgoId(buff, &idx, &dcrl->signatureOID, oidSigType, sz) < 0) {
return ASN_PARSE_E;
}
#ifdef WC_RSA_PSS
else if (dcrl->signatureOID == CTC_RSASSAPSS) {
word32 tmpSz;
const byte* params;
tmpSz = idx;
params = buff + idx;
if (GetSequence(buff, &idx, &len, sz) < 0) {
return ASN_PARSE_E;
}
idx += len;
sigParams = params;
sigParamsSz = idx - tmpSz;
}
#endif
if (GetCRL_Signature(buff, &idx, dcrl, sz) < 0)
return ASN_PARSE_E;
#ifndef NO_SKID
if (dcrl->extAuthKeyIdSet) {
ca = GetCA(cm, dcrl->extAuthKeyId);
}
if (ca != NULL && XMEMCMP(dcrl->issuerHash, ca->subjectNameHash,
KEYID_SIZE) != 0) {
ca = NULL;
}
if (ca == NULL) {
ca = GetCAByName(cm, dcrl->issuerHash);
if (ca && dcrl->extAuthKeyIdSet) {
WOLFSSL_MSG("CA SKID doesn't match AKID");
ca = NULL;
}
}
#else
ca = GetCA(cm, dcrl->issuerHash);
#endif
WOLFSSL_MSG("About to verify CRL signature");
if (ca == NULL) {
WOLFSSL_MSG("Did NOT find CRL issuer CA");
ret = ASN_CRL_NO_SIGNER_E;
WOLFSSL_ERROR_VERBOSE(ret);
goto end;
}
WOLFSSL_MSG("Found CRL issuer CA");
ret = VerifyCRL_Signature(&sigCtx, buff + dcrl->certBegin,
dcrl->sigIndex - dcrl->certBegin, dcrl->signature, dcrl->sigLength,
dcrl->signatureOID, sigParams, sigParamsSz, ca, dcrl->heap);
end:
return ret;
}
#endif
#ifdef WOLFSSL_CERT_PIV
int wc_ParseCertPIV(wc_CertPIV* piv, const byte* buf, word32 totalSz)
{
int length = 0;
word32 idx = 0;
WOLFSSL_ENTER("wc_ParseCertPIV");
if (piv == NULL || buf == NULL || totalSz == 0)
return BAD_FUNC_ARG;
XMEMSET(piv, 0, sizeof(wc_CertPIV));
if (GetASNHeader(buf, ASN_PIV_CERT, &idx, &length, totalSz) >= 0) {
piv->isIdentiv = 1;
piv->cert = &buf[idx];
piv->certSz = length;
idx += length;
if (GetASNHeader(buf, ASN_PIV_NONCE, &idx, &length, totalSz) >= 0) {
piv->nonce = &buf[idx];
piv->nonceSz = length;
idx += length;
}
if (GetASNHeader(buf, ASN_PIV_SIGNED_NONCE, &idx, &length, totalSz) >= 0) {
piv->signedNonce = &buf[idx];
piv->signedNonceSz = length;
}
idx = 0;
buf = piv->cert;
totalSz = piv->certSz;
}
if (GetASNHeader(buf, ASN_APPLICATION | ASN_PRINTABLE_STRING, &idx,
&length, totalSz) < 0) {
return ASN_PARSE_E;
}
if (GetASNHeader(buf, ASN_PIV_TAG_CERT, &idx, &length,
totalSz) < 0) {
return ASN_PARSE_E;
}
piv->cert = &buf[idx];
piv->certSz = length;
idx += length;
if (GetASNHeader(buf, ASN_PIV_TAG_CERT_INFO, &idx, &length,
totalSz) >= 0) {
if (length >= 1) {
piv->compression = (buf[idx] & ASN_PIV_CERT_INFO_COMPRESSED);
piv->isX509 = ((buf[idx] & ASN_PIV_CERT_INFO_ISX509) != 0);
}
idx += length;
}
if (GetASNHeader(buf, ASN_PIV_TAG_ERR_DET, &idx, &length,
totalSz) >= 0) {
piv->certErrDet = &buf[idx];
piv->certErrDetSz = length;
idx += length;
}
return 0;
}
#endif
#endif