Skip to content

Commit 4a61a8d

Browse files
committed
certman: reject a profile leaf with no signer
wc_ParseCert() with NO_VERIFY does not look up the signer of a self-issued leaf, so CheckProfile() treats a NULL cert->ca as a profile mismatch instead of dereferencing it. - test a self-issued leaf that reaches the issuer-DN match Issue: F-8862
1 parent c3a746a commit 4a61a8d

2 files changed

Lines changed: 162 additions & 0 deletions

File tree

‎src/certman.c‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,11 @@ static int CheckProfile(DecodedCert* cert, int profile)
955955
}
956956

957957
/* encoding of issuer DN must be exact match to CA subject DN */
958+
if (valid && cert->ca == NULL) {
959+
/* a self-issued leaf parsed NO_VERIFY has no signer looked up */
960+
WLOG(WS_LOG_CERTMAN, "CA for issuer DN match not found");
961+
valid = 0;
962+
}
958963
if (valid) {
959964
int sz = min(SIGNER_DIGEST_SIZE, KEYID_SIZE);
960965
if (XMEMCMP(cert->ca->subjectNameHash, cert->issuerHash, sz) != 0) {

‎tests/unit.c‎

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)