@@ -38,8 +38,14 @@ func CheckVersion(version string) (exists, fips bool) {
38
38
return false , false
39
39
}
40
40
defer dlclose (handle )
41
- fips = C .go_openssl_fips_enabled (handle ) == 1
42
- return true , fips
41
+ enabled := C .go_openssl_fips_enabled (handle )
42
+ fips = enabled == 1
43
+ // If go_openssl_fips_enabled returns -1, it means that all or some of the necessary
44
+ // functions are not available. This can be due to the version of OpenSSL being too old,
45
+ // too incompatible, or the shared library not being an OpenSSL library. In any case,
46
+ // we shouldn't consider this library to be valid for our purposes.
47
+ exists = enabled != - 1
48
+ return
43
49
}
44
50
45
51
// Init loads and initializes OpenSSL from the shared library at path.
@@ -96,23 +102,36 @@ func VersionText() string {
96
102
var (
97
103
providerNameFips = C .CString ("fips" )
98
104
providerNameDefault = C .CString ("default" )
105
+
106
+ algorithmSHA256 = C .CString ("SHA2-256" )
99
107
)
100
108
101
- // FIPS returns true if OpenSSL is running in FIPS mode, else returns false.
109
+ // FIPS returns true if OpenSSL is running in FIPS mode and there is
110
+ // a provider available that supports FIPS. It returns false otherwise.
102
111
func FIPS () bool {
103
112
switch vMajor {
104
113
case 1 :
105
114
return C .go_openssl_FIPS_mode () == 1
106
115
case 3 :
107
- // If FIPS is not enabled via default properties, then we are sure FIPS is not used.
108
- if C .go_openssl_EVP_default_properties_is_fips_enabled (nil ) == 0 {
116
+ // Check if the default properties contain `fips=1`.
117
+ if C .go_openssl_EVP_default_properties_is_fips_enabled (nil ) != 1 {
118
+ // Note that it is still possible that the provider used by default is FIPS-compliant,
119
+ // but that wouldn't be a system or user requirement.
120
+ return false
121
+ }
122
+ // Check if the SHA-256 algorithm is available. If it is, then we can be sure that there is a provider available that matches
123
+ // the `fips=1` query. Most notably, this works for the common case of using the built-in FIPS provider.
124
+ //
125
+ // Note that this approach has a small chance of false negative if the FIPS provider doesn't provide the SHA-256 algorithm,
126
+ // but that is highly unlikely because SHA-256 is one of the most common algorithms and fundamental to many cryptographic operations.
127
+ // It also has a small chance of false positive if the FIPS provider implements the SHA-256 algorithm but not the other algorithms
128
+ // used by the caller application, but that is also unlikely because the FIPS provider should provide all common algorithms.
129
+ md := C .go_openssl_EVP_MD_fetch (nil , algorithmSHA256 , nil )
130
+ if md == nil {
109
131
return false
110
132
}
111
- // EVP_default_properties_is_fips_enabled can return true even if the FIPS provider isn't loaded,
112
- // it is only based on the default properties.
113
- // We can be sure that the FIPS provider is available if we can fetch an algorithm, e.g., SHA2-256,
114
- // explicitly setting `fips=yes`.
115
- return C .go_openssl_OSSL_PROVIDER_available (nil , providerNameFips ) == 1
133
+ C .go_openssl_EVP_MD_free (md )
134
+ return true
116
135
default :
117
136
panic (errUnsupportedVersion ())
118
137
}
0 commit comments