# HG changeset patch
# Parent  66f9e5e88b1b79375050a85ae7b81c3da004f301
# Use only FIPS approved crypto stuff from OpenSSL when its FIPS mode is
# detected. That means: SHA-1 instead of MD5, disabling some weak ciphers (and
# cut-off hashes), substituing OpenSSL's internal PRNG for arc4 and removing
# SSH-1 protocol from accepted protocols

diff --git a/openssh-5.1p1/audit.c b/openssh-5.1p1/audit.c
--- a/openssh-5.1p1/audit.c
+++ b/openssh-5.1p1/audit.c
@@ -36,16 +36,18 @@
 #include "log.h"
 #include "key.h"
 #include "hostfile.h"
 #include "auth.h"
 #include "ssh-gss.h"
 #include "monitor_wrap.h"
 #include "xmalloc.h"
 
+#include <openssl/fips.h>
+
 /*
  * Care must be taken when using this since it WILL NOT be initialized when
  * audit_connection_from() is called and MAY NOT be initialized when
  * audit_event(CONNECTION_ABANDON) is called.  Test for NULL before using.
  */
 extern Authctxt *the_authctxt;
 
 /* Maybe add the audit class to struct Authmethod? */
@@ -116,17 +118,17 @@ audit_event_lookup(ssh_audit_event_t ev)
 }
 
 void
 audit_key(int host_user, int *rv, const Key *key)
 {
 	char *fp;
 	const char *crypto_name;
 
-	fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+	fp = key_fingerprint(key, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
 	if (key->type == KEY_RSA1)
 		crypto_name = "ssh-rsa1";
 	else
 		crypto_name = key_ssh_name(key);
 	if (audit_keyusage(host_user, crypto_name, key_size(key), fp, *rv) == 0)
 		*rv = 0;
 	xfree(fp);
 }
diff --git a/openssh-5.1p1/auth-rsa.c b/openssh-5.1p1/auth-rsa.c
--- a/openssh-5.1p1/auth-rsa.c
+++ b/openssh-5.1p1/auth-rsa.c
@@ -16,16 +16,17 @@
 
 #include "includes.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
 
 #include <openssl/rsa.h>
 #include <openssl/md5.h>
+#include <openssl/sha.h>
 
 #include <pwd.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -43,16 +44,18 @@
 #include "auth.h"
 #ifdef GSSAPI
 #include "ssh-gss.h"
 #endif
 #include "monitor_wrap.h"
 #include "ssh.h"
 #include "misc.h"
 
+#include <openssl/fips.h>
+
 /* import */
 extern ServerOptions options;
 
 /*
  * Session identifier that is used to bind key exchange and authentication
  * responses to a particular session.
  */
 extern u_char session_id[16];
@@ -83,48 +86,59 @@ auth_rsa_generate_challenge(Key *key)
 	if (BN_mod(challenge, challenge, key->rsa->n, ctx) == 0)
 		fatal("auth_rsa_generate_challenge: BN_mod failed");
 	BN_CTX_free(ctx);
 
 	return challenge;
 }
 
 int
-auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16])
+auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[20])
 {
-	u_char buf[32], mdbuf[16];
+	u_char buf[40], mdbuf[16], shabuf[20];
+	SHA_CTX sha;
 	MD5_CTX md;
 	int len, rv;
 #ifdef SSH_AUDIT_EVENTS
 	char *fp;
 #endif
+	int fips_on;
 
 	/* don't allow short keys */
 	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
 		error("auth_rsa_verify_response: RSA modulus too small: %d < minimum %d bits",
 		    BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE);
 		return (0);
 	}
 
-	/* The response is MD5 of decrypted challenge plus session id. */
+	fips_on = FIPS_mode();
+
+	/* The response may be SHA1 or MD5 of decrypted challenge plus session id. */
 	len = BN_num_bytes(challenge);
-	if (len <= 0 || len > 32)
+	if (len <= 0 || len > (fips_on ? 40 : 32))
 		fatal("auth_rsa_verify_response: bad challenge length %d", len);
-	memset(buf, 0, 32);
-	BN_bn2bin(challenge, buf + 32 - len);
-	MD5_Init(&md);
-	MD5_Update(&md, buf, 32);
-	MD5_Update(&md, session_id, 16);
-	MD5_Final(mdbuf, &md);
+	memset(buf, 0, 40);
+	BN_bn2bin(challenge, buf + (fips_on ? 40 : 32) - len);
+	if (fips_on) {
+		SHA1_Init(&sha);
+		SHA1_Update(&sha, buf, 40);
+		SHA1_Update(&sha, session_id, 20);
+		SHA1_Final(shabuf, &sha);
+	} else {
+		MD5_Init(&md);
+		MD5_Update(&md, buf, 32);
+		MD5_Update(&md, session_id, 16);
+		MD5_Final(mdbuf, &md);
+	}
 
 	/* Verify that the response is the original challenge. */
-	rv = timingsafe_bcmp(response, mdbuf, 16) == 0;
+	rv = timingsafe_bcmp(response, mdbuf, fips_on ? 20 : 16) == 0;
 
 #ifdef SSH_AUDIT_EVENTS
