-
Notifications
You must be signed in to change notification settings - Fork 34
Description
I would like to start a discussion about the need for typed errors from the crypto backends.
The use case I have is detecting whether an error was triggered by OpenSSL. Currently golang-fips/openssl extracts the error string from OpenSSL and then calls errors.New() to create the error. This means that the only way to find out if error was triggered by OpenSSL is to do matching on the error strings. I find that approach error prone and not future proof.
Instead, I would find the following very handy:
Firstly, in microsoft/go, define a CryptoBackendError interface:
src/crypto/boring/boring.go:
type CryptoBackendError interface {
error
CryptoBackend() string
}
Next, in golang-fips/openssl, define a OpenSSLError type and wrap errors to it (note: this is not a complete diff):
diff -urN go1.23.8-1.orig/src/vendor/github.com/golang-fips/openssl/v2/openssl.go go1.23.8-1.cryptobackend-error/src/vendor/github.com/golang-fips/openssl/v2/openssl.go
--- go1.23.8-1.orig/src/vendor/github.com/golang-fips/openssl/v2/openssl.go 2025-04-22 09:34:23.824810048 +0300
+++ go1.23.8-1.cryptobackend-error/src/vendor/github.com/golang-fips/openssl/v2/openssl.go 2025-04-22 14:20:40.295540401 +0300
@@ -74,12 +74,21 @@
}
func errUnsupportedVersion() error {
- return errors.New("openssl: OpenSSL version: " + utoa(vMajor) + "." + utoa(vMinor) + "." + utoa(vPatch))
+ return &openSSLError{err: errors.New("openssl: OpenSSL version: " + utoa(vMajor) + "." + utoa(vMinor) + "." + utoa(vPatch))}
}
type fail string
-func (e fail) Error() string { return "openssl: " + string(e) + " failed" }
+func (e fail) Error() string { return "openssl: " + string(e) + " failed" }
+func (e fail) CryptoBackend() string { return "opensslcrypto" }
+
+type openSSLError struct {
+ err error
+}
+
+func (e openSSLError) Error() string { return e.err.Error() }
+func (e openSSLError) Unwrap() error { return e.err }
+func (e openSSLError) CryptoBackend() string { return "opensslcrypto" }
// VersionText returns the version text of the OpenSSL currently loaded.
func VersionText() string {
@@ -260,7 +269,7 @@
C.go_openssl_ERR_error_string_n(e, (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)))
b.WriteString(string(buf[:]) + "\n\t" + C.GoString(file) + ":" + strconv.Itoa(int(line)))
}
- return errors.New(b.String())
+ return &openSSLError{err: errors.New(b.String())}
}
var unknownFile = "<go code>\000"
Finally, in the application use errors.As() to check if an error is from OpenSSL:
var cryptoBackendErr boring.CryptoBackendError
if errors.As(err, &cryptoBackendErr) {
...
This is not a trivial change, as a) more work would be needed to convert all errors returned in golang-fips/openssl and 2) microsoft/go-crypto-winnative should eventually be converted, for the sake of completeness. The bright side though is, that the work could be done in multiple phases and independently for each crypto backend.
Thoughts?