Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions .github/workflows/mldsa-composite-config.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: ML-DSA Composite Configs

# Builds wolfSSH with ML-DSA on but traditional halves off, exercising the
# Builds wolfSSH with ML-DSA levels or traditional halves off, exercising the
# per-composite gates in wolfssh/internal.h in states the all-on and all-off
# builds never reach.

Expand Down Expand Up @@ -68,6 +68,16 @@ jobs:
defines: -DWOLFSSH_NO_ECDSA_SHA2_NISTP256 -DWOLFSSH_NO_ECDSA_SHA2_NISTP384 -DWOLFSSH_NO_ED25519 -DWOLFSSH_NO_MLDSA87
expect: ''
exclude_tests: tests/api.test tests/testsuite.test
# No level left, so WOLFSSH_NO_MLDSA itself must be derived;
# test_MlDsaLevelsDisabled in unit.test checks that.
- name: no-levels
defines: -DWOLFSSH_NO_MLDSA44 -DWOLFSSH_NO_MLDSA65 -DWOLFSSH_NO_MLDSA87
mldsa_off: true
expect: ''
# ML-DSA-44 alone off; its composites go, 65 and 87 stay.
- name: no-mldsa44
defines: -DWOLFSSH_NO_MLDSA44
expect: ssh-mldsa65-ed25519@wolfssl.com ssh-mldsa65-es256@wolfssl.com ssh-mldsa87-ed448@wolfssl.com ssh-mldsa87-es384@wolfssl.com
# Sets one gate directly rather than deriving it, the rest left on
# to expose a missed site. Only row with --enable-ossh-certs.
- name: single-composite-gate
Expand Down Expand Up @@ -143,14 +153,20 @@ jobs:
# A crash must not pass vacuously with an empty list.
echo "$out" | grep -q '^Set Key: '
keys=$(echo "$out" | sed -n 's/^Set Key: //p')
# ML-DSA itself must be on, or an empty composite list proves nothing.
echo "$keys" | grep -q 'ssh-mldsa-44'
acc=$(echo "$out" | sed -n 's/^Set Key Accepted: //p')
if [ '${{ matrix.mldsa_off }}' = 'true' ]; then
# No ML-DSA name of any kind in either table. A bare `!` does
# not trip bash -e, so fail explicitly.
if echo "$keys,$acc" | grep -q 'ssh-mldsa'; then exit 1; fi
else
# ML-DSA itself must be on, or an empty composite list proves nothing.
echo "$keys" | grep -q 'ssh-mldsa-[0-9]'
fi
got=$(echo "$keys" | tr ',' '\n' | { grep -o 'ssh-mldsa[0-9][0-9]-.*' || true; } | LC_ALL=C sort -u | tr '\n' ' ' | sed 's/ $//')
echo "composites offered: '$got'"
test "$got" = "${{ matrix.expect }}"
# Second table, gated in parallel with the host-key one.
echo "$out" | grep -q '^Set Key Accepted: '
acc=$(echo "$out" | sed -n 's/^Set Key Accepted: //p')
gotAcc=$(echo "$acc" | tr ',' '\n' | { grep -o 'ssh-mldsa[0-9][0-9]-.*' || true; } | LC_ALL=C sort -u | tr '\n' ' ' | sed 's/ $//')
echo "composites accepted: '$gotAcc'"
test "$gotAcc" = "${{ matrix.expect }}"
Expand Down
3 changes: 2 additions & 1 deletion src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ typedef char wolfSSH_channel_overhead_check[
HAVE_ED25519_KEY_EXPORT are all set. Disables ssh-ed25519 server and
user authentication as well as the ML-DSA+Ed25519 composites.
WOLFSSH_NO_MLDSA
Set when MLDSA is disabled and/or not included in wolfssl downloaded.
Set when MLDSA is disabled and/or not included in wolfssl downloaded,
or when WOLFSSH_NO_MLDSA44, 65 and 87 are all set.
WOLFSSH_NO_MLDSA44
Set for ML-DSA-44.
WOLFSSH_NO_MLDSA65
Expand Down
36 changes: 34 additions & 2 deletions tests/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,12 @@ static int test_KDF(void)
}


