diff -ruN openssh-6.3p1_orig/auth2-hostbased.c openssh-6.3p1_modified/auth2-hostbased.c --- openssh-6.3p1_orig/auth2-hostbased.c 2013-07-18 11:40:10.000000000 +0530 +++ openssh-6.3p1_modified/auth2-hostbased.c 2013-10-16 15:18:44.000000000 +0530 @@ -201,13 +201,13 @@ if (host_status == HOST_OK) { if (key_is_cert(key)) { fp = key_fingerprint(key->cert->signature_key, - SSH_FP_MD5, SSH_FP_HEX); + key_fingerprint_alg(), 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, cuser, lookup); } else { - fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + fp = key_fingerprint(key, key_fingerprint_alg(), SSH_FP_HEX); verbose("Accepted %s public key %s from %s@%s", key_type(key), fp, cuser, lookup); } diff -ruN openssh-6.3p1_orig/auth2-pubkey.c openssh-6.3p1_modified/auth2-pubkey.c --- openssh-6.3p1_orig/auth2-pubkey.c 2013-07-18 11:40:10.000000000 +0530 +++ openssh-6.3p1_modified/auth2-pubkey.c 2013-10-16 15:18:44.000000000 +0530 @@ -207,7 +207,7 @@ if (key_is_cert(key)) { fp = key_fingerprint(key->cert->signature_key, - SSH_FP_MD5, SSH_FP_HEX); + key_fingerprint_alg(), 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, @@ -215,7 +215,7 @@ extra == NULL ? "" : ", ", extra == NULL ? "" : extra); free(fp); } else { - fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + fp = key_fingerprint(key, key_fingerprint_alg(), SSH_FP_HEX); auth_info(authctxt, "%s %s%s%s", key_type(key), fp, extra == NULL ? "" : ", ", extra == NULL ? "" : extra); free(fp); @@ -359,7 +359,7 @@ continue; if (!key_is_cert_authority) continue; - fp = key_fingerprint(found, SSH_FP_MD5, + fp = key_fingerprint(found, key_fingerprint_alg(), SSH_FP_HEX); debug("matching CA found: file %s, line %lu, %s %s", file, linenum, key_type(found), fp); @@ -400,7 +400,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_fingerprint_alg(), SSH_FP_HEX); debug("matching key found: file %s, line %lu %s %s", file, linenum, key_type(found), fp); free(fp); @@ -426,7 +426,7 @@ return 0; ca_fp = key_fingerprint(key->cert->signature_key, - SSH_FP_MD5, SSH_FP_HEX); + key_fingerprint_alg(), SSH_FP_HEX); if (key_in_file(key->cert->signature_key, options.trusted_user_ca_keys, 1) != 1) { diff -ruN openssh-6.3p1_orig/auth.c openssh-6.3p1_modified/auth.c --- openssh-6.3p1_orig/auth.c 2013-06-02 03:11:51.000000000 +0530 +++ openssh-6.3p1_modified/auth.c 2013-10-16 15:18:44.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_fingerprint_alg(), 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.3p1_orig/auth-rsa.c openssh-6.3p1_modified/auth-rsa.c --- openssh-6.3p1_orig/auth-rsa.c 2013-07-18 11:42:44.000000000 +0530 +++ openssh-6.3p1_modified/auth-rsa.c 2013-10-16 15:18:44.000000000 +0530 @@ -231,7 +231,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_fingerprint_alg(), 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.3p1_orig/cipher.c openssh-6.3p1_modified/cipher.c --- openssh-6.3p1_orig/cipher.c 2013-06-02 03:01:18.000000000 +0530 +++ openssh-6.3p1_modified/cipher.c 2013-10-16 15:18:44.000000000 +0530 @@ -55,7 +55,7 @@ extern const EVP_CIPHER *evp_ssh1_3des(void); extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); -struct Cipher { +static struct Cipher { char *name; int number; /* for ssh1 only */ u_int block_size; @@ -98,6 +98,37 @@ { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } }; +#ifdef OPENSSL_FIPS_CAPABLE +/* subset of the ciphers table above which is relevant for FIPS140 usage */ +static struct Cipher fips_ciphers[] = { + { "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 }, + { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } +}; +#endif /* OPENSSL_FIPS_CAPABLE */ + +/* return the correct list of ciphers depending on what mode we are + * * operating in (non-FIPS140 or FIPS140 mode) + * */ +struct Cipher *ciphers_list(void) +{ +#ifdef OPENSSL_FIPS_CAPABLE + if (FIPS_mode()) + return fips_ciphers; + else +#endif /* OPENSSL_FIPS_CAPABLE */ + return ciphers; +} + /*--*/ /* Returns a comma-separated list of supported ciphers. */ @@ -173,7 +204,7 @@ cipher_by_name(const char *name) { const Cipher *c; - for (c = ciphers; c->name != NULL; c++) + for (c = ciphers_list(); c->name != NULL; c++) if (strcmp(c->name, name) == 0) return c; return NULL; @@ -183,7 +214,7 @@ cipher_by_number(int id) { const Cipher *c; - for (c = ciphers; c->name != NULL; c++) + for (c = ciphers_list(); c->name != NULL; c++) if (c->number == id) return c; return NULL; @@ -227,7 +258,7 @@ const Cipher *c; if (name == NULL) return -1; - for (c = ciphers; c->name != NULL; c++) + for (c = ciphers_list(); c->name != NULL; c++) if (strcasecmp(c->name, name) == 0) return c->number; return -1; @@ -386,21 +417,19 @@ * passphrase and using the resulting 16 bytes as the key. */ -void +int cipher_set_key_string(CipherContext *cc, const Cipher *cipher, const char *passphrase, int do_encrypt) { - MD5_CTX md; u_char digest[16]; - MD5_Init(&md); - MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase)); - MD5_Final(digest, &md); + if (EVP_Digest(passphrase, strlen(passphrase), digest, NULL, EVP_md5(), NULL) <= 0) + return -1; cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt); memset(digest, 0, sizeof(digest)); - memset(&md, 0, sizeof(md)); + return 0; } /* @@ -497,7 +526,11 @@ const Cipher *c = cc->cipher; int plen = 0; +#ifdef OPENSSL_FIPS_CAPABLE + if (FIPS_mode() || (c->evptype == EVP_rc4) ) { +#else if (c->evptype == EVP_rc4) { +#endif plen = EVP_X_STATE_LEN(cc->evp); if (dat == NULL) return (plen); @@ -512,7 +545,11 @@ const Cipher *c = cc->cipher; int plen; +#ifdef OPENSSL_FIPS_CAPABLE + if (FIPS_mode() || (c->evptype == EVP_rc4) ) { +#else if (c->evptype == EVP_rc4) { +#endif plen = EVP_X_STATE_LEN(cc->evp); memcpy(EVP_X_STATE(cc->evp), dat, plen); } diff -ruN openssh-6.3p1_orig/cipher-ctr.c openssh-6.3p1_modified/cipher-ctr.c --- openssh-6.3p1_orig/cipher-ctr.c 2013-06-02 03:37:32.000000000 +0530 +++ openssh-6.3p1_modified/cipher-ctr.c 1970-01-01 05:30:00.000000000 +0530 @@ -1,146 +0,0 @@ -/* $OpenBSD: cipher-ctr.c,v 1.11 2010/10/01 23:05:32 djm Exp $ */ -/* - * Copyright (c) 2003 Markus Friedl <markus@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include "includes.h" - -#ifndef OPENSSL_HAVE_EVPCTR -#include <sys/types.h> - -#include <stdarg.h> -#include <string.h> - -#include <openssl/evp.h> - -#include "xmalloc.h" -#include "log.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 -{ - AES_KEY aes_ctx; - u_char aes_counter[AES_BLOCK_SIZE]; -}; - -/* - * increment counter 'ctr', - * the counter is of size 'len' bytes and stored in network-byte-order. - * (LSB at ctr[len-1], MSB at ctr[0]) - */ -static void -ssh_ctr_inc(u_char *ctr, size_t len) -{ - int i; - - for (i = len - 1; i >= 0; i--) - if (++ctr[i]) /* continue on overflow */ - return; -} - -static int -ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, - LIBCRYPTO_EVP_INL_TYPE len) -{ - struct ssh_aes_ctr_ctx *c; - size_t n = 0; - u_char buf[AES_BLOCK_SIZE]; - - if (len == 0) - return (1); - if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) - return (0); - - while ((len--) > 0) { - if (n == 0) { - AES_encrypt(c->aes_counter, buf, &c->aes_ctx); - ssh_ctr_inc(c->aes_counter, AES_BLOCK_SIZE); - } - *(dest++) = *(src++) ^ buf[n]; - n = (n + 1) % AES_BLOCK_SIZE; - } - return (1); -} - -static int -ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, - int enc) -{ - struct ssh_aes_ctr_ctx *c; - - if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { - c = xmalloc(sizeof(*c)); - EVP_CIPHER_CTX_set_app_data(ctx, c); - } - if (key != NULL) - AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8, - &c->aes_ctx); - if (iv != NULL) - memcpy(c->aes_counter, iv, AES_BLOCK_SIZE); - return (1); -} - -static int -ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) -{ - struct ssh_aes_ctr_ctx *c; - - if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) { - memset(c, 0, sizeof(*c)); - free(c); - EVP_CIPHER_CTX_set_app_data(ctx, NULL); - } - return (1); -} - -void -ssh_aes_ctr_iv(EVP_CIPHER_CTX *evp, int doset, u_char * iv, size_t len) -{ - struct ssh_aes_ctr_ctx *c; - - if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL) - fatal("ssh_aes_ctr_iv: no context"); - if (doset) - memcpy(c->aes_counter, iv, len); - else - memcpy(iv, c->aes_counter, len); -} - -const EVP_CIPHER * -evp_aes_128_ctr(void) -{ - static EVP_CIPHER aes_ctr; - - memset(&aes_ctr, 0, sizeof(EVP_CIPHER)); - aes_ctr.nid = NID_undef; - aes_ctr.block_size = AES_BLOCK_SIZE; - 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; -#endif - return (&aes_ctr); -} - -#endif /* OPENSSL_HAVE_EVPCTR */ diff -ruN openssh-6.3p1_orig/cipher.h openssh-6.3p1_modified/cipher.h --- openssh-6.3p1_orig/cipher.h 2013-04-23 14:54:32.000000000 +0530 +++ openssh-6.3p1_modified/cipher.h 2013-10-16 15:18:44.000000000 +0530 @@ -81,7 +81,7 @@ void cipher_crypt(CipherContext *, u_char *, const u_char *, u_int, u_int, u_int); void cipher_cleanup(CipherContext *); -void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int); +int cipher_set_key_string(CipherContext *, const Cipher *, const char *, int); u_int cipher_blocksize(const Cipher *); u_int cipher_keylen(const Cipher *); u_int cipher_authlen(const Cipher *); diff -ruN openssh-6.3p1_orig/configure.ac openssh-6.3p1_modified/configure.ac --- openssh-6.3p1_orig/configure.ac 2013-08-04 17:18:41.000000000 +0530 +++ openssh-6.3p1_modified/configure.ac 2013-10-16 15:18:44.000000000 +0530 @@ -2154,6 +2154,39 @@ fi fi ] + ) +LIBS="-lcrypto $LIBS" +AC_ARG_WITH(fips-dir, + [ --with-fips-dir=PATH Specify path to OpenSSL FIPS installation ], + [ + if test "x$withval" != "xno" ; then + case "$withval" in + # Relative paths + ./*|../*) withval="`pwd`/$withval" + esac + if test -d "$withval/lib"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib -Wl,-R${withval} ${LDFLAGS}" + fi + else + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" + else + LDFLAGS="-L${withval} -Wl,-R${withval} ${LDFLAGS}" + fi + fi + if test -d "$withval/include"; then + CPPFLAGS="-DOPENSSL_FIPS_CAPABLE -I${withval}/include ${CPPFLAGS}" + else + CPPFLAGS="-DOPENSSL_FIPS_CAPABLE -I${withval} ${CPPFLAGS}" + fi + fi + AC_DEFINE(OPENSSL_FIPS_CAPABLE, 1, [FIPS capable] ) + openssl_check_nonfatal=1 + fips="yes" + ] ) LIBS="-lcrypto $LIBS" AC_TRY_LINK_FUNC([RAND_add], [AC_DEFINE([HAVE_OPENSSL], [1], @@ -4582,6 +4615,7 @@ H=`eval echo ${PRIVSEP_PATH}` ; H=`eval echo ${H}` I=`eval echo ${user_path}` ; I=`eval echo ${I}` J=`eval echo ${superuser_path}` ; J=`eval echo ${J}` +K=`eval echo ${fips}` ; K=`eval echo ${K}` echo "" echo "OpenSSH has been configured with the following options:" @@ -4638,6 +4672,9 @@ echo " +for ssh: ${SSHLIBS}" fi +echo " fips support: $K" + + echo "" if test "x$MAKE_PACKAGE_SUPPORTED" = "xyes" ; then diff -ruN openssh-6.3p1_orig/key.c openssh-6.3p1_modified/key.c --- openssh-6.3p1_orig/key.c 2013-06-02 03:11:51.000000000 +0530 +++ openssh-6.3p1_modified/key.c 2013-10-16 15:18:44.000000000 +0530 @@ -72,6 +72,16 @@ return cert; } +int key_fingerprint_alg(void) +{ +#ifdef OPENSSL_FIPS_CAPABLE + if (FIPS_mode()) + return SSH_FP_SHA1; + else +#endif /* OPENSSL_FIPS_CAPABLE */ + return SSH_FP_MD5; +} + Key * key_new(int type) { diff -ruN openssh-6.3p1_orig/key.h openssh-6.3p1_modified/key.h --- openssh-6.3p1_orig/key.h 2013-06-02 03:11:51.000000000 +0530 +++ openssh-6.3p1_modified/key.h 2013-10-16 15:18:44.000000000 +0530 @@ -102,6 +102,7 @@ int key_write(const Key *, FILE *); int key_read(Key *, char **); u_int key_size(const Key *); +int key_fingerprint_alg(void); Key *key_generate(int, u_int); Key *key_from_private(const Key *); diff -ruN openssh-6.3p1_orig/mac.c openssh-6.3p1_modified/mac.c --- openssh-6.3p1_orig/mac.c 2013-06-06 03:42:37.000000000 +0530 +++ openssh-6.3p1_modified/mac.c 2013-10-16 15:18:44.000000000 +0530 @@ -60,7 +60,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 }, @@ -91,15 +91,37 @@ { NULL, 0, NULL, 0, 0, 0, 0 } }; +#ifdef OPENSSL_FIPS_CAPABLE +static const struct macalg fips_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 }, + { NULL, 0, NULL, 0, 0, 0, 0 } +}; +#endif /* OPENSSL_FIPS_CAPABLE */ + +/* return the correct list of ciphers depending on what mode we are + * operating in (non-FIPS140 or FIPS140 mode) + * */ +struct macalg *macalg_list(void) +{ +#ifdef OPENSSL_FIPS_CAPABLE + if (FIPS_mode()) + return fips_macs; + else +#endif /* OPENSSL_FIPS_CAPABLE */ + return all_macs; +} + /* Returns a comma-separated list of supported MACs. */ char * mac_alg_list(void) { char *ret = NULL; size_t nlen, rlen = 0; - const struct macalg *m; + const struct macalg *m = macalg_list(); - for (m = macs; m->name != NULL; m++) { + for ( ; m->name != NULL; m++) { if (ret != NULL) ret[rlen++] = '\n'; nlen = strlen(m->name); @@ -134,9 +156,9 @@ int mac_setup(Mac *mac, char *name) { - const struct macalg *m; + const struct macalg *m = macalg_list(); - 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.3p1_orig/Makefile.in openssh-6.3p1_modified/Makefile.in --- openssh-6.3p1_orig/Makefile.in 2013-06-11 06:56:10.000000000 +0530 +++ openssh-6.3p1_modified/Makefile.in 2013-10-16 15:18:44.000000000 +0530 @@ -65,7 +65,7 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ canohost.o channels.o cipher.o cipher-aes.o \ - cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \ + cipher-bf1.o cipher-3des1.o cleanup.o \ compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \ log.o match.o md-sha256.o moduli.o nchan.o packet.o \ readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \ diff -ruN openssh-6.3p1_orig/myproposal.h openssh-6.3p1_modified/myproposal.h --- openssh-6.3p1_orig/myproposal.h 2013-06-11 07:40:02.000000000 +0530 +++ openssh-6.3p1_modified/myproposal.h 2013-10-16 15:18:44.000000000 +0530 @@ -114,6 +114,14 @@ #define KEX_DEFAULT_COMP "none,zlib@openssh.com,zlib" #define KEX_DEFAULT_LANG "" +#ifdef OPENSSL_FIPS_CAPABLE +#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,hmac-sha1-96" +#endif /* OPENSSL_FIPS_CAPABLE */ static char *myproposal[PROPOSAL_MAX] = { KEX_DEFAULT_KEX, diff -ruN openssh-6.3p1_orig/openbsd-compat/bsd-arc4random.c openssh-6.3p1_modified/openbsd-compat/bsd-arc4random.c --- openssh-6.3p1_orig/openbsd-compat/bsd-arc4random.c 2010-03-26 03:22:02.000000000 +0530 +++ openssh-6.3p1_modified/openbsd-compat/bsd-arc4random.c 2013-10-16 15:18:44.000000000 +0530 @@ -43,6 +43,18 @@ arc4random(void) { unsigned int r = 0; +#ifdef OPENSSL_FIPS_CAPABLE + if (FIPS_mode()) { + if (RAND_bytes(&r,sizeof(r)) <= 0) { + /* unfortunately there is no simple way to report this + * to the caller for handling so this is done via + * fatal() as per arc4random_stir + */ + fatal("Could not obtain random bytes (error %ld)", + ERR_get_error()); + } + } else { +#else /* !OPENSSL_FIPS_CAPABLE */ static int first_time = 1; if (rc4_ready <= 0) { @@ -55,13 +67,20 @@ RC4(&rc4, sizeof(r), (unsigned char *)&r, (unsigned char *)&r); rc4_ready -= sizeof(r); - + +#endif /* OPENSSL_FIPS_CAPABLE */ +#ifdef OPENSSL_FIPS_CAPABLE + } +#endif return(r); } void arc4random_stir(void) { +#ifdef OPENSSL_FIPS_CAPABLE + return; +#endif unsigned char rand_buf[SEED_SIZE]; int i; diff -ruN openssh-6.3p1_orig/readconf.c openssh-6.3p1_modified/readconf.c --- openssh-6.3p1_orig/readconf.c 2013-07-18 11:39:05.000000000 +0530 +++ openssh-6.3p1_modified/readconf.c 2013-10-16 15:18:44.000000000 +0530 @@ -138,7 +138,11 @@ oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, - oIgnoredUnknownOption, oDeprecated, oUnsupported + oIgnoredUnknownOption, +#ifdef OPENSSL_FIPS_CAPABLE + oFIPS, +#endif + oDeprecated, oUnsupported } OpCodes; /* Textual representations of the tokens. */ @@ -250,6 +254,9 @@ { "ipqos", oIPQoS }, { "requesttty", oRequestTTY }, { "ignoreunknown", oIgnoreUnknown }, +#ifdef OPENSSL_FIPS_CAPABLE + { "fips", oFIPS }, +#endif { NULL, oBadOption } }; @@ -1076,6 +1083,11 @@ debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); return 0; +#ifdef OPENSSL_FIPS_CAPABLE + case oFIPS: + intptr = &options->fips_mode; + goto parse_flag; +#endif case oUnsupported: error("%s line %d: Unsupported option \"%s\"", @@ -1233,6 +1245,9 @@ options->ip_qos_interactive = -1; options->ip_qos_bulk = -1; options->request_tty = -1; +#ifdef OPENSSL_FIPS_CAPABLE + options->fips_mode = -1; +#endif options->ignored_unknown = NULL; } @@ -1385,6 +1400,10 @@ options->ip_qos_bulk = IPTOS_THROUGHPUT; if (options->request_tty == -1) options->request_tty = REQUEST_TTY_AUTO; +#ifdef OPENSSL_FIPS_CAPABLE + if (options->fips_mode == -1) + options->fips_mode = 0; +#endif /* options->local_command should not be set by default */ /* options->proxy_command should not be set by default */ /* options->user will be set in the main program if appropriate */ diff -ruN openssh-6.3p1_orig/readconf.h openssh-6.3p1_modified/readconf.h --- openssh-6.3p1_orig/readconf.h 2013-05-16 16:00:03.000000000 +0530 +++ openssh-6.3p1_modified/readconf.h 2013-10-16 15:18:44.000000000 +0530 @@ -137,6 +137,9 @@ int use_roaming; int request_tty; +#ifdef OPENSSL_FIPS_CAPABLE + int fips_mode; +#endif char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ } Options; diff -ruN openssh-6.3p1_orig/servconf.c openssh-6.3p1_modified/servconf.c --- openssh-6.3p1_orig/servconf.c 2013-07-20 08:51:53.000000000 +0530 +++ openssh-6.3p1_modified/servconf.c 2013-10-16 15:18:44.000000000 +0530 @@ -153,6 +153,9 @@ options->ip_qos_interactive = -1; options->ip_qos_bulk = -1; options->version_addendum = NULL; +#ifdef OPENSSL_FIPS_CAPABLE + options->fips_mode = -1; +#endif } void @@ -310,6 +313,10 @@ options->compression = 0; } #endif +#ifdef OPENSSL_FIPS_CAPABLE + if (options->fips_mode == -1) + options->fips_mode = 0; +#endif } @@ -346,6 +353,9 @@ sKexAlgorithms, sIPQoS, sVersionAddendum, sAuthorizedKeysCommand, sAuthorizedKeysCommandUser, sAuthenticationMethods, sHostKeyAgent, +#ifdef OPENSSL_FIPS_CAPABLE + sFIPS, +#endif sDeprecated, sUnsupported } ServerOpCodes; @@ -476,6 +486,9 @@ { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL }, { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL }, +#ifdef OPENSSL_FIPS_CAPABLE + { "FIPS", sFIPS, SSHCFG_ALL }, +#endif { NULL, sBadOption, 0 } }; @@ -1613,6 +1626,11 @@ while (arg) arg = strdelim(&cp); break; +#ifdef OPENSSL_FIPS_CAPABLE + case sFIPS: + intptr = &options->fips_mode; + goto parse_flag; +#endif case sUnsupported: logit("%s line %d: Unsupported option %s", @@ -2064,6 +2082,9 @@ printf("%s\n", iptos2str(o->ip_qos_bulk)); printf("rekeylimit %lld %d\n", o->rekey_limit, o->rekey_interval); +#ifdef OPENSSL_FIPS_CAPABLE + dump_cfg_fmtint(sFIPS, o->fips_mode); +#endif channel_print_adm_permitted_opens(); } diff -ruN openssh-6.3p1_orig/servconf.h openssh-6.3p1_modified/servconf.h --- openssh-6.3p1_orig/servconf.h 2013-07-20 08:51:53.000000000 +0530 +++ openssh-6.3p1_modified/servconf.h 2013-10-16 15:18:44.000000000 +0530 @@ -184,6 +184,9 @@ u_int num_auth_methods; char *auth_methods[MAX_AUTH_METHODS]; +#ifdef OPENSSL_FIPS_CAPABLE + int fips_mode; +#endif } ServerOptions; /* Information about the incoming connection as used by Match */ diff -ruN openssh-6.3p1_orig/ssh-add.c openssh-6.3p1_modified/ssh-add.c --- openssh-6.3p1_orig/ssh-add.c 2013-06-02 03:01:19.000000000 +0530 +++ openssh-6.3p1_modified/ssh-add.c 2013-10-16 15:18:44.000000000 +0530 @@ -326,7 +326,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_fingerprint_alg(), SSH_FP_HEX); printf("%d %s %s (%s)\n", key_size(key), fp, comment, key_type(key)); diff -ruN openssh-6.3p1_orig/ssh-agent.c openssh-6.3p1_modified/ssh-agent.c --- openssh-6.3p1_orig/ssh-agent.c 2013-07-20 08:52:49.000000000 +0530 +++ openssh-6.3p1_modified/ssh-agent.c 2013-10-16 15:18:44.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_fingerprint_alg(), SSH_FP_HEX); if (ask_permission("Allow use of key %s?\nKey fingerprint %s.", id->comment, p)) ret = 0; @@ -248,7 +248,7 @@ Identity *id; int i, len; Buffer msg; - MD5_CTX md; + EVP_MD_CTX md; Key *key; buffer_init(&msg); @@ -284,10 +284,13 @@ } 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); + if (EVP_DigestInit(&md, EVP_md5()) <= 0) + goto failure; + if (EVP_DigestUpdate(&md, buf, sizeof buf) <= 0) + goto failure; + if (EVP_DigestUpdate(&md, session_id, sizeof session_id) <= 0) + goto failure; + EVP_DigestFinal(&md, mdbuf, NULL); /* Send the response. */ buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE); diff -ruN openssh-6.3p1_orig/ssh.c openssh-6.3p1_modified/ssh.c --- openssh-6.3p1_orig/ssh.c 2013-07-25 07:25:53.000000000 +0530 +++ openssh-6.3p1_modified/ssh.c 2013-10-16 15:18:44.000000000 +0530 @@ -327,9 +327,20 @@ 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) { + "ACD:E:F:I:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { switch (opt) { case '1': +#ifdef OPENSSL_FIPS_CAPABLE + /* we need to check that we have selected the right + * SSH protocol for FIPS mode - otherwise it will simply + * not work and the error messages reported will not be + * particularly useful to the user; so if the user + * explicitly requests protocol 1 we need to tell them + * that it isn't acceptable in FIPS mode + */ + if (FIPS_mode()) + fatal("Protocol 1 is not allowed in FIPS mode"); +#endif /* OPENSSL_FIPS_CAPABLE */ options.protocol = SSH_PROTO_1; break; case '2': @@ -726,6 +737,32 @@ /* reinit */ log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog); +#ifdef OPENSSL_FIPS_CAPABLE + /* note: OpenSSL itself uses OPENSSL_FIPS to indicate + * wanting to run in FIPS mode + */ + if (options.fips_mode || getenv("OPENSSL_FIPS")) { + if (!FIPS_mode_set(1)) { + /* make sure the error stack is available for some hint as + * to why this operation failed + */ + ERR_load_crypto_strings(); + ERR_print_errors_fp(stdout); + printf("FIPS_mode_set(): failed to enter FIPS mode!\n"); + exit(1); + } + /* we need to check that we have selected the right + * SSH protocol for FIPS mode - otherwise it will simply + * not work and the error messages reported will not be + * particularly useful to the user; so if the user + * explicitly requests protocol 1 we need to tell them + * that it isn't acceptable in FIPS mode + */ + if (SSH_PROTO_1 == options.protocol) + fatal("Protocol 1 is not allowed in FIPS mode"); + } +#endif /* OPENSSL_FIPS_CAPABLE */ + if (options.request_tty == REQUEST_TTY_YES || options.request_tty == REQUEST_TTY_FORCE) tty_flag = 1; @@ -816,6 +853,21 @@ timeout_ms = options.connection_timeout * 1000; +#ifdef OPENSSL_FIPS_CAPABLE + /* after all the configuration files have been processed we + * need to check that we have selected the right SSH protocol + * for FIPS mode - otherwise it will simply not work and the error + * messages reported will not be particularly useful to the user + */ + if (FIPS_mode()) { + options.protocol &= SSH_PROTO_2; + if (options.protocol == 0) + fatal("Protocol 2 disabled by configuration but required by FIPS mode"); + debug("FIPS mode initialized"); + } +#endif /* OPENSSL_FIPS_CAPABLE */ + + /* Open a connection to the remote host. */ if (ssh_connect(host, &hostaddr, options.port, options.address_family, options.connection_attempts, &timeout_ms, diff -ruN openssh-6.3p1_orig/sshconnect2.c openssh-6.3p1_modified/sshconnect2.c --- openssh-6.3p1_orig/sshconnect2.c 2013-06-06 03:52:05.000000000 +0530 +++ openssh-6.3p1_modified/sshconnect2.c 2013-10-16 15:18:44.000000000 +0530 @@ -171,6 +171,12 @@ myproposal[PROPOSAL_ENC_ALGS_CTOS] = myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; } +#ifdef OPENSSL_FIPS_CAPABLE + else if (FIPS_mode()) { + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT; + } +#endif /* OPENSSL_FIPS_CAPABLE */ myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); myproposal[PROPOSAL_ENC_ALGS_STOC] = @@ -186,6 +192,12 @@ myproposal[PROPOSAL_MAC_ALGS_CTOS] = myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; } +#ifdef OPENSSL_FIPS_CAPABLE + else if (FIPS_mode()) { + myproposal[PROPOSAL_MAC_ALGS_CTOS] = + myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC; + } +#endif /* OPENSSL_FIPS_CAPABLE */ if (options.hostkeyalgorithms != NULL) myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = options.hostkeyalgorithms; @@ -590,7 +602,7 @@ key->type, pktype); goto done; } - fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + fp = key_fingerprint(key, key_fingerprint_alg(), SSH_FP_HEX); debug2("input_userauth_pk_ok: fp %s", fp); free(fp); @@ -1202,7 +1214,7 @@ int have_sig = 1; char *fp; - fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); + fp = key_fingerprint(id->key, key_fingerprint_alg(), SSH_FP_HEX); debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp); free(fp); diff -ruN openssh-6.3p1_orig/sshconnect.c openssh-6.3p1_modified/sshconnect.c --- openssh-6.3p1_orig/sshconnect.c 2013-06-02 03:01:19.000000000 +0530 +++ openssh-6.3p1_modified/sshconnect.c 2013-10-16 15:18:44.000000000 +0530 @@ -442,10 +442,10 @@ /* Send our own protocol version identification. */ if (compat20) { xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n", - PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION); + PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION SSH_FIPS); } else { xasprintf(&client_version_string, "SSH-%d.%d-%.100s\n", - PROTOCOL_MAJOR_1, minor1, SSH_VERSION); + PROTOCOL_MAJOR_1, minor1, SSH_VERSION SSH_FIPS); } if (roaming_atomicio(vwrite, connection_out, client_version_string, strlen(client_version_string)) != strlen(client_version_string)) @@ -830,8 +830,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_fingerprint_alg(), SSH_FP_HEX); + ra = key_fingerprint(host_key, key_fingerprint_alg(), SSH_FP_RANDOMART); logit("Host key fingerprint is %s\n%s\n", fp, ra); free(ra); @@ -871,8 +871,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_fingerprint_alg(), SSH_FP_HEX); + ra = key_fingerprint(host_key, key_fingerprint_alg(), SSH_FP_RANDOMART); msg2[0] = '\0'; if (options.verify_host_key_dns) { @@ -888,10 +888,10 @@ 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, key_fingerprint_alg()==SSH_FP_SHA1?"SHA1 ":"", fp, options.visual_host_key ? "\n" : "", options.visual_host_key ? ra : "", msg2); @@ -1136,7 +1136,7 @@ int flags = 0; char *fp; - fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); + fp = key_fingerprint(host_key, key_fingerprint_alg(), SSH_FP_HEX); debug("Server host key: %s %s", key_type(host_key), fp); free(fp); @@ -1238,14 +1238,16 @@ 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_fingerprint_alg(), SSH_FP_HEX); + ra = key_fingerprint(found->key, key_fingerprint_alg(), SSH_FP_RANDOMART); logit("WARNING: %s key found for host %s\n" "in %s:%lu\n" - "%s key fingerprint %s.", + "%s key %sfingerprint %s.\n%s\n", key_type(found->key), found->host, found->file, found->line, - key_type(found->key), fp); + key_type(found->key), + key_fingerprint_alg()==SSH_FP_SHA1?"SHA1 ":"", + fp, ra); if (options.visual_host_key) logit("%s", ra); free(ra); @@ -1259,8 +1261,9 @@ warn_changed_key(Key *host_key) { char *fp; + const char *type = key_type(host_key); - fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); + fp = key_fingerprint(host_key, key_fingerprint_alg(), SSH_FP_HEX); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); @@ -1268,8 +1271,8 @@ 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 a host key has just been changed."); - error("The fingerprint for the %s key sent by the remote host is\n%s.", - key_type(host_key), fp); + error("The %sfingerprint for the %s key sent by the remote host is\n%s.", + key_fingerprint_alg()==SSH_FP_SHA1?"SHA1 ":"", type, fp); error("Please contact your system administrator."); free(fp); diff -ruN openssh-6.3p1_orig/sshd.c openssh-6.3p1_modified/sshd.c --- openssh-6.3p1_orig/sshd.c 2013-07-20 08:51:53.000000000 +0530 +++ openssh-6.3p1_modified/sshd.c 2013-10-16 15:20:12.000000000 +0530 @@ -78,6 +78,8 @@ #include <openssl/rand.h> #include "openbsd-compat/openssl-compat.h" +#include <openssl/err.h> + #ifdef HAVE_SECUREWARE #include <sys/security.h> #include <prot.h> @@ -435,8 +437,9 @@ minor = PROTOCOL_MINOR_1; } - xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s", - major, minor, SSH_VERSION, + xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s%s", + major, minor, SSH_VERSION SSH_FIPS, + FIPS_mode()?"(enabled)":"", *options.version_addendum == '\0' ? "" : " ", options.version_addendum, newline); @@ -1584,13 +1587,40 @@ load_server_config(config_file_name, &cfg); parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, - &cfg, NULL); - - seed_rng(); + &cfg, NULL); /* Fill in default values for those options not explicitly set. */ fill_default_server_options(&options); + /* set default channel AF */ + channel_set_af(options.address_family); + + /* Check that there are no remaining arguments. */ + if (optind < ac) { + fprintf(stderr, "Extra argument %s.\n", av[optind]); + exit(1); + } + +#ifdef OPENSSL_FIPS_CAPABLE + /* note: there should be a command line option to indicate FIPS140 + * mode; however OpenSSL itself uses OPENSSL_FIPS to indicate + * wanting to run in FIPS mode + */ + if (options.fips_mode || getenv("OPENSSL_FIPS")) { + if (!FIPS_mode_set(1)) { + /* make sure the error stack is available for some hint as + * to why this operation failed + */ + ERR_load_crypto_strings(); + ERR_print_errors_fp(stdout); + printf("FIPS_mode_set(): failed to enter FIPS mode!\n"); + exit(1); + } + } +#endif /* OPENSSL_FIPS_CAPABLE */ + + seed_rng(); + /* challenge-response is implemented via keyboard interactive */ if (options.challenge_response_authentication) options.kbd_interactive_authentication = 1; @@ -1622,15 +1652,6 @@ "enabled authentication methods"); } - /* set default channel AF */ - channel_set_af(options.address_family); - - /* Check that there are no remaining arguments. */ - if (optind < ac) { - fprintf(stderr, "Extra argument %s.\n", av[optind]); - exit(1); - } - debug("sshd version %s, %s", SSH_VERSION, SSLeay_version(SSLEAY_VERSION)); @@ -1697,8 +1718,14 @@ break; } debug("private host key: #%d type %d %s", i, keytype, - key_type(key ? key : pubkey)); + key_type(key ? key : pubkey)); + } +#ifdef OPENSSL_FIPS_CAPABLE + if ((options.protocol & SSH_PROTO_1) && FIPS_mode()) { + logit("Disabling protocol version 1. Not allowed in FIPS mode"); + options.protocol &= ~SSH_PROTO_1; } +#endif /* OPENSSL_FIPS_CAPABLE */ 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; @@ -1862,6 +1889,12 @@ /* Initialize the random number generator. */ arc4random_stir(); +#ifdef OPENSSL_FIPS_CAPABLE + if (FIPS_mode()) { + logit("FIPS mode initialized"); + } +#endif /* OPENSSL_FIPS_CAPABLE */ + /* Chdir to the root directory so that the current disk can be unmounted if desired. */ if (chdir("/") == -1) @@ -2414,6 +2447,12 @@ myproposal[PROPOSAL_ENC_ALGS_CTOS] = myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; } +#ifdef OPENSSL_FIPS_CAPABLE + else if (FIPS_mode()) { + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT; + } +#endif /* OPENSSL_FIPS_CAPABLE */ myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); myproposal[PROPOSAL_ENC_ALGS_STOC] = @@ -2423,6 +2462,12 @@ myproposal[PROPOSAL_MAC_ALGS_CTOS] = myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; } +#ifdef OPENSSL_FIPS_CAPABLE + else if (FIPS_mode()) { + myproposal[PROPOSAL_MAC_ALGS_CTOS] = + myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC; + } +#endif /* OPENSSL_FIPS_CAPABLE */ if (options.compression == COMP_NONE) { myproposal[PROPOSAL_COMP_ALGS_CTOS] = myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; diff -ruN openssh-6.3p1_orig/ssh-dss.c openssh-6.3p1_modified/ssh-dss.c --- openssh-6.3p1_orig/ssh-dss.c 2013-06-02 03:01:19.000000000 +0530 +++ openssh-6.3p1_modified/ssh-dss.c 2013-10-16 15:18:44.000000000 +0530 @@ -47,26 +47,48 @@ const u_char *data, u_int datalen) { DSA_SIG *sig; - const EVP_MD *evp_md = EVP_sha1(); + const EVP_MD *evp_md = EVP_dss1(); EVP_MD_CTX md; - u_char digest[EVP_MAX_MD_SIZE], sigblob[SIGBLOB_LEN]; - u_int rlen, slen, len, dlen; + u_char sigblob[SIGBLOB_LEN]; + u_int rlen, slen, len ; Buffer b; + u_char *tsig; + const u_char *psig; + EVP_PKEY *pkey; + int ok; if (key == NULL || key->dsa == NULL || (key->type != KEY_DSA && key->type != KEY_DSA_CERT && key->type != KEY_DSA_CERT_V00)) { error("ssh_dss_sign: no DSA key"); return -1; } - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, data, datalen); - EVP_DigestFinal(&md, digest, &dlen); + pkey = EVP_PKEY_new(); + EVP_PKEY_set1_DSA(pkey, key->dsa); + slen = EVP_PKEY_size(pkey); + tsig = xmalloc(slen); + + EVP_MD_CTX_init(&md); + EVP_SignInit_ex(&md, evp_md, NULL); + EVP_SignUpdate(&md, data, datalen); + ok = EVP_SignFinal(&md, tsig, &len, pkey); + EVP_MD_CTX_cleanup(&md); + EVP_PKEY_free(pkey); - sig = DSA_do_sign(digest, dlen, key->dsa); - memset(digest, 'd', sizeof(digest)); + if (ok != 1) { + free(tsig); + error("ssh_dss_sign: sign failed"); + return -1; + } + + psig = tsig; + + /* Output of EVP_SignFinal() is encoded, convert to DSA_SIG */ + sig = d2i_DSA_SIG(NULL, &psig, len); + memset(tsig, 'd', len); + free(tsig); if (sig == NULL) { - error("ssh_dss_sign: sign failed"); + error("ssh_dss_sign: DSA parse failed"); return -1; } @@ -110,12 +132,14 @@ const u_char *data, u_int datalen) { DSA_SIG *sig; - const EVP_MD *evp_md = EVP_sha1(); + const EVP_MD *evp_md = EVP_dss1(); EVP_MD_CTX md; - u_char digest[EVP_MAX_MD_SIZE], *sigblob; - u_int len, dlen; + u_char *sigblob; + u_int len; int rlen, ret; Buffer b; + u_char *tsig, *psig; + EVP_PKEY *pkey; if (key == NULL || key->dsa == NULL || (key->type != KEY_DSA && key->type != KEY_DSA_CERT && key->type != KEY_DSA_CERT_V00)) { @@ -171,15 +195,27 @@ memset(sigblob, 0, len); free(sigblob); - /* sha1 the data */ - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, data, datalen); - EVP_DigestFinal(&md, digest, &dlen); + /* Sig is in DSA_SIG structure, convert to encoded buffer */ + len = i2d_DSA_SIG(sig, NULL); + tsig = xmalloc(len); + psig = tsig; + i2d_DSA_SIG(sig, &psig); + DSA_SIG_free(sig); - ret = DSA_do_verify(digest, dlen, sig, key->dsa); - memset(digest, 'd', sizeof(digest)); + pkey = EVP_PKEY_new(); + EVP_PKEY_set1_DSA(pkey, key->dsa); - DSA_SIG_free(sig); + /* now verify signature */ + EVP_MD_CTX_init(&md); + EVP_VerifyInit(&md, evp_md); + EVP_VerifyUpdate(&md, data, datalen); + ret = EVP_VerifyFinal(&md, tsig, len, pkey); + EVP_MD_CTX_cleanup(&md); + EVP_PKEY_free(pkey); + + /* Cleanup buffer */ + memset(tsig, 'd', len); + free(tsig); debug("ssh_dss_verify: signature %s", ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); diff -ruN openssh-6.3p1_orig/ssh-keygen.c openssh-6.3p1_modified/ssh-keygen.c --- openssh-6.3p1_orig/ssh-keygen.c 2013-07-20 08:52:32.000000000 +0530 +++ openssh-6.3p1_modified/ssh-keygen.c 2013-10-16 15:18:44.000000000 +0530 @@ -730,7 +730,7 @@ enum fp_type fptype; char *fp, *ra; - fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; + fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_alg(); rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; pkcs11_init(0); @@ -740,7 +740,7 @@ for (i = 0; i < nkeys; i++) { if (print_fingerprint) { fp = key_fingerprint(keys[i], fptype, rep); - ra = key_fingerprint(keys[i], SSH_FP_MD5, + ra = key_fingerprint(keys[i], key_fingerprint_alg(), SSH_FP_RANDOMART); printf("%u %s %s (PKCS11 key)\n", key_size(keys[i]), fp, key_type(keys[i])); @@ -773,7 +773,7 @@ enum fp_type fptype; struct stat st; - fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; + fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_alg(); rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; if (!have_identity) @@ -785,7 +785,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_fingerprint_alg(), SSH_FP_RANDOMART); printf("%u %s %s (%s)\n", key_size(public), fp, comment, key_type(public)); if (log_level >= SYSLOG_LEVEL_VERBOSE) @@ -851,7 +851,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_fingerprint_alg(), 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) @@ -972,10 +972,10 @@ enum fp_type fptype; char *fp, *ra; - fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; + fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_alg(); 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_fingerprint_alg(), SSH_FP_RANDOMART); printf("%u %s %s (%s)\n", key_size(public), fp, name, key_type(public)); if (log_level >= SYSLOG_LEVEL_VERBOSE) @@ -1855,7 +1855,7 @@ 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_fingerprint_alg(), SSH_FP_HEX); ca_fp = key_fingerprint(key->cert->signature_key, SSH_FP_MD5, SSH_FP_HEX); @@ -2201,6 +2201,24 @@ extern int optind; extern char *optarg; +#ifdef OPENSSL_FIPS_CAPABLE + /* note: there should be a command line option to indicate FIPS140 + * mode; however OpenSSL itself uses OPENSSL_FIPS to indicate + * wanting to run in FIPS mode + */ + if (getenv("OPENSSL_FIPS")) { + if (!FIPS_mode_set(1)) { + /* make sure the error stack is available for some hint as + * to why this operation failed + * */ + ERR_load_crypto_strings(); + ERR_print_errors_fp(stdout); + printf("FIPS_mode_set(): failed to enter FIPS mode!\n"); + exit(1); + } + } +#endif /* OPENSSL_FIPS_CAPABLE */ + /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); @@ -2655,8 +2673,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_fingerprint_alg(), SSH_FP_HEX); + char *ra = key_fingerprint(public, key_fingerprint_alg(), SSH_FP_RANDOMART); printf("Your public key has been saved in %s.\n", identity_file); diff -ruN openssh-6.3p1_orig/ssh-rsa.c openssh-6.3p1_modified/ssh-rsa.c --- openssh-6.3p1_orig/ssh-rsa.c 2013-06-02 03:01:19.000000000 +0530 +++ openssh-6.3p1_modified/ssh-rsa.c 2013-10-16 15:18:44.000000000 +0530 @@ -42,10 +42,11 @@ { const EVP_MD *evp_md; EVP_MD_CTX md; - u_char digest[EVP_MAX_MD_SIZE], *sig; - u_int slen, dlen, len; + u_char *sig; + u_int slen, len; int ok, nid; Buffer b; + EVP_PKEY *pkey; if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA && key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) { @@ -57,15 +58,17 @@ 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); - - slen = RSA_size(key->rsa); + pkey = EVP_PKEY_new(); + EVP_PKEY_set1_RSA(pkey, key->rsa); + slen = EVP_PKEY_size(pkey); sig = xmalloc(slen); - ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa); - memset(digest, 'd', sizeof(digest)); + EVP_MD_CTX_init(&md); + EVP_SignInit_ex(&md, evp_md, NULL); + EVP_SignUpdate(&md, data, datalen); + ok = EVP_SignFinal(&md, sig, &len, pkey); + EVP_MD_CTX_cleanup(&md); + EVP_PKEY_free(pkey); if (ok != 1) { int ecode = ERR_get_error(); @@ -111,9 +114,10 @@ const EVP_MD *evp_md; EVP_MD_CTX md; char *ktype; - u_char digest[EVP_MAX_MD_SIZE], *sigblob; - u_int len, dlen, modlen; + u_char *sigblob; + u_int len, modlen; int rlen, ret, nid; + EVP_PKEY *pkey; if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA && key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) { @@ -164,104 +168,17 @@ free(sigblob); return -1; } - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, data, datalen); - EVP_DigestFinal(&md, digest, &dlen); + pkey = EVP_PKEY_new(); + EVP_PKEY_set1_RSA(pkey, key->rsa); + EVP_MD_CTX_init(&md); + EVP_VerifyInit_ex(&md, evp_md, NULL); + EVP_VerifyUpdate(&md, data, datalen); + ret = EVP_VerifyFinal(&md, sigblob, len, pkey); + EVP_MD_CTX_cleanup(&md); + EVP_PKEY_free(pkey); - ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa); - memset(digest, 'd', sizeof(digest)); memset(sigblob, 's', len); free(sigblob); debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : ""); return ret; } - -/* - * See: - * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ - * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn - */ -/* - * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) - * oiw(14) secsig(3) algorithms(2) 26 } - */ -static const u_char id_sha1[] = { - 0x30, 0x21, /* type Sequence, length 0x21 (33) */ - 0x30, 0x09, /* type Sequence, length 0x09 */ - 0x06, 0x05, /* type OID, length 0x05 */ - 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ - 0x05, 0x00, /* NULL */ - 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ -}; -/* - * id-md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) - * rsadsi(113549) digestAlgorithm(2) 5 } - */ -static const u_char id_md5[] = { - 0x30, 0x20, /* type Sequence, length 0x20 (32) */ - 0x30, 0x0c, /* type Sequence, length 0x09 */ - 0x06, 0x08, /* type OID, length 0x05 */ - 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* id-md5 */ - 0x05, 0x00, /* NULL */ - 0x04, 0x10 /* Octet string, length 0x10 (16), followed by md5 hash */ -}; - -static int -openssh_RSA_verify(int type, u_char *hash, u_int hashlen, - u_char *sigbuf, u_int siglen, RSA *rsa) -{ - u_int ret, rsasize, oidlen = 0, hlen = 0; - int len, oidmatch, hashmatch; - const u_char *oid = NULL; - u_char *decrypted = NULL; - - ret = 0; - switch (type) { - case NID_sha1: - oid = id_sha1; - oidlen = sizeof(id_sha1); - hlen = 20; - break; - case NID_md5: - oid = id_md5; - oidlen = sizeof(id_md5); - hlen = 16; - break; - default: - goto done; - } - if (hashlen != hlen) { - error("bad hashlen"); - goto done; - } - rsasize = RSA_size(rsa); - if (siglen == 0 || siglen > rsasize) { - error("bad siglen"); - goto done; - } - decrypted = xmalloc(rsasize); - if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, - RSA_PKCS1_PADDING)) < 0) { - error("RSA_public_decrypt failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto done; - } - if (len < 0 || (u_int)len != hlen + oidlen) { - error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); - goto done; - } - oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; - hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; - if (!oidmatch) { - error("oid mismatch"); - goto done; - } - if (!hashmatch) { - error("hash mismatch"); - goto done; - } - ret = 1; -done: - free(decrypted); - return ret; -} diff -ruN openssh-6.3p1_orig/version.h openssh-6.3p1_modified/version.h --- openssh-6.3p1_orig/version.h 2013-07-25 07:27:15.000000000 +0530 +++ openssh-6.3p1_modified/version.h 2013-10-16 15:18:44.000000000 +0530 @@ -3,4 +3,11 @@ #define SSH_VERSION "OpenSSH_6.3" #define SSH_PORTABLE "p1" -#define SSH_RELEASE SSH_VERSION SSH_PORTABLE + +/* it is important to provide an indication that FIPS is supported */ +#ifdef OPENSSL_FIPS_CAPABLE + #define SSH_FIPS "-FIPS" +#else + #define SSH_FIPS "" +#endif /* OPENSSL_FIPS_CAPABLE */ +#define SSH_RELEASE SSH_VERSION SSH_PORTABLE SSH_FIPS