Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve subjectAltName extension parsing and printing #6525

Merged
merged 14 commits into from
Jul 22, 2023
3 changes: 3 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -7815,6 +7815,9 @@ then

# Uses alt name
ENABLED_ALTNAMES="yes"

AM_CFLAGS="$AM_CFLAGS -DHAVE_OID_ENCODING -DWOLFSSL_NO_ASN_STRICT"

fi

if test "$ENABLED_STRONGSWAN" = "yes"; then
Expand Down
22 changes: 21 additions & 1 deletion src/ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -26105,7 +26105,9 @@ const WOLFSSL_ObjectInfo wolfssl_object_info[] = {

/* oidCertNameType */
{ NID_commonName, NID_commonName, oidCertNameType, "CN", "commonName"},
#if !defined(WOLFSSL_CERT_REQ)
{ NID_surname, NID_surname, oidCertNameType, "SN", "surname"},
#endif
{ NID_serialNumber, NID_serialNumber, oidCertNameType, "serialNumber",
"serialNumber"},
{ NID_userId, NID_userId, oidCertNameType, "UID", "userid"},
Expand Down Expand Up @@ -34269,6 +34271,24 @@ word32 nid2oid(int nid, int grp)
}
break;

/* oidCmsKeyAgreeType */
#ifdef WOLFSSL_CERT_REQ
case oidCsrAttrType:
switch (nid) {
case NID_pkcs9_contentType:
return PKCS9_CONTENT_TYPE_OID;
case NID_pkcs9_challengePassword:
return CHALLENGE_PASSWORD_OID;
case NID_serialNumber:
return SERIAL_NUMBER_OID;
case NID_userId:
return USER_ID_OID;
case NID_surname:
return SURNAME_OID;
}
break;
#endif

default:
WOLFSSL_MSG("NID not in table");
/* MSVC warns without the cast */
Expand Down Expand Up @@ -34647,7 +34667,7 @@ int oid2nid(word32 oid, int grp)
#endif

