diff --git a/openssh-6.4p1-FIPS-mode-SP800-131A.patch b/openssh-6.4p1-FIPS-mode-SP800-131A.patch new file mode 100644 index 0000000..cf632d8 --- /dev/null +++ b/openssh-6.4p1-FIPS-mode-SP800-131A.patch @@ -0,0 +1,206 @@ +diff --git a/dh.h b/dh.h +index 48f7b68..9ff39f4 100644 +--- a/dh.h ++++ b/dh.h +@@ -45,6 +45,7 @@ int dh_estimate(int); + + /* Min and max values from RFC4419. */ + #define DH_GRP_MIN 1024 ++#define DH_GRP_MIN_FIPS 2048 + #define DH_GRP_MAX 8192 + + /* +diff --git a/kex.c b/kex.c +index a468805..3a0eb16 100644 +--- a/kex.c ++++ b/kex.c +@@ -34,6 +34,7 @@ + #include + + #include ++#include + + #include "xmalloc.h" + #include "ssh2.h" +@@ -93,6 +94,20 @@ static const struct kexalg kexalgs[] = { + { NULL, -1, -1, NULL}, + }; + ++static const struct kexalg kexalgs_fips[] = { ++ { KEX_DH14, KEX_DH_GRP14_SHA1, 0, EVP_sha1 }, ++ { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, EVP_sha1 }, ++#ifdef HAVE_EVP_SHA256 ++ { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, EVP_sha256 }, ++#endif ++#ifdef OPENSSL_HAS_ECC ++ { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, NID_X9_62_prime256v1, EVP_sha256 }, ++ { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, EVP_sha384 }, ++ { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, EVP_sha512 }, ++#endif ++ { NULL, -1, -1, NULL}, ++}; ++ + char * + kex_alg_list(void) + { +@@ -116,7 +131,7 @@ kex_alg_by_name(const char *name) + { + const struct kexalg *k; + +- for (k = kexalgs; k->name != NULL; k++) { ++ for (k = (FIPS_mode() ? kexalgs_fips : kexalgs); k->name != NULL; k++) { + if (strcmp(k->name, name) == 0) + return k; + #ifdef GSSAPI +@@ -141,7 +156,10 @@ kex_names_valid(const char *names) + for ((p = strsep(&cp, ",")); p && *p != '\0'; + (p = strsep(&cp, ","))) { + if (kex_alg_by_name(p) == NULL) { +- error("Unsupported KEX algorithm \"%.100s\"", p); ++ if (FIPS_mode()) ++ error("\"%.100s\" is not allowed in FIPS mode", p); ++ else ++ error("Unsupported KEX algorithm \"%.100s\"", p); + free(s); + return 0; + } +diff --git a/kexecdhc.c b/kexecdhc.c +index 6193836..d435f1f 100644 +--- a/kexecdhc.c ++++ b/kexecdhc.c +@@ -154,6 +154,7 @@ kexecdh_client(Kex *kex) + + kex_derive_keys(kex, hash, hashlen, shared_secret); + BN_clear_free(shared_secret); ++ memset(hash, 0, hashlen); + kex_finish(kex); + } + #else /* OPENSSL_HAS_ECC */ +diff --git a/kexecdhs.c b/kexecdhs.c +index 3a580aa..9a06905 100644 +--- a/kexecdhs.c ++++ b/kexecdhs.c +@@ -155,6 +155,7 @@ kexecdh_server(Kex *kex) + + kex_derive_keys(kex, hash, hashlen, shared_secret); + BN_clear_free(shared_secret); ++ memset(hash, 0, hashlen); + kex_finish(kex); + } + #else /* OPENSSL_HAS_ECC */ +diff --git a/kexgexc.c b/kexgexc.c +index 5a3be20..a931b6e 100644 +--- a/kexgexc.c ++++ b/kexgexc.c +@@ -26,6 +26,8 @@ + + #include "includes.h" + ++#include ++ + #include + + #include +@@ -64,13 +66,13 @@ kexgex_client(Kex *kex) + /* Old GEX request */ + packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); + packet_put_int(nbits); +- min = DH_GRP_MIN; ++ min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN; + max = DH_GRP_MAX; + + debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD(%u) sent", nbits); + } else { + /* New GEX request */ +- min = DH_GRP_MIN; ++ min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN; + max = DH_GRP_MAX; + packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); + packet_put_int(min); +diff --git a/kexgexs.c b/kexgexs.c +index 4e473fc..2ed49bd 100644 +--- a/kexgexs.c ++++ b/kexgexs.c +@@ -76,16 +76,16 @@ kexgex_server(Kex *kex) + omin = min = packet_get_int(); + onbits = nbits = packet_get_int(); + omax = max = packet_get_int(); +- min = MAX(DH_GRP_MIN, min); ++ min = MAX(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, min); + max = MIN(DH_GRP_MAX, max); +- nbits = MAX(DH_GRP_MIN, nbits); ++ nbits = MAX(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, nbits); + nbits = MIN(DH_GRP_MAX, nbits); + break; + case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: + debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); + onbits = nbits = packet_get_int(); + /* unused for old GEX */ +- omin = min = DH_GRP_MIN; ++ omin = min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN; + omax = max = DH_GRP_MAX; + break; + default: +diff --git a/myproposal.h b/myproposal.h +index ee69ea2..1b68c5b 100644 +--- a/myproposal.h ++++ b/myproposal.h +@@ -72,6 +72,12 @@ + "diffie-hellman-group14-sha1," \ + "diffie-hellman-group1-sha1" + ++#define KEX_DEFAULT_KEX_FIPS \ ++ KEX_ECDH_METHODS \ ++ KEX_SHA256_METHODS \ ++ "diffie-hellman-group-exchange-sha1," \ ++ "diffie-hellman-group14-sha1" ++ + #define KEX_DEFAULT_PK_ALG \ + HOSTKEY_ECDSA_CERT_METHODS \ + "ssh-rsa-cert-v01@openssh.com," \ +diff --git a/ssh-keygen.c b/ssh-keygen.c +index cac6762..2569016 100644 +--- a/ssh-keygen.c ++++ b/ssh-keygen.c +@@ -183,8 +183,14 @@ type_bits_valid(int type, u_int32_t *bitsp) + fprintf(stderr, "key bits exceeds maximum %d\n", maxbits); + exit(1); + } +- if (type == KEY_DSA && *bitsp != 1024) ++ if (type == KEY_DSA && FIPS_mode()) ++ fatal("DSA keys are not allowed in FIPS mode"); ++ else if (type == KEY_DSA && *bitsp != 1024) + fatal("DSA keys must be 1024 bits"); ++ else if (type == KEY_RSA && bits < DEFAULT_BITS && FIPS_mode()) { ++ fprintf(stderr, "RSA keys must be at least %d bits in FIPS mode\n", DEFAULT_BITS); ++ exit(1); ++ } + else if (type != KEY_ECDSA && *bitsp < 768) + fatal("Key must at least be 768 bits"); + else if (type == KEY_ECDSA && key_ecdsa_bits_to_nid(*bitsp) == -1) +diff --git a/sshconnect2.c b/sshconnect2.c +index 7e48880..3179d82 100644 +--- a/sshconnect2.c ++++ b/sshconnect2.c +@@ -231,6 +231,8 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) + } + if (options.kex_algorithms != NULL) + myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; ++ else if (FIPS_mode()) ++ myproposal[PROPOSAL_KEX_ALGS] = KEX_DEFAULT_KEX_FIPS; + + #ifdef GSSAPI + /* If we've got GSSAPI algorithms, then we also support the +diff --git a/sshd.c b/sshd.c +index 11adbf6..f5e98bc 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -2605,6 +2605,8 @@ do_ssh2_kex(void) + } + if (options.kex_algorithms != NULL) + myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; ++ else if (FIPS_mode()) ++ myproposal[PROPOSAL_KEX_ALGS] = KEX_DEFAULT_KEX_FIPS; + + if (options.rekey_limit || options.rekey_interval) + packet_set_rekey_limits((u_int32_t)options.rekey_limit, diff --git a/openssh.spec b/openssh.spec index 66a58df..829cd75 100644 --- a/openssh.spec +++ b/openssh.spec @@ -182,6 +182,8 @@ Patch901: openssh-6.3p1-kuserok.patch Patch902: openssh-6.3p1-krb5-use-default_ccache_name.patch # increase the size of the Diffie-Hellman groups (#1010607) Patch903: openssh-6.3p1-increase-size-of-DF-groups.patch +# FIPS mode - adjust the key echange DH groups and ssh-keygen according to SP800-131A (#1001748) +Patch904: openssh-6.4p1-FIPS-mode-SP800-131A.patch License: BSD @@ -404,6 +406,7 @@ popd %patch901 -p1 -b .kuserok %patch902 -p1 -b .ccache_name %patch903 -p1 -b .dh +%patch904 -p1 -b .SP800-131A %if 0 # Nothing here yet