Skip to content

Commit

Permalink
Merge pull request #53 from microsoft/fips
Browse files Browse the repository at this point in the history
Prioritize FIPS-enabled versions when automatically selecting a version
  • Loading branch information
qmuntal authored Jun 2, 2023
2 parents e3ffd82 + 4a4132a commit 909778f
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 42 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ jobs:
run: go test -gcflags=all=-d=checkptr -count 10 -v ./...
env:
GO_OPENSSL_VERSION_OVERRIDE: ${{ matrix.openssl-version-build }}
- name: Run Test - Build - No version override
run: go test -gcflags=all=-d=checkptr -v ./...
- name: Run Test - Misc
run: go test -gcflags=all=-d=checkptr -v .
working-directory: ./misc
Expand Down
21 changes: 21 additions & 0 deletions openssl/goopenssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,27 @@
#include <dlfcn.h>
#include <stdio.h>

int
go_openssl_fips_enabled(void* handle)
{
// For OpenSSL 1.x.
int (*FIPS_mode)(void);
FIPS_mode = (int (*)(void))dlsym(handle, "FIPS_mode");
if (FIPS_mode != NULL)
return FIPS_mode();

// For OpenSSL 3.x.
int (*EVP_default_properties_is_fips_enabled)(void*);
int (*OSSL_PROVIDER_available)(void*, const char*);
EVP_default_properties_is_fips_enabled = (int (*)(void*))dlsym(handle, "EVP_default_properties_is_fips_enabled");
OSSL_PROVIDER_available = (int (*)(void*, const char*))dlsym(handle, "OSSL_PROVIDER_available");
if (EVP_default_properties_is_fips_enabled != NULL && OSSL_PROVIDER_available != NULL &&
EVP_default_properties_is_fips_enabled(NULL) == 1 && OSSL_PROVIDER_available(NULL, "fips") == 1)
return 1;

return 0;
}

