Skip to content

Commit

Permalink
implement stronger guarantees for FIPS()
Browse files Browse the repository at this point in the history
  • Loading branch information
qmuntal committed Sep 16, 2024
1 parent 356f8b0 commit 57e886d
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 21 deletions.
18 changes: 14 additions & 4 deletions goopenssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,21 @@ go_openssl_fips_enabled(void* handle)
return FIPS_mode();

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

return 0;
if (EVP_default_properties_is_fips_enabled == NULL || EVP_MD_fetch == NULL || EVP_MD_free == NULL) {
// Shouldn't happen, but if it does, we can't determine if FIPS mode is enabled.
return 0;
}

void *md = EVP_MD_fetch(NULL, "SHA2-256", NULL);
if (md == NULL)
return 0;

EVP_MD_free(md);
return 1;
}

// Load all the functions stored in FOR_ALL_OPENSSL_FUNCTIONS
Expand Down
46 changes: 29 additions & 17 deletions openssl.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,36 @@ func VersionText() string {
var (
providerNameFips = C.CString("fips")
providerNameDefault = C.CString("default")

algorithmSHA256 = C.CString("SHA2-256")
)

// FIPS returns true if OpenSSL is running in FIPS mode, else returns false.
// FIPS returns true if OpenSSL is running in FIPS mode and there is
// a provider available that supports FIPS. It returns false otherwise.
func FIPS() bool {
switch vMajor {
case 1:
return C.go_openssl_FIPS_mode() == 1
case 3:
// EVP_default_properties_is_fips_enabled returns 1 if the default properties contain `fips=1`.
// It doesn't check if there is a provider available that matches that property, but we can be sure
// that any algorithm fetching will fail in that case. So this check is enough to tell if OpenSSL
// will only use FIPS-approved algorithms.
return C.go_openssl_EVP_default_properties_is_fips_enabled(nil) == 1
// FIPS is not enabled via default properties (i.e. `fips=1`), then we are sure FIPS is not used.
// Note that it is still possible that the provider used by default is FIPS-compliant,
// but that wouldn't be a system or user requirement.
if C.go_openssl_EVP_default_properties_is_fips_enabled(nil) != 1 {
return false
}
// Check if the SHA-256 algorithm is available. If it is, then we can be sure that there is a provider available that matches
// the `fips=1` query. Most notably, this works for the common case of using the built-in FIPS provider.
//
// Note that this approach has a small chance of false negative if the FIPS provider doesn't provide the SHA-256 algorithm,
// but that is highly unlikely because SHA-256 is one of the most common algorithms and fundamental to many cryptographic operations.
// It also has a small chance of false positive if the FIPS provider implements the SHA-256 algorithm but not the other algorithms
// used by the caller application, but that is also unlikely because the FIPS provider should provide all common algorithms.
md := C.go_openssl_EVP_MD_fetch(nil, algorithmSHA256, nil)
if md == nil {
return false
}
C.go_openssl_EVP_MD_free(md)
return true
default:
panic(errUnsupportedVersion())
}
Expand Down Expand Up @@ -146,17 +163,12 @@ func SetFIPS(enabled bool) error {
} else {
provName = providerNameDefault
}
// Check if there is any provider that matches props.
if C.go_openssl_OSSL_PROVIDER_available(nil, provName) != 1 {
// If not, fallback to provName provider.
if C.go_openssl_OSSL_PROVIDER_load(nil, provName) == nil {
return newOpenSSLError("OSSL_PROVIDER_try_load")
}
// Make sure we now have a provider available.
if C.go_openssl_OSSL_PROVIDER_available(nil, provName) != 1 {
return fail("SetFIPS(" + strconv.FormatBool(enabled) + ") not supported")
}
}
// Try to load the provider, but don't fail if it's not loaded.
// The built-in provides might not be present in the system, e.g. because
// third-party providers are being used or because the system is not well-configured.
C.go_openssl_OSSL_PROVIDER_try_load(nil, provName, 1)

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / mactest (1.22.x, libcrypto.3.dylib)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / mactest (1.22.x, libcrypto.3.dylib)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 1.1.1)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 1.1.0)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 1.1.0)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 1.1.1)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / wintest (1.22.x, libcrypto-3-x64.dll)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 1.0.2)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / wintest (1.22.x, libcrypto-1_1-x64.dll)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 1.0.2)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / wintest (1.22.x, libcrypto-3-x64.dll)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / wintest (1.22.x, libcrypto-1_1-x64.dll)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.0.13)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.0.1)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.0.13)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.0.1)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.2.1)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.3.0)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.1.5)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.3.1)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.1.5)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.2.1)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.3.0)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load

Check failure on line 169 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.3.1)

could not determine kind of name for C.go_openssl_OSSL_PROVIDER_try_load
C.go_openssl_ERR_clear_error()

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / mactest (1.22.x, libcrypto.3.dylib)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / mactest (1.22.x, libcrypto.3.dylib)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 1.1.1)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 1.1.0)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 1.1.0)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 1.1.1)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / wintest (1.22.x, libcrypto-3-x64.dll)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 1.0.2)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / wintest (1.22.x, libcrypto-1_1-x64.dll)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 1.0.2)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / wintest (1.22.x, libcrypto-3-x64.dll)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / wintest (1.22.x, libcrypto-1_1-x64.dll)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.0.13)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.0.1)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.0.13)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.0.1)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.2.1)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.3.0)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.1.5)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.3.1)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.1.5)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.2.1)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.3.0)

could not determine kind of name for C.go_openssl_ERR_clear_error

Check failure on line 170 in openssl.go

View workflow job for this annotation

GitHub Actions / test (1.22.x, 3.3.1)

could not determine kind of name for C.go_openssl_ERR_clear_error

if C.go_openssl_EVP_default_properties_enable_fips(nil, mode) != 1 {
return newOpenSSLError("openssl: EVP_default_properties_enable_fips")
}
Expand Down

0 comments on commit 57e886d

Please sign in to comment.