added ml-dsa plain key and cert algorithms

pull/1043/head
Emma Stensland 2026-06-29 11:38:09 -06:00 committed by John Safranek
parent 422f69de8b
commit c56dc1027f
15 changed files with 3427 additions and 90 deletions

View File

@ -451,22 +451,30 @@ The wolfSSH client and server will automatically negotiate using Curve25519.
POST-QUANTUM
============
wolfSSH now supports the post-quantum algorithm ML-KEM (formerly known as
Kyber). It uses the ML-KEM-768 parameter set and is hybridized with ECDHE over
the P-256 ECC curve.
wolfSSH supports both post-quantum key exchange via ML-KEM (formerly known as
Kyber) and post-quantum signature verification via ML-DSA (formerly known as
Dilithium).
In order to use this key exchange you must build and install wolfSSL on your
system. Here is an example of an effective configuration:
* **ML-KEM**: Uses the ML-KEM-768 parameter set hybridized with ECDHE over the
P-256 ECC curve.
* **ML-DSA**: Supports ML-DSA-44, ML-DSA-65, and ML-DSA-87 parameter sets for
both server host keys and client public key authentication. When built with
certificate support, ML-DSA X.509 certificates (`x509v3-ssh-mldsa-44`,
`x509v3-ssh-mldsa-65`, and `x509v3-ssh-mldsa-87`) are also supported.
$ ./configure --enable-wolfssh --enable-mlkem
In order to use these algorithms you must build and install wolfSSL with
support for them. Here is an example of an effective configuration:
After that, simply configure and build wolfssh as usual:
$ ./configure --enable-wolfssh --enable-mlkem --enable-mldsa
After that, configure and build wolfSSH as usual:
$ ./configure
$ make all
The wolfSSH client and server will automatically negotiate using ML-KEM-768
hybridized with ECDHE over the P-256 ECC curve.
hybridized with ECDHE over the P-256 ECC curve and ML-DSA for host keys/client
public key authentication.
$ ./examples/echoserver/echoserver -f
@ -476,7 +484,7 @@ On the client side, you will see the following output:
Server said: Hello, wolfSSH!
If you want to see interoperability with OpenQauntumSafe's fork of OpenSSH, you
If you want to see interoperability with OpenQuantumSafe's fork of OpenSSH, you
can build and execute the fork while the echoserver is running. Download the
release from here:
@ -498,6 +506,7 @@ NOTE: when prompted, enter the password which is "upthehill".
You can type a line of text and when you press enter, the line will be echoed
back. Use CTRL-C to terminate the connection.
CERTIFICATE SUPPORT
===================

View File

