Skip to content

Commit cb1b28d

Browse files
committed
error instead of panicing when marshaling hash objects
1 parent 0a2f211 commit cb1b28d

File tree

4 files changed

+66
-0
lines changed

4 files changed

+66
-0
lines changed

export_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
package openssl
22

33
var ErrOpen = errOpen
4+
5+
var TestNotMarshalable = &testNotMarshalable

hash.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"hash"
1111
"runtime"
1212
"strconv"
13+
"sync"
1314
"unsafe"
1415
)
1516

@@ -110,6 +111,37 @@ func SHA3_512(p []byte) (sum [64]byte) {
110111
return
111112
}
112113

114+
var isMarshallableCache sync.Map
115+
116+
// isHashMarshallable returns true if the memory layout of cb
117+
// is known by this library and can therefore be marshalled.
118+
func isHashMarshallable(ch crypto.Hash) bool {
119+
if vMajor == 1 {
120+
return true
121+
}
122+
if v, ok := isMarshallableCache.Load(ch); ok {
123+
return v.(bool)
124+
}
125+
md := cryptoHashToMD(ch)
126+
if md == nil {
127+
return false
128+
}
129+
prov := C.go_openssl_EVP_MD_get0_provider(md)
130+
if prov == nil {
131+
return false
132+
}
133+
cname := C.go_openssl_OSSL_PROVIDER_get0_name(prov)
134+
if cname == nil {
135+
return false
136+
}
137+
name := C.GoString(cname)
138+
// We only know the memory layout of the built-in providers.
139+
// See evpHash.hashState for more details.
140+
marshallable := name == "default" || name == "fips"
141+
isMarshallableCache.Store(ch, marshallable)
142+
return marshallable
143+
}
144+
113145
// evpHash implements generic hash methods.
114146
type evpHash struct {
115147
ctx C.GO_EVP_MD_CTX_PTR
@@ -119,6 +151,8 @@ type evpHash struct {
119151
ctx2 C.GO_EVP_MD_CTX_PTR
120152
size int
121153
blockSize int
154+
155+
marshallable bool
122156
}
123157

124158
func newEvpHash(ch crypto.Hash, size, blockSize int) *evpHash {
@@ -137,6 +171,8 @@ func newEvpHash(ch crypto.Hash, size, blockSize int) *evpHash {
137171
ctx2: ctx2,
138172
size: size,
139173
blockSize: blockSize,
174+
175+
marshallable: isHashMarshallable(ch),
140176
}
141177
runtime.SetFinalizer(h, (*evpHash).finalize)
142178
return h
@@ -195,11 +231,16 @@ func (h *evpHash) sum(out []byte) {
195231
runtime.KeepAlive(h)
196232
}
197233

234+
var testNotMarshalable bool // Used in tests.
235+
198236
// hashState returns a pointer to the internal hash structure.
199237
//
200238
// The EVP_MD_CTX memory layout has changed in OpenSSL 3
201239
// and the property holding the internal structure is no longer md_data but algctx.
202240
func (h *evpHash) hashState() unsafe.Pointer {
241+
if !h.marshallable || testNotMarshalable {
242+
return nil
243+
}
203244
switch vMajor {
204245
case 1:
205246
// https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/crypto/evp/evp_local.h#L12.

hash_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,27 @@ func cryptoToHash(h crypto.Hash) func() hash.Hash {
3939
return nil
4040
}
4141

42+
func TestHashNotMarshalable(t *testing.T) {
43+
h := openssl.NewSHA256()
44+
state, err := h.(encoding.BinaryMarshaler).MarshalBinary()
45+
if err != nil {
46+
t.Fatal(err)
47+
}
48+
*openssl.TestNotMarshalable = true
49+
defer func() {
50+
*openssl.TestNotMarshalable = false
51+
}()
52+
53+
_, err = h.(encoding.BinaryMarshaler).MarshalBinary()
54+
if err == nil {
55+
t.Error("expected error")
56+
}
57+
err = h.(encoding.BinaryUnmarshaler).UnmarshalBinary(state)
58+
if err == nil {
59+
t.Error("expected error")
60+
}
61+
}
62+
4263
func TestHash(t *testing.T) {
4364
msg := []byte("testing")
4465
var tests = []struct {

shims.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,11 @@ DEFINEFUNC_3_0(int, EVP_default_properties_is_fips_enabled, (GO_OSSL_LIB_CTX_PTR
190190
DEFINEFUNC_3_0(int, EVP_default_properties_enable_fips, (GO_OSSL_LIB_CTX_PTR libctx, int enable), (libctx, enable)) \
191191
DEFINEFUNC_3_0(int, OSSL_PROVIDER_available, (GO_OSSL_LIB_CTX_PTR libctx, const char *name), (libctx, name)) \
192192
DEFINEFUNC_3_0(GO_OSSL_PROVIDER_PTR, OSSL_PROVIDER_load, (GO_OSSL_LIB_CTX_PTR libctx, const char *name), (libctx, name)) \
193+
DEFINEFUNC_3_0(const char *, OSSL_PROVIDER_get0_name, (const GO_OSSL_PROVIDER_PTR prov), (prov)) \
193194
DEFINEFUNC_3_0(GO_EVP_MD_PTR, EVP_MD_fetch, (GO_OSSL_LIB_CTX_PTR ctx, const char *algorithm, const char *properties), (ctx, algorithm, properties)) \
194195
DEFINEFUNC_3_0(void, EVP_MD_free, (GO_EVP_MD_PTR md), (md)) \
195196
DEFINEFUNC_3_0(const char *, EVP_MD_get0_name, (const GO_EVP_MD_PTR md), (md)) \
197+
DEFINEFUNC_3_0(const GO_OSSL_PROVIDER_PTR, EVP_MD_get0_provider, (const GO_EVP_MD_PTR md), (md)) \
196198
DEFINEFUNC(int, RAND_bytes, (unsigned char *arg0, int arg1), (arg0, arg1)) \
197199
DEFINEFUNC_RENAMED_1_1(GO_EVP_MD_CTX_PTR, EVP_MD_CTX_new, EVP_MD_CTX_create, (void), ()) \
198200
DEFINEFUNC_RENAMED_1_1(void, EVP_MD_CTX_free, EVP_MD_CTX_destroy, (GO_EVP_MD_CTX_PTR ctx), (ctx)) \

0 commit comments

Comments
 (0)