[Openvpn-devel,1/2] Added support for OpenSSL FIPS Object Module v2.0 validated encryption

Message ID 1512422193-8184-1-git-send-email-jim@carroll.com
State New
Headers show
Series
  • [Openvpn-devel,1/2] Added support for OpenSSL FIPS Object Module v2.0 validated encryption
Related show

Commit Message

Jim Carroll Dec. 4, 2017, 9:16 p.m.
From: Jim Carroll <jim@carroll.com>

Signed-off-by: Jim Carroll <jim@carroll.com>
---
 INSTALL                      | 78 ++++++++++++++++++++++++++++++++++++++++++++
 Makefile.am                  |  5 +++
 configure.ac                 | 41 +++++++++++++++++++++++
 src/openvpn/crypto.c         |  2 +-
 src/openvpn/crypto_backend.h |  3 +-
 src/openvpn/crypto_openssl.c | 16 ++++++++-
 src/openvpn/crypto_openssl.h |  8 +++++
 src/openvpn/ntlm.c           |  2 +-
 src/openvpn/openvpn.c        |  9 +++++
 src/openvpn/options.c        | 18 ++++++++++
 src/openvpn/options.h        |  3 ++
 src/openvpn/ssl.c            | 12 +++++--
 src/openvpn/ssl.h            |  4 +++
 13 files changed, 195 insertions(+), 6 deletions(-)

Comments

Steffan Karger Jan. 21, 2018, 12:10 p.m. | #1
Hi,

Sorry for taking so long to review.  At least some early review comments:

