Skip to content

Commit 99512e2

Browse files
Replace the matching certificate slot instead of appending a duplicate
1 parent ddd9c1a commit 99512e2

2 files changed

Lines changed: 75 additions & 16 deletions

File tree

src/internal.c

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2547,30 +2547,35 @@ static int SetHostCertificate(WOLFSSH_CTX* ctx,
25472547
}
25482548
}
25492549

2550+
/* Replace the matching slot if the search found one, else append. */
2551+
destIdx = HINTISSET(certIdx) ? certIdx : ctx->privateKeyCount;
2552+
25502553
if (destIdx >= WOLFSSH_MAX_PVT_KEYS) {
2554+
WFREE(der, ctx->heap, dynamicType);
25512555
ret = WS_CTX_KEY_COUNT_E;
25522556
}
25532557
else {
25542558
WOLFSSH_PVT_KEY* pvtKey = ctx->privateKey + destIdx;
25552559

2556-
if (pvtKey->publicKeyFmt == certId) {
2557-
if (pvtKey->cert != NULL) {
2558-
WFREE(pvtKey->cert, ctx->heap, dynamicType);
2559-
}
2560+
/* Copy the paired key into the slot before claiming it, so a
2561+
* failure here leaves the table unchanged. */
2562+
ret = UpdateHostCertificates(ctx, keyIdx, destIdx);
2563+
if (ret != WS_SUCCESS) {
2564+
WFREE(der, ctx->heap, dynamicType);
25602565
}
25612566
else {
2562-
certIdx = destIdx;
2563-
ctx->privateKeyCount++;
2564-
pvtKey->publicKeyFmt = certId;
2565-
}
2566-
2567-
pvtKey->cert = der;
2568-
pvtKey->certSz = derSz;
2567+
if (pvtKey->publicKeyFmt == certId) {
2568+
if (pvtKey->cert != NULL) {
2569+
WFREE(pvtKey->cert, ctx->heap, dynamicType);
2570+
}
2571+
}
2572+
else {
2573+
ctx->privateKeyCount++;
2574+
pvtKey->publicKeyFmt = certId;
2575+
}
25692576

2570-
if (ret == WS_SUCCESS) {
2571-
ret = UpdateHostCertificates(ctx, keyIdx, certIdx);
2572-
}
2573-
if (ret == WS_SUCCESS) {
2577+
pvtKey->cert = der;
2578+
pvtKey->certSz = derSz;
25742579
RefreshPublicKeyAlgo(ctx);
25752580
}
25762581
}

tests/api.c

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,12 @@ static void test_wolfSSH_CTX_UseCert_buffer(void)
714714
WOLFSSH_CTX* ctx = NULL;
715715
byte* cert = NULL;
716716
word32 certSz = 0;
717+
#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256
718+
byte* key = NULL;
719+
word32 keySz = 0;
720+
word32 count = 0;
721+
byte lastFmt = ID_NONE;
722+
#endif
717723

718724
ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL);
719725
AssertNotNull(ctx);
@@ -732,6 +738,8 @@ static void test_wolfSSH_CTX_UseCert_buffer(void)
732738
#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256
733739
AssertIntEQ(WS_SUCCESS,
734740
wolfSSH_CTX_UseCert_buffer(ctx, cert, certSz, WOLFSSH_FORMAT_PEM));
741+
AssertIntEQ(1, ctx->privateKeyCount);
742+
AssertNotNull(ctx->privateKey[0].cert);
735743
#endif
736744

737745
AssertIntEQ(WS_BAD_FILETYPE_E,
@@ -756,17 +764,63 @@ static void test_wolfSSH_CTX_UseCert_buffer(void)
756764
free(cert);
757765
cert = NULL;
758766

759-
AssertIntEQ(0, load_file("./keys/server-cert.der", &cert, &certSz));
767+
#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256
768+
/* A matching private key seeds a key copy in the cert slot. */
769+
AssertIntEQ(0, load_file("./keys/server-key-ecc.der", &key, &keySz));
770+
AssertIntEQ(WS_SUCCESS,
771+
wolfSSH_CTX_UsePrivateKey_buffer(ctx, key, keySz,
772+
WOLFSSH_FORMAT_ASN1));
773+
count = ctx->privateKeyCount;
774+
AssertIntEQ(2, count);
775+
#endif
776+
777+
/* A different certificate, so the reload shows in the stored DER. */
778+
AssertIntEQ(0, load_file("./keys/fred-cert.der", &cert, &certSz));
760779
AssertNotNull(cert);
761780
AssertIntNE(0, certSz);
762781

763782
#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256
764783
AssertIntEQ(WS_SUCCESS,
765784
wolfSSH_CTX_UseCert_buffer(ctx, cert, certSz, WOLFSSH_FORMAT_ASN1));
785+
/* Reloading replaces the slot instead of appending a duplicate. */
786+
AssertIntEQ(count, ctx->privateKeyCount);
787+
AssertIntEQ(certSz, ctx->privateKey[0].certSz);
788+
AssertIntEQ(0, XMEMCMP(ctx->privateKey[0].cert, cert, certSz));
789+
AssertIntEQ(2, ctx->publicKeyAlgoCount);
790+
/* The replaced slot keeps a fresh copy of the matching key. */
791+
AssertIntEQ(ctx->privateKey[1].keySz, ctx->privateKey[0].keySz);
792+
AssertIntEQ(0, XMEMCMP(ctx->privateKey[0].key, ctx->privateKey[1].key,
793+
ctx->privateKey[0].keySz));
794+
795+
/* A full table still replaces the matching slot rather than rejecting;
796+
* a third certificate keeps the stored-DER checks honest. */
797+
free(cert);
798+
cert = NULL;
799+
AssertIntEQ(0, load_file("./keys/server-cert.der", &cert, &certSz));
800+
ctx->privateKeyCount = WOLFSSH_MAX_PVT_KEYS;
801+
AssertIntEQ(WS_SUCCESS,
802+
wolfSSH_CTX_UseCert_buffer(ctx, cert, certSz, WOLFSSH_FORMAT_ASN1));
803+
AssertIntEQ(certSz, ctx->privateKey[0].certSz);
804+
AssertIntEQ(0, XMEMCMP(ctx->privateKey[0].cert, cert, certSz));
805+
/* publicKeyAlgo stays stale from the fabricated count; ctx freed below. */
806+
ctx->privateKeyCount = count;
807+
808+
/* No matching slot and no room: rejected, and the DER is freed. */
809+
lastFmt = ctx->privateKey[0].publicKeyFmt;
810+
ctx->privateKey[0].publicKeyFmt = ID_NONE;
811+
ctx->privateKeyCount = WOLFSSH_MAX_PVT_KEYS;
812+
AssertIntEQ(WS_CTX_KEY_COUNT_E,
813+
wolfSSH_CTX_UseCert_buffer(ctx, cert, certSz, WOLFSSH_FORMAT_ASN1));
814+
AssertIntEQ(WOLFSSH_MAX_PVT_KEYS, ctx->privateKeyCount);
815+
ctx->privateKeyCount = count;
816+
ctx->privateKey[0].publicKeyFmt = lastFmt;
766817
#endif
767818

768819
wolfSSH_CTX_free(ctx);
769820
free(cert);
821+
#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256
822+
free(key);
823+
#endif
770824
#endif /* WOLFSSH_CERTS */
771825
}
772826

0 commit comments

Comments
 (0)