/* Checks the internal.h derivation directly, independent of any API. */
#if defined(WOLFSSH_NO_MLDSA44) && defined(WOLFSSH_NO_MLDSA65) && \
defined(WOLFSSH_NO_MLDSA87) && !defined(WOLFSSH_NO_MLDSA)
#error "WOLFSSH_NO_MLDSA must follow from all three levels being off"
#endif

/* Key Generation Unit Test */

#ifdef WOLFSSH_KEYGEN
Expand Down Expand Up @@ -1369,6 +1375,25 @@ static int test_MlDsaCompositesDisabled(void)

#endif /* WOLFSSH_NO_MLDSA */

/* API behaviour with no level built; the #error above covers the derivation. */
#if defined(WOLFSSH_NO_MLDSA44) && defined(WOLFSSH_NO_MLDSA65) && \
defined(WOLFSSH_NO_MLDSA87)
static int test_MlDsaLevelsDisabled(void)
{
byte dummy[1];
int result = 0;
int sz;

sz = wolfSSH_MakeMlDsaKey(dummy, sizeof(dummy), WOLFSSH_MLDSAKEY_44);
if (sz != WS_NOT_COMPILED) {
printf("MlDsaLevelsDisabled: MakeMlDsaKey wrong result %d\n", sz);
result = -133;
}

return result;
}
#endif

#endif /* WOLFSSH_KEYGEN */

/* Exercises the malformed-input error paths of the WOLFSSH_FORMAT_OPENSSH
Expand Down Expand Up @@ -13223,7 +13248,7 @@ static int test_KEY_clean_osshCert(void)
}
#endif /* WOLFSSH_OSSH_CERTS */

#if !defined(WOLFSSH_NO_MLDSA)
#if !defined(WOLFSSH_NO_MLDSA) && !defined(WOLFSSH_NO_MLDSA44)
/* keys/server-key-mldsa44.der - MlDsa44 OneAsymmetricKey */
static const byte unitTestMlDsaPrivKey[] = {
0x30, 0x82, 0x0a, 0x3e, 0x02, 0x01, 0x00, 0x30,
Expand Down Expand Up @@ -13556,7 +13581,7 @@ static const byte unitTestMlDsaPrivKey[] = {
0x27, 0xfe, 0x32, 0x26, 0x3c, 0x33, 0x83, 0xda,
0x18, 0xc9
};
#endif /* !WOLFSSH_NO_MLDSA */
#endif /* !WOLFSSH_NO_MLDSA && !WOLFSSH_NO_MLDSA44 */

#ifndef WOLFSSH_NO_ECDSA
/* P-256 DER with the OID last byte changed 0x07 -> 0x01 (secp192r1).
Expand Down Expand Up @@ -23755,6 +23780,13 @@ int wolfSSH_UnitTest(int argc, char** argv)
testResult = testResult || unitResult;
#endif /* WOLFSSH_NO_MLDSA_COMPOSITES */
#endif
#if defined(WOLFSSH_NO_MLDSA44) && defined(WOLFSSH_NO_MLDSA65) && \
defined(WOLFSSH_NO_MLDSA87)
unitResult = test_MlDsaLevelsDisabled();
printf("MlDsaLevelsDisabled: %s\n",
(unitResult == 0 ? "SUCCESS" : "FAILED"));
testResult = testResult || unitResult;
#endif
#endif /* WOLFSSH_KEYGEN */
unitResult = test_OpenSshPemNegative();
printf("OpenSshPemNegative: %s\n",
Expand Down
6 changes: 6 additions & 0 deletions wolfssh/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,12 @@ extern "C" {
#define WOLFSSH_NO_MLDSA65
#define WOLFSSH_NO_MLDSA87
#endif
/* Each composite needs its ML-DSA level, so no level leaves no ML-DSA. */
#if defined(WOLFSSH_NO_MLDSA44) && defined(WOLFSSH_NO_MLDSA65) && \
defined(WOLFSSH_NO_MLDSA87)
#undef WOLFSSH_NO_MLDSA
#define WOLFSSH_NO_MLDSA
#endif

#ifdef NO_SHA
#undef WOLFSSH_NO_SHA1
Expand Down
Loading