diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index de6f2452f14..239631d84fa 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -757,6 +757,7 @@ WOLFSSL_DTLS_DISALLOW_FUTURE WOLFSSL_DTLS_NO_HVR_ON_RESUME WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS WOLFSSL_DTLS_RESEND_ONLY_TIMEOUT +WOLFSSL_DTN WOLFSSL_DUMP_MEMIO_STREAM WOLFSSL_DUP_CERTPOL WOLFSSL_EARLY_DATA_NO_ANTI_REPLAY diff --git a/certs/bundle-eid-cert.der b/certs/bundle-eid-cert.der new file mode 100644 index 00000000000..ebc7cf98f13 Binary files /dev/null and b/certs/bundle-eid-cert.der differ diff --git a/certs/renewcerts.sh b/certs/renewcerts.sh index 397b989d44b..2f2fcdd331b 100755 --- a/certs/renewcerts.sh +++ b/certs/renewcerts.sh @@ -35,6 +35,7 @@ # fpki-cert.der # fpki-certpol-cert.der # rid-cert.der +# bundle-eid-cert.der # aia/ca-issuers-cert.pem # aia/multi-aia-cert.pem # aia/overflow-aia-cert.pem @@ -490,6 +491,24 @@ run_renewcerts(){ echo "End of section" echo "---------------------------------------------------------------------" ########################################################### + ########## update and sign bundle-eid-cert.der ############ + ########################################################### + # RFC 9174 (Bundle Protocol / DTN) leaf cert whose SAN carries an + # id-on-bundleEID OtherName (OID 1.3.6.1.5.5.7.8.11) with an IA5String + # value, plus a dNSName. ECC leaf signed by the ECC CA. Exercised by the + # WOLFSSL_DTN regression test (test_DecodeOtherName_bundleEID). + echo "Updating bundle-eid-cert.der" + echo "" + #pipe the following arguments to openssl req... + echo -e "US\\nMontana\\nBozeman\\nwolfSSL\\nDTN\\nwww.wolfssl.com\\ninfo@wolfssl.com\\n.\\n.\\n" | openssl req -new -key ecc-key.pem -config ./wolfssl.cnf -nodes > bundle-eid-req.pem + check_result $? "Step 1" + + openssl x509 -req -in bundle-eid-req.pem -extfile wolfssl.cnf -extensions bundle_eid_ext -days 1000 -CA ca-ecc-cert.pem -CAkey ca-ecc-key.pem -set_serial 16 -out bundle-eid-cert.der -outform DER + check_result $? "Step 2" + rm bundle-eid-req.pem + echo "End of section" + echo "---------------------------------------------------------------------" + ########################################################### ########## update and sign server-cert.pem ################ ########################################################### echo "Updating server-cert.pem" diff --git a/certs/renewcerts/wolfssl.cnf b/certs/renewcerts/wolfssl.cnf index 70453f9369f..1997f6e12e2 100644 --- a/certs/renewcerts/wolfssl.cnf +++ b/certs/renewcerts/wolfssl.cnf @@ -452,3 +452,16 @@ DNS.1 = www.example.org URI.1 = https://www.wolfssl.com/ otherName.2 = 2.16.840.1.101.3.6.6;FORMAT:HEX,OCT:D1:38:10:D8:28:AF:2C:10:84:35:15:A1:68:58:28:AF:02:10:86:A2:84:E7:39:C3:EB +# RFC 9174 (Bundle Protocol / DTN) id-on-bundleEID OtherName with an +# IA5String value, followed by a dNSName. Used by the WOLFSSL_DTN test. +[bundle_eid_ext] +basicConstraints = critical, CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid +keyUsage = critical, digitalSignature +subjectAltName = @bundle_eid_altname + +[bundle_eid_altname] +otherName.1 = 1.3.6.1.5.5.7.8.11;IA5STRING:dtn://node000/ +DNS.1 = node000.local + diff --git a/scripts/asn1_oid_sum.pl b/scripts/asn1_oid_sum.pl index 8df6545f022..52414c45ce1 100755 --- a/scripts/asn1_oid_sum.pl +++ b/scripts/asn1_oid_sum.pl @@ -912,6 +912,12 @@ sub print_footer { { name => "HW_NAME", oid => \@sep_hw_name }, ); +# NOTE: SepHardwareName_Sum also carries BUNDLE_EID_OID (1.3.6.1.5.5.7.8.11, +# id-on-bundleEID, RFC 9174). It is maintained directly in oid_sum.h behind +# "#ifdef WOLFSSL_DTN" rather than emitted here, since this generator has no +# per-entry feature-guard support (same approach as ACME_IDENTIFIER_OID). +# old sum = 86, new sum = 0x0e09012e. + print_sum_enum("SepHardwareName", "_OID", \@seps); diff --git a/tests/api/test_asn.c b/tests/api/test_asn.c index bfa95626368..4e9375fd059 100644 --- a/tests/api/test_asn.c +++ b/tests/api/test_asn.c @@ -1495,6 +1495,66 @@ int test_DecodeAltNames_length_underflow(void) return EXPECT_RESULT(); } +/* Regression test for id-on-bundleEID (RFC 9174) OtherName decoding. + * + * A SAN OtherName with OID 1.3.6.1.5.5.7.8.11 whose value is an IA5String must + * be decoded - not rejected with ASN_PARSE_E - when WOLFSSL_DTN is enabled. + * Reproduces the GitHub report "X509 decoder fails to handle OtherName with + * value of an IA5String". + * + * The certificate is generated by certs/renewcerts.sh (bundle-eid-cert.der): + * an ECDSA P-256 leaf whose SAN holds an id-on-bundleEID OtherName carrying + * the IA5String "dtn://node000/", followed by a dNSName "node000.local". */ +int test_DecodeOtherName_bundleEID(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTN) && \ + (defined(WOLFSSL_SEP) || defined(WOLFSSL_FPKI)) && \ + defined(HAVE_ECC) && !defined(NO_CERTS) && !defined(NO_ASN) && \ + !defined(NO_FILESYSTEM) + const char* bundleEidCert = "./certs/bundle-eid-cert.der"; + XFILE f = XBADFILE; + byte buf[2048]; + int bytes = 0; + DecodedCert cert; + DNS_entry* dns = NULL; + int foundBundleEid = 0; + int foundDns = 0; + + ExpectTrue((f = XFOPEN(bundleEidCert, "rb")) != XBADFILE); + ExpectIntGT(bytes = (int)XFREAD(buf, 1, sizeof(buf), f), 0); + if (f != XBADFILE) + XFCLOSE(f); + + wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL); + /* Before the fix this failed with ASN_PARSE_E because the OtherName value + * (an IA5String) did not match any of the supported value types. */ + ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0); + + for (dns = cert.altNames; dns != NULL; dns = dns->next) { + if ((dns->type == ASN_OTHER_TYPE) && (dns->len == 14) && + (XMEMCMP(dns->name, "dtn://node000/", 14) == 0)) { + foundBundleEid = 1; + #ifdef WOLFSSL_FPKI + ExpectIntEQ(dns->oidSum, BUNDLE_EID_OID); + #endif + } + if ((dns->type == ASN_DNS_TYPE) && (dns->len == 13) && + (XMEMCMP(dns->name, "node000.local", 13) == 0)) { + foundDns = 1; + } + } + /* The bundleEID IA5String value must be decoded into an OtherName entry, + * and the trailing dNSName must still be parsed. */ + ExpectIntEQ(foundBundleEid, 1); + ExpectIntEQ(foundDns, 1); + + wc_FreeDecodedCert(&cert); +#endif /* WOLFSSL_DTN && (WOLFSSL_SEP || WOLFSSL_FPKI) && HAVE_ECC && + * !NO_CERTS && !NO_ASN && !NO_FILESYSTEM */ + return EXPECT_RESULT(); +} + /* A certificate must not carry two certificatePolicies extensions * (non-repeatable per RFC 5280 4.2). DecodeCertExtensions calls * DecodeExtensionType once per extension; with strict ASN.1 (the default) a diff --git a/tests/api/test_asn.h b/tests/api/test_asn.h index d48aac7a6f5..0885404b097 100644 --- a/tests/api/test_asn.h +++ b/tests/api/test_asn.h @@ -35,6 +35,7 @@ int test_wolfssl_local_MatchUriNameConstraint(void); int test_wc_DecodeRsaPssParams(void); int test_SerialNumber0_RootCA(void); int test_DecodeAltNames_length_underflow(void); +int test_DecodeOtherName_bundleEID(void); int test_DecodeCertExtensions_dup_certpol(void); int test_ParseCert_SM3wSM2_short_pubkey(void); int test_wc_DecodeObjectId(void); @@ -55,6 +56,7 @@ int test_ToTraditional_ex_mldsa_bad_params(void); TEST_DECL_GROUP("asn", test_wc_DecodeRsaPssParams), \ TEST_DECL_GROUP("asn", test_SerialNumber0_RootCA), \ TEST_DECL_GROUP("asn", test_DecodeAltNames_length_underflow), \ + TEST_DECL_GROUP("asn", test_DecodeOtherName_bundleEID), \ TEST_DECL_GROUP("asn", test_DecodeCertExtensions_dup_certpol), \ TEST_DECL_GROUP("asn", test_ParseCert_SM3wSM2_short_pubkey), \ TEST_DECL_GROUP("asn", test_wc_DecodeObjectId), \ diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 7e855986f67..ef1caf5f107 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -18724,12 +18724,20 @@ static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert) * (RFC3280 sec 4.2.1.7). Often used with FIPS 201 smartcard login. * FASC-N (Federal Agency Smart Credential Number), defined in the document * fpki-x509-cert-policy-common.pdf. Used for a smart card ID. + * + * id-on-bundleEID (RFC 9174, sec 4.4.1), an Other Name whose value is an + * IA5String holding a Bundle Protocol node/endpoint ID (e.g. "dtn://node/"). + * Only handled when WOLFSSL_DTN is defined as these OIDs are specific to + * Delay-Tolerant Networking (DTN) / the Bundle Protocol. */ static const ASNItem otherNameASN[] = { /* TYPEID */ { 0, ASN_OBJECT_ID, 0, 0, 0 }, /* VALUE */ { 0, ASN_CONTEXT_SPECIFIC | ASN_OTHERNAME_VALUE, 1, 1, 0 }, /* UPN */ { 1, ASN_UTF8STRING, 0, 0, 2 }, /* FASC-N */ { 1, ASN_OCTET_STRING, 0, 0, 2 }, +#ifdef WOLFSSL_DTN +/* BEID */ { 1, ASN_IA5_STRING, 0, 0, 2 }, +#endif /* HWN_SEQ */ { 1, ASN_SEQUENCE, 1, 0, 2 }, /* HWN_TYPE */ { 2, ASN_OBJECT_ID, 0, 0, 0 }, /* HWN_NUM */ { 2, ASN_OCTET_STRING, 0, 0, 0 } @@ -18739,6 +18747,9 @@ enum { OTHERNAMEASN_IDX_VALUE, OTHERNAMEASN_IDX_UPN, OTHERNAMEASN_IDX_FASCN, +#ifdef WOLFSSL_DTN + OTHERNAMEASN_IDX_BEID, +#endif OTHERNAMEASN_IDX_HWN_SEQ, OTHERNAMEASN_IDX_HWN_TYPE, OTHERNAMEASN_IDX_HWN_NUM @@ -18806,6 +18817,13 @@ static int DecodeOtherHelper(ASNGetData* dataASN, DecodedCert* cert, int oid) bufLen = dataASN[OTHERNAMEASN_IDX_UPN].data.ref.length; buf = (const char*)dataASN[OTHERNAMEASN_IDX_UPN].data.ref.data; break; +#ifdef WOLFSSL_DTN + case BUNDLE_EID_OID: + /* id-on-bundleEID (RFC 9174) carries an IA5String value. */ + bufLen = dataASN[OTHERNAMEASN_IDX_BEID].data.ref.length; + buf = (const char*)dataASN[OTHERNAMEASN_IDX_BEID].data.ref.data; + break; +#endif /* WOLFSSL_DTN */ default: WOLFSSL_ERROR_VERBOSE(ASN_UNKNOWN_OID_E); ret = ASN_UNKNOWN_OID_E; @@ -18869,6 +18887,9 @@ static int DecodeOtherName(DecodedCert* cert, const byte* input, #ifdef WOLFSSL_FPKI case FASCN_OID: #endif /* WOLFSSL_FPKI */ + #ifdef WOLFSSL_DTN + case BUNDLE_EID_OID: + #endif /* WOLFSSL_DTN */ case UPN_OID: ret = DecodeOtherHelper(dataASN, cert, (int)dataASN[OTHERNAMEASN_IDX_TYPEID].data.oid.sum); diff --git a/wolfssl/wolfcrypt/oid_sum.h b/wolfssl/wolfcrypt/oid_sum.h index d56405c8247..6f71310f19e 100644 --- a/wolfssl/wolfcrypt/oid_sum.h +++ b/wolfssl/wolfcrypt/oid_sum.h @@ -1250,9 +1250,19 @@ enum SepHardwareName_Sum { #ifdef WOLFSSL_OLD_OID_SUM /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x08,0x04 */ HW_NAME_OID = 79 /* 1.3.6.1.5.5.7.8.4 */ +#ifdef WOLFSSL_DTN + , + /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x08,0x0b */ + BUNDLE_EID_OID = 86 /* 1.3.6.1.5.5.7.8.11 */ +#endif #else /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x08,0x04 */ HW_NAME_OID = 0x0109012e /* 1.3.6.1.5.5.7.8.4 */ +#ifdef WOLFSSL_DTN + , + /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x08,0x0b */ + BUNDLE_EID_OID = 0x0e09012e /* 1.3.6.1.5.5.7.8.11 */ +#endif #endif };