[ DRAFT PATCH ] - FIPS 140-2 patch for OpenSSH 6.5p1

Manish Jagtap manish.jagtap at airtightnetworks.com
Tue Feb 18 00:01:16 EST 2014


Hi,

I am facing some difficulties to attach the patch as a file. Trying now to
attach with plain-text email.

In addition, here is inline patch draft which is actually based on
openssh-6.0p1.fips-revised.patch.

I have also submitted via
https://bugzilla.mindrot.org/show_bug.cgi?id=2202

Request moderators to validate this patch and update as required.

Thanks,
Manish

--- PATCH START

diff -ruN openssh-6.5p1_orig/auth2-hostbased.c
openssh-6.5p1_patched/auth2-hostbased.c
--- openssh-6.5p1_orig/auth2-hostbased.c	2013-12-31
06:55:41.000000000 +0530
+++ openssh-6.5p1_patched/auth2-hostbased.c	2014-02-06
20:18:02.000000000 +0530
@@ -207,15 +207,15 @@
 	if (host_status == HOST_OK) {
 		if (key_is_cert(key)) {
 			fp = key_fingerprint(key->cert->signature_key,
-			    SSH_FP_MD5, SSH_FP_HEX);
+			    key_fp_type_select(), SSH_FP_HEX);
 			verbose("Accepted certificate ID \"%s\" signed by
"
 			    "%s CA %s from %s@%s", key->cert->key_id,
-			    key_type(key->cert->signature_key), fp,
+			    key_fp_type_select(), fp,
 			    cuser, lookup);
 		} else {
-			fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+			fp = key_fingerprint(key, key_fp_type_select(),
SSH_FP_HEX);
 			verbose("Accepted %s public key %s from %s@%s",
-			    key_type(key), fp, cuser, lookup);
+			    key_fp_type_select(), fp, cuser, lookup);
 		}
 		free(fp);
 	}
diff -ruN openssh-6.5p1_orig/auth2-pubkey.c
openssh-6.5p1_patched/auth2-pubkey.c
--- openssh-6.5p1_orig/auth2-pubkey.c	2013-12-31 06:55:41.000000000
+0530
+++ openssh-6.5p1_patched/auth2-pubkey.c	2014-02-06
20:18:32.000000000 +0530
@@ -213,7 +213,7 @@

 	if (key_is_cert(key)) {
 		fp = key_fingerprint(key->cert->signature_key,
-		    SSH_FP_MD5, SSH_FP_HEX);
+		    key_fp_type_select(), SSH_FP_HEX);
 		auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s",

 		    key_type(key), key->cert->key_id,
 		    (unsigned long long)key->cert->serial,
@@ -221,7 +221,7 @@
 		    extra == NULL ? "" : ", ", extra == NULL ? "" :
extra);
 		free(fp);
 	} else {
-		fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+		fp = key_fingerprint(key, key_fp_type_select(),
SSH_FP_HEX);
 		auth_info(authctxt, "%s %s%s%s", key_type(key), fp,
 		    extra == NULL ? "" : ", ", extra == NULL ? "" :
extra);
 		free(fp);
@@ -365,7 +365,7 @@
 				continue;
 			if (!key_is_cert_authority)
 				continue;
-			fp = key_fingerprint(found, SSH_FP_MD5,
+			fp = key_fingerprint(found, key_fp_type_select(),
 			    SSH_FP_HEX);
 			debug("matching CA found: file %s, line %lu, %s
%s",
 			    file, linenum, key_type(found), fp);
@@ -406,7 +406,7 @@
 			if (key_is_cert_authority)
 				continue;
 			found_key = 1;
-			fp = key_fingerprint(found, SSH_FP_MD5,
SSH_FP_HEX);
+			fp = key_fingerprint(found, key_fp_type_select(),
SSH_FP_HEX);
 			debug("matching key found: file %s, line %lu %s
%s",
 			    file, linenum, key_type(found), fp);
 			free(fp);
@@ -432,7 +432,7 @@
 		return 0;

 	ca_fp = key_fingerprint(key->cert->signature_key,
-	    SSH_FP_MD5, SSH_FP_HEX);
+	    key_fp_type_select(), SSH_FP_HEX);

 	if (key_in_file(key->cert->signature_key,
 	    options.trusted_user_ca_keys, 1) != 1) {
diff -ruN openssh-6.5p1_orig/auth.c openssh-6.5p1_patched/auth.c
--- openssh-6.5p1_orig/auth.c	2013-06-02 03:11:51.000000000 +0530
+++ openssh-6.5p1_patched/auth.c	2014-02-06 20:19:07.000000000
+0530
@@ -685,7 +685,7 @@
 	case 1:
  revoked:
 		/* Key revoked */
-		key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+		key_fp = key_fingerprint(key, key_fp_type_select(),
SSH_FP_HEX);
 		error("WARNING: authentication attempt with a revoked "
 		    "%s key %s ", key_type(key), key_fp);
 		free(key_fp);
diff -ruN openssh-6.5p1_orig/auth-rsa.c openssh-6.5p1_patched/auth-rsa.c
--- openssh-6.5p1_orig/auth-rsa.c	2013-07-18 11:42:44.000000000
+0530
+++ openssh-6.5p1_patched/auth-rsa.c	2014-02-06 20:27:36.000000000
+0530
@@ -2,7 +2,7 @@
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
- *                    All rights reserved
+ *		      All rights reserved
  * RSA-based authentication.  This code determines whether to admit a
login
  * based on RSA authentication.  This file also contains functions to
check
  * validity of the host key.
@@ -20,7 +20,7 @@
 #include <sys/stat.h>

 #include <openssl/rsa.h>
-#include <openssl/md5.h>
+#include <openssl/evp.h>

 #include <pwd.h>
 #include <stdio.h>
@@ -47,6 +47,7 @@
 #include "monitor_wrap.h"
 #include "ssh.h"
 #include "misc.h"
+#include "fips.h"

 /* import */
 extern ServerOptions options;
@@ -88,11 +89,14 @@
 }

 int
-auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char
response[16])
+auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char
response[MAX_HASH_LEN])
 {
-	u_char buf[32], mdbuf[16];
-	MD5_CTX md;
+	u_char buf[2 * MAX_HASH_LEN], mdbuf[MAX_HASH_LEN];
+	const EVP_MD *evp_md;
+	EVP_MD_CTX md;
+
 	int len;
+	int hash_len;

 	/* don't allow short keys */
 	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
@@ -101,19 +105,29 @@
 		return (0);
 	}

