fix for order of components in issuer when using compatiblity layer api to generate cert

This commit is contained in:
Jacob Barthelmeh
2020-09-01 09:27:45 -06:00
parent ab52bcf43d
commit fd2074da00
5 changed files with 278 additions and 220 deletions

266
src/ssl.c
View File

@@ -37140,167 +37140,38 @@ void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl)
}
#if defined(WOLFSSL_CERT_GEN)
/* Helper function to copy cert name from a WOLFSSL_X509_NAME structure to
* a Cert structure.
*
* returns length of DER on success and a negative error value on failure
*/
static int CopyX509NameToCert(WOLFSSL_X509_NAME* n, byte* out)
{
unsigned char* der = NULL;
int length = BAD_FUNC_ARG, ret = BAD_FUNC_ARG;
word32 idx = 0;
/* helper function for CopyX509NameToCertName()
*
* returns WOLFSSL_SUCCESS on success
*/
static int CopyX509NameEntry(char* out, int mx, WOLFSSL_X509_NAME* name,
int nid, byte* transfered)
{
int inLen = 0;
unsigned char* in = NULL;
int i;
if (nid == ASN_COUNTRY_NAME)
nid = NID_countryName;
if (nid == ASN_EMAIL_NAME)
nid = NID_emailAddress;
for (i = 0; i < MAX_NAME_ENTRIES; i++) {
if (name->entry[i].set && name->entry[i].nid == nid) {
in = wolfSSL_ASN1_STRING_data(name->entry[i].value);
inLen = wolfSSL_ASN1_STRING_length(name->entry[i].value);
transfered[i] = 1;
break;
}
}
if (in == NULL) {
/* entry type not found */
return WOLFSSL_FAILURE;
}
if (inLen > mx) {
WOLFSSL_MSG("Name too long");
XMEMCPY(out, in, mx);
}
else {
XMEMCPY(out, in, inLen);
out[inLen] = '\0';
}
/* make sure is null terminated */
out[mx-1] = '\0';
return WOLFSSL_SUCCESS;
}
#ifdef WOLFSSL_MULTI_ATTRIB
/* Converts from NID_* value to wolfSSL value if needed */
static int ConvertNIDToWolfSSL(int nid)
{
switch (nid) {
case NID_commonName : return ASN_COMMON_NAME;
case NID_surname : return ASN_SUR_NAME;
case NID_countryName: return ASN_COUNTRY_NAME;
case NID_localityName: return ASN_LOCALITY_NAME;
case NID_stateOrProvinceName: return ASN_STATE_NAME;
case NID_organizationName: return ASN_ORG_NAME;
case NID_organizationalUnitName: return ASN_ORGUNIT_NAME;
case NID_emailAddress: return ASN_EMAIL_NAME;
case NID_serialNumber: return ASN_SERIAL_NUMBER;
case NID_businessCategory: return ASN_BUS_CAT;
case NID_domainComponent: return ASN_DOMAIN_COMPONENT;
default:
WOLFSSL_MSG("Attribute NID not found");
return -1;
}
}
#endif /* WOLFSSL_MULTI_ATTRIB */
/* Helper function to copy cert name from a WOLFSSL_X509_NAME structure to
* a CertName structure.
*
* returns WOLFSSL_SUCCESS on success and a negative error value on failure
*/
static int CopyX509NameToCertName(WOLFSSL_X509_NAME* n, CertName* cName)
{
int idx = 0;
#ifdef WOLFSSL_MULTI_ATTRIB
int i, j = 0;
#endif
int count = 0;
const char* current;
byte transferred[MAX_NAME_ENTRIES] = {0};
if (n == NULL || cName == NULL) {
return BAD_FUNC_ARG;
}
/* initialize cert name */
cName->country[0] = '\0';
cName->countryEnc = CTC_PRINTABLE;
cName->state[0] = '\0';
cName->stateEnc = CTC_UTF8;
cName->locality[0] = '\0';
cName->localityEnc = CTC_UTF8;
cName->sur[0] = '\0';
cName->surEnc = CTC_UTF8;
cName->org[0] = '\0';
cName->orgEnc = CTC_UTF8;
cName->unit[0] = '\0';
cName->unitEnc = CTC_UTF8;
cName->commonName[0] = '\0';
cName->commonNameEnc = CTC_UTF8;
cName->serialDev[0] = '\0';
cName->serialDevEnc = CTC_PRINTABLE;
#ifdef WOLFSSL_CERT_EXT
cName->busCat[0] = '\0';
cName->busCatEnc = CTC_UTF8;
cName->joiC[0] = '\0';
cName->joiCEnc = CTC_PRINTABLE;
cName->joiSt[0] = '\0';
cName->joiStEnc = CTC_PRINTABLE;
#endif
cName->email[0] = '\0';
current = GetOneCertName(cName, idx);
while (current != NULL) {
if (CopyX509NameEntry((char*)current, CTC_NAME_SIZE, n,
GetCertNameId(idx), transferred) == SSL_SUCCESS) {
count++;
ret = wolfSSL_i2d_X509_NAME(n, &der);
if (ret > (int)sizeof(CertName) || ret < 0) {
WOLFSSL_MSG("Name conversion error");
ret = MEMORY_E;
}
idx++;
current = GetOneCertName(cName, idx);
}
#ifdef WOLFSSL_MULTI_ATTRIB
/* copy over multiple entries */
idx = wolfSSL_X509_NAME_entry_count(n);
for (i = 0; i < MAX_NAME_ENTRIES && count < idx; i++) {
/* entry is set but was not yet transferred over */
if (n->entry[i].set && transferred[i] == 0) {
unsigned char* data;
int length;
WOLFSSL_X509_NAME_ENTRY* e = &n->entry[i];
data = wolfSSL_ASN1_STRING_data(e->value);
length = wolfSSL_ASN1_STRING_length(e->value);
if (j >= CTC_MAX_ATTRIB) {
WOLFSSL_MSG("No more space left in CertName");
return MEMORY_E;
}
cName->name[j].sz = length;
cName->name[j].type = CTC_UTF8;
cName->name[j].id = ConvertNIDToWolfSSL(e->nid);
XMEMCPY(cName->name[j].value, data, length);
j++;
count++;
if (ret > 0) {
/* strip off sequence, this gets added on certificate creation */
ret = GetSequence(der, &idx, &length, ret);
}
}
#endif /* WOLFSSL_MULTI_ATTRIB */
if (ret > 0) {
XMEMCPY(out, der + idx, length);
}
if (der != NULL)
XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
return length;
}
return WOLFSSL_SUCCESS;
}
#ifdef WOLFSSL_CERT_REQ
static int ReqCertFromX509(Cert* cert, WOLFSSL_X509* req)
@@ -37310,7 +37181,16 @@ static int CopyX509NameToCertName(WOLFSSL_X509_NAME* n, CertName* cName)
if (wc_InitCert(cert) != 0)
return WOLFSSL_FAILURE;
ret = CopyX509NameToCertName(&req->subject, &cert->subject);
ret = CopyX509NameToCert(&(req->subject), cert->sbjRaw);
if (ret < 0) {
WOLFSSL_MSG("REQ subject conversion error");
ret = MEMORY_E;
}
else {
ret = WOLFSSL_SUCCESS;
}
if (ret == WOLFSSL_SUCCESS) {
cert->version = req->version;
cert->isCA = req->isCa;
@@ -37348,6 +37228,7 @@ static int CopyX509NameToCertName(WOLFSSL_X509_NAME* n, CertName* cName)
}
#endif
/* convert a WOLFSSL_X509 to a Cert structure for writing out */
static int CertFromX509(Cert* cert, WOLFSSL_X509* x509)
{
@@ -37457,18 +37338,24 @@ static int CopyX509NameToCertName(WOLFSSL_X509_NAME* n, CertName* cName)
/* copy over Name structures */
if (x509->issuerSet)
cert->selfSigned = 0;
if ((ret = CopyX509NameToCertName(&(x509->issuer), &(cert->issuer)))
!= WOLFSSL_SUCCESS) {
WOLFSSL_MSG("Error copying over issuer names");
WOLFSSL_LEAVE("wolfSSL_X509_to_Cert()", ret);
return WOLFSSL_FAILURE;
ret = CopyX509NameToCert(&(x509->subject), cert->sbjRaw);
if (ret < 0) {
WOLFSSL_MSG("Subject conversion error");
return MEMORY_E;
}
if ((ret = CopyX509NameToCertName(&(x509->subject), &(cert->subject)))
!= WOLFSSL_SUCCESS) {
WOLFSSL_MSG("Error copying over subject names");
WOLFSSL_LEAVE("wolfSSL_X509_to_Cert()", ret);
return WOLFSSL_FAILURE;
if (cert->selfSigned) {
XMEMCPY(cert->issRaw, cert->sbjRaw, sizeof(CertName));
}
else {
ret = CopyX509NameToCert(&(x509->issuer), cert->issRaw);
if (ret < 0) {
WOLFSSL_MSG("Issuer conversion error");
return MEMORY_E;
}
}
cert->heap = x509->heap;
@@ -37779,53 +37666,6 @@ static int CopyX509NameToCertName(WOLFSSL_X509_NAME* n, CertName* cName)
return ret;
}
/* Converts the x509 name structure into DER format.
*
* out pointer to either a pre setup buffer or a pointer to null for
* creating a dynamic buffer. In the case that a pre-existing buffer is
* used out will be incremented the size of the DER buffer on success.
*
* returns the size of the buffer on success, or negative value with failure
*/
int wolfSSL_i2d_X509_NAME(WOLFSSL_X509_NAME* name, unsigned char** out)
{
CertName cName;
unsigned char buf[256]; /* ASN_MAX_NAME */
int sz;
WOLFSSL_ENTER("wolfSSL_i2d_X509_NAME");
if (out == NULL || name == NULL) {
return BAD_FUNC_ARG;
}
XMEMSET(&cName, 0, sizeof(CertName));
if (CopyX509NameToCertName(name, &cName) != SSL_SUCCESS) {
WOLFSSL_MSG("Error converting x509 name to internal CertName");
return SSL_FATAL_ERROR;
}
sz = SetName(buf, sizeof(buf), &cName);
if (sz < 0) {
return sz;
}
/* using buffer passed in */
if (*out != NULL) {
XMEMCPY(*out, buf, sz);
*out += sz;
}
else {
*out = (unsigned char*)XMALLOC(sz, NULL, DYNAMIC_TYPE_OPENSSL);
if (*out == NULL) {
return MEMORY_E;
}
XMEMCPY(*out, buf, sz);
}
return sz;
}
#endif /* WOLFSSL_CERT_GEN */
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)

View File

@@ -27610,20 +27610,26 @@ static void test_wolfSSL_X509_sign(void)
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ)
int ret;
char *caSubject;
X509_NAME *name;
X509 *x509;
X509 *x509, *ca;
DecodedCert dCert;
EVP_PKEY *pub;
EVP_PKEY *priv;
#if defined(USE_CERT_BUFFERS_1024)
const unsigned char* rsaPriv = client_key_der_1024;
const unsigned char* rsaPub = client_keypub_der_1024;
const unsigned char* certIssuer = client_cert_der_1024;
long clientKeySz = (long)sizeof_client_key_der_1024;
long clientPubKeySz = (long)sizeof_client_keypub_der_1024;
long certIssuerSz = (long)sizeof_client_cert_der_1024;
#elif defined(USE_CERT_BUFFERS_2048)
const unsigned char* rsaPriv = client_key_der_2048;
const unsigned char* rsaPub = client_keypub_der_2048;
const unsigned char* certIssuer = client_cert_der_2048;
long clientKeySz = (long)sizeof_client_key_der_2048;
long clientPubKeySz = (long)sizeof_client_keypub_der_2048;
long certIssuerSz = (long)sizeof_client_cert_der_2048;
#endif
byte sn[16];
int snSz = sizeof(sn);
@@ -27648,6 +27654,7 @@ static void test_wolfSSL_X509_sign(void)
AssertIntNE(X509_set_version(x509, 2L), 0);
/* Set subject name, add pubkey, and sign certificate */
AssertIntEQ(X509_set_subject_name(x509, name), SSL_SUCCESS);
X509_NAME_free(name);
AssertIntEQ(X509_set_pubkey(x509, pub), SSL_SUCCESS);
#ifdef WOLFSSL_ALT_NAMES
/* Add some subject alt names */
@@ -27696,7 +27703,7 @@ static void test_wolfSSL_X509_sign(void)
}
XFCLOSE(tmpFile);
#endif
/* Variation in size depends on ASN.1 encoding when MSB is set */
#ifndef WOLFSSL_ALT_NAMES
/* Valid case - size should be 798-797 with 16 byte serial number */
@@ -27708,6 +27715,35 @@ static void test_wolfSSL_X509_sign(void)
/* Valid case - size should be 926-927 with 16 byte serial number */
AssertTrue((ret == 910 + snSz) || (ret == 911 + snSz));
#endif
/* check that issuer name is as expected after signature */
InitDecodedCert(&dCert, certIssuer, (word32)certIssuerSz, 0);
AssertIntEQ(ParseCert(&dCert, CERT_TYPE, NO_VERIFY, NULL), 0);
AssertNotNull(ca = wolfSSL_d2i_X509(NULL, &certIssuer, (int)certIssuerSz));
AssertNotNull(caSubject = wolfSSL_X509_NAME_oneline(
X509_get_subject_name(ca), 0, 0));
AssertIntEQ(0, XSTRNCMP(caSubject, dCert.subject, XSTRLEN(caSubject)));
free(caSubject);
#ifdef WOLFSSL_MULTI_ATTRIB
/* test adding multiple OU's to the signer */
AssertNotNull(name = X509_get_subject_name(ca));
AssertIntEQ(X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_UTF8,
(byte*)"OU1", 3, -1, 0), SSL_SUCCESS);
AssertIntEQ(X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_UTF8,
(byte*)"OU2", 3, -1, 0), SSL_SUCCESS);
AssertIntGT(X509_sign(ca, priv, EVP_sha256()), 0);
#endif
AssertNotNull(name = X509_get_subject_name(ca));
AssertIntEQ(X509_set_issuer_name(x509, name), SSL_SUCCESS);
AssertIntGT(X509_sign(x509, priv, EVP_sha256()), 0);
AssertNotNull(caSubject = wolfSSL_X509_NAME_oneline(
X509_get_issuer_name(x509), 0, 0));
free(caSubject);
FreeDecodedCert(&dCert);
/* Test invalid parameters */
AssertIntEQ(X509_sign(NULL, priv, EVP_sha256()), 0);
@@ -27723,7 +27759,7 @@ static void test_wolfSSL_X509_sign(void)
AssertIntEQ(X509_get_ext_count(x509), SSL_FAILURE);
#endif
X509_NAME_free(name);
EVP_PKEY_free(priv);
EVP_PKEY_free(pub);
X509_free(x509);