@ -118,7 +118,18 @@ struct WOLFSSHD_AUTH {
#endif
#ifndef MAX_LINE_SZ
#define MAX_LINE_SZ 900
/* Sized to hold the largest authorized_keys entry. */
#ifndef WOLFSSH_NO_MLDSA
#ifndef WOLFSSH_NO_MLDSA87
#define MAX_LINE_SZ ((WC_MLDSA_87_PUB_KEY_SIZE + 2) / 3 * 4 + 640)
#elif !defined(WOLFSSH_NO_MLDSA65)
#define MAX_LINE_SZ ((WC_MLDSA_65_PUB_KEY_SIZE + 2) / 3 * 4 + 640)
#else
#define MAX_LINE_SZ ((WC_MLDSA_44_PUB_KEY_SIZE + 2) / 3 * 4 + 640)
#endif
#else
#define MAX_LINE_SZ 900
#endif
#endif
#ifndef MAX_PATH_SZ
#define MAX_PATH_SZ 80
@ -186,14 +197,7 @@ static int CheckAuthKeysLine(char* line, word32 lineSz, const byte* key,
word32 keyCandSz = 0;
char* last = NULL;
enum {
#ifdef WOLFSSH_CERTS
NUM_ALLOWED_TYPES = 9
#else
NUM_ALLOWED_TYPES = 5
#endif
};
static const char* allowedTypes[NUM_ALLOWED_TYPES] = {
static const char* allowedTypes[] = {
"ssh-rsa",
"ssh-ed25519",
"ecdsa-sha2-nistp256",
@ -205,7 +209,31 @@ static int CheckAuthKeysLine(char* line, word32 lineSz, const byte* key,
"x509v3-ecdsa-sha2-nistp384",
"x509v3-ecdsa-sha2-nistp521",
#endif
#ifndef WOLFSSH_NO_MLDSA
#ifndef WOLFSSH_NO_MLDSA44
"ssh-mldsa-44",
#endif
#ifndef WOLFSSH_NO_MLDSA65
"ssh-mldsa-65",
#endif
#ifndef WOLFSSH_NO_MLDSA87
"ssh-mldsa-87",
#endif
#ifdef WOLFSSH_CERTS
#ifndef WOLFSSH_NO_MLDSA44
"x509v3-ssh-mldsa-44",
#endif
#ifndef WOLFSSH_NO_MLDSA65
"x509v3-ssh-mldsa-65",
#endif
#ifndef WOLFSSH_NO_MLDSA87
"x509v3-ssh-mldsa-87",
#endif
#endif
#endif
};
const int NUM_ALLOWED_TYPES =
(int)(sizeof(allowedTypes) / sizeof(allowedTypes[0]));
int typeOk = 0;
int i;

View File

@ -1806,6 +1806,123 @@ static int load_key_ed25519(byte* buf, word32 bufSz)
#endif /* WOLFSSH_NO_ED25519 */
#ifndef WOLFSSH_NO_MLDSA44
static int load_key_mldsa44(byte* buf, word32 bufSz)
{
word32 sz = 0;
#ifndef NO_FILESYSTEM
sz = load_file("./keys/server-key-mldsa44.der", buf, &bufSz);
#else
(void)buf; (void)bufSz;
#endif
return sz;
}
#endif /* WOLFSSH_NO_MLDSA44 */
#ifndef WOLFSSH_NO_MLDSA65
static int load_key_mldsa65(byte* buf, word32 bufSz)
{
word32 sz = 0;
#ifndef NO_FILESYSTEM
sz = load_file("./keys/server-key-mldsa65.der", buf, &bufSz);
#else
(void)buf; (void)bufSz;
#endif
return sz;
}
#endif /* WOLFSSH_NO_MLDSA65 */
#ifndef WOLFSSH_NO_MLDSA87
static int load_key_mldsa87(byte* buf, word32 bufSz)
{
word32 sz = 0;
#ifndef NO_FILESYSTEM
sz = load_file("./keys/server-key-mldsa87.der", buf, &bufSz);
#else
(void)buf; (void)bufSz;
#endif
return sz;
}
#endif /* WOLFSSH_NO_MLDSA87 */
#ifndef WOLFSSH_NO_MLDSA
static int LoadMlDsaHostKeys(WOLFSSH_CTX* ctx, const char* keyList)
{
byte* mldsaBuf;
int loaded = 0;
mldsaBuf = (byte*)WMALLOC(MLDSA_MAX_BOTH_KEY_DER_SIZE, NULL, 0);
if (mldsaBuf == NULL) {
fprintf(stderr, "Couldn't allocate ML-DSA key load buffer.\n");
return -1;
}
#ifndef WOLFSSH_NO_MLDSA44
if (WSTRSTR(keyList, "mldsa-44") != NULL) {
int mldsaSz = load_key_mldsa44(mldsaBuf, MLDSA_MAX_BOTH_KEY_DER_SIZE);
if (mldsaSz <= 0) {
fprintf(stderr, "Couldn't load ML-DSA-44 key file.\n");
WFREE(mldsaBuf, NULL, 0);
return -1;
}
if (wolfSSH_CTX_UsePrivateKey_buffer(ctx, mldsaBuf, (word32)mldsaSz,
WOLFSSH_FORMAT_ASN1) < 0) {
fprintf(stderr, "Couldn't use ML-DSA-44 key buffer.\n");
WFREE(mldsaBuf, NULL, 0);
return -1;
}
loaded++;
}
#endif /* WOLFSSH_NO_MLDSA44 */
#ifndef WOLFSSH_NO_MLDSA65
if (WSTRSTR(keyList, "mldsa-65") != NULL) {
int mldsaSz = load_key_mldsa65(mldsaBuf, MLDSA_MAX_BOTH_KEY_DER_SIZE);
if (mldsaSz <= 0) {
fprintf(stderr, "Couldn't load ML-DSA-65 key file.\n");
WFREE(mldsaBuf, NULL, 0);
return -1;
}
if (wolfSSH_CTX_UsePrivateKey_buffer(ctx, mldsaBuf, (word32)mldsaSz,
WOLFSSH_FORMAT_ASN1) < 0) {
fprintf(stderr, "Couldn't use ML-DSA-65 key buffer.\n");
WFREE(mldsaBuf, NULL, 0);
return -1;
}
loaded++;
}
#endif /* WOLFSSH_NO_MLDSA65 */
#ifndef WOLFSSH_NO_MLDSA87
if (WSTRSTR(keyList, "mldsa-87") != NULL) {
int mldsaSz = load_key_mldsa87(mldsaBuf, MLDSA_MAX_BOTH_KEY_DER_SIZE);
if (mldsaSz <= 0) {
fprintf(stderr, "Couldn't load ML-DSA-87 key file.\n");
WFREE(mldsaBuf, NULL, 0);
return -1;
}
if (wolfSSH_CTX_UsePrivateKey_buffer(ctx, mldsaBuf, (word32)mldsaSz,
WOLFSSH_FORMAT_ASN1) < 0) {
fprintf(stderr, "Couldn't use ML-DSA-87 key buffer.\n");
WFREE(mldsaBuf, NULL, 0);
return -1;
}
loaded++;
}
#endif /* WOLFSSH_NO_MLDSA87 */
WFREE(mldsaBuf, NULL, 0);
if (loaded == 0) {
fprintf(stderr, "ML-DSA key list '%s' matched no supported level.\n",
keyList);
return -1;
}
return 0;
}
#endif /* WOLFSSH_NO_MLDSA */
typedef struct StrList {
const char* str;
struct StrList* next;
@ -3137,7 +3254,8 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
if (tpmHostKeyPath != NULL) {
if (EchoserverInitTpmHostKey(ctx, tpmHostKeyPath,
ECHOSERVER_TPM_KEY_AUTH_DEFAULT) != 0) {
ES_ERROR("Couldn't load TPM host key from %s.\n", tpmHostKeyPath);
ES_ERROR("Couldn't load TPM host key from %s.\n",
tpmHostKeyPath);
}
loadDefaultHostKeys = 0;
}
@ -3180,6 +3298,19 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
#endif /* WOLFSSH_NO_ED25519 */
}
/* Load only the ML-DSA levels requested in keyList; loading all levels
* unconditionally would force mldsa negotiation on non-mldsa tests. */
#ifndef WOLFSSH_NO_MLDSA
if (keyList != NULL && WSTRSTR(keyList, "mldsa") != NULL) {
if (LoadMlDsaHostKeys(ctx, keyList) != 0) {
#ifdef WOLFSSH_SMALL_STACK
WFREE(keyLoadBuf, NULL, 0);
#endif
ES_ERROR("Error loading ML-DSA host keys.\n");
}
}
#endif /* WOLFSSH_NO_MLDSA */
#ifndef NO_FILESYSTEM
if (userPubKey) {
byte* userBuf = NULL;

View File

@ -24,5 +24,7 @@ EXTRA_DIST+= \
keys/server-key.pem keys/fred-key.der keys/fred-key.pem \
keys/id_ecdsa keys/id_ecdsa.pub keys/id_rsa keys/id_rsa.pub \
keys/renewcerts.sh keys/renewcerts.cnf \
keys/server-key-ed25519.der keys/server-key-ed25519.pem
keys/server-key-ed25519.der keys/server-key-ed25519.pem \
keys/server-key-mldsa44.der keys/server-key-mldsa65.der \
keys/server-key-mldsa87.der

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -253,6 +253,82 @@ int wolfSSH_MakeEd25519Key(byte* out, word32 outSz, word32 size)
#endif
}
int wolfSSH_MakeMlDsaKey(byte* out, word32 outSz, word32 level)
{
#if !defined(WOLFSSH_NO_MLDSA)
int ret = WS_SUCCESS;
WC_RNG rng = {0};
byte wc_level;
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_MakeMlDsaKey()");
if (level == WOLFSSH_MLDSAKEY_44) wc_level = WC_ML_DSA_44;
else if (level == WOLFSSH_MLDSAKEY_65) wc_level = WC_ML_DSA_65;
else if (level == WOLFSSH_MLDSAKEY_87) wc_level = WC_ML_DSA_87;
else {
WLOG(WS_LOG_DEBUG, "Invalid ML-DSA key level requested");
return WS_BAD_ARGUMENT;
}
if (wc_InitRng(&rng) != 0) {
WLOG(WS_LOG_DEBUG, "Couldn't create RNG");
ret = WS_CRYPTO_FAILED;
}
if (ret == WS_SUCCESS) {
MlDsaKey key;
int keyInit = 0;
if (wc_MlDsaKey_Init(&key, NULL, INVALID_DEVID) != 0)
ret = WS_CRYPTO_FAILED;
else {
keyInit = 1;
if (wc_MlDsaKey_SetParams(&key, wc_level) != 0)
ret = WS_CRYPTO_FAILED;
}
if (ret == WS_SUCCESS) {
ret = wc_MlDsaKey_MakeKey(&key, &rng);
if (ret != 0) {
WLOG(WS_LOG_DEBUG, "ML-DSA key generation failed");
ret = WS_CRYPTO_FAILED;
}
else
ret = WS_SUCCESS;
}
if (ret == WS_SUCCESS) {
int keySz;
keySz = wc_MlDsaKey_KeyToDer(&key, out, outSz);
if (keySz < 0) {
WLOG(WS_LOG_DEBUG, "ML-DSA key to DER failed");
ret = WS_CRYPTO_FAILED;
}
else
ret = keySz;
}
if (keyInit) {
wc_MlDsaKey_Free(&key);
}
if (wc_FreeRng(&rng) != 0) {
WLOG(WS_LOG_DEBUG, "Couldn't free RNG");
if (ret >= 0)
ret = WS_CRYPTO_FAILED;
}
}
WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_MakeMlDsaKey(), ret = %d", ret);
return ret;
#else
WOLFSSH_UNUSED(out);
WOLFSSH_UNUSED(outSz);
WOLFSSH_UNUSED(level);
return WS_NOT_COMPILED;
#endif
}
#else /* WOLFSSL_KEY_GEN */
#error "wolfSSH keygen requires that keygen is enabled in wolfSSL, use --enable-keygen or #define WOLFSSL_KEY_GEN."

100
src/ssh.c
View File

@ -1712,6 +1712,9 @@ char* wolfSSH_GetUsername(WOLFSSH* ssh)
#include <wolfssl/wolfcrypt/rsa.h>
#include <wolfssl/wolfcrypt/asn_public.h>
#include <wolfssl/wolfcrypt/coding.h>
#ifndef WOLFSSH_NO_MLDSA
#include <wolfssl/wolfcrypt/dilithium.h>
#endif
union wolfSSH_key {
#ifndef WOLFSSH_NO_RSA
@ -1833,7 +1836,72 @@ static int DoAsn1Key(const byte* in, word32 inSz, byte** out,
}
if (ret > 0 && !isPrivate) {
#ifndef WOLFSSH_NO_MLDSA
if (
#ifndef WOLFSSH_NO_MLDSA44
ret == ID_MLDSA44 ||
#endif
#ifndef WOLFSSH_NO_MLDSA65
ret == ID_MLDSA65 ||
#endif
#ifndef WOLFSSH_NO_MLDSA87
ret == ID_MLDSA87 ||
#endif
0) {
byte* rawPub = NULL;
word32 rawPubSz =
#ifndef WOLFSSH_NO_MLDSA87
WC_MLDSA_87_PUB_KEY_SIZE;
#elif !defined(WOLFSSH_NO_MLDSA65)
WC_MLDSA_65_PUB_KEY_SIZE;
#else
WC_MLDSA_44_PUB_KEY_SIZE;
#endif
const char* name = IdToName(ret);
word32 nameLen = (word32)WSTRLEN(name);
word32 localIdx = 0;
*outType = (const byte*)name;
*outTypeSz = nameLen;
rawPub = (byte*)WMALLOC(rawPubSz, heap, DYNTYPE_PUBKEY);
if (rawPub == NULL) {
ret = WS_MEMORY_E;
}
else {
int wcRet = wc_MlDsaKey_ExportPubRaw(&key->ks.mldsa.key,
rawPub, &rawPubSz);
if (wcRet != 0) {
ret = WS_CRYPTO_FAILED;
}
else {
*outSz = LENGTH_SZ + nameLen + LENGTH_SZ + rawPubSz;
newKey = (byte*)WMALLOC(*outSz, heap, DYNTYPE_PUBKEY);
if (newKey == NULL) {
ret = WS_MEMORY_E;
}
else {
c32toa(nameLen, &newKey[localIdx]);
localIdx += LENGTH_SZ;
WMEMCPY(&newKey[localIdx], name, nameLen);
localIdx += nameLen;
c32toa(rawPubSz, &newKey[localIdx]);
localIdx += LENGTH_SZ;
WMEMCPY(&newKey[localIdx], rawPub, rawPubSz);
*out = newKey;
ret = WS_SUCCESS;
}
}
WFREE(rawPub, heap, DYNTYPE_PUBKEY);
}
}
/* The else below intentionally straddles a preprocessor boundary:
* when WOLFSSH_NO_MLDSA is defined the entire if/else is removed and
* the RSA block becomes a standalone scope, which is harmless. */
else
#endif /* WOLFSSH_NO_MLDSA */
#ifndef WOLFSSH_NO_RSA
{
long e;
byte n[RSA_MAX_SIZE]; /* TODO: Handle small stack */
word32 nSz = (word32)sizeof(n), eSz = (word32)sizeof(e);
@ -1882,9 +1950,12 @@ static int DoAsn1Key(const byte* in, word32 inSz, byte** out,
*out = newKey;
}
}
#else
{
WLOG(WS_LOG_DEBUG, "DoAsn1Key failed; WOLFSSH_NO_RSA disabled RSA");
ret = WS_UNIMPLEMENTED_E;
}
#endif
}
else if (ret > 0 && isPrivate) {
@ -1892,23 +1963,22 @@ static int DoAsn1Key(const byte* in, word32 inSz, byte** out,
newKey = (byte*)WMALLOC(inSz, heap, DYNTYPE_PRIVKEY);
if (newKey == NULL) {
ret = WS_MEMORY_E;
return ret;
}
}
else if (*outSz < inSz) {
WLOG(WS_LOG_DEBUG, "DER private key output size too small");
ret = WS_BUFFER_E;
}
else {
if (*outSz < inSz) {
WLOG(WS_LOG_DEBUG, "DER private key output size too small");
ret = WS_BUFFER_E;
return ret;
}
newKey = *out;
}
*out = newKey;
*outSz = inSz;
WMEMCPY(newKey, in, inSz);
*outType = (const byte*)IdToName(ret);
*outTypeSz = (word32)WSTRLEN((const char*)*outType);
if (ret > 0) {
*out = newKey;
*outSz = inSz;
WMEMCPY(newKey, in, inSz);
*outType = (const byte*)IdToName(ret);
*outTypeSz = (word32)WSTRLEN((const char*)*outType);
}
}
wolfSSH_KEY_clean(key);
@ -2169,7 +2239,11 @@ int wolfSSH_ReadKey_file(const char* name,
|| WSTRNSTR((const char*)in,
"ecdsa-sha2-nistp", inSz) == (const char*)in
|| WSTRNSTR((const char*)in,
"ssh-ed25519", inSz) == (const char*)in) {
"ssh-ed25519", inSz) == (const char*)in
|| WSTRNSTR((const char*)in,
"ssh-mldsa-", inSz) == (const char*)in
|| WSTRNSTR((const char*)in,
"x509v3-ssh-mldsa-", inSz) == (const char*)in) {
*isPrivate = 0;
format = WOLFSSH_FORMAT_SSH;
in[inSz] = 0;

View File

@ -380,6 +380,81 @@ static int wolfSSH_KexTest_Ed25519HostKey(void)
}
#endif /* WOLFSSH_NO_ED25519 */
#ifndef WOLFSSH_NO_MLDSA
static int wolfSSH_KexTest_MlDsaHostKey(const char* keyName)
{
tcp_ready ready;
THREAD_TYPE serverThread;
func_args serverArgs;
func_args clientArgs;
char sA[NUMARGS][ARGLEN];
char *serverArgv[NUMARGS] =
{ sA[0], sA[1], sA[2], sA[3], sA[4], sA[5], sA[6], sA[7], sA[8],
sA[9], sA[10], sA[11] };
char cA[NUMARGS][ARGLEN];
char *clientArgv[NUMARGS] =
{ cA[0], cA[1], cA[2], cA[3], cA[4], cA[5], cA[6], cA[7], cA[8],
cA[9], cA[10], cA[11] };
int serverArgc = 0;
int clientArgc = 0;
InitTcpReady(&ready);
ADD_ARG(serverArgv, serverArgc, "echoserver");
ADD_ARG(serverArgv, serverArgc, "-1");
ADD_ARG(serverArgv, serverArgc, "-f");
#if !defined(USE_WINDOWS_API) && !defined(WOLFSSH_ZEPHYR)
ADD_ARG(serverArgv, serverArgc, "-p");
ADD_ARG(serverArgv, serverArgc, "-0");
#endif
ADD_ARG(serverArgv, serverArgc, "-k");
ADD_ARG(serverArgv, serverArgc, keyName);
serverArgs.argc = serverArgc;
serverArgs.argv = serverArgv;
serverArgs.return_code = EXIT_SUCCESS;
serverArgs.signal = &ready;
serverArgs.user_auth = NULL;
ThreadStart(echoserver_test, &serverArgs, &serverThread);
WaitTcpReady(&ready);
ADD_ARG(clientArgv, clientArgc, "client");
ADD_ARG(clientArgv, clientArgc, "-u");
ADD_ARG(clientArgv, clientArgc, "jill");
#if !defined(USE_WINDOWS_API) && !defined(WOLFSSH_ZEPHYR)
ADD_ARG(clientArgv, clientArgc, "-p");
ADD_ARG_INT(clientArgv, clientArgc, ready.port);
#endif
clientArgs.argc = clientArgc;
clientArgs.argv = clientArgv;
clientArgs.return_code = EXIT_SUCCESS;
clientArgs.signal = &ready;
clientArgs.user_auth = tsClientUserAuth;
client_test(&clientArgs);
#ifdef WOLFSSH_ZEPHYR
k_sleep(Z_TIMEOUT_TICKS(100));
#endif
ThreadJoin(serverThread);
if (clientArgs.return_code == WS_SOCKET_ERROR_E) {
clientArgs.return_code = WS_SUCCESS;
}
if (serverArgs.return_code == WS_SOCKET_ERROR_E) {
serverArgs.return_code = WS_SUCCESS;
}
AssertIntEQ(WS_SUCCESS, clientArgs.return_code);
AssertIntEQ(WS_SUCCESS, serverArgs.return_code);
FreeTcpReady(&ready);
return EXIT_SUCCESS;
}
#endif /* WOLFSSH_NO_MLDSA */
#endif /* KEXTEST_AVAILABLE */
int wolfSSH_KexTest(int argc, char** argv)
@ -431,6 +506,15 @@ int wolfSSH_KexTest(int argc, char** argv)
#ifndef WOLFSSH_NO_ED25519
AssertIntEQ(wolfSSH_KexTest_Ed25519HostKey(), EXIT_SUCCESS);
#endif
#ifndef WOLFSSH_NO_MLDSA44
AssertIntEQ(wolfSSH_KexTest_MlDsaHostKey("ssh-mldsa-44"), EXIT_SUCCESS);
#endif
#ifndef WOLFSSH_NO_MLDSA65
AssertIntEQ(wolfSSH_KexTest_MlDsaHostKey("ssh-mldsa-65"), EXIT_SUCCESS);
#endif
#ifndef WOLFSSH_NO_MLDSA87
AssertIntEQ(wolfSSH_KexTest_MlDsaHostKey("ssh-mldsa-87"), EXIT_SUCCESS);
#endif
AssertIntEQ(wolfSSH_Cleanup(), WS_SUCCESS);

File diff suppressed because it is too large Load Diff

View File

@ -137,8 +137,9 @@ enum WS_ErrorCodes {
WS_AUTH_PENDING = -1096, /* User authentication still pending */
WS_KDF_E = -1097, /* KDF error*/
WS_DISCONNECT = -1098, /* peer sent disconnect */
WS_MLDSA_E = -1099, /* MLDSA failure */
WS_LAST_E = WS_DISCONNECT /* Update this to indicate last error */
WS_LAST_E = WS_MLDSA_E /* Last error indicator */
};

View File

@ -43,6 +43,9 @@
#ifndef WOLFSSL_WOLFSSH
#error "wolfssh requires wolfSSL built with WOLFSSL_WOLFSSH"
#endif
#ifdef HAVE_DILITHIUM
#include <wolfssl/wolfcrypt/dilithium.h>
#endif
#ifdef WOLFSSH_SCP
#include <wolfssh/wolfscp.h>
#endif
@ -102,6 +105,17 @@ extern "C" {
#define WOLFSSH_NO_DH
#endif
#ifndef HAVE_DILITHIUM
#undef WOLFSSH_NO_MLDSA
#define WOLFSSH_NO_MLDSA
#undef WOLFSSH_NO_MLDSA44
#undef WOLFSSH_NO_MLDSA65
#undef WOLFSSH_NO_MLDSA87
#define WOLFSSH_NO_MLDSA44
#define WOLFSSH_NO_MLDSA65
#define WOLFSSH_NO_MLDSA87
#endif
#ifdef NO_SHA
#undef WOLFSSH_NO_SHA1
#define WOLFSSH_NO_SHA1
@ -138,7 +152,6 @@ extern "C" {
#error "You need at least one MAC algorithm."
#endif
#if defined(WOLFSSH_NO_DH) || defined(WOLFSSH_NO_SHA1)
#undef WOLFSSH_NO_DH_GROUP1_SHA1
#define WOLFSSH_NO_DH_GROUP1_SHA1
@ -159,6 +172,16 @@ extern "C" {
#undef WOLFSSH_NO_DH_GEX_SHA256
#define WOLFSSH_NO_DH_GEX_SHA256
#endif
#ifdef WOLFSSH_NO_MLDSA
#undef WOLFSSH_NO_MLDSA44
#undef WOLFSSH_NO_MLDSA65
#undef WOLFSSH_NO_MLDSA87
#define WOLFSSH_NO_MLDSA44
#define WOLFSSH_NO_MLDSA65
#define WOLFSSH_NO_MLDSA87
#endif
#if defined(WOLFSSH_NO_ECDH) \
|| defined(NO_SHA256) || defined(NO_ECC256)
#undef WOLFSSH_NO_ECDH_SHA2_NISTP256
@ -262,7 +285,10 @@ extern "C" {
defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) && \
defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) && \
defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521) && \
defined(WOLFSSH_NO_ED25519)
defined(WOLFSSH_NO_ED25519) && \
defined(WOLFSSH_NO_MLDSA44) && \
defined(WOLFSSH_NO_MLDSA65) && \
defined(WOLFSSH_NO_MLDSA87)
#error "You need at least one signing algorithm."
#endif
@ -373,10 +399,22 @@ enum {
ID_ECDSA_SHA2_NISTP384,
ID_ECDSA_SHA2_NISTP521,
ID_ED25519,
/* ML-DSA enum values shift with configs.
* Internal-only, never serialized. */
#ifndef WOLFSSH_NO_MLDSA
ID_MLDSA44,
ID_MLDSA65,
ID_MLDSA87,
#endif
ID_X509V3_SSH_RSA,
ID_X509V3_ECDSA_SHA2_NISTP256,
ID_X509V3_ECDSA_SHA2_NISTP384,
ID_X509V3_ECDSA_SHA2_NISTP521,
#ifndef WOLFSSH_NO_MLDSA
ID_X509V3_MLDSA44,
ID_X509V3_MLDSA65,
ID_X509V3_MLDSA87,
#endif
/* Service IDs */
ID_SERVICE_USERAUTH,
@ -1086,6 +1124,11 @@ typedef struct WS_KeySignature {
ed25519_key key;
} ed25519;
#endif
#ifndef WOLFSSH_NO_MLDSA
struct {
MlDsaKey key;
} mldsa;
#endif /* WOLFSSH_NO_MLDSA */
} ks;
} WS_KeySignature;
@ -1471,6 +1514,21 @@ enum WS_MessageIdLimits {
WOLFSSH_API int wolfSSH_TestDoUserAuthRequestEd25519(WOLFSSH* ssh,
WS_UserAuthData* authData);
#endif /* !WOLFSSH_NO_ED25519 */
#ifndef WOLFSSH_NO_MLDSA
WOLFSSH_API int wolfSSH_TestDoUserAuthRequestMlDsa(WOLFSSH* ssh,
WS_UserAuthData* authData, word32 pubKeyBlobSz);
WOLFSSH_API int wolfSSH_TestPrepareUserAuthRequestMlDsa(WOLFSSH* ssh,
word32* payloadSz, const WS_UserAuthData* authData,
WS_KeySignature* keySig);
#ifdef WOLFSSH_CERTS
WOLFSSH_API int wolfSSH_TestPrepareUserAuthRequestMlDsaCert(WOLFSSH* ssh,
word32* payloadSz, const WS_UserAuthData* authData,
WS_KeySignature* keySig);
#endif /* WOLFSSH_CERTS */
WOLFSSH_API int wolfSSH_TestBuildUserAuthRequestMlDsa(WOLFSSH* ssh,
byte* output, word32* idx, const WS_UserAuthData* authData,
const byte* sigStart, word32 sigStartIdx, WS_KeySignature* keySig);
#endif /* !WOLFSSH_NO_MLDSA */
#if defined(WOLFSSH_SCP) && !defined(WOLFSSH_SCP_USER_CALLBACKS)
WOLFSSH_API int wolfSSH_TestScpExtractFileName(const char* filePath,
char* fileName, word32 fileNameSz);

View File

@ -42,12 +42,16 @@ extern "C" {
#define WOLFSSH_ECDSAKEY_PRIME384 384
#define WOLFSSH_ECDSAKEY_PRIME521 521
#define WOLFSSH_ED25519KEY 256
#define WOLFSSH_MLDSAKEY_44 44
#define WOLFSSH_MLDSAKEY_65 65
#define WOLFSSH_MLDSAKEY_87 87
WOLFSSH_API int wolfSSH_MakeRsaKey(byte* out, word32 outSz,
word32 size, word32 e);
WOLFSSH_API int wolfSSH_MakeEcdsaKey(byte* out, word32 outSz, word32 size);
WOLFSSH_API int wolfSSH_MakeEd25519Key(byte* out, word32 outSz, word32 size);
WOLFSSH_API int wolfSSH_MakeMlDsaKey(byte* out, word32 outSz, word32 level);
#ifdef __cplusplus