Skip to content

Commit fc0ef3a

Browse files
qmuntaldagood
andauthored
Return nil in NewHMAC if HMAC doesn't support the hash function (#159)
* return nil in NewHMAC if HMAC doesn't support the hash function * Update hmac.go Co-authored-by: Davis Goodin <[email protected]> --------- Co-authored-by: Davis Goodin <[email protected]>
1 parent 493baa2 commit fc0ef3a

File tree

2 files changed

+75
-36
lines changed

2 files changed

+75
-36
lines changed

hmac.go

Lines changed: 74 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,6 @@ import (
1313

1414
var OSSL_MAC_PARAM_DIGEST = C.CString("digest")
1515

16-
var (
17-
fetchHMACOnce sync.Once
18-
evpHMAC C.GO_EVP_MAC_PTR
19-
)
20-
2116
// NewHMAC returns a new HMAC using OpenSSL.
2217
// The function h must return a hash implemented by
2318
// OpenSSL (for example, h could be openssl.NewSHA256).
@@ -38,14 +33,29 @@ func NewHMAC(h func() hash.Hash, key []byte) hash.Hash {
3833
key = make([]byte, C.GO_EVP_MAX_MD_SIZE)
3934
}
4035

36+
hmac := &opensslHMAC{
37+
size: ch.Size(),
38+
blockSize: ch.BlockSize(),
39+
}
40+
4141
switch vMajor {
4242
case 1:
43-
return newHMAC1(key, ch, md)
43+
ctx := newHMAC1(key, md)
44+
if ctx.ctx == nil {
45+
return nil
46+
}
47+
hmac.ctx1 = ctx
4448
case 3:
45-
return newHMAC3(key, ch, md)
49+
ctx := newHMAC3(key, md)
50+
if ctx.ctx == nil {
51+
return nil
52+
}
53+
hmac.ctx3 = ctx
4654
default:
4755
panic(errUnsupportedVersion())
4856
}
57+
runtime.SetFinalizer(hmac, (*opensslHMAC).finalize)
58+
return hmac
4959
}
5060

5161
// hmacCtx3 is used for OpenSSL 1.
@@ -67,50 +77,84 @@ type opensslHMAC struct {
6777
sum []byte
6878
}
6979