static unsigned long
version_num(void* handle)
{
Expand Down
1 change: 1 addition & 0 deletions openssl/goopenssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "openssl_funcs.h"

int go_openssl_fips_enabled(void* handle);
int go_openssl_version_major(void* handle);
int go_openssl_version_minor(void* handle);
int go_openssl_thread_setup(void);
Expand Down
75 changes: 38 additions & 37 deletions openssl/openssl.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ import (
var (
providerNameFips = C.CString("fips")
providerNameDefault = C.CString("default")
propFipsYes = C.CString("fips=yes")
propFipsNo = C.CString("fips=no")
algProve = C.CString("SHA2-256")
)

var (
Expand Down Expand Up @@ -126,26 +123,33 @@ func loadLibrary(version string) (unsafe.Pointer, error) {
}
return handle, nil
}
var fallbackHandle unsafe.Pointer
for _, v := range knownVersions {
handle := dlopen(v)
if handle != nil {
if handle == nil {
continue
}
if C.go_openssl_fips_enabled(handle) == 1 {
// Found a FIPS enabled version, use it.
if fallbackHandle != nil {
// If we found a FIPS enabled version but we already have a fallback
// version, close the fallback version.
C.dlclose(fallbackHandle)
}
return handle, nil
}
if fallbackHandle == nil {
// Remember the first version that exists but is not FIPS enabled
// in case we don't find any FIPS enabled version.
fallbackHandle = handle
} else {
C.dlclose(handle)
}
}
return nil, errors.New("openssl: can't load libcrypto.so using any known version suffix")
}

// providerAvailable looks through provider's digests
// checking if there is any that matches the props query.
func providerAvailable(props *C.char) bool {
C.go_openssl_ERR_set_mark()
md := C.go_openssl_EVP_MD_fetch(nil, algProve, props)
C.go_openssl_ERR_pop_to_mark()
if md == nil {
return false
if fallbackHandle != nil {
return fallbackHandle, nil
}
C.go_openssl_EVP_MD_free(md)
return true
return nil, errors.New("openssl: can't load libcrypto.so using any known version suffix")
}

// FIPS returns true if OpenSSL is running in FIPS mode, else returns false.
Expand All @@ -159,53 +163,49 @@ func FIPS() bool {
}
// EVP_default_properties_is_fips_enabled can return true even if the FIPS provider isn't loaded,
// it is only based on the default properties.
return providerAvailable(propFipsYes)
return C.go_openssl_OSSL_PROVIDER_available(nil, providerNameFips) == 1
default:
panic(errUnsuportedVersion())
}
}

// SetFIPS enables or disables FIPS mode.
//
// It implements the following provider fallback logic for OpenSSL 3:
// - The "fips" provider is loaded if enabled=true and no loaded provider matches "fips=yes".
// - The "default" provider is loaded if enabled=false and no loaded provider matches "fips=no".
// This logic allows advanced users to define their own providers that match "fips=yes" and "fips=no" using the OpenSSL config file.
// On OpenSSL 3, the `fips` provider is loaded if enabled is true,
// else the `default` provider is loaded.
func SetFIPS(enabled bool) error {
var mode C.int
if enabled {
mode = C.int(1)
} else {
mode = C.int(0)
}
switch vMajor {
case 1:
var mode C.int
if enabled {
mode = C.int(1)
} else {
mode = C.int(0)
}
if C.go_openssl_FIPS_mode_set(mode) != 1 {
return newOpenSSLError("openssl: FIPS_mode_set")
}
return nil
case 3:
var props, provName *C.char
var provName *C.char
if enabled {
props = propFipsYes
provName = providerNameFips
} else {
props = propFipsNo
provName = providerNameDefault
}
// Check if there is any provider that matches props.
if !providerAvailable(props) {
// Check if provName is not loaded.
if C.go_openssl_OSSL_PROVIDER_available(nil, provName) == 0 {
// If not, fallback to provName provider.
if C.go_openssl_OSSL_PROVIDER_load(nil, provName) == nil {
return newOpenSSLError("openssl: OSSL_PROVIDER_try_load")
return newOpenSSLError("openssl: OSSL_PROVIDER_load")
}
// Make sure we now have a provider available.
if !providerAvailable(props) {
if C.go_openssl_OSSL_PROVIDER_available(nil, provName) == 0 {
return fail("SetFIPS(" + strconv.FormatBool(enabled) + ") not supported")
}
}
if C.go_openssl_EVP_set_default_properties(nil, props) != 1 {
return newOpenSSLError("openssl: EVP_set_default_properties")
if C.go_openssl_EVP_default_properties_enable_fips(nil, mode) != 1 {
return newOpenSSLError("openssl: EVP_default_properties_enable_fips")
}
return nil
default:
Expand Down Expand Up @@ -281,6 +281,7 @@ func bnToBig(bn C.GO_BIGNUM_PTR) BigInt {
// output depends on the input. noescape is inlined and currently
// compiles down to zero instructions.
// USE CAREFULLY!
//
//go:nosplit
func noescape(p unsafe.Pointer) unsafe.Pointer {
x := uintptr(p)
Expand Down
7 changes: 2 additions & 5 deletions openssl/openssl_funcs.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,6 @@ typedef struct {
// #include <openssl/provider.h>
// #endif
#define FOR_ALL_OPENSSL_FUNCTIONS \
DEFINEFUNC(int, ERR_set_mark, (void), ()) \
DEFINEFUNC(int, ERR_pop_to_mark, (void), ()) \
DEFINEFUNC(unsigned long, ERR_get_error, (void), ()) \
DEFINEFUNC(void, ERR_error_string_n, (unsigned long e, char *buf, size_t len), (e, buf, len)) \
DEFINEFUNC_RENAMED_1_1(const char *, OpenSSL_version, SSLeay_version, (int type), (type)) \
Expand All @@ -165,8 +163,9 @@ DEFINEFUNC_1_1(int, OPENSSL_init_crypto, (uint64_t ops, const GO_OPENSSL_INIT_SE
DEFINEFUNC_LEGACY_1(int, FIPS_mode, (void), ()) \
DEFINEFUNC_LEGACY_1(int, FIPS_mode_set, (int r), (r)) \
DEFINEFUNC_3_0(int, EVP_default_properties_is_fips_enabled, (GO_OSSL_LIB_CTX_PTR libctx), (libctx)) \
DEFINEFUNC_3_0(int, EVP_set_default_properties, (GO_OSSL_LIB_CTX_PTR libctx, const char *propq), (libctx, propq)) \
DEFINEFUNC_3_0(int, EVP_default_properties_enable_fips, (GO_OSSL_LIB_CTX_PTR libctx, int enable), (libctx, enable)) \
DEFINEFUNC_3_0(GO_OSSL_PROVIDER_PTR, OSSL_PROVIDER_load, (GO_OSSL_LIB_CTX_PTR libctx, const char *name), (libctx, name)) \
DEFINEFUNC_3_0(int, OSSL_PROVIDER_available, (GO_OSSL_LIB_CTX_PTR libctx, const char *name), (libctx, name)) \
DEFINEFUNC(int, RAND_bytes, (unsigned char* arg0, int arg1), (arg0, arg1)) \
DEFINEFUNC(int, EVP_DigestInit, (GO_EVP_MD_CTX_PTR ctx, const GO_EVP_MD_PTR type), (ctx, type)) \
DEFINEFUNC(int, EVP_DigestInit_ex, (GO_EVP_MD_CTX_PTR ctx, const GO_EVP_MD_PTR type, GO_ENGINE_PTR impl), (ctx, type, impl)) \
Expand All @@ -186,8 +185,6 @@ DEFINEFUNC(const GO_EVP_MD_PTR, EVP_sha256, (void), ()) \
DEFINEFUNC(const GO_EVP_MD_PTR, EVP_sha384, (void), ()) \
DEFINEFUNC(const GO_EVP_MD_PTR, EVP_sha512, (void), ()) \
DEFINEFUNC_1_1(const GO_EVP_MD_PTR, EVP_md5_sha1, (void), ()) \
DEFINEFUNC_3_0(GO_EVP_MD_PTR, EVP_MD_fetch, (GO_OSSL_LIB_CTX_PTR ctx, const char *algorithm, const char *properties), (ctx, algorithm, properties)) \
DEFINEFUNC_3_0(void, EVP_MD_free, (GO_EVP_MD_PTR md), (md)) \
DEFINEFUNC_RENAMED_3_0(int, EVP_MD_get_size, EVP_MD_size, (const GO_EVP_MD_PTR arg0), (arg0)) \
DEFINEFUNC_LEGACY_1_0(void, HMAC_CTX_init, (GO_HMAC_CTX_PTR arg0), (arg0)) \
DEFINEFUNC_LEGACY_1_0(void, HMAC_CTX_cleanup, (GO_HMAC_CTX_PTR arg0), (arg0)) \
Expand Down

0 comments on commit 909778f

Please sign in to comment.