mirror of https://github.com/wolfSSL/wolfssh.git
Add remaining ML-DSA composite signature algorithms
parent
866f7392cd
commit
244c82c86d
|
|
@ -161,13 +161,11 @@ struct WOLFSSHD_AUTH {
|
|||
#endif
|
||||
|
||||
#ifndef MAX_LINE_SZ
|
||||
/* sized for the largest authorized_keys entry, composite pubkeys
|
||||
* included */
|
||||
/* Max authorized_keys entry size. */
|
||||
#ifndef WOLFSSH_NO_MLDSA
|
||||
#ifndef WOLFSSH_NO_MLDSA87
|
||||
#if defined(WOLFSSH_CERTS)
|
||||
/* x509v3-ssh-mldsa-87: ML-DSA-87 pubkey + CA sig + DER
|
||||
* overhead, base64-encoded */
|
||||
/* Max size for ML-DSA-87 certs plus headroom. */
|
||||
#define MAX_LINE_SZ \
|
||||
((WC_MLDSA_87_PUB_KEY_SIZE + WC_MLDSA_87_SIG_SIZE + \
|
||||
COMPOSITE_MAX_TRAD_PUB_SZ + 1024 + 2) / 3 * 4 + 640)
|
||||
|
|
@ -202,6 +200,14 @@ struct WOLFSSHD_AUTH {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSHD_UNIT_TEST
|
||||
/* Expose MAX_LINE_SZ for tests. */
|
||||
word32 wolfsshd_test_MaxLineSz(void)
|
||||
{
|
||||
return (word32)MAX_LINE_SZ;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* this could potentially be useful in a deeply embedded future port */
|
||||
|
||||
|
|
@ -264,46 +270,13 @@ static int CheckAuthKeysLine(char* line, word32 lineSz, const byte* key,
|
|||
word32 keyCandSz = 0;
|
||||
char* last = NULL;
|
||||
|
||||
static const char* allowedTypes[] = {
|
||||
"ssh-rsa",
|
||||
"ssh-ed25519",
|
||||
"ecdsa-sha2-nistp256",
|
||||
"ecdsa-sha2-nistp384",
|
||||
"ecdsa-sha2-nistp521",
|
||||
#ifdef WOLFSSH_CERTS
|
||||
"x509v3-ssh-rsa",
|
||||
"x509v3-ecdsa-sha2-nistp256",
|
||||
"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
|
||||
#if !defined(WOLFSSH_NO_MLDSA44) && !defined(WOLFSSH_NO_ED25519)
|
||||
"ssh-mldsa44-ed25519@openssh.com",
|
||||
#endif
|
||||
};
|
||||
/* Valid key types come from the same TYPE_KEY name registry
|
||||
* (NameIdMap) that KEX negotiation uses, via wolfSSH_QueryKey(),
|
||||
* instead of a separately hand-maintained list that could drift
|
||||
* out of sync with it. */
|
||||
int typeOk = 0;
|
||||
int i;
|
||||
word32 queryIdx = 0;
|
||||
const char* algoName;
|
||||
|
||||
if (line == NULL || lineSz == 0 || key == NULL || keySz == 0) {
|
||||
ret = WS_BAD_ARGUMENT;
|
||||
|
|
@ -318,9 +291,13 @@ static int CheckAuthKeysLine(char* line, word32 lineSz, const byte* key,
|
|||
}
|
||||
}
|
||||
if (ret == WSSHD_AUTH_SUCCESS) {
|
||||
for (i = 0; i < (int)(sizeof(allowedTypes) / sizeof(allowedTypes[0]));
|
||||
++i) {
|
||||
if (allowedTypes[i] != NULL && WSTRCMP(type, allowedTypes[i]) == 0) {
|
||||
while ((algoName = wolfSSH_QueryKey(&queryIdx)) != NULL) {
|
||||
/* OpenSSH cert types are verified via the CA path, not by
|
||||
* literal comparison here; exclude them. */
|
||||
if (WSTRSTR(algoName, "-cert-v01@openssh.com") != NULL) {
|
||||
continue;
|
||||
}
|
||||
if (WSTRCMP(type, algoName) == 0) {
|
||||
typeOk = 1;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1372,17 +1349,7 @@ static int SearchKeysFile(const char* keysFilePath, const byte* key,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Detects OpenSSH vs ASN1/DER format of a raw host private key buffer.
|
||||
*
|
||||
* Uses wc_KeyPemToDer(), not wc_PemToDer(..., PRIVATEKEY_TYPE, ...): the
|
||||
* latter also unwraps PKCS#8 via ToTraditional(), which mangles key types
|
||||
* with no traditional DER form (e.g. ML-DSA).
|
||||
*
|
||||
* On a PEM buffer, *keyDer is a WMALLOC'd (heap, DYNTYPE_SSHD) buffer the
|
||||
* caller must WS_FORCEZERO + WFREE; NULL if data was passed through as-is
|
||||
* (raw DER or OpenSSH). privBuf/privBufSz are set to the buffer to actually
|
||||
* load. Returns WOLFSSH_FORMAT_ASN1/WOLFSSH_FORMAT_OPENSSH, or negative on
|
||||
* error. */
|
||||
/* Detects host private key format. */
|
||||
int wolfSSHD_DetectPrivKeyFormat(byte* data, word32 dataSz, void* heap,
|
||||
byte** keyDer, byte** privBuf, word32* privBufSz)
|
||||
{
|
||||
|
|
@ -1412,15 +1379,15 @@ int wolfSSHD_DetectPrivKeyFormat(byte* data, word32 dataSz, void* heap,
|
|||
|
||||
derSz = wc_KeyPemToDer(data, (int)dataSz, der, (int)dataSz, NULL);
|
||||
if (derSz <= 0) {
|
||||
WS_FORCEZERO(der, dataSz);
|
||||
WFREE(der, heap, DYNTYPE_SSHD);
|
||||
|
||||
*privBuf = data;
|
||||
*privBufSz = dataSz;
|
||||
|
||||
/* wstrnstr() stops at the first NUL, so binary buffers fall
|
||||
* through to the WMEMCMP magic check below. */
|
||||
if (WSTRNSTR((const char*)*privBuf,
|
||||
"-----BEGIN OPENSSH PRIVATE KEY-----", *privBufSz) != NULL) {
|
||||
/* Strict prefix match for OpenSSH magic (35 bytes) */
|
||||
if (*privBufSz >= 35 &&
|
||||
WMEMCMP(*privBuf, "-----BEGIN OPENSSH PRIVATE KEY-----", 35) == 0) {
|
||||
keyFormat = WOLFSSH_FORMAT_OPENSSH;
|
||||
}
|
||||
else if (*privBufSz >= sizeof("openssh-key-v1") &&
|
||||
|
|
@ -1429,17 +1396,34 @@ int wolfSSHD_DetectPrivKeyFormat(byte* data, word32 dataSz, void* heap,
|
|||
/* sizeof() includes the magic's trailing NUL */
|
||||
keyFormat = WOLFSSH_FORMAT_OPENSSH;
|
||||
}
|
||||
else if (data[0] != 0x30) {
|
||||
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failed to convert host private key from PEM.");
|
||||
*privBuf = NULL;
|
||||
*privBufSz = 0;
|
||||
return WS_BAD_FILE_E;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*keyDer = der;
|
||||
*privBuf = der;
|
||||
*privBufSz = (word32)derSz;
|
||||
/* PEM-decoded result may still be an OpenSSH binary blob */
|
||||
if (*privBufSz >= sizeof("openssh-key-v1") &&
|
||||
WMEMCMP(*privBuf, "openssh-key-v1",
|
||||
/* PEM-decoded result may still be an OpenSSH binary blob, or
|
||||
* (on a malformed/truncated PEM input) non-DER garbage; check
|
||||
* for both before accepting it as ASN.1, same as the derSz<=0
|
||||
* branch above does. */
|
||||
if ((word32)derSz >= sizeof("openssh-key-v1") &&
|
||||
WMEMCMP(der, "openssh-key-v1",
|
||||
sizeof("openssh-key-v1")) == 0) {
|
||||
keyFormat = WOLFSSH_FORMAT_OPENSSH;
|
||||
}
|
||||
else if (der[0] != 0x30) {
|
||||
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Decoded host private key is "
|
||||
"not valid ASN.1 or OpenSSH format.");
|
||||
WS_FORCEZERO(der, dataSz);
|
||||
WFREE(der, heap, DYNTYPE_SSHD);
|
||||
return WS_BAD_FILE_E;
|
||||
}
|
||||
|
||||
*keyDer = der;
|
||||
*privBuf = der;
|
||||
*privBufSz = (word32)derSz;
|
||||
}
|
||||
|
||||
return keyFormat;
|
||||
|
|
@ -2209,9 +2193,7 @@ static int CheckPublicKeyWIN(const char* usr,
|
|||
}
|
||||
#endif /* _WIN32*/
|
||||
|
||||
/* Returns 1 if 'usr' is root-equivalent for PermitRootLogin (any uid 0
|
||||
* account, or the literal name "root"; name-only on Windows). Shared by
|
||||
* DoCheckUser and RequestAuthentication so all enforcement points agree. */
|
||||
/* Check if user is root-equivalent. */
|
||||
static int IsRootUser(const char* usr)
|
||||
{
|
||||
int isRoot = 0;
|
||||
|
|
@ -2230,17 +2212,14 @@ static int IsRootUser(const char* usr)
|
|||
return isRoot;
|
||||
}
|
||||
|
||||
/* Returns 1 if root login is denied outright, i.e. PermitRootLogin no.
|
||||
* Used by DoCheckUser. */
|
||||
/* Check if root login denied. */
|
||||
WOLFSSHD_STATIC int IsRootLoginDenied(int isRoot, WOLFSSHD_CONFIG* usrConf)
|
||||
{
|
||||
return (isRoot == 1 &&
|
||||
wolfSSHD_ConfigGetPermitRoot(usrConf) == WOLFSSHD_PERMIT_ROOT_NO);
|
||||
}
|
||||
|
||||
/* Returns 1 if root password authentication is blocked, i.e.
|
||||
* PermitRootLogin prohibit-password or forced-commands-only. Used by
|
||||
* RequestAuthentication for WOLFSSH_USERAUTH_PASSWORD. */
|
||||
/* Check if root password auth blocked. */
|
||||
WOLFSSHD_STATIC int IsRootPasswordAuthBlocked(int isRoot,
|
||||
WOLFSSHD_CONFIG* usrConf)
|
||||
{
|
||||
|
|
@ -2251,9 +2230,7 @@ WOLFSSHD_STATIC int IsRootPasswordAuthBlocked(int isRoot,
|
|||
WOLFSSHD_PERMIT_ROOT_FORCED_CMD));
|
||||
}
|
||||
|
||||
/* Returns 1 if root public key login is missing the ForceCommand required by
|
||||
* PermitRootLogin forced-commands-only. Used by RequestAuthentication for
|
||||
* WOLFSSH_USERAUTH_PUBLICKEY. */
|
||||
/* Check if ForceCommand missing for root. */
|
||||
WOLFSSHD_STATIC int IsRootPubKeyForcedCmdMissing(int isRoot,
|
||||
WOLFSSHD_CONFIG* usrConf)
|
||||
{
|
||||
|
|
@ -2547,7 +2524,7 @@ static int RequestAuthentication(WS_UserAuthData* authData,
|
|||
ret = WOLFSSH_USERAUTH_REJECTED;
|
||||
}
|
||||
else if (IsRootPasswordAuthBlocked(isRoot, usrConf)) {
|
||||
/* prohibit-password and forced-commands-only both block this. */
|
||||
/* Blocked by config. */
|
||||
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Password authentication for "
|
||||
"root not allowed by configuration!");
|
||||
ret = WOLFSSH_USERAUTH_REJECTED;
|
||||
|
|
@ -2612,7 +2589,7 @@ static int RequestAuthentication(WS_UserAuthData* authData,
|
|||
if (ret == WOLFSSH_USERAUTH_SUCCESS &&
|
||||
authData->type == WOLFSSH_USERAUTH_PUBLICKEY &&
|
||||
IsRootPubKeyForcedCmdMissing(isRoot, usrConf)) {
|
||||
/* forced-commands-only requires a forced command for root pubkey. */
|
||||
/* Forced command required. */
|
||||
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Public key login for root requires "
|
||||
"a forced command by configuration!");
|
||||
ret = WOLFSSH_USERAUTH_REJECTED;
|
||||
|
|
@ -2942,11 +2919,7 @@ static int SetDefaultUserID(WOLFSSHD_AUTH* auth)
|
|||
|
||||
pwInfo = getpwnam(WOLFSSH_USER_STRING(WOLFSSH_SSHD_USER));
|
||||
#ifdef WOLFSSHD_UNIT_TEST
|
||||
/* Unit tests run wolfSSHD_AuthCreateUser() outside of a real daemon
|
||||
* install, where the dedicated "sshd" system account may not exist.
|
||||
* Fall back to the invoking user so auth-flow tests can exercise
|
||||
* wolfSSHD_AuthCreateUser() without requiring that account. Never
|
||||
* enabled in a production build. */
|
||||
/* Fallback for unit tests. */
|
||||
if (pwInfo == NULL) {
|
||||
pwInfo = getpwuid(getuid());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,9 @@ int wolfSSHD_GetHomeDirectory(WOLFSSHD_AUTH* auth, WOLFSSH* ssh, WCHAR* out, int
|
|||
int wolfSSHD_OpenSecureFile(const char* path, WUID_T ownerUid,
|
||||
int rejectReadable, void* heap, WFILE** out);
|
||||
|
||||
/* classifies a loaded host private key buffer as OpenSSH or ASN1/DER */
|
||||
/* classifies a loaded host private key buffer as OpenSSH or ASN1/DER.
|
||||
* *keyDer is a WMALLOC'd (heap, DYNTYPE_SSHD) buffer to WS_FORCEZERO +
|
||||
* WFREE on a PEM decode, else NULL. */
|
||||
int wolfSSHD_DetectPrivKeyFormat(byte* data, word32 dataSz, void* heap,
|
||||
byte** keyDer, byte** privBuf, word32* privBufSz);
|
||||
|
||||
|
|
@ -132,6 +134,7 @@ int SearchForPubKey(const char* path, const char* authKeysFile,
|
|||
const WS_UserAuthData_PublicKey* pubKeyCtx,
|
||||
WUID_T uid, int strictModes);
|
||||
#endif
|
||||
word32 wolfsshd_test_MaxLineSz(void);
|
||||
#if defined(WOLFSSH_HAVE_LIBCRYPT) || defined(WOLFSSH_HAVE_LIBLOGIN)
|
||||
int CheckPasswordHashUnix(const char* input, const char* stored);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,6 +16,20 @@ AuthorizedKeysFile $PWD/authorized_keys_test
|
|||
|
||||
EOF
|
||||
|
||||
cat <<EOF > sshd_config_test_mldsa
|
||||
Port 22222
|
||||
Protocol 2
|
||||
LoginGraceTime 600
|
||||
PermitRootLogin yes
|
||||
PasswordAuthentication yes
|
||||
PermitEmptyPasswords no
|
||||
UsePrivilegeSeparation no
|
||||
UseDNS no
|
||||
HostKey $PWD/../../../keys/server-key-mldsa87es384
|
||||
AuthorizedKeysFile $PWD/authorized_keys_test
|
||||
|
||||
EOF
|
||||
|
||||
cat <<EOF > sshd_config_test_x509
|
||||
Port 22222
|
||||
Protocol 2
|
||||
|
|
|
|||
|
|
@ -426,6 +426,27 @@ else
|
|||
stop_wolfsshd
|
||||
fi
|
||||
|
||||
# ML-DSA composite host key test. Runs when we control the local daemon.
|
||||
# The client side uses an ECC key since we only test the host key here.
|
||||
# sshd_config_test_mldsa has no other host key, so a build without ML-DSA
|
||||
# cannot start the daemon at all; check for support out here rather than
|
||||
# letting the test script skip, which would come too late. ML-DSA comes from
|
||||
# wolfSSL (HAVE_DILITHIUM) and has no wolfSSH configure option, so probe the
|
||||
# client's algorithm list. The closed port keeps the probe from connecting.
|
||||
if [ "$USING_LOCAL_HOST" == 1 ]; then
|
||||
if ../../../examples/client/client -E -u "$USER" -h 127.0.0.1 -p 1 \
|
||||
2>/dev/null | grep -q "ssh-mldsa87-es384@wolfssl.com"; then
|
||||
start_wolfsshd "sshd_config_test_mldsa"
|
||||
run_test "sshd_mldsa_composite_test.sh"
|
||||
printf "Shutting down test wolfSSHd\n"
|
||||
stop_wolfsshd
|
||||
else
|
||||
printf "sshd_mldsa_composite_test.sh ... SKIPPED\n"
|
||||
TOTAL=$((TOTAL+1))
|
||||
SKIPPED=$((SKIPPED+1))
|
||||
fi
|
||||
fi
|
||||
|
||||
# OpenSSH certificate user-auth test (self-contained: starts its own
|
||||
# wolfSSHd; skips when not built with --enable-ossh-certs). Runs the suite
|
||||
# against the wolfSSH example client and, for interop, the system OpenSSH
|
||||
|
|
|
|||
|
|
@ -59,8 +59,8 @@ printf "\n"
|
|||
# host key algorithms sent.
|
||||
find_substring_of_algos() {
|
||||
# Extract the substring between start and end lines
|
||||
SUBSTRING=$(printf "$OUTPUT" | grep -A20 "Server Host Key Algorithms")
|
||||
SUBSTRING=$(printf "$SUBSTRING" | grep -v -A15 "DKI: Enc Algorithms")
|
||||
SUBSTRING=$(printf "$OUTPUT" | grep -A100 "Server Host Key Algorithms")
|
||||
SUBSTRING=$(printf "$SUBSTRING" | grep -v -A95 "DKI: Enc Algorithms")
|
||||
}
|
||||
|
||||
# take input argument $1 and checks if it is in the SUBSTRING
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
#!/bin/sh
|
||||
|
||||
# ML-DSA composite host key test.
|
||||
#
|
||||
# The daemon under test is started with sshd_config_test_mldsa, whose only host
|
||||
# key is keys/server-key-mldsa87es384, an OpenSSH-format ML-DSA-87 + ECDSA-P384
|
||||
# composite key. Pinning the client's host key algorithm list is what makes this
|
||||
# an actual assertion about the negotiated algorithm: only the composite name
|
||||
# may succeed, and any other name must fail to find a common host key algorithm.
|
||||
#
|
||||
# ML-DSA support comes from wolfSSL (HAVE_DILITHIUM) and has no wolfSSH
|
||||
# configure option, so probe the client's algorithm list and skip (77) when the
|
||||
# composite is not built in.
|
||||
|
||||
PWD0=`pwd`
|
||||
cd ../../..
|
||||
|
||||
TEST_CLIENT="./examples/client/client"
|
||||
USER=`whoami`
|
||||
PRIVATE_KEY="./keys/hansel-key-ecc.der"
|
||||
PUBLIC_KEY="./keys/hansel-key-ecc.pub"
|
||||
ALGO="ssh-mldsa87-es384@wolfssl.com"
|
||||
OTHER_ALGO="ecdsa-sha2-nistp256"
|
||||
|
||||
if [ -z "$1" ] || [ -z "$2" ]; then
|
||||
echo "expecting host and port as arguments"
|
||||
echo "./sshd_mldsa_composite_test.sh 127.0.0.1 22222"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
skip() { echo "$1"; cd $PWD0; exit 77; }
|
||||
|
||||
[ -x "$TEST_CLIENT" ] || skip "wolfSSH example client not built, skipping"
|
||||
|
||||
# -E lists the compiled-in algorithms before connecting, so point it at a closed
|
||||
# port to keep the probe from opening a session.
|
||||
ALGOS=`$TEST_CLIENT -E -u $USER -h 127.0.0.1 -p 1 2>/dev/null`
|
||||
echo "$ALGOS" | grep -q "$ALGO" || skip "no $ALGO support in this build, skipping"
|
||||
|
||||
# Positive: with only the composite offered, a successful login means it is what
|
||||
# was negotiated.
|
||||
set -e
|
||||
echo "$TEST_CLIENT -k $ALGO -c 'ls' -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY -h \"$1\" -p \"$2\""
|
||||
$TEST_CLIENT -k "$ALGO" -c 'ls' -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY -h "$1" -p "$2"
|
||||
set +e
|
||||
|
||||
# Negative control: offering only ECDSA must fail, proving the pass above was
|
||||
# not some other host key the daemon happened to have loaded.
|
||||
if echo "$ALGOS" | grep -q "$OTHER_ALGO"; then
|
||||
echo "$TEST_CLIENT -k $OTHER_ALGO -c 'ls' -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY -h \"$1\" -p \"$2\""
|
||||
$TEST_CLIENT -k "$OTHER_ALGO" -c 'ls' -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY \
|
||||
-h "$1" -p "$2"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "expected $OTHER_ALGO to fail against the composite host key"
|
||||
cd $PWD0
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
cd $PWD0
|
||||
exit 0
|
||||
|
|
@ -2350,23 +2350,40 @@ static int BuildAuthKeysLine(const byte* key, word32 keySz,
|
|||
return BuildAuthKeysLineType("ssh-rsa", key, keySz, lineOut, lineOutSz);
|
||||
}
|
||||
|
||||
/* Confirms every key-type string in CheckAuthKeysLine's allowedTypes[] table
|
||||
* is recognized, guarding against allowedTypes[]/NUM_ALLOWED_TYPES drifting
|
||||
* out of sync as the ML-DSA/composite/cert #ifdef branches change. */
|
||||
/* Confirms every key-type CheckAuthKeysLine accepts via wolfSSH_QueryKey()
|
||||
* is recognized. */
|
||||
static int test_CheckAuthKeysLineTypes(void)
|
||||
{
|
||||
static const char* types[] = {
|
||||
#ifndef WOLFSSH_NO_RSA
|
||||
"ssh-rsa",
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_ED25519
|
||||
"ssh-ed25519",
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256
|
||||
"ecdsa-sha2-nistp256",
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384
|
||||
"ecdsa-sha2-nistp384",
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521
|
||||
"ecdsa-sha2-nistp521",
|
||||
#endif
|
||||
#ifdef WOLFSSH_CERTS
|
||||
#ifndef WOLFSSH_NO_SSH_RSA_SHA1
|
||||
"x509v3-ssh-rsa",
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256
|
||||
"x509v3-ecdsa-sha2-nistp256",
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384
|
||||
"x509v3-ecdsa-sha2-nistp384",
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521
|
||||
"x509v3-ecdsa-sha2-nistp521",
|
||||
#endif
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_MLDSA
|
||||
#ifndef WOLFSSH_NO_MLDSA44
|
||||
"ssh-mldsa-44",
|
||||
|
|
@ -2389,14 +2406,31 @@ static int test_CheckAuthKeysLineTypes(void)
|
|||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA44) && !defined(WOLFSSH_NO_ED25519)
|
||||
#if !defined(WOLFSSH_NO_MLDSA44) && !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256)
|
||||
"ssh-mldsa44-es256@wolfssl.com",
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA65) && \
|
||||
!defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) && !defined(NO_SHA512)
|
||||
"ssh-mldsa65-es256@wolfssl.com",
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA87) && \
|
||||
!defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) && !defined(NO_SHA512)
|
||||
"ssh-mldsa87-es384@wolfssl.com",
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA44) && !defined(WOLFSSH_NO_ED25519) && \
|
||||
!defined(NO_SHA512)
|
||||
"ssh-mldsa44-ed25519@openssh.com",
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA65) && !defined(WOLFSSH_NO_ED25519) && \
|
||||
!defined(NO_SHA512)
|
||||
"ssh-mldsa65-ed25519@wolfssl.com",
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA87) && defined(HAVE_ED448)
|
||||
"ssh-mldsa87-ed448@wolfssl.com",
|
||||
#endif
|
||||
};
|
||||
static const char keyAStr[] = "wolfssh-auth-key-test-A-AAAAAAA";
|
||||
static const char keyBStr[] = "wolfssh-auth-key-test-B-BBBBBBB";
|
||||
const byte* keyA = (const byte*)keyAStr;
|
||||
const byte* keyB = (const byte*)keyBStr;
|
||||
const word32 keySz = (word32)(sizeof(keyAStr) - 1);
|
||||
char line[256];
|
||||
char lineCopy[256];
|
||||
|
|
@ -2413,11 +2447,11 @@ static int test_CheckAuthKeysLineTypes(void)
|
|||
Log(" Testing scenario: known type %s reaches key comparison.",
|
||||
types[i]);
|
||||
WMEMCPY(lineCopy, line, WSTRLEN(line) + 1);
|
||||
/* Non-matching key: a recognized type must proceed to the key
|
||||
* comparison and report a plain auth failure, not a negative error. */
|
||||
/* Matching key: a recognized type must proceed to the key
|
||||
* comparison and report success. */
|
||||
rc = CheckAuthKeysLine(lineCopy, (word32)WSTRLEN(lineCopy),
|
||||
keyB, keySz);
|
||||
if (rc == WSSHD_AUTH_FAILURE) {
|
||||
keyA, keySz);
|
||||
if (rc == WSSHD_AUTH_SUCCESS) {
|
||||
Log(" PASSED.\n");
|
||||
}
|
||||
else {
|
||||
|
|
@ -2426,7 +2460,8 @@ static int test_CheckAuthKeysLineTypes(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* An unknown type must be rejected with a negative status. */
|
||||
/* An unknown type must be skipped (not matched) rather than aborting
|
||||
* the whole authorized_keys scan with a fatal error. */
|
||||
ret = BuildAuthKeysLineType("ssh-bogus-type", keyA, keySz, line,
|
||||
sizeof(line));
|
||||
if (ret != WS_SUCCESS) {
|
||||
|
|
@ -2435,7 +2470,7 @@ static int test_CheckAuthKeysLineTypes(void)
|
|||
Log(" Testing scenario: unknown type is rejected.");
|
||||
WMEMCPY(lineCopy, line, WSTRLEN(line) + 1);
|
||||
rc = CheckAuthKeysLine(lineCopy, (word32)WSTRLEN(lineCopy), keyA, keySz);
|
||||
if (rc < 0) {
|
||||
if (rc == WSSHD_AUTH_FAILURE) {
|
||||
Log(" PASSED.\n");
|
||||
}
|
||||
else {
|
||||
|
|
@ -2446,6 +2481,136 @@ static int test_CheckAuthKeysLineTypes(void)
|
|||
return WS_SUCCESS;
|
||||
}
|
||||
|
||||
#ifndef WOLFSSH_NO_MLDSA
|
||||
/* Builds a worst-case "<type> <base64(key)>" line, confirms it fits
|
||||
* within MAX_LINE_SZ, and round-trips it through CheckAuthKeysLine(). */
|
||||
static int CheckAuthKeysLineMaxSzCase(const char* type, word32 keySz,
|
||||
word32 maxLineSz)
|
||||
{
|
||||
int ret = WS_SUCCESS;
|
||||
int rc;
|
||||
word32 lineBufSz = maxLineSz + 1;
|
||||
byte* key = NULL;
|
||||
char* line = NULL;
|
||||
char* lineCopy = NULL;
|
||||
|
||||
/* keySz as passed in is just the raw ML-DSA/trad key material. The
|
||||
* real authorized_keys line base64-encodes the full SSH wire blob,
|
||||
* which also carries the string type-name and string key-data length
|
||||
* prefixes; account for that so the MAX_LINE_SZ fit check below is
|
||||
* not under-strict. */
|
||||
keySz += LENGTH_SZ * 2 + (word32)WSTRLEN(type);
|
||||
|
||||
key = (byte*)WMALLOC(keySz, NULL, DYNTYPE_BUFFER);
|
||||
line = (char*)WMALLOC(lineBufSz, NULL, DYNTYPE_BUFFER);
|
||||
lineCopy = (char*)WMALLOC(lineBufSz, NULL, DYNTYPE_BUFFER);
|
||||
if (key == NULL || line == NULL || lineCopy == NULL) {
|
||||
ret = WS_MEMORY_E;
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
word32 i;
|
||||
/* Non-repeating pattern so a truncation bug shows up as a
|
||||
* mismatch, not accidental luck. */
|
||||
for (i = 0; i < keySz; i++) {
|
||||
key[i] = (byte)(i * 31 + 7);
|
||||
}
|
||||
|
||||
ret = BuildAuthKeysLineType(type, key, keySz, line, lineBufSz);
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
word32 lineLen = (word32)WSTRLEN(line);
|
||||
|
||||
Log(" Testing scenario: max-size %s (%u byte key, %u byte line) "
|
||||
"fits within MAX_LINE_SZ (%u) and round-trips.",
|
||||
type, keySz, lineLen, maxLineSz);
|
||||
if (lineLen + 1 > maxLineSz) {
|
||||
Log(" FAILED (line len %u exceeds MAX_LINE_SZ %u).\n",
|
||||
lineLen + 1, maxLineSz);
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
else {
|
||||
WMEMCPY(lineCopy, line, lineLen + 1);
|
||||
rc = CheckAuthKeysLine(lineCopy, lineLen, key, keySz);
|
||||
if (rc == WSSHD_AUTH_SUCCESS) {
|
||||
Log(" PASSED.\n");
|
||||
}
|
||||
else {
|
||||
Log(" FAILED (rc=%d).\n", rc);
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (key != NULL) {
|
||||
WFREE(key, NULL, DYNTYPE_BUFFER);
|
||||
}
|
||||
if (line != NULL) {
|
||||
WFREE(line, NULL, DYNTYPE_BUFFER);
|
||||
}
|
||||
if (lineCopy != NULL) {
|
||||
WFREE(lineCopy, NULL, DYNTYPE_BUFFER);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* MAX_LINE_SZ is sized off the largest ML-DSA level, not the 32-byte
|
||||
* dummy keys test_CheckAuthKeysLineTypes() uses; build a full-size key
|
||||
* to actually catch a miscalculation there. */
|
||||
static int test_CheckAuthKeysLineMaxSz(void)
|
||||
{
|
||||
int ret;
|
||||
const char* type;
|
||||
word32 keySz;
|
||||
word32 maxLineSz = wolfsshd_test_MaxLineSz();
|
||||
|
||||
#if !defined(WOLFSSH_NO_MLDSA87)
|
||||
keySz = WC_MLDSA_87_PUB_KEY_SIZE + COMPOSITE_MAX_TRAD_PUB_SZ;
|
||||
#if !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) && !defined(NO_SHA512)
|
||||
type = "ssh-mldsa87-es384@wolfssl.com";
|
||||
#elif defined(HAVE_ED448)
|
||||
type = "ssh-mldsa87-ed448@wolfssl.com";
|
||||
#else
|
||||
type = "ssh-mldsa-87";
|
||||
keySz = WC_MLDSA_87_PUB_KEY_SIZE;
|
||||
#endif
|
||||
#elif !defined(WOLFSSH_NO_MLDSA65)
|
||||
keySz = WC_MLDSA_65_PUB_KEY_SIZE + COMPOSITE_MAX_TRAD_PUB_SZ;
|
||||
#if !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) && !defined(NO_SHA512)
|
||||
type = "ssh-mldsa65-es256@wolfssl.com";
|
||||
#elif !defined(WOLFSSH_NO_ED25519) && !defined(NO_SHA512)
|
||||
type = "ssh-mldsa65-ed25519@wolfssl.com";
|
||||
#else
|
||||
type = "ssh-mldsa-65";
|
||||
keySz = WC_MLDSA_65_PUB_KEY_SIZE;
|
||||
#endif
|
||||
#else
|
||||
keySz = WC_MLDSA_44_PUB_KEY_SIZE + COMPOSITE_MAX_TRAD_PUB_SZ;
|
||||
#if !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256)
|
||||
type = "ssh-mldsa44-es256@wolfssl.com";
|
||||
#elif !defined(WOLFSSH_NO_ED25519) && !defined(NO_SHA512)
|
||||
type = "ssh-mldsa44-ed25519@openssh.com";
|
||||
#else
|
||||
type = "ssh-mldsa-44";
|
||||
keySz = WC_MLDSA_44_PUB_KEY_SIZE;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ret = CheckAuthKeysLineMaxSzCase(type, keySz, maxLineSz);
|
||||
|
||||
/* The WOLFSSH_CERTS branch of MAX_LINE_SZ adds headroom for x509v3
|
||||
* composite-cert lines, but composite certs aren't supported by this
|
||||
* codebase (composite signatures only) and there's no real generated
|
||||
* cert to derive an assertion from, so that headroom goes untested
|
||||
* here rather than re-deriving MAX_LINE_SZ's own formula as fake
|
||||
* coverage. */
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* !WOLFSSH_NO_MLDSA */
|
||||
|
||||
/* Negative-path coverage for CheckAuthKeysLine so mutation of the
|
||||
* ConstantCompare clause (the only substantive bytewise check after the
|
||||
* length comparison) does not survive the test suite. */
|
||||
|
|
@ -3745,6 +3910,8 @@ static int test_AuthSetGroups_ok(void)
|
|||
conf = wolfSSHD_ConfigNew(NULL);
|
||||
if (conf == NULL)
|
||||
ret = WS_FATAL_ERROR;
|
||||
/* privilege separation defaults to on, so stub getpwnam rather than
|
||||
* depending on the host having an sshd user */
|
||||
if (ret == WS_SUCCESS) {
|
||||
InstallGetpwnamStub(&savedGetpwnam);
|
||||
auth = wolfSSHD_AuthCreateUser(NULL, conf);
|
||||
|
|
@ -3804,6 +3971,8 @@ static int test_AuthSetGroups_setgroups_fail(void)
|
|||
conf = wolfSSHD_ConfigNew(NULL);
|
||||
if (conf == NULL)
|
||||
ret = WS_FATAL_ERROR;
|
||||
/* privilege separation defaults to on, so stub getpwnam rather than
|
||||
* depending on the host having an sshd user */
|
||||
if (ret == WS_SUCCESS) {
|
||||
InstallGetpwnamStub(&savedGetpwnam);
|
||||
auth = wolfSSHD_AuthCreateUser(NULL, conf);
|
||||
|
|
@ -3846,6 +4015,8 @@ static int test_AuthSetGroups_getgrouplist_fail(void)
|
|||
conf = wolfSSHD_ConfigNew(NULL);
|
||||
if (conf == NULL)
|
||||
ret = WS_FATAL_ERROR;
|
||||
/* privilege separation defaults to on, so stub getpwnam rather than
|
||||
* depending on the host having an sshd user */
|
||||
if (ret == WS_SUCCESS) {
|
||||
InstallGetpwnamStub(&savedGetpwnam);
|
||||
auth = wolfSSHD_AuthCreateUser(NULL, conf);
|
||||
|
|
@ -5049,10 +5220,16 @@ static int test_OsshCertForcedCmd(void)
|
|||
const char* got;
|
||||
static const byte cmd1[] = { 'e','c','h','o',' ','h','i' };
|
||||
static const byte cmd2[] = { '/','b','i','n','/','t','r','u','e' };
|
||||
struct passwd* (*savedGetpwnam)(const char*);
|
||||
|
||||
/* privilege separation is on by default, so stub getpwnam rather than
|
||||
* depending on the host having an sshd user */
|
||||
InstallGetpwnamStub(&savedGetpwnam);
|
||||
|
||||
auth = wolfSSHD_AuthCreateUser(NULL, NULL);
|
||||
if (auth == NULL) {
|
||||
Log(" wolfSSHD_AuthCreateUser failed.\n");
|
||||
wsshd_getpwnam_cb = savedGetpwnam;
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
|
|
@ -5132,6 +5309,7 @@ static int test_OsshCertForcedCmd(void)
|
|||
}
|
||||
|
||||
wolfSSHD_AuthFreeUser(auth);
|
||||
wsshd_getpwnam_cb = savedGetpwnam;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -5293,7 +5471,14 @@ static int test_CheckPublicKeyUnixOrdering(void)
|
|||
/* With a peer IP supplied, the source-address restriction accepts an
|
||||
* in-range peer and denies an out-of-range one. */
|
||||
if (ret == WS_SUCCESS) {
|
||||
/* privilege separation is on by default, so stub getpwnam rather than
|
||||
* depending on the host having an sshd user. Restore it immediately:
|
||||
* the scenarios below resolve the real running account. */
|
||||
struct passwd* (*savedGetpwnam)(const char*);
|
||||
|
||||
InstallGetpwnamStub(&savedGetpwnam);
|
||||
auth = wolfSSHD_AuthCreateUser(NULL, NULL);
|
||||
wsshd_getpwnam_cb = savedGetpwnam;
|
||||
if (auth == NULL) {
|
||||
Log(" wolfSSHD_AuthCreateUser failed.\n");
|
||||
ret = WS_FATAL_ERROR;
|
||||
|
|
@ -5468,7 +5653,8 @@ static byte* ReadWholeFile(const char* path, word32* outSz)
|
|||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
buf = (byte*)malloc((size_t)sz);
|
||||
/* malloc(0) may return NULL, which this helper reports as a read failure */
|
||||
buf = (byte*)malloc((size_t)(sz > 0 ? sz : 1));
|
||||
if (buf != NULL) {
|
||||
if (fread(buf, 1, (size_t)sz, f) != (size_t)sz) {
|
||||
free(buf);
|
||||
|
|
@ -5483,16 +5669,37 @@ static byte* ReadWholeFile(const char* path, word32* outSz)
|
|||
}
|
||||
|
||||
/* locate the repo's keys/ directory regardless of whether this binary is run
|
||||
* from the repo root or from apps/wolfsshd/test/ */
|
||||
* from the repo root, from apps/wolfsshd/test/, or by "make check". Automake
|
||||
* runs TESTS from the build directory and exports srcdir, which is the only
|
||||
* way to find keys/ in a VPATH build. */
|
||||
static int BuildKeyPath(const char* name, char* out, size_t outSz)
|
||||
{
|
||||
static const char* candidates[] = { "keys/", "../../../keys/" };
|
||||
const char* srcDir;
|
||||
word32 i;
|
||||
int n;
|
||||
FILE* f;
|
||||
|
||||
srcDir = getenv("srcdir");
|
||||
if (srcDir != NULL) {
|
||||
n = WSNPRINTF(out, outSz, "%s/keys/%s", srcDir, name);
|
||||
/* srcdir is absolute in a VPATH build, so a truncated path is a real
|
||||
* possibility; a truncated name must not be opened */
|
||||
if (n > 0 && (size_t)n < outSz) {
|
||||
f = fopen(out, "rb");
|
||||
if (f != NULL) {
|
||||
fclose(f);
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < (word32)(sizeof(candidates) / sizeof(candidates[0]));
|
||||
i++) {
|
||||
snprintf(out, outSz, "%s%s", candidates[i], name);
|
||||
n = WSNPRINTF(out, outSz, "%s%s", candidates[i], name);
|
||||
if (n <= 0 || (size_t)n >= outSz) {
|
||||
continue;
|
||||
}
|
||||
f = fopen(out, "rb");
|
||||
if (f != NULL) {
|
||||
fclose(f);
|
||||
|
|
@ -5505,24 +5712,32 @@ static int BuildKeyPath(const char* name, char* out, size_t outSz)
|
|||
/* Regression coverage for wolfSSHD_DetectPrivKeyFormat(), the host-key
|
||||
* format auto-detection SetupCTX() relies on to load PEM-armored OpenSSH
|
||||
* keys, raw binary openssh-key-v1 blobs (including composite ML-DSA host
|
||||
* keys, which are only ever stored in that raw form), and traditional
|
||||
* PEM/DER keys. */
|
||||
* keys, which are only ever stored in that raw form), PKCS#8 PEM keys
|
||||
* (e.g. ML-DSA), and traditional PEM/DER keys. */
|
||||
static int test_DetectPrivKeyFormat(void)
|
||||
{
|
||||
typedef struct {
|
||||
const char* desc;
|
||||
const char* file;
|
||||
int wantFormat;
|
||||
/* Expected wc_KeyPemToDer() outcome (1 = succeeds, keyDer non-NULL;
|
||||
* 0 = fails, keyDer NULL); pins down which branch each case hits. */
|
||||
int wantKeyDerNonNull;
|
||||
} DPK_CASE;
|
||||
static const DPK_CASE cases[] = {
|
||||
{ "PEM-armored OpenSSH key", "id_ecdsa", WOLFSSH_FORMAT_OPENSSH },
|
||||
{ "PEM-armored OpenSSH key", "id_ecdsa", WOLFSSH_FORMAT_OPENSSH, 0 },
|
||||
{ "raw binary openssh-key-v1 composite ML-DSA key",
|
||||
"server-key-mldsa44ed25519", WOLFSSH_FORMAT_OPENSSH },
|
||||
"server-key-mldsa44ed25519", WOLFSSH_FORMAT_OPENSSH, 0 },
|
||||
{ "PEM traditional key decodes to DER/ASN1", "server-key-ecc.pem",
|
||||
WOLFSSH_FORMAT_ASN1 },
|
||||
WOLFSSH_FORMAT_ASN1, 1 },
|
||||
{ "un-armored raw DER key falls through to ASN1",
|
||||
"server-key-mldsa44.der", WOLFSSH_FORMAT_ASN1, 0 },
|
||||
{ "PKCS#8 PEM ML-DSA key decodes to DER/ASN1 without PKCS8 "
|
||||
"stripping", "server-key-mldsa44.pem", WOLFSSH_FORMAT_ASN1, 1 },
|
||||
};
|
||||
word32 i;
|
||||
int ret = WS_SUCCESS;
|
||||
int ranCases = 0;
|
||||
byte dummy = 0;
|
||||
byte* badKeyDer = NULL;
|
||||
byte* badPrivBuf = NULL;
|
||||
|
|
@ -5531,14 +5746,19 @@ static int test_DetectPrivKeyFormat(void)
|
|||
|
||||
/* A 0-byte host key file (or otherwise bad arguments) must be rejected
|
||||
* without touching the out-params, matching the empty-file case
|
||||
* getBufferFromFile() can hand back. */
|
||||
* getBufferFromFile() can hand back. Poison out-params with sentinels
|
||||
* first, so the NULL/0 checks below catch a skipped reset instead of
|
||||
* matching by coincidence. */
|
||||
badKeyDer = (byte*)&dummy;
|
||||
badPrivBuf = (byte*)&dummy;
|
||||
badPrivBufSz = 0xDEADBEEF;
|
||||
badGot = wolfSSHD_DetectPrivKeyFormat(&dummy, 0, NULL, &badKeyDer,
|
||||
&badPrivBuf, &badPrivBufSz);
|
||||
Log(" Testing scenario: 0-length buffer. %s\n",
|
||||
(badGot == WS_BAD_ARGUMENT && badPrivBuf == NULL && badPrivBufSz == 0)
|
||||
? "PASSED" : "FAILED");
|
||||
if (badGot != WS_BAD_ARGUMENT || badPrivBuf != NULL ||
|
||||
badPrivBufSz != 0) {
|
||||
(badGot == WS_BAD_ARGUMENT && badKeyDer == NULL &&
|
||||
badPrivBuf == NULL && badPrivBufSz == 0) ? "PASSED" : "FAILED");
|
||||
if (badGot != WS_BAD_ARGUMENT || badKeyDer != NULL ||
|
||||
badPrivBuf != NULL || badPrivBufSz != 0) {
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
|
|
@ -5550,8 +5770,33 @@ static int test_DetectPrivKeyFormat(void)
|
|||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
badGot = wolfSSHD_DetectPrivKeyFormat(&dummy, sizeof(dummy), NULL, NULL,
|
||||
&badPrivBuf, &badPrivBufSz);
|
||||
Log(" Testing scenario: NULL keyDer pointer. %s\n",
|
||||
(badGot == WS_BAD_ARGUMENT) ? "PASSED" : "FAILED");
|
||||
if (badGot != WS_BAD_ARGUMENT) {
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
badGot = wolfSSHD_DetectPrivKeyFormat(&dummy, sizeof(dummy), NULL,
|
||||
&badKeyDer, NULL, &badPrivBufSz);
|
||||
Log(" Testing scenario: NULL privBuf pointer. %s\n",
|
||||
(badGot == WS_BAD_ARGUMENT) ? "PASSED" : "FAILED");
|
||||
if (badGot != WS_BAD_ARGUMENT) {
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
badGot = wolfSSHD_DetectPrivKeyFormat(&dummy, sizeof(dummy), NULL,
|
||||
&badKeyDer, &badPrivBuf, NULL);
|
||||
Log(" Testing scenario: NULL privBufSz pointer. %s\n",
|
||||
(badGot == WS_BAD_ARGUMENT) ? "PASSED" : "FAILED");
|
||||
if (badGot != WS_BAD_ARGUMENT) {
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < (word32)(sizeof(cases) / sizeof(cases[0])); i++) {
|
||||
char path[128];
|
||||
/* srcdir is an absolute path under "make check", so leave room */
|
||||
char path[512];
|
||||
byte* data;
|
||||
word32 dataSz = 0;
|
||||
byte* keyDer = NULL;
|
||||
|
|
@ -5559,11 +5804,14 @@ static int test_DetectPrivKeyFormat(void)
|
|||
word32 privBufSz = 0;
|
||||
int gotFormat;
|
||||
|
||||
/* not being able to find keys/ says nothing about the code under
|
||||
* test, so skip rather than fail the run */
|
||||
if (BuildKeyPath(cases[i].file, path, sizeof(path)) != WS_SUCCESS) {
|
||||
Log(" Testing scenario: %s. FAILED (couldn't locate %s)\n",
|
||||
Log(" Testing scenario: %s. SKIPPED (couldn't locate %s)\n",
|
||||
cases[i].desc, cases[i].file);
|
||||
return WS_FATAL_ERROR;
|
||||
continue;
|
||||
}
|
||||
ranCases++;
|
||||
|
||||
data = ReadWholeFile(path, &dataSz);
|
||||
if (data == NULL) {
|
||||
|
|
@ -5581,6 +5829,28 @@ static int test_DetectPrivKeyFormat(void)
|
|||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
Log(" Testing scenario: %s wc_KeyPemToDer branch. %s\n",
|
||||
cases[i].desc,
|
||||
((keyDer != NULL) == (cases[i].wantKeyDerNonNull != 0)) ?
|
||||
"PASSED" : "FAILED");
|
||||
if ((keyDer != NULL) != (cases[i].wantKeyDerNonNull != 0)) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
if (gotFormat >= 0) {
|
||||
int privOk = 0;
|
||||
if (keyDer != NULL && privBuf == keyDer && privBufSz > 0) {
|
||||
privOk = 1;
|
||||
} else if (keyDer == NULL && privBuf == data && privBufSz == dataSz) {
|
||||
privOk = 1;
|
||||
}
|
||||
Log(" Testing scenario: %s privBuf correctness. %s\n",
|
||||
cases[i].desc, privOk ? "PASSED" : "FAILED");
|
||||
if (!privOk) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyDer != NULL) {
|
||||
WFREE(keyDer, NULL, DYNTYPE_SSHD);
|
||||
}
|
||||
|
|
@ -5590,6 +5860,76 @@ static int test_DetectPrivKeyFormat(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* Synthetic case: wc_KeyPemToDer() succeeds but the decoded body starts
|
||||
* with the openssh-key-v1 magic -- forces the "PEM-decoded result may
|
||||
* still be OpenSSH binary" path no file-based case above reaches. */
|
||||
{
|
||||
/* base64 of "openssh-key-v1\0PADPADPADPADPAD" */
|
||||
static const char pemOpenSshBody[] =
|
||||
"-----BEGIN PRIVATE KEY-----\n"
|
||||
"b3BlbnNzaC1rZXktdjEAUEFEUEFEUEFEUEFEUEFE\n"
|
||||
"-----END PRIVATE KEY-----\n";
|
||||
byte* keyDer = NULL;
|
||||
byte* privBuf = NULL;
|
||||
word32 privBufSz = 0;
|
||||
int gotFormat;
|
||||
|
||||
gotFormat = wolfSSHD_DetectPrivKeyFormat(
|
||||
(byte*)pemOpenSshBody, (word32)(sizeof(pemOpenSshBody) - 1),
|
||||
NULL, &keyDer, &privBuf, &privBufSz);
|
||||
|
||||
Log(" Testing scenario: PEM decodes to an OpenSSH blob. %s\n",
|
||||
(gotFormat == WOLFSSH_FORMAT_OPENSSH && keyDer != NULL) ?
|
||||
"PASSED" : "FAILED");
|
||||
if (gotFormat != WOLFSSH_FORMAT_OPENSSH || keyDer == NULL) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
if (keyDer != NULL) {
|
||||
WFREE(keyDer, NULL, DYNTYPE_SSHD);
|
||||
}
|
||||
if (ret != WS_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (ranCases == 0) {
|
||||
Log(" test_DetectPrivKeyFormat FAILED: No file-based cases ran. "
|
||||
"(Are we in the right directory?)\n");
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
/* Synthetic case: Corrupt/unsupported PEM buffer that fails wc_KeyPemToDer
|
||||
* and does not start with OpenSSH magic, nor raw DER (0x30). */
|
||||
{
|
||||
static const char corruptPem[] =
|
||||
"-----BEGIN RSA PRIVATE KEY-----\n"
|
||||
"not valid base64 !!!\n"
|
||||
"-----END RSA PRIVATE KEY-----\n";
|
||||
byte* keyDer = NULL;
|
||||
byte* privBuf = NULL;
|
||||
word32 privBufSz = 0;
|
||||
int gotFormat;
|
||||
|
||||
gotFormat = wolfSSHD_DetectPrivKeyFormat(
|
||||
(byte*)corruptPem, (word32)(sizeof(corruptPem) - 1),
|
||||
NULL, &keyDer, &privBuf, &privBufSz);
|
||||
|
||||
Log(" Testing scenario: Corrupt/unsupported PEM buffer. %s\n",
|
||||
(gotFormat == WS_BAD_FILE_E && keyDer == NULL) ?
|
||||
"PASSED" : "FAILED");
|
||||
if (gotFormat != WS_BAD_FILE_E || keyDer != NULL) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
if (keyDer != NULL) {
|
||||
WFREE(keyDer, NULL, DYNTYPE_SSHD);
|
||||
}
|
||||
if (ret != WS_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -5625,6 +5965,9 @@ const TEST_CASE testCases[] = {
|
|||
#ifdef WOLFSSL_BASE64_ENCODE
|
||||
TEST_DECL(test_CheckAuthKeysLine),
|
||||
TEST_DECL(test_CheckAuthKeysLineTypes),
|
||||
#ifndef WOLFSSH_NO_MLDSA
|
||||
TEST_DECL(test_CheckAuthKeysLineMaxSz),
|
||||
#endif
|
||||
#endif
|
||||
#if defined(WOLFSSL_BASE64_ENCODE) && !defined(_WIN32)
|
||||
TEST_DECL(test_SearchForPubKey),
|
||||
|
|
|
|||
|
|
@ -416,13 +416,9 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx,
|
|||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
/* Host keys may be OpenSSH, PEM, or DER.
|
||||
* wolfSSHD_DetectPrivKeyFormat() uses wc_KeyPemToDer() (not
|
||||
* wc_PemToDer(..., PRIVATEKEY_TYPE, ...), which unwraps
|
||||
* PKCS#8 via ToTraditional() and mangles key types with no
|
||||
* traditional DER form, e.g. ML-DSA) and also detects the
|
||||
* OpenSSH private-key format, used by composite ML-DSA host
|
||||
* keys generated in that format. */
|
||||
/* Host keys may be OpenSSH, PEM, or DER; detect the format
|
||||
* and decode PEM/DER via wc_KeyPemToDer(), which handles
|
||||
* PKCS#8 keys with no traditional DER form (e.g. ML-DSA). */
|
||||
if (dataSz == 0) {
|
||||
/* An empty (0-byte) file passes the NULL check above but
|
||||
* carries no key material. Handle it explicitly as a file
|
||||
|
|
@ -436,7 +432,12 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx,
|
|||
int keyFormat = wolfSSHD_DetectPrivKeyFormat(data, dataSz,
|
||||
heap, &keyDer, &privBuf, &privBufSz);
|
||||
|
||||
if (keyFormat < 0) {
|
||||
if (keyFormat == WS_MEMORY_E) {
|
||||
wolfSSH_Log(WS_LOG_ERROR,
|
||||
"[SSHD] Out of memory reading host private key.");
|
||||
ret = WS_MEMORY_E;
|
||||
}
|
||||
else if (keyFormat < 0) {
|
||||
wolfSSH_Log(WS_LOG_ERROR,
|
||||
"[SSHD] Host private key file is invalid.");
|
||||
ret = WS_BAD_FILE_E;
|
||||
|
|
@ -453,8 +454,18 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx,
|
|||
if (ret == WS_SUCCESS &&
|
||||
wolfSSH_CTX_UsePrivateKey_buffer(*ctx, privBuf,
|
||||
privBufSz, keyFormat) < 0) {
|
||||
wolfSSH_Log(WS_LOG_ERROR,
|
||||
"[SSHD] Failed to use host private key.");
|
||||
if (keyFormat == WOLFSSH_FORMAT_OPENSSH) {
|
||||
/* Only composite ML-DSA keys support this format. */
|
||||
wolfSSH_Log(WS_LOG_ERROR,
|
||||
"[SSHD] Failed to use host private key: "
|
||||
"OpenSSH format is only supported for "
|
||||
"composite ML-DSA keys; convert with "
|
||||
"\"ssh-keygen -p -m PEM\".");
|
||||
}
|
||||
else {
|
||||
wolfSSH_Log(WS_LOG_ERROR,
|
||||
"[SSHD] Failed to use host private key.");
|
||||
}
|
||||
ret = WS_BAD_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
|
@ -463,9 +474,8 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx,
|
|||
WS_FORCEZERO(keyDer, dataSz);
|
||||
WFREE(keyDer, heap, DYNTYPE_SSHD);
|
||||
}
|
||||
/* data held the raw private key — the DER bytes, or the PEM
|
||||
* text decoded into keyDer above. Zeroize before freeing so key
|
||||
* material does not linger in the heap after use. */
|
||||
/* data is the key material itself for raw DER/OpenSSH
|
||||
* input (privBuf aliases it directly, no copy). */
|
||||
WS_FORCEZERO(data, dataSz);
|
||||
freeBufferFromFile(data, heap);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1861,66 +1861,88 @@ static int load_key_mldsa87(byte* buf, word32 bufSz)
|
|||
}
|
||||
#endif /* WOLFSSH_NO_MLDSA87 */
|
||||
|
||||
#if !defined(WOLFSSH_NO_MLDSA44) && !defined(WOLFSSH_NO_ED25519)
|
||||
/* buf NULL: *bufSz set to file size; else file read into buf (bufSz max) */
|
||||
static int load_key_mldsa44_ed25519(byte* buf, word32* bufSz)
|
||||
{
|
||||
word32 sz = 0;
|
||||
#ifndef NO_FILESYSTEM
|
||||
sz = load_file("./keys/server-key-mldsa44ed25519", buf, bufSz);
|
||||
#else
|
||||
(void)buf; (void)bufSz;
|
||||
#endif
|
||||
return sz;
|
||||
}
|
||||
#endif /* !WOLFSSH_NO_MLDSA44 && !WOLFSSH_NO_ED25519 */
|
||||
|
||||
#ifndef WOLFSSH_NO_MLDSA
|
||||
/* composite key buffer must be sized from the file, not a fixed constant */
|
||||
static int LoadMlDsaCompositeHostKey(WOLFSSH_CTX* ctx,
|
||||
int (*loadFn)(byte*, word32*), const char* label)
|
||||
const char* fileName, const char* label)
|
||||
{
|
||||
#ifndef NO_FILESYSTEM
|
||||
byte* compBuf = NULL;
|
||||
word32 compBufSz = 0;
|
||||
word32 allocSz;
|
||||
word32 compSz;
|
||||
|
||||
loadFn(NULL, &compBufSz);
|
||||
load_file(fileName, NULL, &compBufSz);
|
||||
if (compBufSz == 0) {
|
||||
fprintf(stderr, "Couldn't find size of %s key file.\n", label);
|
||||
return -1;
|
||||
}
|
||||
compBuf = (byte*)WMALLOC(compBufSz, NULL, 0);
|
||||
allocSz = compBufSz;
|
||||
compBuf = (byte*)WMALLOC(allocSz, NULL, 0);
|
||||
if (compBuf == NULL) {
|
||||
fprintf(stderr, "Couldn't allocate %s key buffer.\n", label);
|
||||
return -1;
|
||||
}
|
||||
compSz = loadFn(compBuf, &compBufSz);
|
||||
compSz = load_file(fileName, compBuf, &compBufSz);
|
||||
if (compSz == 0) {
|
||||
wc_ForceZero(compBuf, allocSz);
|
||||
WFREE(compBuf, NULL, 0);
|
||||
fprintf(stderr, "Couldn't load %s key file.\n", label);
|
||||
return -1;
|
||||
}
|
||||
if (wolfSSH_CTX_UsePrivateKey_buffer(ctx, compBuf, compSz,
|
||||
WOLFSSH_FORMAT_OPENSSH) < 0) {
|
||||
wc_ForceZero(compBuf, allocSz);
|
||||
WFREE(compBuf, NULL, 0);
|
||||
fprintf(stderr, "Couldn't use %s key buffer.\n", label);
|
||||
return -1;
|
||||
}
|
||||
wc_ForceZero(compBuf, allocSz);
|
||||
WFREE(compBuf, NULL, 0);
|
||||
return 0;
|
||||
#else
|
||||
(void)ctx; (void)fileName;
|
||||
fprintf(stderr, "Couldn't load %s key: no filesystem.\n", label);
|
||||
return -1;
|
||||
#endif /* NO_FILESYSTEM */
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char* substr;
|
||||
int (*loadFn)(byte*, word32*);
|
||||
const char* fileName;
|
||||
const char* label;
|
||||
} MlDsaCompositeEntry;
|
||||
|
||||
/* NULL-terminated so the table is never empty if ECDSA and Ed25519/Ed448
|
||||
* are both disabled */
|
||||
static const MlDsaCompositeEntry mldsaCompositeEntries[] = {
|
||||
#if !defined(WOLFSSH_NO_MLDSA44) && !defined(WOLFSSH_NO_ED25519)
|
||||
{ "mldsa44-ed25519", load_key_mldsa44_ed25519, "ML-DSA-44+Ed25519" },
|
||||
#if !defined(WOLFSSH_NO_MLDSA44) && !defined(WOLFSSH_NO_ED25519) && \
|
||||
!defined(NO_SHA512)
|
||||
{ "mldsa44-ed25519", "./keys/server-key-mldsa44ed25519",
|
||||
"ML-DSA-44+Ed25519" },
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA44) && !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256)
|
||||
{ "mldsa44-es256", "./keys/server-key-mldsa44es256",
|
||||
"ML-DSA-44+ES256" },
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA65) && !defined(WOLFSSH_NO_ED25519) && \
|
||||
!defined(NO_SHA512)
|
||||
{ "mldsa65-ed25519", "./keys/server-key-mldsa65ed25519",
|
||||
"ML-DSA-65+Ed25519" },
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA65) && \
|
||||
!defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) && !defined(NO_SHA512)
|
||||
{ "mldsa65-es256", "./keys/server-key-mldsa65es256",
|
||||
"ML-DSA-65+ES256" },
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA87) && defined(HAVE_ED448)
|
||||
{ "mldsa87-ed448", "./keys/server-key-mldsa87ed448",
|
||||
"ML-DSA-87+Ed448" },
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA87) && \
|
||||
!defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) && !defined(NO_SHA512)
|
||||
{ "mldsa87-es384", "./keys/server-key-mldsa87es384",
|
||||
"ML-DSA-87+ES384" },
|
||||
#endif
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
|
@ -3508,7 +3530,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
|
|||
|
||||
if (WSTRSTR(keyList, entry->substr) != NULL) {
|
||||
mldsaMatched = 1;
|
||||
if (LoadMlDsaCompositeHostKey(ctx, entry->loadFn,
|
||||
if (LoadMlDsaCompositeHostKey(ctx, entry->fileName,
|
||||
entry->label) != 0) {
|
||||
#ifdef WOLFSSH_SMALL_STACK
|
||||
wc_ForceZero(keyLoadBuf, EXAMPLE_KEYLOAD_BUFFER_SZ);
|
||||
|
|
|
|||
|
|
@ -26,8 +26,12 @@ EXTRA_DIST+= \
|
|||
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-mldsa44.der keys/server-key-mldsa65.der \
|
||||
keys/server-key-mldsa44.der keys/server-key-mldsa44.pem \
|
||||
keys/server-key-mldsa65.der \
|
||||
keys/server-key-mldsa87.der keys/server-key-mldsa44ed25519 \
|
||||
keys/server-key-mldsa44es256 keys/server-key-mldsa65ed25519 \
|
||||
keys/server-key-mldsa65es256 keys/server-key-mldsa87ed448 \
|
||||
keys/server-key-mldsa87es384 \
|
||||
keys/renew-ossh-certs.sh \
|
||||
keys/ossh-ca keys/ossh-ca.pub \
|
||||
keys/ossh-ca-rsa keys/ossh-ca-rsa.pub \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
oexp1D0GP2IqStVF82Fvng==
|
||||
-----END PRIVATE KEY-----
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAFhgAAAB1z
|
||||
c2gtbWxkc2E0NC1lczI1NkB3b2xmc3NsLmNvbQAABWEkOjKuVYKNHxvgtY0n6XfC
|
||||
l1E3c9mT5dEySN/+lCuota22IzFfvP/R3sivUMueGK4OCOQaHghjqdeI7mii/R4N
|
||||
z+V/xF9lB4THcYGKjOI8GDfPTrMJxPCemxM8Cywwz45NsPvVRydvgDMN3JC2Ulg6
|
||||
V7ZFJi55zz5o+JutRmd/UCMiMfAj3/VAOi2jb2m68HX4PYX737pCYiR88xNaET+0
|
||||
BCZwmUSOAqAMdHqlcVQI4s6CxBKsZSBw1YagkAe9aBaeyCG1DraooRky1erWXoaA
|
||||
JuPASo+99A3SruH1jND6L0Vwn0iFHE5UynnmueRDPJPOpiB5jwdJ8d/SIb8F5oVq
|
||||
trxzdoc+FDSKl9f+b1mclsXDR76fk9zzmYLSipgfFzPFaLizRTkqwzeVDdWaMqvE
|
||||
Y/nuofqmPq4VaN998DGblma45G4PGRqlfxDFTiHplhmoxnrM+1BvpNYvAZJtV86n
|
||||
MIQpU8pHQPZ5rZv2ZrepYHTO2UMrliXh7MAGPF4AO7pKJpQkF7mtbMHk7ABimXjR
|
||||
ewR2QKsxCQC6yAuCrJKAUcRKNrdQaBAoavWizOejD8ZCU6HWHi/MqGzONJ0Gim+Q
|
||||
Tn54L9sbd0riJv/meiv3icZqAxNY9uYqu6H7A26bn6yIrD9YIfqc3XRmgXOJLCG0
|
||||
rgvfQDpXa9c3gwtgdQH0IRuR0vr3IgT2U670L9KNPqn0orLriYrW2EKynENt8iX0
|
||||
JMGVZqZiAivRO/a9DhqTSlRczQaCAfkjzK6isPet8sWqhwxwwrKQmng8ZHuagVBQ
|
||||
MceP0EgG7XybsOY/IFaTUmLPSOjZWxuiLHRU8f6f1ukpTdDKebK6jGT8pBp8e+Ju
|
||||
/ycBaCqg8cDBxvi62vy+sYXMK6ZsJ5jhPzGWdwKiykYyRVB7DhRha4Dx0SRhhBdD
|
||||
fJP5BxHLCWc28qfVsU4pI9siASikIxGgyYfKcLyyiOeCiLMfSTLkJi1Trjon77He
|
||||
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
|
||||
/ZN4ubBSC/mmP7mtRcAP4gpwu7JN7V0AAAAAAQI=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
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
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
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
|
||||
3VFth3LT3AAAAAABAg==
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAKfgAAAB1z
|
||||
c2gtbWxkc2E4Ny1lZDQ0OEB3b2xmc3NsLmNvbQAAClmQ3OdvQBVt2Vagc+bKz/RQ
|
||||
LS+KCXQ27n5GN16jHDd/vY9jJFMmQDEqQQiz4Pe+EPWgv7Dtx8MH3lAfiv8Rc/dk
|
||||
1bj6+8AuT/vEsKfZvg09cjnWWmItz5Ip7xuhPm1Tlu/8vu7G4gAGpz5jVEVU8UTt
|
||||
AT8b3h2AzqIs9EUqTeV6LMULcibAIAcCqdjlw7wL2HpEgI2+wSxqe7Lpf99Sr3BX
|
||||
F4t1FDzi1k4m0ZwS9bcL3wKjnVUof72ZTegK/g8QUnH5SFt6GvUvkSjLZzBGEX50
|
||||
lpwlInRA3iiphLgo4gWZw6uTAN+IbwXLUjljQf6re+CQw6DicrEzsVCCkCcBcm4K
|
||||
+9WmXB/diH6HXc8OD/hwCnWPr1CS0tJFPsaXbPSu1R6QSD0m73tIEmQ0sxlB+8X+
|
||||
VKgeqE2KAaikmtFwFTl3cvd4dYZT6JhppdcETQ8qef/chZRPN2hlCeGGAFemaSFV
|
||||
Kwa7qdOJ9pHkNvqREs7I8nD1Rm5PU/nZ+S1k1qghHB0onStNiLZgDPdLeZ85RCJ3
|
||||
yQcnEA/iuy/wX+t/s2uALw4o88fSa5kjYBeJL38Ra80WDRbiHT7mmaxkQu2AS/52
|
||||
GC/UU06OFkCHZVbmBucuaibvEX7OfSQjXraX7z/4+jJFnotAYNZvi8iebTiJ/5/P
|
||||
zOuOeyEz67NUt8txojcwX6Ksl8w17iqMMqBtK+BvBVvINAepq2gghJAZeleu9AGK
|
||||
WL+SeStqHnwa6nr5mq/3DKL76R5Yn8UrqocRU/+mKymellhlBTRB0x2m0BJjwnz9
|
||||
W5AMfmV1DZ3ezTnJsyrcXkqCDQorVkRupmSJhP3Pw4ENR9FxJlOo1eXtTUi2gdwH
|
||||
ysxc9eszdlKBIPK5UJbMlHDMcEGARM93sZhR9S1IyBEHP7u/CTKjmSYCs/xVJh5u
|
||||
vzN96/SyeS95w9AUW3UYEX5aya/V2bx10OuGByIH08HbXOg5fgIRBso1RA18WL7i
|
||||
LHSfxHcLQFsllbRbUjEDtO95MBSHfFgiVPSBiOMyoMdygYxJS0oWkzdv9yY1eAAW
|
||||
24lR1Z5XSJpmdO0tQBLHCWvpxH0sIjfmFQ73INBTWG3yQbanvwwFCtdqB9ktAZ1i
|
||||
ekQdwTJN8ohPmCgIOQzwppj7nljARnXryxBgbPLPRNKstwkkZmZ82tAG5AHUSOnz
|
||||
QUIICDcBedRVbW//s7lqkoTKAgP9vpdEqgVA4htDxgVOjEjklDL9Clo0M2oMRCu3
|
||||
AhpUjGywDmiR3ZjQ68/5ZcJr8a/8P5Ksjh85JIJhOHL0Sop4njRTjcFLukaF36p3
|
||||
06Xs0clX5xBJ9oF1ABOstsgC6TBuiszG3TvaLQ5e6pMEFIs9TKFICBn33ZsKkGoA
|
||||
Bs9Vk59jx81Z7JzGauCl2cUo95LXE3phrLDhFkEsIAbZycveuzJjUoJEVr1mqCZq
|
||||
kO/BOJJHfCWS896ECvBFEC2p7bu7LMAe8Vm4jTYBUl6AVhL49GYUZ4zXzMvdGj9e
|
||||
XCeKNARWNc+UbDt4fFXJcYpbpbIYWJzzoa1LcsVnw3tG2DC3bHXJGdzHO71EEQvs
|
||||
P4SizNH34GksZ9oS+NBMSew4vptHBzNvfJkGgyU05vsv65BMhdHxEfLF2VESn0I/
|
||||
6w4VYKByc7TVYik28cm2db9fPPc2G/SXKlTVeuujmFjz25Y0pxQs1sJMapc28Ie+
|
||||
aIC72eY6FygQCyZLlkodnBaSIfscQFbRMx8ju3px2fXoVYaXHHii6tZtRrBdXMh9
|
||||
/iTP5CNQvKDGBpBDs9GJAtPTVyA+TkxL70SjNr3ANoXmcVmBHhmkaYWxvBPYcgOR
|
||||
4U6+YRJqrQjAGwHWh3/xdYakRbDCbvY6jvYOan19XnIFqKmIaMEVGWIqL6T7/X1F
|
||||
P9oxvGTYJymnKZNadQ15NTZTcddJ0+48dS+6FZKRqSrSF81dFr2judwW8qZN7qqS
|
||||
7YnHeb8pg5IlH2lMP525fE3ap2hOAsRgEZOImNw3yOudURXiYLtvaAQ8GYFV1yPr
|
||||
JzAqnZC+rJN9313GT/S0LZ8HqM8kL13xKrrKL/agdotzv0VzAZDbL4qY0n7NuizE
|
||||
+q5Icr2kCzAYyJeAttuSGF2nt7rLg/oj5+vdnHek8CIDQelMz5z4Px9bmlZaxASd
|
||||
8hsA+yg0ZbRg85B/xlU6QjjBcAd6OWzfpTXET+rIKr95aCHKX1999xumNvwN/2MN
|
||||
AHS0IXpmVRv07FZNA46exvbD5dW8CFcIEVxf3umC9xlxMPphbxwcCLl/ak3+cFwc
|
||||
zNpBpZcz/lDqbqxADB2Y9Z4NCNnDUV8xYV75LPloQSOy8+BULFJH+FHwiuE/GIR3
|
||||
QiXwE1dAlEhTBL+6w/d1D96LH3U7fxOrnI44h30kXUlNKD2JGb6XzLW8MmD4c01B
|
||||
938WXgx4j0WxTAIhuFNMS+fcYcf4yzq1Rfrm9HoUlYnDXh3igdUlszhCuTUakbBD
|
||||
rKILwcR1133V4eoF4DUf1I1VlS8xqQ4hRAgPvgqjyoHRSPKxXZf5epj8k81vWZk3
|
||||
yezCPFNArgnsm5eUCMH4HZMajMy9p8FR45CDh6BznGCHzvPMdif0FH+HsFgoJusj
|
||||
goR/Oy5RYuyNoqgrZn+zURJpL2K+I4C+rEgbBTvCs62AOfc2YoIXkB6p0zpG+m0M
|
||||
dNN8f/eJNZLSJEqKShevBKOaD/NPgfqlBqXVqqeTCde981qM75oyGwjqc6KlE/CN
|
||||
kFFExL57Uc5YBgwemOE6Gwpizh2rRBxqN1371DPbbU4zDDjYYluXeeWwLqynQ1cf
|
||||
BciGsX7T/4Skh+3yhdnROpBcqf1tKMThBy0Op2K0e/sA0ys5Wbg6icTI9fVLInh2
|
||||
f+/94j58YhHuYWoz5Evh97sNyEuh2CN0BYcdOumJG8rR/DFqIkYBDh1+NI/5idZs
|
||||
lkQkeJGw6N73ZgY/LieKik/SRS9cBqB4VBBcMPKNLfNlqdpKxTakw/snxmUJ+ajU
|
||||
fLWYcrebwklNLK6G2LjA/0FQpsaAOlA3FhIK2KVqOvzxhFzb+prNx/OnN/dxbVoF
|
||||
irEEhjfHOO8fUPQJFkgzNIbiqH5JwZOoeyxqhj6LFz28BoGkZ66xKa9Xu674tsac
|
||||
E9dN/kaj0VQlDwwtSQOGv/CYHi6u3XCm/1jfq5V2l+IKAUjml352IzxWtnmuD8dn
|
||||
WrJdip2J+jn//UAn8az/m74CswOy5d2GSHqmnyZbJSWEg+CDzeQDNw7t5dl9zmDZ
|
||||
QYGuDYfhdtIXPI38J07EyPh3rhpHXNBZOn4O/9B/ePXbSSQUKS1gNkCx/J8nXK7p
|
||||
Lp7d3S6jsPCwqaZgbUc3MaklYeOtnSOKP4qbfGkrc6Ejh8m9trN/HCS9mEmCLa5K
|
||||
MMFmt0F1YN8DytkGM9YjYj/4XaAw2o9AdFTJVVnsPJkTAOprlyW/H3s8yMPbmqdN
|
||||
itA5GJQSRj+jnPRExW6Ncme8jXKMeqcBqCSCq/A5TVt6eZJXfGGNYKDnv4rBUXiz
|
||||
oWOVhCyFpE/Z8kT3dEEfRz1gCV8FjjjdTlYxDxKWOscKv5A7LomTdIAAAAroNYTW
|
||||
WDWE1lgAAAAdc3NoLW1sZHNhODctZWQ0NDhAd29sZnNzbC5jb20AAApZkNznb0AV
|
||||
bdlWoHPmys/0UC0vigl0Nu5+Rjdeoxw3f72PYyRTJkAxKkEIs+D3vhD1oL+w7cfD
|
||||
B95QH4r/EXP3ZNW4+vvALk/7xLCn2b4NPXI51lpiLc+SKe8boT5tU5bv/L7uxuIA
|
||||
Bqc+Y1RFVPFE7QE/G94dgM6iLPRFKk3leizFC3ImwCAHAqnY5cO8C9h6RICNvsEs
|
||||
anuy6X/fUq9wVxeLdRQ84tZOJtGcEvW3C98Co51VKH+9mU3oCv4PEFJx+Uhbehr1
|
||||
L5Eoy2cwRhF+dJacJSJ0QN4oqYS4KOIFmcOrkwDfiG8Fy1I5Y0H+q3vgkMOg4nKx
|
||||
M7FQgpAnAXJuCvvVplwf3Yh+h13PDg/4cAp1j69QktLSRT7Gl2z0rtUekEg9Ju97
|
||||
SBJkNLMZQfvF/lSoHqhNigGopJrRcBU5d3L3eHWGU+iYaaXXBE0PKnn/3IWUTzdo
|
||||
ZQnhhgBXpmkhVSsGu6nTifaR5Db6kRLOyPJw9UZuT1P52fktZNaoIRwdKJ0rTYi2
|
||||
YAz3S3mfOUQid8kHJxAP4rsv8F/rf7NrgC8OKPPH0muZI2AXiS9/EWvNFg0W4h0+
|
||||
5pmsZELtgEv+dhgv1FNOjhZAh2VW5gbnLmom7xF+zn0kI162l+8/+PoyRZ6LQGDW
|
||||
b4vInm04if+fz8zrjnshM+uzVLfLcaI3MF+irJfMNe4qjDKgbSvgbwVbyDQHqato
|
||||
IISQGXpXrvQBili/knkrah58Gup6+Zqv9wyi++keWJ/FK6qHEVP/pispnpZYZQU0
|
||||
QdMdptASY8J8/VuQDH5ldQ2d3s05ybMq3F5Kgg0KK1ZEbqZkiYT9z8OBDUfRcSZT
|
||||
qNXl7U1ItoHcB8rMXPXrM3ZSgSDyuVCWzJRwzHBBgETPd7GYUfUtSMgRBz+7vwky
|
||||
o5kmArP8VSYebr8zfev0snkvecPQFFt1GBF+Wsmv1dm8ddDrhgciB9PB21zoOX4C
|
||||
EQbKNUQNfFi+4ix0n8R3C0BbJZW0W1IxA7TveTAUh3xYIlT0gYjjMqDHcoGMSUtK
|
||||
FpM3b/cmNXgAFtuJUdWeV0iaZnTtLUASxwlr6cR9LCI35hUO9yDQU1ht8kG2p78M
|
||||
BQrXagfZLQGdYnpEHcEyTfKIT5goCDkM8KaY+55YwEZ168sQYGzyz0TSrLcJJGZm
|
||||
fNrQBuQB1Ejp80FCCAg3AXnUVW1v/7O5apKEygID/b6XRKoFQOIbQ8YFToxI5JQy
|
||||
/QpaNDNqDEQrtwIaVIxssA5okd2Y0OvP+WXCa/Gv/D+SrI4fOSSCYThy9EqKeJ40
|
||||
U43BS7pGhd+qd9Ol7NHJV+cQSfaBdQATrLbIAukwborMxt072i0OXuqTBBSLPUyh
|
||||
SAgZ992bCpBqAAbPVZOfY8fNWeycxmrgpdnFKPeS1xN6Yayw4RZBLCAG2cnL3rsy
|
||||
Y1KCRFa9ZqgmapDvwTiSR3wlkvPehArwRRAtqe27uyzAHvFZuI02AVJegFYS+PRm
|
||||
FGeM18zL3Ro/XlwnijQEVjXPlGw7eHxVyXGKW6WyGFic86GtS3LFZ8N7Rtgwt2x1
|
||||
yRncxzu9RBEL7D+EoszR9+BpLGfaEvjQTEnsOL6bRwczb3yZBoMlNOb7L+uQTIXR
|
||||
8RHyxdlREp9CP+sOFWCgcnO01WIpNvHJtnW/Xzz3Nhv0lypU1Xrro5hY89uWNKcU
|
||||
LNbCTGqXNvCHvmiAu9nmOhcoEAsmS5ZKHZwWkiH7HEBW0TMfI7t6cdn16FWGlxx4
|
||||
ourWbUawXVzIff4kz+QjULygxgaQQ7PRiQLT01cgPk5MS+9Eoza9wDaF5nFZgR4Z
|
||||
pGmFsbwT2HIDkeFOvmESaq0IwBsB1od/8XWGpEWwwm72Oo72Dmp9fV5yBaipiGjB
|
||||
FRliKi+k+/19RT/aMbxk2CcppymTWnUNeTU2U3HXSdPuPHUvuhWSkakq0hfNXRa9
|
||||
o7ncFvKmTe6qku2Jx3m/KYOSJR9pTD+duXxN2qdoTgLEYBGTiJjcN8jrnVEV4mC7
|
||||
b2gEPBmBVdcj6ycwKp2QvqyTfd9dxk/0tC2fB6jPJC9d8Sq6yi/2oHaLc79FcwGQ
|
||||
2y+KmNJ+zbosxPquSHK9pAswGMiXgLbbkhhdp7e6y4P6I+fr3Zx3pPAiA0HpTM+c
|
||||
+D8fW5pWWsQEnfIbAPsoNGW0YPOQf8ZVOkI4wXAHejls36U1xE/qyCq/eWghyl9f
|
||||
ffcbpjb8Df9jDQB0tCF6ZlUb9OxWTQOOnsb2w+XVvAhXCBFcX97pgvcZcTD6YW8c
|
||||
HAi5f2pN/nBcHMzaQaWXM/5Q6m6sQAwdmPWeDQjZw1FfMWFe+Sz5aEEjsvPgVCxS
|
||||
R/hR8IrhPxiEd0Il8BNXQJRIUwS/usP3dQ/eix91O38Tq5yOOId9JF1JTSg9iRm+
|
||||
l8y1vDJg+HNNQfd/Fl4MeI9FsUwCIbhTTEvn3GHH+Ms6tUX65vR6FJWJw14d4oHV
|
||||
JbM4Qrk1GpGwQ6yiC8HEddd91eHqBeA1H9SNVZUvMakOIUQID74Ko8qB0UjysV2X
|
||||
+XqY/JPNb1mZN8nswjxTQK4J7JuXlAjB+B2TGozMvafBUeOQg4egc5xgh87zzHYn
|
||||
9BR/h7BYKCbrI4KEfzsuUWLsjaKoK2Z/s1ESaS9iviOAvqxIGwU7wrOtgDn3NmKC
|
||||
F5AeqdM6RvptDHTTfH/3iTWS0iRKikoXrwSjmg/zT4H6pQal1aqnkwnXvfNajO+a
|
||||
MhsI6nOipRPwjZBRRMS+e1HOWAYMHpjhOhsKYs4dq0Qcajdd+9Qz221OMww42GJb
|
||||
l3nlsC6sp0NXHwXIhrF+0/+EpIft8oXZ0TqQXKn9bSjE4QctDqditHv7ANMrOVm4
|
||||
OonEyPX1SyJ4dn/v/eI+fGIR7mFqM+RL4fe7DchLodgjdAWHHTrpiRvK0fwxaiJG
|
||||
AQ4dfjSP+YnWbJZEJHiRsOje92YGPy4niopP0kUvXAageFQQXDDyjS3zZanaSsU2
|
||||
pMP7J8ZlCfmo1Hy1mHK3m8JJTSyuhti4wP9BUKbGgDpQNxYSCtilajr88YRc2/qa
|
||||
zcfzpzf3cW1aBYqxBIY3xzjvH1D0CRZIMzSG4qh+ScGTqHssaoY+ixc9vAaBpGeu
|
||||
sSmvV7uu+LbGnBPXTf5Go9FUJQ8MLUkDhr/wmB4urt1wpv9Y36uVdpfiCgFI5pd+
|
||||
diM8VrZ5rg/HZ1qyXYqdifo5//1AJ/Gs/5u+ArMDsuXdhkh6pp8mWyUlhIPgg83k
|
||||
AzcO7eXZfc5g2UGBrg2H4XbSFzyN/CdOxMj4d64aR1zQWTp+Dv/Qf3j120kkFCkt
|
||||
YDZAsfyfJ1yu6S6e3d0uo7DwsKmmYG1HNzGpJWHjrZ0jij+Km3xpK3OhI4fJvbaz
|
||||
fxwkvZhJgi2uSjDBZrdBdWDfA8rZBjPWI2I/+F2gMNqPQHRUyVVZ7DyZEwDqa5cl
|
||||
vx97PMjD25qnTYrQORiUEkY/o5z0RMVujXJnvI1yjHqnAagkgqvwOU1benmSV3xh
|
||||
jWCg57+KwVF4s6FjlYQshaRP2fJE93RBH0c9YAlfBY443U5WMQ8SljrHCr+QOy6J
|
||||
k3SAAAAAWXtBfEZH8NKBxGRlaLdnaCi2Al56SYZYLzOYN8o8LLQzt8E3vC1I6+9T
|
||||
tzQU20Ywt1X+ZVa5uqDBSsgS5w76RsmjaTCKuJsWZTRsgcGwzquDP8gG+Gog47SB
|
||||
AAAAAAE=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
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
|
||||
N6n/UlyR/aAmaZuszD503XxAMXX4BEYAAAAAAQI=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
1007
src/internal.c
1007
src/internal.c
File diff suppressed because it is too large
Load Diff
292
src/keygen.c
292
src/keygen.c
|
|
@ -53,6 +53,7 @@
|
|||
#ifdef HAVE_ED448
|
||||
#include <wolfssl/wolfcrypt/ed448.h>
|
||||
#endif
|
||||
#include <wolfssl/wolfcrypt/asn.h>
|
||||
#include <wolfssl/wolfcrypt/asn_public.h>
|
||||
#include <wolfssl/wolfcrypt/coding.h>
|
||||
#include <wolfssl/wolfcrypt/error-crypt.h>
|
||||
|
|
@ -371,14 +372,115 @@ int wolfSSH_MakeMlDsaKey(byte* out, word32 outSz, word32 level)
|
|||
}
|
||||
|
||||
|
||||
/* builds an OpenSSH-key-v1 envelope (the only on-disk form for composite
|
||||
* keys, which have no ASN.1 representation); see
|
||||
* GetOpenSshKeyMlDsaComposite() in src/internal.c for the parser.
|
||||
* magic "openssh-key-v1\0", string ciphername, string kdfname,
|
||||
* string kdfoptions, uint32 keycount, string pubkeyblob,
|
||||
* string { checkint1, checkint2, { string type, string pub, string priv,
|
||||
* string comment }, padding }
|
||||
* pub is (mldsaPub || tradPub), priv is (mldsaSeed || tradPriv) */
|
||||
/* Build OpenSSH-key-v1 envelope. */
|
||||
#if !defined(WOLFSSH_NO_MLDSA)
|
||||
/* Gen trad composite key half. */
|
||||
static int MakeCompositeTradKey(WC_RNG* rng, const CompositeParams* params,
|
||||
byte* tradPub, byte* tradPriv)
|
||||
{
|
||||
int ret = WS_NOT_COMPILED;
|
||||
|
||||
WOLFSSH_UNUSED(rng);
|
||||
WOLFSSH_UNUSED(tradPub);
|
||||
WOLFSSH_UNUSED(tradPriv);
|
||||
|
||||
if (params->tradType == TRAD_TYPE_ED25519) {
|
||||
#ifndef WOLFSSH_NO_ED25519
|
||||
ed25519_key key;
|
||||
word32 sz;
|
||||
|
||||
if (wc_ed25519_init(&key) != 0) {
|
||||
return WS_CRYPTO_FAILED;
|
||||
}
|
||||
ret = (wc_ed25519_make_key(rng, ED25519_KEY_SIZE, &key) == 0) ?
|
||||
0 : WS_CRYPTO_FAILED;
|
||||
if (ret == 0) {
|
||||
sz = params->tradPrivSz;
|
||||
if (wc_ed25519_export_private_only(&key, tradPriv, &sz) != 0 ||
|
||||
sz != params->tradPrivSz) {
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
sz = params->tradPubSz;
|
||||
if (wc_ed25519_export_public(&key, tradPub, &sz) != 0 ||
|
||||
sz != params->tradPubSz) {
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
}
|
||||
wc_ed25519_free(&key);
|
||||
#endif
|
||||
}
|
||||
else if (params->tradType == TRAD_TYPE_ED448) {
|
||||
#ifdef HAVE_ED448
|
||||
ed448_key key;
|
||||
word32 sz;
|
||||
|
||||
if (wc_ed448_init(&key) != 0) {
|
||||
return WS_CRYPTO_FAILED;
|
||||
}
|
||||
ret = (wc_ed448_make_key(rng, ED448_KEY_SIZE, &key) == 0) ?
|
||||
0 : WS_CRYPTO_FAILED;
|
||||
if (ret == 0) {
|
||||
sz = params->tradPrivSz;
|
||||
if (wc_ed448_export_private_only(&key, tradPriv, &sz) != 0 ||
|
||||
sz != params->tradPrivSz) {
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
sz = params->tradPubSz;
|
||||
if (wc_ed448_export_public(&key, tradPub, &sz) != 0 ||
|
||||
sz != params->tradPubSz) {
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
}
|
||||
wc_ed448_free(&key);
|
||||
#endif
|
||||
}
|
||||
else if (params->tradType == TRAD_TYPE_ECC) {
|
||||
#ifndef WOLFSSH_NO_ECDSA
|
||||
ecc_key key;
|
||||
word32 sz;
|
||||
/* Pin ECC curve explicitly. */
|
||||
if (wc_ecc_init(&key) != 0) {
|
||||
return WS_CRYPTO_FAILED;
|
||||
}
|
||||
ret = (wc_ecc_make_key_ex(rng, (int)params->tradPrivSz, &key,
|
||||
params->eccCurveId) == 0) ? 0 : WS_CRYPTO_FAILED;
|
||||
if (ret == 0) {
|
||||
sz = params->tradPrivSz;
|
||||
if (wc_ecc_export_private_only(&key, tradPriv, &sz) != 0 ||
|
||||
sz != params->tradPrivSz) {
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
sz = params->tradPubSz;
|
||||
if (wc_ecc_export_x963(&key, tradPub, &sz) != 0 ||
|
||||
sz != params->tradPubSz) {
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
}
|
||||
wc_ecc_free(&key);
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* !WOLFSSH_NO_MLDSA */
|
||||
|
||||
#if !defined(WOLFSSH_NO_MLDSA)
|
||||
/* Base64 encoded size. */
|
||||
static word32 MlDsaCompositeBase64Sz(word32 fileSz)
|
||||
{
|
||||
word32 chars = (fileSz + 2) / 3 * 4;
|
||||
word32 lines = (chars + PEM_LINE_SZ - 1) / PEM_LINE_SZ;
|
||||
|
||||
return chars + lines;
|
||||
}
|
||||
#endif /* !WOLFSSH_NO_MLDSA */
|
||||
|
||||
int wolfSSH_MakeMlDsaCompositeKey(byte* out, word32 outSz, word32 level,
|
||||
word32 tradType)
|
||||
{
|
||||
|
|
@ -397,22 +499,16 @@ int wolfSSH_MakeMlDsaCompositeKey(byte* out, word32 outSz, word32 level,
|
|||
int mldsaInit = 0;
|
||||
int mldsaGenOk;
|
||||
byte mldsaSeed[MLDSA_SEED_SZ];
|
||||
#ifndef WOLFSSH_NO_MLDSA87
|
||||
byte mldsaPub[WC_MLDSA_87_PUB_KEY_SIZE];
|
||||
#elif !defined(WOLFSSH_NO_MLDSA65)
|
||||
byte mldsaPub[WC_MLDSA_65_PUB_KEY_SIZE];
|
||||
#else
|
||||
byte mldsaPub[WC_MLDSA_44_PUB_KEY_SIZE];
|
||||
#endif
|
||||
byte tradPub[COMPOSITE_MAX_TRAD_PUB_SZ];
|
||||
byte tradPriv[COMPOSITE_MAX_TRAD_PRIV_SZ];
|
||||
word32 sz;
|
||||
#ifndef WOLFSSH_NO_ECDSA
|
||||
ecc_key eccKey;
|
||||
int eccInit = 0;
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_ED25519
|
||||
ed25519_key ed25519Key;
|
||||
int ed25519Init = 0;
|
||||
#endif
|
||||
#ifdef HAVE_ED448
|
||||
ed448_key ed448Key;
|
||||
int ed448Init = 0;
|
||||
#endif
|
||||
word32 fileSz, pubBlobSz, compositePubSz, compositePrivSz;
|
||||
word32 privKeysStrSz, padSz, off, i, checkint;
|
||||
|
||||
|
|
@ -423,13 +519,24 @@ int wolfSSH_MakeMlDsaCompositeKey(byte* out, word32 outSz, word32 level,
|
|||
|
||||
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_MakeMlDsaCompositeKey()");
|
||||
|
||||
if (out == NULL) {
|
||||
return WS_BAD_ARGUMENT;
|
||||
}
|
||||
|
||||
if (level == WOLFSSH_MLDSAKEY_44 &&
|
||||
tradType == WOLFSSH_COMPOSITE_TRAD_ED25519)
|
||||
keyId = ID_MLDSA44_ED25519;
|
||||
else if (level == WOLFSSH_MLDSAKEY_44 &&
|
||||
tradType == WOLFSSH_COMPOSITE_TRAD_ECDSA)
|
||||
keyId = ID_MLDSA44_ES256;
|
||||
else if (level == WOLFSSH_MLDSAKEY_65 &&
|
||||
tradType == WOLFSSH_COMPOSITE_TRAD_ED25519)
|
||||
keyId = ID_MLDSA65_ED25519;
|
||||
else if (level == WOLFSSH_MLDSAKEY_65 &&
|
||||
tradType == WOLFSSH_COMPOSITE_TRAD_ECDSA)
|
||||
keyId = ID_MLDSA65_ES256;
|
||||
else if (level == WOLFSSH_MLDSAKEY_87 &&
|
||||
tradType == WOLFSSH_COMPOSITE_TRAD_ED448)
|
||||
keyId = ID_MLDSA87_ED448;
|
||||
else if (level == WOLFSSH_MLDSAKEY_87 &&
|
||||
tradType == WOLFSSH_COMPOSITE_TRAD_ECDSA)
|
||||
keyId = ID_MLDSA87_ES384;
|
||||
else {
|
||||
WLOG(WS_LOG_DEBUG, "Invalid ML-DSA composite level/trad combination");
|
||||
return WS_BAD_ARGUMENT;
|
||||
|
|
@ -464,6 +571,18 @@ int wolfSSH_MakeMlDsaCompositeKey(byte* out, word32 outSz, word32 level,
|
|||
+ UINT32_SZ + pubBlobSz
|
||||
+ UINT32_SZ + privKeysStrSz;
|
||||
|
||||
/* Pre-calculate encoded size. */
|
||||
b64Sz = MlDsaCompositeBase64Sz(fileSz);
|
||||
|
||||
if (out == NULL) {
|
||||
/* Size query. */
|
||||
return (int)(WSTRLEN(header) + b64Sz + WSTRLEN(footer) + 1);
|
||||
}
|
||||
if (outSz < b64Sz + WSTRLEN(header) + WSTRLEN(footer) + 1) {
|
||||
WLOG(WS_LOG_DEBUG, "Output buffer too small for composite key");
|
||||
return WS_BUFFER_E;
|
||||
}
|
||||
|
||||
ret = wc_InitRng(&rng);
|
||||
if (ret != 0) {
|
||||
WLOG(WS_LOG_DEBUG, "Couldn't create RNG");
|
||||
|
|
@ -499,85 +618,8 @@ int wolfSSH_MakeMlDsaCompositeKey(byte* out, word32 outSz, word32 level,
|
|||
}
|
||||
mldsaGenOk = (ret == 0);
|
||||
|
||||
if (ret == 0 && params.tradType == TRAD_TYPE_ED25519) {
|
||||
#ifndef WOLFSSH_NO_ED25519
|
||||
if (wc_ed25519_init(&ed25519Key) != 0) {
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
else {
|
||||
ed25519Init = 1;
|
||||
if (wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &ed25519Key) != 0)
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
if (ret == 0) {
|
||||
sz = params.tradPrivSz;
|
||||
if (wc_ed25519_export_private_only(&ed25519Key, tradPriv, &sz)
|
||||
!= 0 || sz != params.tradPrivSz)
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
if (ret == 0) {
|
||||
sz = params.tradPubSz;
|
||||
if (wc_ed25519_export_public(&ed25519Key, tradPub, &sz) != 0 ||
|
||||
sz != params.tradPubSz)
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
#else
|
||||
ret = WS_NOT_COMPILED;
|
||||
#endif
|
||||
}
|
||||
else if (ret == 0 && params.tradType == TRAD_TYPE_ED448) {
|
||||
#ifdef HAVE_ED448
|
||||
if (wc_ed448_init(&ed448Key) != 0) {
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
else {
|
||||
ed448Init = 1;
|
||||
if (wc_ed448_make_key(&rng, ED448_KEY_SIZE, &ed448Key) != 0)
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
if (ret == 0) {
|
||||
sz = params.tradPrivSz;
|
||||
if (wc_ed448_export_private_only(&ed448Key, tradPriv, &sz) != 0 ||
|
||||
sz != params.tradPrivSz)
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
if (ret == 0) {
|
||||
sz = params.tradPubSz;
|
||||
if (wc_ed448_export_public(&ed448Key, tradPub, &sz) != 0 ||
|
||||
sz != params.tradPubSz)
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
#else
|
||||
ret = WS_NOT_COMPILED;
|
||||
#endif
|
||||
}
|
||||
else if (ret == 0 && params.tradType == TRAD_TYPE_ECC) {
|
||||
#ifndef WOLFSSH_NO_ECDSA
|
||||
int eccKeySz = (int)params.tradPrivSz;
|
||||
|
||||
if (wc_ecc_init(&eccKey) != 0) {
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
else {
|
||||
eccInit = 1;
|
||||
if (wc_ecc_make_key(&rng, eccKeySz, &eccKey) != 0)
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
if (ret == 0) {
|
||||
sz = params.tradPrivSz;
|
||||
if (wc_ecc_export_private_only(&eccKey, tradPriv, &sz) != 0 ||
|
||||
sz != params.tradPrivSz)
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
if (ret == 0) {
|
||||
sz = params.tradPubSz;
|
||||
if (wc_ecc_export_x963(&eccKey, tradPub, &sz) != 0 ||
|
||||
sz != params.tradPubSz)
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
#else
|
||||
ret = WS_NOT_COMPILED;
|
||||
#endif
|
||||
if (ret == 0) {
|
||||
ret = MakeCompositeTradKey(&rng, ¶ms, tradPub, tradPriv);
|
||||
}
|
||||
if (ret != 0 && mldsaGenOk) {
|
||||
WLOG(WS_LOG_DEBUG,
|
||||
|
|
@ -613,7 +655,8 @@ int wolfSSH_MakeMlDsaCompositeKey(byte* out, word32 outSz, word32 level,
|
|||
c32toa(compositePubSz, tmpBuf + off); off += UINT32_SZ;
|
||||
WMEMCPY(tmpBuf + off, mldsaPub, params.mldsaPubSz);
|
||||
off += params.mldsaPubSz;
|
||||
WMEMCPY(tmpBuf + off, tradPub, params.tradPubSz); off += params.tradPubSz;
|
||||
WMEMCPY(tmpBuf + off, tradPub, params.tradPubSz);
|
||||
off += params.tradPubSz;
|
||||
|
||||
c32toa(privKeysStrSz, tmpBuf + off); off += UINT32_SZ;
|
||||
c32toa(checkint, tmpBuf + off); off += UINT32_SZ;
|
||||
|
|
@ -623,7 +666,8 @@ int wolfSSH_MakeMlDsaCompositeKey(byte* out, word32 outSz, word32 level,
|
|||
c32toa(compositePubSz, tmpBuf + off); off += UINT32_SZ;
|
||||
WMEMCPY(tmpBuf + off, mldsaPub, params.mldsaPubSz);
|
||||
off += params.mldsaPubSz;
|
||||
WMEMCPY(tmpBuf + off, tradPub, params.tradPubSz); off += params.tradPubSz;
|
||||
WMEMCPY(tmpBuf + off, tradPub, params.tradPubSz);
|
||||
off += params.tradPubSz;
|
||||
c32toa(compositePrivSz, tmpBuf + off); off += UINT32_SZ;
|
||||
WMEMCPY(tmpBuf + off, mldsaSeed, MLDSA_SEED_SZ); off += MLDSA_SEED_SZ;
|
||||
WMEMCPY(tmpBuf + off, tradPriv, params.tradPrivSz);
|
||||
|
|
@ -637,37 +681,23 @@ int wolfSSH_MakeMlDsaCompositeKey(byte* out, word32 outSz, word32 level,
|
|||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
else {
|
||||
int b64Ret = Base64_Encode(tmpBuf, fileSz, NULL, &b64Sz);
|
||||
if (b64Ret != 0 && b64Ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) {
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
else if (outSz < b64Sz + WSTRLEN(header) + WSTRLEN(footer)) {
|
||||
WLOG(WS_LOG_DEBUG, "Output buffer too small for composite key");
|
||||
ret = WS_BUFFER_E;
|
||||
}
|
||||
else {
|
||||
off = 0;
|
||||
WMEMCPY(out + off, header, WSTRLEN(header)); off += (word32)WSTRLEN(header);
|
||||
if (Base64_Encode(tmpBuf, fileSz, out + off, &b64Sz) == 0) {
|
||||
off += b64Sz;
|
||||
WMEMCPY(out + off, footer, WSTRLEN(footer)); off += (word32)WSTRLEN(footer);
|
||||
ret = (int)off;
|
||||
}
|
||||
else ret = WS_CRYPTO_FAILED;
|
||||
/* outSz already verified. */
|
||||
off = 0;
|
||||
WMEMCPY(out + off, header, WSTRLEN(header));
|
||||
off += (word32)WSTRLEN(header);
|
||||
if (Base64_Encode(tmpBuf, fileSz, out + off, &b64Sz) == 0) {
|
||||
off += b64Sz;
|
||||
WMEMCPY(out + off, footer, WSTRLEN(footer));
|
||||
off += (word32)WSTRLEN(footer);
|
||||
/* NUL-terminate PEM text; outSz was already verified. */
|
||||
out[off] = '\0';
|
||||
ret = (int)(off + 1);
|
||||
}
|
||||
else ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (mldsaInit) wc_MlDsaKey_Free(&mldsaKey);
|
||||
#ifndef WOLFSSH_NO_ECDSA
|
||||
if (eccInit) wc_ecc_free(&eccKey);
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_ED25519
|
||||
if (ed25519Init) wc_ed25519_free(&ed25519Key);
|
||||
#endif
|
||||
#ifdef HAVE_ED448
|
||||
if (ed448Init) wc_ed448_free(&ed448Key);
|
||||
#endif
|
||||
if (rngInit) wc_FreeRng(&rng);
|
||||
|
||||
WS_FORCEZERO(mldsaSeed, sizeof(mldsaSeed));
|
||||
|
|
|
|||
139
src/ossh.c
139
src/ossh.c
|
|
@ -298,9 +298,7 @@ static int GetOpenSshKeyMlDsa(MlDsaKey* key,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Parse OpenSSH ML-DSA composite private key blob; see
|
||||
* GetOpenSshKeyPublicMlDsaComposite() for the public-key-only counterpart.
|
||||
* Returns WS_SUCCESS or negative WS_* error. */
|
||||
/* Parse OpenSSH ML-DSA composite private key. */
|
||||
static int GetOpenSshKeyMlDsaComposite(byte keyId, MlDsaKey* mldsa,
|
||||
void* tradKey, void* heap, const byte* buf, word32 len, word32* idx)
|
||||
{
|
||||
|
|
@ -309,6 +307,8 @@ static int GetOpenSshKeyMlDsaComposite(byte keyId, MlDsaKey* mldsa,
|
|||
word32 pubSz = 0;
|
||||
word32 privSz = 0;
|
||||
int ret;
|
||||
int mldsaInit = 0;
|
||||
int tradInit = 0;
|
||||
CompositeParams params;
|
||||
const CompositeTradOps* ops;
|
||||
|
||||
|
|
@ -317,25 +317,12 @@ static int GetOpenSshKeyMlDsaComposite(byte keyId, MlDsaKey* mldsa,
|
|||
|
||||
ops = WS_GetTradOps(params.tradType);
|
||||
|
||||
/* caller doesn't clean up on error; each path below frees what it
|
||||
* already initialized */
|
||||
ret = wc_MlDsaKey_Init(mldsa, heap, INVALID_DEVID);
|
||||
ret = InitCompositeKeyPair(¶ms, mldsa, tradKey, ops, heap,
|
||||
&mldsaInit, &tradInit);
|
||||
if (ret != 0) {
|
||||
return WS_CRYPTO_FAILED;
|
||||
}
|
||||
ret = wc_MlDsaKey_SetParams(mldsa, params.mldsaLevel);
|
||||
if (ret != 0) {
|
||||
wc_MlDsaKey_Free(mldsa);
|
||||
return WS_CRYPTO_FAILED;
|
||||
}
|
||||
if (ops == NULL) {
|
||||
wc_MlDsaKey_Free(mldsa);
|
||||
return WS_UNIMPLEMENTED_E;
|
||||
}
|
||||
ret = ops->init(tradKey, heap);
|
||||
if (ret != 0) {
|
||||
wc_MlDsaKey_Free(mldsa);
|
||||
return WS_CRYPTO_FAILED;
|
||||
if (mldsaInit) wc_MlDsaKey_Free(mldsa);
|
||||
if (tradInit) ops->free(tradKey);
|
||||
return (ret == WS_UNIMPLEMENTED_E) ? ret : WS_CRYPTO_FAILED;
|
||||
}
|
||||
|
||||
ret = GetStringRef(&pubSz, &pub, buf, len, idx);
|
||||
|
|
@ -352,15 +339,42 @@ static int GetOpenSshKeyMlDsaComposite(byte keyId, MlDsaKey* mldsa,
|
|||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
ret = wc_MlDsaKey_ImportPubRaw(mldsa, pub, params.mldsaPubSz);
|
||||
ret = wc_MlDsaKey_MakeKeyFromSeed(mldsa, priv);
|
||||
}
|
||||
if (ret == WS_SUCCESS) {
|
||||
ret = wc_MlDsaKey_MakeKeyFromSeed(mldsa, priv);
|
||||
#ifndef WOLFSSH_NO_MLDSA87
|
||||
byte mldsaPubCheck[WC_MLDSA_87_PUB_KEY_SIZE];
|
||||
#elif !defined(WOLFSSH_NO_MLDSA65)
|
||||
byte mldsaPubCheck[WC_MLDSA_65_PUB_KEY_SIZE];
|
||||
#else
|
||||
byte mldsaPubCheck[WC_MLDSA_44_PUB_KEY_SIZE];
|
||||
#endif
|
||||
word32 mldsaPubCheckSz = sizeof(mldsaPubCheck);
|
||||
|
||||
ret = wc_MlDsaKey_ExportPubRaw(mldsa, mldsaPubCheck,
|
||||
&mldsaPubCheckSz);
|
||||
if (ret == 0 &&
|
||||
(mldsaPubCheckSz != params.mldsaPubSz ||
|
||||
WMEMCMP(mldsaPubCheck, pub, params.mldsaPubSz) != 0)) {
|
||||
ret = WS_KEY_FORMAT_E;
|
||||
}
|
||||
}
|
||||
if (ret == WS_SUCCESS) {
|
||||
ret = ops->importPriv(tradKey, priv + MLDSA_SEED_SZ, params.tradPrivSz,
|
||||
pub + params.mldsaPubSz, params.tradPubSz);
|
||||
}
|
||||
if (ret == WS_SUCCESS) {
|
||||
byte tradPubCheck[COMPOSITE_MAX_TRAD_PUB_SZ];
|
||||
word32 tradPubCheckSz = sizeof(tradPubCheck);
|
||||
|
||||
ret = ops->exportPub(tradKey, tradPubCheck, &tradPubCheckSz);
|
||||
if (ret == 0 &&
|
||||
(tradPubCheckSz != params.tradPubSz ||
|
||||
WMEMCMP(tradPubCheck, pub + params.mldsaPubSz,
|
||||
params.tradPubSz) != 0)) {
|
||||
ret = WS_KEY_FORMAT_E;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
wc_MlDsaKey_Free(mldsa);
|
||||
|
|
@ -430,63 +444,6 @@ static int GetOpenSshKeyPublicMlDsa(MlDsaKey* key, const byte* buf,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* public-key-only counterpart to GetOpenSshKeyMlDsaComposite(); no trailing
|
||||
* private-key string to parse. Returns WS_SUCCESS or negative WS_* error */
|
||||
static int GetOpenSshKeyPublicMlDsaComposite(byte keyId, MlDsaKey* mldsa,
|
||||
void* tradKey, void* heap, const byte* buf, word32 len, word32* idx)
|
||||
{
|
||||
int ret;
|
||||
int mldsaInit = 0;
|
||||
int tradInit = 0;
|
||||
const byte* pub = NULL;
|
||||
word32 pubSz = 0;
|
||||
CompositeParams params;
|
||||
const CompositeTradOps* ops;
|
||||
|
||||
ret = WS_GetCompositeParams(keyId, ¶ms);
|
||||
if (ret != WS_SUCCESS) return ret;
|
||||
|
||||
ops = WS_GetTradOps(params.tradType);
|
||||
|
||||
ret = wc_MlDsaKey_Init(mldsa, heap, INVALID_DEVID);
|
||||
if (ret == 0) {
|
||||
mldsaInit = 1;
|
||||
ret = wc_MlDsaKey_SetParams(mldsa, params.mldsaLevel);
|
||||
}
|
||||
if (ret == 0) {
|
||||
if (ops == NULL) {
|
||||
ret = WS_UNIMPLEMENTED_E;
|
||||
}
|
||||
else {
|
||||
ret = ops->init(tradKey, heap);
|
||||
if (ret == 0) tradInit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ret = GetStringRef(&pubSz, &pub, buf, len, idx);
|
||||
}
|
||||
if (ret == 0) {
|
||||
if (pubSz != (params.mldsaPubSz + params.tradPubSz)) {
|
||||
ret = WS_KEY_FORMAT_E;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_MlDsaKey_ImportPubRaw(mldsa, pub, params.mldsaPubSz);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = ops->importPub(tradKey, pub + params.mldsaPubSz, params.tradPubSz);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
if (mldsaInit) wc_MlDsaKey_Free(mldsa);
|
||||
if (tradInit) {
|
||||
ops->free(tradKey);
|
||||
}
|
||||
ret = WS_CRYPTO_FAILED;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_RSA
|
||||
static int GetOpenSshPublicKeyRsa(RsaKey* key, const byte* buf, word32 len,
|
||||
|
|
@ -553,12 +510,6 @@ int GetOpenSshPublicKey(WS_KeySignature *key,
|
|||
ret = GetOpenSshKeyPublicMlDsa(&key->ks.mldsa.key, buf, len,
|
||||
idx, WC_ML_DSA_87);
|
||||
break;
|
||||
case ID_MLDSA44_ED25519:
|
||||
ret = GetOpenSshKeyPublicMlDsaComposite(keyId,
|
||||
&key->ks.mldsa_composite.mldsa,
|
||||
&key->ks.mldsa_composite.trad,
|
||||
key->heap, buf, len, idx);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ret = WS_UNIMPLEMENTED_E;
|
||||
|
|
@ -576,11 +527,12 @@ int GetOpenSshKey(WS_KeySignature *key,
|
|||
const byte* buf, word32 len, word32* idx)
|
||||
{
|
||||
const char AuthMagic[] = "openssh-key-v1";
|
||||
const word32 authMagicSz = (word32)WSTRLEN(AuthMagic) + 1; /* incl NUL */
|
||||
const byte* str = NULL;
|
||||
word32 keyCount = 0, strSz, i;
|
||||
int ret = WS_SUCCESS;
|
||||
|
||||
if (WSTRCMP(AuthMagic, (const char*)buf) != 0) {
|
||||
if (len < authMagicSz || WMEMCMP(AuthMagic, buf, authMagicSz) != 0) {
|
||||
ret = WS_KEY_AUTH_MAGIC_E;
|
||||
}
|
||||
|
||||
|
|
@ -668,8 +620,7 @@ int GetOpenSshKey(WS_KeySignature *key,
|
|||
ret = GetOpenSshKeyMlDsa(
|
||||
&key->ks.mldsa.key,
|
||||
str, strSz, &subIdx, WC_ML_DSA_44);
|
||||
/* clear keyId: key already freed, avoid
|
||||
* double free */
|
||||
/* Avoid double free. */
|
||||
if (ret != WS_SUCCESS)
|
||||
key->keyId = ID_NONE;
|
||||
break;
|
||||
|
|
@ -687,15 +638,19 @@ int GetOpenSshKey(WS_KeySignature *key,
|
|||
if (ret != WS_SUCCESS)
|
||||
key->keyId = ID_NONE;
|
||||
break;
|
||||
case ID_MLDSA44_ES256:
|
||||
case ID_MLDSA65_ES256:
|
||||
case ID_MLDSA87_ES384:
|
||||
case ID_MLDSA44_ED25519:
|
||||
case ID_MLDSA65_ED25519:
|
||||
case ID_MLDSA87_ED448:
|
||||
ret = GetOpenSshKeyMlDsaComposite(
|
||||
key->keyId,
|
||||
&key->ks.mldsa_composite.mldsa,
|
||||
&key->ks.mldsa_composite.trad,
|
||||
key->heap,
|
||||
str, strSz, &subIdx);
|
||||
/* clear keyId: key already freed, avoid
|
||||
* double free */
|
||||
/* Avoid double free. */
|
||||
if (ret != WS_SUCCESS)
|
||||
key->keyId = ID_NONE;
|
||||
break;
|
||||
|
|
@ -727,7 +682,7 @@ int GetOpenSshKey(WS_KeySignature *key,
|
|||
check1 <= check2;
|
||||
check1++, subIdx++) {
|
||||
if (check1 != str[subIdx]) {
|
||||
/* bad pad: free key decoded above */
|
||||
/* Bad pad: free key. */
|
||||
wolfSSH_KEY_clean(key);
|
||||
key->keyId = ID_NONE;
|
||||
ret = WS_KEY_FORMAT_E;
|
||||
|
|
|
|||
49
src/ssh.c
49
src/ssh.c
|
|
@ -1799,11 +1799,9 @@ union wolfSSH_key {
|
|||
#endif
|
||||
};
|
||||
|
||||
static const char* PrivBeginOpenSSH = "-----BEGIN OPENSSH PRIVATE KEY-----";
|
||||
static const char* PrivEndOpenSSH = "-----END OPENSSH PRIVATE KEY-----";
|
||||
|
||||
#if !defined(NO_FILESYSTEM) && !defined(WOLFSSH_USER_FILESYSTEM)
|
||||
/* currently only used in wolfSSH_ReadKey_file() */
|
||||
static const char* PrivBeginOpenSSH = "-----BEGIN OPENSSH PRIVATE KEY-----";
|
||||
static const char* PrivBeginPrefix = "-----BEGIN ";
|
||||
/* static const char* PrivEndPrefix = "-----END "; */
|
||||
static const char* PrivSuffix = " PRIVATE KEY-----";
|
||||
|
|
@ -2246,35 +2244,6 @@ static int DoOpenSshKey(const byte* in, word32 inSz, byte** out,
|
|||
int ret = WS_SUCCESS;
|
||||
byte* newKey = NULL;
|
||||
word32 newKeySz = inSz; /* binary will be smaller than PEM */
|
||||
word32 beginSz = (word32)WSTRLEN(PrivBeginOpenSSH);
|
||||
word32 endSz = (word32)WSTRLEN(PrivEndOpenSSH);
|
||||
const byte* b64 = NULL;
|
||||
const char* footer = NULL;
|
||||
word32 b64Sz = 0;
|
||||
|
||||
/* Reject buffers too small to hold both markers. Without this guard the
|
||||
* subtraction used to locate the base64 region underflows inSz. */
|
||||
if (inSz <= beginSz + endSz) {
|
||||
WLOG(WS_LOG_DEBUG, "OpenSSH private key buffer too small");
|
||||
return WS_PARSE_E;
|
||||
}
|
||||
|
||||
/* The begin marker must lead the buffer. */
|
||||
if (WMEMCMP(in, PrivBeginOpenSSH, beginSz) != 0) {
|
||||
WLOG(WS_LOG_DEBUG, "OpenSSH private key missing begin marker");
|
||||
return WS_PARSE_E;
|
||||
}
|
||||
|
||||
/* Locate the end marker so the base64 region is bounded by the input. */
|
||||
footer = WSTRNSTR((const char*)in + beginSz, PrivEndOpenSSH,
|
||||
inSz - beginSz);
|
||||
if (footer == NULL) {
|
||||
WLOG(WS_LOG_DEBUG, "OpenSSH private key missing end marker");
|
||||
return WS_PARSE_E;
|
||||
}
|
||||
|
||||
b64 = in + beginSz;
|
||||
b64Sz = (word32)(footer - (const char*)b64);
|
||||
|
||||
if (*out == NULL) {
|
||||
newKey = (byte*)WMALLOC(newKeySz, heap, DYNTYPE_PRIVKEY);
|
||||
|
|
@ -2291,17 +2260,18 @@ static int DoOpenSshKey(const byte* in, word32 inSz, byte** out,
|
|||
newKeySz = *outSz;
|
||||
}
|
||||
|
||||
ret = Base64_Decode((byte*)b64, b64Sz, newKey, &newKeySz);
|
||||
if (ret == 0) {
|
||||
ret = WS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
WLOG(WS_LOG_DEBUG, "Base64 decode of public key failed.");
|
||||
ret = WS_PARSE_E;
|
||||
/* locates the begin/end markers and base64-decodes the block between
|
||||
* them; shared with wolfSSH_ProcessBuffer()'s OPENSSH format path */
|
||||
ret = WS_StripOpenSshPem(in, inSz, newKey, &newKeySz);
|
||||
if (ret != WS_SUCCESS) {
|
||||
WLOG(WS_LOG_DEBUG, "OpenSSH private key marker/decode failed.");
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
ret = IdentifyOpenSshKey(newKey, newKeySz, heap);
|
||||
if (ret <= 0) {
|
||||
WLOG(WS_LOG_DEBUG, "Unable to identify key");
|
||||
}
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
|
|
@ -2312,7 +2282,6 @@ static int DoOpenSshKey(const byte* in, word32 inSz, byte** out,
|
|||
ret = WS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
WLOG(WS_LOG_DEBUG, "Unable to identify key");
|
||||
WS_FORCEZERO(newKey, newKeySz);
|
||||
if (*out == NULL) {
|
||||
WFREE(newKey, heap, DYNTYPE_PRIVKEY);
|
||||
|
|
|
|||
26
tests/kex.c
26
tests/kex.c
|
|
@ -518,13 +518,37 @@ int wolfSSH_KexTest(int argc, char** argv)
|
|||
#ifndef WOLFSSH_NO_MLDSA87
|
||||
AssertIntEQ(wolfSSH_KexTest_MlDsaHostKey("ssh-mldsa-87"), EXIT_SUCCESS);
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA44) && !defined(WOLFSSH_NO_ED25519)
|
||||
#if !defined(WOLFSSH_NO_MLDSA44) && !defined(WOLFSSH_NO_ED25519) && \
|
||||
!defined(NO_SHA512)
|
||||
/* Uses the "@openssh.com" wire name that OpenSSH negotiates for this
|
||||
* algorithm, matching what wolfSSH now emits (see NameIdMap). */
|
||||
AssertIntEQ(
|
||||
wolfSSH_KexTest_MlDsaHostKey("ssh-mldsa44-ed25519@openssh.com"),
|
||||
EXIT_SUCCESS);
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA44) && !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256)
|
||||
AssertIntEQ(wolfSSH_KexTest_MlDsaHostKey("ssh-mldsa44-es256@wolfssl.com"),
|
||||
EXIT_SUCCESS);
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA65) && \
|
||||
!defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) && !defined(NO_SHA512)
|
||||
AssertIntEQ(wolfSSH_KexTest_MlDsaHostKey("ssh-mldsa65-es256@wolfssl.com"),
|
||||
EXIT_SUCCESS);
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA65) && !defined(WOLFSSH_NO_ED25519) && \
|
||||
!defined(NO_SHA512)
|
||||
AssertIntEQ(wolfSSH_KexTest_MlDsaHostKey("ssh-mldsa65-ed25519@wolfssl.com"),
|
||||
EXIT_SUCCESS);
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA87) && \
|
||||
!defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) && !defined(NO_SHA512)
|
||||
AssertIntEQ(wolfSSH_KexTest_MlDsaHostKey("ssh-mldsa87-es384@wolfssl.com"),
|
||||
EXIT_SUCCESS);
|
||||
#endif
|
||||
#if !defined(WOLFSSH_NO_MLDSA87) && defined(HAVE_ED448)
|
||||
AssertIntEQ(wolfSSH_KexTest_MlDsaHostKey("ssh-mldsa87-ed448@wolfssl.com"),
|
||||
EXIT_SUCCESS);
|
||||
#endif
|
||||
|
||||
AssertIntEQ(wolfSSH_Cleanup(), WS_SUCCESS);
|
||||
|
||||
|
|
|
|||
659
tests/unit.c
659
tests/unit.c
File diff suppressed because it is too large
Load Diff
|
|
@ -138,8 +138,9 @@ enum WS_ErrorCodes {
|
|||
WS_KDF_E = -1097, /* KDF error*/
|
||||
WS_DISCONNECT = -1098, /* peer sent disconnect */
|
||||
WS_MLDSA_E = -1099, /* MLDSA failure */
|
||||
WS_ED448_E = -1100, /* Ed448 failure */
|
||||
|
||||
WS_LAST_E = WS_MLDSA_E /* Last error indicator */
|
||||
WS_LAST_E = WS_ED448_E /* Update to indicate last error */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -471,8 +471,13 @@ enum {
|
|||
ID_MLDSA44,
|
||||
ID_MLDSA65,
|
||||
ID_MLDSA87,
|
||||
/* always declared; NameIdMap/WS_GetCompositeParams() gate reachability */
|
||||
/* always declared */
|
||||
ID_MLDSA44_ES256,
|
||||
ID_MLDSA65_ES256,
|
||||
ID_MLDSA87_ES384,
|
||||
ID_MLDSA44_ED25519,
|
||||
ID_MLDSA65_ED25519,
|
||||
ID_MLDSA87_ED448,
|
||||
#endif
|
||||
ID_X509V3_SSH_RSA,
|
||||
ID_X509V3_ECDSA_SHA2_NISTP256,
|
||||
|
|
@ -674,7 +679,9 @@ enum NameIdType {
|
|||
#define WOLFSSH_MAX_FILE_SIZE (1024ul * 1024ul * 4)
|
||||
#endif
|
||||
#ifndef WOLFSSH_MAX_PVT_KEYS
|
||||
#define WOLFSSH_MAX_PVT_KEYS 8
|
||||
/* 3 default host keys (RSA, ECDSA, Ed25519) + 3 plain ML-DSA levels +
|
||||
* 6 ML-DSA composite combos, with headroom for future combos. */
|
||||
#define WOLFSSH_MAX_PVT_KEYS 16
|
||||
#endif
|
||||
#ifndef WOLFSSH_MAX_PUB_KEY_ALGO
|
||||
#define WOLFSSH_MAX_PUB_KEY_ALGO (WOLFSSH_MAX_PVT_KEYS + 2)
|
||||
|
|
@ -1290,6 +1297,30 @@ WOLFSSH_LOCAL int wolfSSH_SetHostTpmKey(WOLFSSH_CTX* ctx, byte keyId);
|
|||
WOLFSSH_LOCAL int wolfSSH_FwdWorker(WOLFSSH* ssh);
|
||||
|
||||
|
||||
#ifndef WOLFSSH_NO_MLDSA
|
||||
/* Shared shape for a composite key's ML-DSA+traditional pair; reused
|
||||
* in src/internal.c so the copies can't drift apart. */
|
||||
typedef struct WS_MlDsaCompositeBody {
|
||||
MlDsaKey mldsa;
|
||||
union {
|
||||
#ifndef WOLFSSH_NO_ECDSA
|
||||
ecc_key ecc;
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_ED25519
|
||||
ed25519_key ed25519;
|
||||
#endif
|
||||
#ifdef HAVE_ED448
|
||||
ed448_key ed448;
|
||||
#endif
|
||||
#if defined(WOLFSSH_NO_ECDSA) && defined(WOLFSSH_NO_ED25519) && \
|
||||
!defined(HAVE_ED448)
|
||||
/* keep union non-empty */
|
||||
byte placeholder;
|
||||
#endif
|
||||
} trad;
|
||||
} WS_MlDsaCompositeBody;
|
||||
#endif /* WOLFSSH_NO_MLDSA */
|
||||
|
||||
typedef struct WS_KeySignature {
|
||||
byte keyId;
|
||||
byte sigId;
|
||||
|
|
@ -1319,29 +1350,8 @@ typedef struct WS_KeySignature {
|
|||
struct {
|
||||
MlDsaKey key;
|
||||
} mldsa;
|
||||
WS_MlDsaCompositeBody mldsa_composite;
|
||||
#endif /* WOLFSSH_NO_MLDSA */
|
||||
#ifndef WOLFSSH_NO_MLDSA
|
||||
struct {
|
||||
MlDsaKey mldsa;
|
||||
union {
|
||||
#ifndef WOLFSSH_NO_ECDSA
|
||||
ecc_key ecc;
|
||||
#endif
|
||||
#ifndef WOLFSSH_NO_ED25519
|
||||
ed25519_key ed25519;
|
||||
#endif
|
||||
#ifdef HAVE_ED448
|
||||
ed448_key ed448;
|
||||
#endif
|
||||
#if defined(WOLFSSH_NO_ECDSA) && defined(WOLFSSH_NO_ED25519) && \
|
||||
!defined(HAVE_ED448)
|
||||
/* keep union non-empty (empty union rejected by some
|
||||
* compilers) though unusable without a trad component */
|
||||
byte placeholder;
|
||||
#endif
|
||||
} trad;
|
||||
} mldsa_composite;
|
||||
#endif
|
||||
} ks;
|
||||
} WS_KeySignature;
|
||||
|
||||
|
|
@ -1355,26 +1365,25 @@ typedef struct WS_KeySignature {
|
|||
#define TRAD_TYPE_ED448 3
|
||||
#define COMPOSITE_DOMAIN_PREFIX "CompositeAlgorithmSignatures2025"
|
||||
#define COMPOSITE_DOMAIN_PREFIX_SZ 32
|
||||
/* worst-case label size across all currently defined composite combos */
|
||||
/* max label size */
|
||||
#define COMPOSITE_MAX_LABEL_SZ 33
|
||||
#define ECC_P256_COORD_SZ 32
|
||||
#define ECC_P384_COORD_SZ 48
|
||||
/* worst-case trad public key size: P-384 uncompressed point */
|
||||
/* max trad pubkey size */
|
||||
#define COMPOSITE_MAX_TRAD_PUB_SZ (1 + (2 * ECC_P384_COORD_SZ))
|
||||
/* worst-case trad private key size: Ed448 seed, else P-384 scalar */
|
||||
/* max trad privkey size */
|
||||
#ifdef HAVE_ED448
|
||||
#define COMPOSITE_MAX_TRAD_PRIV_SZ ED448_KEY_SIZE
|
||||
#else
|
||||
#define COMPOSITE_MAX_TRAD_PRIV_SZ ECC_P384_COORD_SZ
|
||||
#endif
|
||||
/* worst-case trad signature size: Ed448, else P-384 raw r/s */
|
||||
/* max trad sig size */
|
||||
#ifdef HAVE_ED448
|
||||
#define COMPOSITE_MAX_TRAD_SIG_SZ ED448_SIG_SIZE
|
||||
#else
|
||||
#define COMPOSITE_MAX_TRAD_SIG_SZ (2 * ECC_P384_COORD_SZ)
|
||||
#define COMPOSITE_MAX_TRAD_SIG_SZ (2 * (LENGTH_SZ + ECC_P384_COORD_SZ + 1))
|
||||
#endif
|
||||
/* defensive slack on top of BuildUserAuthRequestMlDsaComposite()'s
|
||||
* worst-case signature size; not load-bearing */
|
||||
/* alloc slack */
|
||||
#define COMPOSITE_SIG_ALLOC_SLACK_SZ 32
|
||||
|
||||
typedef struct CompositeParams {
|
||||
|
|
@ -1390,16 +1399,17 @@ typedef struct CompositeParams {
|
|||
byte keyId;
|
||||
byte mldsaLevel;
|
||||
byte tradType;
|
||||
int eccCurveId;
|
||||
} CompositeParams;
|
||||
|
||||
/* dispatch table for a composite key's trad (ECC/Ed25519/Ed448) half; see
|
||||
* WS_GetTradOps() in src/internal.c */
|
||||
/* trad dispatch table */
|
||||
typedef struct CompositeTradOps {
|
||||
int (*init)(void* key, void* heap);
|
||||
void (*free)(void* key);
|
||||
int (*importPub)(void* key, const byte* pub, word32 pubSz);
|
||||
int (*importPriv)(void* key, const byte* priv, word32 privSz,
|
||||
const byte* pub, word32 pubSz);
|
||||
int (*exportPrivOnly)(void* key, byte* out, word32* outSz);
|
||||
int (*exportPub)(void* key, byte* out, word32* outSz);
|
||||
int (*sign)(void* key, WC_RNG* rng, void* heap,
|
||||
enum wc_HashType tradHashId, word32 tradHashSz,
|
||||
|
|
@ -1414,7 +1424,12 @@ typedef struct CompositeTradOps {
|
|||
|
||||
WOLFSSH_LOCAL int WS_GetCompositeParams(byte keyId, CompositeParams* params);
|
||||
WOLFSSH_LOCAL const CompositeTradOps* WS_GetTradOps(byte tradType);
|
||||
WOLFSSH_LOCAL int WS_Hash_Helper(enum wc_HashType hashId, const byte* msg, word32 msgSz, byte* hash, word32 hashSz);
|
||||
/* Init composite key pair */
|
||||
WOLFSSH_LOCAL int InitCompositeKeyPair(const CompositeParams* params,
|
||||
MlDsaKey* mldsa, void* tradKey, const CompositeTradOps* ops,
|
||||
void* heap, int* mldsaInit, int* tradInit);
|
||||
WOLFSSH_LOCAL int WS_Hash_Helper(enum wc_HashType hashId, const byte* msg,
|
||||
word32 msgSz, byte* hash, word32 hashSz);
|
||||
#endif
|
||||
|
||||
WOLFSSH_LOCAL int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap,
|
||||
|
|
@ -1430,6 +1445,8 @@ WOLFSSH_LOCAL int GetOpenSshPublicKey(WS_KeySignature *key,
|
|||
#ifdef WOLFSSH_CERTS
|
||||
WOLFSSH_LOCAL int IdentifyCert(const byte* in, word32 inSz, void* heap);
|
||||
#endif
|
||||
WOLFSSH_LOCAL int WS_StripOpenSshPem(const byte* in, word32 inSz,
|
||||
byte* out, word32* outSz);
|
||||
|
||||
|
||||
/* Parsing functions */
|
||||
|
|
@ -1873,8 +1890,8 @@ enum WS_MessageIdLimits {
|
|||
const byte* sigStart, word32 sigStartIdx, WS_KeySignature* keySig);
|
||||
WOLFSSH_API int wolfSSH_TestDoUserAuthRequestMlDsaComposite(WOLFSSH* ssh,
|
||||
WS_UserAuthData* authData, byte keyId, word32 pubKeyBlobSz);
|
||||
WOLFSSH_API int wolfSSH_TestPrepareUserAuthRequestMlDsaComposite(WOLFSSH* ssh,
|
||||
word32* payloadSz, const WS_UserAuthData* authData,
|
||||
WOLFSSH_API int wolfSSH_TestPrepareUserAuthRequestMlDsaComposite(
|
||||
WOLFSSH* ssh, word32* payloadSz, const WS_UserAuthData* authData,
|
||||
WS_KeySignature* keySig);
|
||||
WOLFSSH_API int wolfSSH_TestSignHMlDsaComposite(WOLFSSH* ssh, byte* sig,
|
||||
word32* sigSz, byte keyId);
|
||||
|
|
|
|||
|
|
@ -46,11 +46,7 @@ extern "C" {
|
|||
#define WOLFSSH_MLDSAKEY_65 65
|
||||
#define WOLFSSH_MLDSAKEY_87 87
|
||||
|
||||
/* Traditional algorithm paired with the ML-DSA level in a composite key.
|
||||
* Not every (level, trad) pair is a defined composite: ED25519 pairs with
|
||||
* 44/65, ED448 pairs with 87 only, ECDSA pairs with all three levels (at
|
||||
* P-256 for 44/65, P-384 for 87). See WS_GetCompositeParams() in
|
||||
* src/internal.c for the authoritative list. */
|
||||
/* Trad algo paired with ML-DSA level; see WS_GetCompositeParams(). */
|
||||
#define WOLFSSH_COMPOSITE_TRAD_ECDSA 1
|
||||
#define WOLFSSH_COMPOSITE_TRAD_ED25519 2
|
||||
#define WOLFSSH_COMPOSITE_TRAD_ED448 3
|
||||
|
|
@ -61,6 +57,7 @@ WOLFSSH_API int wolfSSH_MakeRsaKey(byte* out, word32 outSz,
|
|||
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);
|
||||
/* Generate ML-DSA composite key. out=NULL queries length. */
|
||||
WOLFSSH_API int wolfSSH_MakeMlDsaCompositeKey(byte* out, word32 outSz,
|
||||
word32 level, word32 tradType);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue