Skip to content

Commit 0b18a8b

Browse files
beldmitclaude
andcommitted
Implement ML-DSA signature algorithms per draft-sfluhrer-ssh-mldsa-06
Add ssh-mldsa-44, ssh-mldsa-65, and ssh-mldsa-87 public key algorithms using FIPS 204 (ML-DSA) via OpenSSL 3.5+ EVP API. Includes certificate variants and FIPS mode support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 53c21ce commit 0b18a8b

19 files changed

Lines changed: 745 additions & 20 deletions

Makefile.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
103103
msg.o dns.o entropy.o gss-genr.o umac.o umac128.o \
104104
smult_curve25519_ref.o \
105105
poly1305.o chacha.o cipher-chachapoly.o cipher-chachapoly-libcrypto.o \
106-
ssh-ed25519.o digest-openssl.o digest-libc.o \
106+
ssh-ed25519.o ssh-mldsa.o digest-openssl.o digest-libc.o \
107107
libcrux-mlkem-mldsa.o ssh-mldsa-eddsa.o \
108108
hmac.o ed25519.o ed25519-openssl.o \
109109
kex.o kex-names.o kexdh.o kexgex.o kexecdh.o kexc25519.o \

authfd.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,14 @@ ssh_add_identity_constrained(int sock, struct sshkey *key,
605605
case KEY_ECDSA_CERT:
606606
case KEY_ECDSA_SK:
607607
case KEY_ECDSA_SK_CERT:
608+
#ifdef OPENSSL_HAS_MLDSA
609+
case KEY_MLDSA44:
610+
case KEY_MLDSA44_CERT:
611+
case KEY_MLDSA65:
612+
case KEY_MLDSA65_CERT:
613+
case KEY_MLDSA87:
614+
case KEY_MLDSA87_CERT:
615+
#endif
608616
#endif
609617
case KEY_ED25519:
610618
case KEY_ED25519_CERT:

configure.ac

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515

16-
AC_INIT([OpenSSH], [Portable], [openssh-unix-dev@mindrot.org])
16+
AC_INIT([OpenSSH],[Portable],[openssh-unix-dev@mindrot.org])
1717
AC_CONFIG_MACRO_DIR([m4])
1818
AC_CONFIG_SRCDIR([ssh.c])
1919

@@ -845,29 +845,22 @@ int main(void) { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
845845
AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
846846
[Prepend the address family to IP tunnel traffic])
847847
AC_MSG_CHECKING([if we have the Security Authorization Session API])
848-
AC_TRY_COMPILE([#include <Security/AuthSession.h>],
849-
[SessionCreate(0, 0);],
850-
[ac_cv_use_security_session_api="yes"
848+
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <Security/AuthSession.h>]], [[SessionCreate(0, 0);]])],[ac_cv_use_security_session_api="yes"
851849
AC_DEFINE([USE_SECURITY_SESSION_API], [1],
852850
[platform has the Security Authorization Session API])
853851
LIBS="$LIBS -framework Security"
854-
AC_MSG_RESULT([yes])],
855-
[ac_cv_use_security_session_api="no"
852+
AC_MSG_RESULT([yes])],[ac_cv_use_security_session_api="no"
856853
AC_MSG_RESULT([no])])
857854
AC_MSG_CHECKING([if we have an in-memory credentials cache])
858-
AC_TRY_COMPILE(
859-
[#include <Kerberos/Kerberos.h>],
860-
[cc_context_t c;
861-
(void) cc_initialize (&c, 0, NULL, NULL);],
862-
[AC_DEFINE([USE_CCAPI], [1],
855+
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <Kerberos/Kerberos.h>]], [[cc_context_t c;
856+
(void) cc_initialize (&c, 0, NULL, NULL);]])],[AC_DEFINE([USE_CCAPI], [1],
863857
[platform uses an in-memory credentials cache])
864858
LIBS="$LIBS -framework Security"
865859
AC_MSG_RESULT([yes])
866860
if test "x$ac_cv_use_security_session_api" = "xno"; then
867861
AC_MSG_ERROR([*** Need a security framework to use the credentials cache API ***])
868-
fi],
869-
[AC_MSG_RESULT([no])]
870-
)
862+
fi],[AC_MSG_RESULT([no])
863+
])
871864
m4_pattern_allow([AU_IPv])
872865
AC_CHECK_DECL([AU_IPv4], [],
873866
AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
@@ -3485,6 +3478,26 @@ if test "x$openssl" = "xyes" ; then
34853478
AC_MSG_RESULT([no])
34863479
]
34873480
)
3481+
3482+
AC_MSG_CHECKING([whether OpenSSL has ML-DSA support])
3483+
AC_LINK_IFELSE(
3484+
[AC_LANG_PROGRAM([[
3485+
#include <openssl/evp.h>
3486+
]], [[
3487+
EVP_PKEY_CTX *ctx;
3488+
ctx = EVP_PKEY_CTX_new_from_name(NULL, "ML-DSA-44", NULL);
3489+
if (ctx == NULL) return 1;
3490+
EVP_PKEY_CTX_free(ctx);
3491+
]])],
3492+
[
3493+
AC_MSG_RESULT([yes])
3494+
AC_DEFINE([OPENSSL_HAS_MLDSA], [1],
3495+
[libcrypto has ML-DSA support])
3496+
],
3497+
[
3498+
AC_MSG_RESULT([no])
3499+
]
3500+
)
34883501
fi
34893502

