From 2035279b2dff086228a1332f4a2459b191d95f6e Mon Sep 17 00:00:00 2001 From: qmuntal Date: Tue, 26 Nov 2024 11:08:29 +0100 Subject: [PATCH] fix memory leak --- ec.go | 22 ---------------------- ecdh.go | 3 ++- evp.go | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/ec.go b/ec.go index efc004e..734c14b 100644 --- a/ec.go +++ b/ec.go @@ -4,7 +4,6 @@ package openssl // #include "goopenssl.h" import "C" -import "errors" func curveNID(curve string) C.int { switch curve { @@ -67,24 +66,3 @@ func generateAndEncodeEcPublicKey(nid C.int, newPubKeyPointFn func(group C.GO_EC defer C.go_openssl_EC_POINT_free(pt) return encodeEcPoint(group, pt) } - -func checkPkey(pkey C.GO_EVP_PKEY_PTR, isPrivate bool) error { - ctx := C.go_openssl_EVP_PKEY_CTX_new(pkey, nil) - if ctx == nil { - return newOpenSSLError("EVP_PKEY_CTX_new") - } - defer C.go_openssl_EVP_PKEY_CTX_free(ctx) - if isPrivate { - if C.go_openssl_EVP_PKEY_private_check(ctx) != 1 { - // Match upstream error message. - return errors.New("invalid private key") - } - } else { - // Upstream Go does a partial check here, so do we. - if C.go_openssl_EVP_PKEY_public_check_quick(ctx) != 1 { - // Match upstream error message. - return errors.New("invalid public key") - } - } - return nil -} diff --git a/ecdh.go b/ecdh.go index d8c72f6..ad392dc 100644 --- a/ecdh.go +++ b/ecdh.go @@ -7,6 +7,7 @@ import "C" import ( "errors" "runtime" + "slices" "unsafe" ) @@ -36,7 +37,7 @@ func NewPublicKeyECDH(curve string, bytes []byte) (*PublicKeyECDH, error) { if err != nil { return nil, err } - k := &PublicKeyECDH{pkey, append([]byte(nil), bytes...)} + k := &PublicKeyECDH{pkey, slices.Clone(bytes)} runtime.SetFinalizer(k, (*PublicKeyECDH).finalize) return k, nil } diff --git a/evp.go b/evp.go index 17d040a..e7ccdee 100644 --- a/evp.go +++ b/evp.go @@ -510,7 +510,34 @@ func newEvpFromParams(id C.int, selection C.int, params C.GO_OSSL_PARAM_PTR) (C. } var pkey C.GO_EVP_PKEY_PTR if C.go_openssl_EVP_PKEY_fromdata(ctx, &pkey, selection, params) != 1 { + if vMinor < 2 { + // OpenSSL 3.0.1 and 3.0.2 have a bug where EVP_PKEY_fromdata + // does not free the internally allocated EVP_PKEY on error. + // See https://github.com/openssl/openssl/issues/17407. + C.go_openssl_EVP_PKEY_free(pkey) + } return nil, newOpenSSLError("EVP_PKEY_fromdata") } return pkey, nil } + +func checkPkey(pkey C.GO_EVP_PKEY_PTR, isPrivate bool) error { + ctx := C.go_openssl_EVP_PKEY_CTX_new(pkey, nil) + if ctx == nil { + return newOpenSSLError("EVP_PKEY_CTX_new") + } + defer C.go_openssl_EVP_PKEY_CTX_free(ctx) + if isPrivate { + if C.go_openssl_EVP_PKEY_private_check(ctx) != 1 { + // Match upstream error message. + return errors.New("invalid private key") + } + } else { + // Upstream Go does a partial check here, so do we. + if C.go_openssl_EVP_PKEY_public_check_quick(ctx) != 1 { + // Match upstream error message. + return errors.New("invalid public key") + } + } + return nil +}