efb05e6527
- Update of the underlying OpenSSH to 6.6p1 - update to 6.6p1 Security: * sshd(8): when using environment passing with a sshd_config(5) AcceptEnv pattern with a wildcard. OpenSSH prior to 6.6 could be tricked into accepting any enviornment variable that contains the characters before the wildcard character. Features since 6.5p1: * ssh(1), sshd(8): removal of the J-PAKE authentication code, which was experimental, never enabled and has been unmaintained for some time. * ssh(1): skip 'exec' clauses other clauses predicates failed to match while processing Match blocks. * ssh(1): if hostname canonicalisation is enabled and results in the destination hostname being changed, then re-parse ssh_config(5) files using the new destination hostname. This gives 'Host' and 'Match' directives that use the expanded hostname a chance to be applied. Bugfixes: * ssh(1): avoid spurious "getsockname failed: Bad file descriptor" in ssh -W. bz#2200, debian#738692 * sshd(8): allow the shutdown(2) syscall in seccomp-bpf and systrace sandbox modes, as it is reachable if the connection is terminated during the pre-auth phase. * ssh(1), sshd(8): fix unsigned overflow that in SSH protocol 1 bignum parsing. Minimum key length checks render this bug unexploitable to compromise SSH 1 sessions. * sshd_config(5): clarify behaviour of a keyword that appears in multiple matching Match blocks. bz#2184 OBS-URL: https://build.opensuse.org/request/show/230097 OBS-URL: https://build.opensuse.org/package/show/network/openssh?expand=0&rev=76
1060 lines
32 KiB
Diff
1060 lines
32 KiB
Diff
# comply with FIPS 140-2 by using only approved crypto algorithms
|
|
# when OpenSSL is detected to be running in FIPS mode
|
|
#
|
|
# HG changeset patch
|
|
# Parent ff04a9a96b7c41e99445c68d91911a9a1474ffa2
|
|
|
|
diff --git a/openssh-6.6p1/Makefile.in b/openssh-6.6p1/Makefile.in
|
|
--- a/openssh-6.6p1/Makefile.in
|
|
+++ b/openssh-6.6p1/Makefile.in
|
|
@@ -71,17 +71,18 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o
|
|
readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \
|
|
atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
|
|
monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
|
|
kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \
|
|
msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.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-openssl.o hmac.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 \
|
|
roaming_common.o roaming_client.o
|
|
|
|
SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
|
|
audit.o audit-bsm.o audit-linux.o platform.o \
|
|
sshpty.o sshlogin.o servconf.o serverloop.o \
|
|
diff --git a/openssh-6.6p1/auth-rsa.c b/openssh-6.6p1/auth-rsa.c
|
|
--- a/openssh-6.6p1/auth-rsa.c
|
|
+++ b/openssh-6.6p1/auth-rsa.c
|
|
@@ -44,16 +44,18 @@
|
|
#include "ssh-gss.h"
|
|
#endif
|
|
#include "monitor_wrap.h"
|
|
#include "ssh.h"
|
|
#include "misc.h"
|
|
|
|
#include "digest.h"
|
|
|
|
+#include "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];
|
|
@@ -84,45 +86,52 @@ 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[SSH_DIGEST_MAX_LENGTH])
|
|
{
|
|
- u_char buf[32], mdbuf[16];
|
|
+ u_char buf[2 * SSH_DIGEST_MAX_LENGTH], mdbuf[SSH_DIGEST_MAX_LENGTH];
|
|
struct ssh_digest_ctx *md;
|
|
int len;
|
|
+ int dgst;
|
|
+ size_t dgst_len;
|
|
|
|
/* don't allow short keys */
|
|
if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
|
|
error("%s: RSA modulus too small: %d < minimum %d bits",
|
|
__func__,
|
|
BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE);
|
|
return (0);
|
|
}
|
|
|
|
- /* The response is MD5 of decrypted challenge plus session id. */
|
|
+ dgst = fips_correct_dgst(SSH_DIGEST_MD5);
|
|
+ dgst_len = ssh_digest_bytes(dgst);
|
|
+
|
|
+ /* 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 || (unsigned int)len > (2 * dgst_len))
|
|
fatal("%s: bad challenge length %d", __func__, len);
|
|
- memset(buf, 0, 32);
|
|
- BN_bn2bin(challenge, buf + 32 - len);
|
|
- if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
|
|
- ssh_digest_update(md, buf, 32) < 0 ||
|
|
- ssh_digest_update(md, session_id, 16) < 0 ||
|
|
+ memset(buf, 0, sizeof(buf));
|
|
+ BN_bn2bin(challenge, buf + 2 * dgst_len - len);
|
|
+ if ((md = ssh_digest_start(dgst)) == NULL ||
|
|
+ ssh_digest_update(md, buf, 2 * dgst_len) < 0 ||
|
|
+ ssh_digest_update(md, session_id, dgst_len) < 0 ||
|
|
ssh_digest_final(md, mdbuf, sizeof(mdbuf)) < 0)
|
|
fatal("%s: md5 failed", __func__);
|
|
ssh_digest_free(md);
|
|
|
|
/* Verify that the response is the original challenge. */
|
|
- if (timingsafe_bcmp(response, mdbuf, 16) != 0) {
|
|
+ if (timingsafe_bcmp(response, mdbuf, dgst_len) != 0) {
|
|
/* Wrong answer. */
|
|
return (0);
|
|
}
|
|
/* Correct answer. */
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
@@ -130,17 +139,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[SSH_DIGEST_MAX_LENGTH];
|
|
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. */
|
|
@@ -150,17 +159,17 @@ auth_rsa_challenge_dialog(Key *key)
|
|
packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE);
|
|
packet_put_bignum(encrypted_challenge);
|
|
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++)
|
|
+ for (i = 0; i < ssh_digest_bytes(fips_dgst_min()); 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);
|
|
}
|
|
|
|
diff --git a/openssh-6.6p1/cipher-ctr.c b/openssh-6.6p1/cipher-ctr.c
|
|
--- a/openssh-6.6p1/cipher-ctr.c
|
|
+++ b/openssh-6.6p1/cipher-ctr.c
|
|
@@ -22,16 +22,18 @@
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#include <openssl/evp.h>
|
|
|
|
#include "xmalloc.h"
|
|
#include "log.h"
|
|
|
|
+#include "fips.h"
|
|
+
|
|
/* compatibility with old or broken OpenSSL versions */
|
|
#include "openbsd-compat/openssl-compat.h"
|
|
|
|
#ifndef USE_BUILTIN_RIJNDAEL
|
|
#include <openssl/aes.h>
|
|
#endif
|
|
|
|
struct ssh_aes_ctr_ctx
|
|
@@ -134,13 +136,15 @@ 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);
|
|
}
|
|
|
|
#endif /* OPENSSL_HAVE_EVPCTR */
|
|
diff --git a/openssh-6.6p1/cipher.c b/openssh-6.6p1/cipher.c
|
|
--- a/openssh-6.6p1/cipher.c
|
|
+++ b/openssh-6.6p1/cipher.c
|
|
@@ -45,16 +45,18 @@
|
|
|
|
#include "xmalloc.h"
|
|
#include "log.h"
|
|
#include "misc.h"
|
|
#include "cipher.h"
|
|
#include "buffer.h"
|
|
#include "digest.h"
|
|
|
|
+#include "fips.h"
|
|
+
|
|
/* compatibility with old or broken OpenSSL versions */
|
|
#include "openbsd-compat/openssl-compat.h"
|
|
|
|
extern const EVP_CIPHER *evp_ssh1_bf(void);
|
|
extern const EVP_CIPHER *evp_ssh1_3des(void);
|
|
extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
|
|
|
|
struct Cipher {
|
|
@@ -66,17 +68,17 @@ struct Cipher {
|
|
u_int auth_len;
|
|
u_int discard_len;
|
|
u_int flags;
|
|
#define CFLAG_CBC (1<<0)
|
|
#define CFLAG_CHACHAPOLY (1<<1)
|
|
const EVP_CIPHER *(*evptype)(void);
|
|
};
|
|
|
|
-static const struct Cipher ciphers[] = {
|
|
+static const struct Cipher ciphers_all[] = {
|
|
{ "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
|
|
{ "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc },
|
|
{ "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des },
|
|
{ "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, 0, 0, 0, 1, evp_ssh1_bf },
|
|
|
|
{ "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc },
|
|
{ "blowfish-cbc",
|
|
SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_bf_cbc },
|
|
@@ -99,27 +101,67 @@ static const struct Cipher ciphers[] = {
|
|
{ "aes256-gcm@openssh.com",
|
|
SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm },
|
|
#endif
|
|
{ "chacha20-poly1305@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 const 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@lysator.liu.se",
|
|
+ SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc },
|
|
+ { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr },
|
|
+ { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr },
|
|
+ { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr },
|
|
+#ifdef OPENSSL_HAVE_EVPGCM
|
|
+ { "aes128-gcm@openssh.com",
|
|
+ SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm },
|
|
+ { "aes256-gcm@openssh.com",
|
|
+ SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm },
|
|
+#endif
|
|
+ { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL }
|
|
+};
|
|
+
|
|
/*--*/
|
|
|
|
+/* Returns array of ciphers available depending on selected FIPS mode */
|
|
+static struct Cipher *
|
|
+fips_select_ciphers(void)
|
|
+{
|
|
+ int fips = fips_mode();
|
|
+ switch (fips) {
|
|
+ case 0:
|
|
+ return ciphers_all;
|
|
+ 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)
|
|
{
|
|
char *ret = NULL;
|
|
size_t nlen, rlen = 0;
|
|
const Cipher *c;
|
|
|
|
- for (c = ciphers; c->name != NULL; c++) {
|
|
+ for (c = fips_select_ciphers(); c->name != NULL; c++) {
|
|
if (c->number != SSH_CIPHER_SSH2)
|
|
continue;
|
|
if (auth_only && c->auth_len == 0)
|
|
continue;
|
|
if (ret != NULL)
|
|
ret[rlen++] = sep;
|
|
nlen = strlen(c->name);
|
|
ret = xrealloc(ret, 1, rlen + nlen + 2);
|
|
@@ -189,27 +231,27 @@ cipher_mask_ssh1(int client)
|
|
}
|
|
return mask;
|
|
}
|
|
|
|
const Cipher *
|
|
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;
|
|
}
|
|
|
|
const Cipher *
|
|
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;
|
|
}
|
|
|
|
#define CIPHER_SEP ","
|
|
int
|
|
ciphers_valid(const char *names)
|
|
@@ -241,17 +283,17 @@ ciphers_valid(const char *names)
|
|
*/
|
|
|
|
int
|
|
cipher_number(const char *name)
|
|
{
|
|
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;
|
|
}
|
|
|
|
char *
|
|
cipher_name(int id)
|
|
{
|
|
@@ -429,23 +471,24 @@ cipher_cleanup(CipherContext *cc)
|
|
* Selects the cipher, and keys if by computing the MD5 checksum of the
|
|
* passphrase and using the resulting 16 bytes as the key.
|
|
*/
|
|
|
|
void
|
|
cipher_set_key_string(CipherContext *cc, const Cipher *cipher,
|
|
const char *passphrase, int do_encrypt)
|
|
{
|
|
- u_char digest[16];
|
|
+ u_char digest[SSH_DIGEST_MAX_LENGTH];
|
|
+ int dgst = fips_correct_dgst(SSH_DIGEST_MD5);
|
|
|
|
- if (ssh_digest_memory(SSH_DIGEST_MD5, passphrase, strlen(passphrase),
|
|
+ if (ssh_digest_memory(dgst, passphrase, strlen(passphrase),
|
|
digest, sizeof(digest)) < 0)
|
|
fatal("%s: md5 failed", __func__);
|
|
|
|
- cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt);
|
|
+ cipher_init(cc, cipher, digest, ssh_digest_bytes(dgst), NULL, 0, do_encrypt);
|
|
|
|
explicit_bzero(digest, sizeof(digest));
|
|
}
|
|
|
|
/*
|
|
* 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-6.6p1/fips.c b/openssh-6.6p1/fips.c
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/openssh-6.6p1/fips.c
|
|
@@ -0,0 +1,128 @@
|
|
+/*
|
|
+ * 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 "includes.h"
|
|
+
|
|
+#include "fips.h"
|
|
+
|
|
+#include "digest.h"
|
|
+#include "key.h"
|
|
+#include "log.h"
|
|
+
|
|
+#include <openssl/crypto.h>
|
|
+
|
|
+static int fips_state = -1;
|
|
+
|
|
+int
|
|
+fips_mode()
|
|
+{
|
|
+ if (-1 == fips_state) {
|
|
+ fips_state = FIPS_mode();
|
|
+ if (fips_state)
|
|
+ debug("FIPS mode initialized");
|
|
+ }
|
|
+ return fips_state;
|
|
+}
|
|
+
|
|
+enum fp_type
|
|
+fips_correct_fp_type(enum fp_type fp)
|
|
+{
|
|
+ int fips;
|
|
+ enum fp_type fp_fix = fp;
|
|
+
|
|
+ fips = fips_mode();
|
|
+ switch (fips) {
|
|
+ case 0:
|
|
+ break;
|
|
+ case 1:
|
|
+ if (SSH_FP_MD5 == fp) {
|
|
+ fp_fix = SSH_FP_SHA1;
|
|
+ debug("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 fp_fix;
|
|
+}
|
|
+
|
|
+int
|
|
+fips_correct_dgst(int digest)
|
|
+{
|
|
+ int fips;
|
|
+ int rv = -1;
|
|
+
|
|
+ fips = fips_mode();
|
|
+ switch (fips) {
|
|
+ case 0:
|
|
+ rv = digest;
|
|
+ break;
|
|
+ case 1:
|
|
+ switch (digest) {
|
|
+ case SSH_DIGEST_MD5:
|
|
+ case SSH_DIGEST_RIPEMD160:
|
|
+ debug("MD5/RIPEMD160 digests not allowed in FIPS 140-2 mode"
|
|
+ "using SHA-1 instead.");
|
|
+ rv = SSH_DIGEST_SHA1;
|
|
+ break;
|
|
+ default:
|
|
+ rv = digest;
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ /* should not be reached */
|
|
+ fatal("Fatal error: incorrect FIPS mode '%i' at %s:%u",
|
|
+ fips, __FILE__, __LINE__);
|
|
+ }
|
|
+
|
|
+ return rv;
|
|
+}
|
|
+
|
|
+int
|
|
+fips_dgst_min(void)
|
|
+{
|
|
+ int fips;
|
|
+ int dgst;
|
|
+
|
|
+ fips = fips_mode();
|
|
+ switch (fips) {
|
|
+ case 0:
|
|
+ dgst = SSH_DIGEST_MD5;
|
|
+ break;
|
|
+ case 1:
|
|
+ dgst = SSH_DIGEST_SHA1;
|
|
+ break;
|
|
+ default:
|
|
+ /* should not be reached */
|
|
+ fatal("Fatal error: incorrect FIPS mode '%i' at %s:%u",
|
|
+ fips, __FILE__, __LINE__);
|
|
+ }
|
|
+ return dgst;
|
|
+}
|
|
+
|
|
diff --git a/openssh-6.6p1/fips.h b/openssh-6.6p1/fips.h
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/openssh-6.6p1/fips.h
|
|
@@ -0,0 +1,33 @@
|
|
+/*
|
|
+ * 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
|
|
+
|
|
+int fips_mode(void);
|
|
+int fips_correct_dgst(int);
|
|
+int fips_dgst_min(void);
|
|
+enum fp_type fips_correct_fp_type(enum fp_type);
|
|
+
|
|
+#endif
|
|
+
|
|
diff --git a/openssh-6.6p1/hmac.c b/openssh-6.6p1/hmac.c
|
|
--- a/openssh-6.6p1/hmac.c
|
|
+++ b/openssh-6.6p1/hmac.c
|
|
@@ -139,17 +139,17 @@ ssh_hmac_free(struct ssh_hmac_ctx *ctx)
|
|
/* cc -DTEST hmac.c digest.c buffer.c cleanup.c fatal.c log.c xmalloc.c -lcrypto */
|
|
static void
|
|
hmac_test(void *key, size_t klen, void *m, size_t mlen, u_char *e, size_t elen)
|
|
{
|
|
struct ssh_hmac_ctx *ctx;
|
|
size_t i;
|
|
u_char digest[16];
|
|
|
|
- if ((ctx = ssh_hmac_start(SSH_DIGEST_MD5)) == NULL)
|
|
+ if ((ctx = ssh_hmac_start(fips_correct_dgst(SSH_DIGEST_MD5))) == NULL)
|
|
printf("ssh_hmac_start failed");
|
|
if (ssh_hmac_init(ctx, key, klen) < 0 ||
|
|
ssh_hmac_update(ctx, m, mlen) < 0 ||
|
|
ssh_hmac_final(ctx, digest, sizeof(digest)) < 0)
|
|
printf("ssh_hmac_xxx failed");
|
|
ssh_hmac_free(ctx);
|
|
|
|
if (memcmp(e, digest, elen)) {
|
|
diff --git a/openssh-6.6p1/kex.c b/openssh-6.6p1/kex.c
|
|
--- a/openssh-6.6p1/kex.c
|
|
+++ b/openssh-6.6p1/kex.c
|
|
@@ -638,19 +638,21 @@ kex_get_newkeys(int mode)
|
|
}
|
|
|
|
void
|
|
derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
|
|
u_int8_t cookie[8], u_int8_t id[16])
|
|
{
|
|
u_int8_t nbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH];
|
|
int len;
|
|
+ int digest;
|
|
struct ssh_digest_ctx *hashctx;
|
|
|
|
- if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL)
|
|
+ digest = fips_correct_dgst(SSH_DIGEST_MD5);
|
|
+ if ((hashctx = ssh_digest_start(digest)) == NULL)
|
|
fatal("%s: ssh_digest_start", __func__);
|
|
|
|
len = BN_num_bytes(host_modulus);
|
|
if (len < (512 / 8) || (u_int)len > sizeof(nbuf))
|
|
fatal("%s: bad host modulus (len %d)", __func__, len);
|
|
BN_bn2bin(host_modulus, nbuf);
|
|
if (ssh_digest_update(hashctx, nbuf, len) != 0)
|
|
fatal("%s: ssh_digest_update failed", __func__);
|
|
@@ -659,17 +661,17 @@ derive_ssh1_session_id(BIGNUM *host_modu
|
|
if (len < (512 / 8) || (u_int)len > sizeof(nbuf))
|
|
fatal("%s: bad server modulus (len %d)", __func__, len);
|
|
BN_bn2bin(server_modulus, nbuf);
|
|
if (ssh_digest_update(hashctx, nbuf, len) != 0 ||
|
|
ssh_digest_update(hashctx, cookie, 8) != 0)
|
|
fatal("%s: ssh_digest_update failed", __func__);
|
|
if (ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0)
|
|
fatal("%s: ssh_digest_final failed", __func__);
|
|
- memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5));
|
|
+ memcpy(id, obuf, ssh_digest_bytes(digest));
|
|
|
|
explicit_bzero(nbuf, sizeof(nbuf));
|
|
explicit_bzero(obuf, sizeof(obuf));
|
|
}
|
|
|
|
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
|
|
void
|
|
dump_digest(char *msg, u_char *digest, int len)
|
|
diff --git a/openssh-6.6p1/key.c b/openssh-6.6p1/key.c
|
|
--- a/openssh-6.6p1/key.c
|
|
+++ b/openssh-6.6p1/key.c
|
|
@@ -53,16 +53,18 @@
|
|
#include "rsa.h"
|
|
#include "uuencode.h"
|
|
#include "buffer.h"
|
|
#include "log.h"
|
|
#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);
|
|
|
|
static struct KeyCert *
|
|
cert_new(void)
|
|
{
|
|
struct KeyCert *cert;
|
|
|
|
@@ -664,16 +666,19 @@ key_fp_type_select(void)
|
|
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())
|
|
+ fp = 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
|
|
diff --git a/openssh-6.6p1/mac.c b/openssh-6.6p1/mac.c
|
|
--- a/openssh-6.6p1/mac.c
|
|
+++ b/openssh-6.6p1/mac.c
|
|
@@ -39,33 +39,35 @@
|
|
#include "kex.h"
|
|
#include "mac.h"
|
|
#include "misc.h"
|
|
|
|
#include "digest.h"
|
|
#include "hmac.h"
|
|
#include "umac.h"
|
|
|
|
+#include "fips.h"
|
|
+
|
|
#include "openbsd-compat/openssl-compat.h"
|
|
|
|
#define SSH_DIGEST 1 /* SSH_DIGEST_XXX */
|
|
#define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */
|
|
#define SSH_UMAC128 3
|
|
|
|
struct macalg {
|
|
char *name;
|
|
int type;
|
|
int alg;
|
|
int truncatebits; /* truncate digest if != 0 */
|
|
int key_len; /* just for UMAC */
|
|
int len; /* just for UMAC */
|
|
int etm; /* Encrypt-then-MAC */
|
|
};
|
|
|
|
-static const struct macalg macs[] = {
|
|
+static const struct macalg macs_all[] = {
|
|
/* Encrypt-and-MAC (encrypt-and-authenticate) variants */
|
|
{ "hmac-sha1", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 },
|
|
{ "hmac-sha1-96", SSH_DIGEST, SSH_DIGEST_SHA1, 96, 0, 0, 0 },
|
|
#ifdef HAVE_EVP_SHA256
|
|
{ "hmac-sha2-256", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 0 },
|
|
{ "hmac-sha2-512", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 0 },
|
|
#endif
|
|
{ "hmac-md5", SSH_DIGEST, SSH_DIGEST_MD5, 0, 0, 0, 0 },
|
|
@@ -86,25 +88,59 @@ static const struct macalg macs[] = {
|
|
{ "hmac-md5-96-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_MD5, 96, 0, 0, 1 },
|
|
{ "hmac-ripemd160-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_RIPEMD160, 0, 0, 0, 1 },
|
|
{ "umac-64-etm@openssh.com", SSH_UMAC, 0, 0, 128, 64, 1 },
|
|
{ "umac-128-etm@openssh.com", SSH_UMAC128, 0, 0, 128, 128, 1 },
|
|
|
|
{ NULL, 0, 0, 0, 0, 0, 0 }
|
|
};
|
|
|
|
+static const struct macalg macs_fips140_2[] = {
|
|
+ /* Encrypt-and-MAC (encrypt-and-authenticate) variants */
|
|
+ { "hmac-sha1", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 },
|
|
+#ifdef HAVE_EVP_SHA256
|
|
+ { "hmac-sha2-256", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 0 },
|
|
+ { "hmac-sha2-512", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 0 },
|
|
+#endif
|
|
+
|
|
+ /* Encrypt-then-MAC variants */
|
|
+#ifdef HAVE_EVP_SHA256
|
|
+ { "hmac-sha2-256-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 1 },
|
|
+ { "hmac-sha2-512-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 1 },
|
|
+#endif
|
|
+ { NULL, 0, 0, 0, 0, 0, 0 }
|
|
+};
|
|
+
|
|
+/* Returns array of macs available depending on selected FIPS mode */
|
|
+static struct macalg *
|
|
+fips_select_macs(void)
|
|
+{
|
|
+ int fips = fips_mode();
|
|
+ switch (fips) {
|
|
+ case 0:
|
|
+ return macs_all;
|
|
+ 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 *
|
|
mac_alg_list(char sep)
|
|
{
|
|
char *ret = NULL;
|
|
size_t nlen, rlen = 0;
|
|
const struct macalg *m;
|
|
|
|
- for (m = macs; m->name != NULL; m++) {
|
|
+ for (m = fips_select_macs(); m->name != NULL; m++) {
|
|
if (ret != NULL)
|
|
ret[rlen++] = sep;
|
|
nlen = strlen(m->name);
|
|
ret = xrealloc(ret, 1, rlen + nlen + 2);
|
|
memcpy(ret + rlen, m->name, nlen + 1);
|
|
rlen += nlen;
|
|
}
|
|
return ret;
|
|
@@ -128,17 +164,17 @@ mac_setup_by_alg(Mac *mac, const struct
|
|
mac->etm = macalg->etm;
|
|
}
|
|
|
|
int
|
|
mac_setup(Mac *mac, char *name)
|
|
{
|
|
const struct macalg *m;
|
|
|
|
- for (m = macs; m->name != NULL; m++) {
|
|
+ for (m = fips_select_macs(); m->name != NULL; m++) {
|
|
if (strcmp(name, m->name) != 0)
|
|
continue;
|
|
if (mac != NULL) {
|
|
mac_setup_by_alg(mac, m);
|
|
debug2("mac_setup: setup %s", name);
|
|
}
|
|
return (0);
|
|
}
|
|
diff --git a/openssh-6.6p1/myproposal.h b/openssh-6.6p1/myproposal.h
|
|
--- a/openssh-6.6p1/myproposal.h
|
|
+++ b/openssh-6.6p1/myproposal.h
|
|
@@ -104,16 +104,20 @@
|
|
|
|
#define KEX_DEFAULT_ENCRYPT \
|
|
"aes128-ctr,aes192-ctr,aes256-ctr," \
|
|
"arcfour256,arcfour128," \
|
|
AESGCM_CIPHER_MODES \
|
|
"chacha20-poly1305@openssh.com," \
|
|
"aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \
|
|
"aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@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@lysator.liu.se"
|
|
|
|
#define KEX_DEFAULT_MAC \
|
|
"hmac-md5-etm@openssh.com," \
|
|
"hmac-sha1-etm@openssh.com," \
|
|
"umac-64-etm@openssh.com," \
|
|
"umac-128-etm@openssh.com," \
|
|
"hmac-sha2-256-etm@openssh.com," \
|
|
"hmac-sha2-512-etm@openssh.com," \
|
|
@@ -124,16 +128,19 @@
|
|
"hmac-sha1," \
|
|
"umac-64@openssh.com," \
|
|
"umac-128@openssh.com," \
|
|
SHA2_HMAC_MODES \
|
|
"hmac-ripemd160," \
|
|
"hmac-ripemd160@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@openssh.com,zlib"
|
|
#define KEX_DEFAULT_LANG ""
|
|
|
|
|
|
static char *myproposal[PROPOSAL_MAX] = {
|
|
KEX_DEFAULT_KEX,
|
|
KEX_DEFAULT_PK_ALG,
|
|
diff --git a/openssh-6.6p1/ssh.c b/openssh-6.6p1/ssh.c
|
|
--- a/openssh-6.6p1/ssh.c
|
|
+++ b/openssh-6.6p1/ssh.c
|
|
@@ -100,16 +100,18 @@
|
|
#include "mac.h"
|
|
#include "sshpty.h"
|
|
#include "match.h"
|
|
#include "msg.h"
|
|
#include "uidswap.h"
|
|
#include "roaming.h"
|
|
#include "version.h"
|
|
|
|
+#include "fips.h"
|
|
+
|
|
#ifdef ENABLE_PKCS11
|
|
#include "ssh-pkcs11.h"
|
|
#endif
|
|
|
|
extern char *__progname;
|
|
|
|
/* Saves a copy of argv for setproctitle emulation */
|
|
#ifndef HAVE_SETPROCTITLE
|
|
@@ -499,16 +501,18 @@ main(int ac, char **av)
|
|
logfile = NULL;
|
|
argv0 = av[0];
|
|
|
|
again:
|
|
while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
|
|
"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':
|
|
options.protocol = SSH_PROTO_2;
|
|
break;
|
|
case '4':
|
|
options.address_family = AF_INET;
|
|
break;
|
|
@@ -826,16 +830,22 @@ main(int ac, char **av)
|
|
if (!host)
|
|
usage();
|
|
|
|
host_arg = xstrdup(host);
|
|
|
|
OpenSSL_add_all_algorithms();
|
|
ERR_load_crypto_strings();
|
|
|
|
+ if (FIPS_mode()) {
|
|
+ options.protocol &= SSH_PROTO_2;
|
|
+ if (options.protocol == 0)
|
|
+ fatal("Protocol 2 disabled by configuration but required in the FIPS mode");
|
|
+ }
|
|
+
|
|
/* 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.
|
|
*/
|
|
diff --git a/openssh-6.6p1/sshconnect2.c b/openssh-6.6p1/sshconnect2.c
|
|
--- a/openssh-6.6p1/sshconnect2.c
|
|
+++ b/openssh-6.6p1/sshconnect2.c
|
|
@@ -66,16 +66,18 @@
|
|
#include "match.h"
|
|
#include "dispatch.h"
|
|
#include "canohost.h"
|
|
#include "msg.h"
|
|
#include "pathnames.h"
|
|
#include "uidswap.h"
|
|
#include "hostfile.h"
|
|
|
|
+#include "fips.h"
|
|
+
|
|
#ifdef GSSAPI
|
|
#include "ssh-gss.h"
|
|
#endif
|
|
|
|
/* import */
|
|
extern char *client_version_string;
|
|
extern char *server_version_string;
|
|
extern Options options;
|
|
@@ -163,31 +165,41 @@ 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()) {
|
|
+ /* TODO: use intersection of FIPS ciphers and those requested in
|
|
+ * configuration */
|
|
+ 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]);
|
|
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()) {
|
|
+ /* TODO: use intersection of FIPS macs and those requested in
|
|
+ * configuration */
|
|
+ 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] =
|
|
compat_pkalg_proposal(options.hostkeyalgorithms);
|
|
else {
|
|
/* Prefer algorithms that we already have keys for */
|
|
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
|
|
compat_pkalg_proposal(
|
|
diff --git a/openssh-6.6p1/sshd.c b/openssh-6.6p1/sshd.c
|
|
--- a/openssh-6.6p1/sshd.c
|
|
+++ b/openssh-6.6p1/sshd.c
|
|
@@ -117,16 +117,18 @@
|
|
#ifdef GSSAPI
|
|
#include "ssh-gss.h"
|
|
#endif
|
|
#include "monitor_wrap.h"
|
|
#include "roaming.h"
|
|
#include "ssh-sandbox.h"
|
|
#include "version.h"
|
|
|
|
+#include "fips.h"
|
|
+
|
|
#ifdef LIBWRAP
|
|
#include <tcpd.h>
|
|
#include <syslog.h>
|
|
int allow_severity;
|
|
int deny_severity;
|
|
#endif /* LIBWRAP */
|
|
|
|
#ifndef O_NOCTTY
|
|
@@ -1723,16 +1725,20 @@ main(int ac, char **av)
|
|
case KEY_ECDSA:
|
|
case KEY_ED25519:
|
|
sensitive_data.have_ssh2_key = 1;
|
|
break;
|
|
}
|
|
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;
|
|
}
|
|
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;
|
|
}
|
|
@@ -2370,30 +2376,30 @@ do_ssh1_kex(void)
|
|
}
|
|
if (rsafail) {
|
|
int bytes = BN_num_bytes(session_key_int);
|
|
u_char *buf = xmalloc(bytes);
|
|
struct ssh_digest_ctx *md;
|
|
|
|
logit("do_connection: generating a fake encryption key");
|
|
BN_bn2bin(session_key_int, buf);
|
|
- if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
|
|
+ if ((md = ssh_digest_start(fips_correct_dgst(SSH_DIGEST_MD5))) == NULL ||
|
|
ssh_digest_update(md, buf, bytes) < 0 ||
|
|
ssh_digest_update(md, sensitive_data.ssh1_cookie,
|
|
SSH_SESSION_KEY_LENGTH) < 0 ||
|
|
ssh_digest_final(md, session_key, sizeof(session_key)) < 0)
|
|
- fatal("%s: md5 failed", __func__);
|
|
+ fatal("%s: hash failed", __func__);
|
|
ssh_digest_free(md);
|
|
- if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
|
|
+ if ((md = ssh_digest_start(fips_correct_dgst(SSH_DIGEST_MD5))) == NULL ||
|
|
ssh_digest_update(md, session_key, 16) < 0 ||
|
|
ssh_digest_update(md, sensitive_data.ssh1_cookie,
|
|
SSH_SESSION_KEY_LENGTH) < 0 ||
|
|
ssh_digest_final(md, session_key + 16,
|
|
sizeof(session_key) - 16) < 0)
|
|
- fatal("%s: md5 failed", __func__);
|
|
+ fatal("%s: hash failed", __func__);
|
|
ssh_digest_free(md);
|
|
explicit_bzero(buf, bytes);
|
|
free(buf);
|
|
for (i = 0; i < 16; i++)
|
|
session_id[i] = session_key[i] ^ session_key[i + 16];
|
|
}
|
|
/* Destroy the private and public keys. No longer. */
|
|
destroy_sensitive_data();
|
|
@@ -2441,25 +2447,31 @@ sshd_hostkey_sign(Key *privkey, Key *pub
|
|
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_140_2_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_140_2_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";
|
|
}
|