From 11704a77d7b1eb2a8ff9c65e00fd6cfc906e14d3 Mon Sep 17 00:00:00 2001 From: Quim Muntal Date: Tue, 27 May 2025 17:48:30 +0200 Subject: [PATCH 1/2] Revert "[ms-go1.23-support] Support serializing SymCrypt hash objects (#281)" This reverts commit 9b2e96796e7d18de182a0b4dcc98c946fb4f3507. --- .github/workflows/test.yml | 13 +- hash.go | 512 ++++++++++++++++++++++++++++--------- hash_test.go | 116 +-------- params.go | 48 ---- provideropenssl.go | 239 ----------------- providersymcrypt.go | 379 --------------------------- shims.h | 14 - 7 files changed, 407 insertions(+), 914 deletions(-) delete mode 100644 params.go delete mode 100644 provideropenssl.go delete mode 100644 providersymcrypt.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8b981fb8..e3c0695e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,9 +5,9 @@ jobs: strategy: fail-fast: false matrix: - go-version: [1.23.x] + go-version: [1.20.x] openssl-version: [1.0.2, 1.1.0, 1.1.1, 3.0.1, 3.0.13, 3.1.5, 3.2.1] - runs-on: ubuntu-22.04 + runs-on: ubuntu-20.04 steps: - name: Install build tools run: sudo apt-get install -y build-essential @@ -22,7 +22,6 @@ jobs: - name: Check headers working-directory: ./cmd/checkheader run: go run . --ossl-include /usr/local/src/openssl-${{ matrix.openssl-version }}/include -shim ../../shims.h - if: ${{ matrix.openssl-version != '1.0.2' }} # Doesn't work on Ubuntu 22.04 - name: Set OpenSSL config and prove FIPS run: | sudo cp ./scripts/openssl-3.cnf /usr/local/ssl/openssl.cnf @@ -51,7 +50,7 @@ jobs: strategy: fail-fast: false matrix: - go-version: [1.23.x] + go-version: [1.20.x] openssl-version: [libcrypto-1_1-x64.dll, libcrypto-3-x64.dll] steps: - name: Install Go @@ -68,9 +67,9 @@ jobs: strategy: fail-fast: false matrix: - go-version: [1.23.x] - openssl-version: [/usr/local/opt/openssl@3/lib/libcrypto.3.dylib] - runs-on: macos-13 + go-version: [1.20.x] + openssl-version: [libcrypto.3.dylib] + runs-on: macos-12 steps: - name: Install Go uses: actions/setup-go@v3 diff --git a/hash.go b/hash.go index dc43990d..120fc412 100644 --- a/hash.go +++ b/hash.go @@ -14,25 +14,6 @@ import ( "unsafe" ) -const ( - magicMD5 = "md5\x01" - magic1 = "sha\x01" - magic224 = "sha\x02" - magic256 = "sha\x03" - magic384 = "sha\x04" - magic512_224 = "sha\x05" - magic512_256 = "sha\x06" - magic512 = "sha\x07" - - marshaledSizeMD5 = len(magicMD5) + 4*4 + 64 + 8 - marshaledSize1 = len(magic1) + 5*4 + 64 + 8 - marshaledSize256 = len(magic256) + 8*4 + 64 + 8 - marshaledSize512 = len(magic512) + 8*8 + 128 + 8 -) - -// maxHashSize is the size of SHA52 and SHA3_512, the largest hashes we support. -const maxHashSize = 64 - // NOTE: Implementation ported from https://go-review.googlesource.com/c/go/+/404295. // The cgo calls in this file are arranged to avoid marking the parameters as escaping. // To do that, we call noescape (including via addr). @@ -130,49 +111,35 @@ func SHA3_512(p []byte) (sum [64]byte) { return } -// provider is an identifier for a known provider. -type provider uint8 - -const ( - providerNone provider = iota - providerOSSLDefault - providerOSSLFIPS - providerSymCrypt -) - -var mdProviderCache sync.Map +var isMarshallableCache sync.Map -// mdProvider returns the provider for the given hash. -func mdProvider(ch crypto.Hash) provider { +// isHashMarshallable returns true if the memory layout of cb +// is known by this library and can therefore be marshalled. +func isHashMarshallable(ch crypto.Hash) bool { if vMajor == 1 { - return providerOSSLDefault + return true } - if v, ok := mdProviderCache.Load(ch); ok { - return v.(provider) + if v, ok := isMarshallableCache.Load(ch); ok { + return v.(bool) } md := cryptoHashToMD(ch) if md == nil { - return providerNone + return false } prov := C.go_openssl_EVP_MD_get0_provider(md) if prov == nil { - return providerNone + return false } cname := C.go_openssl_OSSL_PROVIDER_get0_name(prov) if cname == nil { - return providerNone + return false } - var provider provider - switch C.GoString(cname) { - case "default": - provider = providerOSSLDefault - case "fips": - provider = providerOSSLFIPS - case "symcryptprovider": - provider = providerSymCrypt - } - mdProviderCache.Store(ch, provider) - return provider + name := C.GoString(cname) + // We only know the memory layout of the built-in providers. + // See evpHash.hashState for more details. + marshallable := name == "default" || name == "fips" + isMarshallableCache.Store(ch, marshallable) + return marshallable } // evpHash implements generic hash methods. @@ -185,7 +152,7 @@ type evpHash struct { size int blockSize int - ch crypto.Hash + marshallable bool } func newEvpHash(ch crypto.Hash, size, blockSize int) *evpHash { @@ -205,7 +172,7 @@ func newEvpHash(ch crypto.Hash, size, blockSize int) *evpHash { size: size, blockSize: blockSize, - ch: ch, + marshallable: isHashMarshallable(ch), } runtime.SetFinalizer(h, (*evpHash).finalize) return h @@ -282,11 +249,11 @@ func (h *evpHash) clone() (*evpHash, error) { return nil, newOpenSSLError("EVP_MD_CTX_new") } cloned := &evpHash{ - ctx: ctx, - ctx2: ctx2, - size: h.size, - blockSize: h.blockSize, - ch: h.ch, + ctx: ctx, + ctx2: ctx2, + size: h.size, + blockSize: h.blockSize, + marshallable: h.marshallable, } runtime.SetFinalizer(cloned, (*evpHash).finalize) return cloned, nil @@ -294,67 +261,34 @@ func (h *evpHash) clone() (*evpHash, error) { var testNotMarshalable bool // Used in tests. -var errHashNotMarshallable = errors.New("openssl: hash state is not marshallable") - -func (d *evpHash) MarshalBinary() ([]byte, error) { - defer runtime.KeepAlive(d) - buf := make([]byte, 0, marshaledSize512) // stack allocate the buffer by setting the max size we support - magic, _ := cryptoHashEncodingInfo(d.ch) - if magic == "" || testNotMarshalable { - return nil, errHashNotMarshallable - } - switch mdProvider(d.ch) { - case providerOSSLDefault, providerOSSLFIPS: - return osslHashAppendBinary(d.ctx, d.ch, magic, buf) - case providerSymCrypt: - return symCryptHashAppendBinary(d.ctx, d.ch, magic, buf) +// hashState returns a pointer to the internal hash structure. +// +// The EVP_MD_CTX memory layout has changed in OpenSSL 3 +// and the property holding the internal structure is no longer md_data but algctx. +func (h *evpHash) hashState() unsafe.Pointer { + if !h.marshallable || testNotMarshalable { + return nil + } + switch vMajor { + case 1: + // https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/crypto/evp/evp_local.h#L12. + type mdCtx struct { + _ [2]unsafe.Pointer + _ C.ulong + md_data unsafe.Pointer + } + return (*mdCtx)(unsafe.Pointer(h.ctx)).md_data + case 3: + // https://github.com/openssl/openssl/blob/5675a5aaf6a2e489022bcfc18330dae9263e598e/crypto/evp/evp_local.h#L16. + type mdCtx struct { + _ [3]unsafe.Pointer + _ C.ulong + _ [3]unsafe.Pointer + algctx unsafe.Pointer + } + return (*mdCtx)(unsafe.Pointer(h.ctx)).algctx default: - return nil, errHashNotMarshallable - } -} - -func (d *evpHash) UnmarshalBinary(b []byte) error { - defer runtime.KeepAlive(d) - magic, size := cryptoHashEncodingInfo(d.ch) - if magic == "" || testNotMarshalable { - return errHashNotMarshallable - } - if len(b) < len(magic) || string(b[:len(magic)]) != string(magic[:]) { - return errors.New("openssl: invalid hash state identifier") - } - if len(b) != size { - return errors.New("openssl: invalid hash state size") - } - switch mdProvider(d.ch) { - case providerOSSLDefault, providerOSSLFIPS: - return osslHashUnmarshalBinary(d.ctx, d.ch, magic, b) - case providerSymCrypt: - return symCryptHashUnmarshalBinary(d.ctx, d.ch, magic, b) - default: - return errHashNotMarshallable - } -} - -func cryptoHashEncodingInfo(ch crypto.Hash) (magic string, size int) { - switch ch { - case crypto.MD5: - return magicMD5, marshaledSizeMD5 - case crypto.SHA1: - return magic1, marshaledSize1 - case crypto.SHA224: - return magic224, marshaledSize256 - case crypto.SHA256: - return magic256, marshaledSize256 - case crypto.SHA384: - return magic384, marshaledSize512 - case crypto.SHA512_224: - return magic512_224, marshaledSize512 - case crypto.SHA512_256: - return magic512_256, marshaledSize512 - case crypto.SHA512: - return magic512, marshaledSize512 - default: - return "", 0 + panic(errUnsupportedVersion()) } } @@ -384,6 +318,15 @@ func NewMD5() hash.Hash { } } +// md5State layout is taken from +// https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/include/openssl/md5.h#L33. +type md5State struct { + h [4]uint32 + nl, nh uint32 + x [64]byte + nx uint32 +} + type md5Hash struct { *evpHash out [16]byte @@ -394,6 +337,52 @@ func (h *md5Hash) Sum(in []byte) []byte { return append(in, h.out[:]...) } +const ( + md5Magic = "md5\x01" + md5MarshaledSize = len(md5Magic) + 4*4 + 64 + 8 +) + +func (h *md5Hash) MarshalBinary() ([]byte, error) { + d := (*md5State)(h.hashState()) + if d == nil { + return nil, errors.New("crypto/md5: can't retrieve hash state") + } + b := make([]byte, 0, md5MarshaledSize) + b = append(b, md5Magic...) + b = appendUint32(b, d.h[0]) + b = appendUint32(b, d.h[1]) + b = appendUint32(b, d.h[2]) + b = appendUint32(b, d.h[3]) + b = append(b, d.x[:d.nx]...) + b = b[:len(b)+len(d.x)-int(d.nx)] // already zero + b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29) + return b, nil +} + +func (h *md5Hash) UnmarshalBinary(b []byte) error { + if len(b) < len(md5Magic) || string(b[:len(md5Magic)]) != md5Magic { + return errors.New("crypto/md5: invalid hash state identifier") + } + if len(b) != md5MarshaledSize { + return errors.New("crypto/md5: invalid hash state size") + } + d := (*md5State)(h.hashState()) + if d == nil { + return errors.New("crypto/md5: can't retrieve hash state") + } + b = b[len(md5Magic):] + b, d.h[0] = consumeUint32(b) + b, d.h[1] = consumeUint32(b) + b, d.h[2] = consumeUint32(b) + b, d.h[3] = consumeUint32(b) + b = b[copy(d.x[:], b):] + _, n := consumeUint64(b) + d.nl = uint32(n << 3) + d.nh = uint32(n >> 29) + d.nx = uint32(n) % 64 + return nil +} + // NewSHA1 returns a new SHA1 hash. func NewSHA1() hash.Hash { return &sha1Hash{ @@ -411,6 +400,63 @@ func (h *sha1Hash) Sum(in []byte) []byte { return append(in, h.out[:]...) } +// sha1State layout is taken from +// https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/include/openssl/sha.h#L34. +type sha1State struct { + h [5]uint32 + nl, nh uint32 + x [64]byte + nx uint32 +} + +const ( + sha1Magic = "sha\x01" + sha1MarshaledSize = len(sha1Magic) + 5*4 + 64 + 8 +) + +func (h *sha1Hash) MarshalBinary() ([]byte, error) { + d := (*sha1State)(h.hashState()) + if d == nil { + return nil, errors.New("crypto/sha1: can't retrieve hash state") + } + b := make([]byte, 0, sha1MarshaledSize) + b = append(b, sha1Magic...) + b = appendUint32(b, d.h[0]) + b = appendUint32(b, d.h[1]) + b = appendUint32(b, d.h[2]) + b = appendUint32(b, d.h[3]) + b = appendUint32(b, d.h[4]) + b = append(b, d.x[:d.nx]...) + b = b[:len(b)+len(d.x)-int(d.nx)] // already zero + b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29) + return b, nil +} + +func (h *sha1Hash) UnmarshalBinary(b []byte) error { + if len(b) < len(sha1Magic) || string(b[:len(sha1Magic)]) != sha1Magic { + return errors.New("crypto/sha1: invalid hash state identifier") + } + if len(b) != sha1MarshaledSize { + return errors.New("crypto/sha1: invalid hash state size") + } + d := (*sha1State)(h.hashState()) + if d == nil { + return errors.New("crypto/sha1: can't retrieve hash state") + } + b = b[len(sha1Magic):] + b, d.h[0] = consumeUint32(b) + b, d.h[1] = consumeUint32(b) + b, d.h[2] = consumeUint32(b) + b, d.h[3] = consumeUint32(b) + b, d.h[4] = consumeUint32(b) + b = b[copy(d.x[:], b):] + _, n := consumeUint64(b) + d.nl = uint32(n << 3) + d.nh = uint32(n >> 29) + d.nx = uint32(n) % 64 + return nil +} + // NewSHA224 returns a new SHA224 hash. func NewSHA224() hash.Hash { return &sha224Hash{ @@ -445,6 +491,119 @@ func (h *sha256Hash) Sum(in []byte) []byte { return append(in, h.out[:]...) } +const ( + magic224 = "sha\x02" + magic256 = "sha\x03" + marshaledSize256 = len(magic256) + 8*4 + 64 + 8 +) + +// sha256State layout is taken from +// https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/include/openssl/sha.h#L51. +type sha256State struct { + h [8]uint32 + nl, nh uint32 + x [64]byte + nx uint32 +} + +func (h *sha224Hash) MarshalBinary() ([]byte, error) { + d := (*sha256State)(h.hashState()) + if d == nil { + return nil, errors.New("crypto/sha256: can't retrieve hash state") + } + b := make([]byte, 0, marshaledSize256) + b = append(b, magic224...) + b = appendUint32(b, d.h[0]) + b = appendUint32(b, d.h[1]) + b = appendUint32(b, d.h[2]) + b = appendUint32(b, d.h[3]) + b = appendUint32(b, d.h[4]) + b = appendUint32(b, d.h[5]) + b = appendUint32(b, d.h[6]) + b = appendUint32(b, d.h[7]) + b = append(b, d.x[:d.nx]...) + b = b[:len(b)+len(d.x)-int(d.nx)] // already zero + b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29) + return b, nil +} + +func (h *sha256Hash) MarshalBinary() ([]byte, error) { + d := (*sha256State)(h.hashState()) + if d == nil { + return nil, errors.New("crypto/sha256: can't retrieve hash state") + } + b := make([]byte, 0, marshaledSize256) + b = append(b, magic256...) + b = appendUint32(b, d.h[0]) + b = appendUint32(b, d.h[1]) + b = appendUint32(b, d.h[2]) + b = appendUint32(b, d.h[3]) + b = appendUint32(b, d.h[4]) + b = appendUint32(b, d.h[5]) + b = appendUint32(b, d.h[6]) + b = appendUint32(b, d.h[7]) + b = append(b, d.x[:d.nx]...) + b = b[:len(b)+len(d.x)-int(d.nx)] // already zero + b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29) + return b, nil +} + +func (h *sha224Hash) UnmarshalBinary(b []byte) error { + if len(b) < len(magic224) || string(b[:len(magic224)]) != magic224 { + return errors.New("crypto/sha256: invalid hash state identifier") + } + if len(b) != marshaledSize256 { + return errors.New("crypto/sha256: invalid hash state size") + } + d := (*sha256State)(h.hashState()) + if d == nil { + return errors.New("crypto/sha256: can't retrieve hash state") + } + b = b[len(magic224):] + b, d.h[0] = consumeUint32(b) + b, d.h[1] = consumeUint32(b) + b, d.h[2] = consumeUint32(b) + b, d.h[3] = consumeUint32(b) + b, d.h[4] = consumeUint32(b) + b, d.h[5] = consumeUint32(b) + b, d.h[6] = consumeUint32(b) + b, d.h[7] = consumeUint32(b) + b = b[copy(d.x[:], b):] + _, n := consumeUint64(b) + d.nl = uint32(n << 3) + d.nh = uint32(n >> 29) + d.nx = uint32(n) % 64 + return nil +} + +func (h *sha256Hash) UnmarshalBinary(b []byte) error { + if len(b) < len(magic256) || string(b[:len(magic256)]) != magic256 { + return errors.New("crypto/sha256: invalid hash state identifier") + } + if len(b) != marshaledSize256 { + return errors.New("crypto/sha256: invalid hash state size") + } + d := (*sha256State)(h.hashState()) + if d == nil { + return errors.New("crypto/sha256: can't retrieve hash state") + } + b = b[len(magic256):] + b, d.h[0] = consumeUint32(b) + b, d.h[1] = consumeUint32(b) + b, d.h[2] = consumeUint32(b) + b, d.h[3] = consumeUint32(b) + b, d.h[4] = consumeUint32(b) + b, d.h[5] = consumeUint32(b) + b, d.h[6] = consumeUint32(b) + b, d.h[7] = consumeUint32(b) + b = b[copy(d.x[:], b):] + _, n := consumeUint64(b) + d.nl = uint32(n << 3) + d.nh = uint32(n >> 29) + d.nx = uint32(n) % 64 + return nil +} + // Clone returns a new [hash.Hash] object that is a deep clone of itself. // The duplicate object contains all state and data contained in the // original object at the point of duplication. @@ -501,6 +660,127 @@ func (h *sha512Hash) Sum(in []byte) []byte { return append(in, h.out[:]...) } +// sha512State layout is taken from +// https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/include/openssl/sha.h#L95. +type sha512State struct { + h [8]uint64 + nl, nh uint64 + x [128]byte + nx uint32 +} + +const ( + magic384 = "sha\x04" + magic512_224 = "sha\x05" + magic512_256 = "sha\x06" + magic512 = "sha\x07" + marshaledSize512 = len(magic512) + 8*8 + 128 + 8 +) + +func (h *sha384Hash) MarshalBinary() ([]byte, error) { + d := (*sha512State)(h.hashState()) + if d == nil { + return nil, errors.New("crypto/sha512: can't retrieve hash state") + } + b := make([]byte, 0, marshaledSize512) + b = append(b, magic384...) + b = appendUint64(b, d.h[0]) + b = appendUint64(b, d.h[1]) + b = appendUint64(b, d.h[2]) + b = appendUint64(b, d.h[3]) + b = appendUint64(b, d.h[4]) + b = appendUint64(b, d.h[5]) + b = appendUint64(b, d.h[6]) + b = appendUint64(b, d.h[7]) + b = append(b, d.x[:d.nx]...) + b = b[:len(b)+len(d.x)-int(d.nx)] // already zero + b = appendUint64(b, d.nl>>3|d.nh<<61) + return b, nil +} + +func (h *sha512Hash) MarshalBinary() ([]byte, error) { + d := (*sha512State)(h.hashState()) + if d == nil { + return nil, errors.New("crypto/sha512: can't retrieve hash state") + } + b := make([]byte, 0, marshaledSize512) + b = append(b, magic512...) + b = appendUint64(b, d.h[0]) + b = appendUint64(b, d.h[1]) + b = appendUint64(b, d.h[2]) + b = appendUint64(b, d.h[3]) + b = appendUint64(b, d.h[4]) + b = appendUint64(b, d.h[5]) + b = appendUint64(b, d.h[6]) + b = appendUint64(b, d.h[7]) + b = append(b, d.x[:d.nx]...) + b = b[:len(b)+len(d.x)-int(d.nx)] // already zero + b = appendUint64(b, d.nl>>3|d.nh<<61) + return b, nil +} + +func (h *sha384Hash) UnmarshalBinary(b []byte) error { + if len(b) < len(magic512) { + return errors.New("crypto/sha512: invalid hash state identifier") + } + if string(b[:len(magic384)]) != magic384 { + return errors.New("crypto/sha512: invalid hash state identifier") + } + if len(b) != marshaledSize512 { + return errors.New("crypto/sha512: invalid hash state size") + } + d := (*sha512State)(h.hashState()) + if d == nil { + return errors.New("crypto/sha512: can't retrieve hash state") + } + b = b[len(magic512):] + b, d.h[0] = consumeUint64(b) + b, d.h[1] = consumeUint64(b) + b, d.h[2] = consumeUint64(b) + b, d.h[3] = consumeUint64(b) + b, d.h[4] = consumeUint64(b) + b, d.h[5] = consumeUint64(b) + b, d.h[6] = consumeUint64(b) + b, d.h[7] = consumeUint64(b) + b = b[copy(d.x[:], b):] + _, n := consumeUint64(b) + d.nl = n << 3 + d.nh = n >> 61 + d.nx = uint32(n) % 128 + return nil +} + +func (h *sha512Hash) UnmarshalBinary(b []byte) error { + if len(b) < len(magic512) { + return errors.New("crypto/sha512: invalid hash state identifier") + } + if string(b[:len(magic512)]) != magic512 { + return errors.New("crypto/sha512: invalid hash state identifier") + } + if len(b) != marshaledSize512 { + return errors.New("crypto/sha512: invalid hash state size") + } + d := (*sha512State)(h.hashState()) + if d == nil { + return errors.New("crypto/sha512: can't retrieve hash state") + } + b = b[len(magic512):] + b, d.h[0] = consumeUint64(b) + b, d.h[1] = consumeUint64(b) + b, d.h[2] = consumeUint64(b) + b, d.h[3] = consumeUint64(b) + b, d.h[4] = consumeUint64(b) + b, d.h[5] = consumeUint64(b) + b, d.h[6] = consumeUint64(b) + b, d.h[7] = consumeUint64(b) + b = b[copy(d.x[:], b):] + _, n := consumeUint64(b) + d.nl = n << 3 + d.nh = n >> 61 + d.nx = uint32(n) % 128 + return nil +} + // Clone returns a new [hash.Hash] object that is a deep clone of itself. // The duplicate object contains all state and data contained in the // original object at the point of duplication. diff --git a/hash_test.go b/hash_test.go index 9f9d2b7d..c7103e28 100644 --- a/hash_test.go +++ b/hash_test.go @@ -6,15 +6,8 @@ import ( "encoding" "hash" "io" - "strings" "testing" - // Blank imports to ensure that the hash functions are registered. - _ "crypto/md5" - _ "crypto/sha1" - _ "crypto/sha256" - _ "crypto/sha512" - "github.com/golang-fips/openssl/v2" ) @@ -160,118 +153,20 @@ func TestHash(t *testing.T) { if !bytes.Equal(sum, initSum) { t.Errorf("got:%x want:%x", sum, initSum) } - }) - } -} - -type hashEncoding interface { - hash.Hash - encoding.BinaryMarshaler - encoding.BinaryUnmarshaler -} - -type hashEncodingAppender interface { - hashEncoding - AppendBinary(b []byte) ([]byte, error) -} - -func TestHash_BinaryMarshaler(t *testing.T) { - msg := []byte("testing") - for _, ch := range []crypto.Hash{crypto.MD4, crypto.MD5, crypto.SHA1, crypto.SHA224, crypto.SHA256, crypto.SHA384, crypto.SHA512} { - t.Run(ch.String(), func(t *testing.T) { - t.Parallel() - if !openssl.SupportsHash(ch) { - t.Skip("hash not supported") - } - hashMarshaler, ok := cryptoToHash(ch)().(hashEncoding) - if !ok { - t.Fatal("BinaryMarshaler not supported") - } - - if _, err := hashMarshaler.Write(msg); err != nil { - t.Fatalf("Write failed: %v", err) - } - - state, err := hashMarshaler.MarshalBinary() - if err != nil { - if strings.Contains(err.Error(), "hash state is not marshallable") { - t.Skip("BinaryMarshaler not supported") - } - t.Fatalf("MarshalBinary failed: %v", err) - } - - hashUnmarshaler := cryptoToHash(ch)().(hashEncoding) - if err := hashUnmarshaler.UnmarshalBinary(state); err != nil { - t.Fatalf("UnmarshalBinary failed: %v", err) - } - - if actual, actual2 := hashMarshaler.Sum(nil), hashUnmarshaler.Sum(nil); !bytes.Equal(actual, actual2) { - t.Errorf("0x%x != appended 0x%x", actual, actual2) - } - - // Test that the hash state is compatible with native Go. - h, ok := ch.New().(hashEncoding) - if !ok { - // The standard library doesn't support encoding this hash. - // Nothing else to do. - return - } - h.Write(msg) - stateh, err := h.(encoding.BinaryMarshaler).MarshalBinary() - if err != nil { - t.Error(err) - } - if !bytes.Equal(state, stateh) { - t.Errorf("got 0x%x != want 0x%x", state, stateh) - } - h = ch.New().(hashEncoding) - if err := h.UnmarshalBinary(state); err != nil { - t.Error(err) - } - }) - } -} - -func TestHash_ByteWriter(t *testing.T) { - msg := []byte("testing") - for _, ch := range []crypto.Hash{crypto.MD5, crypto.SHA1, crypto.SHA224, crypto.SHA256, crypto.SHA384, crypto.SHA512} { - t.Run(ch.String(), func(t *testing.T) { - t.Parallel() - if !openssl.SupportsHash(ch) { - t.Skip("not supported") - } - bwh := cryptoToHash(ch)().(interface { - hash.Hash - io.ByteWriter - }) - initSum := bwh.Sum(nil) + bw := h.(io.ByteWriter) for i := 0; i < len(msg); i++ { - bwh.WriteByte(msg[i]) + bw.WriteByte(msg[i]) } - bwh.Reset() - sum := bwh.Sum(nil) + h.Reset() + sum = h.Sum(nil) if !bytes.Equal(sum, initSum) { t.Errorf("got:%x want:%x", sum, initSum) } - }) - } -} -func TestHash_StringWriter(t *testing.T) { - msg := []byte("testing") - for _, ch := range []crypto.Hash{crypto.MD5, crypto.SHA1, crypto.SHA224, crypto.SHA256, crypto.SHA384, crypto.SHA512} { - t.Run(ch.String(), func(t *testing.T) { - t.Parallel() - if !openssl.SupportsHash(ch) { - t.Skip("not supported") - } - h := cryptoToHash(ch)() - initSum := h.Sum(nil) - h.(io.StringWriter).WriteString("") h.(io.StringWriter).WriteString(string(msg)) h.Reset() - sum := h.Sum(nil) + sum = h.Sum(nil) if !bytes.Equal(sum, initSum) { t.Errorf("got:%x want:%x", sum, initSum) } @@ -327,7 +222,6 @@ func TestHash_OneShot(t *testing.T) { if !openssl.SupportsHash(tt.h) { t.Skip("skipping: not supported") } - _ = tt.oneShot(nil) // test that does not panic got := tt.oneShot(msg) h := cryptoToHash(tt.h)() h.Write(msg) diff --git a/params.go b/params.go deleted file mode 100644 index fd66fff1..00000000 --- a/params.go +++ /dev/null @@ -1,48 +0,0 @@ -//go:build !cmd_go_bootstrap - -package openssl - -// #include "goopenssl.h" -import "C" -import ( - "unsafe" -) - -const _OSSL_PARAM_UNMODIFIED uint = uint(^uintptr(0)) - -// _OSSL_PARAM is a structure to pass or request object parameters. -// https://docs.openssl.org/3.0/man3/OSSL_PARAM/. -type _OSSL_PARAM struct { - Key *C.char - DataType uint32 - Data unsafe.Pointer - DataSize uint - ReturnSize uint -} - -func ossl_param_construct(key *C.char, dataType uint32, data unsafe.Pointer, dataSize int) _OSSL_PARAM { - return _OSSL_PARAM{ - Key: key, - DataType: dataType, - Data: data, - DataSize: uint(dataSize), - ReturnSize: _OSSL_PARAM_UNMODIFIED, - } -} - -func _OSSL_PARAM_construct_octet_string(key *C.char, data unsafe.Pointer, dataSize int) _OSSL_PARAM { - return ossl_param_construct(key, C.GO_OSSL_PARAM_OCTET_STRING, data, dataSize) -} - -func _OSSL_PARAM_construct_int32(key *C.char, data *int32) _OSSL_PARAM { - return ossl_param_construct(key, C.GO_OSSL_PARAM_INTEGER, unsafe.Pointer(data), 4) -} - -func _OSSL_PARAM_construct_end() _OSSL_PARAM { - return _OSSL_PARAM{} -} - -func _OSSL_PARAM_modified(param *_OSSL_PARAM) bool { - // If ReturnSize is not set, the parameter has not been modified. - return param != nil && param.ReturnSize != _OSSL_PARAM_UNMODIFIED -} diff --git a/provideropenssl.go b/provideropenssl.go deleted file mode 100644 index 912bcbbf..00000000 --- a/provideropenssl.go +++ /dev/null @@ -1,239 +0,0 @@ -//go:build !cmd_go_bootstrap - -package openssl - -// #include "goopenssl.h" -import "C" -import ( - "crypto" - "errors" - "unsafe" -) - -// This file contains code specific to the built-in OpenSSL providers. - -// _OSSL_MD5_CTX layout is taken from -// https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/include/openssl/md5.h#L33. -type _OSSL_MD5_CTX struct { - h [4]uint32 - nl, nh uint32 - x [64]byte - nx uint32 -} - -func (d *_OSSL_MD5_CTX) UnmarshalBinary(b []byte) error { - b, d.h[0] = consumeUint32(b) - b, d.h[1] = consumeUint32(b) - b, d.h[2] = consumeUint32(b) - b, d.h[3] = consumeUint32(b) - b = b[copy(d.x[:], b):] - _, n := consumeUint64(b) - d.nl = uint32(n << 3) - d.nh = uint32(n >> 29) - d.nx = uint32(n) % 64 - return nil -} - -func (d *_OSSL_MD5_CTX) AppendBinary(buf []byte) ([]byte, error) { - buf = appendUint32(buf, d.h[0]) - buf = appendUint32(buf, d.h[1]) - buf = appendUint32(buf, d.h[2]) - buf = appendUint32(buf, d.h[3]) - buf = append(buf, d.x[:d.nx]...) - buf = append(buf, make([]byte, len(d.x)-int(d.nx))...) - buf = appendUint64(buf, uint64(d.nl)>>3|uint64(d.nh)<<29) - return buf, nil -} - -// _OSSL_SHA_CTX layout is taken from -// https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/include/openssl/sha.h#L34. -type _OSSL_SHA_CTX struct { - h [5]uint32 - nl, nh uint32 - x [64]byte - nx uint32 -} - -func (d *_OSSL_SHA_CTX) UnmarshalBinary(b []byte) error { - b, d.h[0] = consumeUint32(b) - b, d.h[1] = consumeUint32(b) - b, d.h[2] = consumeUint32(b) - b, d.h[3] = consumeUint32(b) - b, d.h[4] = consumeUint32(b) - b = b[copy(d.x[:], b):] - _, n := consumeUint64(b) - d.nl = uint32(n << 3) - d.nh = uint32(n >> 29) - d.nx = uint32(n) % 64 - return nil -} - -func (d *_OSSL_SHA_CTX) AppendBinary(buf []byte) ([]byte, error) { - buf = appendUint32(buf, d.h[0]) - buf = appendUint32(buf, d.h[1]) - buf = appendUint32(buf, d.h[2]) - buf = appendUint32(buf, d.h[3]) - buf = appendUint32(buf, d.h[4]) - buf = append(buf, d.x[:d.nx]...) - buf = append(buf, make([]byte, len(d.x)-int(d.nx))...) - buf = appendUint64(buf, uint64(d.nl)>>3|uint64(d.nh)<<29) - return buf, nil -} - -// _OSSL_SHA256_CTX layout is taken from -// https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/include/openssl/sha.h#L51. -type _OSSL_SHA256_CTX struct { - h [8]uint32 - nl, nh uint32 - x [64]byte - nx uint32 -} - -func (d *_OSSL_SHA256_CTX) UnmarshalBinary(b []byte) error { - b, d.h[0] = consumeUint32(b) - b, d.h[1] = consumeUint32(b) - b, d.h[2] = consumeUint32(b) - b, d.h[3] = consumeUint32(b) - b, d.h[4] = consumeUint32(b) - b, d.h[5] = consumeUint32(b) - b, d.h[6] = consumeUint32(b) - b, d.h[7] = consumeUint32(b) - b = b[copy(d.x[:], b):] - _, n := consumeUint64(b) - d.nl = uint32(n << 3) - d.nh = uint32(n >> 29) - d.nx = uint32(n) % 64 - return nil -} - -func (d *_OSSL_SHA256_CTX) AppendBinary(buf []byte) ([]byte, error) { - buf = appendUint32(buf, d.h[0]) - buf = appendUint32(buf, d.h[1]) - buf = appendUint32(buf, d.h[2]) - buf = appendUint32(buf, d.h[3]) - buf = appendUint32(buf, d.h[4]) - buf = appendUint32(buf, d.h[5]) - buf = appendUint32(buf, d.h[6]) - buf = appendUint32(buf, d.h[7]) - buf = append(buf, d.x[:d.nx]...) - buf = append(buf, make([]byte, len(d.x)-int(d.nx))...) - buf = appendUint64(buf, uint64(d.nl)>>3|uint64(d.nh)<<29) - return buf, nil -} - -// _OSSL_SHA512_CTX layout is taken from -// https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/include/openssl/sha.h#L95. -type _OSSL_SHA512_CTX struct { - h [8]uint64 - nl, nh uint64 - x [128]byte - nx uint32 -} - -func (d *_OSSL_SHA512_CTX) UnmarshalBinary(b []byte) error { - b, d.h[0] = consumeUint64(b) - b, d.h[1] = consumeUint64(b) - b, d.h[2] = consumeUint64(b) - b, d.h[3] = consumeUint64(b) - b, d.h[4] = consumeUint64(b) - b, d.h[5] = consumeUint64(b) - b, d.h[6] = consumeUint64(b) - b, d.h[7] = consumeUint64(b) - b = b[copy(d.x[:], b):] - _, n := consumeUint64(b) - d.nl = n << 3 - d.nh = n >> 61 - d.nx = uint32(n) % 128 - return nil -} - -func (d *_OSSL_SHA512_CTX) AppendBinary(buf []byte) ([]byte, error) { - buf = appendUint64(buf, d.h[0]) - buf = appendUint64(buf, d.h[1]) - buf = appendUint64(buf, d.h[2]) - buf = appendUint64(buf, d.h[3]) - buf = appendUint64(buf, d.h[4]) - buf = appendUint64(buf, d.h[5]) - buf = appendUint64(buf, d.h[6]) - buf = appendUint64(buf, d.h[7]) - buf = append(buf, d.x[:d.nx]...) - buf = append(buf, make([]byte, len(d.x)-int(d.nx))...) - buf = appendUint64(buf, d.nl>>3|d.nh<<61) - return buf, nil -} - -func getOSSLDigetsContext(ctx C.GO_EVP_MD_CTX_PTR) unsafe.Pointer { - switch vMajor { - case 1: - // https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/crypto/evp/evp_local.h#L12. - type mdCtx struct { - _ [2]unsafe.Pointer - _ uint32 - md_data unsafe.Pointer - } - return (*mdCtx)(unsafe.Pointer(ctx)).md_data - case 3: - // The EVP_MD_CTX memory layout has changed in OpenSSL 3 - // and the property holding the internal structure is no longer md_data but algctx. - // https://github.com/openssl/openssl/blob/5675a5aaf6a2e489022bcfc18330dae9263e598e/crypto/evp/evp_local.h#L16. - type mdCtx struct { - _ [3]unsafe.Pointer - _ uint32 - _ [3]unsafe.Pointer - algctx unsafe.Pointer - } - return (*mdCtx)(unsafe.Pointer(ctx)).algctx - default: - panic(errUnsupportedVersion()) - } -} - -var errHashStateInvalid = errors.New("openssl: can't retrieve hash state") - -func osslHashAppendBinary(ctx C.GO_EVP_MD_CTX_PTR, ch crypto.Hash, magic string, buf []byte) ([]byte, error) { - algctx := getOSSLDigetsContext(ctx) - if algctx == nil { - return nil, errHashStateInvalid - } - buf = append(buf, magic...) - switch ch { - case crypto.MD5: - d := (*_OSSL_MD5_CTX)(unsafe.Pointer(algctx)) - return d.AppendBinary(buf) - case crypto.SHA1: - d := (*_OSSL_SHA_CTX)(unsafe.Pointer(algctx)) - return d.AppendBinary(buf) - case crypto.SHA224, crypto.SHA256: - d := (*_OSSL_SHA256_CTX)(unsafe.Pointer(algctx)) - return d.AppendBinary(buf) - case crypto.SHA384, crypto.SHA512_224, crypto.SHA512_256, crypto.SHA512: - d := (*_OSSL_SHA512_CTX)(unsafe.Pointer(algctx)) - return d.AppendBinary(buf) - default: - panic("unsupported hash " + ch.String()) - } -} - -func osslHashUnmarshalBinary(ctx C.GO_EVP_MD_CTX_PTR, ch crypto.Hash, magic string, b []byte) error { - algctx := getOSSLDigetsContext(ctx) - if algctx == nil { - return errHashStateInvalid - } - b = b[len(magic):] - switch ch { - case crypto.MD5: - d := (*_OSSL_MD5_CTX)(unsafe.Pointer(algctx)) - return d.UnmarshalBinary(b) - case crypto.SHA1: - d := (*_OSSL_SHA_CTX)(unsafe.Pointer(algctx)) - return d.UnmarshalBinary(b) - case crypto.SHA224, crypto.SHA256: - d := (*_OSSL_SHA256_CTX)(unsafe.Pointer(algctx)) - return d.UnmarshalBinary(b) - case crypto.SHA384, crypto.SHA512_224, crypto.SHA512_256, crypto.SHA512: - d := (*_OSSL_SHA512_CTX)(unsafe.Pointer(algctx)) - return d.UnmarshalBinary(b) - default: - panic("unsupported hash " + ch.String()) - } -} diff --git a/providersymcrypt.go b/providersymcrypt.go deleted file mode 100644 index b2da8854..00000000 --- a/providersymcrypt.go +++ /dev/null @@ -1,379 +0,0 @@ -//go:build !cmd_go_bootstrap - -package openssl - -// #include "goopenssl.h" -import "C" -import ( - "crypto" - "encoding/binary" - "errors" - "runtime" - "sync" - "unsafe" -) - -// This file contains code specific to the SymCrypt provider. - -var ( - _SCOSSL_DIGEST_PARAM_STATE = C.CString("state") - _SCOSSL_DIGEST_PARAM_RECOMPUTE_CHECKSUM = C.CString("recompute_checksum") -) - -const ( - _SYMCRYPT_BLOB_MAGIC = 0x636D7973 // "cysm" in little-endian - - _SymCryptBlobTypeHashState = 0x100 - _SymCryptBlobTypeMd2State = _SymCryptBlobTypeHashState + 1 - _SymCryptBlobTypeMd4State = _SymCryptBlobTypeHashState + 2 - _SymCryptBlobTypeMd5State = _SymCryptBlobTypeHashState + 3 - _SymCryptBlobTypeSha1State = _SymCryptBlobTypeHashState + 4 - _SymCryptBlobTypeSha256State = _SymCryptBlobTypeHashState + 5 - _SymCryptBlobTypeSha384State = _SymCryptBlobTypeHashState + 6 - _SymCryptBlobTypeSha512State = _SymCryptBlobTypeHashState + 7 - _SymCryptBlobTypeSha3_256State = _SymCryptBlobTypeHashState + 8 - _SymCryptBlobTypeSha3_384State = _SymCryptBlobTypeHashState + 9 - _SymCryptBlobTypeSha3_512State = _SymCryptBlobTypeHashState + 10 - _SymCryptBlobTypeSha224State = _SymCryptBlobTypeHashState + 11 - _SymCryptBlobTypeSha512_224State = _SymCryptBlobTypeHashState + 12 - _SymCryptBlobTypeSha512_256State = _SymCryptBlobTypeHashState + 13 - _SymCryptBlobTypeSha3_224State = _SymCryptBlobTypeHashState + 14 - - _SYMCRYPT_MD5_STATE_EXPORT_SIZE = uint32(unsafe.Sizeof(_SYMCRYPT_MD5_STATE_EXPORT_BLOB{})) - _SYMCRYPT_SHA1_STATE_EXPORT_SIZE = uint32(unsafe.Sizeof(_SYMCRYPT_SHA1_STATE_EXPORT_BLOB{})) - _SYMCRYPT_SHA256_STATE_EXPORT_SIZE = uint32(unsafe.Sizeof(_SYMCRYPT_SHA256_STATE_EXPORT_BLOB{})) - _SYMCRYPT_SHA512_STATE_EXPORT_SIZE = uint32(unsafe.Sizeof(_SYMCRYPT_SHA512_STATE_EXPORT_BLOB{})) -) - -type _SYMCRYPT_BLOB_HEADER struct { - magic uint32 - size uint32 - _type uint32 -} - -type _SYMCRYPT_BLOB_TRAILER struct { - checksum [8]uint8 -} - -// _UINT64 is a 64-bit unsigned integer, stored in native endianess. -// It is used to represent a SymCrypt UINT64 type without making the -// parent struct 8-byte aligned, given that the Windows ABI makes -// the struct 4-byte aligned. -type _UINT64 [2]uint32 - -func newUINT64(v uint64) _UINT64 { - var u _UINT64 - if nativeEndian == binary.BigEndian { - u[0], u[1] = uint32(v>>32), uint32(v) - } else { - u[0], u[1] = uint32(v), uint32(v>>32) - } - return u -} - -func (u *_UINT64) uint64() uint64 { - if nativeEndian == binary.BigEndian { - return uint64(u[0])<<32 | (uint64(u[1])) - } - return uint64(u[0]) | (uint64(u[1]) << 32) -} - -// symCryptAppendBinary appends the binary representation of a SymCrypt state -// to the given destination slice. -func symCryptAppendBinary(dst, chain, buffer []byte, blength _UINT64) []byte { - length := blength.uint64() - var nx uint64 - if len(buffer) <= 64 { - nx = length & 0x3f - } else { - nx = length & 0x7f - } - dst = append(dst, chain...) - dst = append(dst, buffer[:nx]...) - dst = append(dst, make([]byte, len(buffer)-int(nx))...) - dst = appendUint64(dst, length) - return dst -} - -// symCryptUnmarshalBinary unmarshals the binary representation of a SymCrypt state -// from the given source slice. It returns the length of the data. -func symCryptUnmarshalBinary(d []byte, chain, buffer []byte) _UINT64 { - copy(chain[:], d) - d = d[len(chain):] - copy(buffer[:], d) - d = d[len(buffer):] - _, length := consumeUint64(d) - return newUINT64(length) -} - -// swapEndianessUint32 swaps the endianness of the given byte slice -// in place. It assumes the slice is a backup of a 32-bit integer array. -func swapEndianessUint32(d []uint8) { - for i := 0; i < len(d); i += 4 { - d[i], d[i+3] = d[i+3], d[i] - d[i+1], d[i+2] = d[i+2], d[i+1] - } - -} - -type _SYMCRYPT_MD5_STATE_EXPORT_BLOB struct { - header _SYMCRYPT_BLOB_HEADER - chain [16]uint8 // little endian - length _UINT64 // native endian - buffer [64]uint8 - _ [8]uint8 // reserved - _ _SYMCRYPT_BLOB_TRAILER -} - -func (b *_SYMCRYPT_MD5_STATE_EXPORT_BLOB) appendBinary(d []byte) ([]byte, error) { - // b.chain is little endian, but Go expects big endian, - // we need to swap the bytes. - swapEndianessUint32(b.chain[:]) - return symCryptAppendBinary(d, b.chain[:], b.buffer[:], b.length), nil -} - -func (b *_SYMCRYPT_MD5_STATE_EXPORT_BLOB) unmarshalBinary(d []byte) { - b.length = symCryptUnmarshalBinary(d, b.chain[:], b.buffer[:]) - swapEndianessUint32(b.chain[:]) -} - -type _SYMCRYPT_SHA1_STATE_EXPORT_BLOB struct { - header _SYMCRYPT_BLOB_HEADER - chain [20]uint8 // big endian - length _UINT64 // native endian - buffer [64]uint8 - _ [8]uint8 // reserved - _ _SYMCRYPT_BLOB_TRAILER -} - -func (b *_SYMCRYPT_SHA1_STATE_EXPORT_BLOB) appendBinary(d []byte) ([]byte, error) { - return symCryptAppendBinary(d, b.chain[:], b.buffer[:], b.length), nil -} - -func (b *_SYMCRYPT_SHA1_STATE_EXPORT_BLOB) unmarshalBinary(d []byte) { - b.length = symCryptUnmarshalBinary(d, b.chain[:], b.buffer[:]) -} - -type _SYMCRYPT_SHA256_STATE_EXPORT_BLOB struct { - header _SYMCRYPT_BLOB_HEADER - chain [32]uint8 // big endian - length _UINT64 // native endian - buffer [64]uint8 - _ [8]uint8 // reserved - _ _SYMCRYPT_BLOB_TRAILER -} - -func (b *_SYMCRYPT_SHA256_STATE_EXPORT_BLOB) appendBinary(d []byte) ([]byte, error) { - return symCryptAppendBinary(d, b.chain[:], b.buffer[:], b.length), nil -} - -func (b *_SYMCRYPT_SHA256_STATE_EXPORT_BLOB) unmarshalBinary(d []byte) { - b.length = symCryptUnmarshalBinary(d, b.chain[:], b.buffer[:]) -} - -type _SYMCRYPT_SHA512_STATE_EXPORT_BLOB struct { - header _SYMCRYPT_BLOB_HEADER - chain [64]uint8 // big endian - lengthL _UINT64 // native endian - lengthH _UINT64 // native endian - buffer [128]uint8 - _ [8]uint8 // reserved - _ _SYMCRYPT_BLOB_TRAILER -} - -func (b *_SYMCRYPT_SHA512_STATE_EXPORT_BLOB) appendBinary(d []byte) ([]byte, error) { - if b.lengthH.uint64() != 0 { - return nil, errors.New("exporting state with more than 2^63-1 bytes of data is not supported") - } - return symCryptAppendBinary(d, b.chain[:], b.buffer[:], b.lengthL), nil -} - -func (b *_SYMCRYPT_SHA512_STATE_EXPORT_BLOB) unmarshalBinary(d []byte) { - b.lengthL = symCryptUnmarshalBinary(d, b.chain[:], b.buffer[:]) -} - -func symCryptHashAppendBinary(ctx C.GO_EVP_MD_CTX_PTR, ch crypto.Hash, magic string, buf []byte) ([]byte, error) { - size, typ, serializable := symCryptHashStateInfo(ch) - if !serializable { - return nil, errHashNotMarshallable - } - state := make([]byte, size, _SYMCRYPT_SHA512_STATE_EXPORT_SIZE) // 512 is the largest size - var pinner runtime.Pinner - pinner.Pin(&state[0]) - defer pinner.Unpin() - params := [2]_OSSL_PARAM{ - _OSSL_PARAM_construct_octet_string(_SCOSSL_DIGEST_PARAM_STATE, unsafe.Pointer(&state[0]), len(state)), - _OSSL_PARAM_construct_end(), - } - if C.go_openssl_EVP_MD_CTX_get_params(ctx, (C.GO_OSSL_PARAM_PTR)(unsafe.Pointer(¶ms[0]))) != 1 { - return nil, newOpenSSLError("EVP_MD_CTX_get_params") - } - if !_OSSL_PARAM_modified(¶ms[0]) { - return nil, errors.New("EVP_MD_CTX_get_params did not retrieve the state") - } - - header := (*_SYMCRYPT_BLOB_HEADER)(unsafe.Pointer(&state[0])) - if header.magic != _SYMCRYPT_BLOB_MAGIC { - return nil, errors.New("invalid blob magic") - } - if header.size != size { - return nil, errors.New("invalid blob size") - } - if header._type != typ { - return nil, errors.New("invalid blob type") - } - - buf = append(buf, magic...) - switch ch { - case crypto.MD5: - blob := (*_SYMCRYPT_MD5_STATE_EXPORT_BLOB)(unsafe.Pointer(&state[0])) - return blob.appendBinary(buf) - case crypto.SHA1: - blob := (*_SYMCRYPT_SHA1_STATE_EXPORT_BLOB)(unsafe.Pointer(&state[0])) - return blob.appendBinary(buf) - case crypto.SHA224, crypto.SHA256: - blob := (*_SYMCRYPT_SHA256_STATE_EXPORT_BLOB)(unsafe.Pointer(&state[0])) - return blob.appendBinary(buf) - case crypto.SHA384, crypto.SHA512_224, crypto.SHA512_256, crypto.SHA512: - blob := (*_SYMCRYPT_SHA512_STATE_EXPORT_BLOB)(unsafe.Pointer(&state[0])) - return blob.appendBinary(buf) - default: - panic("unsupported hash " + ch.String()) - } -} - -func symCryptHashUnmarshalBinary(ctx C.GO_EVP_MD_CTX_PTR, ch crypto.Hash, magic string, b []byte) error { - size, typ, serializable := symCryptHashStateInfo(ch) - if !serializable { - return errHashNotMarshallable - } - hdr := _SYMCRYPT_BLOB_HEADER{ - magic: _SYMCRYPT_BLOB_MAGIC, - size: size, - _type: typ, - } - var blobPtr unsafe.Pointer - b = b[len(magic):] - switch ch { - case crypto.MD5: - var blob _SYMCRYPT_MD5_STATE_EXPORT_BLOB - blobPtr = unsafe.Pointer(&blob) - blob.header = hdr - blob.unmarshalBinary(b) - case crypto.SHA1: - var blob _SYMCRYPT_SHA1_STATE_EXPORT_BLOB - blobPtr = unsafe.Pointer(&blob) - blob.header = hdr - blob.unmarshalBinary(b) - case crypto.SHA224, crypto.SHA256: - var blob _SYMCRYPT_SHA256_STATE_EXPORT_BLOB - blobPtr = unsafe.Pointer(&blob) - blob.header = hdr - blob.unmarshalBinary(b) - case crypto.SHA384, crypto.SHA512_224, crypto.SHA512_256, crypto.SHA512: - var blob _SYMCRYPT_SHA512_STATE_EXPORT_BLOB - blobPtr = unsafe.Pointer(&blob) - blob.header = hdr - blob.unmarshalBinary(b) - default: - panic("unsupported hash " + ch.String()) - } - var checksum int32 = 1 - cbytesBlob := C.CBytes(unsafe.Slice((*byte)(blobPtr), hdr.size)) - defer C.free(cbytesBlob) - cbytesCheksum := C.CBytes(unsafe.Slice((*byte)(unsafe.Pointer(&checksum)), 4)) - defer C.free(cbytesCheksum) - params := [3]_OSSL_PARAM{ - _OSSL_PARAM_construct_octet_string(_SCOSSL_DIGEST_PARAM_STATE, cbytesBlob, int(hdr.size)), - _OSSL_PARAM_construct_int32(_SCOSSL_DIGEST_PARAM_RECOMPUTE_CHECKSUM, (*int32)(cbytesCheksum)), - _OSSL_PARAM_construct_end(), - } - if C.go_openssl_EVP_MD_CTX_set_params(ctx, (C.GO_OSSL_PARAM_PTR)(unsafe.Pointer(¶ms[0]))) != 1 { - return newOpenSSLError("EVP_MD_CTX_set_params") - } - return nil -} - -func symCryptHashStateInfo(ch crypto.Hash) (size, typ uint32, serializable bool) { - switch ch { - case crypto.MD5: - return _SYMCRYPT_MD5_STATE_EXPORT_SIZE, _SymCryptBlobTypeMd5State, symCryptHashStateSerializableMD5() - case crypto.SHA1: - return _SYMCRYPT_SHA1_STATE_EXPORT_SIZE, _SymCryptBlobTypeSha1State, symCryptHashStateSerializableSHA1() - case crypto.SHA224: - return _SYMCRYPT_SHA256_STATE_EXPORT_SIZE, _SymCryptBlobTypeSha224State, symCryptHashStateSerializableSHA224() - case crypto.SHA256: - return _SYMCRYPT_SHA256_STATE_EXPORT_SIZE, _SymCryptBlobTypeSha256State, symCryptHashStateSerializableSHA256() - case crypto.SHA384: - return _SYMCRYPT_SHA512_STATE_EXPORT_SIZE, _SymCryptBlobTypeSha384State, symCryptHashStateSerializableSHA384() - case crypto.SHA512_224: - return _SYMCRYPT_SHA512_STATE_EXPORT_SIZE, _SymCryptBlobTypeSha512_224State, symCryptHashStateSerializableSHA512_224() - case crypto.SHA512_256: - return _SYMCRYPT_SHA512_STATE_EXPORT_SIZE, _SymCryptBlobTypeSha512_256State, symCryptHashStateSerializableSHA512_256() - case crypto.SHA512: - return _SYMCRYPT_SHA512_STATE_EXPORT_SIZE, _SymCryptBlobTypeSha512State, symCryptHashStateSerializableSHA512() - default: - panic("unsupported hash " + ch.String()) - } -} - -var ( - symCryptHashStateSerializableMD5 = sync.OnceValue(func() bool { - return isSymCryptHashStateSerializable(crypto.MD5) - }) - symCryptHashStateSerializableSHA1 = sync.OnceValue(func() bool { - return isSymCryptHashStateSerializable(crypto.SHA1) - }) - symCryptHashStateSerializableSHA224 = sync.OnceValue(func() bool { - return isSymCryptHashStateSerializable(crypto.SHA224) - }) - symCryptHashStateSerializableSHA256 = sync.OnceValue(func() bool { - return isSymCryptHashStateSerializable(crypto.SHA256) - }) - symCryptHashStateSerializableSHA384 = sync.OnceValue(func() bool { - return isSymCryptHashStateSerializable(crypto.SHA384) - }) - symCryptHashStateSerializableSHA512_224 = sync.OnceValue(func() bool { - return isSymCryptHashStateSerializable(crypto.SHA512_224) - }) - symCryptHashStateSerializableSHA512_256 = sync.OnceValue(func() bool { - return isSymCryptHashStateSerializable(crypto.SHA512_256) - }) - symCryptHashStateSerializableSHA512 = sync.OnceValue(func() bool { - return isSymCryptHashStateSerializable(crypto.SHA512) - }) -) - -// isSymCryptHashStateSerializable checks if the SymCrypt hash state is serializable. -func isSymCryptHashStateSerializable(ch crypto.Hash) bool { - md := cryptoHashToMD(ch) - if md == nil { - return false - } - ctx := C.go_openssl_EVP_MD_CTX_new() - if ctx == nil { - return false - } - defer C.go_openssl_EVP_MD_CTX_free(ctx) - if C.go_openssl_EVP_DigestInit_ex(ctx, md, nil) != 1 { - return false - } - params := C.go_openssl_EVP_MD_CTX_gettable_params(ctx) - if params == nil { - return false - } - if C.go_openssl_OSSL_PARAM_locate_const(params, _SCOSSL_DIGEST_PARAM_STATE) == nil { - return false - } - params = C.go_openssl_EVP_MD_CTX_settable_params(ctx) - if params == nil { - return false - } - if C.go_openssl_OSSL_PARAM_locate_const(params, _SCOSSL_DIGEST_PARAM_STATE) == nil { - return false - } - if C.go_openssl_OSSL_PARAM_locate_const(params, _SCOSSL_DIGEST_PARAM_RECOMPUTE_CHECKSUM) == nil { - return false - } - return true -} diff --git a/shims.h b/shims.h index 436380c3..deddeb93 100644 --- a/shims.h +++ b/shims.h @@ -29,14 +29,6 @@ enum { GO_EVP_PKEY_KEYPAIR = 0x87 }; -// #if OPENSSL_VERSION_NUMBER >= 0x30000000L -// #include -// #endif -enum { - GO_OSSL_PARAM_INTEGER = 1, - GO_OSSL_PARAM_OCTET_STRING = 5 -}; - // #include enum { GO_EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID = 0x1001 @@ -209,10 +201,6 @@ DEFINEFUNC_RENAMED_1_1(GO_EVP_MD_CTX_PTR, EVP_MD_CTX_new, EVP_MD_CTX_create, (vo DEFINEFUNC_RENAMED_1_1(void, EVP_MD_CTX_free, EVP_MD_CTX_destroy, (GO_EVP_MD_CTX_PTR ctx), (ctx)) \ DEFINEFUNC(int, EVP_MD_CTX_copy, (GO_EVP_MD_CTX_PTR out, const GO_EVP_MD_CTX_PTR in), (out, in)) \ DEFINEFUNC(int, EVP_MD_CTX_copy_ex, (GO_EVP_MD_CTX_PTR out, const GO_EVP_MD_CTX_PTR in), (out, in)) \ -DEFINEFUNC_3_0(const GO_OSSL_PARAM_PTR, EVP_MD_CTX_gettable_params, (GO_EVP_MD_CTX_PTR ctx), (ctx)) \ -DEFINEFUNC_3_0(const GO_OSSL_PARAM_PTR, EVP_MD_CTX_settable_params, (GO_EVP_MD_CTX_PTR ctx), (ctx)) \ -DEFINEFUNC_3_0(int, EVP_MD_CTX_get_params, (GO_EVP_MD_CTX_PTR ctx, GO_OSSL_PARAM_PTR params), (ctx, params)) \ -DEFINEFUNC_3_0(int, EVP_MD_CTX_set_params, (GO_EVP_MD_CTX_PTR ctx, const GO_OSSL_PARAM_PTR params), (ctx, params)) \ DEFINEFUNC(int, EVP_Digest, (const void *data, size_t count, unsigned char *md, unsigned int *size, const GO_EVP_MD_PTR type, GO_ENGINE_PTR impl), (data, count, md, size, type, impl)) \ DEFINEFUNC(int, EVP_DigestInit_ex, (GO_EVP_MD_CTX_PTR ctx, const GO_EVP_MD_PTR type, GO_ENGINE_PTR impl), (ctx, type, impl)) \ DEFINEFUNC(int, EVP_DigestInit, (GO_EVP_MD_CTX_PTR ctx, const GO_EVP_MD_PTR type), (ctx, type)) \ @@ -362,13 +350,11 @@ DEFINEFUNC_3_0(int, EVP_MAC_init, (GO_EVP_MAC_CTX_PTR ctx, const unsigned char * DEFINEFUNC_3_0(int, EVP_MAC_update, (GO_EVP_MAC_CTX_PTR ctx, const unsigned char *data, size_t datalen), (ctx, data, datalen)) \ DEFINEFUNC_3_0(int, EVP_MAC_final, (GO_EVP_MAC_CTX_PTR ctx, unsigned char *out, size_t *outl, size_t outsize), (ctx, out, outl, outsize)) \ DEFINEFUNC_3_0(void, OSSL_PARAM_free, (GO_OSSL_PARAM_PTR p), (p)) \ -DEFINEFUNC_3_0(const GO_OSSL_PARAM_PTR, OSSL_PARAM_locate_const, (const GO_OSSL_PARAM_PTR p, const char *key), (p, key)) \ DEFINEFUNC_3_0(GO_OSSL_PARAM_BLD_PTR, OSSL_PARAM_BLD_new, (void), ()) \ DEFINEFUNC_3_0(void, OSSL_PARAM_BLD_free, (GO_OSSL_PARAM_BLD_PTR bld), (bld)) \ DEFINEFUNC_3_0(GO_OSSL_PARAM_PTR, OSSL_PARAM_BLD_to_param, (GO_OSSL_PARAM_BLD_PTR bld), (bld)) \ DEFINEFUNC_3_0(int, OSSL_PARAM_BLD_push_utf8_string, (GO_OSSL_PARAM_BLD_PTR bld, const char *key, const char *buf, size_t bsize), (bld, key, buf, bsize)) \ DEFINEFUNC_3_0(int, OSSL_PARAM_BLD_push_octet_string, (GO_OSSL_PARAM_BLD_PTR bld, const char *key, const void *buf, size_t bsize), (bld, key, buf, bsize)) \ -DEFINEFUNC_3_0(int, OSSL_PARAM_BLD_push_int32, (GO_OSSL_PARAM_BLD_PTR bld, const char *key, int32_t num), (bld, key, num)) \ DEFINEFUNC_3_0(int, OSSL_PARAM_BLD_push_BN, (GO_OSSL_PARAM_BLD_PTR bld, const char *key, const GO_BIGNUM_PTR bn), (bld, key, bn)) \ DEFINEFUNC_3_0(int, EVP_PKEY_CTX_set_hkdf_mode, (GO_EVP_PKEY_CTX_PTR arg0, int arg1), (arg0, arg1)) \ DEFINEFUNC_3_0(int, EVP_PKEY_CTX_set_hkdf_md, (GO_EVP_PKEY_CTX_PTR arg0, const GO_EVP_MD_PTR arg1), (arg0, arg1)) \ From 7da9a897e393cb903fc206bdb0ec7ea7d7e41628 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Tue, 27 May 2025 17:51:48 +0200 Subject: [PATCH 2/2] don't backport CI changes --- .github/workflows/test.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e3c0695e..e749b9fe 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,9 +5,9 @@ jobs: strategy: fail-fast: false matrix: - go-version: [1.20.x] + go-version: [1.23.x] openssl-version: [1.0.2, 1.1.0, 1.1.1, 3.0.1, 3.0.13, 3.1.5, 3.2.1] - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Install build tools run: sudo apt-get install -y build-essential @@ -22,6 +22,7 @@ jobs: - name: Check headers working-directory: ./cmd/checkheader run: go run . --ossl-include /usr/local/src/openssl-${{ matrix.openssl-version }}/include -shim ../../shims.h + if: ${{ matrix.openssl-version != '1.0.2' }} # Doesn't work on Ubuntu 22.04 - name: Set OpenSSL config and prove FIPS run: | sudo cp ./scripts/openssl-3.cnf /usr/local/ssl/openssl.cnf @@ -50,7 +51,7 @@ jobs: strategy: fail-fast: false matrix: - go-version: [1.20.x] + go-version: [1.23.x] openssl-version: [libcrypto-1_1-x64.dll, libcrypto-3-x64.dll] steps: - name: Install Go @@ -67,9 +68,9 @@ jobs: strategy: fail-fast: false matrix: - go-version: [1.20.x] - openssl-version: [libcrypto.3.dylib] - runs-on: macos-12 + go-version: [1.23.x] + openssl-version: [/usr/local/opt/openssl@3/lib/libcrypto.3.dylib] + runs-on: macos-13 steps: - name: Install Go uses: actions/setup-go@v3 @@ -80,4 +81,4 @@ jobs: - name: Run Test run: go test -gcflags=all=-d=checkptr -count 10 -v ./... env: - GO_OPENSSL_VERSION_OVERRIDE: ${{ matrix.openssl-version }} + GO_OPENSSL_VERSION_OVERRIDE: ${{ matrix.openssl-version }} \ No newline at end of file