-	fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+	fp = key_fingerprint(key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
 	if (audit_keyusage(1, "ssh-rsa1", RSA_size(key->rsa) * 8, fp, rv) == 0) {
 		debug("unsuccessful audit");
 		rv = 0;
 	}
 	xfree(fp);
 #endif
 
 	return rv;
@@ -135,17 +149,17 @@ auth_rsa_verify_response(Key *key, BIGNU
  * and returns true (non-zero) if the client gave the correct answer to
  * our challenge; returns zero if the client gives a wrong answer.
  */
 
 int
 auth_rsa_challenge_dialog(Key *key)
 {
 	BIGNUM *challenge, *encrypted_challenge;
-	u_char response[16];
+	u_char response[20];
 	int i, success;
 
 	if ((encrypted_challenge = BN_new()) == NULL)
 		fatal("auth_rsa_challenge_dialog: BN_new() failed");
 
 	challenge = PRIVSEP(auth_rsa_generate_challenge(key));
 
 	/* Encrypt the challenge with the public key. */
@@ -157,16 +171,20 @@ auth_rsa_challenge_dialog(Key *key)
 	packet_send();
 	BN_clear_free(encrypted_challenge);
 	packet_write_wait();
 
 	/* Wait for a response. */
 	packet_read_expect(SSH_CMSG_AUTH_RSA_RESPONSE);
 	for (i = 0; i < 16; i++)
 		response[i] = (u_char)packet_get_char();
+	if( FIPS_mode() ) {	
+		for (i = 16; i < 20; i++)
+			response[i] = (u_char)packet_get_char();
+	}	
 	packet_check_eom();
 
 	success = PRIVSEP(auth_rsa_verify_response(key, challenge, response));
 	BN_clear_free(challenge);
 	return (success);
 }
 
 /*
@@ -317,17 +335,17 @@ auth_rsa(Authctxt *authctxt, BIGNUM *cli
 		return (0);
 	}
 	/*
 	 * Correct response.  The client has been successfully
 	 * authenticated. Note that we have not yet processed the
 	 * options; this will be reset if the options cause the
 	 * authentication to be rejected.
 	 */
-	fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+	fp = key_fingerprint(key, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
 	verbose("Found matching %s key: %s",
 	    key_type(key), fp);
 	xfree(fp);
 	key_free(key);
 
 	packet_send_debug("RSA authentication accepted.");
 	return (1);
 }
diff --git a/openssh-5.1p1/auth2-pubkey.c b/openssh-5.1p1/auth2-pubkey.c
--- a/openssh-5.1p1/auth2-pubkey.c
+++ b/openssh-5.1p1/auth2-pubkey.c
@@ -52,16 +52,18 @@
 #include "auth-options.h"
 #include "canohost.h"
 #ifdef GSSAPI
 #include "ssh-gss.h"
 #endif
 #include "monitor_wrap.h"
 #include "misc.h"
 
+#include <openssl/fips.h>
+
 /* import */
 extern ServerOptions options;
 extern u_char *session_id2;
 extern u_int session_id2_len;
 
 static int
 userauth_pubkey(Authctxt *authctxt)
 {
@@ -233,17 +235,17 @@ user_search_key_in_file(FILE *f, char *f
 				continue;
 			}
 		}
 		if (key_equal(found, key) &&
 		    auth_parse_options(pw, key_options, file, linenum) == 1) {
 			found_key = 1;
 			debug("matching key found: file %s, line %lu",
 			    file, linenum);
-			fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
+			fp = key_fingerprint(found, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
 			verbose("Found matching %s key: %s",
 			    key_type(found), fp);
 			xfree(fp);
 			break;
 		}
 	}
 	key_free(found);
 	if (!found_key)
diff --git a/openssh-5.1p1/authfile.c b/openssh-5.1p1/authfile.c
--- a/openssh-5.1p1/authfile.c
+++ b/openssh-5.1p1/authfile.c
@@ -40,16 +40,17 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/param.h>
 #include <sys/uio.h>
 
 #include <openssl/err.h>
 #include <openssl/evp.h>
+#include <openssl/fips.h>
 #include <openssl/pem.h>
 
 #include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -138,18 +139,23 @@ key_save_private_rsa1(Key *key, const ch
 	buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
 	buffer_put_bignum(&encrypted, key->rsa->n);
 	buffer_put_bignum(&encrypted, key->rsa->e);
 	buffer_put_cstring(&encrypted, comment);
 
 	/* Allocate space for the private part of the key in the buffer. */
 	cp = buffer_append_space(&encrypted, buffer_len(&buffer));
 
-	cipher_set_key_string(&ciphercontext, cipher, passphrase,
-	    CIPHER_ENCRYPT);
+	if (cipher_set_key_string(&ciphercontext, cipher, passphrase,
+		    CIPHER_ENCRYPT) < 0) {
+		error("cipher_set_key_string failed.");
+		buffer_free(&encrypted);
+		buffer_free(&buffer);
+		return 0;
+    }
 	cipher_crypt(&ciphercontext, cp,
 	    buffer_ptr(&buffer), buffer_len(&buffer));
 	cipher_cleanup(&ciphercontext);
 	memset(&ciphercontext, 0, sizeof(ciphercontext));
 
 	/* Destroy temporary data. */
 	memset(buf, 0, sizeof(buf));
 	buffer_free(&buffer);
@@ -409,18 +415,23 @@ key_load_private_rsa1(int fd, const char
 		buffer_free(&buffer);
 		goto fail;
 	}
 	/* Initialize space for decrypted data. */
 	buffer_init(&decrypted);
 	cp = buffer_append_space(&decrypted, buffer_len(&buffer));
 
 	/* Rest of the buffer is encrypted.  Decrypt it using the passphrase. */
-	cipher_set_key_string(&ciphercontext, cipher, passphrase,
-	    CIPHER_DECRYPT);
+	if (cipher_set_key_string(&ciphercontext, cipher, passphrase,
+		    CIPHER_ENCRYPT) < 0) {
+		error("cipher_set_key_string failed.");
+		buffer_free(&decrypted);
+		buffer_free(&buffer);
+		return 0;
+    }
 	cipher_crypt(&ciphercontext, cp,
 	    buffer_ptr(&buffer), buffer_len(&buffer));
 	cipher_cleanup(&ciphercontext);
 	memset(&ciphercontext, 0, sizeof(ciphercontext));
 	buffer_free(&buffer);
 
 	check1 = buffer_get_char(&decrypted);
 	check2 = buffer_get_char(&decrypted);
diff --git a/openssh-5.1p1/cipher-ctr.c b/openssh-5.1p1/cipher-ctr.c
--- a/openssh-5.1p1/cipher-ctr.c
+++ b/openssh-5.1p1/cipher-ctr.c
@@ -17,16 +17,17 @@
 #include "includes.h"
 
 #include <sys/types.h>
 
 #include <stdarg.h>
 #include <string.h>
 
 #include <openssl/evp.h>
+#include <openssl/fips.h>
 
 #include "xmalloc.h"
 #include "log.h"
 
 /* compatibility with old or broken OpenSSL versions */
 #include "openbsd-compat/openssl-compat.h"
 
 #ifndef USE_BUILTIN_RIJNDAEL
@@ -136,11 +137,13 @@ evp_aes_128_ctr(void)
 	aes_ctr.iv_len = AES_BLOCK_SIZE;
 	aes_ctr.key_len = 16;
 	aes_ctr.init = ssh_aes_ctr_init;
 	aes_ctr.cleanup = ssh_aes_ctr_cleanup;
 	aes_ctr.do_cipher = ssh_aes_ctr;
 #ifndef SSH_OLD_EVP
 	aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
 	    EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV;
+	if (FIPS_mode())
+		aes_ctr.flags |= EVP_CIPH_FLAG_FIPS;
 #endif
 	return (&aes_ctr);
 }
diff --git a/openssh-5.1p1/cipher.c b/openssh-5.1p1/cipher.c
--- a/openssh-5.1p1/cipher.c
+++ b/openssh-5.1p1/cipher.c
@@ -34,17 +34,19 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "includes.h"
 
 #include <sys/types.h>
 
+#include <openssl/sha.h>
 #include <openssl/md5.h>
+#include <openssl/fips.h>
 
 #include <string.h>
 #include <stdarg.h>
 
 #include "xmalloc.h"
 #include "log.h"
 #include "cipher.h"
 
@@ -78,16 +80,32 @@ struct Cipher ciphers[] = {
 	{ "aes192-ctr",		SSH_CIPHER_SSH2, 16, 24, 0, evp_aes_128_ctr },
 	{ "aes256-ctr",		SSH_CIPHER_SSH2, 16, 32, 0, evp_aes_128_ctr },
 #ifdef USE_CIPHER_ACSS
 	{ "acss@openssh.org",	SSH_CIPHER_SSH2, 16, 5, 0, EVP_acss },
 #endif
 	{ NULL,			SSH_CIPHER_INVALID, 0, 0, 0, NULL }
 };
 
+struct Cipher fips_ciphers[] = {
+	{ "none",		SSH_CIPHER_NONE, 8, 0, 0, EVP_enc_null },
+	{ "3des",		SSH_CIPHER_3DES, 8, 16, 0, evp_ssh1_3des },
+
+	{ "3des-cbc",		SSH_CIPHER_SSH2, 8, 24, 0, EVP_des_ede3_cbc },
+	{ "aes128-cbc",		SSH_CIPHER_SSH2, 16, 16, 0, EVP_aes_128_cbc },
+	{ "aes192-cbc",		SSH_CIPHER_SSH2, 16, 24, 0, EVP_aes_192_cbc },
+	{ "aes256-cbc",		SSH_CIPHER_SSH2, 16, 32, 0, EVP_aes_256_cbc },
+	{ "rijndael-cbc@lysator.liu.se",
+				SSH_CIPHER_SSH2, 16, 32, 0, EVP_aes_256_cbc },
+	{ "aes128-ctr",		SSH_CIPHER_SSH2, 16, 16, 0, evp_aes_128_ctr },
+	{ "aes192-ctr",		SSH_CIPHER_SSH2, 16, 24, 0, evp_aes_128_ctr },
+	{ "aes256-ctr",		SSH_CIPHER_SSH2, 16, 32, 0, evp_aes_128_ctr },
+	{ NULL,			SSH_CIPHER_INVALID, 0, 0, 0, NULL }
+};
+
 /*--*/
 
 u_int
 cipher_blocksize(const Cipher *c)
 {
 	return (c->block_size);
 }
 
@@ -114,27 +132,27 @@ cipher_mask_ssh1(int client)
 	}
 	return mask;
 }
 
 Cipher *
 cipher_by_name(const char *name)
 {
 	Cipher *c;
-	for (c = ciphers; c->name != NULL; c++)
+	for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++)
 		if (strcmp(c->name, name) == 0)
 			return c;
 	return NULL;
 }
 
 Cipher *
 cipher_by_number(int id)
 {
 	Cipher *c;
-	for (c = ciphers; c->name != NULL; c++)
+	for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++)
 		if (c->number == id)
 			return c;
 	return NULL;
 }
 
 #define	CIPHER_SEP	","
 int
 ciphers_valid(const char *names)