-	/* The response is MD5 of decrypted challenge plus session id. */
+	hash_len = fips_hash_len(fips_hash_min());
+
+	/* The response is a hash of decrypted challenge plus session id.
+	 * Normally this is MD5, in FIPS mode a stronger function is
used.*/
+
+
 	len = BN_num_bytes(challenge);
-	if (len <= 0 || len > 32)
+	if (len <= 0 || len > (2 * hash_len))
 		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, sizeof(buf));
+	BN_bn2bin(challenge, buf + 2 * hash_len - len);
+
+	if ((evp_md = fips_EVP_get_digest_min()) == NULL) {
+				   fatal("auth_rsa_verify_response:
fips_EVP_get_digest_min failed");
+	}
+	EVP_DigestInit(&md, evp_md);
+	EVP_DigestUpdate(&md, buf, 2 * hash_len);
+	EVP_DigestUpdate(&md, session_id, hash_len);
+	EVP_DigestFinal(&md, mdbuf, NULL);

 	/* Verify that the response is the original challenge. */
-	if (timingsafe_bcmp(response, mdbuf, 16) != 0) {
+	if (timingsafe_bcmp(response, mdbuf, hash_len) != 0) {
 		/* Wrong answer. */
 		return (0);
 	}
@@ -131,7 +145,7 @@
 auth_rsa_challenge_dialog(Key *key)
 {
 	BIGNUM *challenge, *encrypted_challenge;
-	u_char response[16];
+	u_char response[MAX_HASH_LEN];
 	int i, success;

 	if ((encrypted_challenge = BN_new()) == NULL)
@@ -151,7 +165,7 @@

 	/* Wait for a response. */
 	packet_read_expect(SSH_CMSG_AUTH_RSA_RESPONSE);
-	for (i = 0; i < 16; i++)
+	for (i = 0; i < fips_hash_len(fips_hash_min()); i++)
 		response[i] = (u_char)packet_get_char();
 	packet_check_eom();

@@ -231,7 +245,7 @@
 			    "actual %d vs. announced %d.",
 			    file, linenum, BN_num_bits(key->rsa->n),
bits);

-		fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+		fp = key_fingerprint(key, key_fp_type_select(),
SSH_FP_HEX);
 		debug("matching key found: file %s, line %lu %s %s",
 		    file, linenum, key_type(key), fp);
 		free(fp);
diff -ruN openssh-6.5p1_orig/cipher.c openssh-6.5p1_patched/cipher.c
--- openssh-6.5p1_orig/cipher.c	2014-01-26 04:07:26.000000000 +0530
+++ openssh-6.5p1_patched/cipher.c	2014-02-07 00:52:15.000000000
+0530
@@ -2,7 +2,7 @@
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
- *                    All rights reserved
+ *		      All rights reserved
  *
  * As far as I am concerned, the code I have written for this software
  * can be used freely for any purpose.  Any derived versions of this
@@ -49,6 +49,7 @@
 #include "log.h"
 #include "misc.h"
 #include "cipher.h"
+#include "fips.h"

 /* compatibility with old or broken OpenSSL versions */
 #include "openbsd-compat/openssl-compat.h"
@@ -104,8 +105,50 @@
 	{ NULL,		SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL }
 };

+struct Cipher ciphers_fips140_2[] = {
+	{ "none",	SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
+	{ "3des",	SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des
},
+
+	{ "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 at 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 at openssh.com",
+					    SSH_CIPHER_SSH2, 16, 16, 12,
16, 0, 0, EVP_aes_128_gcm },
+	{ "aes256-gcm at openssh.com",
+					    SSH_CIPHER_SSH2, 16, 32, 12,
16, 0, 0, EVP_aes_256_gcm },
+#endif
+	{ "chacha20-poly1305 at openssh.com",
+			SSH_CIPHER_SSH2, 8, 64, 0, 16, 0,
CFLAG_CHACHAPOLY, NULL },
+	{ NULL,	  SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL }
+};
+
 /*--*/

+static struct Cipher *
+fips_select_ciphers(void)
+{
+	int fips = fips_mode();
+	switch (fips) {
+		 case 0:
+			  return ciphers;
+		 case 1:
+			  return ciphers_fips140_2;
+		 default:
+	/* should not be reached */
+	fatal("Fatal error: incorrect FIPS mode '%i' at %s:%u",
+	fips, __FILE__, __LINE__);
+//     return NULL;
+	}
+}
+
+
 /* Returns a list of supported ciphers separated by the specified char.
*/
 char *
 cipher_alg_list(char sep, int auth_only)
@@ -194,7 +237,7 @@
 cipher_by_name(const char *name)
 {
 	const Cipher *c;
-	for (c = ciphers; c->name != NULL; c++)
+	for (c = fips_select_ciphers(); c->name != NULL; c++)
 		if (strcmp(c->name, name) == 0)
 			return c;
 	return NULL;
@@ -204,7 +247,7 @@
 cipher_by_number(int id)
 {
 	const Cipher *c;
-	for (c = ciphers; c->name != NULL; c++)
+	for (c = fips_select_ciphers(); c->name != NULL; c++)
 		if (c->number == id)
 			return c;
 	return NULL;
@@ -248,7 +291,7 @@
 	const Cipher *c;
 	if (name == NULL)
 		return -1;
-	for (c = ciphers; c->name != NULL; c++)
+	for (c =  fips_select_ciphers(); c->name != NULL; c++)
 		if (strcasecmp(c->name, name) == 0)
 			return c->number;
 	return -1;
@@ -436,14 +479,19 @@
 cipher_set_key_string(CipherContext *cc, const Cipher *cipher,
     const char *passphrase, int do_encrypt)
 {
-	MD5_CTX md;
-	u_char digest[16];
+	const EVP_MD *evp_md;
+	EVP_MD_CTX md;
+	u_char digest[MAX_HASH_LEN];
+	int dlen;
+	if ((evp_md = fips_EVP_get_digest_min()) == NULL) {
+		 fatal("auth_rsa_verify_response: fips_EVP_get_digest_min
failed");
+	}

-	MD5_Init(&md);
-	MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase));
-	MD5_Final(digest, &md);
+	EVP_DigestInit(&md, evp_md);
+	EVP_DigestUpdate(&md, (const u_char *)passphrase,
strlen(passphrase));
+	EVP_DigestFinal(&md, digest, &dlen);

-	cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt);
+	cipher_init(cc, cipher, digest, dlen, NULL, 0, do_encrypt);

 	memset(digest, 0, sizeof(digest));
 	memset(&md, 0, sizeof(md));
diff -ruN openssh-6.5p1_orig/cipher-ctr.c
openssh-6.5p1_patched/cipher-ctr.c
--- openssh-6.5p1_orig/cipher-ctr.c	2013-06-02 03:37:32.000000000
+0530
+++ openssh-6.5p1_patched/cipher-ctr.c	2014-02-07 00:54:23.000000000
+0530
@@ -26,6 +26,7 @@

 #include "xmalloc.h"
 #include "log.h"
+#include "fips.h"

 /* compatibility with old or broken OpenSSL versions */
 #include "openbsd-compat/openssl-compat.h"
@@ -139,6 +140,9 @@
 #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 -ruN openssh-6.5p1_orig/fips.c openssh-6.5p1_patched/fips.c
--- openssh-6.5p1_orig/fips.c	1970-01-01 05:30:00.000000000 +0530
+++ openssh-6.5p1_patched/fips.c	2014-02-07 00:56:54.000000000
+0530
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2012 Petr Cerny.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "fips.h"
+
+#include "log.h"
+
+enum hgp {
+	HGP_LEN,
+	HGP_NID
+};
+
+static int fips_state = -1;
+
+static const struct Hashes {
+	enum hash_type ht;
+	int byte_length;
+	int nid;
+} hashes[] = {
+	{ HASH_MD5,    HASH_LEN_MD5,    NID_md5 },
+	{ HASH_SHA1,   HASH_LEN_SHA1,   NID_sha1 },
+	{ HASH_SHA256, HASH_LEN_SHA256, NID_sha256 },
+	{ HASH_err,    -1,              -1 }
+};
+
+int
+fips_mode()
+{
+	if (-1 == fips_state) {
+		fips_state = FIPS_mode();
+		if (fips_state)
+			debug("FIPS mode initialized");
+	}
+	return fips_state;
+}
+
+static int
+fips_hash_get_param(enum hash_type ht, int param)
+{
+	int i;
+	for (i = 0; i < HASH_err; i++) {
+		if (hashes[i].ht == ht) {
+			switch (param) {
+				case HGP_LEN:
+					return hashes[i].byte_length;
+				case HGP_NID:
+					return hashes[i].nid;
+				default:
+					fatal("Fatal error: internal error
at %s:%u",
+					    __FILE__, __LINE__);
+			}
+		}
+	}
+	/* should not be reached */
+	fatal("Fatal error: incorrect hash type '%i' at %s:%u",
+	    ht, __FILE__, __LINE__);
+//    return -1;
+}
+
+int
+fips_hash2nid(enum hash_type ht)
+{
+	return fips_hash_get_param(ht, HGP_NID);
+}
+
+int
+fips_hash_len(enum hash_type ht)
+{
+	return fips_hash_get_param(ht, HGP_LEN);
+}
+
+void
+fips_correct_fp_type(enum fp_type *fp)
+{
+	int fips;
+
+	fips = fips_mode();
+	switch (fips) {
+		case 0:
+			break;
+		case 1:
+			if (SSH_FP_MD5 == *fp) {
+				*fp = SSH_FP_SHA1;
+				logit("MD5 not allowed in FIPS 140-2 mode,
"
+				    "using SHA-1 for key fingerprints
instead.");
+			}
+			break;
+		default:
+			/* should not be reached */
+			fatal("Fatal error: incorrect FIPS mode '%i' at
%s:%u",
+			    fips, __FILE__, __LINE__);
+	}
+
+	return;
+}
+
+void
+fips_correct_nid(int *nid)
+{
+	int fips;
+
+	fips = fips_mode();
+	switch (fips) {
+		case 0:
+			break;
+		case 1:
+			if (NID_md5 == *nid) {
+				*nid = NID_sha1;
+				logit("MD5 not allowed in FIPS 140-2 mode,
"
+				    "using SHA-1 for hashing instead.");
+			}
+			break;
+		default:
+			/* should not be reached */
+			fatal("Fatal error: incorrect FIPS mode '%i' at
%s:%u",
+			    fips, __FILE__, __LINE__);
+	}
+
+	return;
+}
+
+enum hash_type
+fips_hash_min(void)
+{
+	int fips;
+	enum hash_type ht;
+
+	fips = fips_mode();
+	switch (fips) {
+		case 0:
+			ht = HASH_MD5;
+			break;
+		case 1:
+			ht = HASH_SHA1;
+			break;
+		default:
+			/* should not be reached */
+			fatal("Fatal error: incorrect FIPS mode '%i' at
%s:%u",
+			    fips, __FILE__, __LINE__);
+	}
+	return ht;
+}
+
+enum hash_type
+fips_hash_nid_min()
+{
+	return fips_hash2nid(fips_hash_min());
+}
+
+const EVP_MD *
+fips_EVP_get_digest_min(void)
+{
+	return EVP_get_digestbynid(fips_hash_nid_min());
+}
+
diff -ruN openssh-6.5p1_orig/fips.h openssh-6.5p1_patched/fips.h
--- openssh-6.5p1_orig/fips.h	1970-01-01 05:30:00.000000000 +0530
+++ openssh-6.5p1_patched/fips.h	2014-02-07 00:58:38.000000000
+0530
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012 Petr Cerny.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in
the
+ *	documentation and/or other materials provided with the
distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef FIPS_H
+#define FIPS_H
+
+#include <openssl/evp.h>
+
+#include "key.h"
+
+#define HASH_LEN_MD5	16
+#define HASH_LEN_SHA1	20
+#define HASH_LEN_SHA256	32
+#define MAX_HASH_LEN	HASH_LEN_SHA256
+
+enum hash_type {
+	HASH_MD5 = 1,
+	HASH_SHA1,
+	HASH_SHA256,
+	HASH_err
+};
+
+int	 fips_mode(void);
+void	 fips_correct_fp_type(enum fp_type *);
+void	 fips_correct_nid(int *);
+
+enum hash_type	 fips_hash_min(void);
+const EVP_MD	*fips_EVP_get_digest_min(void);
+int		 fips_hash2nid(enum hash_type);
+int		 fips_hash_len(enum hash_type);
+
+#endif
diff -ruN openssh-6.5p1_orig/key.c openssh-6.5p1_patched/key.c
--- openssh-6.5p1_orig/key.c	2014-01-10 05:28:53.000000000 +0530
+++ openssh-6.5p1_patched/key.c	2014-02-11 00:57:29.000000000 +0530
@@ -57,6 +57,7 @@
 #include "misc.h"
 #include "ssh2.h"
 #include "digest.h"
+#include "fips.h"

 static int to_blob(const Key *, u_char **, u_int *, int);
 static Key *key_from_blob2(const u_char *, u_int, int);
@@ -425,12 +426,12 @@
 }

 static char *
-key_fingerprint_hex(u_char *dgst_raw, u_int dgst_raw_len)
+key_fingerprint_hex(u_char *dgst_raw, u_int dgst_raw_len, enum fp_type
dgst_type)
 {
 	char *retval;
 	u_int i;

-	retval = xcalloc(1, dgst_raw_len * 3 + 1);
+	retval = xcalloc(1, dgst_raw_len * 3 + 1 + SSH_FP_TYPE_STRLEN +
2);
 	for (i = 0; i < dgst_raw_len; i++) {
 		char hex[4];
 		snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]);
@@ -438,7 +439,14 @@
 	}

 	/* Remove the trailing ':' character */
-	retval[(dgst_raw_len * 3) - 1] = '\0';
+	retval[(dgst_raw_len * 3) - 1] = ' ';
+	/* Append hash type */
+	{
+		char hash[SSH_FP_TYPE_STRLEN + 2 + 1];
+		snprintf(hash, sizeof(hash), "[%s]",
key_fp_type_str(dgst_type));
+		strlcat(retval, hash, dgst_raw_len * 3 + 1 +
SSH_FP_TYPE_STRLEN + 2);
+	}
+
 	return retval;
 }

@@ -523,7 +531,7 @@
 #define	FLDSIZE_Y	(FLDBASE + 1)
 #define	FLDSIZE_X	(FLDBASE * 2 + 1)
 static char *
-key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key
*k)
+key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key
*k, enum fp_type dgst_type)
 {
 	/*
 	 * Chars to be used after each other every time the worm
@@ -590,8 +598,9 @@
 	}

 	/* output lower border */
-	*p++ = '+';
-	for (i = 0; i < FLDSIZE_X; i++)
+	i = snprintf(p, FLDSIZE_X, "+--[%s]", key_fp_type_str(dgst_type));
+	p += i;
+	for (i--; i < FLDSIZE_X; i++)
 		*p++ = '-';
 	*p++ = '+';

@@ -610,13 +619,13 @@
 		fatal("key_fingerprint: null from key_fingerprint_raw()");
 	switch (dgst_rep) {
 	case SSH_FP_HEX:
-		retval = key_fingerprint_hex(dgst_raw, dgst_raw_len);
+		retval = key_fingerprint_hex(dgst_raw, dgst_raw_len,
dgst_type);
 		break;
 	case SSH_FP_BUBBLEBABBLE:
 		retval = key_fingerprint_bubblebabble(dgst_raw,
dgst_raw_len);
 		break;
 	case SSH_FP_RANDOMART:
-		retval = key_fingerprint_randomart(dgst_raw, dgst_raw_len,
k);
+		retval = key_fingerprint_randomart(dgst_raw, dgst_raw_len,
k, dgst_type);
 		break;
 	default:
 		fatal("key_fingerprint: bad digest representation %d",
@@ -628,6 +637,65 @@
 	return retval;
 }

+enum fp_type
+key_fp_type_select(void)
+{
+	static enum fp_type fp;
+	static char fp_defined = 0;
+	char *env;
+
+	if (!fp_defined) {
+		env = getenv(SSH_FP_TYPE_ENVVAR);
+		if (env) {
+			if (!strcasecmp(env, "md5") ||
+				!strcasecmp(env, "md-5"))
+				fp = SSH_FP_MD5;
+			else if (!strcasecmp(env, "sha1") ||
+				!strcasecmp(env, "sha-1"))
+				fp = SSH_FP_SHA1;
+#ifdef HAVE_EVP_SHA256
+			else if (!strcasecmp(env, "sha256") ||
+					!strcasecmp(env, "sha-256"))
+				fp = SSH_FP_SHA256;
+#endif
+			else {
+				error("invalid key type in environment
variable "
+						SSH_FP_TYPE_ENVVAR ": '%s'
- falling back to MD5.",
+						env);
+				fp = SSH_FP_MD5;
+				}
+		} else
+			fp = SSH_FP_MD5;
+
+		if (fips_mode())
+			fips_correct_fp_type(&fp);
+
+		fp_defined = 1;
+	}
+	return fp;
+}
+
+/*
+ * string lengths must be less or equal to SSH_FP_TYPE_STRLEN (defined in
+ * key.h) as to fit into the fingerprint string buffer
+ */
+char *
+key_fp_type_str(enum fp_type dgst_type)
+{
+	switch (dgst_type) {
+		case SSH_FP_MD5:
+			return "MD5";
+		case SSH_FP_SHA1:
+			return "SHA-1";
+#ifdef HAVE_EVP_SHA256
+		case SSH_FP_SHA256:
+			return "SHA-256";
+#endif
+		default:
+			fatal("%s: unknown key fingerprint hash algorithm
requested", __func__);
+	}
+}
+
 /*
  * Reads a multiple-precision integer in decimal from the buffer, and
advances
  * the pointer.  The integer must already be initialized.  This function
is
diff -ruN openssh-6.5p1_orig/key.h openssh-6.5p1_patched/key.h
--- openssh-6.5p1_orig/key.h	2014-01-10 05:28:53.000000000 +0530
+++ openssh-6.5p1_patched/key.h	2014-02-07 01:09:41.000000000 +0530
@@ -58,6 +58,8 @@
 	SSH_FP_BUBBLEBABBLE,
 	SSH_FP_RANDOMART
 };
+#define SSH_FP_TYPE_ENVVAR  "SSH_FINGERPRINT_TYPE"
+#define SSH_FP_TYPE_STRLEN  8

 /* key is stored in external hardware */
 #define KEY_FLAG_EXT		0x0001
@@ -109,6 +111,9 @@
 int		 key_write(const Key *, FILE *);
 int		 key_read(Key *, char **);
 u_int		 key_size(const Key *);
+enum fp_type	  key_fp_type_select(void);
+char	  *key_fp_type_str(enum fp_type);
+

 Key	*key_generate(int, u_int);
 Key	*key_from_private(const Key *);
diff -ruN openssh-6.5p1_orig/mac.c openssh-6.5p1_patched/mac.c
--- openssh-6.5p1_orig/mac.c	2014-01-10 05:07:05.000000000 +0530
+++ openssh-6.5p1_patched/mac.c	2014-02-07 01:14:38.000000000 +0530
@@ -41,6 +41,7 @@
 #include "kex.h"
 #include "mac.h"
 #include "misc.h"
+#include "fips.h"

 #include "umac.h"

@@ -60,7 +61,7 @@
 	int		etm;		/* Encrypt-then-MAC */
 };

-static const struct macalg macs[] = {
+static const struct macalg all_macs[] = {
 	/* Encrypt-and-MAC (encrypt-and-authenticate) variants */
 	{ "hmac-sha1",				SSH_EVP, EVP_sha1, 0, 0,
0, 0 },
 	{ "hmac-sha1-96",			SSH_EVP, EVP_sha1, 96, 0,
0, 0 },
@@ -90,6 +91,30 @@

 	{ NULL,					0, NULL, 0, 0, 0, 0 }
 };
+struct macalg macs_fips140_2[] = {
+	{ "hmac-sha1",				SSH_EVP, EVP_sha1, 0, 0,
0, 0 },
+#ifdef HAVE_EVP_SHA256
+	{ "hmac-sha2-256",			SSH_EVP, EVP_sha256, 0, 0,
0, 0 },
+	{ "hmac-sha2-512",			SSH_EVP, EVP_sha512, 0, 0,
0, 0 },
+#endif
+	{ NULL,					0, NULL, 0, 0, 0, 0 }
+};
+
+static struct macalg *
+fips_select_macs(void)
+{
+	int fips = fips_mode();
+	switch (fips) {
+		case 0:
+			return all_macs;
+		case 1:
+			return macs_fips140_2;
+		default:
+			/* should not be reached */
+			fatal("Fatal error: incorrect FIPS mode '%i' at
%s:%u", fips, __FILE__, __LINE__);
+//			return NULL;
+	}
+}

 /* Returns a list of supported MACs separated by the specified char. */
 char *
@@ -97,9 +122,9 @@
 {
 	char *ret = NULL;
 	size_t nlen, rlen = 0;
-	const struct macalg *m;
+	const struct macalg *m = fips_select_macs();

-	for (m = macs; m->name != NULL; m++) {
+	for (; m->name != NULL; m++) {
 		if (ret != NULL)
 			ret[rlen++] = sep;
 		nlen = strlen(m->name);
@@ -134,9 +159,9 @@
 int
 mac_setup(Mac *mac, char *name)
 {
-	const struct macalg *m;
+	const struct macalg *m = fips_select_macs();

-	for (m = macs; m->name != NULL; m++) {
+	for (; m->name != NULL; m++) {
 		if (strcmp(name, m->name) != 0)
 			continue;
 		if (mac != NULL)
diff -ruN openssh-6.5p1_orig/Makefile.in openssh-6.5p1_patched/Makefile.in
--- openssh-6.5p1_orig/Makefile.in	2014-01-27 12:05:04.000000000
+0530
+++ openssh-6.5p1_patched/Makefile.in	2014-02-07 01:58:20.000000000
+0530
@@ -76,7 +76,7 @@
 	jpake.o schnorr.o ssh-pkcs11.o krl.o smult_curve25519_ref.o \
 	kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \
 	ssh-ed25519.o digest.o \
-	sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o
+	sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o
fips.o

 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
 	sshconnect.o sshconnect1.o sshconnect2.o mux.o \
diff -ruN openssh-6.5p1_orig/myproposal.h
openssh-6.5p1_patched/myproposal.h
--- openssh-6.5p1_orig/myproposal.h	2013-12-07 05:54:02.000000000
+0530
+++ openssh-6.5p1_patched/myproposal.h	2014-02-07 02:00:09.000000000
+0530
@@ -109,6 +109,10 @@
 	"chacha20-poly1305 at openssh.com," \
 	"aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \
 	"aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se"
+#define    KEX_FIPS_140_2_ENCRYPT \
+	"aes128-ctr,aes192-ctr,aes256-ctr," \
+	"aes128-cbc,3des-cbc," \
+	"aes192-cbc,aes256-cbc,rijndael-cbc at lysator.liu.se"

 #define	KEX_DEFAULT_MAC \
 	"hmac-md5-etm at openssh.com," \
@@ -129,6 +133,10 @@
 	"hmac-ripemd160 at openssh.com," \
 	"hmac-sha1-96," \
 	"hmac-md5-96"
+#define    KEX_FIPS_140_2_MAC \
+	"hmac-sha1," \
+	SHA2_HMAC_MODES
+

 #define	KEX_DEFAULT_COMP	"none,zlib at openssh.com,zlib"
 #define	KEX_DEFAULT_LANG	""
diff -ruN openssh-6.5p1_orig/openbsd-compat/arc4random.c
openssh-6.5p1_patched/openbsd-compat/arc4random.c
--- openssh-6.5p1_orig/openbsd-compat/arc4random.c	2013-10-09
05:14:49.000000000 +0530
+++ openssh-6.5p1_patched/openbsd-compat/arc4random.c	2014-02-07
02:02:32.000000000 +0530
@@ -37,6 +37,7 @@
 #include <openssl/err.h>

 #include "log.h"
+#include "fips.h"

 #define KEYSTREAM_ONLY
 #include "chacha_private.h"
diff -ruN openssh-6.5p1_orig/ssh-add.c openssh-6.5p1_patched/ssh-add.c
--- openssh-6.5p1_orig/ssh-add.c	2013-12-29 12:14:07.000000000
+0530
+++ openssh-6.5p1_patched/ssh-add.c	2014-02-07 02:08:54.000000000
+0530
@@ -330,7 +330,7 @@
 		    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,
key_fp_type_select(),
 				    SSH_FP_HEX);
 				printf("%d %s %s (%s)\n",
 				    key_size(key), fp, comment,
key_type(key));
diff -ruN openssh-6.5p1_orig/ssh-agent.c openssh-6.5p1_patched/ssh-agent.c
--- openssh-6.5p1_orig/ssh-agent.c	2013-12-29 12:15:52.000000000
+0530
+++ openssh-6.5p1_patched/ssh-agent.c	2014-02-07 02:09:21.000000000
+0530
@@ -198,7 +198,7 @@
 	char *p;
 	int ret = -1;

-	p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
+	p = key_fingerprint(id->key, key_fp_type_select(), SSH_FP_HEX);
 	if (ask_permission("Allow use of key %s?\nKey fingerprint %s.",
 	    id->comment, p))
 		ret = 0;
diff -ruN openssh-6.5p1_orig/ssh.c openssh-6.5p1_patched/ssh.c
--- openssh-6.5p1_orig/ssh.c	2013-12-29 12:23:40.000000000 +0530
+++ openssh-6.5p1_patched/ssh.c	2014-02-07 02:11:49.000000000 +0530
@@ -104,6 +104,7 @@
 #include "uidswap.h"
 #include "roaming.h"
 #include "version.h"
+#include "fips.h"

 #ifdef ENABLE_PKCS11
 #include "ssh-pkcs11.h"
@@ -458,6 +459,8 @@
 	    "ACD:E:F:I:KL:MNO:PQ:R:S:TVw:W:XYy")) != -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':
@@ -964,6 +967,12 @@

 	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, addrs, &hostaddr, options.port,
 	    options.address_family, options.connection_attempts,
diff -ruN openssh-6.5p1_orig/sshconnect2.c
openssh-6.5p1_patched/sshconnect2.c
--- openssh-6.5p1_orig/sshconnect2.c	2014-01-10 05:28:53.000000000
+0530
+++ openssh-6.5p1_patched/sshconnect2.c	2014-02-07 02:16:14.000000000
+0530
@@ -72,6 +72,7 @@
 #include "hostfile.h"
 #include "schnorr.h"
 #include "jpake.h"
+#include "fips.h"

 #ifdef GSSAPI
 #include "ssh-gss.h"
@@ -170,6 +171,9 @@
 	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_140_2_ENCRYPT;
 	}
 	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
 	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
@@ -185,6 +189,9 @@
 	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_140_2_MAC;
 	}
 	if (options.hostkeyalgorithms != NULL)
 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
@@ -592,7 +599,7 @@
 		    key->type, pktype);
 		goto done;
 	}
-	fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+	fp = key_fingerprint(key, key_fp_type_select(), SSH_FP_HEX);
 	debug2("input_userauth_pk_ok: fp %s", fp);
 	free(fp);

@@ -1204,7 +1211,7 @@
 	int have_sig = 1;
 	char *fp;

-	fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
+	fp = key_fingerprint(id->key, key_fp_type_select(), SSH_FP_HEX);
 	debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp);
 	free(fp);

diff -ruN openssh-6.5p1_orig/sshconnect.c
openssh-6.5p1_patched/sshconnect.c
--- openssh-6.5p1_orig/sshconnect.c	2014-01-10 05:29:24.000000000
+0530
+++ openssh-6.5p1_patched/sshconnect.c	2014-02-07 02:17:50.000000000
+0530
@@ -911,8 +911,8 @@
 				    "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,
key_fp_type_select(), SSH_FP_HEX);
+			ra = key_fingerprint(host_key,
key_fp_type_select(),
 			    SSH_FP_RANDOMART);
 			logit("Host key fingerprint is %s\n%s\n", fp, ra);
 			free(ra);
@@ -952,8 +952,8 @@
 			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,
key_fp_type_select(), SSH_FP_HEX);
+			ra = key_fingerprint(host_key,
key_fp_type_select(),
 			    SSH_FP_RANDOMART);
 			msg2[0] = '\0';
 			if (options.verify_host_key_dns) {
@@ -1217,7 +1217,7 @@
 	int flags = 0;
 	char *fp;

-	fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+	fp = key_fingerprint(host_key, key_fp_type_select(), SSH_FP_HEX);
 	debug("Server host key: %s %s", key_type(host_key), fp);
 	free(fp);

@@ -1324,8 +1324,8 @@
 			continue;
 		if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i],