default:
WOLFSSL_MSG("NID not in table");
WOLFSSL_MSG("OID not in table");
}
/* If not found in above switch then try the table */
for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++) {
Expand Down
10 changes: 10 additions & 0 deletions src/x509.c
Original file line number Diff line number Diff line change
Expand Up @@ -5790,11 +5790,21 @@ static int X509PrintSubjAltName(WOLFSSL_BIO* bio, WOLFSSL_X509* x509,
else if (entry->type == ASN_URI_TYPE) {
len = XSNPRINTF(scratch, MAX_WIDTH, "URI:%s",
entry->name);
if (len >= MAX_WIDTH) {
ret = WOLFSSL_FAILURE;
break;
}
}
#if defined(OPENSSL_ALL)
else if (entry->type == ASN_RID_TYPE) {
len = XSNPRINTF(scratch, MAX_WIDTH, "Registered ID:%s",
entry->ridString);
if (len >= MAX_WIDTH) {
ret = WOLFSSL_FAILURE;
break;
}
}
#endif
else if (entry->type == ASN_OTHER_TYPE) {
len = XSNPRINTF(scratch, MAX_WIDTH,
"othername <unsupported>");
Expand Down
216 changes: 207 additions & 9 deletions wolfcrypt/src/asn.c
Original file line number Diff line number Diff line change
Expand Up @@ -5438,13 +5438,18 @@ static int CheckCurve(word32 oid)
* @return BAD_FUNC_ARG when in or outSz is NULL.
* @return BUFFER_E when buffer too small.
*/
int wc_EncodeObjectId(const word16* in, word32 inSz, byte* out, word32* outSz)
{
return EncodeObjectId(in, inSz, out, outSz);
}

int EncodeObjectId(const word16* in, word32 inSz, byte* out, word32* outSz)
{
int i, x, len;
word32 d, t;

/* check args */
if (in == NULL || outSz == NULL) {
if (in == NULL || outSz == NULL || inSz <= 0) {
return BAD_FUNC_ARG;
}

Expand Down Expand Up @@ -5513,7 +5518,8 @@ int EncodeObjectId(const word16* in, word32 inSz, byte* out, word32* outSz)
}
#endif /* HAVE_OID_ENCODING */

#if defined(HAVE_OID_DECODING) || defined(WOLFSSL_ASN_PRINT)
#if defined(HAVE_OID_DECODING) || defined(WOLFSSL_ASN_PRINT) || \
defined(OPENSSL_ALL)
/* Encode dotted form of OID into byte array version.
*
* @param [in] in Byte array containing OID.
Expand Down Expand Up @@ -5560,7 +5566,7 @@ int DecodeObjectId(const byte* in, word32 inSz, word16* out, word32* outSz)

return 0;
}
#endif /* HAVE_OID_DECODING */
#endif /* HAVE_OID_DECODING || WOLFSSL_ASN_PRINT || OPENSSL_ALL */

/* Decode the header of a BER/DER encoded OBJECT ID.
*
Expand Down Expand Up @@ -11159,6 +11165,9 @@ void FreeAltNames(DNS_entry* altNames, void* heap)
XFREE(altNames->name, heap, DYNAMIC_TYPE_ALTNAME);
#if defined(OPENSSL_ALL) || defined(WOLFSSL_IP_ALT_NAME)
XFREE(altNames->ipString, heap, DYNAMIC_TYPE_ALTNAME);
#endif
#if defined(OPENSSL_ALL)
XFREE(altNames->ridString, heap, DYNAMIC_TYPE_ALTNAME);
#endif
XFREE(altNames, heap, DYNAMIC_TYPE_ALTNAME);
altNames = tmp;
Expand Down Expand Up @@ -12337,6 +12346,90 @@ static int GenerateDNSEntryIPString(DNS_entry* entry, void* heap)
}
#endif /* OPENSSL_ALL || WOLFSSL_IP_ALT_NAME */

#if defined(OPENSSL_ALL)
/* used to set the human readable string for the registeredID with an
* ASN_RID_TYPE DNS entry
* return 0 on success
*/
static int GenerateDNSEntryRIDString(DNS_entry* entry, void* heap)
{
int i, j, ret = 0;
int nameSz = 0;
int numerical = 0;
int nid = 0;
int tmpSize = MAX_OID_SZ;
word32 oid = 0;
word32 idx = 0;
word16 tmpName[MAX_OID_SZ];
char oidName[MAX_OID_SZ];
char* finalName;

if (entry == NULL || entry->type != ASN_RID_TYPE) {
return BAD_FUNC_ARG;
}

if (entry->len <= 0) {
return BAD_FUNC_ARG;
}

XMEMSET(&oidName, 0, MAX_OID_SZ);

ret = GetOID((const byte*)entry->name, &idx, &oid, oidIgnoreType,
entry->len);

if (ret == 0 && (nid = oid2nid(oid, oidCsrAttrType)) > 0) {
/* OID has known string value */
JacobBarthelmeh marked this conversation as resolved.
Show resolved Hide resolved
finalName = (char*)wolfSSL_OBJ_nid2ln(nid);
}
else {
/* Decode OBJECT_ID into dotted form array. */
ret = DecodeObjectId((const byte*)(entry->name),(word32)entry->len,
tmpName, (word32*)&tmpSize);

numerical = 1;
if (ret == 0) {
j = 0;
/* Append each number of dotted form. */
for (i = 0; i < tmpSize; i++) {
ret = XSNPRINTF(oidName + j, MAX_OID_SZ, "%d", tmpName[i]);
if (ret >= 0) {
j += ret;
if (i < tmpSize - 1) {
oidName[j] = '.';
j++;
}
}
else {
return BUFFER_E;
}
}
ret = 0;
finalName = oidName;
}
}

if (ret == 0) {
nameSz = (int)XSTRLEN((const char*)finalName);

entry->ridString = (char*)XMALLOC(nameSz + numerical, heap,
DYNAMIC_TYPE_ALTNAME);

if (entry->ridString == NULL) {
JacobBarthelmeh marked this conversation as resolved.
Show resolved Hide resolved
ret = MEMORY_E;
}

if (ret == 0) {
XMEMCPY(entry->ridString, finalName, nameSz);
if (numerical) {
entry->ridString[nameSz] = '\0';
}
}
}

return ret;
}
#endif /* OPENSSL_ALL && WOLFSSL_ASN_TEMPLATE */

#ifdef WOLFSSL_ASN_TEMPLATE

#if defined(WOLFSSL_CERT_GEN) || !defined(NO_CERTS)
Expand Down Expand Up @@ -12415,6 +12508,15 @@ static int SetDNSEntry(DecodedCert* cert, const char* str, int strLen,
XMEMCPY(dnsEntry->name, str, (size_t)strLen);
dnsEntry->name[strLen] = '\0';

#if defined(OPENSSL_ALL)
/* store registeredID as a string */
if (type == ASN_RID_TYPE) {
if ((ret = GenerateDNSEntryRIDString(dnsEntry, cert->heap)) != 0) {
XFREE(dnsEntry->name, cert->heap, DYNAMIC_TYPE_ALTNAME);
XFREE(dnsEntry, cert->heap, DYNAMIC_TYPE_ALTNAME);
}
}
#endif
#if defined(OPENSSL_ALL) || defined(WOLFSSL_IP_ALT_NAME)
/* store IP addresses as a string */
if (type == ASN_IP_TYPE) {
Expand Down Expand Up @@ -16924,6 +17026,15 @@ static int DecodeGeneralName(const byte* input, word32* inOutIdx, byte tag,
}
}
#endif /* WOLFSSL_QT || OPENSSL_ALL */

/* GeneralName choice: registeredID */
else if (tag == (ASN_CONTEXT_SPECIFIC | ASN_RID_TYPE)) {
ret = SetDNSEntry(cert, (const char*)(input + idx), len,
ASN_RID_TYPE, &cert->altNames);
if (ret == 0) {
idx += (word32)len;
}
}
#endif /* IGNORE_NAME_CONSTRAINTS */
#if defined(WOLFSSL_SEP) || defined(WOLFSSL_FPKI)
/* GeneralName choice: otherName */
Expand All @@ -16932,8 +17043,7 @@ static int DecodeGeneralName(const byte* input, word32* inOutIdx, byte tag,
ret = DecodeOtherName(cert, input, &idx, idx + (word32)len);
}
#endif
/* GeneralName choice: dNSName, x400Address, ediPartyName,
* registeredID */
/* GeneralName choice: dNSName, x400Address, ediPartyName */
else {
WOLFSSL_MSG("\tUnsupported name type, skipping");
idx += (word32)len;
Expand Down Expand Up @@ -17443,7 +17553,55 @@ static int DecodeAltNames(const byte* input, word32 sz, DecodedCert* cert)
length -= strLen;
idx += (word32)strLen;
}
#endif /* WOLFSSL_QT || OPENSSL_ALL */
#endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_IP_ALT_NAME */
#if defined(OPENSSL_ALL)
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);
/* check that strLen at index is not past input buffer */
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->len = strLen;
XMEMCPY(rid->name, &input[idx], strLen);
rid->name[strLen] = '\0';

if (GenerateDNSEntryRIDString(rid, cert->heap) != 0) {
WOLFSSL_MSG("\tOut of Memory for registerd Id string");
XFREE(rid->name, cert->heap, DYNAMIC_TYPE_ALTNAME);
XFREE(rid, cert->heap, DYNAMIC_TYPE_ALTNAME);
return MEMORY_E;
}

AddAltName(cert, rid);

length -= strLen;
idx += (word32)strLen;
}
#endif /* OPENSSL_ALL */
#endif /* IGNORE_NAME_CONSTRAINTS */
else if (current_byte ==
(ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | ASN_OTHER_TYPE)) {
Expand Down Expand Up @@ -20480,6 +20638,22 @@ static int DecodeCertReqAttrValue(DecodedCert* cert, int* criticalExt,
}
break;

case UNSTRUCTURED_NAME_OID:
/* Clear dynamic data and specify choices acceptable. */
XMEMSET(strDataASN, 0, sizeof(strDataASN));
GetASN_Choice(&strDataASN[STRATTRASN_IDX_STR], strAttrChoice);
/* Parse a string. */
ret = GetASN_Items(strAttrASN, strDataASN, strAttrASN_Length,
1, input, &idx, maxIdx);
if (ret == 0) {
/* Store references to unstructured name. */
cert->unstructuredName =
(char*)strDataASN[STRATTRASN_IDX_STR].data.ref.data;
cert->unstructuredNameLen = (int)strDataASN[STRATTRASN_IDX_STR].
data.ref.length;
}
break;

/* Certificate extensions to be included in generated certificate.
* PKCS#9: RFC 2985, 5.4.2 - Extension request
*/
Expand Down Expand Up @@ -29346,6 +29520,11 @@ static const ASNItem certReqBodyASN[] = {
/* ATTRS_CPW_SET */ { 3, ASN_SET, 1, 1, 0 },
/* ATTRS_CPW_PS */ { 4, ASN_PRINTABLE_STRING, 0, 0, 0 },
/* ATTRS_CPW_UTF */ { 4, ASN_UTF8STRING, 0, 0, 0 },
/* ATTRS_USN_SEQ */ { 2, ASN_SEQUENCE, 1, 1, 1 },
/* ATTRS_USN_OID */ { 3, ASN_OBJECT_ID, 0, 0, 0 },
/* ATTRS_USN_SET */ { 3, ASN_SET, 1, 1, 0 },
/* ATTRS_USN_PS */ { 4, ASN_PRINTABLE_STRING, 0, 0, 0 },
/* ATTRS_USN_UTF */ { 4, ASN_UTF8STRING, 0, 0, 0 },
/* Extensions Attribute */
/* EXT_SEQ */ { 2, ASN_SEQUENCE, 1, 1, 1 },
/* EXT_OID */ { 3, ASN_OBJECT_ID, 0, 0, 0 },
Expand All @@ -29363,6 +29542,11 @@ enum {
CERTREQBODYASN_IDX_ATTRS_CPW_SET,
CERTREQBODYASN_IDX_ATTRS_CPW_PS,
CERTREQBODYASN_IDX_ATTRS_CPW_UTF,
CERTREQBODYASN_IDX_ATTRS_USN_SEQ,
CERTREQBODYASN_IDX_ATTRS_USN_OID,
CERTREQBODYASN_IDX_ATTRS_USN_SET,
CERTREQBODYASN_IDX_ATTRS_USN_PS,
CERTREQBODYASN_IDX_ATTRS_USN_UTF,
CERTREQBODYASN_IDX_EXT_SEQ,
CERTREQBODYASN_IDX_EXT_OID,
CERTREQBODYASN_IDX_EXT_SET,
Expand Down Expand Up @@ -29616,6 +29800,23 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz,
SetASNItem_NoOutNode(dataASN, certReqBodyASN,
CERTREQBODYASN_IDX_ATTRS_CPW_SEQ, certReqBodyASN_Length);
}
if (cert->unstructuredName[0] != '\0') {
/* Add unstructured name attribute. */
/* Set unstructured name OID. */
SetASN_Buffer(&dataASN[CERTREQBODYASN_IDX_ATTRS_USN_OID],
attrUnstructuredNameOid, sizeof(attrUnstructuredNameOid));
/* PRINTABLE_STRING - set buffer */
SetASN_Buffer(&dataASN[CERTREQBODYASN_IDX_ATTRS_USN_PS],
(byte*)cert->unstructuredName,
(word32)XSTRLEN(cert->unstructuredName));
/* UTF8STRING - don't encode */
dataASN[CERTREQBODYASN_IDX_ATTRS_USN_UTF].noOut = 1;
}
else {
/* Leave out unstructured name attribute item. */
SetASNItem_NoOutNode(dataASN, certReqBodyASN,
CERTREQBODYASN_IDX_ATTRS_USN_SEQ, certReqBodyASN_Length);
}
if (extSz > 0) {
/* Set extension attribute OID. */
SetASN_Buffer(&dataASN[CERTREQBODYASN_IDX_EXT_OID], attrExtensionRequestOid,
Expand Down Expand Up @@ -37152,9 +37353,6 @@ int wc_Asn1_SetFile(Asn1* asn1, XFILE file)
return ret;
}

/* Maximum OID dotted form size. */
#define ASN1_OID_DOTTED_MAX_SZ 16

/* Print OID in dotted form or as hex bytes.
*
* @param [in] file File pointer to write to.
Expand Down
Loading