@@ -168,17 +186,17 @@ ciphers_valid(const char *names)
  */
 
 int
 cipher_number(const char *name)
 {
 	Cipher *c;
 	if (name == NULL)
 		return -1;
-	for (c = ciphers; c->name != NULL; c++)
+	for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++)
 		if (strcasecmp(c->name, name) == 0)
 			return c->number;
 	return -1;
 }
 
 char *
 cipher_name(int id)
 {
@@ -271,35 +289,50 @@ cipher_crypt(CipherContext *cc, u_char *
 void
 cipher_cleanup(CipherContext *cc)
 {
 	if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0)
 		error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed");
 }
 
 /*
- * Selects the cipher, and keys if by computing the MD5 checksum of the
+ * Selects the cipher, and keys if by computing the SHA/MD5 checksum of the
  * passphrase and using the resulting 16 bytes as the key.
  */
 
-void
+int
 cipher_set_key_string(CipherContext *cc, Cipher *cipher,
     const char *passphrase, int do_encrypt)
 {
 	MD5_CTX md;
-	u_char digest[16];
+	SHA_CTX sha;
+	u_char digest[20];
+	int fips_on;
 
-	MD5_Init(&md);
-	MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase));
-	MD5_Final(digest, &md);
+	fips_on = FIPS_mode();
 
-	cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt);
+	if (fips_on) {	
+		if (SHA1_Init(&sha) <= 0)
+			return -1;
+		SHA1_Update(&sha, (const u_char *)passphrase, strlen(passphrase));
+		SHA1_Final(digest, &sha);
+
+	} else {
+		if (MD5_Init(&md) <= 0)
+			return -1;
+		MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase));
+		MD5_Final(digest, &md);
+	}
+	cipher_init(cc, cipher, digest, fips_on ? 20 : 16, NULL, 0, do_encrypt);
 
 	memset(digest, 0, sizeof(digest));
 	memset(&md, 0, sizeof(md));
+	memset(&sha, 0, sizeof(sha));
+
+	return 0;
 }
 
 /*
  * Exports an IV from the CipherContext required to export the key
  * state back from the unprivileged child to the privileged parent
  * process.
  */
 
diff --git a/openssh-5.1p1/cipher.h b/openssh-5.1p1/cipher.h
--- a/openssh-5.1p1/cipher.h
+++ b/openssh-5.1p1/cipher.h
@@ -81,17 +81,17 @@ Cipher	*cipher_by_name(const char *);
 Cipher	*cipher_by_number(int);
 int	 cipher_number(const char *);
 char	*cipher_name(int);
 int	 ciphers_valid(const char *);
 void	 cipher_init(CipherContext *, Cipher *, const u_char *, u_int,
     const u_char *, u_int, int);
 void	 cipher_crypt(CipherContext *, u_char *, const u_char *, u_int);
 void	 cipher_cleanup(CipherContext *);
-void	 cipher_set_key_string(CipherContext *, Cipher *, const char *, int);
+int	 cipher_set_key_string(CipherContext *, Cipher *, const char *, int);
 u_int	 cipher_blocksize(const Cipher *);
 u_int	 cipher_keylen(const Cipher *);
 
 u_int	 cipher_get_number(const Cipher *);
 void	 cipher_get_keyiv(CipherContext *, u_char *, u_int);
 void	 cipher_set_keyiv(CipherContext *, u_char *);
 int	 cipher_get_keyiv_len(const CipherContext *);
 int	 cipher_get_keycontext(const CipherContext *, u_char *);
diff --git a/openssh-5.1p1/mac.c b/openssh-5.1p1/mac.c
--- a/openssh-5.1p1/mac.c
+++ b/openssh-5.1p1/mac.c
@@ -22,16 +22,17 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "includes.h"
 
 #include <sys/types.h>
 
+#include <openssl/fips.h>
 #include <openssl/hmac.h>
 
 #include <stdarg.h>
 #include <string.h>
 #include <signal.h>
 
 #include "xmalloc.h"
 #include "log.h"
