Harden wolfSSL and wolfSSH validation
Enable validated ECC imports and X25519 all-zero rejection through PUBLIC build policy. Tighten wolfSSH parser bounds, overflow handling, and signature framing with guard-page and crypto vector contracts.
This commit is contained in:
+222
-1
@@ -119,6 +119,227 @@ TLS_POLICY = """ /* mbedTLS retains this pointer: it must outlive every serve
|
||||
# DHCP uses equivalent remaining-length checks to avoid forming pointers beyond
|
||||
# the input object. Keep original upstream notices verbatim, rather than changing
|
||||
# their copyright year; the central project modification notice is separate.
|
||||
# Bounded server parser subset of official wolfSSL/wolfssh PRs 892, 881,
|
||||
# and 880 (reviewed alongside PR 899). Keep the 1.4.20 state machine and
|
||||
# password/async edits below. GetSize already uses safe remaining lengths.
|
||||
WOLFSSH_PARSER_EDITS = (
|
||||
Edit("""int GetString(char* s, word32* sSz, const byte* buf, word32 len, word32 *idx)
|
||||
{
|
||||
int result;
|
||||
word32 strSz;
|
||||
|
||||
result = GetUint32(&strSz, buf, len, idx);
|
||||
""", """int GetString(char* s, word32* sSz, const byte* buf, word32 len, word32 *idx)
|
||||
{
|
||||
int result;
|
||||
word32 strSz;
|
||||
|
||||
if (*sSz == 0)
|
||||
return WS_BUFFER_E;
|
||||
|
||||
result = GetSize(&strSz, buf, len, idx);
|
||||
"""),
|
||||
Edit(""" result = GetUint32(&sz, buf, len, idx);
|
||||
|
||||
if (result == WS_SUCCESS) {
|
||||
result = WS_BUFFER_E;
|
||||
|
||||
if (*idx < len && sz <= len - *idx) {""", """ result = GetSize(&sz, buf, len, idx);
|
||||
|
||||
if (result == WS_SUCCESS) {
|
||||
result = WS_BUFFER_E;
|
||||
|
||||
if (*idx <= len && sz <= len - *idx) {"""),
|
||||
Edit(""" word32 dataSz;
|
||||
word32 begin = *idx;
|
||||
|
||||
WOLFSSH_UNUSED(ssh);
|
||||
WOLFSSH_UNUSED(len);
|
||||
|
||||
ato32(buf + begin, &dataSz);
|
||||
begin += LENGTH_SZ + dataSz;
|
||||
|
||||
*idx = begin;
|
||||
|
||||
return WS_SUCCESS;""", """ WOLFSSH_UNUSED(ssh);
|
||||
return GetSkip(buf, len, idx);"""),
|
||||
Edit(""" WOLFSSH_UNUSED(len);
|
||||
|
||||
ato32(buf + begin, &nameSz);
|
||||
begin += LENGTH_SZ;
|
||||
|
||||
if (begin + nameSz > len || nameSz >= WOLFSSH_MAX_NAMESZ) {
|
||||
return WS_BUFFER_E;
|
||||
}
|
||||
|
||||
WMEMCPY(serviceName, buf + begin, nameSz);
|
||||
begin += nameSz;
|
||||
serviceName[nameSz] = 0;
|
||||
|
||||
*idx = begin;
|
||||
|
||||
WLOG(WS_LOG_DEBUG, "Requesting service: %s", serviceName);""", """ int ret = GetSize(&nameSz, buf, len, &begin);
|
||||
|
||||
/* Preserve 1.4.20's service-name limit; GetString normally truncates. */
|
||||
if (ret != WS_SUCCESS || nameSz >= sizeof(serviceName))
|
||||
return WS_BUFFER_E;
|
||||
|
||||
begin = *idx;
|
||||
nameSz = sizeof(serviceName);
|
||||
ret = GetString(serviceName, &nameSz, buf, len, &begin);
|
||||
if (ret != WS_SUCCESS)
|
||||
return ret;
|
||||
*idx = begin;
|
||||
|
||||
WLOG(WS_LOG_DEBUG, "Requesting service: %s", serviceName);"""),
|
||||
Edit(""" channel->peerWindowSz += bytesToAdd;
|
||||
|
||||
WLOG(WS_LOG_INFO, " update peerWindowSz = %u",
|
||||
channel->peerWindowSz);""", """ if (bytesToAdd > (word32)0xFFFFFFFFU - channel->peerWindowSz) {
|
||||
ret = WS_OVERFLOW_E;
|
||||
}
|
||||
else {
|
||||
channel->peerWindowSz += bytesToAdd;
|
||||
WLOG(WS_LOG_INFO, " update peerWindowSz = %u",
|
||||
channel->peerWindowSz);
|
||||
}"""),
|
||||
Edit(""" if (publicKeyTypeSz != pk->publicKeyTypeSz &&
|
||||
WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
|
||||
|
||||
WLOG(WS_LOG_DEBUG,
|
||||
"Public Key's type does not match public key type");""", """ if (publicKeyTypeSz != pk->publicKeyTypeSz ||
|
||||
WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
|
||||
|
||||
WLOG(WS_LOG_DEBUG,
|
||||
"Public Key's type does not match public key type");"""),
|
||||
Edit(""" if (publicKeyTypeSz != pk->publicKeyTypeSz &&
|
||||
WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
|
||||
|
||||
WLOG(WS_LOG_DEBUG,
|
||||
"Signature's type does not match public key type");
|
||||
ret = WS_INVALID_ALGO_ID;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
/* Get the size of the signature blob. */
|
||||
ret = GetSize(&sz, pk->signature, pk->signatureSz, &i);
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
ret = GetStringRef(&rSz, &r, pk->signature, pk->signatureSz, &i);""", """ if (publicKeyTypeSz != pk->publicKeyTypeSz ||
|
||||
WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
|
||||
|
||||
WLOG(WS_LOG_DEBUG,
|
||||
"Signature's type does not match public key type");
|
||||
ret = WS_INVALID_ALGO_ID;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
/* Get the size of the signature blob. */
|
||||
ret = GetSize(&sz, pk->signature, pk->signatureSz, &i);
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
ret = GetStringRef(&rSz, &r, pk->signature, pk->signatureSz, &i);"""),
|
||||
# Local framing correction: GetSize proves i + sz cannot overflow. Bound
|
||||
# both mpints to that sub-blob, then reject unconsumed inner/outer bytes.
|
||||
Edit(""" if (publicKeyTypeSz != pk->publicKeyTypeSz ||
|
||||
WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
|
||||
|
||||
WLOG(WS_LOG_DEBUG,
|
||||
"Signature's type does not match public key type");
|
||||
ret = WS_INVALID_ALGO_ID;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
/* Get the size of the signature blob. */
|
||||
ret = GetSize(&sz, pk->signature, pk->signatureSz, &i);
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
ret = GetStringRef(&rSz, &r, pk->signature, pk->signatureSz, &i);
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
ret = GetStringRef(&sSz, &s, pk->signature, pk->signatureSz, &i);
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
ret = wc_ecc_rs_raw_to_sig(r, rSz, s, sSz,""", """ if (publicKeyTypeSz != pk->publicKeyTypeSz ||
|
||||
WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
|
||||
|
||||
WLOG(WS_LOG_DEBUG,
|
||||
"Signature's type does not match public key type");
|
||||
ret = WS_INVALID_ALGO_ID;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
/* Get the size of the signature blob. */
|
||||
ret = GetSize(&sz, pk->signature, pk->signatureSz, &i);
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
/* GetSize bounded sz by signatureSz - i: this end cannot wrap. */
|
||||
sz += i;
|
||||
ret = GetStringRef(&rSz, &r, pk->signature, sz, &i);
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
ret = GetStringRef(&sSz, &s, pk->signature, sz, &i);
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS && (i != sz || sz != pk->signatureSz))
|
||||
ret = WS_BUFFER_E;
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
ret = wc_ecc_rs_raw_to_sig(r, rSz, s, sSz,"""),
|
||||
# PR 880's remaining current-feature label checks (Ed25519).
|
||||
Edit(""" if (publicKeyTypeSz != pk->publicKeyTypeSz
|
||||
&& WMEMCMP(publicKeyType,
|
||||
pk->publicKeyType, publicKeyTypeSz) != 0) {""", """ if (publicKeyTypeSz != pk->publicKeyTypeSz
|
||||
|| WMEMCMP(publicKeyType,
|
||||
pk->publicKeyType, publicKeyTypeSz) != 0) {"""),
|
||||
Edit(""" if (publicKeyTypeSz != pk->publicKeyTypeSz &&
|
||||
WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
|
||||
|
||||
WLOG(WS_LOG_DEBUG,
|
||||
"Signature's type does not match public key type");
|
||||
ret = WS_INVALID_ALGO_ID;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
/* Get the size of the signature blob. */
|
||||
ret = GetSize(&sz, pk->signature, pk->signatureSz, &i);
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
ret = wc_ed25519_verify_msg_init(pk->signature + i, sz,""", """ if (publicKeyTypeSz != pk->publicKeyTypeSz ||
|
||||
WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
|
||||
|
||||
WLOG(WS_LOG_DEBUG,
|
||||
"Signature's type does not match public key type");
|
||||
ret = WS_INVALID_ALGO_ID;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
/* Get the size of the signature blob. */
|
||||
ret = GetSize(&sz, pk->signature, pk->signatureSz, &i);
|
||||
}
|
||||
|
||||
/* The signature string must consume the enclosing signature field. */
|
||||
if (ret == WS_SUCCESS && sz != pk->signatureSz - i)
|
||||
ret = WS_BUFFER_E;
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
ret = wc_ed25519_verify_msg_init(pk->signature + i, sz,"""),
|
||||
)
|
||||
|
||||
ENTRIES = (
|
||||
Entry("dhcpserver", "lwip", "idf",
|
||||
"components/lwip/apps/dhcpserver/dhcpserver.c",
|
||||
@@ -206,7 +427,7 @@ ENTRIES = (
|
||||
), target="mbedx509"),
|
||||
Entry("wolfssh_internal", "wolfssl__wolfssh", "project",
|
||||
"managed_components/wolfssl__wolfssh/src/internal.c",
|
||||
"81ff1f9166708abd5c2911e9fe57c0aee01c88b5d3f68c909ee8a856d37f36a9", (
|
||||
"81ff1f9166708abd5c2911e9fe57c0aee01c88b5d3f68c909ee8a856d37f36a9", WOLFSSH_PARSER_EDITS + (
|
||||
Edit(""" WS_UserAuthData_Password* pw = NULL;
|
||||
int ret = WS_SUCCESS;
|
||||
""", """ WS_UserAuthData_Password* pw = NULL;
|
||||
|
||||
Reference in New Issue
Block a user