golang-fips / openssl

OpenSSL bindings for Go
MIT License
22 stars 12 forks source link

NewHMAC panics if the HMAC doesn't support a valid digest #153

Closed qmuntal closed 1 month ago

qmuntal commented 2 months ago

The hmac.New function falls back to Go crypto when it is called with a hash function not supported by BoringCrypto's HMAC implementation. This is is signaled by making the bindings return a nil hasher: https://github.com/golang/go/blob/fc9f02c7aec81bcfcc95434d2529e0bb0bc03d66/src/crypto/hmac/hmac.go#L135

We tried to replicate the same behavior in openssl.NewHMAC:

https://github.com/golang-fips/openssl/blob/f8eea431f613cac3064280dbb97d9ce1a39de973/hmac.go#L25-L30

The problem is that some OpenSSL providers return a valid hasher that can't be used as a HMAC hasher. An example is the SymCrypt-OpenSSL provider, which doesn't implement HMAC-SHA224 (see test failure below).

We should instruct openssl.NewHMAC to return a nil HMAC object when that happens.

go test -run TestHMAC/sha224
Using libcrypto.so.3
OpenSSL version: OpenSSL 3.3.0 9 Apr 2024
FIPS enabled: false
[ERROR] error:41000066:SCOSSL::Algorithm not supported by SCOSSL:SCOSSL does not support hash algorithm for MAC 675 at /usr/src/azl/BUILD/SymCrypt-OpenSSL-1.5.1/ScosslCommon/src/scossl_mac.c, line 193
--- FAIL: TestHMAC (0.00s)
    --- FAIL: TestHMAC/sha224 (0.00s)
panic: EVP_MAC_init failed
openssl error(s):
error:41000066:SCOSSL::Algorithm not supported by SCOSSL
        /usr/src/azl/BUILD/SymCrypt-OpenSSL-1.5.1/ScosslCommon/src/scossl_mac.c:193
error:1C80007D:Provider routines::invalid mode
        /usr/src/azl/BUILD/SymCrypt-OpenSSL-1.5.1/SymCryptProvider/src/mac/p_scossl_hmac.c:164 [recovered]
        panic: EVP_MAC_init failed
openssl error(s):
error:41000066:SCOSSL::Algorithm not supported by SCOSSL
        /usr/src/azl/BUILD/SymCrypt-OpenSSL-1.5.1/ScosslCommon/src/scossl_mac.c:193
error:1C80007D:Provider routines::invalid mode
        /usr/src/azl/BUILD/SymCrypt-OpenSSL-1.5.1/SymCryptProvider/src/mac/p_scossl_hmac.c:164

goroutine 7 [running]:
testing.tRunner.func1.2({0x5b1560, 0xc00002e5b0})
        /usr/lib/golang/src/testing/testing.go:1631 +0x24a
testing.tRunner.func1()
        /usr/lib/golang/src/testing/testing.go:1634 +0x377
panic({0x5b1560?, 0xc00002e5b0?})
        /usr/lib/golang/src/runtime/panic.go:770 +0x132
github.com/golang-fips/openssl/v2.newHMAC3({0xc000024080, 0x40, 0x40}, {0x63a208, 0xc00010aa50}, 0x7f44a0005bc0)
        /root/openssl/hmac.go:113 +0x345
github.com/golang-fips/openssl/v2.NewHMAC(0xc000118820?, {0x0, 0x0, 0x0})
        /root/openssl/hmac.go:45 +0xac
github.com/golang-fips/openssl/v2.TestHMAC.func1(0xc000118820)
        /root/openssl/hmac_test.go:24 +0x4a
testing.tRunner(0xc000118820, 0xc000038140)
        /usr/lib/golang/src/testing/testing.go:1689 +0xfb
created by testing.(*T).Run in goroutine 6
        /usr/lib/golang/src/testing/testing.go:1742 +0x390
exit status 2
FAIL    github.com/golang-fips/openssl/v2       0.009s
qmuntal commented 2 months ago

I've dug a bit more here. Azure Linux 3 sets the SymCrypt provider as the default provider, but still loads and activates the built-in provider so that the algorithms not supported by SymCrypt are automatically routed to the built-in provider. The SymCrypt provider doesn't announce SHA224 support, so when fetching its implementation we get it from the built-in provider. The SymCrypt provider does announce support from HMAC, but the OpenSSL fetching mechanism doesn't allow to specify the digest here, so we get the implementation from SymCrypt, which doesn't support HMAC-SHA224.

This causes the following situation:

We think that we can support a given digest, but in reality we don't, so the implemented short-circuit doesn't detect this case:

https://github.com/golang-fips/openssl/blob/f8eea431f613cac3064280dbb97d9ce1a39de973/hmac.go#L25-L30

When initializing the HMAC algorithm, the SymCrypt provider returns an error and we panic:

https://github.com/golang-fips/openssl/blob/f8eea431f613cac3064280dbb97d9ce1a39de973/hmac.go#L112-L114