@@ -20209,6 +20209,156 @@ static int test_CertMan_LeafKeyUsage(void)
2020920209 return result;
2021020210}
2021120211
20212+ #if !defined(WOLFSSH_NO_FPKI) && defined(WOLFSSL_SUBJ_DIR_ATTR)
20213+
20214+ /* A leaf that names its issuer as its own subject is self-issued, so the
20215+ * NO_VERIFY parse before CheckProfile() looks up no signer for it. Give it
20216+ * what the FPKI worksheet 6 profile checks ahead of the issuer-DN match and
20217+ * expect WS_CERT_PROFILE_E, not a NULL dereference. wolfSSL cannot write a
20218+ * subjectDirectoryAttributes extension, so the leaf carries the
20219+ * countryOfCitizenship value as a CRL distribution points extension whose
20220+ * OID is rewritten to 2.5.29.9 before signing. */
20221+ static int test_CertMan_ProfileLeafNoSigner(void)
20222+ {
20223+ static const byte sda[] = {
20224+ 0x30, 0x12, 0x30, 0x10,
20225+ 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x09, 0x04,
20226+ 0x31, 0x04, 0x13, 0x02, 'U', 'S'
20227+ };
20228+ static const byte crlDpOid[] = { 0x06, 0x03, 0x55, 0x1d, 0x1f };
20229+ int result = 0;
20230+ int ret;
20231+ int sz;
20232+ byte* root = NULL;
20233+ byte* rootKeyBuf = NULL;
20234+ word32 rootSz = 0, rootKeySz = 0;
20235+ byte leaf[2048];
20236+ word32 leafSz = 0;
20237+ byte chain[4096];
20238+ word32 chainSz;
20239+ word32 idx;
20240+ ecc_key rootKey, leafKey;
20241+ int haveRootKey = 0, haveLeafKey = 0;
20242+ WC_RNG rng;
20243+ int haveRng = 0;
20244+ Cert cert;
20245+ DecodedCert decoded;
20246+ WOLFSSH_CERTMAN* cm = NULL;
20247+
20248+ if (certmanLoadFile("./keys/ca-cert-ecc.der", &root, &rootSz) != 0 ||
20249+ certmanLoadFile("./keys/ca-key-ecc.der",
20250+ &rootKeyBuf, &rootKeySz) != 0) {
20251+ printf("CertMan: can't load test certs\n");
20252+ result = -970; goto done;
20253+ }
20254+ if (wc_InitRng(&rng) != 0) {
20255+ result = -971; goto done;
20256+ }
20257+ haveRng = 1;
20258+ if (wc_ecc_init(&rootKey) != 0) {
20259+ result = -972; goto done;
20260+ }
20261+ haveRootKey = 1;
20262+ idx = 0;
20263+ if (wc_EccPrivateKeyDecode(rootKeyBuf, &idx, &rootKey, rootKeySz) != 0) {
20264+ result = -973; goto done;
20265+ }
20266+ if (wc_ecc_init(&leafKey) != 0) {
20267+ result = -974; goto done;
20268+ }
20269+ haveLeafKey = 1;
20270+ if (wc_ecc_make_key(&rng, 32, &leafKey) != 0) {
20271+ result = -975; goto done;
20272+ }
20273+
20274+ ret = wc_InitCert(&cert);
20275+ if (ret == 0)
20276+ ret = wc_SetSubjectBuffer(&cert, root, (int)rootSz);
20277+ if (ret == 0)
20278+ ret = wc_SetIssuerBuffer(&cert, root, (int)rootSz);
20279+ if (ret == 0)
20280+ ret = wc_SetKeyUsage(&cert, "digitalSignature");
20281+ if (ret == 0)
20282+ ret = wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &leafKey);
20283+ if (ret == 0)
20284+ ret = wc_SetAuthKeyIdFromCert(&cert, root, (int)rootSz);
20285+ if (ret == 0) {
20286+ cert.sigType = CTC_SHA256wECDSA;
20287+ cert.daysValid = 365;
20288+ cert.isCA = 0;
20289+ WSTRNCPY(cert.certPolicies[0], "2.16.840.1.101.3.2.1.3.13",
20290+ CTC_MAX_CERTPOL_SZ - 1);
20291+ cert.certPoliciesNb = 1;
20292+ WMEMCPY(cert.crlInfo, sda, sizeof(sda));
20293+ cert.crlInfoSz = (int)sizeof(sda);
20294+ sz = wc_MakeCert(&cert, leaf, sizeof(leaf), NULL, &leafKey, &rng);
20295+ if (sz < 0)
20296+ ret = sz;
20297+ }
20298+ if (ret == 0) {
20299+ ret = -1;
20300+ for (idx = 0; idx + sizeof(crlDpOid) <= (word32)cert.bodySz; idx++) {
20301+ if (WMEMCMP(leaf + idx, crlDpOid, sizeof(crlDpOid)) == 0) {
20302+ leaf[idx + sizeof(crlDpOid) - 1] = 0x09;
20303+ ret = 0;
20304+ break;
20305+ }
20306+ }
20307+ }
20308+ if (ret == 0) {
20309+ sz = wc_SignCert(cert.bodySz, cert.sigType, leaf, sizeof(leaf), NULL,
20310+ &rootKey, &rng);
20311+ if (sz < 0)
20312+ ret = sz;
20313+ else
20314+ leafSz = (word32)sz;
20315+ }
20316+ if (ret != 0) {
20317+ printf("CertMan: forge profile leaf failed, ret=%d\n", ret);
20318+ result = -976; goto done;
20319+ }
20320+
20321+ /* The leaf must get as far as the issuer-DN match. */
20322+ wc_InitDecodedCert(&decoded, leaf, leafSz, NULL);
20323+ ret = wc_ParseCert(&decoded, CERT_TYPE, NO_VERIFY, NULL);
20324+ if (ret == 0 && WSTRCMP(decoded.countryOfCitizenship, "US") != 0) {
20325+ ret = -1;
20326+ }
20327+ wc_FreeDecodedCert(&decoded);
20328+ if (ret != 0 || !certmanIsSelfIssued(leaf, leafSz)) {
20329+ printf("CertMan: forged profile leaf is not as intended\n");
20330+ result = -977; goto done;
20331+ }
20332+
20333+ cm = wolfSSH_CERTMAN_new(NULL);
20334+ if (cm == NULL ||
20335+ wolfSSH_CERTMAN_LoadRootCA_buffer(cm, root, rootSz) != WS_SUCCESS) {
20336+ result = -978; goto done;
20337+ }
20338+ chainSz = certmanAppendCert(chain, (word32)sizeof(chain), 0,
20339+ leaf, leafSz);
20340+ ret = wolfSSH_CERTMAN_VerifyCerts_buffer(cm, chain, chainSz, 1);
20341+ if (ret != WS_CERT_PROFILE_E) {
20342+ printf("CertMan: self-issued profile leaf got %d\n", ret);
20343+ result = -979; goto done;
20344+ }
20345+
20346+ done:
20347+ if (cm != NULL)
20348+ wolfSSH_CERTMAN_free(cm);
20349+ if (haveRootKey)
20350+ wc_ecc_free(&rootKey);
20351+ if (haveLeafKey)
20352+ wc_ecc_free(&leafKey);
20353+ if (haveRng)
20354+ wc_FreeRng(&rng);
20355+ free(root);
20356+ free(rootKeyBuf);
20357+ return result;
20358+ }
20359+
20360+ #endif /* !WOLFSSH_NO_FPKI && WOLFSSL_SUBJ_DIR_ATTR */
20361+
2021220362#endif /* WOLFSSL_CERT_EXT */
2021320363
2021420364#endif /* WOLFSSH_TEST_CERTMAN_PROMOTE */
@@ -27519,6 +27669,13 @@ int wolfSSH_UnitTest(int argc, char** argv)
2751927669 printf("CertMan_LeafKeyUsage: %s\n",
2752027670 (unitResult == 0 ? "SUCCESS" : "FAILED"));
2752127671 testResult = testResult || unitResult;
27672+
27673+ #if !defined(WOLFSSH_NO_FPKI) && defined(WOLFSSL_SUBJ_DIR_ATTR)
27674+ unitResult = test_CertMan_ProfileLeafNoSigner();
27675+ printf("CertMan_ProfileLeafNoSigner: %s\n",
27676+ (unitResult == 0 ? "SUCCESS" : "FAILED"));
27677+ testResult = testResult || unitResult;
27678+ #endif
2752227679#endif
2752327680#endif
2752427681
0 commit comments