70-
func newHMAC1(key []byte, h hash.Hash, md C.GO_EVP_MD_PTR) *opensslHMAC {
80+
func newHMAC1(key []byte, md C.GO_EVP_MD_PTR) hmacCtx1 {
7181
ctx := hmacCtxNew()
7282
if ctx == nil {
7383
panic("openssl: EVP_MAC_CTX_new failed")
7484
}
7585
if C.go_openssl_HMAC_Init_ex(ctx, unsafe.Pointer(&key[0]), C.int(len(key)), md, nil) == 0 {
7686
panic(newOpenSSLError("HMAC_Init_ex failed"))
7787
}
78-
hmac := &opensslHMAC{
79-
size: h.Size(),
80-
blockSize: h.BlockSize(),
81-
ctx1: hmacCtx1{ctx},
82-
}
83-
runtime.SetFinalizer(hmac, (*opensslHMAC).finalize)
84-
return hmac
88+
return hmacCtx1{ctx}
8589
}
8690

87-
func newHMAC3(key []byte, h hash.Hash, md C.GO_EVP_MD_PTR) *opensslHMAC {
88-
fetchHMACOnce.Do(func() {
89-
name := C.CString("HMAC")
90-
evpHMAC = C.go_openssl_EVP_MAC_fetch(nil, name, nil)
91-
C.free(unsafe.Pointer(name))
92-
})
93-
if evpHMAC == nil {
91+
var hmacDigestsSupported sync.Map
92+
var fetchHMAC3 = sync.OnceValue(func() C.GO_EVP_MAC_PTR {
93+
name := C.CString("HMAC")
94+
mac := C.go_openssl_EVP_MAC_fetch(nil, name, nil)
95+
C.free(unsafe.Pointer(name))
96+
if mac == nil {
9497
panic("openssl: HMAC not supported")
9598
}
96-
ctx := C.go_openssl_EVP_MAC_CTX_new(evpHMAC)
97-
if ctx == nil {
98-
panic("openssl: EVP_MAC_CTX_new failed")
99-
}
100-
digest := C.go_openssl_EVP_MD_get0_name(md)
99+
return mac
100+
})
101+
102+
func buildHMAC3Params(digest *C.char) C.GO_OSSL_PARAM_PTR {
101103
bld := C.go_openssl_OSSL_PARAM_BLD_new()
102104
if bld == nil {
103105
panic(newOpenSSLError("OSSL_PARAM_BLD_new"))
104106
}
105107
defer C.go_openssl_OSSL_PARAM_BLD_free(bld)
106108
C.go_openssl_OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_MAC_PARAM_DIGEST, digest, 0)
107-
params := C.go_openssl_OSSL_PARAM_BLD_to_param(bld)
109+
return C.go_openssl_OSSL_PARAM_BLD_to_param(bld)
110+
}
111+
112+
func isHMAC3DigestSupported(digest string) bool {
113+
if v, ok := hmacDigestsSupported.Load(digest); ok {
114+
return v.(bool)
115+
}
116+
ctx := C.go_openssl_EVP_MAC_CTX_new(fetchHMAC3())
117+
if ctx == nil {
118+
panic(newOpenSSLError("EVP_MAC_CTX_new"))
119+
}
120+
defer C.go_openssl_EVP_MAC_CTX_free(ctx)
121+
122+
cdigest := C.CString(digest)
123+
defer C.free(unsafe.Pointer(cdigest))
124+
params := buildHMAC3Params(cdigest)
125+
if params == nil {
126+
panic(newOpenSSLError("OSSL_PARAM_BLD_to_param"))
127+
}
128+
defer C.go_openssl_OSSL_PARAM_free(params)
129+
130+
supported := C.go_openssl_EVP_MAC_CTX_set_params(ctx, params) != 0
131+
hmacDigestsSupported.Store(digest, supported)
132+
return supported
133+
}
134+
135+
func newHMAC3(key []byte, md C.GO_EVP_MD_PTR) hmacCtx3 {
136+
digest := C.go_openssl_EVP_MD_get0_name(md)
137+
if !isHMAC3DigestSupported(C.GoString(digest)) {
138+
// The digest is not supported by the HMAC provider.
139+
// Don't panic here so the Go standard library to
140+
// fall back to the Go implementation.
141+
// See https://github.com/golang-fips/openssl/issues/153.
142+
return hmacCtx3{}
143+
}
144+
params := buildHMAC3Params(digest)
108145
if params == nil {
109146
panic(newOpenSSLError("OSSL_PARAM_BLD_to_param"))
110147
}
111148
defer C.go_openssl_OSSL_PARAM_free(params)
149+
150+
ctx := C.go_openssl_EVP_MAC_CTX_new(fetchHMAC3())
151+
if ctx == nil {
152+
panic(newOpenSSLError("EVP_MAC_CTX_new"))
153+
}
154+
112155
if C.go_openssl_EVP_MAC_init(ctx, base(key), C.size_t(len(key)), params) == 0 {
113-
panic(newOpenSSLError("EVP_MAC_init failed"))
156+
C.go_openssl_EVP_MAC_CTX_free(ctx)
157+
panic(newOpenSSLError("EVP_MAC_init"))
114158
}
115159
var hkey []byte
116160
if vMinor == 0 && vPatch <= 2 {
@@ -122,13 +166,7 @@ func newHMAC3(key []byte, h hash.Hash, md C.GO_EVP_MD_PTR) *opensslHMAC {
122166
hkey = make([]byte, len(key))
123167
copy(hkey, key)
124168
}
125-
hmac := &opensslHMAC{
126-
size: h.Size(),
127-
blockSize: h.BlockSize(),
128-
ctx3: hmacCtx3{ctx, hkey},
129-
}
130-
runtime.SetFinalizer(hmac, (*opensslHMAC).finalize)
131-
return hmac
169+
return hmacCtx3{ctx, hkey}
132170
}
133171

134172
func (h *opensslHMAC) Reset() {

shims.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,7 @@ DEFINEFUNC(GO_EC_GROUP_PTR, EC_GROUP_new_by_curve_name, (int nid), (nid)) \
344344
DEFINEFUNC(void, EC_GROUP_free, (GO_EC_GROUP_PTR group), (group)) \
345345
DEFINEFUNC_3_0(GO_EVP_MAC_PTR, EVP_MAC_fetch, (GO_OSSL_LIB_CTX_PTR ctx, const char *algorithm, const char *properties), (ctx, algorithm, properties)) \
346346
DEFINEFUNC_3_0(GO_EVP_MAC_CTX_PTR, EVP_MAC_CTX_new, (GO_EVP_MAC_PTR arg0), (arg0)) \
347+
DEFINEFUNC_3_0(int, EVP_MAC_CTX_set_params, (GO_EVP_MAC_CTX_PTR ctx, const GO_OSSL_PARAM_PTR params), (ctx, params)) \
347348
DEFINEFUNC_3_0(void, EVP_MAC_CTX_free, (GO_EVP_MAC_CTX_PTR arg0), (arg0)) \
348349
DEFINEFUNC_3_0(GO_EVP_MAC_CTX_PTR, EVP_MAC_CTX_dup, (const GO_EVP_MAC_CTX_PTR arg0), (arg0)) \
349350
DEFINEFUNC_3_0(int, EVP_MAC_init, (GO_EVP_MAC_CTX_PTR ctx, const unsigned char *key, size_t keylen, const GO_OSSL_PARAM_PTR params), (ctx, key, keylen, params)) \

0 commit comments

Comments
 (0)