|
Packit |
c4476c |
/* ====================================================================
|
|
Packit |
c4476c |
* Copyright (c) 2003 The OpenSSL Project. All rights reserved.
|
|
Packit |
c4476c |
*
|
|
Packit |
c4476c |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
c4476c |
* modification, are permitted provided that the following conditions
|
|
Packit |
c4476c |
* are met:
|
|
Packit |
c4476c |
*
|
|
Packit |
c4476c |
* 1. Redistributions of source code must retain the above copyright
|
|
Packit |
c4476c |
* notice, this list of conditions and the following disclaimer.
|
|
Packit |
c4476c |
*
|
|
Packit |
c4476c |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
Packit |
c4476c |
* notice, this list of conditions and the following disclaimer in
|
|
Packit |
c4476c |
* the documentation and/or other materials provided with the
|
|
Packit |
c4476c |
* distribution.
|
|
Packit |
c4476c |
*
|
|
Packit |
c4476c |
* 3. All advertising materials mentioning features or use of this
|
|
Packit |
c4476c |
* software must display the following acknowledgment:
|
|
Packit |
c4476c |
* "This product includes software developed by the OpenSSL Project
|
|
Packit |
c4476c |
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
|
Packit |
c4476c |
*
|
|
Packit |
c4476c |
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
|
Packit |
c4476c |
* endorse or promote products derived from this software without
|
|
Packit |
c4476c |
* prior written permission. For written permission, please contact
|
|
Packit |
c4476c |
* openssl-core@openssl.org.
|
|
Packit |
c4476c |
*
|
|
Packit |
c4476c |
* 5. Products derived from this software may not be called "OpenSSL"
|
|
Packit |
c4476c |
* nor may "OpenSSL" appear in their names without prior written
|
|
Packit |
c4476c |
* permission of the OpenSSL Project.
|
|
Packit |
c4476c |
*
|
|
Packit |
c4476c |
* 6. Redistributions of any form whatsoever must retain the following
|
|
Packit |
c4476c |
* acknowledgment:
|
|
Packit |
c4476c |
* "This product includes software developed by the OpenSSL Project
|
|
Packit |
c4476c |
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
|
Packit |
c4476c |
*
|
|
Packit |
c4476c |
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
|
Packit |
c4476c |
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
c4476c |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
Packit |
c4476c |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
|
Packit |
c4476c |
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
Packit |
c4476c |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
Packit |
c4476c |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
Packit |
c4476c |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
Packit |
c4476c |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
Packit |
c4476c |
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
Packit |
c4476c |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
Packit |
c4476c |
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
c4476c |
*
|
|
Packit |
c4476c |
*/
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
#define _GNU_SOURCE
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
#include <openssl/rand.h>
|
|
Packit |
c4476c |
#include <openssl/fips_rand.h>
|
|
Packit |
c4476c |
#include <openssl/err.h>
|
|
Packit |
c4476c |
#include <openssl/bio.h>
|
|
Packit |
c4476c |
#include <openssl/hmac.h>
|
|
Packit |
c4476c |
#include <openssl/rsa.h>
|
|
Packit |
c4476c |
#include <string.h>
|
|
Packit |
c4476c |
#include <limits.h>
|
|
Packit |
c4476c |
#include <dlfcn.h>
|
|
Packit |
c4476c |
#include <stdio.h>
|
|
Packit |
c4476c |
#include <stdlib.h>
|
|
Packit |
c4476c |
#include <unistd.h>
|
|
Packit |
c4476c |
#include <errno.h>
|
|
Packit |
c4476c |
#include "fips_locl.h"
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
#ifdef OPENSSL_FIPS
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
# include <openssl/fips.h>
|
|
Packit |
c4476c |
# include "internal/thread_once.h"
|
|
Packit |
c4476c |
# include "crypto/rand.h"
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
# ifndef PATH_MAX
|
|
Packit |
c4476c |
# define PATH_MAX 1024
|
|
Packit |
c4476c |
# endif
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
static int fips_selftest_fail = 0;
|
|
Packit |
c4476c |
static int fips_mode = 0;
|
|
Packit |
c4476c |
static int fips_started = 0;
|
|
Packit |
c4476c |
static int fips_post = 0;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
static int fips_is_owning_thread(void);
|
|
Packit |
c4476c |
static int fips_set_owning_thread(void);
|
|
Packit |
c4476c |
static int fips_clear_owning_thread(void);
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
static CRYPTO_RWLOCK *fips_lock = NULL;
|
|
Packit |
c4476c |
static CRYPTO_RWLOCK *fips_owning_lock = NULL;
|
|
Packit |
c4476c |
static CRYPTO_ONCE fips_lock_init = CRYPTO_ONCE_STATIC_INIT;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
DEFINE_RUN_ONCE_STATIC(do_fips_lock_init)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
fips_lock = CRYPTO_THREAD_lock_new();
|
|
Packit |
c4476c |
fips_owning_lock = CRYPTO_THREAD_lock_new();
|
|
Packit |
c4476c |
return fips_lock != NULL && fips_owning_lock != NULL;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
# define fips_w_lock() CRYPTO_THREAD_write_lock(fips_lock)
|
|
Packit |
c4476c |
# define fips_w_unlock() CRYPTO_THREAD_unlock(fips_lock)
|
|
Packit |
c4476c |
# define fips_r_lock() CRYPTO_THREAD_read_lock(fips_lock)
|
|
Packit |
c4476c |
# define fips_r_unlock() CRYPTO_THREAD_unlock(fips_lock)
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
static void fips_set_mode(int onoff)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
int owning_thread = fips_is_owning_thread();
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (fips_started) {
|
|
Packit |
c4476c |
if (!owning_thread)
|
|
Packit |
c4476c |
fips_w_lock();
|
|
Packit |
c4476c |
fips_mode = onoff;
|
|
Packit |
c4476c |
if (!owning_thread)
|
|
Packit |
c4476c |
fips_w_unlock();
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
int FIPS_module_mode(void)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
int ret = 0;
|
|
Packit |
c4476c |
int owning_thread = fips_is_owning_thread();
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (fips_started) {
|
|
Packit |
c4476c |
if (!owning_thread)
|
|
Packit |
c4476c |
fips_r_lock();
|
|
Packit |
c4476c |
ret = fips_mode;
|
|
Packit |
c4476c |
if (!owning_thread)
|
|
Packit |
c4476c |
fips_r_unlock();
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
return ret;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
/* just a compat symbol - return NULL */
|
|
Packit |
c4476c |
int FIPS_selftest_failed(void)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
int ret = 0;
|
|
Packit |
c4476c |
if (fips_started) {
|
|
Packit |
c4476c |
int owning_thread = fips_is_owning_thread();
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (!owning_thread)
|
|
Packit |
c4476c |
fips_r_lock();
|
|
Packit |
c4476c |
ret = fips_selftest_fail;
|
|
Packit |
c4476c |
if (!owning_thread)
|
|
Packit |
c4476c |
fips_r_unlock();
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
return ret;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
/* Selftest failure fatal exit routine. This will be called
|
|
Packit |
c4476c |
* during *any* cryptographic operation. It has the minimum
|
|
Packit |
c4476c |
* overhead possible to avoid too big a performance hit.
|
|
Packit |
c4476c |
*/
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
void FIPS_selftest_check(void)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
if (fips_selftest_fail) {
|
|
Packit |
c4476c |
OpenSSLDie(__FILE__, __LINE__, "FATAL FIPS SELFTEST FAILURE");
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
void fips_set_selftest_fail(void)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
fips_selftest_fail = 1;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
int fips_in_post(void)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
return fips_post;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
/* we implement what libfipscheck does ourselves */
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
static int
|
|
Packit |
c4476c |
get_library_path(const char *libname, const char *symbolname, char *path,
|
|
Packit |
c4476c |
size_t pathlen)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
Dl_info info;
|
|
Packit |
c4476c |
void *dl, *sym;
|
|
Packit |
c4476c |
int rv = -1;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
dl = dlopen(libname, RTLD_LAZY);
|
|
Packit |
c4476c |
if (dl == NULL) {
|
|
Packit |
c4476c |
return -1;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
sym = dlsym(dl, symbolname);
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (sym != NULL && dladdr(sym, &info)) {
|
|
Packit |
c4476c |
strncpy(path, info.dli_fname, pathlen - 1);
|
|
Packit |
c4476c |
path[pathlen - 1] = '\0';
|
|
Packit |
c4476c |
rv = 0;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
dlclose(dl);
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
return rv;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
static const char conv[] = "0123456789abcdef";
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
static char *bin2hex(void *buf, size_t len)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
char *hex, *p;
|
|
Packit |
c4476c |
unsigned char *src = buf;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
hex = malloc(len * 2 + 1);
|
|
Packit |
c4476c |
if (hex == NULL)
|
|
Packit |
c4476c |
return NULL;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
p = hex;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
while (len > 0) {
|
|
Packit |
c4476c |
unsigned c;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
c = *src;
|
|
Packit |
c4476c |
src++;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
*p = conv[c >> 4];
|
|
Packit |
c4476c |
++p;
|
|
Packit |
c4476c |
*p = conv[c & 0x0f];
|
|
Packit |
c4476c |
++p;
|
|
Packit |
c4476c |
--len;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
*p = '\0';
|
|
Packit |
c4476c |
return hex;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
# define HMAC_PREFIX "."
|
|
Packit |
c4476c |
# ifndef HMAC_SUFFIX
|
|
Packit |
c4476c |
# define HMAC_SUFFIX ".hmac"
|
|
Packit |
c4476c |
# endif
|
|
Packit |
c4476c |
# define READ_BUFFER_LENGTH 16384
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
static char *make_hmac_path(const char *origpath)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
char *path, *p;
|
|
Packit |
c4476c |
const char *fn;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
path =
|
|
Packit |
c4476c |
malloc(sizeof(HMAC_PREFIX) + sizeof(HMAC_SUFFIX) + strlen(origpath));
|
|
Packit |
c4476c |
if (path == NULL) {
|
|
Packit |
c4476c |
return NULL;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
fn = strrchr(origpath, '/');
|
|
Packit |
c4476c |
if (fn == NULL) {
|
|
Packit |
c4476c |
fn = origpath;
|
|
Packit |
c4476c |
} else {
|
|
Packit |
c4476c |
++fn;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
strncpy(path, origpath, fn - origpath);
|
|
Packit |
c4476c |
p = path + (fn - origpath);
|
|
Packit |
c4476c |
p = stpcpy(p, HMAC_PREFIX);
|
|
Packit |
c4476c |
p = stpcpy(p, fn);
|
|
Packit |
c4476c |
p = stpcpy(p, HMAC_SUFFIX);
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
return path;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
static const char hmackey[] = "orboDeJITITejsirpADONivirpUkvarP";
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
static int compute_file_hmac(const char *path, void **buf, size_t *hmaclen)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
FILE *f = NULL;
|
|
Packit |
c4476c |
int rv = -1;
|
|
Packit |
c4476c |
unsigned char rbuf[READ_BUFFER_LENGTH];
|
|
Packit |
c4476c |
size_t len;
|
|
Packit |
c4476c |
unsigned int hlen;
|
|
Packit |
c4476c |
HMAC_CTX *c;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
c = HMAC_CTX_new();
|
|
Packit |
c4476c |
if (c == NULL)
|
|
Packit |
c4476c |
return rv;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
f = fopen(path, "r");
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (f == NULL) {
|
|
Packit |
c4476c |
goto end;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (HMAC_Init_ex(c, hmackey, sizeof(hmackey) - 1, EVP_sha256(), NULL) <= 0) {
|
|
Packit |
c4476c |
goto end;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
while ((len = fread(rbuf, 1, sizeof(rbuf), f)) != 0) {
|
|
Packit |
c4476c |
if (HMAC_Update(c, rbuf, len) <= 0) {
|
|
Packit |
c4476c |
goto end;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
len = sizeof(rbuf);
|
|
Packit |
c4476c |
/* reuse rbuf for hmac */
|
|
Packit |
c4476c |
if (HMAC_Final(c, rbuf, &hlen) <= 0) {
|
|
Packit |
c4476c |
goto end;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
*buf = malloc(hlen);
|
|
Packit |
c4476c |
if (*buf == NULL) {
|
|
Packit |
c4476c |
goto end;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
*hmaclen = hlen;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
memcpy(*buf, rbuf, hlen);
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
rv = 0;
|
|
Packit |
c4476c |
end:
|
|
Packit |
c4476c |
HMAC_CTX_free(c);
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (f)
|
|
Packit |
c4476c |
fclose(f);
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
return rv;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
static int FIPSCHECK_verify(const char *path)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
int rv = 0;
|
|
Packit |
c4476c |
FILE *hf;
|
|
Packit |
c4476c |
char *hmacpath, *p;
|
|
Packit |
c4476c |
char *hmac = NULL;
|
|
Packit |
c4476c |
size_t n;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
hmacpath = make_hmac_path(path);
|
|
Packit |
c4476c |
if (hmacpath == NULL)
|
|
Packit |
c4476c |
return 0;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
hf = fopen(hmacpath, "r");
|
|
Packit |
c4476c |
if (hf == NULL) {
|
|
Packit |
c4476c |
free(hmacpath);
|
|
Packit |
c4476c |
return 0;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (getline(&hmac, &n, hf) > 0) {
|
|
Packit |
c4476c |
void *buf;
|
|
Packit |
c4476c |
size_t hmaclen;
|
|
Packit |
c4476c |
char *hex;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if ((p = strchr(hmac, '\n')) != NULL)
|
|
Packit |
c4476c |
*p = '\0';
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (compute_file_hmac(path, &buf, &hmaclen) < 0) {
|
|
Packit |
c4476c |
rv = -4;
|
|
Packit |
c4476c |
goto end;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if ((hex = bin2hex(buf, hmaclen)) == NULL) {
|
|
Packit |
c4476c |
free(buf);
|
|
Packit |
c4476c |
rv = -5;
|
|
Packit |
c4476c |
goto end;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (strcmp(hex, hmac) != 0) {
|
|
Packit |
c4476c |
rv = -1;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
free(buf);
|
|
Packit |
c4476c |
free(hex);
|
|
Packit |
c4476c |
} else {
|
|
Packit |
c4476c |
rv = -1;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
end:
|
|
Packit |
c4476c |
free(hmac);
|
|
Packit |
c4476c |
free(hmacpath);
|
|
Packit |
c4476c |
fclose(hf);
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (rv < 0)
|
|
Packit |
c4476c |
return 0;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
/* check successful */
|
|
Packit |
c4476c |
return 1;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
static int verify_checksums(void)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
int rv;
|
|
Packit |
c4476c |
char path[PATH_MAX + 1];
|
|
Packit |
c4476c |
char *p;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
/* we need to avoid dlopening libssl, assume both libcrypto and libssl
|
|
Packit |
c4476c |
are in the same directory */
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
rv = get_library_path("libcrypto.so." SHLIB_VERSION_NUMBER,
|
|
Packit |
c4476c |
"FIPS_mode_set", path, sizeof(path));
|
|
Packit |
c4476c |
if (rv < 0)
|
|
Packit |
c4476c |
return 0;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
rv = FIPSCHECK_verify(path);
|
|
Packit |
c4476c |
if (!rv)
|
|
Packit |
c4476c |
return 0;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
/* replace libcrypto with libssl */
|
|
Packit |
c4476c |
while ((p = strstr(path, "libcrypto.so")) != NULL) {
|
|
Packit |
c4476c |
p = stpcpy(p, "libssl");
|
|
Packit |
c4476c |
memmove(p, p + 3, strlen(p + 2));
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
rv = FIPSCHECK_verify(path);
|
|
Packit |
c4476c |
if (!rv)
|
|
Packit |
c4476c |
return 0;
|
|
Packit |
c4476c |
return 1;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
# ifndef FIPS_MODULE_PATH
|
|
Packit |
c4476c |
# define FIPS_MODULE_PATH "/etc/system-fips"
|
|
Packit |
c4476c |
# endif
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
int FIPS_module_installed(void)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
int rv;
|
|
Packit |
c4476c |
rv = access(FIPS_MODULE_PATH, F_OK);
|
|
Packit |
c4476c |
if (rv < 0 && errno != ENOENT)
|
|
Packit |
c4476c |
rv = 0;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
/* Installed == true */
|
|
Packit |
c4476c |
return !rv || FIPS_module_mode();
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
int FIPS_module_mode_set(int onoff)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
int ret = 0;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (!RUN_ONCE(&fips_lock_init, do_fips_lock_init))
|
|
Packit |
c4476c |
return 0;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
fips_w_lock();
|
|
Packit |
c4476c |
fips_started = 1;
|
|
Packit |
c4476c |
fips_set_owning_thread();
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (onoff) {
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
fips_selftest_fail = 0;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
/* Don't go into FIPS mode twice, just so we can do automagic
|
|
Packit |
c4476c |
seeding */
|
|
Packit |
c4476c |
if (FIPS_module_mode()) {
|
|
Packit |
c4476c |
FIPSerr(FIPS_F_FIPS_MODULE_MODE_SET,
|
|
Packit |
c4476c |
FIPS_R_FIPS_MODE_ALREADY_SET);
|
|
Packit |
c4476c |
fips_selftest_fail = 1;
|
|
Packit |
c4476c |
ret = 0;
|
|
Packit |
c4476c |
goto end;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
# ifdef OPENSSL_IA32_SSE2
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
extern unsigned int OPENSSL_ia32cap_P[2];
|
|
Packit |
c4476c |
if ((OPENSSL_ia32cap_P[0] & (1 << 25 | 1 << 26)) !=
|
|
Packit |
c4476c |
(1 << 25 | 1 << 26)) {
|
|
Packit |
c4476c |
FIPSerr(FIPS_F_FIPS_MODULE_MODE_SET,
|
|
Packit |
c4476c |
FIPS_R_UNSUPPORTED_PLATFORM);
|
|
Packit |
c4476c |
fips_selftest_fail = 1;
|
|
Packit |
c4476c |
ret = 0;
|
|
Packit |
c4476c |
goto end;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
# endif
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
fips_post = 1;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (!FIPS_selftest()) {
|
|
Packit |
c4476c |
fips_selftest_fail = 1;
|
|
Packit |
c4476c |
ret = 0;
|
|
Packit |
c4476c |
goto end;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (!verify_checksums()) {
|
|
Packit |
c4476c |
FIPSerr(FIPS_F_FIPS_MODULE_MODE_SET,
|
|
Packit |
c4476c |
FIPS_R_FINGERPRINT_DOES_NOT_MATCH);
|
|
Packit |
c4476c |
fips_selftest_fail = 1;
|
|
Packit |
c4476c |
ret = 0;
|
|
Packit |
c4476c |
goto end;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
fips_post = 0;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
fips_set_mode(onoff);
|
|
Packit |
c4476c |
/* force RNG reseed with entropy from getrandom() on next call */
|
|
Packit |
c4476c |
rand_force_reseed();
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
ret = 1;
|
|
Packit |
c4476c |
goto end;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
fips_set_mode(0);
|
|
Packit |
c4476c |
fips_selftest_fail = 0;
|
|
Packit |
c4476c |
ret = 1;
|
|
Packit |
c4476c |
end:
|
|
Packit |
c4476c |
fips_clear_owning_thread();
|
|
Packit |
c4476c |
fips_w_unlock();
|
|
Packit |
c4476c |
return ret;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
static CRYPTO_THREAD_ID fips_threadid;
|
|
Packit |
c4476c |
static int fips_thread_set = 0;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
static int fips_is_owning_thread(void)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
int ret = 0;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (fips_started) {
|
|
Packit |
c4476c |
CRYPTO_THREAD_read_lock(fips_owning_lock);
|
|
Packit |
c4476c |
if (fips_thread_set) {
|
|
Packit |
c4476c |
CRYPTO_THREAD_ID cur = CRYPTO_THREAD_get_current_id();
|
|
Packit |
c4476c |
if (CRYPTO_THREAD_compare_id(fips_threadid, cur))
|
|
Packit |
c4476c |
ret = 1;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
CRYPTO_THREAD_unlock(fips_owning_lock);
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
return ret;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
int fips_set_owning_thread(void)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
int ret = 0;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (fips_started) {
|
|
Packit |
c4476c |
CRYPTO_THREAD_write_lock(fips_owning_lock);
|
|
Packit |
c4476c |
if (!fips_thread_set) {
|
|
Packit |
c4476c |
fips_threadid = CRYPTO_THREAD_get_current_id();
|
|
Packit |
c4476c |
ret = 1;
|
|
Packit |
c4476c |
fips_thread_set = 1;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
CRYPTO_THREAD_unlock(fips_owning_lock);
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
return ret;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
int fips_clear_owning_thread(void)
|
|
Packit |
c4476c |
{
|
|
Packit |
c4476c |
int ret = 0;
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
if (fips_started) {
|
|
Packit |
c4476c |
CRYPTO_THREAD_write_lock(fips_owning_lock);
|
|
Packit |
c4476c |
if (fips_thread_set) {
|
|
Packit |
c4476c |
CRYPTO_THREAD_ID cur = CRYPTO_THREAD_get_current_id();
|
|
Packit |
c4476c |
if (CRYPTO_THREAD_compare_id(fips_threadid, cur))
|
|
Packit |
c4476c |
fips_thread_set = 0;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
CRYPTO_THREAD_unlock(fips_owning_lock);
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
return ret;
|
|
Packit |
c4476c |
}
|
|
Packit |
c4476c |
|
|
Packit |
c4476c |
#endif
|