Skip to content

Commit cdeba4e

Browse files
Merge pull request #6364 from anhu/compat_unknown_oid
Allow for unknown OIDs in extensions in wolfSSL_X509_set_ext()
2 parents 11512c7 + 730db6a commit cdeba4e

2 files changed

Lines changed: 139 additions & 18 deletions

File tree

src/x509.c

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -686,17 +686,24 @@ WOLFSSL_X509_EXTENSION* wolfSSL_X509_set_ext(WOLFSSL_X509* x509, int loc)
686686
/* extCount == loc. Now get the extension. */
687687
/* Check if extension has been set */
688688
isSet = wolfSSL_X509_ext_isSet_by_NID((WOLFSSL_X509*)x509, nid);
689-
ext->obj = wolfSSL_OBJ_nid2obj(nid);
690-
if (ext->obj == NULL) {
691-
WOLFSSL_MSG("\tfail: Invalid OBJECT");
692-
wolfSSL_X509_EXTENSION_free(ext);
693-
FreeDecodedCert(cert);
694-
#ifdef WOLFSSL_SMALL_STACK
695-
XFREE(cert, NULL, DYNAMIC_TYPE_DCERT);
696-
#endif
697-
return NULL;
689+
690+
if (wolfSSL_OBJ_nid2ln(nid) != NULL) {
691+
/* This is NOT an unknown OID. */
692+
ext->obj = wolfSSL_OBJ_nid2obj(nid);
693+
if (ext->obj == NULL) {
694+
WOLFSSL_MSG("\tfail: Invalid OBJECT");
695+
wolfSSL_X509_EXTENSION_free(ext);
696+
FreeDecodedCert(cert);
697+
#ifdef WOLFSSL_SMALL_STACK
698+
XFREE(cert, NULL, DYNAMIC_TYPE_DCERT);
699+
#endif
700+
return NULL;
701+
}
702+
}
703+
704+
if (ext->obj) {
705+
ext->obj->nid = nid;
698706
}
699-
ext->obj->nid = nid;
700707

701708
switch (oid) {
702709
case BASIC_CA_OID:
@@ -1000,8 +1007,8 @@ WOLFSSL_X509_EXTENSION* wolfSSL_X509_set_ext(WOLFSSL_X509* x509, int loc)
10001007
default:
10011008
WOLFSSL_MSG("Unknown extension type found, parsing OID");
10021009
/* If the extension type is not recognized/supported,
1003-
set the ASN1_OBJECT in the extension with the
1004-
parsed oid for access in later function calls */
1010+
* set the ASN1_OBJECT in the extension with the
1011+
* parsed oid for access in later function calls */
10051012

10061013
/* Get OID from input */
10071014
if (GetASNObjectId(input, &idx, &length, sz) != 0) {
@@ -1030,6 +1037,18 @@ WOLFSSL_X509_EXTENSION* wolfSSL_X509_set_ext(WOLFSSL_X509* x509, int loc)
10301037
objSz += length;
10311038

10321039
/* Set object size and reallocate space in object buffer */
1040+
if (ext->obj == NULL) {
1041+
ext->obj = wolfSSL_ASN1_OBJECT_new();
1042+
if (ext->obj == NULL) {
1043+
wolfSSL_X509_EXTENSION_free(ext);
1044+
FreeDecodedCert(cert);
1045+
#ifdef WOLFSSL_SMALL_STACK
1046+
XFREE(cert, NULL, DYNAMIC_TYPE_DCERT);
1047+
#endif
1048+
return NULL;
1049+
}
1050+
}
1051+
10331052
ext->obj->objSz = objSz;
10341053
if(((ext->obj->dynamic & WOLFSSL_ASN1_DYNAMIC_DATA) != 0) ||
10351054
(ext->obj->obj == NULL)) {
@@ -4600,10 +4619,12 @@ static void wolfSSL_GENERAL_NAME_type_free(WOLFSSL_GENERAL_NAME* name)
46004619
name->d.registeredID = NULL;
46014620
break;
46024621
case GEN_OTHERNAME:
4603-
wolfSSL_ASN1_OBJECT_free(name->d.otherName->type_id);
4604-
wolfSSL_ASN1_TYPE_free(name->d.otherName->value);
4605-
XFREE(name->d.otherName, NULL, DYNAMIC_TYPE_ASN1);
4606-
name->d.otherName = NULL;
4622+
if (name->d.otherName != NULL) {
4623+
wolfSSL_ASN1_OBJECT_free(name->d.otherName->type_id);
4624+
wolfSSL_ASN1_TYPE_free(name->d.otherName->value);
4625+
XFREE(name->d.otherName, NULL, DYNAMIC_TYPE_ASN1);
4626+
name->d.otherName = NULL;
4627+
}
46074628
break;
46084629
case GEN_X400:
46094630
/* Unsupported: fall through */

tests/api.c

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43880,7 +43880,13 @@ static int test_GENERAL_NAME_set0_othername(void) {
4388043880
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
4388143881
defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) && \
4388243882
defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ALT_NAMES) && \
43883-
defined(WOLFSSL_CERT_EXT) && !defined(NO_FILESYSTEM)
43883+
defined(WOLFSSL_CERT_EXT) && !defined(NO_FILESYSTEM) && \
43884+
defined(WOLFSSL_FPKI)
43885+
43886+
/* ./configure --enable-opensslall --enable-certgen --enable-certreq
43887+
* --enable-certext --enable-debug 'CPPFLAGS=-DWOLFSSL_CUSTOM_OID
43888+
* -DWOLFSSL_ALT_NAMES -DWOLFSSL_FPKI' */
43889+
4388443890
const char * cert_fname = "./certs/server-cert.der";
4388543891
const char * key_fname = "./certs/server-key.der";
4388643892
X509* x509 = NULL;
@@ -43896,6 +43902,18 @@ static int test_GENERAL_NAME_set0_othername(void) {
4389643902
int derSz = 0;
4389743903
EVP_PKEY* priv = NULL;
4389843904
FILE* f = NULL;
43905+
/* The length of this buffer is 37 */
43906+
const unsigned char expected_asn1[] = {
43907+
/* OID specifier and length */
43908+
0x06, 0x0A,
43909+
/* 1.3.6.1.4.1.311.20.2.3 */
43910+
0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x03,
43911+
/* TODO */
43912+
0xA0, 0x17, 0x0C, 0x15,
43913+
/* othername@wolfssl.com */
43914+
0x6F, 0x74, 0x68, 0x65, 0x72, 0x6E, 0x61, 0x6D, 0x65, 0x40, 0x77, 0x6F,
43915+
0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D
43916+
};
4389943917

4390043918
AssertNotNull(f = fopen(cert_fname, "rb"));
4390143919
AssertNotNull(x509 = d2i_X509_fp(f, NULL));
@@ -43919,6 +43937,25 @@ static int test_GENERAL_NAME_set0_othername(void) {
4391943937
(const unsigned char**)&pt, derSz));
4392043938
AssertIntGT(X509_sign(x509, priv, EVP_sha256()), 0);
4392143939
sk_GENERAL_NAME_pop_free(gns, GENERAL_NAME_free);
43940+
AssertNotNull(gns = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL,
43941+
NULL));
43942+
43943+
AssertIntEQ(sk_GENERAL_NAME_num(gns), 3);
43944+
43945+
AssertNotNull(gn = sk_GENERAL_NAME_value(gns, 2));
43946+
AssertIntEQ(gn->type, 0);
43947+
43948+
/* It is odd that we are using ASN_RFC822_TYPE. It is because when we are
43949+
* parsing der, the string is not fully parsed. It is still raw der whereas
43950+
* when we encode we set the oid (for example, upn) and value. As we are
43951+
* overloading the meaning of the type, here we manually do the right thing.
43952+
*/
43953+
AssertIntEQ(ASN1_STRING_length(gn->d.rfc822Name), 37);
43954+
AssertIntEQ(XMEMCMP(ASN1_STRING_data(gn->d.rfc822Name), expected_asn1, 37),
43955+
0);
43956+
gn->type = ASN_RFC822_TYPE;
43957+
sk_GENERAL_NAME_pop_free(gns, GENERAL_NAME_free);
43958+
4392243959
ASN1_OBJECT_free(upn_oid);
4392343960
X509_EXTENSION_free(ext);
4392443961
X509_free(x509);
@@ -43934,7 +43971,13 @@ static int test_othername_and_SID_ext(void) {
4393443971
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
4393543972
defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) && \
4393643973
defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ALT_NAMES) && \
43937-
defined(WOLFSSL_CERT_EXT) && !defined(NO_FILESYSTEM)
43974+
defined(WOLFSSL_CERT_EXT) && !defined(NO_FILESYSTEM) && \
43975+
defined(WOLFSSL_FPKI) && defined(WOLFSSL_ASN_TEMPLATE)
43976+
43977+
/* ./configure --enable-opensslall --enable-certgen --enable-certreq
43978+
* --enable-certext --enable-debug 'CPPFLAGS=-DWOLFSSL_CUSTOM_OID
43979+
* -DWOLFSSL_ALT_NAMES -DWOLFSSL_FPKI' */
43980+
4393843981

4393943982
const char* csr_fname = "./certs/csr.signed.der";
4394043983
const char* key_fname = "./certs/server-key.der";
@@ -43945,11 +43988,13 @@ static int test_othername_and_SID_ext(void) {
4394543988
STACK_OF(X509_EXTENSION) *exts = NULL;
4394643989

4394743990
X509_EXTENSION * san_ext = NULL;
43991+
X509_EXTENSION * ext = NULL;
4394843992
GENERAL_NAME* gn = NULL;
4394943993
GENERAL_NAMES* gns = NULL;
4395043994
ASN1_OBJECT* upn_oid = NULL;
4395143995
ASN1_UTF8STRING *utf8str = NULL;
4395243996
ASN1_TYPE *value = NULL;
43997+
ASN1_STRING *extval = NULL;
4395343998

4395443999
/* SID extension. SID data format explained here:
4395544000
* https://blog.qdsecurity.se/2022/05/27/manually-injecting-a-sid-in-a-certificate/
@@ -43959,13 +44004,21 @@ static int test_othername_and_SID_ext(void) {
4395944004
48, 4, 46, 83, 45, 49, 45, 53, 45, 50, 49, 45, 50, 56, 52, 51, 57,
4396044005
48, 55, 52, 49, 56, 45, 51, 57, 50, 54, 50, 55, 55, 52, 50, 49, 45,
4396144006
51, 56, 49, 53, 57, 57, 51, 57, 55, 50, 45, 52, 54, 48, 49};
44007+
44008+
uint8_t expectedAltName[] = {
44009+
0x30, 0x27, 0xA0, 0x25, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82,
44010+
0x37, 0x14, 0x02, 0x03, 0xA0, 0x17, 0x0C, 0x15, 0x6F, 0x74, 0x68, 0x65,
44011+
0x72, 0x6E, 0x61, 0x6D, 0x65, 0x40, 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73,
44012+
0x6C, 0x2E, 0x63, 0x6F, 0x6D};
44013+
4396244014
X509_EXTENSION *sid_ext = NULL;
4396344015
ASN1_OBJECT* sid_oid = NULL;
4396444016
ASN1_OCTET_STRING *sid_data = NULL;
4396544017

4396644018
EVP_PKEY* priv = NULL;
4396744019
FILE* f = NULL;
4396844020
byte* pt = NULL;
44021+
BIO* bio = NULL;
4396944022

4397044023
AssertNotNull(f = fopen(csr_fname, "rb"));
4397144024
AssertNotNull(x509 = d2i_X509_REQ_fp(f, NULL));
@@ -44007,7 +44060,54 @@ static int test_othername_and_SID_ext(void) {
4400744060
ASN1_OBJECT_free(sid_oid);
4400844061
ASN1_OCTET_STRING_free(sid_data);
4400944062
X509_REQ_free(x509);
44063+
x509 = NULL;
4401044064
EVP_PKEY_free(priv);
44065+
44066+
/* At this point everything used to generate what is in der is cleaned up.
44067+
* We now read back from der to confirm the extensions were inserted
44068+
* correctly. */
44069+
bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem());
44070+
AssertNotNull(bio);
44071+
44072+
AssertIntEQ(BIO_write(bio, der, derSz), derSz); /* d2i consumes BIO */
44073+
d2i_X509_REQ_bio(bio, &x509);
44074+
AssertNotNull(x509);
44075+
BIO_free(bio);
44076+
AssertNotNull(exts = (STACK_OF(X509_EXTENSION)*) X509_REQ_get_extensions(
44077+
x509));
44078+
AssertIntEQ(sk_X509_EXTENSION_num(exts), 2);
44079+
44080+
/* Check the SID extension. */
44081+
AssertNotNull(ext = sk_X509_EXTENSION_value(exts, 0));
44082+
AssertNotNull(extval = X509_EXTENSION_get_data(ext));
44083+
AssertIntEQ(extval->length, sizeof(SidExtension));
44084+
AssertIntEQ(XMEMCMP(SidExtension, extval->data, sizeof(SidExtension)), 0);
44085+
44086+
/* Check the AltNames extension. */
44087+
AssertNotNull(ext = sk_X509_EXTENSION_value(exts, 1));
44088+
AssertNotNull(extval = X509_EXTENSION_get_data(ext));
44089+
AssertIntEQ(extval->length, sizeof(expectedAltName));
44090+
AssertIntEQ(XMEMCMP(expectedAltName, extval->data, sizeof(expectedAltName)),
44091+
0);
44092+
44093+
/* Cleanup */
44094+
AssertNotNull(gns = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL,
44095+
NULL));
44096+
AssertIntEQ(sk_GENERAL_NAME_num(gns), 1);
44097+
AssertNotNull(gn = sk_GENERAL_NAME_value(gns, 0));
44098+
AssertIntEQ(gn->type, 0);
44099+
44100+
/* It is odd that we are using ASN_RFC822_TYPE. It is because when we are
44101+
* parsing der, the string is not fully parsed. It is still raw der whereas
44102+
* when we encode we set the oid (for example, upn) and value. As we are
44103+
* overloading the meaning of the type, here we manually do the right thing.
44104+
*/
44105+
gn->type = ASN_RFC822_TYPE;
44106+
sk_GENERAL_NAME_pop_free(gns, GENERAL_NAME_free);
44107+
44108+
ext->ext_sk->data.gn->type = ASN_RFC822_TYPE;
44109+
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
44110+
X509_REQ_free(x509);
4401144111
res = TEST_RES_CHECK(1);
4401244112
#endif
4401344113
return res;

0 commit comments

Comments
 (0)