Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
reduce diffs
  • Loading branch information
qmuntal committed May 26, 2025
commit dd36184002a280e6d2356c92f84f522f0f9ea823
37 changes: 32 additions & 5 deletions evp.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,14 @@ const (
)

type hashAlgorithm struct {
md ossl.EVP_MD_PTR
ch crypto.Hash
size int
blockSize int
provider provider
md ossl.EVP_MD_PTR
ch crypto.Hash
size int
blockSize int
provider provider
marshallable bool
magic string
marshalledSize int
}

// loadHash converts a crypto.Hash to a EVP_MD.
Expand All @@ -95,25 +98,41 @@ func loadHash(ch crypto.Hash) *hashAlgorithm {
hash.md = ossl.EVP_md4()
case crypto.MD5:
hash.md = ossl.EVP_md5()
hash.magic = magicMD5
hash.marshalledSize = marshaledSizeMD5
case crypto.MD5SHA1:
hash.md = ossl.EVP_md5_sha1()
case crypto.SHA1:
hash.md = ossl.EVP_sha1()
hash.magic = magic1
hash.marshalledSize = marshaledSize1
case crypto.SHA224:
hash.md = ossl.EVP_sha224()
hash.magic = magic224
hash.marshalledSize = marshaledSize256
case crypto.SHA256:
hash.md = ossl.EVP_sha256()
hash.magic = magic256
hash.marshalledSize = marshaledSize256
case crypto.SHA384:
hash.md = ossl.EVP_sha384()
hash.magic = magic384
hash.marshalledSize = marshaledSize512
case crypto.SHA512:
hash.md = ossl.EVP_sha512()
hash.magic = magic512
hash.marshalledSize = marshaledSize512
case crypto.SHA512_224:
if versionAtOrAbove(1, 1, 1) {
hash.md = ossl.EVP_sha512_224()
hash.magic = magic512_224
hash.marshalledSize = marshaledSize512
}
case crypto.SHA512_256:
if versionAtOrAbove(1, 1, 1) {
hash.md = ossl.EVP_sha512_256()
hash.magic = magic512_256
hash.marshalledSize = marshaledSize512
}
case crypto.SHA3_224:
if versionAtOrAbove(1, 1, 1) {
Expand Down Expand Up @@ -151,6 +170,11 @@ func loadHash(ch crypto.Hash) *hashAlgorithm {
hash.md = md
}
}
if hash.magic != "" {
if hash.marshalledSize == 0 {
panic("marshalledSize must be set for " + hash.magic)
}
}

switch vMajor {
case 1:
Expand All @@ -161,10 +185,13 @@ func loadHash(ch crypto.Hash) *hashAlgorithm {
switch C.GoString((*C.char)(unsafe.Pointer(cname))) {
case "default":
hash.provider = providerOSSLDefault
hash.marshallable = hash.magic != ""
case "fips":
hash.provider = providerOSSLFIPS
hash.marshallable = hash.magic != ""
case "symcryptprovider":
hash.provider = providerSymCrypt
hash.marshallable = hash.magic != "" && isSymCryptHashStateSerializable(hash.md)
}
}
default:
Expand Down
60 changes: 19 additions & 41 deletions hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ const (
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
marshaledSizeMD5 = len(magicMD5) + 4*4 + 64 + 8 // from crypto/md5
marshaledSize1 = len(magic1) + 5*4 + 64 + 8 // from crypto/sha1
marshaledSize256 = len(magic256) + 8*4 + 64 + 8 // from crypto/sha256
marshaledSize512 = len(magic512) + 8*8 + 128 + 8 // from crypto/sha512
)

// maxHashSize is the size of SHA52 and SHA3_512, the largest hashes we support.
Expand Down Expand Up @@ -385,70 +385,48 @@ func (h *evpHash) Clone() hash.Hash {
var errHashNotMarshallable = errors.New("openssl: hash state is not marshallable")

func (d *evpHash) MarshalBinary() ([]byte, error) {
buf := make([]byte, 0, marshaledSize512) // stack allocate the buffer by setting the max size we support
if !d.alg.marshallable {
return nil, errHashNotMarshallable
}
buf := make([]byte, 0, d.alg.marshalledSize)
return d.AppendBinary(buf)
}

func (d *evpHash) AppendBinary(buf []byte) ([]byte, error) {
defer runtime.KeepAlive(d)
d.init()
magic, _ := cryptoHashEncodingInfo(d.alg.ch)
if magic == "" {
if !d.alg.marshallable {
return nil, errHashNotMarshallable
}
d.init()
switch d.alg.provider {
case providerOSSLDefault, providerOSSLFIPS:
return osslHashAppendBinary(d.ctx, d.alg.ch, magic, buf)
return osslHashAppendBinary(d.ctx, d.alg.ch, d.alg.magic, buf)
case providerSymCrypt:
return symCryptHashAppendBinary(d.ctx, d.alg.ch, magic, buf)
return symCryptHashAppendBinary(d.ctx, d.alg.ch, d.alg.magic, buf)
default:
return nil, errHashNotMarshallable
panic("openssl: unknown hash provider" + strconv.Itoa(int(d.alg.provider)))
}
}

func (d *evpHash) UnmarshalBinary(b []byte) error {
defer runtime.KeepAlive(d)
d.init()
magic, size := cryptoHashEncodingInfo(d.alg.ch)
if magic == "" {
if !d.alg.marshallable {
return errHashNotMarshallable
}
if len(b) < len(magic) || string(b[:len(magic)]) != string(magic[:]) {
if len(b) < len(d.alg.magic) || string(b[:len(d.alg.magic)]) != d.alg.magic {
return errors.New("openssl: invalid hash state identifier")
}
if len(b) != size {
if len(b) != d.alg.marshalledSize {
return errors.New("openssl: invalid hash state size")
}
switch d.alg.provider {
case providerOSSLDefault, providerOSSLFIPS:
return osslHashUnmarshalBinary(d.ctx, d.alg.ch, magic, b)
return osslHashUnmarshalBinary(d.ctx, d.alg.ch, d.alg.magic, b)
case providerSymCrypt:
return symCryptHashUnmarshalBinary(d.ctx, d.alg.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
return symCryptHashUnmarshalBinary(d.ctx, d.alg.ch, d.alg.magic, b)
default:
return "", 0
panic("openssl: unknown hash provider" + strconv.Itoa(int(d.alg.provider)))
}
}

Expand Down
20 changes: 15 additions & 5 deletions internal/ossl/ossl.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ go_hash_sum(const _EVP_MD_CTX_PTR ctx, _EVP_MD_CTX_PTR ctx2, unsigned char *out,
*/
import "C"
import (
"math"
"unsafe"
)

Expand All @@ -42,30 +41,41 @@ func HashSum(ctx1, ctx2 EVP_MD_CTX_PTR, out []byte) error {
return nil
}

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 *byte
DataType uint32
Data unsafe.Pointer
DataSize int
ReturnSize int
DataSize uint
ReturnSize uint
}

func ossl_param_construct(key *byte, dataType uint32, data unsafe.Pointer, dataSize int) OSSL_PARAM {
return OSSL_PARAM{
Key: key,
DataType: dataType,
Data: data,
DataSize: dataSize,
ReturnSize: math.MaxInt - 1,
DataSize: uint(dataSize),
ReturnSize: _OSSL_PARAM_UNMODIFIED,
}
}

func OSSL_PARAM_construct_octet_string(key *byte, data unsafe.Pointer, dataSize int) OSSL_PARAM {
return ossl_param_construct(key, OSSL_PARAM_OCTET_STRING, data, dataSize)
}

func OSSL_PARAM_construct_int32(key *byte, data *int32) OSSL_PARAM {
return ossl_param_construct(key, 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
}
2 changes: 2 additions & 0 deletions internal/ossl/shims.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
// #include <openssl/core_names.h>
// #include <openssl/provider.h>
// #include <openssl/param_build.h>
// #include <openssl/params.h>
// #endif
// #if OPENSSL_VERSION_NUMBER < 0x10100000L
// #include <openssl/bn.h>
Expand Down Expand Up @@ -87,6 +88,7 @@ enum {
_EVP_PKEY_CTRL_DSA_PARAMGEN_BITS = 0x1001,
_EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS = 0x1002,

_OSSL_PARAM_INTEGER = 1,
_OSSL_PARAM_OCTET_STRING = 5,
};

Expand Down
1 change: 1 addition & 0 deletions internal/ossl/zossl.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions internal/ossl/zossl.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ enum {
_EVP_PKEY_CTRL_RSA_OAEP_LABEL = 0x100A,
_EVP_PKEY_CTRL_DSA_PARAMGEN_BITS = 0x1001,
_EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS = 0x1002,
_OSSL_PARAM_INTEGER = 1,
_OSSL_PARAM_OCTET_STRING = 5,
};

Expand Down
6 changes: 1 addition & 5 deletions params.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,13 @@ type paramBuilder struct {

// newParamBuilder creates a new paramBuilder.
func newParamBuilder() (*paramBuilder, error) {
return newParamBuilderN(8) // the maximum known number of BIGNUMs to free are 8 for RSA
}

func newParamBuilderN(n int) (*paramBuilder, error) {
bld, err := ossl.OSSL_PARAM_BLD_new()
if err != nil {
return nil, err
}
pb := &paramBuilder{
bld: bld,
bnToFree: make([]bnParam, 0, n),
bnToFree: make([]bnParam, 0, 8), // the maximum known number of BIGNUMs to free are 8 for RSA
}
runtime.SetFinalizer(pb, (*paramBuilder).finalize)
return pb, nil
Expand Down
Loading
Loading