On 04-12-17 22:16, jim@carroll.com wrote:
> From: Jim Carroll <jim@carroll.com>
> 
> Signed-off-by: Jim Carroll <jim@carroll.com>
> ---
>  INSTALL                      | 78 ++++++++++++++++++++++++++++++++++++++++++++
>  Makefile.am                  |  5 +++
>  configure.ac                 | 41 +++++++++++++++++++++++
>  src/openvpn/crypto.c         |  2 +-
>  src/openvpn/crypto_backend.h |  3 +-
>  src/openvpn/crypto_openssl.c | 16 ++++++++-
>  src/openvpn/crypto_openssl.h |  8 +++++
>  src/openvpn/ntlm.c           |  2 +-
>  src/openvpn/openvpn.c        |  9 +++++
>  src/openvpn/options.c        | 18 ++++++++++
>  src/openvpn/options.h        |  3 ++
>  src/openvpn/ssl.c            | 12 +++++--
>  src/openvpn/ssl.h            |  4 +++
>  13 files changed, 195 insertions(+), 6 deletions(-)
> 
> diff --git a/INSTALL b/INSTALL
> index 3a31e6f..b001cb1 100644
> --- a/INSTALL
> +++ b/INSTALL
> @@ -305,6 +305,84 @@ TUN/TAP Driver Configuration:
>  
>  *************************************************************************
>  
> +OpenSSL FIPS Object Module v2.0 Configuration:
> +
> +These instructions were adapted from
> +
> +    https://www.openssl.org/docs/fipsnotes.html
> +
> +Requirements:
> +
> +    * OpenSSL 1.0.2m
> +    * openssl-fips-2.0.2
> +
> +WARNING
> +
> +To install FIPS Validated encryption, you must follow the instructions in the
> +FIPS 2.0 User's Guide precisely. You are not permitted to modify any of the FIPS
> +build artifacts, makefiles or scripts. The FIPS 2.0 module is only compatible with
> +OpenSSL 1.0.1 and 1.0.2.
> +
> +These instructions describe the use of OpenSSL 1.0.2m.
> +
> +PRE-INSTALLATION CHECKUP:
> +
> +    The INSTALLATION procecure describes how to install an OpenSSL library that
> +    is built with FIPS support. If your platform already provides a FIPS
> +    enabled library you can skip to step 6 (build OpenVPN).
> +
> +INSTALLATION:
> +
> +    1. Surf to https://www.openssl.org/source/
> +    2. Download source AND validate the download was correct (preferably using PGP)
> +    3. Untar and uncompress tarball
> +    4. You must build using this precise command (do NOT choose any other options):
> +
> +            # ./config && make install
> +
> +            (you may optionslly pass 'no-asm' to config)
> +
> +       If the above procedure does not build on your system -- STOP. You are not
> +       building on a FIPS supported platform, and therefore will not have a
> +       FIPS validated encryption environment. See chapter 3 of the FIPS 2.0
> +       User's Guide for the complete list of supported platforms:
> +
> +            https://openssl.org/docs/fips/UserGuide-2.0.pdf
> +
> +    5. Download, build & install openssl 1.0.2m (you are permitted to
> +       modify this step to suite your preferences):
> +
> +            # git clone https://github.com/openssl/openssl.git
> +            # (cd openssl && \
> +                    git checkout OpenSSL_1_0_2m && \
> +                    ./config fips && \
> +                    make depend && \
> +                    make install)
> +
> +    6. Now build openvpn and tell it where to find you recently installed OpenSSL
> +
> +            # ./configure --enable-fips-mode \
> +                    OPENSSL_CFLAGS=-I/usr/local/ssl/include \
> +                    OPENSSL_LIBS="-ldl -L/usr/local/ssl/lib -lssl -lcrypto"
> +
> +            # make install
> +
> +    7. You can confirm FIPS mode is available with the command
> +
> +            # ./openvpn --version | grep 'library version'
> +            library versions: OpenSSL 1.0.2m-fips  2 Nov 2017, LZO 2.08
> +
> +USAGE:
> +
> +The above adds a new '--enable-fips-mode' command line option to OpenVPN. Add this to your
> +invocation statement. If you've successfully configured OpenVPN for FIPS mode, check your
> +OpenVPN logs for the statement:
> +
> +    *** FIPS MODE ENABLE ***
> +
> +
> +*************************************************************************
> +
>  CAVEATS & BUGS:
>  
>  * I have noticed cases where TCP sessions tunneled over the Linux
> diff --git a/Makefile.am b/Makefile.am
> index 773b786..6d571ec 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -83,6 +83,11 @@ rootdir=$(prefix)
>  root_DATA = version.sh
>  endif
>  
> +if FIPSMODE
> +export CC
> +export FIPSLD_CC
> +endif
> +
>  config-version.h:
>  	@CONFIGURE_GIT_CHFILES="`GIT_DIR=\"$(top_srcdir)/.git\" $(GIT) diff-files --name-status -r --ignore-submodules --quiet -- || echo \"+\"`"; \
>  	CONFIGURE_GIT_UNCOMMITTED="`GIT_DIR=\"$(top_srcdir)/.git\" $(GIT) diff-index --cached  --quiet --ignore-submodules HEAD || echo \"*\"`"; \
> diff --git a/configure.ac b/configure.ac
> index b4fd1b3..dc74230 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -286,6 +286,17 @@ AC_ARG_WITH(
>  	[with_crypto_library="openssl"]
>  )
>  
> +AC_ARG_ENABLE(
> +    [fips-mode],
> +    [AS_HELP_STRING([--enable-fips-mode], [OpenSSL FIPS Object Module 2.0 @<:@default=no@:>@])],
> +    [
> +        if test "${with_crypto_library}" != "openssl"; then
> +            AC_MSG_ERROR([enable_fips_mode requires --with_crypto_library=openssl])
> +        fi
> +    ],
> +    [enable_fips_mode="no"]
> +)
> +
>  AC_ARG_VAR([PLUGINDIR], [Path of plug-in directory @<:@default=LIBDIR/openvpn/plugins@:>@])
>  if test -n "${PLUGINDIR}"; then
>  	plugindir="${PLUGINDIR}"
> @@ -948,6 +959,35 @@ if test "${with_crypto_library}" = "openssl"; then
>  		]
>  	)
>  
> +    if test "${enable_fips_mode}" = "yes"; then
> +        AC_CHECK_FUNCS(
> +            [ \
> +                FIPS_mode \
> +                FIPS_mode_set \
> +                SSLeay_version
> +            ],
> +            [],
> +            [AC_MSG_ERROR([Incorrect version of OpenSSL, require 1.0.2])]

This isn't really the version check that fails, right?  Something like
"Couldn't find functions required for FIPS" sounds more accurate.

> +            )
> +        AC_RUN_IFELSE(
> +            [AC_LANG_PROGRAM(
> +                [[#include <openssl/crypto.h>]],
> +                [[printf("%s\n", SSLeay_version(SSLEAY_DIR));]])
> +            ],
> +            [AC_SUBST(OPENSSLDIR,
> +                [[`./conftest$EXEEXT | $SED -n 's/.*"\(.*\)".*/\1/p'`]])
> +            ]
> +        )

Instead of calling SSLeay_version(), consider using the OPENSSL_VERSION
define, like we already do elsewhere in configure.ac.  That will not
break as soon as there is a FIPS-compliant 1.1 release (which the
openssl devs say there will be "soon").

> +        if ! test -x "${OPENSSLDIR}/fips-2.0/bin/fipsld"; then
> +            AC_MSG_ERROR([Incomplete OpenSSL FIPS installation; missing fipsld])
> +        fi
> +        AC_SUBST([FIPSLD_CC], ["${CC}"])
> +        AC_SUBST([CC], ["${OPENSSLDIR}/fips-2.0/bin/fipsld"])
> +        export CC
> +        export FIPSLD_CC
> +        AC_DEFINE([ENABLE_FIPS], [1], [Enable OpenSSL FIPS 2.0 Options])
> +    fi
> +
>  	CFLAGS="${saved_CFLAGS}"
>  	LIBS="${saved_LIBS}"
>  
> @@ -1359,6 +1399,7 @@ AM_CONDITIONAL([GIT_CHECKOUT], [test "${GIT_CHECKOUT}" = "yes"])
>  AM_CONDITIONAL([ENABLE_PLUGIN_AUTH_PAM], [test "${enable_plugin_auth_pam}" = "yes"])
>  AM_CONDITIONAL([ENABLE_PLUGIN_DOWN_ROOT], [test "${enable_plugin_down_root}" = "yes"])
>  AM_CONDITIONAL([HAVE_LD_WRAP_SUPPORT], [test "${have_ld_wrap_support}" = "yes"])
> +AM_CONDITIONAL([FIPSMODE], [test "${enable_fips_mode}" = "yes"])
>  
>  sampledir="\$(docdir)/sample"
>  AC_SUBST([plugindir])
> diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
> index 3096f3b..97d117b 100644
> --- a/src/openvpn/crypto.c
> +++ b/src/openvpn/crypto.c
> @@ -852,7 +852,7 @@ init_key_ctx(struct key_ctx *ctx, const struct key *key,
>      if (kt->digest && kt->hmac_length > 0)
>      {
>          ctx->hmac = hmac_ctx_new();
> -        hmac_ctx_init(ctx->hmac, key->hmac, kt->hmac_length, kt->digest);
> +        hmac_ctx_init(ctx->hmac, key->hmac, kt->hmac_length, kt->digest, false);
>  
>          msg(D_HANDSHAKE,
>              "%s: Using %d bit message hash '%s' for HMAC authentication",
> diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h
> index 567fd9b..8790ca5 100644
> --- a/src/openvpn/crypto_backend.h
> +++ b/src/openvpn/crypto_backend.h
> @@ -604,10 +604,11 @@ void hmac_ctx_free(hmac_ctx_t *ctx);
>   * @param key           The key to use for the HMAC
>   * @param key_len       The key length to use
>   * @param kt            Static message digest parameters
> + * @param prf_use       Intended use for PRF in TLS protocol
>   *
>   */
>  void hmac_ctx_init(hmac_ctx_t *ctx, const uint8_t *key, int key_length,
> -                   const md_kt_t *kt);
> +                   const md_kt_t *kt, bool prf_use);

Instead of adding this parameter, I'd prefer to add a
hmac_ctx_set_fips_prf() function.  That way all the non-prf hmac calls
don't have to change.

>  /*
>   * Free the given HMAC context.
> diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c
> index 20a519e..fe4cef3 100644
> --- a/src/openvpn/crypto_openssl.c
> +++ b/src/openvpn/crypto_openssl.c
> @@ -159,6 +159,18 @@ crypto_init_lib(void)
>  #endif
>  }
>  
> +int
> +crypto_enable_fips_mode(int mode)
> +{
> +    if (!FIPS_mode_set(mode))
> +    {
> +        ERR_print_errors_fp(stderr);
> +        return 1;
> +    }
> +    msg(M_INFO, "*** FIPS MODE ENABLED ***");
> +    return 0;
> +}
> +
>  void
>  crypto_uninit_lib(void)
>  {
> @@ -926,11 +938,13 @@ hmac_ctx_free(HMAC_CTX *ctx)
>  
>  void
>  hmac_ctx_init(HMAC_CTX *ctx, const uint8_t *key, int key_len,
> -              const EVP_MD *kt)
> +              const EVP_MD *kt, bool prf_use)
>  {
>      ASSERT(NULL != kt && NULL != ctx);
>  
>      HMAC_CTX_reset(ctx);
> +    if (kt == EVP_md5() && prf_use)
> +        HMAC_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);

Please always use braces for a branch.

>      HMAC_Init_ex(ctx, key, key_len, kt, NULL);
>  
>      /* make sure we used a big enough key */
> diff --git a/src/openvpn/crypto_openssl.h b/src/openvpn/crypto_openssl.h
> index 60a2812..fbc8b2a 100644
> --- a/src/openvpn/crypto_openssl.h
> +++ b/src/openvpn/crypto_openssl.h
> @@ -102,4 +102,12 @@ void crypto_print_openssl_errors(const unsigned int flags);
>      } while (false)
>  
>  
> +/**
> + * Enable FIPS Mode. Returns non-zero to indicate an error.
> + *
> + * @param mode         Should be 1. Future versions of OpenSSL FIPS
> + *                     code are expected to accept extended modes.
> + */
> +int crypto_enable_fips_mode(int mode);
> +
>  #endif /* CRYPTO_OPENSSL_H_ */
> diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c
> index 077fa3e..fe39ab1 100644
> --- a/src/openvpn/ntlm.c
> +++ b/src/openvpn/ntlm.c
> @@ -88,7 +88,7 @@ gen_hmac_md5(const uint8_t *data, int data_len, const uint8_t *key, int key_len,
>      const md_kt_t *md5_kt = md_kt_get("MD5");
>      hmac_ctx_t *hmac_ctx = hmac_ctx_new();
>  
> -    hmac_ctx_init(hmac_ctx, key, key_len, md5_kt);
> +    hmac_ctx_init(hmac_ctx, key, key_len, md5_kt, false);
>      hmac_ctx_update(hmac_ctx, data, data_len);
>      hmac_ctx_final(hmac_ctx, result);
>      hmac_ctx_cleanup(hmac_ctx);
> diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c
> index e237ee5..da8e852 100644
> --- a/src/openvpn/openvpn.c
> +++ b/src/openvpn/openvpn.c
> @@ -210,6 +210,15 @@ openvpn_main(int argc, char *argv[])
>              /* parse command line options, and read configuration file */
>              parse_argv(&c.options, argc, argv, M_USAGE, OPT_P_DEFAULT, NULL, c.es);
>  
> +#if ENABLE_FIPS
> +            if (c.options.fips_mode)
> +            {
> +                if (enable_fips_mode(c.options.fips_mode))
> +                {
> +                    break;
> +                }
> +            }
> +#endif
>  #ifdef ENABLE_PLUGIN
>              /* plugins may contribute options configuration */
>              init_verb_mute(&c, IVM_LEVEL_1);
> diff --git a/src/openvpn/options.c b/src/openvpn/options.c
> index 7be5f38..99d3ccc 100644
> --- a/src/openvpn/options.c
> +++ b/src/openvpn/options.c
> @@ -517,6 +517,11 @@ static const char usage_message[] =
>      "\n"
>      "Data Channel Encryption Options (must be compatible between peers):\n"
>      "(These options are meaningful for both Static Key & TLS-mode)\n"
> +#ifdef ENABLE_FIPS
> +	"--enable-fips-mode : Enable OpenSSL FIPS Object Module v2.0.\n"
> +	"                  Setting this on the server will enforce FIPS validated\n"
> +	"                  encryption on both client and server.\n"
> +#endif
>      "--secret f [d]  : Enable Static Key encryption mode (non-TLS).\n"
>      "                  Use shared secret file f, generate with --genkey.\n"
>      "                  The optional d parameter controls key directionality.\n"
> @@ -847,6 +852,9 @@ init_options(struct options *o, const bool init_gc)
>      o->scheduled_exit_interval = 5;
>  #endif
>      o->ciphername = "BF-CBC";
> +#ifdef ENABLE_FIPS
> +	o->fips_mode = 0;
> +#endif
>  #ifdef HAVE_AEAD_CIPHER_MODES /* IV_NCP=2 requires GCM support */
>      o->ncp_enabled = true;
>  #else
> @@ -1550,6 +1558,9 @@ show_settings(const struct options *o)
>      SHOW_INT(persist_mode);
>  #endif
>  
> +#ifdef ENABLE_FIPS
> +    SHOW_INT(fips_mode);
> +#endif
>      SHOW_BOOL(show_ciphers);
>      SHOW_BOOL(show_digests);
>      SHOW_BOOL(show_engines);
> @@ -7389,6 +7400,13 @@ add_option(struct options *options,
>          }
>      }
>  #endif /* USE_COMP */
> +#ifdef ENABLE_FIPS
> +    else if (streq(p[0], "enable-fips-mode") && !p[1])
> +    {
> +        VERIFY_PERMISSION(OPT_P_GENERAL);
> +        options->fips_mode = 1;
> +    }
> +#endif
>      else if (streq(p[0], "show-ciphers") && !p[1])
>      {
>          VERIFY_PERMISSION(OPT_P_GENERAL);
> diff --git a/src/openvpn/options.h b/src/openvpn/options.h
> index f70760c..6ffe646 100644
> --- a/src/openvpn/options.h
> +++ b/src/openvpn/options.h
> @@ -186,6 +186,9 @@ struct options
>      bool persist_config;
>      int persist_mode;
>  
> +#ifdef ENABLE_FIPS
> +	int fips_mode;
> +#endif

Use spaces for indentation.  Also, sounds like this should be bool,
rather than an int?

>      const char *key_pass_file;
>      bool show_ciphers;
>      bool show_digests;
> diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
> index 7b42845..3992f4d 100644
> --- a/src/openvpn/ssl.c
> +++ b/src/openvpn/ssl.c
> @@ -352,6 +352,14 @@ init_ssl_lib(void)
>      crypto_init_lib();
>  }
>  
> +#if ENABLE_FIPS
> +int
> +enable_fips_mode(int mode)
> +{
> +	return crypto_enable_fips_mode(mode);
> +}
> +#endif
> +
>  void
>  free_ssl_lib(void)
>  {
> @@ -1638,8 +1646,8 @@ tls1_P_hash(const md_kt_t *md_kt,
>      chunk = md_kt_size(md_kt);
>      A1_len = md_kt_size(md_kt);
>  
> -    hmac_ctx_init(ctx, sec, sec_len, md_kt);
> -    hmac_ctx_init(ctx_tmp, sec, sec_len, md_kt);
> +    hmac_ctx_init(ctx, sec, sec_len, md_kt, true);
> +    hmac_ctx_init(ctx_tmp, sec, sec_len, md_kt, true);
>  
>      hmac_ctx_update(ctx,seed,seed_len);
>      hmac_ctx_final(ctx, A1);
> diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h
> index dd1ab0f..f251765 100644
> --- a/src/openvpn/ssl.h
> +++ b/src/openvpn/ssl.h
> @@ -598,4 +598,8 @@ bool is_hard_reset(int op, int key_method);
>  
>  void delayed_auth_pass_purge(void);
>  
> +#if ENABLE_FIPS
> +int enable_fips_mode(int mode);
> +#endif
> +
>  #endif /* ifndef OPENVPN_SSL_H */
> 

I hope to look into this patch more, and run some test later.

Thanks so far,
-Steffan

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
Jim Carroll Jan. 21, 2018, 4:37 p.m. | #2
> > +    if test "${enable_fips_mode}" = "yes"; then
> > +        AC_CHECK_FUNCS(
> > +            [ \
> > +                FIPS_mode \
> > +                FIPS_mode_set \
> > +                SSLeay_version
> > +            ],
> > +            [],
> > +            [AC_MSG_ERROR([Incorrect version of OpenSSL, require
> 1.0.2])]
> 
> This isn't really the version check that fails, right?  Something like
> "Couldn't find functions required for FIPS" sounds more accurate.

The intention was to ensure the right version is being used.
SSLeay_version() doesn't exists in 1.1+. If they are using a newer version
of OpenSSL, the FIPS module is not valid. We also need the SSLeay_version()
function so we can extract the openssl installation directory.


> > +            )
> > +        AC_RUN_IFELSE(
> > +            [AC_LANG_PROGRAM(
> > +                [[#include <openssl/crypto.h>]],
> > +                [[printf("%s\n", SSLeay_version(SSLEAY_DIR));]])
> > +            ],
> > +            [AC_SUBST(OPENSSLDIR,
> > +                [[`./conftest$EXEEXT | $SED -n
> 's/.*"\(.*\)".*/\1/p'`]])
> > +            ]
> > +        )
> 
> Instead of calling SSLeay_version(), consider using the OPENSSL_VERSION
> define, like we already do elsewhere in configure.ac.  That will not
> break as soon as there is a FIPS-compliant 1.1 release (which the
> openssl devs say there will be "soon").

We are not interested in the version here -- we are trying to set OPENSSLDIR
to the directory where openssl is installed, which we capture from the
output of SSLeay_version(). We need the openssldir so we can find fipld and
use this during the build process.


> >  void hmac_ctx_init(hmac_ctx_t *ctx, const uint8_t *key, int
> key_length,
> > -                   const md_kt_t *kt);
> > +                   const md_kt_t *kt, bool prf_use);
> 
> Instead of adding this parameter, I'd prefer to add a
> hmac_ctx_set_fips_prf() function.  That way all the non-prf hmac calls
> don't have to change.

The function is called from three places (all of which we have patched).
You'd prefer to add create a largely duplicate function and then if/else
tests to those three calls rather than just add a parameter?  


> >      HMAC_CTX_reset(ctx);
> > +    if (kt == EVP_md5() && prf_use)
> > +        HMAC_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
> 
> Please always use braces for a branch.


Agreed. I tried to follow the coding conventions in the project, but missed
this one.


> > +#ifdef ENABLE_FIPS
> > +	int fips_mode;
> > +#endif
> 
> Use spaces for indentation.  Also, sounds like this should be bool,
> rather than an int?


It is strongly advised to use an int. Future versions of OpenSSL
FIPS_mode_set() are expected to accept extended modes. From
https://wiki.openssl.org/index.php/FIPS_mode_set()

		Currently all non-zero values of ONOFF enable 
		FIPS mode. In the future other values may specify 
		additional actions beyond enabling FIPS mode, such 
		as a value of 2 to designate an additional 
		restriction to Suite B algorithms. To avoid 
		further compatibility issues, a program is 
		encouraged to call FIPS_mode_set() with a ONOFF 
		value of 1 (rather than an arbitrary non-zero value).


> I hope to look into this patch more, and run some test later.
> 
> Thanks so far,
> -Steffan

Thanks Steffan


BTW: I just remembered, there are two more small changes I would like to
suggest. One is to fix a typo in the documentation, and the second was to
test the returned value from FIPS_mode_set() and to clean up error
reporting:




diff --git a/INSTALL b/INSTALL
index 0bb25b4..62a2bee 100644
--- a/INSTALL
+++ b/INSTALL
@@ -378,7 +378,7 @@ The above adds a new '--enable-fips-mode' command line
option to OpenVPN. Add th
 invocation statement. If you've successfully configured OpenVPN for FIPS
mode, check your
 OpenVPN logs for the statement:

-    *** FIPS MODE ENABLE ***
+    *** FIPS MODE ENABLED ***


 *************************************************************************
diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c
index fe4cef3..b55bad8 100644
--- a/src/openvpn/crypto_openssl.c
+++ b/src/openvpn/crypto_openssl.c
@@ -162,9 +162,9 @@ crypto_init_lib(void)
 int
 crypto_enable_fips_mode(int mode)
 {
-    if (!FIPS_mode_set(mode))
+    if (FIPS_mode_set(mode) != mode)
     {
-        ERR_print_errors_fp(stderr);
+        crypto_msg(M_FATAL, "Unable to set fips mode");
         return 1;
     }
     msg(M_INFO, "*** FIPS MODE ENABLED ***");


begin 666 smime.p7s
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
J(M&D&2&:5@,@7=/JI!\(&A&LRF2C-VFUFTZE%9,#-H3U3=??````````
`
end


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot

Patch

diff --git a/INSTALL b/INSTALL
index 3a31e6f..b001cb1 100644
--- a/INSTALL
+++ b/INSTALL
@@ -305,6 +305,84 @@  TUN/TAP Driver Configuration:
 
 *************************************************************************
 
+OpenSSL FIPS Object Module v2.0 Configuration:
+
+These instructions were adapted from
+
+    https://www.openssl.org/docs/fipsnotes.html
+
+Requirements:
+
+    * OpenSSL 1.0.2m
+    * openssl-fips-2.0.2
+
+WARNING
+
+To install FIPS Validated encryption, you must follow the instructions in the
+FIPS 2.0 User's Guide precisely. You are not permitted to modify any of the FIPS
+build artifacts, makefiles or scripts. The FIPS 2.0 module is only compatible with
+OpenSSL 1.0.1 and 1.0.2.
+
+These instructions describe the use of OpenSSL 1.0.2m.
+
+PRE-INSTALLATION CHECKUP:
+
+    The INSTALLATION procecure describes how to install an OpenSSL library that
+    is built with FIPS support. If your platform already provides a FIPS
+    enabled library you can skip to step 6 (build OpenVPN).
+
+INSTALLATION:
+
+    1. Surf to https://www.openssl.org/source/
+    2. Download source AND validate the download was correct (preferably using PGP)
+    3. Untar and uncompress tarball
+    4. You must build using this precise command (do NOT choose any other options):
+
+            # ./config && make install
+
+            (you may optionslly pass 'no-asm' to config)
+
+       If the above procedure does not build on your system -- STOP. You are not
+       building on a FIPS supported platform, and therefore will not have a
+       FIPS validated encryption environment. See chapter 3 of the FIPS 2.0
+       User's Guide for the complete list of supported platforms:
+
+            https://openssl.org/docs/fips/UserGuide-2.0.pdf
+
+    5. Download, build & install openssl 1.0.2m (you are permitted to
+       modify this step to suite your preferences):
+
+            # git clone https://github.com/openssl/openssl.git
+            # (cd openssl && \
+                    git checkout OpenSSL_1_0_2m && \
+                    ./config fips && \
+                    make depend && \
+                    make install)
+
+    6. Now build openvpn and tell it where to find you recently installed OpenSSL
+
+            # ./configure --enable-fips-mode \
+                    OPENSSL_CFLAGS=-I/usr/local/ssl/include \
+                    OPENSSL_LIBS="-ldl -L/usr/local/ssl/lib -lssl -lcrypto"
+
+            # make install
+
+    7. You can confirm FIPS mode is available with the command
+
+            # ./openvpn --version | grep 'library version'
+            library versions: OpenSSL 1.0.2m-fips  2 Nov 2017, LZO 2.08
+
+USAGE:
+
+The above adds a new '--enable-fips-mode' command line option to OpenVPN. Add this to your
+invocation statement. If you've successfully configured OpenVPN for FIPS mode, check your
+OpenVPN logs for the statement:
+
+    *** FIPS MODE ENABLE ***
+
+
+*************************************************************************
+
 CAVEATS & BUGS:
 
 * I have noticed cases where TCP sessions tunneled over the Linux
diff --git a/Makefile.am b/Makefile.am
index 773b786..6d571ec 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -83,6 +83,11 @@  rootdir=$(prefix)
 root_DATA = version.sh
 endif
 
+if FIPSMODE
+export CC
+export FIPSLD_CC
+endif
+
 config-version.h:
 	@CONFIGURE_GIT_CHFILES="`GIT_DIR=\"$(top_srcdir)/.git\" $(GIT) diff-files --name-status -r --ignore-submodules --quiet -- || echo \"+\"`"; \
 	CONFIGURE_GIT_UNCOMMITTED="`GIT_DIR=\"$(top_srcdir)/.git\" $(GIT) diff-index --cached  --quiet --ignore-submodules HEAD || echo \"*\"`"; \
diff --git a/configure.ac b/configure.ac
index b4fd1b3..dc74230 100644
--- a/configure.ac
+++ b/configure.ac
@@ -286,6 +286,17 @@  AC_ARG_WITH(
 	[with_crypto_library="openssl"]
 )
 
+AC_ARG_ENABLE(
+    [fips-mode],
+    [AS_HELP_STRING([--enable-fips-mode], [OpenSSL FIPS Object Module 2.0 @<:@default=no@:>@])],
+    [
+        if test "${with_crypto_library}" != "openssl"; then
+            AC_MSG_ERROR([enable_fips_mode requires --with_crypto_library=openssl])
+        fi
+    ],
+    [enable_fips_mode="no"]
+)
+
 AC_ARG_VAR([PLUGINDIR], [Path of plug-in directory @<:@default=LIBDIR/openvpn/plugins@:>@])
 if test -n "${PLUGINDIR}"; then
 	plugindir="${PLUGINDIR}"
@@ -948,6 +959,35 @@  if test "${with_crypto_library}" = "openssl"; then
 		]
 	)
 
+    if test "${enable_fips_mode}" = "yes"; then
+        AC_CHECK_FUNCS(
+            [ \
+                FIPS_mode \
+                FIPS_mode_set \
+                SSLeay_version
+            ],
+            [],
+            [AC_MSG_ERROR([Incorrect version of OpenSSL, require 1.0.2])]
+            )
+        AC_RUN_IFELSE(
+            [AC_LANG_PROGRAM(
+                [[#include <openssl/crypto.h>]],
+                [[printf("%s\n", SSLeay_version(SSLEAY_DIR));]])
+            ],
+            [AC_SUBST(OPENSSLDIR,
+                [[`./conftest$EXEEXT | $SED -n 's/.*"\(.*\)".*/\1/p'`]])
+            ]
+        )
+        if ! test -x "${OPENSSLDIR}/fips-2.0/bin/fipsld"; then
+            AC_MSG_ERROR([Incomplete OpenSSL FIPS installation; missing fipsld])
+        fi
+        AC_SUBST([FIPSLD_CC], ["${CC}"])
+        AC_SUBST([CC], ["${OPENSSLDIR}/fips-2.0/bin/fipsld"])
+        export CC
+        export FIPSLD_CC
+        AC_DEFINE([ENABLE_FIPS], [1], [Enable OpenSSL FIPS 2.0 Options])
+    fi
+
 	CFLAGS="${saved_CFLAGS}"
 	LIBS="${saved_LIBS}"
 
@@ -1359,6 +1399,7 @@  AM_CONDITIONAL([GIT_CHECKOUT], [test "${GIT_CHECKOUT}" = "yes"])
 AM_CONDITIONAL([ENABLE_PLUGIN_AUTH_PAM], [test "${enable_plugin_auth_pam}" = "yes"])
 AM_CONDITIONAL([ENABLE_PLUGIN_DOWN_ROOT], [test "${enable_plugin_down_root}" = "yes"])
 AM_CONDITIONAL([HAVE_LD_WRAP_SUPPORT], [test "${have_ld_wrap_support}" = "yes"])
+AM_CONDITIONAL([FIPSMODE], [test "${enable_fips_mode}" = "yes"])
 
 sampledir="\$(docdir)/sample"
 AC_SUBST([plugindir])
diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
index 3096f3b..97d117b 100644
--- a/src/openvpn/crypto.c
+++ b/src/openvpn/crypto.c
@@ -852,7 +852,7 @@  init_key_ctx(struct key_ctx *ctx, const struct key *key,
     if (kt->digest && kt->hmac_length > 0)
     {
         ctx->hmac = hmac_ctx_new();
-        hmac_ctx_init(ctx->hmac, key->hmac, kt->hmac_length, kt->digest);
+        hmac_ctx_init(ctx->hmac, key->hmac, kt->hmac_length, kt->digest, false);
 
         msg(D_HANDSHAKE,
             "%s: Using %d bit message hash '%s' for HMAC authentication",
diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h
index 567fd9b..8790ca5 100644
--- a/src/openvpn/crypto_backend.h
+++ b/src/openvpn/crypto_backend.h
@@ -604,10 +604,11 @@  void hmac_ctx_free(hmac_ctx_t *ctx);
  * @param key           The key to use for the HMAC
  * @param key_len       The key length to use
  * @param kt            Static message digest parameters
+ * @param prf_use       Intended use for PRF in TLS protocol
  *
  */
 void hmac_ctx_init(hmac_ctx_t *ctx, const uint8_t *key, int key_length,
-                   const md_kt_t *kt);
+                   const md_kt_t *kt, bool prf_use);
 
 /*
  * Free the given HMAC context.
diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c
index 20a519e..fe4cef3 100644
--- a/src/openvpn/crypto_openssl.c
+++ b/src/openvpn/crypto_openssl.c
@@ -159,6 +159,18 @@  crypto_init_lib(void)
 #endif
 }
 
+int
+crypto_enable_fips_mode(int mode)
+{
+    if (!FIPS_mode_set(mode))
+    {
+        ERR_print_errors_fp(stderr);
+        return 1;
+    }
+    msg(M_INFO, "*** FIPS MODE ENABLED ***");
+    return 0;
+}
+
 void
 crypto_uninit_lib(void)
 {
@@ -926,11 +938,13 @@  hmac_ctx_free(HMAC_CTX *ctx)
 
 void
 hmac_ctx_init(HMAC_CTX *ctx, const uint8_t *key, int key_len,
-              const EVP_MD *kt)
+              const EVP_MD *kt, bool prf_use)
 {
     ASSERT(NULL != kt && NULL != ctx);
 
     HMAC_CTX_reset(ctx);
+    if (kt == EVP_md5() && prf_use)
+        HMAC_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
     HMAC_Init_ex(ctx, key, key_len, kt, NULL);
 
     /* make sure we used a big enough key */
diff --git a/src/openvpn/crypto_openssl.h b/src/openvpn/crypto_openssl.h
index 60a2812..fbc8b2a 100644
--- a/src/openvpn/crypto_openssl.h
+++ b/src/openvpn/crypto_openssl.h
@@ -102,4 +102,12 @@  void crypto_print_openssl_errors(const unsigned int flags);
     } while (false)
 
 
+/**
+ * Enable FIPS Mode. Returns non-zero to indicate an error.
+ *
+ * @param mode         Should be 1. Future versions of OpenSSL FIPS
+ *                     code are expected to accept extended modes.
+ */
+int crypto_enable_fips_mode(int mode);
+
 #endif /* CRYPTO_OPENSSL_H_ */
diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c
index 077fa3e..fe39ab1 100644
--- a/src/openvpn/ntlm.c
+++ b/src/openvpn/ntlm.c
@@ -88,7 +88,7 @@  gen_hmac_md5(const uint8_t *data, int data_len, const uint8_t *key, int key_len,
     const md_kt_t *md5_kt = md_kt_get("MD5");
     hmac_ctx_t *hmac_ctx = hmac_ctx_new();
 
-    hmac_ctx_init(hmac_ctx, key, key_len, md5_kt);
+    hmac_ctx_init(hmac_ctx, key, key_len, md5_kt, false);
     hmac_ctx_update(hmac_ctx, data, data_len);
     hmac_ctx_final(hmac_ctx, result);
     hmac_ctx_cleanup(hmac_ctx);
diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c
index e237ee5..da8e852 100644
--- a/src/openvpn/openvpn.c
+++ b/src/openvpn/openvpn.c
@@ -210,6 +210,15 @@  openvpn_main(int argc, char *argv[])
             /* parse command line options, and read configuration file */
             parse_argv(&c.options, argc, argv, M_USAGE, OPT_P_DEFAULT, NULL, c.es);
 
+#if ENABLE_FIPS
+            if (c.options.fips_mode)
+            {
+                if (enable_fips_mode(c.options.fips_mode))
+                {
+                    break;
+                }
+            }
+#endif
 #ifdef ENABLE_PLUGIN
             /* plugins may contribute options configuration */
             init_verb_mute(&c, IVM_LEVEL_1);
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 7be5f38..99d3ccc 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -517,6 +517,11 @@  static const char usage_message[] =
     "\n"
     "Data Channel Encryption Options (must be compatible between peers):\n"
     "(These options are meaningful for both Static Key & TLS-mode)\n"
+#ifdef ENABLE_FIPS
+	"--enable-fips-mode : Enable OpenSSL FIPS Object Module v2.0.\n"
+	"                  Setting this on the server will enforce FIPS validated\n"
+	"                  encryption on both client and server.\n"
+#endif
     "--secret f [d]  : Enable Static Key encryption mode (non-TLS).\n"
     "                  Use shared secret file f, generate with --genkey.\n"
     "                  The optional d parameter controls key directionality.\n"
@@ -847,6 +852,9 @@  init_options(struct options *o, const bool init_gc)
     o->scheduled_exit_interval = 5;
 #endif
     o->ciphername = "BF-CBC";
+#ifdef ENABLE_FIPS
+	o->fips_mode = 0;
+#endif
 #ifdef HAVE_AEAD_CIPHER_MODES /* IV_NCP=2 requires GCM support */
     o->ncp_enabled = true;
 #else
@@ -1550,6 +1558,9 @@  show_settings(const struct options *o)
     SHOW_INT(persist_mode);
 #endif
 
+#ifdef ENABLE_FIPS
+    SHOW_INT(fips_mode);
+#endif
     SHOW_BOOL(show_ciphers);
     SHOW_BOOL(show_digests);
     SHOW_BOOL(show_engines);
@@ -7389,6 +7400,13 @@  add_option(struct options *options,
         }
     }
 #endif /* USE_COMP */
+#ifdef ENABLE_FIPS
+    else if (streq(p[0], "enable-fips-mode") && !p[1])
+    {
+        VERIFY_PERMISSION(OPT_P_GENERAL);
+        options->fips_mode = 1;
+    }
+#endif
     else if (streq(p[0], "show-ciphers") && !p[1])
     {
         VERIFY_PERMISSION(OPT_P_GENERAL);
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index f70760c..6ffe646 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -186,6 +186,9 @@  struct options
     bool persist_config;
     int persist_mode;
 
+#ifdef ENABLE_FIPS
+	int fips_mode;
+#endif
     const char *key_pass_file;
     bool show_ciphers;
     bool show_digests;
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index 7b42845..3992f4d 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -352,6 +352,14 @@  init_ssl_lib(void)
     crypto_init_lib();
 }
 
+#if ENABLE_FIPS
+int
+enable_fips_mode(int mode)
+{
+	return crypto_enable_fips_mode(mode);
+}
+#endif
+
 void
 free_ssl_lib(void)
 {
@@ -1638,8 +1646,8 @@  tls1_P_hash(const md_kt_t *md_kt,
     chunk = md_kt_size(md_kt);
     A1_len = md_kt_size(md_kt);
 
-    hmac_ctx_init(ctx, sec, sec_len, md_kt);
-    hmac_ctx_init(ctx_tmp, sec, sec_len, md_kt);
+    hmac_ctx_init(ctx, sec, sec_len, md_kt, true);
+    hmac_ctx_init(ctx_tmp, sec, sec_len, md_kt, true);
 
     hmac_ctx_update(ctx,seed,seed_len);
     hmac_ctx_final(ctx, A1);
diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h
index dd1ab0f..f251765 100644
--- a/src/openvpn/ssl.h
+++ b/src/openvpn/ssl.h
@@ -598,4 +598,8 @@  bool is_hard_reset(int op, int key_method);
 
 void delayed_auth_pass_purge(void);
 
+#if ENABLE_FIPS
+int enable_fips_mode(int mode);
+#endif
+
 #endif /* ifndef OPENVPN_SSL_H */
-- 
2.1.4


From 85a23fd158f36c444e59ff41c35d0750917898b1 Mon Sep 17 00:00:00 2001
From: Jim Carroll <jim@carroll.com>
Date: Mon, 4 Dec 2017 16:12:42 -0500
Subject: [PATCH 2/2] fixed typo

Signed-off-by: Jim Carroll <jim@carroll.com>
---
 INSTALL | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/INSTALL b/INSTALL
index b001cb1..0bb25b4 100644
--- a/INSTALL
+++ b/INSTALL
@@ -327,7 +327,7 @@  These instructions describe the use of OpenSSL 1.0.2m.
 
 PRE-INSTALLATION CHECKUP:
 
-    The INSTALLATION procecure describes how to install an OpenSSL library that
+    The INSTALLATION procedure describes how to install an OpenSSL library that
     is built with FIPS support. If your platform already provides a FIPS
     enabled library you can skip to step 6 (build OpenVPN).