\r
Note this branch includes apr and apr-util, while the authors figure out what\r
to do about apr MD5 and other fips issues are resolved. That work will be\r
-submitted to the apr project, once the least distruptive change is ascertained.\r
+submitted to the apr project, once the least distruptive change is\r
+ascertained.\r
+\r
+Note also that even with FIPS mode is off, operations using MD5 are\r
+not possible.\r
\r
Stuff FIPS requires\r
-------------------\r
code).\r
\r
Certificates: must be signed using SHA-1.\r
+\r
+Passwords: must be SHA-1 hashed.\r
# The build environment was provided by Sascha Schumann.
PROGRAM_OBJECTS = $(PROGRAM_SOURCES:.c=.lo)
+TOP=/home/ben/work/openssl-0.9.7
+
+# XXX: I don't know how to work out the correct path for the real executable
+TO_FINGERPRINT = $(PROGRAM_NAME:httpd=.libs/lt-httpd)
+FINGERPRINT = $(TO_FINGERPRINT).sha1
$(PROGRAM_NAME): $(PROGRAM_DEPENDENCIES) $(PROGRAM_OBJECTS)
$(PROGRAM_PRELINK)
$(LINK) $(PROGRAM_LDFLAGS) $(PROGRAM_OBJECTS) $(PROGRAM_LDADD)
+# blearg - force libtool to do its stupid magic
+ -./$(PROGRAM_NAME) --help
+ TOP=$(TOP) $(TOP)/fips/openssl_fips_fingerprint $(TOP)/libcrypto.a $(TO_FINGERPRINT) > $(FINGERPRINT)
sinclude(build/find_apu.m4)
sinclude(acinclude.m4)
+dnl Allow FIPS mode
+AC_ARG_ENABLE(fips,[Enable FIPS mode (i.e. disable or replace all crypto)],
+ [AC_DEFINE([AP_FIPS],1,[Set to 1 if FIPS mode is enabled])])
+
dnl XXX we can't just use AC_PREFIX_DEFAULT because that isn't subbed in
dnl by configure until it is too late. Is that how it should be or not?
dnl Something seems broken here.
esac
if test "$apu_found" = "reconfig"; then
+ if test "${enable_fips+set}" = set; then
+ fips_option="--enable-fips"
+ fi
APR_SUBDIR_CONFIG(srclib/apr-util,
- [--with-apr=../apr --prefix=$prefix --exec-prefix=$exec_prefix --libdir=$libdir --includedir=$includedir --bindir=$bindir],
+ [--with-apr=../apr --prefix=$prefix --exec-prefix=$exec_prefix --libdir=$libdir --includedir=$includedir --bindir=$bindir $fips_option],
[--enable-layout=*|\'--enable-layout=*])
dnl We must be the last to build and the first to be cleaned
AP_BUILD_SRCLIB_DIRS="$AP_BUILD_SRCLIB_DIRS apr-util"
/** The name of the Apache executable */
AP_DECLARE_DATA extern const char *ap_server_argv0;
+AP_DECLARE_DATA extern const char *ap_server_full_argv0;
/** The global server's ServerRoot */
AP_DECLARE_DATA extern const char *ap_server_root;
*/
#include "apr_md5.h"
+#include "ap_config_auto.h"
+#ifdef AP_FIPS
+/**
+ * Create a SHA-1 checksum of a string of binary data
+ * @param a Pool to allocate out of
+ * @param buf Buffer to generate checksum for
+ * @param len The length of the buffer
+ * @return The checksum in hex
+ * @deffunc char *ap_md5_binary(apr_pool_t *a, const unsigned char *buf, int len)
+ */
+AP_DECLARE(char *) ap_sha1_binary(apr_pool_t *a, const unsigned char *buf, int len);
+
+#else
/**
* Create an MD5 checksum of a given string
* @param a Pool to allocate out of
*/
AP_DECLARE(char *) ap_md5digest(apr_pool_t *p, apr_file_t *infile);
+#endif /*ndef AP_FIPS */
+
#ifdef __cplusplus
}
#endif
SSL_CMD_SRV(Engine, TAKE1,
"SSL switch for the protocol engine "
"(`on', `off')")
+#ifdef AP_FIPS
SSL_CMD_SRV(FIPS, TAKE1,
"Enable FIPS-140 compliance "
"(`on', `off')")
+#endif
SSL_CMD_ALL(CipherSuite, TAKE1,
"Colon-delimited list of permitted SSL Ciphers "
"(`XXX:...:XXX' - see manual)")
SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
SSL *ssl;
SSLConnRec *sslconn = myConnConfig(c);
- char *vhost_md5;
+ char *vhost_digest;
modssl_ctx_t *mctx;
/*
return DECLINED; /* XXX */
}
- vhost_md5 = ap_md5_binary(c->pool, (unsigned char *)sc->vhost_id,
- sc->vhost_id_len);
-
- if (!SSL_set_session_id_context(ssl, (unsigned char *)vhost_md5,
+#ifdef AP_FIPS
+ vhost_digest = ap_sha1_binary(c->pool, (unsigned char *)sc->vhost_id,
+ sc->vhost_id_len);
+#else
+ vhost_digest = ap_md5_binary(c->pool, (unsigned char *)sc->vhost_id,
+ sc->vhost_id_len);
+#endif
+
+/* Using only 32 bytes is deliberate */
+ if (!SSL_set_session_id_context(ssl, (unsigned char *)vhost_digest,
APR_MD5_DIGESTSIZE*2))
{
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
- "Unable to set session id context to `%s'", vhost_md5);
+ "Unable to set session id context to `%s'", vhost_digest);
ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, c->base_server);
c->aborted = 1;
cfgMerge(mc, NULL);
cfgMerge(enabled, SSL_ENABLED_UNSET);
+#ifdef AP_FIPS
cfgMerge(fips, SSL_FIPS_UNSET); // FIPS-XXX: make more than one setting an error?
+#endif
cfgMergeBool(proxy_enabled);
cfgMergeInt(session_cache_timeout);
cfgMergeBool(cipher_server_pref);
return "Argument must be On, Off, or Optional";
}
+
+#ifdef AP_FIPS
// FIPS-XXX: this is global, i.e. can only be set once, not per-server.
const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, const char *arg)
{
return "Argument must be On or Off";
}
+#endif
const char *ssl_cmd_SSLCipherSuite(cmd_parms *cmd,
void *dcfg,
MODSSL_TMP_KEY_FREE(mc, type, SSL_TMP_KEY_##type##_512); \
MODSSL_TMP_KEY_FREE(mc, type, SSL_TMP_KEY_##type##_1024)
+#if AP_FIPS
/* FIPS-140 prevents automatic rekeying in child processes, so we have
* to do it */
-
static void fips_rand_reseed(server_rec *s, apr_pool_t *ptemp)
{
static int rand_seeded;
rand_seeded=1;
}
}
+#endif
static void ssl_tmp_keys_free(server_rec *s)
{
sc->enabled = SSL_ENABLED_FALSE;
}
+#ifdef AP_FIPS
if(sc->fips == SSL_FIPS_UNSET)
sc->enabled = SSL_FIPS_FALSE;
+#endif
if (sc->proxy_enabled == UNSET) {
sc->proxy_enabled = FALSE;
*/
ssl_rand_seed(base_server, ptemp, SSL_RSCTX_STARTUP, "Init: ");
+#ifdef AP_FIPS
/* Do this after randomness has been seeded */
// XXX: also need to set FIPS mode for APR (i.e. exclude all crypto/randomness from APR)
if(!fips_done) {
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, "FIPS mode disabled");
fips_done=1;
}
+#endif
/*
* read server private keys/public certs into memory.
/* open the mutex lockfile */
ssl_mutex_reinit(s, p);
-
+#ifdef AP_FIPS
fips_rand_reseed(s, p);
+#endif
}
#define MODSSL_CFG_ITEM_FREE(func, item) \
#include "ssl_private.h"
+#ifdef AP_FIPS
+# include <openssl/fips_rand.h>
+#endif
+
/* _________________________________________________________________
**
** Support for better seeding of SSL library's RNG
*/
static int ssl_rand_choosenum(int, int);
+
+#ifdef AP_FIPS
static int ssl_rand_feedfp(int, apr_pool_t *, apr_file_t *, int);
/* Deal with the arcanity of the FIPS PRNG, which requires keying
}
RAND_seed(buf, num);
}
+#else
+
+static int ssl_rand_feedfp(apr_pool_t *, apr_file_t *, int);
+
+# define inject_rand(fips, buf, num) RAND_seed(buf, num)
+
+#endif
int ssl_rand_seed(server_rec *s, apr_pool_t *p, ssl_rsctx_t nCtx, char *prefix)
{
if (apr_file_open(&fp, pRandSeed->cpPath,
APR_READ, APR_OS_DEFAULT, p) != APR_SUCCESS)
continue;
+#ifdef AP_FIPS
nDone += ssl_rand_feedfp(sc->fips == SSL_FIPS_TRUE, p, fp,
pRandSeed->nBytes);
+#else
+ nDone += ssl_rand_feedfp(p, fp, pRandSeed->nBytes);
+#endif
apr_file_close(fp);
}
else if (pRandSeed->nSrc == SSL_RSSRC_EXEC) {
if ((fp = ssl_util_ppopen(s, p, cmd, argv)) == NULL)
continue;
+#ifdef AP_FIPS
nDone += ssl_rand_feedfp(sc->fips == SSL_FIPS_TRUE, p, fp,
pRandSeed->nBytes);
+#else
+ nDone += ssl_rand_feedfp(p, fp, pRandSeed->nBytes);
+#endif
ssl_util_ppclose(s, p, fp);
}
#ifdef HAVE_SSL_RAND_EGD
#define BUFSIZE 8192
+#ifdef AP_FIPS
static int ssl_rand_feedfp(int fips, apr_pool_t *p, apr_file_t *fp, int nReq)
+#else
+static int ssl_rand_feedfp(apr_pool_t *p, apr_file_t *fp, int nReq)
+#endif
{
apr_size_t nDone;
unsigned char caBuf[BUFSIZE];
SSL_ENABLED_OPTIONAL = 3
} ssl_enabled_t;
+#ifdef AP_FIPS
typedef enum {
SSL_FIPS_UNSET = UNSET,
SSL_FIPS_FALSE = 0,
SSL_FIPS_TRUE = 1
} fips_enabled_t;
+#endif
/*
* Define the SSL requirement structure
struct SSLSrvConfigRec {
SSLModConfigRec *mc;
ssl_enabled_t enabled;
+#ifdef AP_FIPS
fips_enabled_t fips;
+#endif
BOOL proxy_enabled;
const char *vhost_id;
int vhost_id_len;
rm -f $$tmp
exports.c: export_files
- $(AWK) -f $(top_srcdir)/build/make_exports.awk `cat $?` > $@
+ $(AWK) -f $(top_srcdir)/build/make_exports.awk `cat $?` | $(top_srcdir)/build/fipsify_exports $(top_srcdir)/include/ap_config_auto.h > $@
export_vars.h: export_files
$(AWK) -f $(top_srcdir)/build/make_var_export.awk `cat $?` > $@
}
else {
if (bld_content_md5) {
+#ifndef AP_NO_FIPS
+ // FIPS-XXX: is it safe to continue despite this?
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Can't do Content-MD5 in FIPS mode");
+#else
apr_table_setn(r->headers_out, "Content-MD5",
ap_md5digest(r->pool, fd));
+#endif
}
/* For platforms where the size of the file may be larger than
#include "util_md5.h"
#include "util_ebcdic.h"
+#ifdef AP_FIPS
+#include <openssl/sha.h>
+
+AP_DECLARE(char *) ap_sha1_binary(apr_pool_t *p, const unsigned char *buf, int length)
+{
+ const char *hex = "0123456789abcdef";
+ SHA_CTX my_sha1;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+ char *r, result[SHA_DIGEST_LENGTH*2+1];
+ int i;
+
+ /*
+ * Take the SHA-1 hash of the string argument.
+ */
+
+ SHA1_Init(&my_sha1);
+#if APR_CHARSET_EBCDIC
+# error no EBCDIC support
+#endif
+ SHA1_Update(&my_sha1, buf, (unsigned int)length);
+ SHA1_Final(hash, &my_sha1);
+
+ for (i = 0, r = result; i < APR_MD5_DIGESTSIZE; i++) {
+ *r++ = hex[hash[i] >> 4];
+ *r++ = hex[hash[i] & 0xF];
+ }
+ *r = '\0';
+
+ return apr_pstrndup(p, result, SHA_DIGEST_LENGTH*2);
+}
+
+#else
AP_DECLARE(char *) ap_md5_binary(apr_pool_t *p, const unsigned char *buf, int length)
{
const char *hex = "0123456789abcdef";
return ap_md5contextTo64(p, &context);
}
+#endif /*ndef AP_FIPS */
sinclude(build/dbm.m4)
sinclude(build/dbd.m4)
+dnl Allow FIPS mode
+AC_ARG_ENABLE(fips,[Enable FIPS mode (i.e. disable or replace all crypto)],
+ [AC_DEFINE([APU_FIPS],1,[Set to 1 if FIPS mode is enabled])])
+
dnl Generate ./config.nice for reproducing runs of configure
dnl
APR_CONFIG_NICE(config.nice)
#include "apr_strings.h"
#include "apr_md4.h"
#include "apr_lib.h"
+#include "apu_config.h"
#if APR_HAVE_STRING_H
#include <string.h>
#include <unistd.h>
#endif
+#ifndef APU_FIPS
/* Constants for MD4Transform routine.
*/
-
+
#define S11 3
#define S12 7
#define S13 11
return APR_SUCCESS;
}
#endif
+
+#endif /*ndef APU_FIPS */
#include <pthread.h>
#endif
+/*
+ * Define the Magic String prefix that identifies a password as being
+ * hashed using our algorithm.
+ */
+static const char *apr1_id = "$apr1$";
+
+#ifndef APU_FIPS
/* Constants for MD5Transform routine.
*/
}
#endif
-/*
- * Define the Magic String prefix that identifies a password as being
- * hashed using our algorithm.
- */
-static const char *apr1_id = "$apr1$";
-
/*
* The following MD5 password encryption code was largely borrowed from
* the FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c file, which is
#endif
#endif
+#endif /* ndef APU_FIPS */
+
/*
* Validate a plaintext password against a smashed one. Uses either
* crypt() (if available) or apr_md5_encode() or apr_sha1_base64(), depending
char *crypt_pw;
#endif
if (!strncmp(hash, apr1_id, strlen(apr1_id))) {
+#ifdef APU_FIPS
+ return APR_EMISMATCH;
+#else
/*
* The hash was created using our custom algorithm.
*/
apr_md5_encode(passwd, hash, sample, sizeof(sample));
+#endif
}
else if (!strncmp(hash, APR_SHA1PW_ID, APR_SHA1PW_IDLEN)) {
apr_sha1_base64(passwd, strlen(passwd), sample);
}
else {
+#ifdef APU_FIPS
+ return APR_EMISMATCH;
+#else
/*
* It's not our algorithm, so feed it to crypt() if possible.
*/
apr_cpystrn(sample, crypt_pw, sizeof(sample) - 1);
crypt_mutex_unlock();
#endif
+#endif /*ndef APU_FIPS */
}
return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
}
#include "apr_base64.h"
#include "apr_strings.h"
#include "apr_lib.h"
+#include "apu_config.h"
#if APR_CHARSET_EBCDIC
#include "apr_xlate.h"
#endif /*APR_CHARSET_EBCDIC*/
#include <string.h>
+#ifndef APU_FIPS
+
/* a bit faster & bigger, if defined */
#define UNROLL_LOOPS
}
}
-
APU_DECLARE(void) apr_sha1_base64(const char *clear, int len, char *out)
{
int l;
* output of base64 encoded SHA1 is always 28 chars + APR_SHA1PW_IDLEN
*/
}
+#else /*def APR_FIPS */
+
+APU_DECLARE(void) apr_sha1_base64(const char *clear, int len, char *out)
+{
+ int l;
+ apr_byte_t digest[APR_SHA1_DIGESTSIZE];
+
+ if (strncmp(clear, APR_SHA1PW_ID, APR_SHA1PW_IDLEN) == 0) {
+ clear += APR_SHA1PW_IDLEN;
+ }
+
+ SHA1(clear, len, digest);
+
+ /* private marker. */
+ apr_cpystrn(out, APR_SHA1PW_ID, APR_SHA1PW_IDLEN + 1);
+
+ /* SHA1 hash is always 20 chars */
+ l = apr_base64_encode_binary(out + APR_SHA1PW_IDLEN, digest, sizeof(digest));
+ out[l + APR_SHA1PW_IDLEN] = '\0';
+
+ /*
+ * output of base64 encoded SHA1 is always 28 chars + APR_SHA1PW_IDLEN
+ */
+}
+
+#endif /*def APR_FIPS */
+
#include "apr_md5.h"
#include "apr_sha1.h"
#include "apr_dbm.h"
+#include "ap_config_auto.h"
#if APR_HAVE_STDLIB_H
#include <stdlib.h>
#define MAX_STRING_LEN 256
#define ALG_PLAIN 0
-#define ALG_APMD5 1
+#ifndef AP_FIPS
+# define ALG_APMD5 1
+#endif
#define ALG_APSHA 2
#if APR_HAVE_CRYPT_H
}
#endif /*APR_CHARSET_EBCDIC*/
+#ifdef AP_FIPS
+ (*hdbm)->alg = ALG_APSHA;
+#else
/* Set MD5 as default */
(*hdbm)->alg = ALG_APMD5;
+#endif
(*hdbm)->type = "default";
return APR_SUCCESS;
}
apr_sha1_base64(htdbm->userpass,strlen(htdbm->userpass),cpw);
break;
+#ifndef AP_FIPS
case ALG_APMD5:
(void) srand((int) time((time_t *) NULL));
to64(&salt[0], rand(), 8);
apr_md5_encode((const char *)htdbm->userpass, (const char *)salt,
cpw, sizeof(cpw));
break;
+#endif
+
case ALG_PLAIN:
/* XXX this len limitation is not in sync with any HTTPd len. */
apr_cpystrn(cpw,htdbm->userpass,sizeof(cpw));
need_pwd = 0;
cmd = HTDBM_DELETE;
break;
+#ifndef AP_FIPS
case 'm':
h->alg = ALG_APMD5;
break;
+#endif
case 'p':
h->alg = ALG_PLAIN;
break;
#include "apr_general.h"
#include "apr_signal.h"
#include "apr_strings.h" /* for apr_pstrdup() */
+#include "ap_config_auto.h"
+
+#ifndef AP_FIPS
#define APR_WANT_STDIO
#define APR_WANT_STRFUNC
return 0;
}
+
+#else /*def AP_FIPS */
+
+int main(int argc, const char * const argv[])
+{
+ fprintf(stderr,"HTTP Digest uses MD5 and so is not available if FIPS mode.\n");
+ exit(1);
+}
+
+#endif
#include "apr_file_io.h"
#include "apr_general.h"
#include "apr_signal.h"
+#include "ap_config_auto.h"
#if APR_HAVE_STDIO_H
#include <stdio.h>
#define MAX_STRING_LEN 256
#define ALG_PLAIN 0
-#define ALG_CRYPT 1
-#define ALG_APMD5 2
+#ifndef AP_FIPS
+# define ALG_CRYPT 1
+# define ALG_APMD5 2
+#endif
#define ALG_APSHA 3
#define ERR_FILEPERM 1
char cpw[120];
char pwin[MAX_STRING_LEN];
char pwv[MAX_STRING_LEN];
+#ifndef AP_FIPS
char salt[9];
+#endif
apr_size_t bufsize;
if (passwd != NULL) {
apr_sha1_base64(pw,strlen(pw),cpw);
break;
+#ifndef AP_FIPS
case ALG_APMD5:
(void) srand((int) time((time_t *) NULL));
to64(&salt[0], rand(), 8);
apr_md5_encode((const char *)pw, (const char *)salt,
cpw, sizeof(cpw));
break;
+#endif
case ALG_PLAIN:
/* XXX this len limitation is not in sync with any HTTPd len. */
apr_cpystrn(cpw,pw,sizeof(cpw));
break;
-#if !(defined(WIN32) || defined(NETWARE))
+#if !(defined(WIN32) || defined(NETWARE)) && !defined(AP_FIPS)
case ALG_CRYPT:
default:
(void) srand((int) time((time_t *) NULL));
*mask |= APHTP_NOFILE;
args_left--;
}
+#ifndef AP_FIPS
else if (*arg == 'm') {
*alg = ALG_APMD5;
}
+ else if (*arg == 'd') {
+ *alg = ALG_CRYPT;
+ }
+#endif
else if (*arg == 's') {
*alg = ALG_APSHA;
}
else if (*arg == 'p') {
*alg = ALG_PLAIN;
}
- else if (*arg == 'd') {
- *alg = ALG_CRYPT;
- }
else if (*arg == 'b') {
*mask |= APHTP_NONINTERACTIVE;
args_left++;
char *scratch, cp[MAX_STRING_LEN];
int found = 0;
int i;
+#ifdef AP_FIPS
+ int alg = ALG_APSHA;
+#else
int alg = ALG_CRYPT;
+#endif
int mask = 0;
apr_pool_t *pool;
int existing_file = 0;