@@ -42,37 +43,43 @@
 #include "mac.h"
 #include "misc.h"
 
 #include "umac.h"
 
 #define SSH_EVP		1	/* OpenSSL EVP-based MAC */
 #define SSH_UMAC	2	/* UMAC (not integrated with OpenSSL) */
 
-struct {
+struct Macs {
 	char		*name;
 	int		type;
 	const EVP_MD *	(*mdfunc)(void);
 	int		truncatebits;	/* truncate digest if != 0 */
 	int		key_len;	/* just for UMAC */
 	int		len;		/* just for UMAC */
-} macs[] = {
+} all_macs[] = {
 	{ "hmac-sha1",			SSH_EVP, EVP_sha1, 0, -1, -1 },
 	{ "hmac-sha1-96",		SSH_EVP, EVP_sha1, 96, -1, -1 },
 	{ "hmac-md5",			SSH_EVP, EVP_md5, 0, -1, -1 },
 	{ "hmac-md5-96",		SSH_EVP, EVP_md5, 96, -1, -1 },
 	{ "hmac-ripemd160",		SSH_EVP, EVP_ripemd160, 0, -1, -1 },
 	{ "hmac-ripemd160@openssh.com",	SSH_EVP, EVP_ripemd160, 0, -1, -1 },
 	{ "umac-64@openssh.com",	SSH_UMAC, NULL, 0, 128, 64 },
 	{ NULL,				0, NULL, 0, -1, -1 }
 };
 
+struct Macs fips_macs[] = {
+	{ "hmac-sha1",			SSH_EVP, EVP_sha1, 0, -1, -1 },
+	{ NULL,				0, NULL, 0, -1, -1 }
+};
+
 static void
 mac_setup_by_id(Mac *mac, int which)
 {
+	struct Macs *macs = FIPS_mode() ? fips_macs : all_macs;
 	int evp_len;
 	mac->type = macs[which].type;
 	if (mac->type == SSH_EVP) {
 		mac->evp_md = (*macs[which].mdfunc)();
 		if ((evp_len = EVP_MD_size(mac->evp_md)) <= 0)
 			fatal("mac %s len %d", mac->name, evp_len);
 		mac->key_len = mac->mac_len = (u_int)evp_len;
 	} else {
@@ -83,16 +90,17 @@ mac_setup_by_id(Mac *mac, int which)
 	if (macs[which].truncatebits != 0)
 		mac->mac_len = macs[which].truncatebits / 8;
 }
 
 int
 mac_setup(Mac *mac, char *name)
 {
 	int i;
+	struct Macs *macs = FIPS_mode() ? fips_macs : all_macs;
 
 	for (i = 0; macs[i].name; i++) {
 		if (strcmp(name, macs[i].name) == 0) {
 			if (mac != NULL)
 				mac_setup_by_id(mac, i);
 			debug2("mac_setup: found %s", name);
 			return (0);
 		}
diff --git a/openssh-5.1p1/myproposal.h b/openssh-5.1p1/myproposal.h
--- a/openssh-5.1p1/myproposal.h
+++ b/openssh-5.1p1/myproposal.h
@@ -47,17 +47,22 @@
 	"aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se," \
 	"aes128-ctr,aes192-ctr,aes256-ctr"
 #define	KEX_DEFAULT_MAC \
 	"hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160," \
 	"hmac-ripemd160@openssh.com," \
 	"hmac-sha1-96,hmac-md5-96"
 #define	KEX_DEFAULT_COMP	"none,zlib@openssh.com,zlib"
 #define	KEX_DEFAULT_LANG	""
-
+#define	KEX_FIPS_ENCRYPT \
+	"aes128-ctr,aes192-ctr,aes256-ctr," \
+	"aes128-cbc,3des-cbc," \
+	"aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se"
+#define	KEX_FIPS_MAC \
+	"hmac-sha1"
 
 static char *myproposal[PROPOSAL_MAX] = {
 	KEX_DEFAULT_KEX,
 	KEX_DEFAULT_PK_ALG,
 	KEX_DEFAULT_ENCRYPT,
 	KEX_DEFAULT_ENCRYPT,
 	KEX_DEFAULT_MAC,
 	KEX_DEFAULT_MAC,
diff --git a/openssh-5.1p1/openbsd-compat/bsd-arc4random.c b/openssh-5.1p1/openbsd-compat/bsd-arc4random.c
--- a/openssh-5.1p1/openbsd-compat/bsd-arc4random.c
+++ b/openssh-5.1p1/openbsd-compat/bsd-arc4random.c
@@ -24,28 +24,29 @@
 
 #include "log.h"
 
 #ifndef HAVE_ARC4RANDOM
 
 #include <openssl/rand.h>
 #include <openssl/rc4.h>
 #include <openssl/err.h>
+#include <openssl/fips.h>
 
 /* Size of key to use */
 #define SEED_SIZE 20
 
 /* Number of bytes to reseed after */
 #define REKEY_BYTES	(1 << 24)
 
 static int rc4_ready = 0;
 static RC4_KEY rc4;
 
-unsigned int
-arc4random(void)
+static unsigned int
+arc4random_bsd(void)
 {
 	unsigned int r = 0;
 	static int first_time = 1;
 
 	if (rc4_ready <= 0) {
 		if (first_time)
 			seed_rng();
 		first_time = 0;
@@ -54,18 +55,18 @@ arc4random(void)
 
 	RC4(&rc4, sizeof(r), (unsigned char *)&r, (unsigned char *)&r);
 
 	rc4_ready -= sizeof(r);
 	
 	return(r);
 }
 
-void
-arc4random_stir(void)
+static void
+arc4random_stir_bsd(void)
 {
 	unsigned char rand_buf[SEED_SIZE];
 	int i;
 
 	memset(&rc4, 0, sizeof(rc4));
 	if (RAND_bytes(rand_buf, sizeof(rand_buf)) <= 0)
 		fatal("Couldn't obtain random bytes (error %ld)",
 		    ERR_get_error());
@@ -77,16 +78,62 @@ arc4random_stir(void)
 	 */
 	for(i = 0; i <= 256; i += sizeof(rand_buf))
 		RC4(&rc4, sizeof(rand_buf), rand_buf, rand_buf);
 
 	memset(rand_buf, 0, sizeof(rand_buf));
 
 	rc4_ready = REKEY_BYTES;
 }
+static unsigned int
+arc4random_fips(void)
+{
+	unsigned int r = 0;
+	void *rp = &r;
+	static int first_time = 1;
+
+	if (first_time) {
+		seed_rng();
+		first_time = 0;
+	}
+	if (!rc4_ready)
+		arc4random_stir();
+	RAND_bytes(rp, sizeof(r));
+
+	return(r);
+}
+
+static void
+arc4random_stir_fips(void)
+{
+	unsigned char rand_buf[SEED_SIZE];
+
+	if (RAND_bytes(rand_buf, sizeof(rand_buf)) <= 0)
+		fatal("Couldn't obtain random bytes (error %ld)",
+		    ERR_get_error());
+	rc4_ready = 1;
+}
+
+unsigned int
+arc4random(void)
+{
+	if (FIPS_mode())
+		return arc4random_fips();
+	else
+		return arc4random_bsd();
+}
+
+void
+arc4random_stir(void)
+{
+	if (FIPS_mode())
+		return arc4random_stir_fips();
+	else
+		return arc4random_stir_bsd();
+}
 #endif /* !HAVE_ARC4RANDOM */
 
 #ifndef ARC4RANDOM_BUF
 void
 arc4random_buf(void *_buf, size_t n)
 {
 	size_t i;
 	u_int32_t r = 0;
diff --git a/openssh-5.1p1/scard-opensc.c b/openssh-5.1p1/scard-opensc.c
--- a/openssh-5.1p1/scard-opensc.c
+++ b/openssh-5.1p1/scard-opensc.c
@@ -388,17 +388,17 @@ sc_read_pubkey(Key * k, const struct sc_
 	k->rsa->flags |= RSA_FLAG_SIGN_VER;
 	RSA_set_method(k->rsa, sc_get_rsa_method());
 	priv = xmalloc(sizeof(struct sc_priv_data));
 	priv->cert_id = cinfo->id;
 	priv->ref_count = 1;
 	RSA_set_app_data(k->rsa, priv);
 
 	k->flags = KEY_FLAG_EXT;
-	tmp = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
+	tmp = key_fingerprint(k, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
 	debug("fingerprint %d %s", key_size(k), tmp);
 	xfree(tmp);
 
 	return 0;
 err:
 	if (cert)
 		sc_pkcs15_free_certificate(cert);
 	if (pubkey)
diff --git a/openssh-5.1p1/scard.c b/openssh-5.1p1/scard.c
--- a/openssh-5.1p1/scard.c
+++ b/openssh-5.1p1/scard.c
@@ -190,17 +190,17 @@ sc_read_pubkey(Key * k)
 
 	/* currently the java applet just stores 'n' */
 	if (!BN_set_word(k->rsa->e, 35)) {
 		error("c_read_pubkey: BN_set_word(e, 35) failed");
 		goto err;
 	}
 
 	status = 0;
-	p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
+	p = key_fingerprint(k, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
 	debug("fingerprint %u %s", key_size(k), p);
 	xfree(p);
 
 err:
 	if (n != NULL)
 		xfree(n);
 	sc_close();
 	return status;
diff --git a/openssh-5.1p1/ssh-add.c b/openssh-5.1p1/ssh-add.c
--- a/openssh-5.1p1/ssh-add.c
+++ b/openssh-5.1p1/ssh-add.c
@@ -37,16 +37,17 @@
 
 #include "includes.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/param.h>
 
 #include <openssl/evp.h>
+#include <openssl/fips.h>
 #include "openbsd-compat/openssl-compat.h"
 #include <openssl/conf.h>
 #include <openssl/engine.h>
 
 #include <fcntl.h>
 #include <pwd.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -242,17 +243,17 @@ list_identities(AuthenticationConnection
 	int version;
 
 	for (version = 1; version <= 2; version++) {
 		for (key = ssh_get_first_identity(ac, &comment, version);
 		    key != NULL;
 		    key = ssh_get_next_identity(ac, &comment, version)) {
 			had_identities = 1;
 			if (do_fp) {
-				fp = key_fingerprint(key, SSH_FP_MD5,
+				fp = key_fingerprint(key, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5,
 				    SSH_FP_HEX);
 				printf("%d %s %s (%s)\n",
 				    key_size(key), fp, comment, key_type(key));
 				xfree(fp);
 			} else {
 				if (!key_write(key, stdout))
 					fprintf(stderr, "key_write failed");
 				fprintf(stdout, " %s\n", comment);
diff --git a/openssh-5.1p1/ssh-agent.c b/openssh-5.1p1/ssh-agent.c
--- a/openssh-5.1p1/ssh-agent.c
+++ b/openssh-5.1p1/ssh-agent.c
@@ -46,16 +46,17 @@
 #endif
 #ifdef HAVE_SYS_UN_H
 # include <sys/un.h>
 #endif
 #include "openbsd-compat/sys-queue.h"
 
 #include <openssl/evp.h>
 #include <openssl/md5.h>
+#include <openssl/fips.h>
 #include "openbsd-compat/openssl-compat.h"
 #include <openssl/conf.h>
 #include <openssl/engine.h>
 
 #include <errno.h>
 #include <fcntl.h>
 #ifdef HAVE_PATHS_H
 # include <paths.h>
@@ -193,19 +194,19 @@ lookup_identity(Key *key, int version)
 
 /* Check confirmation of keysign request */
 static int
 confirm_key(Identity *id)
 {
 	char *p;
 	int ret = -1;
 
-	p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
-	if (ask_permission("Allow use of key %s?\nKey fingerprint %s.",
-	    id->comment, p))
+	p = key_fingerprint(id->key, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
+	if (ask_permission("Allow use of key %s?\nKey %sfingerprint %s.",
+	    id->comment, FIPS_mode() ? "SHA1 " : "", p))
 		ret = 0;
 	xfree(p);
 
 	return (ret);
 }
 
 /* send list of supported public keys to 'client' */
 static void
diff --git a/openssh-5.1p1/ssh-keygen.c b/openssh-5.1p1/ssh-keygen.c
--- a/openssh-5.1p1/ssh-keygen.c
+++ b/openssh-5.1p1/ssh-keygen.c
@@ -16,16 +16,17 @@
 
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/param.h>
 
 #include <openssl/evp.h>
 #include <openssl/pem.h>
+#include <openssl/fips.h>
 #include "openbsd-compat/openssl-compat.h"
 #include <openssl/conf.h>
 #include <openssl/engine.h>
 
 #include <errno.h>
 #include <fcntl.h>
 #include <netdb.h>
 #ifdef HAVE_PATHS_H
@@ -509,17 +510,17 @@ do_fingerprint(struct passwd *pw)
 	FILE *f;
 	Key *public;
 	char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra;
 	int i, skip = 0, num = 0, invalid = 1;
 	enum fp_rep rep;
 	enum fp_type fptype;
 	struct stat st;
 
-	fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
+	fptype = print_bubblebabble ? SSH_FP_SHA1 : FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5;
 	rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
 
 	if (!have_identity)
 		ask_filename(pw, "Enter file in which the key is");
 	if (stat(identity_file, &st) < 0) {
 		perror(identity_file);
 		exit(1);
 	}
@@ -1468,24 +1469,25 @@ passphrase_again:
 		exit(1);
 	}
 	if (!key_write(public, f))
 		fprintf(stderr, "write key failed");
 	fprintf(f, " %s\n", comment);
 	fclose(f);
 
 	if (!quiet) {
-		char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
-		char *ra = key_fingerprint(public, SSH_FP_MD5,
+		int fips_on = FIPS_mode();
+		char *fp = key_fingerprint(public, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
+		char *ra = key_fingerprint(public, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5,
 		    SSH_FP_RANDOMART);
 		printf("Your public key has been saved in %s.\n",
 		    identity_file);
-		printf("The key fingerprint is:\n");
+		printf("The key %sfingerprint is:\n", fips_on ? "SHA1 " : "");
 		printf("%s %s\n", fp, comment);
-		printf("The key's randomart image is:\n");
+		printf("The key's %srandomart image is:\n", fips_on ? "SHA1 " :"");
 		printf("%s\n", ra);
 		xfree(ra);
 		xfree(fp);
 	}
 
 	key_free(public);
 	exit(0);
 }
diff --git a/openssh-5.1p1/ssh-rsa.c b/openssh-5.1p1/ssh-rsa.c
--- a/openssh-5.1p1/ssh-rsa.c
+++ b/openssh-5.1p1/ssh-rsa.c
@@ -16,16 +16,17 @@
  */
 
 #include "includes.h"
 
 #include <sys/types.h>
 
 #include <openssl/evp.h>
 #include <openssl/err.h>
+#include <openssl/fips.h>
 
 #include <stdarg.h>
 #include <string.h>
 
 #include "xmalloc.h"
 #include "log.h"
 #include "buffer.h"
 #include "key.h"
@@ -46,16 +47,19 @@ ssh_rsa_sign(const Key *key, u_char **si
 	int ok, nid;
 	Buffer b;
 
 	if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
 		error("ssh_rsa_sign: no RSA key");
 		return -1;
 	}
 	nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
+	if (FIPS_mode())
+		nid = NID_sha1;
+	OpenSSL_add_all_digests();
 	if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
 		error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid);
 		return -1;
 	}
 	EVP_DigestInit(&md, evp_md);
 	EVP_DigestUpdate(&md, data, datalen);
 	EVP_DigestFinal(&md, digest, &dlen);
 
@@ -151,16 +155,19 @@ ssh_rsa_verify(const Key *key, const u_c
 		debug("ssh_rsa_verify: add padding: modlen %u > len %u",
 		    modlen, len);
 		sigblob = xrealloc(sigblob, 1, modlen);
 		memmove(sigblob + diff, sigblob, len);
 		memset(sigblob, 0, diff);
 		len = modlen;
 	}
 	nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
+	if (FIPS_mode())
+		nid = NID_sha1;
+	OpenSSL_add_all_digests();
 	if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
 		error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid);
 		xfree(sigblob);
 		return -1;
 	}
 	EVP_DigestInit(&md, evp_md);
 	EVP_DigestUpdate(&md, data, datalen);
 	EVP_DigestFinal(&md, digest, &dlen);
diff --git a/openssh-5.1p1/ssh.c b/openssh-5.1p1/ssh.c
--- a/openssh-5.1p1/ssh.c
+++ b/openssh-5.1p1/ssh.c
@@ -66,16 +66,17 @@
 #include <string.h>
 #include <unistd.h>
 
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
 #include <openssl/evp.h>
 #include <openssl/err.h>
+#include <openssl/fips.h>
 #include "openbsd-compat/openssl-compat.h"
 #include "openbsd-compat/sys-queue.h"
 #include <openssl/conf.h>
 #include <openssl/engine.h>
 
 #include "xmalloc.h"
 #include "ssh.h"
 #include "ssh1.h"
@@ -217,16 +218,28 @@ main(int ac, char **av)
 
 	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
 	sanitise_stdfd();
 
 	__progname = ssh_get_progname(av[0]);
 	init_rng();
 
 	/*
+	 * Initialise OpenSSL here so that the appropriate cipher and HMAC lists
+	 * are used depending on whether we are running in FIPS mode or not.
+	 */
+	SSLeay_add_all_algorithms();
+	ERR_load_crypto_strings();
+
+	/* Init available hardware crypto engines. */
+	OPENSSL_config(NULL);
+	ENGINE_load_builtin_engines();
+	ENGINE_register_all_complete();
+
+	/*
 	 * Save the original real uid.  It will be needed later (uid-swapping
 	 * may clobber the real uid).
 	 */
 	original_real_uid = getuid();
 	original_effective_uid = geteuid();
 
 	/*
 	 * Use uid-swapping to give up root privileges for the duration of
@@ -272,16 +285,19 @@ main(int ac, char **av)
 	/* Parse command-line arguments. */
 	host = NULL;
 
  again:
 	while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
 	    "ACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) {
 		switch (opt) {
 		case '1':
+			if (FIPS_mode()) {
+				fatal("Protocol 1 not allowed in the FIPS mode.");
+			}
 			options.protocol = SSH_PROTO_1;
 			break;
 		case '2':
 			options.protocol = SSH_PROTO_2;
 			break;
 		case '4':
 			options.address_family = AF_INET;
 			break;
@@ -556,24 +572,16 @@ main(int ac, char **av)
 		}
 		ac--, av++;
 	}
 
 	/* Check that we got a host name. */
 	if (!host)
 		usage();
 
-	SSLeay_add_all_algorithms();
-	ERR_load_crypto_strings();
-
-	/* Init available hardware crypto engines. */
-	OPENSSL_config(NULL);
-	ENGINE_load_builtin_engines();
-	ENGINE_register_all_complete();
-
 	/* Initialize the command to execute on remote host. */
 	buffer_init(&command);
 
 	/*
 	 * Save the command to execute on the remote host in a buffer. There
 	 * is no limit on the length of the command, except by the maximum
 	 * packet size.  Also sets the tty flag if there is no command.
 	 */
@@ -646,16 +654,20 @@ main(int ac, char **av)
 
 	channel_set_af(options.address_family);
 
 	/* reinit */
 	log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 1);
 
 	seed_rng();
 
+	if (FIPS_mode()) {
+		debug("FIPS mode initialized");
+	}
+
 	if (options.user == NULL)
 		options.user = xstrdup(pw->pw_name);
 
 	/* Get default port if port has not been set. */
 	if (options.port == 0) {
 		sp = getservbyname(SSH_SERVICE_NAME, "tcp");
 		options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
 	}
@@ -712,16 +724,22 @@ main(int ac, char **av)
 	}
 	if (muxclient_command != 0 && options.control_path == NULL)
 		fatal("No ControlPath specified for \"-O\" command");
 	if (options.control_path != NULL)
 		muxclient(options.control_path);
 
 	timeout_ms = options.connection_timeout * 1000;
 
+	if (FIPS_mode()) {
+		options.protocol &= SSH_PROTO_2;
+		if (options.protocol == 0)
+			fatal("Protocol 2 disabled by configuration but required in the FIPS mode.");
+	}
+
 	/* Open a connection to the remote host. */
 	if (ssh_connect(host, &hostaddr, options.port,
 	    options.address_family, options.connection_attempts, &timeout_ms,
 	    options.tcp_keep_alive, 
 #ifdef HAVE_CYGWIN
 	    options.use_privileged_port,
 #else
 	    original_effective_uid == 0 && options.use_privileged_port,
diff --git a/openssh-5.1p1/sshconnect.c b/openssh-5.1p1/sshconnect.c
--- a/openssh-5.1p1/sshconnect.c
+++ b/openssh-5.1p1/sshconnect.c
@@ -34,16 +34,18 @@
 #endif
 #include <pwd.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
+#include <openssl/fips.h>
+
 #include "xmalloc.h"
 #include "key.h"
 #include "hostfile.h"
 #include "ssh.h"
 #include "rsa.h"
 #include "buffer.h"
 #include "packet.h"
 #include "uidswap.h"
@@ -593,16 +595,17 @@ check_host_key(char *hostname, struct so
 	HostStatus host_status;
 	HostStatus ip_status;
 	int r, local = 0, host_ip_differ = 0;
 	int salen;
 	char ntop[NI_MAXHOST];
 	char msg[1024];
 	int len, host_line, ip_line, cancelled_forwarding = 0;
 	const char *host_file = NULL, *ip_file = NULL;
+	int fips_on = FIPS_mode();
 
 	/*
 	 * Force accepting of the host key for loopback/localhost. The
 	 * problem is that if the home directory is NFS-mounted to multiple
 	 * machines, localhost will refer to a different machine in each of
 	 * them, and the user will get bogus HOST_CHANGED warnings.  This
 	 * essentially disables host authentication for localhost; however,
 	 * this is probably not a real problem.
@@ -724,20 +727,20 @@ check_host_key(char *hostname, struct so
 				logit("Failed to add the %s host key for IP "
 				    "address '%.128s' to the list of known "
 				    "hosts (%.30s).", type, ip, user_hostfile);
 			else
 				logit("Warning: Permanently added the %s host "
 				    "key for IP address '%.128s' to the list "
 				    "of known hosts.", type, ip);
 		} else if (options.visual_host_key) {
-			fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
-			ra = key_fingerprint(host_key, SSH_FP_MD5,
+			fp = key_fingerprint(host_key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
+			ra = key_fingerprint(host_key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5,
 			    SSH_FP_RANDOMART);
-			logit("Host key fingerprint is %s\n%s\n", fp, ra);
+			logit("Host %skey fingerprint is %s\n%s\n", fips_on ? "SHA1 " : "", fp, ra);
 			xfree(ra);
 			xfree(fp);
 		}
 		break;
 	case HOST_NEW:
 		if (options.host_key_alias == NULL && port != 0 &&
 		    port != SSH_DEFAULT_PORT) {
 			debug("checking without port identifier");
@@ -764,37 +767,37 @@ check_host_key(char *hostname, struct so
 
 			if (show_other_keys(host, host_key))
 				snprintf(msg1, sizeof(msg1),
 				    "\nbut keys of different type are already"
 				    " known for this host.");
 			else
 				snprintf(msg1, sizeof(msg1), ".");
 			/* The default */
-			fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
-			ra = key_fingerprint(host_key, SSH_FP_MD5,
+			fp = key_fingerprint(host_key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
+			ra = key_fingerprint(host_key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5,
 			    SSH_FP_RANDOMART);
 			msg2[0] = '\0';
 			if (options.verify_host_key_dns) {
 				if (matching_host_key_dns)
 					snprintf(msg2, sizeof(msg2),
 					    "Matching host key fingerprint"
 					    " found in DNS.\n");
 				else
 					snprintf(msg2, sizeof(msg2),
 					    "No matching host key fingerprint"
 					    " found in DNS.\n");
 			}
 			snprintf(msg, sizeof(msg),
 			    "The authenticity of host '%.200s (%s)' can't be "
 			    "established%s\n"
-			    "%s key fingerprint is %s.%s%s\n%s"
+			    "%s key %sfingerprint is %s.%s%s\n%s"
 			    "Are you sure you want to continue connecting "
 			    "(yes/no)? ",
-			    host, ip, msg1, type, fp,
+			    host, ip, msg1, type, fips_on ? "SHA1 " : "", fp,
 			    options.visual_host_key ? "\n" : "",
 			    options.visual_host_key ? ra : "",
 			    msg2);
 			xfree(ra);
 			xfree(fp);
 			if (!confirm(msg))
 				goto fail;
 		}
@@ -1072,27 +1075,28 @@ ssh_put_password(char *password)
 }
 
 static int
 show_key_from_file(const char *file, const char *host, int keytype)
 {
 	Key *found;
 	char *fp, *ra;
 	int line, ret;
+	int fips_on = FIPS_mode();
 
 	found = key_new(keytype);
 	if ((ret = lookup_key_in_hostfile_by_type(file, host,
 	    keytype, found, &line))) {
-		fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
-		ra = key_fingerprint(found, SSH_FP_MD5, SSH_FP_RANDOMART);
+		fp = key_fingerprint(found, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
+		ra = key_fingerprint(found, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_RANDOMART);
 		logit("WARNING: %s key found for host %s\n"
 		    "in %s:%d\n"
-		    "%s key fingerprint %s.\n%s\n",
+		    "%s key %sfingerprint %s.\n%s\n",
 		    key_type(found), host, file, line,
-		    key_type(found), fp, ra);
+		    key_type(found), fips_on ? "SHA1 ":"", fp, ra);
 		xfree(ra);
 		xfree(fp);
 	}
 	key_free(found);
 	return (ret);
 }
 
 /* print all known host keys for a given host, but skip keys of given type */
@@ -1128,27 +1132,28 @@ show_other_keys(const char *host, Key *k
 	return (found);
 }
 
 static void
 warn_changed_key(Key *host_key)
 {
 	char *fp;
 	const char *type = key_type(host_key);
+	int fips_on = FIPS_mode();
 
-	fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+	fp = key_fingerprint(host_key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX);
 
 	error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
 	error("@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @");
 	error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
 	error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
 	error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
 	error("It is also possible that the %s host key has just been changed.", type);
-	error("The fingerprint for the %s key sent by the remote host is\n%s.",
-	    type, fp);
+	error("The %sfingerprint for the %s key sent by the remote host is\n%s.",
+	    fips_on ? "SHA1 ":"", type, fp);
 	error("Please contact your system administrator.");
 
 	xfree(fp);
 }
 
 /*
  * Execute a local command
  */
diff --git a/openssh-5.1p1/sshconnect2.c b/openssh-5.1p1/sshconnect2.c
--- a/openssh-5.1p1/sshconnect2.c
+++ b/openssh-5.1p1/sshconnect2.c
@@ -37,16 +37,18 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H)
 #include <vis.h>
 #endif
 
+#include <openssl/fips.h>
+
 #include "openbsd-compat/sys-queue.h"
 
 #include "xmalloc.h"
 #include "ssh.h"
 #include "ssh2.h"
 #include "buffer.h"
 #include "packet.h"
 #include "compat.h"
@@ -107,32 +109,40 @@ ssh_kex2(char *host, struct sockaddr *ho
 
 	if (options.ciphers == (char *)-1) {
 		logit("No valid ciphers for protocol version 2 given, using defaults.");
 		options.ciphers = NULL;
 	}
 	if (options.ciphers != NULL) {
 		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
 		myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
+	} else if (FIPS_mode()) {
+		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+		myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT;
+
 	}
 	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
 	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
 	myproposal[PROPOSAL_ENC_ALGS_STOC] =
 	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]);
 	if (options.compression) {
 		myproposal[PROPOSAL_COMP_ALGS_CTOS] =
 		myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib@openssh.com,zlib,none";
 	} else {
 		myproposal[PROPOSAL_COMP_ALGS_CTOS] =
 		myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com,zlib";
 	}
 	if (options.macs != NULL) {
 		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
 		myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
+	} else if (FIPS_mode()) {
+		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
+		myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC;
 	}
+
 	if (options.hostkeyalgorithms != NULL)
 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
 		    options.hostkeyalgorithms;
 
 	if (options.rekey_limit)
 		packet_set_rekey_limit((u_int32_t)options.rekey_limit);
 
 	/* start key exchange */
@@ -475,18 +485,18 @@ input_userauth_pk_ok(int type, u_int32_t
 		goto done;
 	}
 	if (key->type != pktype) {
 		error("input_userauth_pk_ok: type mismatch "
 		    "for decoded key (received %d, expected %d)",
 		    key->type, pktype);
 		goto done;
 	}
-	fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
-	debug2("input_userauth_pk_ok: fp %s", fp);
+	fp = key_fingerprint(key, SSH_FP_SHA1, SSH_FP_HEX);
+	debug2("input_userauth_pk_ok: SHA1 fp %s", fp);
 	xfree(fp);
 
 	/*
 	 * search keys in the reverse order, because last candidate has been
 	 * moved to the end of the queue.  this also avoids confusion by
 	 * duplicate keys
 	 */
 	TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) {
diff --git a/openssh-5.1p1/sshd.c b/openssh-5.1p1/sshd.c
--- a/openssh-5.1p1/sshd.c
+++ b/openssh-5.1p1/sshd.c
@@ -73,16 +73,17 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include <openssl/dh.h>
 #include <openssl/bn.h>
 #include <openssl/md5.h>
 #include <openssl/rand.h>
+#include <openssl/fips.h>
 #include "openbsd-compat/openssl-compat.h"
 #include <openssl/conf.h>
 #include <openssl/engine.h>
 
 #ifdef HAVE_SECUREWARE
 #include <sys/security.h>
 #include <prot.h>
 #endif
@@ -569,17 +570,17 @@ destroy_sensitive_data(int privsep)
 	pid = getpid();
 	uid = getuid();
 	for (i = 0; i < options.num_host_key_files; i++) {
 		if (sensitive_data.host_keys[i]) {
 			char *fp;
 
 			if (key_is_private(sensitive_data.host_keys[i]))
 				fp = key_fingerprint(sensitive_data.host_keys[i],
-					SSH_FP_MD5,
+					FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5,
 					SSH_FP_HEX);
 			else
 				fp = NULL;
 			key_free(sensitive_data.host_keys[i]);
 			sensitive_data.host_keys[i] = NULL;
 			if (fp != NULL) {
 				if (privsep)
 					PRIVSEP(audit_destroy_sensitive_data(fp,
@@ -613,17 +614,17 @@ demote_sensitive_data(void)
 	pid = getpid();
 	uid = getuid();
 	for (i = 0; i < options.num_host_key_files; i++) {
 		if (sensitive_data.host_keys[i]) {
 			char *fp;
 
 			if (key_is_private(sensitive_data.host_keys[i]))
 				fp = key_fingerprint(sensitive_data.host_keys[i],
-					SSH_FP_MD5,
+					FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5,
 					SSH_FP_HEX);
 			else
 				fp = NULL;
 			tmp = key_demote(sensitive_data.host_keys[i]);
 			key_free(sensitive_data.host_keys[i]);
 			sensitive_data.host_keys[i] = tmp;
 			if (tmp->type == KEY_RSA1)
 				sensitive_data.ssh1_host_key = tmp;
@@ -1605,16 +1606,20 @@ main(int ac, char **av)
 		case KEY_RSA:
 		case KEY_DSA:
 			sensitive_data.have_ssh2_key = 1;
 			break;
 		}
 		debug("private host key: #%d type %d %s", i, key->type,
 		    key_type(key));
 	}
+	if ((options.protocol & SSH_PROTO_1) && FIPS_mode()) {
+		logit("Disabling protocol version 1. Not allowed in the FIPS mode.");
+		options.protocol &= ~SSH_PROTO_1;
+	}
 	if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) {
 		logit("Disabling protocol version 1. Could not load host key");
 		options.protocol &= ~SSH_PROTO_1;
 	}
 	if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
 		logit("Disabling protocol version 2. Could not load host key");
 		options.protocol &= ~SSH_PROTO_2;
 	}
@@ -1729,16 +1734,20 @@ main(int ac, char **av)
 #endif /* TIOCNOTTY */
 	}
 	/* Reinitialize the log (because of the fork above). */
 	log_init(__progname, options.log_level, options.log_facility, log_stderr);
 
 	/* Initialize the random number generator. */
 	arc4random_stir();
 
+	if (FIPS_mode()) {
+		debug("FIPS mode initialized");
+	}
+
 	/* Chdir to the root directory so that the current disk can be
 	   unmounted if desired. */
 	chdir("/");
 
 	/* ignore SIGPIPE */
 	signal(SIGPIPE, SIG_IGN);
 
 	/* Get a connection, either from inetd or a listening TCP socket */
@@ -2263,25 +2272,31 @@ do_ssh1_kex(void)
 static void
 do_ssh2_kex(void)
 {
 	Kex *kex;
 
 	if (options.ciphers != NULL) {
 		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
 		myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
+	} else if (FIPS_mode()) {
+		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+		myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT;
 	}
 	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
 	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
 	myproposal[PROPOSAL_ENC_ALGS_STOC] =
 	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]);
 
 	if (options.macs != NULL) {
 		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
 		myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
+	} else if (FIPS_mode()) {
+		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
+		myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC;
 	}
 	if (options.compression == COMP_NONE) {
 		myproposal[PROPOSAL_COMP_ALGS_CTOS] =
 		myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
 	} else if (options.compression == COMP_DELAYED) {
 		myproposal[PROPOSAL_COMP_ALGS_CTOS] =
 		myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com";
 	}