34903503
# PKCS11/U2F depend on OpenSSL and dlopen().

myproposal.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,13 @@
6060
"sk-ecdsa-sha2-nistp256@openssh.com," \
6161
"webauthn-sk-ecdsa-sha2-nistp256@openssh.com," \
6262
"rsa-sha2-512," \
63-
"rsa-sha2-256"
63+
"rsa-sha2-256," \
64+
"ssh-mldsa-44-cert-v01@openssh.com," \
65+
"ssh-mldsa-65-cert-v01@openssh.com," \
66+
"ssh-mldsa-87-cert-v01@openssh.com," \
67+
"ssh-mldsa-44," \
68+
"ssh-mldsa-65," \
69+
"ssh-mldsa-87"
6470

6571
#define KEX_FIPS_PK_ALG \
6672
"ecdsa-sha2-nistp256-cert-v01@openssh.com," \
@@ -72,7 +78,13 @@
7278
"ecdsa-sha2-nistp384," \
7379
"ecdsa-sha2-nistp521," \
7480
"rsa-sha2-512," \
75-
"rsa-sha2-256"
81+
"rsa-sha2-256," \
82+
"ssh-mldsa-44-cert-v01@openssh.com," \
83+
"ssh-mldsa-65-cert-v01@openssh.com," \
84+
"ssh-mldsa-87-cert-v01@openssh.com," \
85+
"ssh-mldsa-44," \
86+
"ssh-mldsa-65," \
87+
"ssh-mldsa-87"
7688

7789
#define KEX_SERVER_ENCRYPT \
7890
"chacha20-poly1305@openssh.com," \

pathnames.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
#define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key"
4141
#define _PATH_HOST_ED25519_KEY_FILE SSHDIR "/ssh_host_ed25519_key"
4242
#define _PATH_HOST_MLDSA44_ED25519_KEY_FILE SSHDIR "/ssh_host_mldsa44_ed25519_key"
43+
#define _PATH_HOST_MLDSA44_KEY_FILE SSHDIR "/ssh_host_mldsa44_key"
44+
#define _PATH_HOST_MLDSA65_KEY_FILE SSHDIR "/ssh_host_mldsa65_key"
45+
#define _PATH_HOST_MLDSA87_KEY_FILE SSHDIR "/ssh_host_mldsa87_key"
4346
#define _PATH_DH_MODULI SSHDIR "/moduli"
4447
#define _PATH_SCP_KILL_SWITCH SSHDIR "/disable_scp"
4548