&found))
 			continue;
-		fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX);
-		ra = key_fingerprint(found->key, SSH_FP_MD5,
SSH_FP_RANDOMART);
+		fp = key_fingerprint(found->key, key_fp_type_select(),
SSH_FP_HEX);
+		ra = key_fingerprint(found->key, key_fp_type_select(),
SSH_FP_RANDOMART);
 		logit("WARNING: %s key found for host %s\n"
 		    "in %s:%lu\n"
 		    "%s key fingerprint %s.",
@@ -1346,7 +1346,7 @@
 {
 	char *fp;

-	fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+	fp = key_fingerprint(host_key, key_fp_type_select(), SSH_FP_HEX);


error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
 	error("@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
@");
diff -ruN openssh-6.5p1_orig/sshd.c openssh-6.5p1_patched/sshd.c
--- openssh-6.5p1_orig/sshd.c	2014-01-28 09:38:13.000000000 +0530
+++ openssh-6.5p1_patched/sshd.c	2014-02-07 02:22:10.000000000
+0530
@@ -121,6 +121,7 @@
 #include "roaming.h"
 #include "ssh-sandbox.h"
 #include "version.h"
+#include "fips.h"

 #ifdef LIBWRAP
 #include <tcpd.h>
@@ -1717,6 +1718,10 @@
 		debug("private host key: #%d type %d %s", i, keytype,
 		    key_type(key ? key : pubkey));
 	}
+	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;
@@ -2429,6 +2434,9 @@
 	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_140_2_ENCRYPT;
 	}
 	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
 	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
@@ -2438,6 +2446,9 @@
 	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_140_2_MAC;
 	}
 	if (options.compression == COMP_NONE) {
 		myproposal[PROPOSAL_COMP_ALGS_CTOS] =
diff -ruN openssh-6.5p1_orig/ssh-keygen.c
openssh-6.5p1_patched/ssh-keygen.c
--- openssh-6.5p1_orig/ssh-keygen.c	2013-12-07 05:54:02.000000000
+0530
+++ openssh-6.5p1_patched/ssh-keygen.c	2014-02-07 02:27:57.000000000
+0530
@@ -746,7 +746,7 @@
 	enum fp_type fptype;
 	char *fp, *ra;

-	fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
+	fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fp_type_select();
 	rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;

 	pkcs11_init(0);
@@ -801,7 +801,7 @@
 	public = key_load_public(identity_file, &comment);
 	if (public != NULL) {
 		fp = key_fingerprint(public, fptype, rep);
-		ra = key_fingerprint(public, SSH_FP_MD5,
SSH_FP_RANDOMART);
+		ra = key_fingerprint(public, key_fp_type_select(),
SSH_FP_RANDOMART);
 		printf("%u %s %s (%s)\n", key_size(public), fp, comment,
 		    key_type(public));
 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
@@ -867,7 +867,7 @@
 		}
 		comment = *cp ? cp : comment;
 		fp = key_fingerprint(public, fptype, rep);
-		ra = key_fingerprint(public, SSH_FP_MD5,
SSH_FP_RANDOMART);
+		ra = key_fingerprint(public, key_fp_type_select(),
SSH_FP_RANDOMART);
 		printf("%u %s %s (%s)\n", key_size(public), fp,
 		    comment ? comment : "no comment", key_type(public));
 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
@@ -988,10 +988,10 @@
 		enum fp_type fptype;
 		char *fp, *ra;

-		fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
+		fptype = print_bubblebabble ? SSH_FP_SHA1 :
key_fp_type_select();
 		rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE :
SSH_FP_HEX;
 		fp = key_fingerprint(public, fptype, rep);
-		ra = key_fingerprint(public, SSH_FP_MD5,
SSH_FP_RANDOMART);
+		ra = key_fingerprint(public, key_fp_type_select(),
SSH_FP_RANDOMART);
 		printf("%u %s %s (%s)\n", key_size(public), fp, name,
 		    key_type(public));
 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
@@ -1878,9 +1878,9 @@
 		fatal("%s is not a certificate", identity_file);
 	v00 = key->type == KEY_RSA_CERT_V00 || key->type ==
KEY_DSA_CERT_V00;

-	key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+	key_fp = key_fingerprint(key, key_fp_type_select(), SSH_FP_HEX);
 	ca_fp = key_fingerprint(key->cert->signature_key,
-	    SSH_FP_MD5, SSH_FP_HEX);
+	    key_fp_type_select(), SSH_FP_HEX);

 	printf("%s:\n", identity_file);
 	printf("        Type: %s %s certificate\n", key_ssh_name(key),
@@ -2686,8 +2686,8 @@
 	fclose(f);

 	if (!quiet) {
-		char *fp = key_fingerprint(public, SSH_FP_MD5,
SSH_FP_HEX);
-		char *ra = key_fingerprint(public, SSH_FP_MD5,
+		char *fp = key_fingerprint(public, key_fp_type_select(),
SSH_FP_HEX);
+		char *ra = key_fingerprint(public, key_fp_type_select(),
 		    SSH_FP_RANDOMART);
 		printf("Your public key has been saved in %s.\n",
 		    identity_file);
diff -ruN openssh-6.5p1_orig/ssh-rsa.c openssh-6.5p1_patched/ssh-rsa.c
--- openssh-6.5p1_orig/ssh-rsa.c	2014-01-10 05:28:53.000000000
+0530
+++ openssh-6.5p1_patched/ssh-rsa.c	2014-02-07 02:36:26.000000000
+0530
@@ -33,6 +33,7 @@
 #include "misc.h"
 #include "ssh.h"
 #include "digest.h"
+#include "fips.h"

 static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA
*);

@@ -56,6 +57,7 @@
 	/* hash the data */
 	hash_alg = SSH_DIGEST_SHA1;
 	nid = NID_sha1;
+	fips_correct_nid(&nid);
 	if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
 		error("%s: bad hash algorithm %d", __func__, hash_alg);
 		return -1;

--- PATCH END

-----Original Message-----
From: Steve Marquess [mailto:marquess at opensslfoundation.com]
Sent: Monday, February 17, 2014 5:35 PM
To: openssh-unix-dev at mindrot.org
Cc: manish.jagtap at airtightnetworks.com
Subject: Re: [ DRAFT PATCH ] - FIPS 140-2 patch for OpenSSH 6.5p1

On 02/17/2014 01:09 AM, Manish Jagtap wrote:
> Hi,
>
>
>
> Here is FIPS 140-2 patch for OpenSSH 6.5p1. Since our expertise in
> OpenSSH code is limited, request moderators to validate this patch and
> update as required.

I didn't see any patch but the following comments apply regardless.

For a long time I hoped to see native OpenSSL FIPS module support in
OpenSSH. Over the years OSF has prepared a number of patches such as:


http://opensslfoundation.com/export/openssh/openssh-6.0p1.fips-revised.pat
ch

for interested clients.

However, with continuing evolution of OpenSSH and changing FIPS 140-2
requirements such support is becoming increasingly difficult. In order to
make any reasonable claim that an application like OpenSSH is "FIPS
140-2 compliant" *all* cryptography used by that application must be
implemented in the validated module(s). OpenSSH has always had some
inlined cryptography, but the recent introduction of "non-NIST"
cryptography exacerbates that issue.

Then there is the additional consideration that FIPS 140-2 is only
desirable in a context (USG and DoD) where x.509 support is also
mandatory. OpenSSH has adopted a different (and more robust) certificate
scheme. FIPS 140-2 has always been focused on compliance to a specific
ritualized policy and process, and thus is necessarily less secure in an
absolute sense, while OpenSSH is focused on real-world security. IMHO that
discrepancy will probably continue to grow.

So while it remains technically possible to jam the round OpenSSH peg into
the square FIPS 140-2 hole, I'm no longer sure it makes sense to attempt
it in the baseline OpenSSH.

-Steve M.

--
Steve Marquess
OpenSSL Software Foundation, Inc.
1829 Mount Ephraim Road
Adamstown, MD  21710
USA
+1 877 673 6775 s/b
+1 301 874 2571 direct
marquess at opensslfoundation.com
marquess at openssl.com
gpg/pgp key: http://openssl.com/docs/0xCE69424E.asc


More information about the openssh-unix-dev mailing list