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,