@@ -93,6 +96,9 @@
9396
#define _PATH_SSH_CLIENT_ID_ECDSA_SK _PATH_SSH_USER_DIR "/id_ecdsa_sk"
9497
#define _PATH_SSH_CLIENT_ID_ED25519_SK _PATH_SSH_USER_DIR "/id_ed25519_sk"
9598
#define _PATH_SSH_CLIENT_ID_MLDSA44_ED25519 _PATH_SSH_USER_DIR "/id_mldsa44_ed25519"
99+
#define _PATH_SSH_CLIENT_ID_MLDSA44 _PATH_SSH_USER_DIR "/id_mldsa44"
100+
#define _PATH_SSH_CLIENT_ID_MLDSA65 _PATH_SSH_USER_DIR "/id_mldsa65"
101+
#define _PATH_SSH_CLIENT_ID_MLDSA87 _PATH_SSH_USER_DIR "/id_mldsa87"
96102

97103
/*
98104
* Configuration file in user's home directory. This file need not be

regress/cert-userkey.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ kname() {
3636
sk-ecdsa-*) n="sk-ecdsa" ;;
3737
sk-ssh-ed25519*) n="sk-ssh-ed25519" ;;
3838
ssh-mldsa*) n=`echo "$1" | sed 's/@.*//'` ;;
39+
mldsa-*) n="ssh-$1" ;;
3940
# subshell because some seds will add a newline
4041
*) n=$(echo $1 | sed 's/^rsa/ssh-rsa/;s/^ed/ssh-ed/') ;;
4142
esac

regress/hostkey-agent.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ echo "UpdateHostkeys=yes" >> $OBJ/ssh_proxy
108108
echo "GlobalKnownHostsFile=none" >> $OBJ/ssh_proxy
109109

110110
HOSTKEYALGS=""
111-
for k in $SSH_KEYTYPES ; do
111+
for k in $SSH_ACCEPTED_KEYTYPES ; do
112112
verbose "Addkey type $k"
113113
echo "Hostkey $OBJ/agent-key.${k}" >> $OBJ/sshd_proxy
114114
test -z "$HOSTKEYALGS" || HOSTKEYALGS="${HOSTKEYALGS},"

regress/keygen-comment.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ for fmt in '' RFC4716 PKCS8 PEM; do
3131
# stored in old formats.
3232
case "$t" in
3333
ssh-ed25519|*openssh.com) test -z "$oldfmt" || continue ;;
34+
ssh-mldsa-*) test "$fmt" = "PEM" && continue ;;
3435
esac
3536
comment="foo bar"
3637
fmtarg=""

regress/keytype.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ for i in ${SSH_KEYTYPES}; do
1818
sk-ssh-ed25519*) ktypes="$ktypes ed25519-sk" ;;
1919
sk-ecdsa-sha2-nistp256*) ktypes="$ktypes ecdsa-sk" ;;
2020
ssh-mldsa44-ed25519*) ktypes="$ktypes mldsa44-ed25519" ;;
21+
ssh-mldsa-44) ktypes="$ktypes mldsa-44" ;;
22+
ssh-mldsa-65) ktypes="$ktypes mldsa-65" ;;
23+
ssh-mldsa-87) ktypes="$ktypes mldsa-87" ;;
2124
esac
2225
done
2326

@@ -44,6 +47,9 @@ kname_to_ktype() {
4447
ed25519-sk) echo sk-ssh-ed25519@openssh.com;;
4548
ecdsa-sk) echo sk-ecdsa-sha2-nistp256@openssh.com;;
4649
mldsa44-ed25519) echo ssh-mldsa44-ed25519@openssh.com ;;
50+
mldsa-44) echo ssh-mldsa-44;;
51+
mldsa-65) echo ssh-mldsa-65;;
52+
mldsa-87) echo ssh-mldsa-87;;
4753
esac
4854
}
4955

regress/krl.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ for t in $SSH_KEYTYPES; do
1111
case "$t" in
1212
ecdsa*) ktype2=ecdsa ;;
1313
ssh-rsa) ktype3=rsa ;;
14+
ssh-mldsa-44) ktype4=mldsa-44 ;;
1415
sk-ssh-ed25519@openssh.com) ktype5=ed25519-sk ;;
1516
sk-ecdsa-sha2-nistp256@openssh.com) ktype6=ecdsa-sk ;;
1617
esac

0 commit comments

Comments
 (0)