#
# Dynamically set FIPS mode, when underlying libcrypto is FIPS capable.
# Limit ciphers and MACs in algorithm negotiation proposal.
#
# This patch is unlikely to be accepted upstream.
#
diff -pur old/cipher.c new/cipher.c
--- old/cipher.c
+++ new/cipher.c
@@ -77,7 +77,34 @@ struct sshcipher {
#endif
};
+#ifdef ENABLE_OPENSSL_FIPS
+/* in FIPS mode limit ciphers to FIPS compliant only */
+#define ciphers (ssh_FIPS_mode() ? ciphers_fips : ciphers_dflt)
+
+static const struct sshcipher ciphers_fips[] = {
+ { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
+ { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc },
+ { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 1, EVP_aes_128_cbc },
+ { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 1, EVP_aes_192_cbc },
+ { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc },
+ { "rijndael-cbc@lysator.liu.se",
+ SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc },
+ { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr },
+ { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr },
+ { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr },
+# ifdef OPENSSL_HAVE_EVPGCM
+ { "aes128-gcm@openssh.com",
+ SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm },
+ { "aes256-gcm@openssh.com",
+ SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm },
+# endif /* OPENSSL_HAVE_EVPGCM */
+ { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL }
+};
+
+static const struct sshcipher ciphers_dflt[] = {
+#else /* ENABLE_OPENSSL_FIPS */
static const struct sshcipher ciphers[] = {
+#endif /* ENABLE_OPENSSL_FIPS */
#ifdef WITH_SSH1
{ "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc },
{ "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des },
diff -pur old/digest-openssl.c new/digest-openssl.c
--- old/digest-openssl.c
+++ new/digest-openssl.c
@@ -31,6 +31,7 @@
#include "sshbuf.h"
#include "digest.h"
#include "ssherr.h"
+#include "misc.h"
#ifndef HAVE_EVP_RIPEMD160
# define EVP_ripemd160 NULL
@@ -53,8 +54,22 @@ struct ssh_digest {
const EVP_MD *(*mdfunc)(void);
};
+#ifdef ENABLE_OPENSSL_FIPS
/* NB. Indexed directly by algorithm number */
+const struct ssh_digest digests_fips[] = {
+ { SSH_DIGEST_MD5, "", 16, NULL },
+ { SSH_DIGEST_RIPEMD160, "", 20, NULL },
+ { SSH_DIGEST_SHA1, "SHA1", 20, EVP_sha1 },
+ { SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 },
+ { SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 },
+ { SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 },
+ { -1, NULL, 0, NULL },
+};
+/* NB. Indexed directly by algorithm number */
+const struct ssh_digest digests_dflt[] = {
+#else /* ENABLE_OPENSSL_FIPS */
const struct ssh_digest digests[] = {
+#endif /* ENABLE_OPENSSL_FIPS */
{ SSH_DIGEST_MD5, "MD5", 16, EVP_md5 },
{ SSH_DIGEST_RIPEMD160, "RIPEMD160", 20, EVP_ripemd160 },
{ SSH_DIGEST_SHA1, "SHA1", 20, EVP_sha1 },
@@ -67,6 +82,9 @@ const struct ssh_digest digests[] = {
static const struct ssh_digest *
ssh_digest_by_alg(int alg)
{
+#ifdef ENABLE_OPENSSL_FIPS
+ struct ssh_digest *digests = ssh_FIPS_mode() ? digests_fips : digests_dflt;
+#endif
if (alg < 0 || alg >= SSH_DIGEST_MAX)
return NULL;
if (digests[alg].id != alg) /* sanity */
@@ -79,6 +97,9 @@ ssh_digest_by_alg(int alg)
int
ssh_digest_alg_by_name(const char *name)
{
+#ifdef ENABLE_OPENSSL_FIPS
+ struct ssh_digest *digests = ssh_FIPS_mode() ? digests_fips : digests_dflt;
+#endif
int alg;
for (alg = 0; digests[alg].id != -1; alg++) {
diff -pur old/gss-genr.c new/gss-genr.c
--- old/gss-genr.c
+++ new/gss-genr.c
@@ -44,6 +44,7 @@
#include "cipher.h"
#include "key.h"
#include "kex.h"
+#include "misc.h"
#include <openssl/evp.h>
#include "ssh-gss.h"
@@ -100,6 +101,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup
char deroid[2];
const EVP_MD *evp_md = EVP_md5();
EVP_MD_CTX md;
+ int fips_mode;
if (gss_enc2oid != NULL) {
for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
@@ -112,6 +114,14 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup
buffer_init(&buf);
+#ifdef ENABLE_OPENSSL_FIPS
+ fips_mode = ssh_FIPS_mode();
+ if (fips_mode) {
+ debug3("Temporarily unsetting FIPS mode to compute MD5 for "
+ "GSS-API key exchange method names");
+ FIPS_mode_set(0);
+ }
+#endif
oidpos = 0;
for (i = 0; i < gss_supported->count; i++) {
if (gss_supported->elements[i].length < 128 &&
@@ -119,7 +129,6 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup
deroid[0] = SSH_GSS_OIDTYPE;
deroid[1] = gss_supported->elements[i].length;
-
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, deroid, 2);
EVP_DigestUpdate(&md,
@@ -151,6 +160,12 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup
oidpos++;
}
}
+#ifdef ENABLE_OPENSSL_FIPS
+ if (fips_mode) {
+ ssh_FIPS_mode_set_if_capable();
+ ssh_FIPS_check_status();
+ }
+#endif
gss_enc2oid[oidpos].oid = NULL;
gss_enc2oid[oidpos].encoded = NULL;
diff -pur old/kex.c new/kex.c
--- old/kex.c
+++ new/kex.c
@@ -90,7 +90,43 @@ struct kexalg {
int ec_nid;
int hash_alg;
};
+
+#ifdef ENABLE_OPENSSL_FIPS
+/* in FIPS mode limit kexalgs to FIPS compliant only */
+#define kexalgs (ssh_FIPS_mode() ? kexalgs_fips : kexalgs_dflt)
+static const struct kexalg kexalgs_fips[] = {
+#ifdef WITH_OPENSSL
+ { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
+ { KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
+ { KEX_DH14_SHA256, KEX_DH_GRP14_SHA256, 0, SSH_DIGEST_SHA256 },
+ { KEX_DH16_SHA512, KEX_DH_GRP16_SHA512, 0, SSH_DIGEST_SHA512 },
+ { KEX_DH18_SHA512, KEX_DH_GRP18_SHA512, 0, SSH_DIGEST_SHA512 },
+ { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
+#ifdef HAVE_EVP_SHA256
+ { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
+#endif /* HAVE_EVP_SHA256 */
+#ifdef OPENSSL_HAS_ECC
+ { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,
+ NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
+ { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1,
+ SSH_DIGEST_SHA384 },
+# ifdef OPENSSL_HAS_NISTP521
+ { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
+ SSH_DIGEST_SHA512 },
+# endif /* OPENSSL_HAS_NISTP521 */
+#endif /* OPENSSL_HAS_ECC */
+#endif /* WITH_OPENSSL */
+#ifdef GSSAPI
+ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
+ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
+ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
+#endif
+ { NULL, -1, -1, -1},
+};
+static const struct kexalg kexalgs_dflt[] = {
+#else
static const struct kexalg kexalgs[] = {
+#endif
#ifdef WITH_OPENSSL
{ KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
{ KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
diff -pur old/mac.c new/mac.c
--- old/mac.c
+++ new/mac.c
@@ -53,8 +53,33 @@ struct macalg {
int len; /* just for UMAC */
int etm; /* Encrypt-then-MAC */
};
+#ifdef ENABLE_OPENSSL_FIPS
+/* in FIPS mode limit macs to FIPS compliant only */
+#define macs (ssh_FIPS_mode() ? macs_fips : macs_dflt)
+static const struct macalg macs_fips[] = {
+ /* Encrypt-and-MAC (encrypt-and-authenticate) variants */
+ { "hmac-sha1", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 },
+ { "hmac-sha1-96", SSH_DIGEST, SSH_DIGEST_SHA1, 96, 0, 0, 0 },
+#ifdef HAVE_EVP_SHA256
+ { "hmac-sha2-256", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 0 },
+ { "hmac-sha2-512", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 0 },
+#endif
+ /* Encrypt-then-MAC variants */
+ { "hmac-sha1-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 1 },
+ { "hmac-sha1-96-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA1, 96, 0, 0, 1 },
+#ifdef HAVE_EVP_SHA256
+ { "hmac-sha2-256-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 1 },
+ { "hmac-sha2-512-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 1 },
+#endif
+
+ { NULL, 0, 0, 0, 0, 0, 0 }
+};
+
+static const struct macalg macs_dflt[] = {
+#else /* ENABLE_OPENSSL_FIPS */
static const struct macalg macs[] = {
+#endif /* ENABLE_OPENSSL_FIPS */
/* Encrypt-and-MAC (encrypt-and-authenticate) variants */
{ "hmac-sha1", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 },
{ "hmac-sha1-96", SSH_DIGEST, SSH_DIGEST_SHA1, 96, 0, 0, 0 },
diff -pur old/misc.c new/misc.c
--- old/misc.c
+++ new/misc.c
@@ -39,12 +39,16 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <dlfcn.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -78,6 +82,60 @@ chop(char *s)
}
+#ifdef ENABLE_OPENSSL_FIPS
+/* is OpenSSL FIPS mode set? */
+int
+ssh_FIPS_mode()
+{
+ return FIPS_mode();
+}
+
+/* store FIPS_mode_set() err code */
+static unsigned long ssh_FIPS_err_code = 0;
+
+#define MSGBUFSIZ 1024 /* equals log.c:MSGBUFSIZ */
+
+/*
+ * Check and display FIPS mode status.
+ * Called after ssh_FIPS_mode_set_if_capable() and when logging facility is
+ * available.
+ * If FIPS_mode_failed for FIPS capable libcrypto, exits with 255 code.
+ */
+void
+ssh_FIPS_check_status()
+{
+ char ebuf[MSGBUFSIZ];
+
+ if (dlsym(RTLD_DEFAULT, "FIPS_module_mode_set") != NULL) {
+ if (ssh_FIPS_mode()) {
+ debug("Running in FIPS mode.");
+ } else {
+ ERR_error_string_n(ssh_FIPS_err_code, ebuf,
+ sizeof (ebuf));
+ fatal("Setting FIPS mode failed! %s", ebuf);
+ }
+ } else {
+ debug3("Loaded libcrypto is not FIPS capable.");
+ }
+
+}
+
+/* if underlying libcrypto is FIPS capable, set FIPS_mode to 1 */
+int
+ssh_FIPS_mode_set_if_capable()
+{
+ /* presence of FIPS_module_mode_set indicates FIPS capable OpenSSL */
+ if (dlsym(RTLD_DEFAULT, "FIPS_module_mode_set") != NULL) {
+ /* call the API function FIPS_mode_set*/
+ if (!FIPS_mode_set(1)) {
+ ssh_FIPS_err_code = ERR_get_error();
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
/* set/unset filedescriptor to non-blocking */
int
set_nonblock(int fd)
diff -pur old/misc.h new/misc.h
--- old/misc.h
+++ new/misc.h
@@ -40,6 +40,11 @@ struct ForwardOptions {
char *chop(char *);
char *strdelim(char **);
+#ifdef ENABLE_OPENSSL_FIPS
+int ssh_FIPS_mode();
+int ssh_FIPS_mode_set_if_capable();
+void ssh_FIPS_check_status();
+#endif
int set_nonblock(int);
int unset_nonblock(int);
void set_nodelay(int);
diff -pur old/myproposal.h new/myproposal.h
--- old/myproposal.h
+++ new/myproposal.h
@@ -88,21 +88,33 @@
# else
# define KEX_CURVE25519_METHODS ""
# endif
-#define KEX_COMMON_KEX \
+
+#define KEX_COMMON_KEX_DFLT \
KEX_CURVE25519_METHODS \
KEX_ECDH_METHODS \
KEX_SHA2_METHODS
-#define KEX_SERVER_KEX KEX_COMMON_KEX \
+#define KEX_SERVER_KEX_DFLT KEX_COMMON_KEX_DFLT \
KEX_SHA2_GROUP14 \
"diffie-hellman-group14-sha1" \
-#define KEX_CLIENT_KEX KEX_COMMON_KEX \
+#define KEX_CLIENT_KEX_DFLT KEX_COMMON_KEX_DFLT \
"diffie-hellman-group-exchange-sha1," \
KEX_SHA2_GROUP14 \
"diffie-hellman-group14-sha1"
-#define KEX_DEFAULT_PK_ALG \
+#define KEX_COMMON_KEX_FIPS \
+ KEX_ECDH_METHODS \
+ KEX_SHA2_METHODS
+
+#define KEX_SERVER_KEX_FIPS KEX_COMMON_KEX_FIPS \
+ "diffie-hellman-group14-sha1" \
+
+#define KEX_CLIENT_KEX_FIPS KEX_COMMON_KEX_FIPS \
+ "diffie-hellman-group-exchange-sha1," \
+ "diffie-hellman-group14-sha1"
+
+#define KEX_DEFAULT_PK_ALG_DFLT \
HOSTKEY_ECDSA_CERT_METHODS \
"ssh-ed25519-cert-v01@openssh.com," \
"ssh-rsa-cert-v01@openssh.com," \
@@ -112,17 +124,32 @@
"rsa-sha2-256," \
"ssh-rsa"
+#define KEX_DEFAULT_PK_ALG_FIPS \
+ HOSTKEY_ECDSA_CERT_METHODS \
+ "ssh-rsa-cert-v01@openssh.com," \
+ HOSTKEY_ECDSA_METHODS \
+ "rsa-sha2-512," \
+ "rsa-sha2-256," \
+ "ssh-rsa"
+
/* the actual algorithms */
-#define KEX_SERVER_ENCRYPT \
+#define KEX_SERVER_ENCRYPT_DFLT \
"chacha20-poly1305@openssh.com," \
"aes128-ctr,aes192-ctr,aes256-ctr" \
AESGCM_CIPHER_MODES
-#define KEX_CLIENT_ENCRYPT KEX_SERVER_ENCRYPT "," \
+#define KEX_CLIENT_ENCRYPT_DFLT KEX_SERVER_ENCRYPT_DFLT "," \
+ "aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc"
+
+#define KEX_SERVER_ENCRYPT_FIPS \
+ "aes128-ctr,aes192-ctr,aes256-ctr" \
+ AESGCM_CIPHER_MODES
+
+#define KEX_CLIENT_ENCRYPT_FIPS KEX_SERVER_ENCRYPT_FIPS "," \
"aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc"
-#define KEX_SERVER_MAC \
+#define KEX_SERVER_MAC_DFLT \
"umac-64-etm@openssh.com," \
"umac-128-etm@openssh.com," \
"hmac-sha2-256-etm@openssh.com," \
@@ -134,7 +161,42 @@
"hmac-sha2-512," \
"hmac-sha1"
-#define KEX_CLIENT_MAC KEX_SERVER_MAC
+#define KEX_CLIENT_MAC_DFLT KEX_SERVER_MAC_DFLT
+
+#define KEX_SERVER_MAC_FIPS \
+ "hmac-sha2-256-etm@openssh.com," \
+ "hmac-sha2-512-etm@openssh.com," \
+ "hmac-sha1-etm@openssh.com," \
+ "hmac-sha2-256," \
+ "hmac-sha2-512," \
+ "hmac-sha1"
+
+#define KEX_CLIENT_MAC_FIPS KEX_SERVER_MAC_FIPS
+
+#ifdef ENABLE_OPENSSL_FIPS
+ #define KEX_SERVER_KEX \
+ (ssh_FIPS_mode() ? (KEX_SERVER_KEX_FIPS) : (KEX_SERVER_KEX_DFLT) )
+ #define KEX_CLIENT_KEX \
+ (ssh_FIPS_mode() ? (KEX_CLIENT_KEX_FIPS) : (KEX_CLIENT_KEX_DFLT) )
+ #define KEX_DEFAULT_PK_ALG \
+ (ssh_FIPS_mode() ? (KEX_DEFAULT_PK_ALG_FIPS) : (KEX_DEFAULT_PK_ALG_DFLT) )
+ #define KEX_SERVER_ENCRYPT \
+ (ssh_FIPS_mode() ? (KEX_SERVER_ENCRYPT_FIPS) : (KEX_SERVER_ENCRYPT_DFLT))
+ #define KEX_CLIENT_ENCRYPT \
+ (ssh_FIPS_mode() ? (KEX_CLIENT_ENCRYPT_FIPS) : (KEX_CLIENT_ENCRYPT_DFLT))
+ #define KEX_SERVER_MAC \
+ (ssh_FIPS_mode() ? (KEX_SERVER_MAC_FIPS) : (KEX_SERVER_MAC_DFLT) )
+ #define KEX_CLIENT_MAC \
+ (ssh_FIPS_mode() ? (KEX_CLIENT_MAC_FIPS) : (KEX_CLIENT_MAC_DFLT) )
+#else /* ENABLE_OPENSSL_FIPS */
+ #define KEX_SERVER_KEX KEX_SERVER_KEX_DFLT
+ #define KEX_CLIENT_KEX KEX_CLIENT_KEX_DFLT
+ #define KEX_DEFAULT_PK_ALG KEX_DEFAULT_PK_ALG_DFLT
+ #define KEX_SERVER_ENCRYPT KEX_SERVER_ENCRYPT_DFLT
+ #define KEX_CLIENT_ENCRYPT KEX_CLIENT_ENCRYPT_DFLT
+ #define KEX_SERVER_MAC KEX_SERVER_MAC_DFLT
+ #define KEX_CLIENT_MAC KEX_CLIENT_MAC_DFLT
+#endif /* ENABLE_OPENSSL_FIPS */
#else /* WITH_OPENSSL */
diff -pur old/ssh-add.1 new/ssh-add.1
--- old/ssh-add.1
+++ new/ssh-add.1
@@ -116,6 +116,8 @@ and
.Dq sha256 .
The default is
.Dq sha256 .
+If OpenSSL is running in FIPS-140 mode, the only supported option is
+.Dq sha256 .
.It Fl e Ar pkcs11
Remove keys provided by the PKCS#11 shared library
.Ar pkcs11 .
diff -pur old/ssh-add.c new/ssh-add.c
--- old/ssh-add.c
+++ new/ssh-add.c
@@ -488,6 +488,12 @@ main(int argc, char **argv)
__progname = ssh_get_progname(argv[0]);
seed_rng();
+#ifdef ENABLE_OPENSSL_FIPS
+ if (ssh_FIPS_mode_set_if_capable()) {
+ fprintf(stderr, "Setting FIPS mode failed!");
+ exit(1);
+ }
+#endif
#ifdef WITH_OPENSSL
OpenSSL_add_all_algorithms();
#endif
diff -pur old/ssh-agent.1 new/ssh-agent.1
--- old/ssh-agent.1
+++ new/ssh-agent.1
@@ -117,6 +117,8 @@ and
.Dq sha256 .
The default is
.Dq sha256 .
+If OpenSSL is running in FIPS-140 mode, the only supported option is
+.Dq sha256 .
.It Fl k
Kill the current agent (given by the
.Ev SSH_AGENT_PID
diff -pur old/ssh-agent.c new/ssh-agent.c
--- old/ssh-agent.c
+++ new/ssh-agent.c
@@ -1196,6 +1196,7 @@ main(int ac, char **av)
struct timeval *tvp = NULL;
size_t len;
mode_t prev_mask;
+ int fips_err;
ssh_malloc_init(); /* must be called before any mallocs */
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
@@ -1207,6 +1208,9 @@ main(int ac, char **av)
platform_disable_tracing(0); /* strict=no */
+#ifdef ENABLE_OPENSSL_FIPS
+ fips_err = ssh_FIPS_mode_set_if_capable();
+#endif
#ifdef WITH_OPENSSL
OpenSSL_add_all_algorithms();
#endif
@@ -1337,8 +1341,19 @@ main(int ac, char **av)
printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
SSH_AUTHSOCKET_ENV_NAME);
printf("echo Agent pid %ld;\n", (long)parent_pid);
+#ifdef ENABLE_OPENSSL_FIPS
+ ssh_FIPS_check_status();
+#endif
fflush(stdout);
goto skip;
+#ifdef ENABLE_OPENSSL_FIPS
+ } else {
+ /* we still need to error out on FIPS_mode_set failure */
+ if (fips_err) {
+ fprintf(stderr, "Setting FIPS mode failed!");
+ cleanup_exit(1);
+ }
+#endif
}
pid = fork();
if (pid == -1) {
diff -pur old/ssh-keygen.1 new/ssh-keygen.1
--- old/ssh-keygen.1
+++ new/ssh-keygen.1
@@ -284,6 +284,8 @@ and
.Dq sha256 .
The default is
.Dq sha256 .
+If OpenSSL is running in FIPS-140 mode, the only supported option is
+.Dq sha256 .
.It Fl e
This option will read a private or public OpenSSH key file and
print to stdout the key in one of the formats specified by the
diff -pur old/ssh-keygen.c new/ssh-keygen.c
--- old/ssh-keygen.c
+++ new/ssh-keygen.c
@@ -2273,11 +2273,18 @@ main(int argc, char **argv)
__progname = ssh_get_progname(argv[0]);
+#ifdef ENABLE_OPENSSL_FIPS
+ ssh_FIPS_mode_set_if_capable();
+#endif
#ifdef WITH_OPENSSL
OpenSSL_add_all_algorithms();
#endif
log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
+#ifdef ENABLE_OPENSSL_FIPS
+ ssh_FIPS_check_status();
+#endif
+
seed_rng();
/* we need this for the home * directory. */
diff -pur old/ssh-keysign.c new/ssh-keysign.c
--- old/ssh-keysign.c
+++ new/ssh-keysign.c
@@ -178,6 +178,7 @@ main(int argc, char **argv)
u_char *signature, *data, rver;
char *host, *fp;
size_t slen, dlen;
+ int fips_err;
#ifdef WITH_OPENSSL
u_int32_t rnd[256];
#endif
@@ -228,6 +229,16 @@ main(int argc, char **argv)
if (found == 0)
fatal("could not open any host key");
+#ifdef ENABLE_OPENSSL_FIPS
+ fips_err = ssh_FIPS_mode_set_if_capable();
+#ifdef DEBUG_SSH_KEYSIGN
+ ssh_FIPS_check_status();
+#else
+ /* we still need to error out on FIPS_mode_set failure */
+ if (fips_err)
+ fatal("Setting FIPS mode failed!");
+#endif
+#endif
#ifdef WITH_OPENSSL
OpenSSL_add_all_algorithms();
arc4random_buf(rnd, sizeof(rnd));
diff -pur old/ssh.1 new/ssh.1
--- old/ssh.1
+++ new/ssh.1
@@ -92,6 +92,9 @@ If
is specified,
it is executed on the remote host instead of a login shell.
.Pp
+If ssh links with FIPS-capable OpenSSL, ssh runs in FIPS-140 mode.
+In FIPS-140 mode non-FIPS approved ciphers, MACs and digests are disabled.
+.Pp
The options are as follows:
.Pp
.Bl -tag -width Ds -compact
diff -pur old/ssh.c new/ssh.c
--- old/ssh.c
+++ new/ssh.c
@@ -609,6 +609,11 @@ main(int ac, char **av)
*/
initialize_options(&options);
+#ifdef ENABLE_OPENSSL_FIPS
+ /* determine FIPS mode early to limit ciphers and macs */
+ ssh_FIPS_mode_set_if_capable();
+#endif
+
/* Parse command-line arguments. */
host = NULL;
use_syslog = 0;
@@ -1028,6 +1033,10 @@ main(int ac, char **av)
#endif
);
+#ifdef ENABLE_OPENSSL_FIPS
+ ssh_FIPS_check_status();
+#endif
+
/* Parse the configuration files */
process_config_files(host_arg, pw, 0);
diff -pur old/ssh_api.c new/ssh_api.c
--- old/ssh_api.c
+++ new/ssh_api.c
@@ -79,6 +79,10 @@ ssh_init(struct ssh **sshp, int is_serve
int r;
if (!called) {
+#ifdef ENABLE_OPENSSL_FIPS
+ ssh_FIPS_mode_set_if_capable();
+ ssh_FIPS_check_status();
+#endif
#ifdef WITH_OPENSSL
OpenSSL_add_all_algorithms();
#endif /* WITH_OPENSSL */
diff -pur old/ssh_config.5 new/ssh_config.5
--- old/ssh_config.5
+++ new/ssh_config.5
@@ -489,6 +489,13 @@ aes128-gcm@openssh.com,aes256-gcm@openss
aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc
.Ed
.Pp
+The following ciphers are FIPS-140 approved and are supported in FIPS-140 mode:
+.Bd -literal -offset indent
+aes128-ctr,aes192-ctr,aes256-ctr,
+aes128-gcm@openssh.com,aes256-gcm@openssh.com,
+aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc
+.Ed
+.Pp
The list of available ciphers may also be obtained using the
.Fl Q
option of
@@ -738,6 +745,8 @@ and
.Dq sha256 .
The default is
.Dq sha256 .
+In FIPS-140 mode the only supported option is
+.Dq sha256 .
.It Cm ForwardAgent
Specifies whether the connection to the authentication agent (if any)
will be forwarded to the remote machine.
@@ -1249,6 +1258,16 @@ umac-64@openssh.com,umac-128@openssh.com
hmac-sha2-256,hmac-sha2-512,hmac-sha1
.Ed
.Pp
+The following MACs are FIPS-140 approved and are supported in FIPS-140 mode:
+.Bd -literal -offset indent
+hmac-sha2-256-etm@openssh.com,
+hmac-sha2-512-etm@openssh.com,
+hmac-sha2-256,hmac-sha2-512,
+hmac-sha1-etm@openssh.com,
+hmac-sha1-96-etm@openssh.com
+hmac-sha1,hmac-sha1-96
+.Ed
+.Pp
The list of available MAC algorithms may also be obtained using the
.Fl Q
option of
diff -pur old/sshconnect.c new/sshconnect.c
--- old/sshconnect.c
+++ new/sshconnect.c
@@ -530,8 +530,14 @@ send_client_banner(int connection_out, i
{
/* Send our own protocol version identification. */
if (compat20) {
+#ifdef ENABLE_OPENSSL_FIPS
+ xasprintf(&client_version_string, "SSH-%d.%d-%.100s%s\r\n",
+ PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION,
+ ssh_FIPS_mode() ? " FIPS" : "");
+#else
xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n",
PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION);
+#endif
} else {
xasprintf(&client_version_string, "SSH-%d.%d-%.100s\n",
PROTOCOL_MAJOR_1, minor1, SSH_VERSION);
diff -pur old/sshd.8 new/sshd.8
--- old/sshd.8
+++ new/sshd.8
@@ -86,6 +86,9 @@ rereads its configuration file when it r
by executing itself with the name and options it was started with, e.g.\&
.Pa /usr/sbin/sshd .
.Pp
+If sshd links with FIPS-capable OpenSSL, sshd runs in FIPS-140 mode.
+In FIPS-140 mode non-FIPS approved ciphers, MACs and digests are disabled.
+.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl 4
diff -pur old/sshd.c new/sshd.c
--- old/sshd.c
+++ new/sshd.c
@@ -431,10 +431,18 @@ sshd_exchange_identification(struct ssh
minor = PROTOCOL_MINOR_1;
}
+#ifdef ENABLE_OPENSSL_FIPS
+ xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s%s",
+ major, minor, SSH_VERSION,
+ ssh_FIPS_mode() ? " FIPS" : " ",
+ *options.version_addendum == '\0' ? "" : " ",
+ options.version_addendum, newline);
+#else
xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s",
major, minor, SSH_VERSION,
*options.version_addendum == '\0' ? "" : " ",
options.version_addendum, newline);
+#endif
/* Send our protocol version identification. */
if (atomicio(vwrite, sock_out, server_version_string,
@@ -1562,6 +1570,10 @@ main(int ac, char **av)
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
+#ifdef ENABLE_OPENSSL_FIPS
+ ssh_FIPS_mode_set_if_capable();
+#endif
+
/* Initialize configuration options to their default values. */
initialize_server_options(&options);
@@ -1712,6 +1724,10 @@ main(int ac, char **av)
SYSLOG_FACILITY_AUTH : options.log_facility,
log_stderr || !inetd_flag);
+#ifdef ENABLE_OPENSSL_FIPS
+ ssh_FIPS_check_status();
+#endif
+
/*
* Unset KRB5CCNAME, otherwise the user's session may inherit it from
* root's environment
diff -pur old/sshd_config.5 new/sshd_config.5
--- old/sshd_config.5
+++ new/sshd_config.5
@@ -489,6 +489,13 @@ aes128-ctr,aes192-ctr,aes256-ctr,
aes128-gcm@openssh.com,aes256-gcm@openssh.com
.Ed
.Pp
+The following ciphers are FIPS-140 approved and are supported in FIPS-140 mode:
+.Bd -literal -offset indent
+aes128-ctr,aes192-ctr,aes256-ctr,
+aes128-gcm@openssh.com,aes256-gcm@openssh.com,
+aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc
+.Ed
+.Pp
The list of available ciphers may also be obtained using the
.Fl Q
option of
@@ -585,6 +592,8 @@ and
.Dq sha256 .
The default is
.Dq sha256 .
+In FIPS-140 mode the only supported option is
+.Dq sha256 .
.It Cm ForceCommand
Forces the execution of the command specified by
.Cm ForceCommand ,
@@ -1034,6 +1043,16 @@ umac-64@openssh.com,umac-128@openssh.com
hmac-sha2-256,hmac-sha2-512,hmac-sha1
.Ed
.Pp
+The following MACs are FIPS-140 approved and are supported in FIPS-140 mode:
+.Bd -literal -offset indent
+hmac-sha2-256-etm@openssh.com,
+hmac-sha2-512-etm@openssh.com,
+hmac-sha2-256,hmac-sha2-512,
+hmac-sha1-etm@openssh.com,
+hmac-sha1-96-etm@openssh.com
+hmac-sha1,hmac-sha1-96
+.Ed
+.Pp
The list of available MAC algorithms may also be obtained using the
.Fl Q
option of
diff -pur old/sshkey.c new/sshkey.c
--- old/sshkey.c
+++ new/sshkey.c
@@ -85,7 +85,46 @@ struct keytype {
int cert;
int sigonly;
};
+
+#ifdef ENABLE_OPENSSL_FIPS
+/* in FIPS mode limit keytypes to FIPS compliant only */
+#define keytypes (ssh_FIPS_mode() ? keytypes_fips : keytypes_dflt)
+
+static const struct keytype keytypes_fips[] = {
+#ifdef WITH_OPENSSL
+ { NULL, "RSA1", KEY_RSA1, 0, 0, 0 },
+ { "ssh-rsa", "RSA", KEY_RSA, 0, 0, 0 },
+ { "rsa-sha2-256", "RSA", KEY_RSA, 0, 0, 1 },
+ { "rsa-sha2-512", "RSA", KEY_RSA, 0, 0, 1 },
+ { "ssh-dss", "DSA", KEY_DSA, 0, 0, 0 },
+# ifdef OPENSSL_HAS_ECC
+ { "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0, 0 },
+ { "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0, 0 },
+# ifdef OPENSSL_HAS_NISTP521
+ { "ecdsa-sha2-nistp521", "ECDSA", KEY_ECDSA, NID_secp521r1, 0, 0 },
+# endif /* OPENSSL_HAS_NISTP521 */
+# endif /* OPENSSL_HAS_ECC */
+ { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", KEY_RSA_CERT, 0, 1, 0 },
+ { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", KEY_DSA_CERT, 0, 1, 0 },
+# ifdef OPENSSL_HAS_ECC
+ { "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT",
+ KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1, 0 },
+ { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT",
+ KEY_ECDSA_CERT, NID_secp384r1, 1, 0 },
+# ifdef OPENSSL_HAS_NISTP521
+ { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT",
+ KEY_ECDSA_CERT, NID_secp521r1, 1, 0 },
+# endif /* OPENSSL_HAS_NISTP521 */
+# endif /* OPENSSL_HAS_ECC */
+#endif /* WITH_OPENSSL */
+ { "null", "null", KEY_NULL, 0, 0 },
+ { NULL, NULL, -1, -1, 0, 0 }
+};
+
+static const struct keytype keytypes_dflt[] = {
+#else /* ENABLE_OPENSSL_FIPS */
static const struct keytype keytypes[] = {
+#endif /* ENABLE_OPENSSL_FIPS */
{ "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0, 0 },
{ "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT",
KEY_ED25519_CERT, 0, 1, 0 },