View File

@@ -5647,6 +5647,7 @@ int GetName(DecodedCert* cert, int nameType, int maxIdx)
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) \
&& !defined(WOLFCRYPT_ONLY)
int nid = NID_undef;
int enc;
#endif /* OPENSSL_EXTRA */
if (GetSet(cert->source, &cert->srcIdx, &dummy, maxIdx) < 0) {
@@ -6037,8 +6038,20 @@ int GetName(DecodedCert* cert, int nameType, int maxIdx)
}
#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \
!defined(WOLFCRYPT_ONLY)
switch (b) {
case CTC_UTF8:
enc = MBSTRING_UTF8;
break;
case CTC_PRINTABLE:
enc = V_ASN1_PRINTABLESTRING;
break;
default:
WOLFSSL_MSG("Unknown encoding type, using UTF8 by default");
enc = MBSTRING_UTF8;
}
if (nid != NID_undef) {
if (wolfSSL_X509_NAME_add_entry_by_NID(dName, nid, MBSTRING_UTF8,
if (wolfSSL_X509_NAME_add_entry_by_NID(dName, nid, enc,
&cert->source[cert->srcIdx], strLen, -1, -1) !=
WOLFSSL_SUCCESS) {
wolfSSL_X509_NAME_free(dName);
@@ -12707,6 +12720,149 @@ static int wc_EncodeName(EncodedName* name, const char* nameStr, char nameType,
return idx;
}
#if defined(OPENSSL_EXTRA)
/* Converts from NID_* value to wolfSSL value if needed */
static int ConvertNIDToWolfSSL(int nid)
{
switch (nid) {
case NID_commonName : return ASN_COMMON_NAME;
case NID_surname : return ASN_SUR_NAME;
case NID_countryName: return ASN_COUNTRY_NAME;
case NID_localityName: return ASN_LOCALITY_NAME;
case NID_stateOrProvinceName: return ASN_STATE_NAME;
case NID_organizationName: return ASN_ORG_NAME;
case NID_organizationalUnitName: return ASN_ORGUNIT_NAME;
case NID_emailAddress: return ASN_EMAIL_NAME;
case NID_serialNumber: return ASN_SERIAL_NUMBER;
case NID_businessCategory: return ASN_BUS_CAT;
case NID_domainComponent: return ASN_DOMAIN_COMPONENT;
default:
WOLFSSL_MSG("Attribute NID not found");
return -1;
}
}
/* Converts the x509 name structure into DER format.
*
* out pointer to either a pre setup buffer or a pointer to null for
* creating a dynamic buffer. In the case that a pre-existing buffer is
* used out will be incremented the size of the DER buffer on success.
*
* returns the size of the buffer on success, or negative value with failure
*/
int wolfSSL_i2d_X509_NAME(WOLFSSL_X509_NAME* name, unsigned char** out)
{
int totalBytes = 0, i, idx;
byte temp[MAX_SEQ_SZ];
byte *output, *local = NULL;
#ifdef WOLFSSL_SMALL_STACK
EncodedName* names = NULL;
#else
EncodedName names[MAX_NAME_ENTRIES];
#endif
if (out == NULL || name == NULL)
return BAD_FUNC_ARG;
#ifdef WOLFSSL_SMALL_STACK
names = (EncodedName*)XMALLOC(sizeof(EncodedName) * MAX_NAME_ENTRIES, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (names == NULL)
return MEMORY_E;
#endif
XMEMSET(names, 0, sizeof(EncodedName) * MAX_NAME_ENTRIES);
for (i = 0; i < MAX_NAME_ENTRIES; i++) {
WOLFSSL_X509_NAME_ENTRY* entry;
int ret;
entry = wolfSSL_X509_NAME_get_entry(name, i);
if (entry != NULL && entry->set == 1) {
const char* nameStr;
int type;
WOLFSSL_ASN1_STRING* data;
data = wolfSSL_X509_NAME_ENTRY_get_data(entry);
if (data == NULL) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
WOLFSSL_MSG("Error getting entry data");
return WOLFSSL_FATAL_ERROR;
}
nameStr = (const char*)wolfSSL_ASN1_STRING_data(data);
type = wolfSSL_ASN1_STRING_type(data);
switch (type) {
case MBSTRING_UTF8:
type = CTC_UTF8;
break;
case V_ASN1_PRINTABLESTRING:
type = CTC_PRINTABLE;
break;
default:
WOLFSSL_MSG("Unknown encoding type conversion UTF8 by default");
type = CTC_UTF8;
}
ret = wc_EncodeName(&names[i], nameStr, type,
ConvertNIDToWolfSSL(entry->nid));
if (ret < 0) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
WOLFSSL_MSG("EncodeName failed");
return WOLFSSL_FATAL_ERROR;
}
totalBytes += ret;
}
}
/* header */
idx = SetSequence(totalBytes, temp);
if (totalBytes + idx > ASN_NAME_MAX) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
WOLFSSL_MSG("Total Bytes is greater than ASN_NAME_MAX");
return BUFFER_E;
}
/* check if using buffer passed in */
if (*out == NULL) {
*out = local = (unsigned char*)XMALLOC(totalBytes + idx, NULL,
DYNAMIC_TYPE_OPENSSL);
if (*out == NULL) {
return MEMORY_E;
}
}
output = *out;
idx = SetSequence(totalBytes, output);
totalBytes += idx;
for (i = 0; i < MAX_NAME_ENTRIES; i++) {
if (names[i].used) {
XMEMCPY(output + idx, names[i].encoded, names[i].totalLen);
idx += names[i].totalLen;
}
}
#ifdef WOLFSSL_SMALL_STACK
XFREE(names, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
/* used existing buffer passed in, so increment pointer */
if (local == NULL) {
*out += totalBytes;
}
return totalBytes;
}
#endif /* OPENSSL_EXTRA */
/* encode CertName into output, return total bytes written */
int SetName(byte* output, word32 outputSz, CertName* name)
{
@@ -12966,7 +13122,7 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey,
}
/* subject name */
#ifdef WOLFSSL_CERT_EXT
#if defined(WOLFSSL_CERT_EXT) || defined(OPENSSL_EXTRA)
if (XSTRLEN((const char*)cert->sbjRaw) > 0) {
/* Use the raw subject */
int idx;
@@ -12994,13 +13150,14 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey,
return SUBJECT_E;
/* issuer name */
#ifdef WOLFSSL_CERT_EXT
#if defined(WOLFSSL_CERT_EXT) || defined(OPENSSL_EXTRA)
if (XSTRLEN((const char*)cert->issRaw) > 0) {
/* Use the raw issuer */
int idx;
der->issuerSz = min(sizeof(der->issuer),
(word32)XSTRLEN((const char*)cert->issRaw));
/* header */
idx = SetSequence(der->issuerSz, der->issuer);
if (der->issuerSz + idx > (int)sizeof(der->issuer)) {
@@ -13590,7 +13747,29 @@ static int EncodeCertReq(Cert* cert, DerCert* der, RsaKey* rsaKey,
der->versionSz = SetMyVersion(cert->version, der->version, FALSE);
/* subject name */
der->subjectSz = SetName(der->subject, sizeof(der->subject), &cert->subject);
#if defined(WOLFSSL_CERT_EXT) || defined(OPENSSL_EXTRA)
if (XSTRLEN((const char*)cert->sbjRaw) > 0) {
/* Use the raw subject */
int idx;
der->subjectSz = min(sizeof(der->subject),
(word32)XSTRLEN((const char*)cert->sbjRaw));
/* header */
idx = SetSequence(der->subjectSz, der->subject);
if (der->subjectSz + idx > (int)sizeof(der->subject)) {
return SUBJECT_E;
}
XMEMCPY((char*)der->subject + idx, (const char*)cert->sbjRaw,
der->subjectSz);
der->subjectSz += idx;
}
else
#endif
{
der->subjectSz = SetName(der->subject, sizeof(der->subject),
&cert->subject);
}
if (der->subjectSz <= 0)
return SUBJECT_E;

View File

@@ -69,6 +69,7 @@
#define V_ASN1_OBJECT 6
#define V_ASN1_UTCTIME 23
#define V_ASN1_GENERALIZEDTIME 24
#define V_ASN1_PRINTABLESTRING 19
#define ASN1_STRING_FLAG_BITS_LEFT 0x008
#define ASN1_STRING_FLAG_NDEF 0x010

View File

@@ -330,6 +330,8 @@ typedef struct Cert {
#endif
char certPolicies[CTC_MAX_CERTPOL_NB][CTC_MAX_CERTPOL_SZ];
word16 certPoliciesNb; /* Number of Cert Policy */
#endif
#if defined(WOLFSSL_CERT_EXT) || defined(OPENSSL_EXTRA)
byte issRaw[sizeof(CertName)]; /* raw issuer info */
byte sbjRaw[sizeof(CertName)]; /* raw subject info */
#endif