5
5
package openssl
6
6
7
7
// #include "goopenssl.h"
8
+ // #include <dlfcn.h>
8
9
// #cgo LDFLAGS: -ldl
9
10
import "C"
10
11
import (
@@ -30,17 +31,28 @@ var (
30
31
31
32
var nativeEndian binary.ByteOrder
32
33
34
+ // CheckVersion checks if the OpenSSL version can be loaded
35
+ // and if the FIPS mode is enabled.
36
+ // This function can be called before Init.
37
+ func CheckVersion (version string ) (exists , fips bool ) {
38
+ handle := dlopen (version )
39
+ if handle == nil {
40
+ return false , false
41
+ }
42
+ defer C .dlclose (handle )
43
+ fips = C .go_openssl_fips_enabled (handle ) == 1
44
+ return true , fips
45
+ }
46
+
33
47
// Init loads and initializes OpenSSL.
34
- // It must be called before any other OpenSSL call.
48
+ // It must be called before any other OpenSSL call, except CheckVersion .
35
49
//
36
50
// Only the first call to Init is effective,
37
51
// subsequent calls will return the same error result as the one from the first call.
38
52
//
39
- // If version is not empty, its value will be appended to the OpenSSL shared library name
40
- // as a version suffix when calling dlopen. For example, `version=1.1.1k-fips`
41
- // makes Init look for the shared library libcrypto.so.1.1.1k-fips.
42
- // If version is empty, Init will try to load the OpenSSL shared library
43
- // using a list of supported and well-known version suffixes, going from higher to lower versions.
53
+ // version will be appended to the OpenSSL shared library name as a version suffix
54
+ // when calling dlopen. For example, `version=1.1.1k-fips` makes Init look for
55
+ // the shared library libcrypto.so.1.1.1k-fips.
44
56
func Init (version string ) error {
45
57
initOnce .Do (func () {
46
58
buf := [2 ]byte {}
@@ -75,24 +87,8 @@ func VersionText() string {
75
87
var (
76
88
providerNameFips = C .CString ("fips" )
77
89
providerNameDefault = C .CString ("default" )
78
- propFipsYes = C .CString ("fips=yes" )
79
- propFipsNo = C .CString ("fips=no" )
80
- algProve = C .CString ("SHA2-256" )
81
90
)
82
91
83
- // providerAvailable looks through provider's digests
84
- // checking if there is any that matches the props query.
85
- func providerAvailable (props * C.char ) bool {
86
- C .go_openssl_ERR_set_mark ()
87
- defer C .go_openssl_ERR_pop_to_mark ()
88
- md := C .go_openssl_EVP_MD_fetch (nil , algProve , props )
89
- if md == nil {
90
- return false
91
- }
92
- C .go_openssl_EVP_MD_free (md )
93
- return true
94
- }
95
-
96
92
// FIPS returns true if OpenSSL is running in FIPS mode, else returns false.
97
93
func FIPS () bool {
98
94
switch vMajor {
@@ -107,54 +103,49 @@ func FIPS() bool {
107
103
// it is only based on the default properties.
108
104
// We can be sure that the FIPS provider is available if we can fetch an algorithm, e.g., SHA2-256,
109
105
// explicitly setting `fips=yes`.
110
- return providerAvailable ( propFipsYes )
106
+ return C . go_openssl_OSSL_PROVIDER_available ( nil , providerNameFips ) == 1
111
107
default :
112
108
panic (errUnsupportedVersion ())
113
109
}
114
110
}
115
111
116
112
// SetFIPS enables or disables FIPS mode.
117
113
//
118
- // It implements the following provider fallback logic for OpenSSL 3:
119
- // - The "fips" provider is loaded if enabled=true and no loaded provider matches "fips=yes".
120
- // - The "default" provider is loaded if enabled=false and no loaded provider matches "fips=no".
121
- //
122
- // This logic allows advanced users to define their own providers that match "fips=yes" and "fips=no" using the OpenSSL config file.
114
+ // For OpenSSL 3, the `fips` provider is loaded if enabled is true,
115
+ // else the `default` provider is loaded.
123
116
func SetFIPS (enabled bool ) error {
117
+ var mode C.int
118
+ if enabled {
119
+ mode = C .int (1 )
120
+ } else {
121
+ mode = C .int (0 )
122
+ }
124
123
switch vMajor {
125
124
case 1 :
126
- var mode C.int
127
- if enabled {
128
- mode = C .int (1 )
129
- } else {
130
- mode = C .int (0 )
131
- }
132
125
if C .go_openssl_FIPS_mode_set (mode ) != 1 {
133
126
return newOpenSSLError ("FIPS_mode_set" )
134
127
}
135
128
return nil
136
129
case 3 :
137
- var props , provName * C.char
130
+ var provName * C.char
138
131
if enabled {
139
- props = propFipsYes
140
132
provName = providerNameFips
141
133
} else {
142
- props = propFipsNo
143
134
provName = providerNameDefault
144
135
}
145
136
// Check if there is any provider that matches props.
146
- if ! providerAvailable ( props ) {
137
+ if C . go_openssl_OSSL_PROVIDER_available ( nil , provName ) != 1 {
147
138
// If not, fallback to provName provider.
148
139
if C .go_openssl_OSSL_PROVIDER_load (nil , provName ) == nil {
149
140
return newOpenSSLError ("OSSL_PROVIDER_try_load" )
150
141
}
151
142
// Make sure we now have a provider available.
152
- if ! providerAvailable ( props ) {
143
+ if C . go_openssl_OSSL_PROVIDER_available ( nil , provName ) != 1 {
153
144
return fail ("SetFIPS(" + strconv .FormatBool (enabled ) + ") not supported" )
154
145
}
155
146
}
156
- if C .go_openssl_EVP_set_default_properties (nil , props ) != 1 {
157
- return newOpenSSLError ("EVP_set_default_properties " )
147
+ if C .go_openssl_EVP_default_properties_enable_fips (nil , mode ) != 1 {
148
+ return newOpenSSLError ("openssl: EVP_default_properties_enable_fips " )
158
149
}
159
150
return nil
160
151
default :
0 commit comments