diff --git a/aes.go b/aes.go index 18bb070..36ad3d6 100644 --- a/aes.go +++ b/aes.go @@ -1,9 +1,7 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( "crypto/cipher" "errors" diff --git a/cipher.go b/cipher.go index 72f7aeb..6f6b56b 100644 --- a/cipher.go +++ b/cipher.go @@ -1,10 +1,7 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" - import ( "crypto/cipher" "encoding/binary" @@ -13,6 +10,8 @@ import ( "strconv" "sync" "unsafe" + + "github.com/golang-fips/openssl/v2/internal/ossl" ) type cipherKind int8 @@ -76,9 +75,9 @@ type cacheCipherKey struct { } // loadCipher returns a cipher object for the given k. -func loadCipher(k cipherKind, mode cipherMode) (cipher C.GO_EVP_CIPHER_PTR) { +func loadCipher(k cipherKind, mode cipherMode) (cipher ossl.EVP_CIPHER_PTR) { if v, ok := cacheCipher.Load(cacheCipherKey{k, mode}); ok { - return v.(C.GO_EVP_CIPHER_PTR) + return v.(ossl.EVP_CIPHER_PTR) } defer func() { if cipher != nil && vMajor == 3 { @@ -86,7 +85,7 @@ func loadCipher(k cipherKind, mode cipherMode) (cipher C.GO_EVP_CIPHER_PTR) { // not created by EVP_CIPHER has negative performance // implications, as cipher operations will have // to fetch it on every call. Better to just fetch it once here. - cipher = C.go_openssl_EVP_CIPHER_fetch(nil, C.go_openssl_EVP_CIPHER_get0_name(cipher), nil) + cipher, _ = ossl.EVP_CIPHER_fetch(nil, ossl.EVP_CIPHER_get0_name(cipher), nil) } cacheCipher.Store(cacheCipherKey{k, mode}, cipher) }() @@ -94,52 +93,52 @@ func loadCipher(k cipherKind, mode cipherMode) (cipher C.GO_EVP_CIPHER_PTR) { case cipherAES128: switch mode { case cipherModeECB: - cipher = C.go_openssl_EVP_aes_128_ecb() + cipher = ossl.EVP_aes_128_ecb() case cipherModeCBC: - cipher = C.go_openssl_EVP_aes_128_cbc() + cipher = ossl.EVP_aes_128_cbc() case cipherModeCTR: - cipher = C.go_openssl_EVP_aes_128_ctr() + cipher = ossl.EVP_aes_128_ctr() case cipherModeGCM: - cipher = C.go_openssl_EVP_aes_128_gcm() + cipher = ossl.EVP_aes_128_gcm() } case cipherAES192: switch mode { case cipherModeECB: - cipher = C.go_openssl_EVP_aes_192_ecb() + cipher = ossl.EVP_aes_192_ecb() case cipherModeCBC: - cipher = C.go_openssl_EVP_aes_192_cbc() + cipher = ossl.EVP_aes_192_cbc() case cipherModeCTR: - cipher = C.go_openssl_EVP_aes_192_ctr() + cipher = ossl.EVP_aes_192_ctr() case cipherModeGCM: - cipher = C.go_openssl_EVP_aes_192_gcm() + cipher = ossl.EVP_aes_192_gcm() } case cipherAES256: switch mode { case cipherModeECB: - cipher = C.go_openssl_EVP_aes_256_ecb() + cipher = ossl.EVP_aes_256_ecb() case cipherModeCBC: - cipher = C.go_openssl_EVP_aes_256_cbc() + cipher = ossl.EVP_aes_256_cbc() case cipherModeCTR: - cipher = C.go_openssl_EVP_aes_256_ctr() + cipher = ossl.EVP_aes_256_ctr() case cipherModeGCM: - cipher = C.go_openssl_EVP_aes_256_gcm() + cipher = ossl.EVP_aes_256_gcm() } case cipherDES: switch mode { case cipherModeECB: - cipher = C.go_openssl_EVP_des_ecb() + cipher = ossl.EVP_des_ecb() case cipherModeCBC: - cipher = C.go_openssl_EVP_des_cbc() + cipher = ossl.EVP_des_cbc() } case cipherDES3: switch mode { case cipherModeECB: - cipher = C.go_openssl_EVP_des_ede3_ecb() + cipher = ossl.EVP_des_ede3_ecb() case cipherModeCBC: - cipher = C.go_openssl_EVP_des_ede3_cbc() + cipher = ossl.EVP_des_ede3_cbc() } case cipherRC4: - cipher = C.go_openssl_EVP_rc4() + cipher = ossl.EVP_rc4() } return cipher } @@ -157,7 +156,7 @@ func newEVPCipher(key []byte, kind cipherKind) (*evpCipher, error) { } c := &evpCipher{key: make([]byte, len(key)), kind: kind} copy(c.key, key) - c.blockSize = int(C.go_openssl_EVP_CIPHER_get_block_size(cipher)) + c.blockSize = int(ossl.EVP_CIPHER_get_block_size(cipher)) return c, nil } @@ -177,9 +176,9 @@ func (c *evpCipher) encrypt(dst, src []byte) error { if err != nil { return err } - defer C.go_openssl_EVP_CIPHER_CTX_free(enc_ctx) + defer ossl.EVP_CIPHER_CTX_free(enc_ctx) - if C.go_openssl_EVP_EncryptUpdate_wrapper(enc_ctx, base(dst), base(src), C.int(c.blockSize)) != 1 { + if ossl.EVP_EncryptUpdate_wrapper(enc_ctx, unsafe.SliceData(dst), unsafe.SliceData(src), int32(c.blockSize)) != nil { return errors.New("EncryptUpdate failed") } runtime.KeepAlive(c) @@ -202,24 +201,24 @@ func (c *evpCipher) decrypt(dst, src []byte) error { if err != nil { return err } - defer C.go_openssl_EVP_CIPHER_CTX_free(dec_ctx) + defer ossl.EVP_CIPHER_CTX_free(dec_ctx) - if C.go_openssl_EVP_CIPHER_CTX_set_padding(dec_ctx, 0) != 1 { + if ossl.EVP_CIPHER_CTX_set_padding(dec_ctx, 0) != nil { return errors.New("could not disable cipher padding") } - C.go_openssl_EVP_DecryptUpdate_wrapper(dec_ctx, base(dst), base(src), C.int(c.blockSize)) + ossl.EVP_DecryptUpdate_wrapper(dec_ctx, unsafe.SliceData(dst), unsafe.SliceData(src), int32(c.blockSize)) runtime.KeepAlive(c) return nil } type cipherCBC struct { - ctx C.GO_EVP_CIPHER_CTX_PTR + ctx ossl.EVP_CIPHER_CTX_PTR blockSize int } func (c *cipherCBC) finalize() { - C.go_openssl_EVP_CIPHER_CTX_free(c.ctx) + ossl.EVP_CIPHER_CTX_free(c.ctx) } func (x *cipherCBC) BlockSize() int { return x.blockSize } @@ -235,7 +234,7 @@ func (x *cipherCBC) CryptBlocks(dst, src []byte) { panic("crypto/cipher: output smaller than input") } if len(src) > 0 { - if C.go_openssl_EVP_CipherUpdate_wrapper(x.ctx, base(dst), base(src), C.int(len(src))) != 1 { + if ossl.EVP_CipherUpdate_wrapper(x.ctx, unsafe.SliceData(dst), unsafe.SliceData(src), int32(len(src))) != nil { panic("crypto/cipher: CipherUpdate failed") } runtime.KeepAlive(x) @@ -246,7 +245,7 @@ func (x *cipherCBC) SetIV(iv []byte) { if len(iv) != x.blockSize { panic("cipher: incorrect length IV") } - if C.go_openssl_EVP_CipherInit_ex(x.ctx, nil, nil, nil, base(iv), C.int(cipherOpNone)) != 1 { + if ossl.EVP_CipherInit_ex(x.ctx, nil, nil, nil, unsafe.SliceData(iv), int32(cipherOpNone)) != nil { panic("cipher: unable to initialize EVP cipher ctx") } } @@ -258,14 +257,14 @@ func (c *evpCipher) newCBC(iv []byte, op cipherOp) cipher.BlockMode { } x := &cipherCBC{ctx: ctx, blockSize: c.blockSize} runtime.SetFinalizer(x, (*cipherCBC).finalize) - if C.go_openssl_EVP_CIPHER_CTX_set_padding(x.ctx, 0) != 1 { + if ossl.EVP_CIPHER_CTX_set_padding(x.ctx, 0) != nil { panic("cipher: unable to set padding") } return x } type cipherCTR struct { - ctx C.GO_EVP_CIPHER_CTX_PTR + ctx ossl.EVP_CIPHER_CTX_PTR } func (x *cipherCTR) XORKeyStream(dst, src []byte) { @@ -278,7 +277,7 @@ func (x *cipherCTR) XORKeyStream(dst, src []byte) { if len(src) == 0 { return } - if C.go_openssl_EVP_EncryptUpdate_wrapper(x.ctx, base(dst), base(src), C.int(len(src))) != 1 { + if ossl.EVP_EncryptUpdate_wrapper(x.ctx, base(dst), base(src), int32(len(src))) != nil { panic("crypto/cipher: EncryptUpdate failed") } runtime.KeepAlive(x) @@ -295,7 +294,7 @@ func (c *evpCipher) newCTR(iv []byte) cipher.Stream { } func (c *cipherCTR) finalize() { - C.go_openssl_EVP_CIPHER_CTX_free(c.ctx) + ossl.EVP_CIPHER_CTX_free(c.ctx) } type cipherGCMTLS uint8 @@ -445,7 +444,7 @@ func (g *cipherGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte { if err != nil { panic(err) } - defer C.go_openssl_EVP_CIPHER_CTX_free(ctx) + defer ossl.EVP_CIPHER_CTX_free(ctx) // Encrypt additional data. // When sealing a TLS payload, OpenSSL app sets the additional data using // 'EVP_CIPHER_CTX_ctrl(g.ctx, C.EVP_CTRL_AEAD_TLS1_AAD, C.EVP_AEAD_TLS1_AAD_LEN, base(additionalData))'. @@ -453,9 +452,9 @@ func (g *cipherGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte { // relying in the explicit nonce being securely set externally, // and it also gives some interesting speed gains. // Unfortunately we can't use it because Go expects AEAD.Seal to honor the provided nonce. - if C.go_openssl_EVP_CIPHER_CTX_seal_wrapper(ctx, base(out), base(nonce), - base(plaintext), C.int(len(plaintext)), - base(additionalData), C.int(len(additionalData))) != 1 { + if ossl.EVP_CIPHER_CTX_seal_wrapper(ctx, base(out), base(nonce), + base(plaintext), int32(len(plaintext)), + base(additionalData), int32(len(additionalData))) != nil { panic(fail("EVP_CIPHER_CTX_seal")) } @@ -492,13 +491,13 @@ func (g *cipherGCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, if err != nil { return nil, err } - defer C.go_openssl_EVP_CIPHER_CTX_free(ctx) - ok := C.go_openssl_EVP_CIPHER_CTX_open_wrapper( + defer ossl.EVP_CIPHER_CTX_free(ctx) + err = ossl.EVP_CIPHER_CTX_open_wrapper( ctx, base(out), base(nonce), - base(ciphertext), C.int(len(ciphertext)), - base(additionalData), C.int(len(additionalData)), base(tag)) + base(ciphertext), int32(len(ciphertext)), + base(additionalData), int32(len(additionalData)), base(tag)) runtime.KeepAlive(g) - if ok == 0 { + if err != nil { // Zero output buffer on error. for i := range out { out[i] = 0 @@ -520,35 +519,35 @@ func sliceForAppend(in []byte, n int) (head, tail []byte) { return } -func newCipherCtx(kind cipherKind, mode cipherMode, encrypt cipherOp, key, iv []byte) (_ C.GO_EVP_CIPHER_CTX_PTR, err error) { +func newCipherCtx(kind cipherKind, mode cipherMode, encrypt cipherOp, key, iv []byte) (_ ossl.EVP_CIPHER_CTX_PTR, err error) { cipher := loadCipher(kind, mode) if cipher == nil { panic("crypto/cipher: unsupported cipher: " + kind.String()) } - ctx := C.go_openssl_EVP_CIPHER_CTX_new() - if ctx == nil { + ctx, err := ossl.EVP_CIPHER_CTX_new() + if err != nil { return nil, fail("unable to create EVP cipher ctx") } defer func() { if err != nil { - C.go_openssl_EVP_CIPHER_CTX_free(ctx) + ossl.EVP_CIPHER_CTX_free(ctx) } }() if kind == cipherRC4 { // RC4 cipher supports a variable key length. // We need to set the key length before setting the key, // and to do so we need to have an initialized cipher ctx. - if C.go_openssl_EVP_CipherInit_ex(ctx, cipher, nil, nil, nil, C.int(encrypt)) != 1 { - return nil, newOpenSSLError("EVP_CipherInit_ex") + if err := ossl.EVP_CipherInit_ex(ctx, cipher, nil, nil, nil, int32(encrypt)); err != nil { + return nil, err } - if C.go_openssl_EVP_CIPHER_CTX_set_key_length(ctx, C.int(len(key))) != 1 { - return nil, newOpenSSLError("EVP_CIPHER_CTX_set_key_length") + if err := ossl.EVP_CIPHER_CTX_set_key_length(ctx, int32(len(key))); err != nil { + return nil, err } // Pass nil to the next call to EVP_CipherInit_ex to avoid resetting ctx's cipher. cipher = nil } - if C.go_openssl_EVP_CipherInit_ex(ctx, cipher, nil, base(key), base(iv), C.int(encrypt)) != 1 { - return nil, newOpenSSLError("unable to initialize EVP cipher ctx") + if err := ossl.EVP_CipherInit_ex(ctx, cipher, nil, base(key), base(iv), int32(encrypt)); err != nil { + return nil, err } return ctx, nil } diff --git a/des.go b/des.go index cd00654..6a47513 100644 --- a/des.go +++ b/des.go @@ -1,9 +1,7 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( "crypto/cipher" "errors" diff --git a/dsa.go b/dsa.go index c56071f..73a2cd7 100644 --- a/dsa.go +++ b/dsa.go @@ -1,21 +1,21 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( "runtime" "unsafe" + + "github.com/golang-fips/openssl/v2/internal/ossl" ) // SupportsDSA returns true if the OpenSSL library supports DSA. func SupportsDSA() bool { - ctx := C.go_openssl_EVP_PKEY_CTX_new_id(C.GO_EVP_PKEY_DSA, nil) - if ctx == nil { + ctx, err := ossl.EVP_PKEY_CTX_new_id(ossl.EVP_PKEY_DSA, nil) + if err != nil { return false } - C.go_openssl_EVP_PKEY_CTX_free(ctx) + ossl.EVP_PKEY_CTX_free(ctx) return true } @@ -30,14 +30,14 @@ type PrivateKeyDSA struct { X, Y BigInt // _pkey MUST NOT be accessed directly. Instead, use the withKey method. - _pkey C.GO_EVP_PKEY_PTR + _pkey ossl.EVP_PKEY_PTR } func (k *PrivateKeyDSA) finalize() { - C.go_openssl_EVP_PKEY_free(k._pkey) + ossl.EVP_PKEY_free(k._pkey) } -func (k *PrivateKeyDSA) withKey(f func(C.GO_EVP_PKEY_PTR) C.int) C.int { +func (k *PrivateKeyDSA) withKey(f func(ossl.EVP_PKEY_PTR) error) error { defer runtime.KeepAlive(k) return f(k._pkey) } @@ -48,14 +48,14 @@ type PublicKeyDSA struct { Y BigInt // _pkey MUST NOT be accessed directly. Instead, use the withKey method. - _pkey C.GO_EVP_PKEY_PTR + _pkey ossl.EVP_PKEY_PTR } func (k *PublicKeyDSA) finalize() { - C.go_openssl_EVP_PKEY_free(k._pkey) + ossl.EVP_PKEY_free(k._pkey) } -func (k *PublicKeyDSA) withKey(f func(C.GO_EVP_PKEY_PTR) C.int) C.int { +func (k *PublicKeyDSA) withKey(f func(ossl.EVP_PKEY_PTR) error) error { defer runtime.KeepAlive(k) return f(k._pkey) } @@ -66,46 +66,50 @@ func GenerateDSAParameters(l, n int) (DSAParameters, error) { // extracting the domain parameters from it. // Generate a new DSA key context and set the known parameters. - ctx := C.go_openssl_EVP_PKEY_CTX_new_id(C.GO_EVP_PKEY_DSA, nil) - if ctx == nil { - return DSAParameters{}, newOpenSSLError("EVP_PKEY_CTX_new_id failed") + ctx, err := ossl.EVP_PKEY_CTX_new_id(ossl.EVP_PKEY_DSA, nil) + if err != nil { + return DSAParameters{}, err } - defer C.go_openssl_EVP_PKEY_CTX_free(ctx) - if C.go_openssl_EVP_PKEY_paramgen_init(ctx) != 1 { - return DSAParameters{}, newOpenSSLError("EVP_PKEY_paramgen_init failed") + defer ossl.EVP_PKEY_CTX_free(ctx) + if err := ossl.EVP_PKEY_paramgen_init(ctx); err != nil { + return DSAParameters{}, err } - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, C.GO_EVP_PKEY_DSA, -1, C.GO_EVP_PKEY_CTRL_DSA_PARAMGEN_BITS, C.int(l), nil) != 1 { - return DSAParameters{}, newOpenSSLError("EVP_PKEY_CTX_ctrl failed") + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, ossl.EVP_PKEY_DSA, -1, ossl.EVP_PKEY_CTRL_DSA_PARAMGEN_BITS, int32(l), nil); err != nil { + return DSAParameters{}, err } - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, C.GO_EVP_PKEY_DSA, -1, C.GO_EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS, C.int(n), nil) != 1 { - return DSAParameters{}, newOpenSSLError("EVP_PKEY_CTX_ctrl failed") + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, ossl.EVP_PKEY_DSA, -1, ossl.EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS, int32(n), nil); err != nil { + return DSAParameters{}, err } - var pkey C.GO_EVP_PKEY_PTR - if C.go_openssl_EVP_PKEY_paramgen(ctx, &pkey) != 1 { - return DSAParameters{}, newOpenSSLError("EVP_PKEY_paramgen failed") + var pkey ossl.EVP_PKEY_PTR + if err := ossl.EVP_PKEY_paramgen(ctx, &pkey); err != nil { + return DSAParameters{}, err } - defer C.go_openssl_EVP_PKEY_free(pkey) + defer ossl.EVP_PKEY_free(pkey) // Extract the domain parameters from the generated key. - var p, q, g C.GO_BIGNUM_PTR + var p, q, g ossl.BIGNUM_PTR switch vMajor { case 1: dsa := getDSA(pkey) if vMinor == 0 { - C.go_openssl_DSA_get0_pqg_backport(dsa, &p, &q, &g) + ossl.DSA_get0_pqg_backport(dsa, &p, &q, &g) } else { - C.go_openssl_DSA_get0_pqg(dsa, &p, &q, &g) + ossl.DSA_get0_pqg(dsa, &p, &q, &g) } case 3: defer func() { - C.go_openssl_BN_free(p) - C.go_openssl_BN_free(q) - C.go_openssl_BN_free(g) + ossl.BN_free(p) + ossl.BN_free(q) + ossl.BN_free(g) }() - if C.go_openssl_EVP_PKEY_get_bn_param(pkey, _OSSL_PKEY_PARAM_FFC_P, &p) != 1 || - C.go_openssl_EVP_PKEY_get_bn_param(pkey, _OSSL_PKEY_PARAM_FFC_Q, &q) != 1 || - C.go_openssl_EVP_PKEY_get_bn_param(pkey, _OSSL_PKEY_PARAM_FFC_G, &g) != 1 { - return DSAParameters{}, newOpenSSLError("EVP_PKEY_get_bn_param") + if err := getBnParam(pkey, ossl.OSSL_PKEY_PARAM_FFC_P, &p); err != err { + return DSAParameters{}, err + } + if err := getBnParam(pkey, ossl.OSSL_PKEY_PARAM_FFC_Q, &q); err != err { + return DSAParameters{}, err + } + if err := getBnParam(pkey, ossl.OSSL_PKEY_PARAM_FFC_G, &g); err != err { + return DSAParameters{}, err } default: panic(errUnsupportedVersion()) @@ -152,23 +156,25 @@ func GenerateKeyDSA(params DSAParameters) (*PrivateKeyDSA, error) { if err != nil { return nil, err } - var x, y C.GO_BIGNUM_PTR + var x, y ossl.BIGNUM_PTR switch vMajor { case 1: dsa := getDSA(pkey) if vMinor == 0 { - C.go_openssl_DSA_get0_key_backport(dsa, &y, &x) + ossl.DSA_get0_key_backport(dsa, &y, &x) } else { - C.go_openssl_DSA_get0_key(dsa, &y, &x) + ossl.DSA_get0_key(dsa, &y, &x) } case 3: defer func() { - C.go_openssl_BN_clear_free(x) - C.go_openssl_BN_free(y) + ossl.BN_clear_free(x) + ossl.BN_free(y) }() - if C.go_openssl_EVP_PKEY_get_bn_param(pkey, _OSSL_PKEY_PARAM_PUB_KEY, &y) != 1 || - C.go_openssl_EVP_PKEY_get_bn_param(pkey, _OSSL_PKEY_PARAM_PRIV_KEY, &x) != 1 { - return nil, newOpenSSLError("EVP_PKEY_get_bn_param") + if err := getBnParam(pkey, ossl.OSSL_PKEY_PARAM_PUB_KEY, &y); err != nil { + return nil, err + } + if err := getBnParam(pkey, ossl.OSSL_PKEY_PARAM_PRIV_KEY, &x); err != nil { + return nil, err } default: panic(errUnsupportedVersion()) @@ -188,7 +194,7 @@ func VerifyDSA(pub *PublicKeyDSA, hash []byte, sig []byte) bool { return evpVerify(pub.withKey, 0, 0, 0, sig, hash) == nil } -func newDSA(params DSAParameters, x, y BigInt) (C.GO_EVP_PKEY_PTR, error) { +func newDSA(params DSAParameters, x, y BigInt) (ossl.EVP_PKEY_PTR, error) { switch vMajor { case 1: return newDSA1(params, x, y) @@ -199,61 +205,60 @@ func newDSA(params DSAParameters, x, y BigInt) (C.GO_EVP_PKEY_PTR, error) { } } -func newDSA1(params DSAParameters, x, y BigInt) (pkey C.GO_EVP_PKEY_PTR, err error) { +func newDSA1(params DSAParameters, x, y BigInt) (pkey ossl.EVP_PKEY_PTR, _ error) { checkMajorVersion(1) - dsa := C.go_openssl_DSA_new() - if dsa == nil { - return nil, newOpenSSLError("DSA_new failed") + dsa, err := ossl.DSA_new() + if err != nil { + return nil, err } defer func() { if pkey == nil { - C.go_openssl_DSA_free(dsa) + ossl.DSA_free(dsa) } }() p, q, g := bigToBN(params.P), bigToBN(params.Q), bigToBN(params.G) - var ret C.int if vMinor == 0 { - ret = C.go_openssl_DSA_set0_pqg_backport(dsa, p, q, g) + err = ossl.DSA_set0_pqg_backport(dsa, p, q, g) } else { - ret = C.go_openssl_DSA_set0_pqg(dsa, p, q, g) + err = ossl.DSA_set0_pqg(dsa, p, q, g) } - if ret != 1 { - C.go_openssl_BN_free(p) - C.go_openssl_BN_free(q) - C.go_openssl_BN_free(g) - return nil, newOpenSSLError("DSA_set0_pqg failed") + if err != nil { + ossl.BN_free(p) + ossl.BN_free(q) + ossl.BN_free(g) + return nil, err } if y != nil { pub, priv := bigToBN(y), bigToBN(x) if vMinor == 0 { - ret = C.go_openssl_DSA_set0_key_backport(dsa, pub, priv) + err = ossl.DSA_set0_key_backport(dsa, pub, priv) } else { - ret = C.go_openssl_DSA_set0_key(dsa, pub, priv) + err = ossl.DSA_set0_key(dsa, pub, priv) } - if ret != 1 { - C.go_openssl_BN_free(pub) - C.go_openssl_BN_clear_free(priv) - return nil, newOpenSSLError("DSA_set0_key failed") + if err != nil { + ossl.BN_free(pub) + ossl.BN_clear_free(priv) + return nil, err } } else { - if C.go_openssl_DSA_generate_key(dsa) != 1 { - return nil, newOpenSSLError("DSA_generate_key failed") + if err := ossl.DSA_generate_key(dsa); err != nil { + return nil, err } } - pkey = C.go_openssl_EVP_PKEY_new() - if pkey == nil { - return nil, newOpenSSLError("EVP_PKEY_new failed") + pkey, err = ossl.EVP_PKEY_new() + if err != nil { + return nil, err } - if C.go_openssl_EVP_PKEY_assign(pkey, C.GO_EVP_PKEY_DSA, unsafe.Pointer(dsa)) != 1 { - C.go_openssl_EVP_PKEY_free(pkey) - return nil, newOpenSSLError("EVP_PKEY_assign failed") + if err := ossl.EVP_PKEY_assign(pkey, ossl.EVP_PKEY_DSA, unsafe.Pointer(dsa)); err != nil { + ossl.EVP_PKEY_free(pkey) + return nil, err } return pkey, nil } -func newDSA3(params DSAParameters, x, y BigInt) (C.GO_EVP_PKEY_PTR, error) { +func newDSA3(params DSAParameters, x, y BigInt) (ossl.EVP_PKEY_PTR, error) { checkMajorVersion(3) bld, err := newParamBuilder() @@ -262,25 +267,25 @@ func newDSA3(params DSAParameters, x, y BigInt) (C.GO_EVP_PKEY_PTR, error) { } defer bld.finalize() - bld.addBigInt(_OSSL_PKEY_PARAM_FFC_P, params.P, false) - bld.addBigInt(_OSSL_PKEY_PARAM_FFC_Q, params.Q, false) - bld.addBigInt(_OSSL_PKEY_PARAM_FFC_G, params.G, false) - selection := C.int(C.GO_EVP_PKEY_KEYPAIR) + bld.addBigInt(ossl.OSSL_PKEY_PARAM_FFC_P, params.P, false) + bld.addBigInt(ossl.OSSL_PKEY_PARAM_FFC_Q, params.Q, false) + bld.addBigInt(ossl.OSSL_PKEY_PARAM_FFC_G, params.G, false) + selection := ossl.EVP_PKEY_KEYPAIR if y != nil { - bld.addBigInt(_OSSL_PKEY_PARAM_PUB_KEY, y, false) + bld.addBigInt(ossl.OSSL_PKEY_PARAM_PUB_KEY, y, false) if x == nil { - selection = C.int(C.GO_EVP_PKEY_PUBLIC_KEY) + selection = ossl.EVP_PKEY_PUBLIC_KEY } } if x != nil { - bld.addBigInt(_OSSL_PKEY_PARAM_PRIV_KEY, x, true) + bld.addBigInt(ossl.OSSL_PKEY_PARAM_PRIV_KEY, x, true) } bldparams, err := bld.build() if err != nil { return nil, err } - defer C.go_openssl_OSSL_PARAM_free(bldparams) - pkey, err := newEvpFromParams(C.GO_EVP_PKEY_DSA, selection, bldparams) + defer ossl.OSSL_PARAM_free(bldparams) + pkey, err := newEvpFromParams(ossl.EVP_PKEY_DSA, selection, bldparams) if err != nil { return nil, err } @@ -290,18 +295,18 @@ func newDSA3(params DSAParameters, x, y BigInt) (C.GO_EVP_PKEY_PTR, error) { // pkey doesn't contain the public component, but the crypto/dsa package // expects it to be always there. Generate a new key using pkey as domain // parameters placeholder. - defer C.go_openssl_EVP_PKEY_free(pkey) - ctx := C.go_openssl_EVP_PKEY_CTX_new_from_pkey(nil, pkey, nil) - if ctx == nil { - return nil, newOpenSSLError("EVP_PKEY_CTX_new_from_pkey") + defer ossl.EVP_PKEY_free(pkey) + ctx, err := ossl.EVP_PKEY_CTX_new_from_pkey(nil, pkey, nil) + if err != nil { + return nil, err } - defer C.go_openssl_EVP_PKEY_CTX_free(ctx) - if C.go_openssl_EVP_PKEY_keygen_init(ctx) != 1 { - return nil, newOpenSSLError("EVP_PKEY_keygen_init") + defer ossl.EVP_PKEY_CTX_free(ctx) + if err := ossl.EVP_PKEY_keygen_init(ctx); err != nil { + return nil, err } - var gkey C.GO_EVP_PKEY_PTR - if C.go_openssl_EVP_PKEY_keygen(ctx, &gkey) != 1 { - return nil, newOpenSSLError("EVP_PKEY_keygen") + var gkey ossl.EVP_PKEY_PTR + if err := ossl.EVP_PKEY_keygen(ctx, &gkey); err != nil { + return nil, err } return gkey, nil } @@ -309,13 +314,13 @@ func newDSA3(params DSAParameters, x, y BigInt) (C.GO_EVP_PKEY_PTR, error) { // getDSA returns the DSA from pkey. // If pkey does not contain an DSA it panics. // The returned key should not be freed. -func getDSA(pkey C.GO_EVP_PKEY_PTR) (key C.GO_DSA_PTR) { +func getDSA(pkey ossl.EVP_PKEY_PTR) (key ossl.DSA_PTR) { if vMajor == 1 && vMinor == 0 { - if key0 := C.go_openssl_EVP_PKEY_get0(pkey); key0 != nil { - key = C.GO_DSA_PTR(key0) + if key0, err := ossl.EVP_PKEY_get0(pkey); err == nil { + key = ossl.DSA_PTR(key0) } } else { - key = C.go_openssl_EVP_PKEY_get0_DSA(pkey) + key, _ = ossl.EVP_PKEY_get0_DSA(pkey) } if key == nil { panic("pkey does not contain an DSA") diff --git a/ec.go b/ec.go index 03c51e5..e27bec6 100644 --- a/ec.go +++ b/ec.go @@ -1,51 +1,50 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" +import "github.com/golang-fips/openssl/v2/internal/ossl" -func curveNID(curve string) (C.int, error) { +func curveNID(curve string) (int, error) { switch curve { case "P-224": - return C.GO_NID_secp224r1, nil + return ossl.NID_secp224r1, nil case "P-256": - return C.GO_NID_X9_62_prime256v1, nil + return ossl.NID_X9_62_prime256v1, nil case "P-384": - return C.GO_NID_secp384r1, nil + return ossl.NID_secp384r1, nil case "P-521": - return C.GO_NID_secp521r1, nil + return ossl.NID_secp521r1, nil } return 0, errUnknownCurve } // encodeEcPoint encodes pt. -func encodeEcPoint(group C.GO_EC_GROUP_PTR, pt C.GO_EC_POINT_PTR) ([]byte, error) { +func encodeEcPoint(group ossl.EC_GROUP_PTR, pt ossl.EC_POINT_PTR) ([]byte, error) { // Get encoded point size. - n := C.go_openssl_EC_POINT_point2oct(group, pt, C.GO_POINT_CONVERSION_UNCOMPRESSED, nil, 0, nil) - if n == 0 { - return nil, newOpenSSLError("EC_POINT_point2oct") + n, err := ossl.EC_POINT_point2oct(group, pt, ossl.POINT_CONVERSION_UNCOMPRESSED, nil, 0, nil) + if err != nil { + return nil, err } // Encode point into bytes. bytes := make([]byte, n) - n = C.go_openssl_EC_POINT_point2oct(group, pt, C.GO_POINT_CONVERSION_UNCOMPRESSED, base(bytes), n, nil) - if n == 0 { - return nil, newOpenSSLError("EC_POINT_point2oct") + n, err = ossl.EC_POINT_point2oct(group, pt, ossl.POINT_CONVERSION_UNCOMPRESSED, base(bytes), n, nil) + if err != nil { + return nil, err } return bytes, nil } // generateAndEncodeEcPublicKey calls newPubKeyPointFn to generate a public key point and then encodes it. -func generateAndEncodeEcPublicKey(nid C.int, newPubKeyPointFn func(group C.GO_EC_GROUP_PTR) (C.GO_EC_POINT_PTR, error)) ([]byte, error) { - group := C.go_openssl_EC_GROUP_new_by_curve_name(nid) - if group == nil { - return nil, newOpenSSLError("EC_GROUP_new_by_curve_name") +func generateAndEncodeEcPublicKey(nid int, newPubKeyPointFn func(group ossl.EC_GROUP_PTR) (ossl.EC_POINT_PTR, error)) ([]byte, error) { + group, err := ossl.EC_GROUP_new_by_curve_name(int32(nid)) + if err != nil { + return nil, err } - defer C.go_openssl_EC_GROUP_free(group) + defer ossl.EC_GROUP_free(group) pt, err := newPubKeyPointFn(group) if err != nil { return nil, err } - defer C.go_openssl_EC_POINT_free(pt) + defer ossl.EC_POINT_free(pt) return encodeEcPoint(group, pt) } diff --git a/ecdh.go b/ecdh.go index 5b14674..d748771 100644 --- a/ecdh.go +++ b/ecdh.go @@ -1,32 +1,32 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( "errors" "runtime" "unsafe" + + "github.com/golang-fips/openssl/v2/internal/ossl" ) type PublicKeyECDH struct { - _pkey C.GO_EVP_PKEY_PTR + _pkey ossl.EVP_PKEY_PTR bytes []byte } func (k *PublicKeyECDH) finalize() { - C.go_openssl_EVP_PKEY_free(k._pkey) + ossl.EVP_PKEY_free(k._pkey) } type PrivateKeyECDH struct { - _pkey C.GO_EVP_PKEY_PTR + _pkey ossl.EVP_PKEY_PTR curve string hasPublicKey bool } func (k *PrivateKeyECDH) finalize() { - C.go_openssl_EVP_PKEY_free(k._pkey) + ossl.EVP_PKEY_free(k._pkey) } func NewPublicKeyECDH(curve string, bytes []byte) (*PublicKeyECDH, error) { @@ -63,44 +63,48 @@ func (k *PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) { } k.hasPublicKey = true } - var pkey C.GO_EVP_PKEY_PTR + var pkey ossl.EVP_PKEY_PTR defer func() { - C.go_openssl_EVP_PKEY_free(pkey) + ossl.EVP_PKEY_free(pkey) }() var bytes []byte switch vMajor { case 1: - pkey = C.go_openssl_EVP_PKEY_new() - if pkey == nil { - return nil, newOpenSSLError("EVP_PKEY_new") + var err error + pkey, err = ossl.EVP_PKEY_new() + if err != nil { + return nil, err } key := getECKey(k._pkey) - if C.go_openssl_EVP_PKEY_set1_EC_KEY(pkey, key) != 1 { - return nil, newOpenSSLError("EVP_PKEY_set1_EC_KEY") + if err := ossl.EVP_PKEY_set1_EC_KEY(pkey, key); err != nil { + return nil, err } - pt := C.go_openssl_EC_KEY_get0_public_key(key) - if pt == nil { - return nil, newOpenSSLError("EC_KEY_get0_public_key") + pt, err := ossl.EC_KEY_get0_public_key(key) + if err != nil { + return nil, err + } + group, err := ossl.EC_KEY_get0_group(key) + if err != nil { + return nil, err } - group := C.go_openssl_EC_KEY_get0_group(key) - var err error bytes, err = encodeEcPoint(group, pt) if err != nil { return nil, err } case 3: pkey = k._pkey - if C.go_openssl_EVP_PKEY_up_ref(pkey) != 1 { - return nil, newOpenSSLError("EVP_PKEY_up_ref") + if err := ossl.EVP_PKEY_up_ref(pkey); err != nil { + return nil, err } - var cbytes *C.uchar - n := C.go_openssl_EVP_PKEY_get1_encoded_public_key(k._pkey, &cbytes) - if n == 0 { - return nil, newOpenSSLError("EVP_PKEY_get_octet_string_param") + var cbytes *byte + n, err := ossl.EVP_PKEY_get1_encoded_public_key(k._pkey, &cbytes) + if err != nil { + return nil, err } - bytes = C.GoBytes(unsafe.Pointer(cbytes), C.int(n)) + bytes = make([]byte, n) + copy(bytes, unsafe.Slice(cbytes, n)) cryptoFree(unsafe.Pointer(cbytes)) default: panic(errUnsupportedVersion()) @@ -111,7 +115,7 @@ func (k *PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) { return pub, nil } -func newECDHPkey(curve string, bytes []byte, isPrivate bool) (C.GO_EVP_PKEY_PTR, error) { +func newECDHPkey(curve string, bytes []byte, isPrivate bool) (ossl.EVP_PKEY_PTR, error) { nid, err := curveNID(curve) if err != nil { return nil, err @@ -126,45 +130,48 @@ func newECDHPkey(curve string, bytes []byte, isPrivate bool) (C.GO_EVP_PKEY_PTR, } } -func newECDHPkey1(nid C.int, bytes []byte, isPrivate bool) (pkey C.GO_EVP_PKEY_PTR, err error) { +func newECDHPkey1(nid int, bytes []byte, isPrivate bool) (pkey ossl.EVP_PKEY_PTR, err error) { checkMajorVersion(1) - key := C.go_openssl_EC_KEY_new_by_curve_name(nid) - if key == nil { - return nil, newOpenSSLError("EC_KEY_new_by_curve_name") + key, err := ossl.EC_KEY_new_by_curve_name(int32(nid)) + if err != nil { + return nil, err } defer func() { if pkey == nil { - C.go_openssl_EC_KEY_free(key) + ossl.EC_KEY_free(key) } }() if isPrivate { - priv := C.go_openssl_BN_bin2bn(base(bytes), C.int(len(bytes)), nil) - if priv == nil { - return nil, newOpenSSLError("BN_bin2bn") + priv, err := ossl.BN_bin2bn(base(bytes), int32(len(bytes)), nil) + if err != nil { + return nil, err } - defer C.go_openssl_BN_clear_free(priv) - if C.go_openssl_EC_KEY_set_private_key(key, priv) != 1 { - return nil, newOpenSSLError("EC_KEY_set_private_key") + defer ossl.BN_clear_free(priv) + if err := ossl.EC_KEY_set_private_key(key, priv); err != nil { + return nil, err } } else { - group := C.go_openssl_EC_KEY_get0_group(key) - pub := C.go_openssl_EC_POINT_new(group) - if pub == nil { - return nil, newOpenSSLError("EC_POINT_new") + group, err := ossl.EC_KEY_get0_group(key) + if err != nil { + return nil, err } - defer C.go_openssl_EC_POINT_free(pub) - if C.go_openssl_EC_POINT_oct2point(group, pub, base(bytes), C.size_t(len(bytes)), nil) != 1 { + pub, err := ossl.EC_POINT_new(group) + if err != nil { + return nil, err + } + defer ossl.EC_POINT_free(pub) + if ossl.EC_POINT_oct2point(group, pub, base(bytes), len(bytes), nil) != nil { return nil, errors.New("point not on curve") } - if C.go_openssl_EC_KEY_set_public_key(key, pub) != 1 { - return nil, newOpenSSLError("EC_KEY_set_public_key") + if err := ossl.EC_KEY_set_public_key(key, pub); err != nil { + return nil, err } } return newEVPPKEY(key) } -func newECDHPkey3(nid C.int, bytes []byte, isPrivate bool) (C.GO_EVP_PKEY_PTR, error) { +func newECDHPkey3(nid int, bytes []byte, isPrivate bool) (ossl.EVP_PKEY_PTR, error) { checkMajorVersion(3) bld, err := newParamBuilder() @@ -172,72 +179,75 @@ func newECDHPkey3(nid C.int, bytes []byte, isPrivate bool) (C.GO_EVP_PKEY_PTR, e return nil, err } defer bld.finalize() - bld.addUTF8String(_OSSL_PKEY_PARAM_GROUP_NAME, C.go_openssl_OBJ_nid2sn(nid), 0) - var selection C.int + bld.addUTF8String(ossl.OSSL_PKEY_PARAM_GROUP_NAME, ossl.OBJ_nid2sn(int32(nid)), 0) + var selection int if isPrivate { - bld.addBin(_OSSL_PKEY_PARAM_PRIV_KEY, bytes, true) - selection = C.GO_EVP_PKEY_KEYPAIR + bld.addBin(ossl.OSSL_PKEY_PARAM_PRIV_KEY, bytes, true) + selection = ossl.EVP_PKEY_KEYPAIR } else { - bld.addOctetString(_OSSL_PKEY_PARAM_PUB_KEY, bytes) - selection = C.GO_EVP_PKEY_PUBLIC_KEY + bld.addOctetString(ossl.OSSL_PKEY_PARAM_PUB_KEY, bytes) + selection = ossl.EVP_PKEY_PUBLIC_KEY } params, err := bld.build() if err != nil { return nil, err } - defer C.go_openssl_OSSL_PARAM_free(params) - return newEvpFromParams(C.GO_EVP_PKEY_EC, selection, params) + defer ossl.OSSL_PARAM_free(params) + return newEvpFromParams(ossl.EVP_PKEY_EC, selection, params) } // deriveEcdhPublicKey sets the raw public key of pkey by deriving it from // the raw private key. -func deriveEcdhPublicKey(pkey C.GO_EVP_PKEY_PTR, curve string) error { - derive := func(group C.GO_EC_GROUP_PTR, priv C.GO_BIGNUM_PTR) (C.GO_EC_POINT_PTR, error) { +func deriveEcdhPublicKey(pkey ossl.EVP_PKEY_PTR, curve string) error { + derive := func(group ossl.EC_GROUP_PTR, priv ossl.BIGNUM_PTR) (ossl.EC_POINT_PTR, error) { // OpenSSL does not expose any method to generate the public // key from the private key [1], so we have to calculate it here. // [1] https://github.com/openssl/openssl/issues/18437#issuecomment-1144717206 - pt := C.go_openssl_EC_POINT_new(group) - if pt == nil { - return nil, newOpenSSLError("EC_POINT_new") + pt, err := ossl.EC_POINT_new(group) + if err != nil { + return nil, err } - if C.go_openssl_EC_POINT_mul(group, pt, priv, nil, nil, nil) == 0 { - C.go_openssl_EC_POINT_free(pt) - return nil, newOpenSSLError("EC_POINT_mul") + if err := ossl.EC_POINT_mul(group, pt, priv, nil, nil, nil); err != nil { + ossl.EC_POINT_free(pt) + return nil, err } return pt, nil } switch vMajor { case 1: key := getECKey(pkey) - priv := C.go_openssl_EC_KEY_get0_private_key(key) - if priv == nil { - return newOpenSSLError("EC_KEY_get0_private_key") + priv, err := ossl.EC_KEY_get0_private_key(key) + if err != nil { + return err + } + group, err := ossl.EC_KEY_get0_group(key) + if err != nil { + return err } - group := C.go_openssl_EC_KEY_get0_group(key) pub, err := derive(group, priv) if err != nil { return err } - defer C.go_openssl_EC_POINT_free(pub) - if C.go_openssl_EC_KEY_set_public_key(key, pub) != 1 { - return newOpenSSLError("EC_KEY_set_public_key") + defer ossl.EC_POINT_free(pub) + if err := ossl.EC_KEY_set_public_key(key, pub); err != nil { + return err } case 3: - var priv C.GO_BIGNUM_PTR - if C.go_openssl_EVP_PKEY_get_bn_param(pkey, _OSSL_PKEY_PARAM_PRIV_KEY, &priv) != 1 { - return newOpenSSLError("EVP_PKEY_get_bn_param") + var priv ossl.BIGNUM_PTR + if err := getBnParam(pkey, ossl.OSSL_PKEY_PARAM_PRIV_KEY, &priv); err != nil { + return err } - defer C.go_openssl_BN_clear_free(priv) + defer ossl.BN_clear_free(priv) nid, _ := curveNID(curve) - pubBytes, err := generateAndEncodeEcPublicKey(nid, func(group C.GO_EC_GROUP_PTR) (C.GO_EC_POINT_PTR, error) { + pubBytes, err := generateAndEncodeEcPublicKey(nid, func(group ossl.EC_GROUP_PTR) (ossl.EC_POINT_PTR, error) { return derive(group, priv) }) if err != nil { return err } - if C.go_openssl_EVP_PKEY_set1_encoded_public_key(pkey, base(pubBytes), C.size_t(len(pubBytes))) != 1 { - return newOpenSSLError("EVP_PKEY_set1_encoded_public_key") + if err := ossl.EVP_PKEY_set1_encoded_public_key(pkey, base(pubBytes), len(pubBytes)); err != nil { + return err } default: panic(errUnsupportedVersion()) @@ -248,52 +258,52 @@ func deriveEcdhPublicKey(pkey C.GO_EVP_PKEY_PTR, curve string) error { func ECDH(priv *PrivateKeyECDH, pub *PublicKeyECDH) ([]byte, error) { defer runtime.KeepAlive(priv) defer runtime.KeepAlive(pub) - ctx := C.go_openssl_EVP_PKEY_CTX_new(priv._pkey, nil) - if ctx == nil { - return nil, newOpenSSLError("EVP_PKEY_CTX_new") + ctx, err := ossl.EVP_PKEY_CTX_new(priv._pkey, nil) + if err != nil { + return nil, err } - defer C.go_openssl_EVP_PKEY_CTX_free(ctx) - if C.go_openssl_EVP_PKEY_derive_init(ctx) != 1 { - return nil, newOpenSSLError("EVP_PKEY_derive_init") + defer ossl.EVP_PKEY_CTX_free(ctx) + if err := ossl.EVP_PKEY_derive_init(ctx); err != nil { + return nil, err } - if C.go_openssl_EVP_PKEY_derive_set_peer(ctx, pub._pkey) != 1 { - return nil, newOpenSSLError("EVP_PKEY_derive_set_peer") + if err := ossl.EVP_PKEY_derive_set_peer(ctx, pub._pkey); err != nil { + return nil, err } - r := C.go_openssl_EVP_PKEY_derive_wrapper(ctx, nil, 0) - if r.result != 1 { - return nil, newOpenSSLError("EVP_PKEY_derive_init") + keyLength, err := ossl.EVP_PKEY_derive_wrapper(ctx, nil, 0) + if err != nil { + return nil, err } - out := make([]byte, r.keylen) - if C.go_openssl_EVP_PKEY_derive_wrapper(ctx, base(out), r.keylen).result != 1 { - return nil, newOpenSSLError("EVP_PKEY_derive_init") + out := make([]byte, keyLength) + if _, err := ossl.EVP_PKEY_derive_wrapper(ctx, base(out), keyLength); err != nil { + return nil, err } return out, nil } func GenerateKeyECDH(curve string) (*PrivateKeyECDH, []byte, error) { - pkey, err := generateEVPPKey(C.GO_EVP_PKEY_EC, 0, curve) + pkey, err := generateEVPPKey(ossl.EVP_PKEY_EC, 0, curve) if err != nil { return nil, nil, err } var k *PrivateKeyECDH defer func() { if k == nil { - C.go_openssl_EVP_PKEY_free(pkey) + ossl.EVP_PKEY_free(pkey) } }() - var priv C.GO_BIGNUM_PTR + var priv ossl.BIGNUM_PTR switch vMajor { case 1: key := getECKey(pkey) - priv = C.go_openssl_EC_KEY_get0_private_key(key) - if priv == nil { - return nil, nil, newOpenSSLError("EC_KEY_get0_private_key") + priv, err = ossl.EC_KEY_get0_private_key(key) + if err != nil { + return nil, nil, err } case 3: - if C.go_openssl_EVP_PKEY_get_bn_param(pkey, _OSSL_PKEY_PARAM_PRIV_KEY, &priv) != 1 { - return nil, nil, newOpenSSLError("EVP_PKEY_get_bn_param") + if err := getBnParam(pkey, ossl.OSSL_PKEY_PARAM_PRIV_KEY, &priv); err != nil { + return nil, nil, err } - defer C.go_openssl_BN_clear_free(priv) + defer ossl.BN_clear_free(priv) default: panic(errUnsupportedVersion()) } @@ -302,7 +312,7 @@ func GenerateKeyECDH(curve string) (*PrivateKeyECDH, []byte, error) { // The fixed length is the order of the large prime subgroup of the curve, // returned by EVP_PKEY_get_bits, which is generally the upper bound for // generating a private ECDH key. - bits := C.go_openssl_EVP_PKEY_get_bits(pkey) + bits := ossl.EVP_PKEY_get_bits(pkey) bytes := make([]byte, (bits+7)/8) if err := bnToBinPad(priv, bytes); err != nil { return nil, nil, err diff --git a/ecdsa.go b/ecdsa.go index f85782a..d7de63c 100644 --- a/ecdsa.go +++ b/ecdsa.go @@ -1,39 +1,39 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( "crypto" "errors" "runtime" + + "github.com/golang-fips/openssl/v2/internal/ossl" ) type PrivateKeyECDSA struct { // _pkey MUST NOT be accessed directly. Instead, use the withKey method. - _pkey C.GO_EVP_PKEY_PTR + _pkey ossl.EVP_PKEY_PTR } func (k *PrivateKeyECDSA) finalize() { - C.go_openssl_EVP_PKEY_free(k._pkey) + ossl.EVP_PKEY_free(k._pkey) } -func (k *PrivateKeyECDSA) withKey(f func(C.GO_EVP_PKEY_PTR) C.int) C.int { +func (k *PrivateKeyECDSA) withKey(f func(ossl.EVP_PKEY_PTR) error) error { defer runtime.KeepAlive(k) return f(k._pkey) } type PublicKeyECDSA struct { // _pkey MUST NOT be accessed directly. Instead, use the withKey method. - _pkey C.GO_EVP_PKEY_PTR + _pkey ossl.EVP_PKEY_PTR } func (k *PublicKeyECDSA) finalize() { - C.go_openssl_EVP_PKEY_free(k._pkey) + ossl.EVP_PKEY_free(k._pkey) } -func (k *PublicKeyECDSA) withKey(f func(C.GO_EVP_PKEY_PTR) C.int) C.int { +func (k *PublicKeyECDSA) withKey(f func(ossl.EVP_PKEY_PTR) error) error { defer runtime.KeepAlive(k) return f(k._pkey) } @@ -61,42 +61,62 @@ func NewPrivateKeyECDSA(curve string, x, y, d BigInt) (*PrivateKeyECDSA, error) } func GenerateKeyECDSA(curve string) (x, y, d BigInt, err error) { + fail := func(err error) (BigInt, BigInt, BigInt, error) { + return nil, nil, nil, err + } // Generate the private key. - pkey, err := generateEVPPKey(C.GO_EVP_PKEY_EC, 0, curve) + pkey, err := generateEVPPKey(ossl.EVP_PKEY_EC, 0, curve) if err != nil { - return nil, nil, nil, err + return fail(err) } - defer C.go_openssl_EVP_PKEY_free(pkey) + defer ossl.EVP_PKEY_free(pkey) - var bx, by, bd C.GO_BIGNUM_PTR + var bx, by, bd ossl.BIGNUM_PTR defer func() { - C.go_openssl_BN_free(bx) - C.go_openssl_BN_free(by) + ossl.BN_free(bx) + ossl.BN_free(by) }() switch vMajor { case 1: // Retrieve the internal EC_KEY, which holds the X, Y, and D coordinates. key := getECKey(pkey) - group := C.go_openssl_EC_KEY_get0_group(key) - pt := C.go_openssl_EC_KEY_get0_public_key(key) + group, err := ossl.EC_KEY_get0_group(key) + if err != nil { + return fail(err) + } + pt, err := ossl.EC_KEY_get0_public_key(key) + if err != nil { + return fail(err) + } // Allocate two big numbers to store the X and Y coordinates. - bx, by = C.go_openssl_BN_new(), C.go_openssl_BN_new() - if bx == nil || by == nil { - return nil, nil, nil, newOpenSSLError("BN_new failed") + bx, err = ossl.BN_new() + if err != nil { + return fail(err) + } + by, err = ossl.BN_new() + if err != nil { + return fail(err) } // Get X and Y. - if C.go_openssl_EC_POINT_get_affine_coordinates_GFp(group, pt, bx, by, nil) == 0 { - return nil, nil, nil, newOpenSSLError("EC_POINT_get_affine_coordinates_GFp failed") + if err := ossl.EC_POINT_get_affine_coordinates_GFp(group, pt, bx, by, nil); err != nil { + return fail(err) } // Get Z. We don't need to free it, get0 does not increase the reference count. - bd = C.go_openssl_EC_KEY_get0_private_key(key) + bd, err = ossl.EC_KEY_get0_private_key(key) + if err != nil { + return fail(err) + } case 3: - if C.go_openssl_EVP_PKEY_get_bn_param(pkey, _OSSL_PKEY_PARAM_EC_PUB_X, &bx) != 1 || - C.go_openssl_EVP_PKEY_get_bn_param(pkey, _OSSL_PKEY_PARAM_EC_PUB_Y, &by) != 1 || - C.go_openssl_EVP_PKEY_get_bn_param(pkey, _OSSL_PKEY_PARAM_PRIV_KEY, &bd) != 1 { - return nil, nil, nil, newOpenSSLError("EVP_PKEY_get_bn_param") + if err := getBnParam(pkey, ossl.OSSL_PKEY_PARAM_EC_PUB_X, &bx); err != nil { + return fail(err) } - defer C.go_openssl_BN_clear_free(bd) + if err := getBnParam(pkey, ossl.OSSL_PKEY_PARAM_EC_PUB_Y, &by); err != nil { + return fail(err) + } + if err := getBnParam(pkey, ossl.OSSL_PKEY_PARAM_PRIV_KEY, &bd); err != nil { + return fail(err) + } + defer ossl.BN_clear_free(bd) default: panic(errUnsupportedVersion()) } @@ -121,16 +141,16 @@ func HashVerifyECDSA(pub *PublicKeyECDSA, h crypto.Hash, msg, sig []byte) bool { return evpHashVerify(pub.withKey, h, msg, sig) == nil } -func newECDSAKey(curve string, x, y, d BigInt) (C.GO_EVP_PKEY_PTR, error) { +func newECDSAKey(curve string, x, y, d BigInt) (ossl.EVP_PKEY_PTR, error) { nid, err := curveNID(curve) if err != nil { return nil, err } - var bx, by, bd C.GO_BIGNUM_PTR + var bx, by, bd ossl.BIGNUM_PTR defer func() { - C.go_openssl_BN_free(bx) - C.go_openssl_BN_free(by) - C.go_openssl_BN_clear_free(bd) + ossl.BN_free(bx) + ossl.BN_free(by) + ossl.BN_clear_free(bd) }() bx = bigToBN(x) by = bigToBN(y) @@ -148,38 +168,40 @@ func newECDSAKey(curve string, x, y, d BigInt) (C.GO_EVP_PKEY_PTR, error) { } } -func newECDSAKey1(nid C.int, bx, by, bd C.GO_BIGNUM_PTR) (pkey C.GO_EVP_PKEY_PTR, err error) { +func newECDSAKey1(nid int, bx, by, bd ossl.BIGNUM_PTR) (pkey ossl.EVP_PKEY_PTR, err error) { checkMajorVersion(1) - key := C.go_openssl_EC_KEY_new_by_curve_name(nid) - if key == nil { - return nil, newOpenSSLError("EC_KEY_new_by_curve_name failed") + key, err := ossl.EC_KEY_new_by_curve_name(int32(nid)) + if err != nil { + return nil, err } defer func() { if pkey == nil { - defer C.go_openssl_EC_KEY_free(key) + defer ossl.EC_KEY_free(key) } }() - if C.go_openssl_EC_KEY_set_public_key_affine_coordinates(key, bx, by) != 1 { - return nil, newOpenSSLError("EC_KEY_set_public_key_affine_coordinates failed") + if err := ossl.EC_KEY_set_public_key_affine_coordinates(key, bx, by); err != nil { + return nil, err } - if bd != nil && C.go_openssl_EC_KEY_set_private_key(key, bd) != 1 { - return nil, newOpenSSLError("EC_KEY_set_private_key failed") + if bd != nil { + if err := ossl.EC_KEY_set_private_key(key, bd); err != nil { + return nil, err + } } return newEVPPKEY(key) } -func newECDSAKey3(nid C.int, bx, by, bd C.GO_BIGNUM_PTR) (C.GO_EVP_PKEY_PTR, error) { +func newECDSAKey3(nid int, bx, by, bd ossl.BIGNUM_PTR) (ossl.EVP_PKEY_PTR, error) { checkMajorVersion(3) // Create the encoded public key public key from bx and by. - pubBytes, err := generateAndEncodeEcPublicKey(nid, func(group C.GO_EC_GROUP_PTR) (C.GO_EC_POINT_PTR, error) { - pt := C.go_openssl_EC_POINT_new(group) - if pt == nil { - return nil, newOpenSSLError("EC_POINT_new") + pubBytes, err := generateAndEncodeEcPublicKey(nid, func(group ossl.EC_GROUP_PTR) (ossl.EC_POINT_PTR, error) { + pt, err := ossl.EC_POINT_new(group) + if err != nil { + return nil, err } - if C.go_openssl_EC_POINT_set_affine_coordinates(group, pt, bx, by, nil) != 1 { - C.go_openssl_EC_POINT_free(pt) + if err := ossl.EC_POINT_set_affine_coordinates(group, pt, bx, by, nil); err != nil { + ossl.EC_POINT_free(pt) return nil, newOpenSSLError("EC_POINT_set_affine_coordinates") } return pt, nil @@ -193,19 +215,19 @@ func newECDSAKey3(nid C.int, bx, by, bd C.GO_BIGNUM_PTR) (C.GO_EVP_PKEY_PTR, err return nil, err } defer bld.finalize() - bld.addUTF8String(_OSSL_PKEY_PARAM_GROUP_NAME, C.go_openssl_OBJ_nid2sn(nid), 0) - bld.addOctetString(_OSSL_PKEY_PARAM_PUB_KEY, pubBytes) - var selection C.int + bld.addUTF8String(ossl.OSSL_PKEY_PARAM_GROUP_NAME, ossl.OBJ_nid2sn(int32(nid)), 0) + bld.addOctetString(ossl.OSSL_PKEY_PARAM_PUB_KEY, pubBytes) + var selection int if bd != nil { - bld.addBN(_OSSL_PKEY_PARAM_PRIV_KEY, bd) - selection = C.GO_EVP_PKEY_KEYPAIR + bld.addBN(ossl.OSSL_PKEY_PARAM_PRIV_KEY, bd) + selection = ossl.EVP_PKEY_KEYPAIR } else { - selection = C.GO_EVP_PKEY_PUBLIC_KEY + selection = ossl.EVP_PKEY_PUBLIC_KEY } params, err := bld.build() if err != nil { return nil, err } - defer C.go_openssl_OSSL_PARAM_free(params) - return newEvpFromParams(C.GO_EVP_PKEY_EC, selection, params) + defer ossl.OSSL_PARAM_free(params) + return newEvpFromParams(ossl.EVP_PKEY_EC, selection, params) } diff --git a/ecdsa_test.go b/ecdsa_test.go index 40186a7..2a805b5 100644 --- a/ecdsa_test.go +++ b/ecdsa_test.go @@ -23,7 +23,6 @@ func testAllCurves(t *testing.T, f func(*testing.T, elliptic.Curve)) { for _, test := range tests { curve := test.curve t.Run(test.name, func(t *testing.T) { - t.Parallel() f(t, curve) }) } diff --git a/ed25519.go b/ed25519.go index cd23702..f4b3e2d 100644 --- a/ed25519.go +++ b/ed25519.go @@ -1,14 +1,14 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( "errors" "runtime" "strconv" "sync" + + "github.com/golang-fips/openssl/v2/internal/ossl" ) const ( @@ -29,16 +29,16 @@ var supportsEd25519 = sync.OnceValue(func() bool { switch vMajor { case 1: if versionAtOrAbove(1, 1, 1) { - ctx := C.go_openssl_EVP_PKEY_CTX_new_id(C.GO_EVP_PKEY_ED25519, nil) - if ctx != nil { - C.go_openssl_EVP_PKEY_CTX_free(ctx) + ctx, err := ossl.EVP_PKEY_CTX_new_id(ossl.EVP_PKEY_ED25519, nil) + if err == nil { + ossl.EVP_PKEY_CTX_free(ctx) return true } } case 3: - sig := C.go_openssl_EVP_SIGNATURE_fetch(nil, keyTypeED25519, nil) - if sig != nil { - C.go_openssl_EVP_SIGNATURE_free(sig) + sig, err := ossl.EVP_SIGNATURE_fetch(nil, cStringData(ossl.KeyTypeED25519), nil) + if err == nil { + ossl.EVP_SIGNATURE_free(sig) return true } } @@ -52,11 +52,11 @@ func SupportsEd25519() bool { } type PublicKeyEd25519 struct { - _pkey C.GO_EVP_PKEY_PTR + _pkey ossl.EVP_PKEY_PTR } func (k *PublicKeyEd25519) finalize() { - C.go_openssl_EVP_PKEY_free(k._pkey) + ossl.EVP_PKEY_free(k._pkey) } func (k *PublicKeyEd25519) Bytes() ([]byte, error) { @@ -69,11 +69,11 @@ func (k *PublicKeyEd25519) Bytes() ([]byte, error) { } type PrivateKeyEd25519 struct { - _pkey C.GO_EVP_PKEY_PTR + _pkey ossl.EVP_PKEY_PTR } func (k *PrivateKeyEd25519) finalize() { - C.go_openssl_EVP_PKEY_free(k._pkey) + ossl.EVP_PKEY_free(k._pkey) } func (k *PrivateKeyEd25519) Bytes() ([]byte, error) { @@ -99,7 +99,7 @@ func (k *PrivateKeyEd25519) Public() (*PublicKeyEd25519, error) { // GenerateKeyEd25519 generates a private key. func GenerateKeyEd25519() (*PrivateKeyEd25519, error) { - pkeyPriv, err := generateEVPPKey(C.GO_EVP_PKEY_ED25519, 0, "") + pkeyPriv, err := generateEVPPKey(ossl.EVP_PKEY_ED25519, 0, "") if err != nil { return nil, err } @@ -119,9 +119,9 @@ func NewPublicKeyEd25119(pub []byte) (*PublicKeyEd25519, error) { if len(pub) != publicKeySizeEd25519 { panic("ed25519: bad public key length: " + strconv.Itoa(len(pub))) } - pkey := C.go_openssl_EVP_PKEY_new_raw_public_key(C.GO_EVP_PKEY_ED25519, nil, base(pub), C.size_t(len(pub))) - if pkey == nil { - return nil, newOpenSSLError("EVP_PKEY_new_raw_public_key") + pkey, err := ossl.EVP_PKEY_new_raw_public_key(ossl.EVP_PKEY_ED25519, nil, base(pub), len(pub)) + if err != nil { + return nil, err } pubk := &PublicKeyEd25519{_pkey: pkey} runtime.SetFinalizer(pubk, (*PublicKeyEd25519).finalize) @@ -135,36 +135,36 @@ func NewPrivateKeyEd25519FromSeed(seed []byte) (*PrivateKeyEd25519, error) { if len(seed) != seedSizeEd25519 { panic("ed25519: bad seed length: " + strconv.Itoa(len(seed))) } - pkey := C.go_openssl_EVP_PKEY_new_raw_private_key(C.GO_EVP_PKEY_ED25519, nil, base(seed), C.size_t(len(seed))) - if pkey == nil { - return nil, newOpenSSLError("EVP_PKEY_new_raw_private_key") + pkey, err := ossl.EVP_PKEY_new_raw_private_key(ossl.EVP_PKEY_ED25519, nil, base(seed), len(seed)) + if err != nil { + return nil, err } priv := &PrivateKeyEd25519{_pkey: pkey} runtime.SetFinalizer(priv, (*PrivateKeyEd25519).finalize) return priv, nil } -func extractPKEYPubEd25519(pkey C.GO_EVP_PKEY_PTR, pub []byte) error { - r := C.go_openssl_EVP_PKEY_get_raw_public_key_wrapper(pkey, base(pub), C.size_t(publicKeySizeEd25519)) - if r.result != 1 { - return newOpenSSLError("EVP_PKEY_get_raw_public_key") +func extractPKEYPubEd25519(pkey ossl.EVP_PKEY_PTR, pub []byte) error { + keyLength, err := ossl.EVP_PKEY_get_raw_public_key_wrapper(pkey, base(pub), publicKeySizeEd25519) + if err != nil { + return err } - if r.len != publicKeySizeEd25519 { - return errors.New("ed25519: bad public key length: " + strconv.Itoa(int(r.len))) + if keyLength != publicKeySizeEd25519 { + return errors.New("ed25519: bad public key length: " + strconv.Itoa(keyLength)) } return nil } -func extractPKEYPrivEd25519(pkey C.GO_EVP_PKEY_PTR, priv []byte) error { +func extractPKEYPrivEd25519(pkey ossl.EVP_PKEY_PTR, priv []byte) error { if err := extractPKEYPubEd25519(pkey, priv[seedSizeEd25519:]); err != nil { return err } - r := C.go_openssl_EVP_PKEY_get_raw_private_key_wrapper(pkey, base(priv), C.size_t(seedSizeEd25519)) - if r.result != 1 { - return newOpenSSLError("EVP_PKEY_get_raw_private_key") + keyLength, err := ossl.EVP_PKEY_get_raw_private_key_wrapper(pkey, base(priv), seedSizeEd25519) + if err != nil { + return err } - if r.len != seedSizeEd25519 { - return errors.New("ed25519: bad private key length: " + strconv.Itoa(int(r.len))) + if keyLength != seedSizeEd25519 { + return errors.New("ed25519: bad private key length: " + strconv.Itoa(keyLength)) } return nil } @@ -182,20 +182,20 @@ func SignEd25519(priv *PrivateKeyEd25519, message []byte) (sig []byte, err error func signEd25519(priv *PrivateKeyEd25519, sig, message []byte) error { defer runtime.KeepAlive(priv) - ctx := C.go_openssl_EVP_MD_CTX_new() - if ctx == nil { - return newOpenSSLError("EVP_MD_CTX_new") + ctx, err := ossl.EVP_MD_CTX_new() + if err != nil { + return err } - defer C.go_openssl_EVP_MD_CTX_free(ctx) - if C.go_openssl_EVP_DigestSignInit(ctx, nil, nil, nil, priv._pkey) != 1 { - return newOpenSSLError("EVP_DigestSignInit") + defer ossl.EVP_MD_CTX_free(ctx) + if err := ossl.EVP_DigestSignInit(ctx, nil, nil, nil, priv._pkey); err != nil { + return err } - r := C.go_openssl_EVP_DigestSign_wrapper(ctx, base(sig), C.size_t(signatureSizeEd25519), base(message), C.size_t(len(message))) - if r.result != 1 { - return newOpenSSLError("EVP_DigestSign") + keyLength, err := ossl.EVP_DigestSign_wrapper(ctx, base(sig), signatureSizeEd25519, base(message), len(message)) + if err != nil { + return err } - if r.siglen != signatureSizeEd25519 { - return errors.New("ed25519: bad signature length: " + strconv.Itoa(int(r.siglen))) + if keyLength != signatureSizeEd25519 { + return errors.New("ed25519: bad signature length: " + strconv.Itoa(keyLength)) } return nil } @@ -203,15 +203,15 @@ func signEd25519(priv *PrivateKeyEd25519, sig, message []byte) error { // VerifyEd25519 reports whether sig is a valid signature of message by pub. func VerifyEd25519(pub *PublicKeyEd25519, message, sig []byte) error { defer runtime.KeepAlive(pub) - ctx := C.go_openssl_EVP_MD_CTX_new() - if ctx == nil { - return newOpenSSLError("EVP_MD_CTX_new") + ctx, err := ossl.EVP_MD_CTX_new() + if err != nil { + return err } - defer C.go_openssl_EVP_MD_CTX_free(ctx) - if C.go_openssl_EVP_DigestVerifyInit(ctx, nil, nil, nil, pub._pkey) != 1 { - return newOpenSSLError("EVP_DigestVerifyInit") + defer ossl.EVP_MD_CTX_free(ctx) + if err := ossl.EVP_DigestVerifyInit(ctx, nil, nil, nil, pub._pkey); err != nil { + return err } - if C.go_openssl_EVP_DigestVerify(ctx, base(sig), C.size_t(len(sig)), base(message), C.size_t(len(message))) != 1 { + if err := ossl.EVP_DigestVerify(ctx, base(sig), len(sig), base(message), len(message)); err != nil { return errors.New("ed25519: invalid signature") } return nil diff --git a/evp.go b/evp.go index 73f65c7..5aace7e 100644 --- a/evp.go +++ b/evp.go @@ -1,9 +1,7 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( "crypto" "errors" @@ -11,12 +9,8 @@ import ( "strconv" "sync" "unsafe" -) -var ( - keyTypeRSA = C.CString("RSA") - keyTypeEC = C.CString("EC") - keyTypeED25519 = C.CString("ED25519") + "github.com/golang-fips/openssl/v2/internal/ossl" ) // cacheMD is a cache of crypto.Hash to GO_EVP_MD_PTR. @@ -47,7 +41,7 @@ func hashFuncHash(fn func() hash.Hash) (h hash.Hash, err error) { } // hashToMD converts a hash.Hash implementation from this package to a GO_EVP_MD_PTR. -func hashToMD(h hash.Hash) C.GO_EVP_MD_PTR { +func hashToMD(h hash.Hash) ossl.EVP_MD_PTR { var ch crypto.Hash switch h.(type) { case *sha1Hash, *sha1Marshal: @@ -77,7 +71,7 @@ func hashToMD(h hash.Hash) C.GO_EVP_MD_PTR { // hashFuncToMD converts a hash.Hash function to a GO_EVP_MD_PTR. // See [hashFuncHash] for details on error handling. -func hashFuncToMD(fn func() hash.Hash) (C.GO_EVP_MD_PTR, error) { +func hashFuncToMD(fn func() hash.Hash) (ossl.EVP_MD_PTR, error) { h, err := hashFuncHash(fn) if err != nil { return nil, err @@ -90,9 +84,9 @@ func hashFuncToMD(fn func() hash.Hash) (C.GO_EVP_MD_PTR, error) { } // cryptoHashToMD converts a crypto.Hash to a GO_EVP_MD_PTR. -func cryptoHashToMD(ch crypto.Hash) (md C.GO_EVP_MD_PTR) { +func cryptoHashToMD(ch crypto.Hash) (md ossl.EVP_MD_PTR) { if v, ok := cacheMD.Load(ch); ok { - return v.(C.GO_EVP_MD_PTR) + return v.(ossl.EVP_MD_PTR) } defer func() { if md != nil { @@ -101,17 +95,17 @@ func cryptoHashToMD(ch crypto.Hash) (md C.GO_EVP_MD_PTR) { // On OpenSSL 1 EVP_MD objects can be not-nil even // when they are not supported. We need to pass the md // to a EVP_MD_CTX to really know if they can be used. - ctx := C.go_openssl_EVP_MD_CTX_new() - if C.go_openssl_EVP_DigestInit_ex(ctx, md, nil) != 1 { + ctx, _ := ossl.EVP_MD_CTX_new() + if ossl.EVP_DigestInit_ex(ctx, md, nil) != nil { md = nil } - C.go_openssl_EVP_MD_CTX_free(ctx) + ossl.EVP_MD_CTX_free(ctx) case 3: // On OpenSSL 3, directly operating on a EVP_MD object // not created by EVP_MD_fetch has negative performance // implications, as digest operations will have // to fetch it on every call. Better to just fetch it once here. - md = C.go_openssl_EVP_MD_fetch(nil, C.go_openssl_EVP_MD_get0_name(md), nil) + md, _ = ossl.EVP_MD_fetch(nil, ossl.EVP_MD_get0_name(md), nil) default: panic(errUnsupportedVersion()) } @@ -123,52 +117,52 @@ func cryptoHashToMD(ch crypto.Hash) (md C.GO_EVP_MD_PTR) { // still be used when signing/verifying with an RSA key. if ch == crypto.MD5SHA1 { if vMajor == 1 && vMinor == 0 { - return C.go_openssl_EVP_md5_sha1_backport() + return ossl.EVP_md5_sha1_backport() } else { - return C.go_openssl_EVP_md5_sha1() + return ossl.EVP_md5_sha1() } } switch ch { case crypto.MD4: - return C.go_openssl_EVP_md4() + return ossl.EVP_md4() case crypto.MD5: - return C.go_openssl_EVP_md5() + return ossl.EVP_md5() case crypto.SHA1: - return C.go_openssl_EVP_sha1() + return ossl.EVP_sha1() case crypto.SHA224: - return C.go_openssl_EVP_sha224() + return ossl.EVP_sha224() case crypto.SHA256: - return C.go_openssl_EVP_sha256() + return ossl.EVP_sha256() case crypto.SHA384: - return C.go_openssl_EVP_sha384() + return ossl.EVP_sha384() case crypto.SHA512: - return C.go_openssl_EVP_sha512() + return ossl.EVP_sha512() case crypto.SHA3_224: if versionAtOrAbove(1, 1, 1) { - return C.go_openssl_EVP_sha3_224() + return ossl.EVP_sha3_224() } case crypto.SHA3_256: if versionAtOrAbove(1, 1, 1) { - return C.go_openssl_EVP_sha3_256() + return ossl.EVP_sha3_256() } case crypto.SHA3_384: if versionAtOrAbove(1, 1, 1) { - return C.go_openssl_EVP_sha3_384() + return ossl.EVP_sha3_384() } case crypto.SHA3_512: if versionAtOrAbove(1, 1, 1) { - return C.go_openssl_EVP_sha3_512() + return ossl.EVP_sha3_512() } } return nil } // generateEVPPKey generates a new EVP_PKEY with the given id and properties. -func generateEVPPKey(id C.int, bits int, curve string) (C.GO_EVP_PKEY_PTR, error) { +func generateEVPPKey(id int, bits int, curve string) (ossl.EVP_PKEY_PTR, error) { if bits != 0 && curve != "" { return nil, fail("incorrect generateEVPPKey parameters") } - var curveID C.int + var curveID int if curve != "" { var err error curveID, err = curveNID(curve) @@ -176,43 +170,44 @@ func generateEVPPKey(id C.int, bits int, curve string) (C.GO_EVP_PKEY_PTR, error return nil, err } } - var pkey C.GO_EVP_PKEY_PTR + var pkey ossl.EVP_PKEY_PTR switch vMajor { case 1: - ctx := C.go_openssl_EVP_PKEY_CTX_new_id(id, nil) - if ctx == nil { - return nil, newOpenSSLError("EVP_PKEY_CTX_new_id") + ctx, err := ossl.EVP_PKEY_CTX_new_id(int32(id), nil) + if err != nil { + return nil, err } - defer C.go_openssl_EVP_PKEY_CTX_free(ctx) - if C.go_openssl_EVP_PKEY_keygen_init(ctx) != 1 { - return nil, newOpenSSLError("EVP_PKEY_keygen_init") + defer ossl.EVP_PKEY_CTX_free(ctx) + if err := ossl.EVP_PKEY_keygen_init(ctx); err != nil { + return nil, err } if bits != 0 { - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, id, -1, C.GO_EVP_PKEY_CTRL_RSA_KEYGEN_BITS, C.int(bits), nil) != 1 { - return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl") + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, int32(id), -1, ossl.EVP_PKEY_CTRL_RSA_KEYGEN_BITS, int32(bits), nil); err != nil { + return nil, err } } if curve != "" { - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, id, -1, C.GO_EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID, curveID, nil) != 1 { - return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl") + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, int32(id), -1, ossl.EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID, int32(curveID), nil); err != nil { + return nil, err } } - if C.go_openssl_EVP_PKEY_keygen(ctx, &pkey) != 1 { - return nil, newOpenSSLError("EVP_PKEY_keygen") + if err := ossl.EVP_PKEY_keygen(ctx, &pkey); err != nil { + return nil, err } case 3: + var err error switch id { - case C.GO_EVP_PKEY_RSA: - pkey = C.go_openssl_EVP_PKEY_Q_keygen_RSA(nil, nil, keyTypeRSA, C.size_t(bits)) - case C.GO_EVP_PKEY_EC: - pkey = C.go_openssl_EVP_PKEY_Q_keygen_EC(nil, nil, keyTypeEC, C.go_openssl_OBJ_nid2sn(curveID)) - case C.GO_EVP_PKEY_ED25519: - pkey = C.go_openssl_EVP_PKEY_Q_keygen(nil, nil, keyTypeED25519) + case ossl.EVP_PKEY_RSA: + pkey, err = ossl.EVP_PKEY_Q_keygen_RSA(nil, nil, cStringData(ossl.KeyTypeRSA), bits) + case ossl.EVP_PKEY_EC: + pkey, err = ossl.EVP_PKEY_Q_keygen_EC(nil, nil, cStringData(ossl.KeyTypeEC), ossl.OBJ_nid2sn(int32(curveID))) + case ossl.EVP_PKEY_ED25519: + pkey, err = ossl.EVP_PKEY_Q_keygen_ED25519(nil, nil, cStringData(ossl.KeyTypeED25519)) default: panic("unsupported key type '" + strconv.Itoa(int(id)) + "'") } - if pkey == nil { - return nil, newOpenSSLError("EVP_PKEY_Q_keygen") + if err != nil { + return nil, err } default: panic(errUnsupportedVersion()) @@ -221,26 +216,26 @@ func generateEVPPKey(id C.int, bits int, curve string) (C.GO_EVP_PKEY_PTR, error return pkey, nil } -type withKeyFunc func(func(C.GO_EVP_PKEY_PTR) C.int) C.int -type initFunc func(C.GO_EVP_PKEY_CTX_PTR) error -type cryptFunc func(C.GO_EVP_PKEY_CTX_PTR, *C.uchar, *C.size_t, *C.uchar, C.size_t) error -type verifyFunc func(C.GO_EVP_PKEY_CTX_PTR, *C.uchar, C.size_t, *C.uchar, C.size_t) error +type withKeyFunc func(func(ossl.EVP_PKEY_PTR) error) error +type initFunc func(ossl.EVP_PKEY_CTX_PTR) error +type cryptFunc func(ossl.EVP_PKEY_CTX_PTR, *byte, *int, *byte, int) error +type verifyFunc func(ossl.EVP_PKEY_CTX_PTR, *byte, int, *byte, int) error -func setupEVP(withKey withKeyFunc, padding C.int, - h, mgfHash hash.Hash, label []byte, saltLen C.int, ch crypto.Hash, - init initFunc) (_ C.GO_EVP_PKEY_CTX_PTR, err error) { - var ctx C.GO_EVP_PKEY_CTX_PTR - withKey(func(pkey C.GO_EVP_PKEY_PTR) C.int { - ctx = C.go_openssl_EVP_PKEY_CTX_new(pkey, nil) - return 1 +func setupEVP(withKey withKeyFunc, padding int, + h, mgfHash hash.Hash, label []byte, saltLen int, ch crypto.Hash, + init initFunc) (_ ossl.EVP_PKEY_CTX_PTR, err error) { + var ctx ossl.EVP_PKEY_CTX_PTR + err = withKey(func(pkey ossl.EVP_PKEY_PTR) (err error) { + ctx, err = ossl.EVP_PKEY_CTX_new(pkey, nil) + return err }) - if ctx == nil { - return nil, newOpenSSLError("EVP_PKEY_CTX_new failed") + if err != nil { + return nil, err } defer func() { if err != nil { if ctx != nil { - C.go_openssl_EVP_PKEY_CTX_free(ctx) + ossl.EVP_PKEY_CTX_free(ctx) ctx = nil } } @@ -254,18 +249,18 @@ func setupEVP(withKey withKeyFunc, padding C.int, // Each padding type has its own requirements in terms of when to apply the padding, // so it can't be just set at this point. setPadding := func() error { - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, C.GO_EVP_PKEY_RSA, -1, C.GO_EVP_PKEY_CTRL_RSA_PADDING, padding, nil) != 1 { - return newOpenSSLError("EVP_PKEY_CTX_ctrl failed") + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, ossl.EVP_PKEY_RSA, -1, ossl.EVP_PKEY_CTRL_RSA_PADDING, int32(padding), nil); err != nil { + return err } return nil } switch padding { - case C.GO_RSA_PKCS1_OAEP_PADDING: + case ossl.RSA_PKCS1_OAEP_PADDING: md := hashToMD(h) if md == nil { return nil, errors.New("crypto/rsa: unsupported hash function") } - var mgfMD C.GO_EVP_MD_PTR + var mgfMD ossl.EVP_MD_PTR if mgfHash != nil { // mgfHash is optional, but if it is set it must match a supported hash function. mgfMD = hashToMD(mgfHash) @@ -277,65 +272,58 @@ func setupEVP(withKey withKeyFunc, padding C.int, if err := setPadding(); err != nil { return nil, err } - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, C.GO_EVP_PKEY_RSA, -1, C.GO_EVP_PKEY_CTRL_RSA_OAEP_MD, 0, unsafe.Pointer(md)) != 1 { - return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl failed") + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, ossl.EVP_PKEY_RSA, -1, ossl.EVP_PKEY_CTRL_RSA_OAEP_MD, 0, unsafe.Pointer(md)); err != nil { + return nil, err } if mgfHash != nil { - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, C.GO_EVP_PKEY_RSA, -1, C.GO_EVP_PKEY_CTRL_RSA_MGF1_MD, 0, unsafe.Pointer(mgfMD)) != 1 { - return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl failed") + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, ossl.EVP_PKEY_RSA, -1, ossl.EVP_PKEY_CTRL_RSA_MGF1_MD, 0, unsafe.Pointer(mgfMD)); err != nil { + return nil, err } } // ctx takes ownership of label, so malloc a copy for OpenSSL to free. // OpenSSL does not take ownership of the label if the length is zero, // so better avoid the allocation. - var clabel *C.uchar if len(label) > 0 { - clabel = (*C.uchar)(cryptoMalloc(len(label))) + clabel := cryptoMalloc(len(label)) copy((*[1 << 30]byte)(unsafe.Pointer(clabel))[:len(label)], label) var err error if vMajor == 3 { - ret := C.go_openssl_EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, unsafe.Pointer(clabel), C.int(len(label))) - if ret != 1 { - err = newOpenSSLError("EVP_PKEY_CTX_set0_rsa_oaep_label failed") - } + err = ossl.EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, clabel, int32(len(label))) } else { - ret := C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, C.GO_EVP_PKEY_RSA, -1, C.GO_EVP_PKEY_CTRL_RSA_OAEP_LABEL, C.int(len(label)), unsafe.Pointer(clabel)) - if ret != 1 { - err = newOpenSSLError("EVP_PKEY_CTX_ctrl failed") - } + err = ossl.EVP_PKEY_CTX_ctrl(ctx, ossl.EVP_PKEY_RSA, -1, ossl.EVP_PKEY_CTRL_RSA_OAEP_LABEL, int32(len(label)), clabel) } if err != nil { - cryptoFree(unsafe.Pointer(clabel)) + cryptoFree(clabel) return nil, err } } - case C.GO_RSA_PKCS1_PSS_PADDING: + case ossl.RSA_PKCS1_PSS_PADDING: md := cryptoHashToMD(ch) if md == nil { return nil, errors.New("crypto/rsa: unsupported hash function") } - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, C.GO_EVP_PKEY_RSA, -1, C.GO_EVP_PKEY_CTRL_MD, 0, unsafe.Pointer(md)) != 1 { - return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl failed") + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, ossl.EVP_PKEY_RSA, -1, ossl.EVP_PKEY_CTRL_MD, 0, unsafe.Pointer(md)); err != nil { + return nil, err } // setPadding must happen after setting EVP_PKEY_CTRL_MD. if err := setPadding(); err != nil { return nil, err } if saltLen != 0 { - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, C.GO_EVP_PKEY_RSA, -1, C.GO_EVP_PKEY_CTRL_RSA_PSS_SALTLEN, saltLen, nil) != 1 { - return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl failed") + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, ossl.EVP_PKEY_RSA, -1, ossl.EVP_PKEY_CTRL_RSA_PSS_SALTLEN, int32(saltLen), nil); err != nil { + return nil, err } } - case C.GO_RSA_PKCS1_PADDING: + case ossl.RSA_PKCS1_PADDING: if ch != 0 { // We support unhashed messages. md := cryptoHashToMD(ch) if md == nil { return nil, errors.New("crypto/rsa: unsupported hash function") } - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, -1, -1, C.GO_EVP_PKEY_CTRL_MD, 0, unsafe.Pointer(md)) != 1 { - return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl failed") + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, -1, -1, ossl.EVP_PKEY_CTRL_MD, 0, unsafe.Pointer(md)); err != nil { + return nil, err } if err := setPadding(); err != nil { return nil, err @@ -349,21 +337,23 @@ func setupEVP(withKey withKeyFunc, padding C.int, return ctx, nil } -func cryptEVP(withKey withKeyFunc, padding C.int, - h, mgfHash hash.Hash, label []byte, saltLen C.int, ch crypto.Hash, +func cryptEVP(withKey withKeyFunc, padding int, + h, mgfHash hash.Hash, label []byte, saltLen int, ch crypto.Hash, init initFunc, crypt cryptFunc, in []byte) ([]byte, error) { ctx, err := setupEVP(withKey, padding, h, mgfHash, label, saltLen, ch, init) if err != nil { return nil, err } - defer C.go_openssl_EVP_PKEY_CTX_free(ctx) - pkeySize := withKey(func(pkey C.GO_EVP_PKEY_PTR) C.int { - return C.go_openssl_EVP_PKEY_get_size(pkey) + defer ossl.EVP_PKEY_CTX_free(ctx) + var pkeySize int + withKey(func(pkey ossl.EVP_PKEY_PTR) error { + pkeySize = int(ossl.EVP_PKEY_get_size(pkey)) + return nil }) - outLen := C.size_t(pkeySize) + outLen := pkeySize out := make([]byte, pkeySize) - if err := crypt(ctx, base(out), &outLen, base(in), C.size_t(len(in))); err != nil { + if err := crypt(ctx, base(out), &outLen, base(in), len(in)); err != nil { return nil, err } // The size returned by EVP_PKEY_get_size() is only preliminary and not exact, @@ -371,8 +361,8 @@ func cryptEVP(withKey withKeyFunc, padding C.int, return out[:outLen], nil } -func verifyEVP(withKey withKeyFunc, padding C.int, - h hash.Hash, label []byte, saltLen C.int, ch crypto.Hash, +func verifyEVP(withKey withKeyFunc, padding int, + h hash.Hash, label []byte, saltLen int, ch crypto.Hash, init initFunc, verify verifyFunc, sig, in []byte) error { @@ -380,72 +370,24 @@ func verifyEVP(withKey withKeyFunc, padding C.int, if err != nil { return err } - defer C.go_openssl_EVP_PKEY_CTX_free(ctx) - return verify(ctx, base(sig), C.size_t(len(sig)), base(in), C.size_t(len(in))) + defer ossl.EVP_PKEY_CTX_free(ctx) + return verify(ctx, base(sig), len(sig), base(in), len(in)) } -func evpEncrypt(withKey withKeyFunc, padding C.int, h, mgfHash hash.Hash, label, msg []byte) ([]byte, error) { - encryptInit := func(ctx C.GO_EVP_PKEY_CTX_PTR) error { - if ret := C.go_openssl_EVP_PKEY_encrypt_init(ctx); ret != 1 { - return newOpenSSLError("EVP_PKEY_encrypt_init failed") - } - return nil - } - encrypt := func(ctx C.GO_EVP_PKEY_CTX_PTR, out *C.uchar, outLen *C.size_t, in *C.uchar, inLen C.size_t) error { - if ret := C.go_openssl_EVP_PKEY_encrypt(ctx, out, outLen, in, inLen); ret != 1 { - return newOpenSSLError("EVP_PKEY_encrypt failed") - } - return nil - } - return cryptEVP(withKey, padding, h, mgfHash, label, 0, 0, encryptInit, encrypt, msg) +func evpEncrypt(withKey withKeyFunc, padding int, h, mgfHash hash.Hash, label, msg []byte) ([]byte, error) { + return cryptEVP(withKey, padding, h, mgfHash, label, 0, 0, ossl.EVP_PKEY_encrypt_init, ossl.EVP_PKEY_encrypt, msg) } -func evpDecrypt(withKey withKeyFunc, padding C.int, h, mgfHash hash.Hash, label, msg []byte) ([]byte, error) { - decryptInit := func(ctx C.GO_EVP_PKEY_CTX_PTR) error { - if ret := C.go_openssl_EVP_PKEY_decrypt_init(ctx); ret != 1 { - return newOpenSSLError("EVP_PKEY_decrypt_init failed") - } - return nil - } - decrypt := func(ctx C.GO_EVP_PKEY_CTX_PTR, out *C.uchar, outLen *C.size_t, in *C.uchar, inLen C.size_t) error { - if ret := C.go_openssl_EVP_PKEY_decrypt(ctx, out, outLen, in, inLen); ret != 1 { - return newOpenSSLError("EVP_PKEY_decrypt failed") - } - return nil - } - return cryptEVP(withKey, padding, h, mgfHash, label, 0, 0, decryptInit, decrypt, msg) +func evpDecrypt(withKey withKeyFunc, padding int, h, mgfHash hash.Hash, label, msg []byte) ([]byte, error) { + return cryptEVP(withKey, padding, h, mgfHash, label, 0, 0, ossl.EVP_PKEY_decrypt_init, ossl.EVP_PKEY_decrypt, msg) } -func evpSign(withKey withKeyFunc, padding C.int, saltLen C.int, h crypto.Hash, hashed []byte) ([]byte, error) { - signtInit := func(ctx C.GO_EVP_PKEY_CTX_PTR) error { - if ret := C.go_openssl_EVP_PKEY_sign_init(ctx); ret != 1 { - return newOpenSSLError("EVP_PKEY_sign_init failed") - } - return nil - } - sign := func(ctx C.GO_EVP_PKEY_CTX_PTR, out *C.uchar, outLen *C.size_t, in *C.uchar, inLen C.size_t) error { - if ret := C.go_openssl_EVP_PKEY_sign(ctx, out, outLen, in, inLen); ret != 1 { - return newOpenSSLError("EVP_PKEY_sign failed") - } - return nil - } - return cryptEVP(withKey, padding, nil, nil, nil, saltLen, h, signtInit, sign, hashed) +func evpSign(withKey withKeyFunc, padding int, saltLen int, h crypto.Hash, hashed []byte) ([]byte, error) { + return cryptEVP(withKey, padding, nil, nil, nil, saltLen, h, ossl.EVP_PKEY_sign_init, ossl.EVP_PKEY_sign, hashed) } -func evpVerify(withKey withKeyFunc, padding C.int, saltLen C.int, h crypto.Hash, sig, hashed []byte) error { - verifyInit := func(ctx C.GO_EVP_PKEY_CTX_PTR) error { - if ret := C.go_openssl_EVP_PKEY_verify_init(ctx); ret != 1 { - return newOpenSSLError("EVP_PKEY_verify_init failed") - } - return nil - } - verify := func(ctx C.GO_EVP_PKEY_CTX_PTR, out *C.uchar, outLen C.size_t, in *C.uchar, inLen C.size_t) error { - if ret := C.go_openssl_EVP_PKEY_verify(ctx, out, outLen, in, inLen); ret != 1 { - return newOpenSSLError("EVP_PKEY_verify failed") - } - return nil - } - return verifyEVP(withKey, padding, nil, nil, saltLen, h, verifyInit, verify, sig, hashed) +func evpVerify(withKey withKeyFunc, padding int, saltLen int, h crypto.Hash, sig, hashed []byte) error { + return verifyEVP(withKey, padding, nil, nil, saltLen, h, ossl.EVP_PKEY_verify_init, ossl.EVP_PKEY_verify, sig, hashed) } func evpHashSign(withKey withKeyFunc, h crypto.Hash, msg []byte) ([]byte, error) { @@ -454,28 +396,28 @@ func evpHashSign(withKey withKeyFunc, h crypto.Hash, msg []byte) ([]byte, error) return nil, errors.New("unsupported hash function: " + strconv.Itoa(int(h))) } var out []byte - var outLen C.size_t - ctx := C.go_openssl_EVP_MD_CTX_new() - if ctx == nil { - return nil, newOpenSSLError("EVP_MD_CTX_new failed") + var outLen int + ctx, err := ossl.EVP_MD_CTX_new() + if err != nil { + return nil, err } - defer C.go_openssl_EVP_MD_CTX_free(ctx) - if withKey(func(key C.GO_EVP_PKEY_PTR) C.int { - return C.go_openssl_EVP_DigestSignInit(ctx, nil, md, nil, key) - }) != 1 { - return nil, newOpenSSLError("EVP_DigestSignInit failed") + defer ossl.EVP_MD_CTX_free(ctx) + if err := withKey(func(key ossl.EVP_PKEY_PTR) error { + return ossl.EVP_DigestSignInit(ctx, nil, md, nil, key) + }); err != nil { + return nil, err } - if C.go_openssl_EVP_DigestUpdate(ctx, unsafe.Pointer(base(msg)), C.size_t(len(msg))) != 1 { - return nil, newOpenSSLError("EVP_DigestUpdate failed") + if err := ossl.EVP_DigestUpdate(ctx, unsafe.Pointer(base(msg)), len(msg)); err != nil { + return nil, err } // Obtain the signature length - if C.go_openssl_EVP_DigestSignFinal(ctx, nil, &outLen) != 1 { - return nil, newOpenSSLError("EVP_DigestSignFinal failed") + if err := ossl.EVP_DigestSignFinal(ctx, nil, &outLen); err != nil { + return nil, err } out = make([]byte, outLen) // Obtain the signature - if C.go_openssl_EVP_DigestSignFinal(ctx, base(out), &outLen) != 1 { - return nil, newOpenSSLError("EVP_DigestSignFinal failed") + if err := ossl.EVP_DigestSignFinal(ctx, base(out), &outLen); err != nil { + return nil, err } return out[:outLen], nil } @@ -485,33 +427,30 @@ func evpHashVerify(withKey withKeyFunc, h crypto.Hash, msg, sig []byte) error { if md == nil { return errors.New("unsupported hash function: " + strconv.Itoa(int(h))) } - ctx := C.go_openssl_EVP_MD_CTX_new() - if ctx == nil { - return newOpenSSLError("EVP_MD_CTX_new failed") - } - defer C.go_openssl_EVP_MD_CTX_free(ctx) - if withKey(func(key C.GO_EVP_PKEY_PTR) C.int { - return C.go_openssl_EVP_DigestVerifyInit(ctx, nil, md, nil, key) - }) != 1 { - return newOpenSSLError("EVP_DigestVerifyInit failed") + ctx, err := ossl.EVP_MD_CTX_new() + if err != nil { + return err } - if C.go_openssl_EVP_DigestUpdate(ctx, unsafe.Pointer(base(msg)), C.size_t(len(msg))) != 1 { - return newOpenSSLError("EVP_DigestUpdate failed") + defer ossl.EVP_MD_CTX_free(ctx) + if err := withKey(func(key ossl.EVP_PKEY_PTR) error { + return ossl.EVP_DigestVerifyInit(ctx, nil, md, nil, key) + }); err != nil { + return err } - if C.go_openssl_EVP_DigestVerifyFinal(ctx, base(sig), C.size_t(len(sig))) != 1 { - return newOpenSSLError("EVP_DigestVerifyFinal failed") + if err := ossl.EVP_DigestUpdate(ctx, unsafe.Pointer(base(msg)), len(msg)); err != nil { + return err } - return nil + return ossl.EVP_DigestVerifyFinal(ctx, base(sig), len(sig)) } -func newEVPPKEY(key C.GO_EC_KEY_PTR) (C.GO_EVP_PKEY_PTR, error) { - pkey := C.go_openssl_EVP_PKEY_new() - if pkey == nil { - return nil, newOpenSSLError("EVP_PKEY_new failed") +func newEVPPKEY(key ossl.EC_KEY_PTR) (ossl.EVP_PKEY_PTR, error) { + pkey, err := ossl.EVP_PKEY_new() + if err != nil { + return nil, err } - if C.go_openssl_EVP_PKEY_assign(pkey, C.GO_EVP_PKEY_EC, unsafe.Pointer(key)) != 1 { - C.go_openssl_EVP_PKEY_free(pkey) - return nil, newOpenSSLError("EVP_PKEY_assign failed") + if err := ossl.EVP_PKEY_assign(pkey, ossl.EVP_PKEY_EC, unsafe.Pointer(key)); err != nil { + ossl.EVP_PKEY_free(pkey) + return nil, err } return pkey, nil } @@ -519,13 +458,13 @@ func newEVPPKEY(key C.GO_EC_KEY_PTR) (C.GO_EVP_PKEY_PTR, error) { // getECKey returns the EC_KEY from pkey. // If pkey does not contain an EC_KEY it panics. // The returned key should not be freed. -func getECKey(pkey C.GO_EVP_PKEY_PTR) (key C.GO_EC_KEY_PTR) { +func getECKey(pkey ossl.EVP_PKEY_PTR) (key ossl.EC_KEY_PTR) { if vMajor == 1 && vMinor == 0 { - if key0 := C.go_openssl_EVP_PKEY_get0(pkey); key0 != nil { - key = C.GO_EC_KEY_PTR(key0) + if key0, err := ossl.EVP_PKEY_get0(pkey); err != nil { + key = ossl.EC_KEY_PTR(key0) } } else { - key = C.go_openssl_EVP_PKEY_get0_EC_KEY(pkey) + key, _ = ossl.EVP_PKEY_get0_EC_KEY(pkey) } if key == nil { panic("pkey does not contain an EC_KEY") @@ -533,18 +472,18 @@ func getECKey(pkey C.GO_EVP_PKEY_PTR) (key C.GO_EC_KEY_PTR) { return key } -func newEvpFromParams(id C.int, selection C.int, params C.GO_OSSL_PARAM_PTR) (C.GO_EVP_PKEY_PTR, error) { - ctx := C.go_openssl_EVP_PKEY_CTX_new_id(id, nil) - if ctx == nil { - return nil, newOpenSSLError("EVP_PKEY_CTX_new_id") - } - defer C.go_openssl_EVP_PKEY_CTX_free(ctx) - if C.go_openssl_EVP_PKEY_fromdata_init(ctx) != 1 { - return nil, newOpenSSLError("EVP_PKEY_fromdata_init") - } - var pkey C.GO_EVP_PKEY_PTR - if C.go_openssl_EVP_PKEY_fromdata(ctx, &pkey, selection, params) != 1 { - return nil, newOpenSSLError("EVP_PKEY_fromdata") +func newEvpFromParams(id int, selection int, params ossl.OSSL_PARAM_PTR) (ossl.EVP_PKEY_PTR, error) { + ctx, err := ossl.EVP_PKEY_CTX_new_id(int32(id), nil) + if err != nil { + return nil, err + } + defer ossl.EVP_PKEY_CTX_free(ctx) + if err := ossl.EVP_PKEY_fromdata_init(ctx); err != nil { + return nil, err + } + var pkey ossl.EVP_PKEY_PTR + if err := ossl.EVP_PKEY_fromdata(ctx, &pkey, int32(selection), params); err != nil { + return nil, err } return pkey, nil } diff --git a/export_test.go b/export_test.go index f55857d..2ff9295 100644 --- a/export_test.go +++ b/export_test.go @@ -5,13 +5,13 @@ import "sync" var ErrOpen = errOpen var SymCryptProviderAvailable = sync.OnceValue(func() bool { - return isProviderAvailable("symcryptprovider") + return isProviderAvailable("symcryptprovider\x00") }) var FIPSProviderAvailable = sync.OnceValue(func() bool { - return isProviderAvailable("fips") + return isProviderAvailable("fips\x00") }) var DefaultProviderAvailable = sync.OnceValue(func() bool { - return isProviderAvailable("default") + return isProviderAvailable("default\x00") }) diff --git a/goopenssl.c b/goopenssl.c deleted file mode 100644 index 626f184..0000000 --- a/goopenssl.c +++ /dev/null @@ -1,248 +0,0 @@ -//go:build unix || windows - -#include "goopenssl.h" - -#ifdef _WIN32 -# include -# define dlsym (void*)GetProcAddress -#else -# include // dlsym -#endif -#include // fprintf - -// Approach taken from .Net System.Security.Cryptography.Native -// https://github.com/dotnet/runtime/blob/f64246ce08fb7a58221b2b7c8e68f69c02522b0d/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.c - -#define DEFINEFUNC(ret, func, args, argscall) ret (*_g_##func)args; -#define DEFINEFUNC_LEGACY_1_1(ret, func, args, argscall) DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_LEGACY_1_0(ret, func, args, argscall) DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_LEGACY_1(ret, func, args, argscall) DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_1_1(ret, func, args, argscall) DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_1_1_1(ret, func, args, argscall) DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_3_0(ret, func, args, argscall) DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_RENAMED_1_1(ret, func, oldfunc, args, argscall) DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_RENAMED_3_0(ret, func, oldfunc, args, argscall) DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_VARIADIC_3_0(ret, func, newname, args, argscall) DEFINEFUNC(ret, newname, args, argscall) - -FOR_ALL_OPENSSL_FUNCTIONS - -#undef DEFINEFUNC -#undef DEFINEFUNC_LEGACY_1_1 -#undef DEFINEFUNC_LEGACY_1_0 -#undef DEFINEFUNC_LEGACY_1 -#undef DEFINEFUNC_1_1 -#undef DEFINEFUNC_1_1_1 -#undef DEFINEFUNC_3_0 -#undef DEFINEFUNC_RENAMED_1_1 -#undef DEFINEFUNC_RENAMED_3_0 -#undef DEFINEFUNC_VARIADIC_3_0 - -// go_openssl_fips_enabled returns 1 if FIPS mode is enabled, 0 otherwise. -// As a special case, it returns -1 if it cannot determine if FIPS mode is enabled. -// See openssl.FIPS for details about its implementation. -// -// This function is reimplemented here because openssl.FIPS assumes that -// all the OpenSSL bindings are loaded, that is, go_openssl_load_functions has -// already been called. On the other hand, go_openssl_fips_enabled is called from -// openssl.CheckVersion, which is used to check if a given OpenSSL shared library -// exists and is FIPS compliant. That shared library might not be the one that -// was passed to go_openssl_load_functions, or it might not even have been called at all. -// -// It is written in C because it is not possible to directly call C function pointers -// retrieved using dlsym from Go. -int -go_openssl_fips_enabled(void* handle) -{ - // For OpenSSL 1.x. - int (*FIPS_mode)(void); - FIPS_mode = (int (*)(void))dlsym(handle, "FIPS_mode"); - if (FIPS_mode != NULL) - return FIPS_mode(); - - // For OpenSSL 3.x. - int (*EVP_default_properties_is_fips_enabled)(void*) = (int (*)(void*))dlsym(handle, "EVP_default_properties_is_fips_enabled"); - void *(*EVP_MD_fetch)(void*, const char*, const char*) = (void* (*)(void*, const char*, const char*))dlsym(handle, "EVP_MD_fetch"); - void (*EVP_MD_free)(void*) = (void (*)(void*))dlsym(handle, "EVP_MD_free"); - - if (EVP_default_properties_is_fips_enabled == NULL || EVP_MD_fetch == NULL || EVP_MD_free == NULL) { - // Shouldn't happen, but if it does, we can't determine if FIPS mode is enabled. - return -1; - } - - if (EVP_default_properties_is_fips_enabled(NULL) != 1) - return 0; - - void *md = EVP_MD_fetch(NULL, "SHA2-256", NULL); - if (md == NULL) - return 0; - - EVP_MD_free(md); - return 1; -} - -// Load all the functions stored in FOR_ALL_OPENSSL_FUNCTIONS -// and assign them to their corresponding function pointer -// defined in goopenssl.h. -void -go_openssl_load_functions(void* handle, unsigned int major, unsigned int minor, unsigned int patch) -{ -#define DEFINEFUNC_INTERNAL(name, func) \ - _g_##name = dlsym(handle, func); \ - if (_g_##name == NULL) { \ - fprintf(stderr, "Cannot get required symbol " #func " from libcrypto version %u.%u\n", major, minor); \ - abort(); \ - } -#define DEFINEFUNC(ret, func, args, argscall) \ - DEFINEFUNC_INTERNAL(func, #func) -#define DEFINEFUNC_LEGACY_1_1(ret, func, args, argscall) \ - if (major == 1 && minor == 1) \ - { \ - DEFINEFUNC_INTERNAL(func, #func) \ - } -#define DEFINEFUNC_LEGACY_1_0(ret, func, args, argscall) \ - if (major == 1 && minor == 0) \ - { \ - DEFINEFUNC_INTERNAL(func, #func) \ - } -#define DEFINEFUNC_LEGACY_1(ret, func, args, argscall) \ - if (major == 1) \ - { \ - DEFINEFUNC_INTERNAL(func, #func) \ - } -#define DEFINEFUNC_1_1(ret, func, args, argscall) \ - if (major == 3 || (major == 1 && minor == 1)) \ - { \ - DEFINEFUNC_INTERNAL(func, #func) \ - } -#define DEFINEFUNC_1_1_1(ret, func, args, argscall) \ - if (major == 3 || (major == 1 && minor == 1 && patch == 1)) \ - { \ - DEFINEFUNC_INTERNAL(func, #func) \ - } -#define DEFINEFUNC_3_0(ret, func, args, argscall) \ - if (major == 3) \ - { \ - DEFINEFUNC_INTERNAL(func, #func) \ - } -#define DEFINEFUNC_RENAMED_1_1(ret, func, oldfunc, args, argscall) \ - if (major == 1 && minor == 0) \ - { \ - DEFINEFUNC_INTERNAL(func, #oldfunc) \ - } \ - else \ - { \ - DEFINEFUNC_INTERNAL(func, #func) \ - } -#define DEFINEFUNC_RENAMED_3_0(ret, func, oldfunc, args, argscall) \ - if (major == 1) \ - { \ - DEFINEFUNC_INTERNAL(func, #oldfunc) \ - } \ - else \ - { \ - DEFINEFUNC_INTERNAL(func, #func) \ - } -#define DEFINEFUNC_VARIADIC_3_0(ret, func, newname, args, argscall) \ - if (major == 3) \ - { \ - DEFINEFUNC_INTERNAL(newname, #func) \ - } - -FOR_ALL_OPENSSL_FUNCTIONS - -#undef DEFINEFUNC -#undef DEFINEFUNC_LEGACY_1_1 -#undef DEFINEFUNC_LEGACY_1_0 -#undef DEFINEFUNC_LEGACY_1 -#undef DEFINEFUNC_1_1 -#undef DEFINEFUNC_1_1_1 -#undef DEFINEFUNC_3_0 -#undef DEFINEFUNC_RENAMED_1_1 -#undef DEFINEFUNC_RENAMED_3_0 -#undef DEFINEFUNC_VARIADIC_3_0 -} - -static unsigned long -version_num(void* handle) -{ - unsigned long (*fn)(void); - // OPENSSL_version_num is defined in OpenSSL 1.1.0 and 1.1.1. - fn = (unsigned long (*)(void))dlsym(handle, "OpenSSL_version_num"); - if (fn != NULL) - return fn(); - - // SSLeay is defined in OpenSSL 1.0.2. - fn = (unsigned long (*)(void))dlsym(handle, "SSLeay"); - if (fn != NULL) - return fn(); - - return 0; -} - -int -go_openssl_version_major(void* handle) -{ - unsigned int (*fn)(void); - // OPENSSL_version_major is supported since OpenSSL 3. - fn = (unsigned int (*)(void))dlsym(handle, "OPENSSL_version_major"); - if (fn != NULL) - return (int)fn(); - - // If OPENSSL_version_major is not defined, try with OpenSSL 1 functions. - unsigned long num = version_num(handle); - if (num < 0x10000000L || num >= 0x20000000L) - return -1; - - return 1; -} - -int -go_openssl_version_minor(void* handle) -{ - unsigned int (*fn)(void); - // OPENSSL_version_minor is supported since OpenSSL 3. - fn = (unsigned int (*)(void))dlsym(handle, "OPENSSL_version_minor"); - if (fn != NULL) - return (int)fn(); - - // If OPENSSL_version_minor is not defined, try with OpenSSL 1 functions. - unsigned long num = version_num(handle); - // OpenSSL version number follows this schema: - // MNNFFPPS: major minor fix patch status. - if (num < 0x10000000L || num >= 0x10200000L) - { - // We only support minor version 0 and 1, - // so there is no need to implement an algorithm - // that decodes the version number into individual components. - return -1; - } - - if (num >= 0x10100000L) - return 1; - - return 0; -} - -int -go_openssl_version_patch(void* handle) -{ - unsigned int (*fn)(void); - // OPENSSL_version_patch is supported since OpenSSL 3. - fn = (unsigned int (*)(void))dlsym(handle, "OPENSSL_version_patch"); - if (fn != NULL) - return (int)fn(); - - // If OPENSSL_version_patch is not defined, try with OpenSSL 1 functions. - unsigned long num = version_num(handle); - // OpenSSL version number follows this schema: - // MNNFFPPS: major minor fix patch status. - if (num < 0x10000000L || num >= 0x10200000L) - { - // We only support minor version 0 and 1, - // so there is no need to implement an algorithm - // that decodes the version number into individual components. - return -1; - } - - return (num >> 12) & 0xff; -} diff --git a/goopenssl.h b/goopenssl.h deleted file mode 100644 index 1165f99..0000000 --- a/goopenssl.h +++ /dev/null @@ -1,262 +0,0 @@ -// This header file describes the OpenSSL ABI as built for use in Go. - -#include // size_t - -#include "shims.h" - -// Suppress warnings about unused parameters. -#define UNUSED(x) (void)(x) - -static inline void -go_openssl_do_leak_check(void) -{ -#ifndef __has_feature -#define __has_feature(x) 0 -#endif - -#if (defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__) || \ - __has_feature(address_sanitizer) - extern void __lsan_do_leak_check(void); - __lsan_do_leak_check(); -#endif -} - -int go_openssl_fips_enabled(void* handle); -int go_openssl_version_major(void* handle); -int go_openssl_version_minor(void* handle); -int go_openssl_version_patch(void* handle); -int go_openssl_thread_setup(void); -void go_openssl_load_functions(void* handle, unsigned int major, unsigned int minor, unsigned int patch); -const GO_EVP_MD_PTR go_openssl_EVP_md5_sha1_backport(void); -void go_openssl_DSA_get0_pqg_backport(const GO_DSA_PTR d, GO_BIGNUM_PTR *p, GO_BIGNUM_PTR *q, GO_BIGNUM_PTR *g); -int go_openssl_DSA_set0_pqg_backport(GO_DSA_PTR d, GO_BIGNUM_PTR p, GO_BIGNUM_PTR q, GO_BIGNUM_PTR g); -void go_openssl_DSA_get0_key_backport(const GO_DSA_PTR d, GO_BIGNUM_PTR *pub_key, GO_BIGNUM_PTR *priv_key); -int go_openssl_DSA_set0_key_backport(GO_DSA_PTR d, GO_BIGNUM_PTR pub_key, GO_BIGNUM_PTR priv_key); - -// Define pointers to all the used OpenSSL functions. -// Calling C function pointers from Go is currently not supported. -// It is possible to circumvent this by using a C function wrapper. -// https://pkg.go.dev/cmd/cgo -#define DEFINEFUNC(ret, func, args, argscall) \ - extern ret (*_g_##func)args; \ - static inline ret go_openssl_##func args \ - { \ - return _g_##func argscall; \ - } -#define DEFINEFUNC_LEGACY_1_1(ret, func, args, argscall) \ - DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_LEGACY_1_0(ret, func, args, argscall) \ - DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_LEGACY_1(ret, func, args, argscall) \ - DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_1_1(ret, func, args, argscall) \ - DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_1_1_1(ret, func, args, argscall) \ - DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_3_0(ret, func, args, argscall) \ - DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_RENAMED_1_1(ret, func, oldfunc, args, argscall) \ - DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_RENAMED_3_0(ret, func, oldfunc, args, argscall) \ - DEFINEFUNC(ret, func, args, argscall) -#define DEFINEFUNC_VARIADIC_3_0(ret, func, newname, args, argscall) \ - DEFINEFUNC(ret, newname, args, argscall) - -FOR_ALL_OPENSSL_FUNCTIONS - -#undef DEFINEFUNC -#undef DEFINEFUNC_LEGACY_1_1 -#undef DEFINEFUNC_LEGACY_1_0 -#undef DEFINEFUNC_LEGACY_1 -#undef DEFINEFUNC_1_1 -#undef DEFINEFUNC_1_1_1 -#undef DEFINEFUNC_3_0 -#undef DEFINEFUNC_RENAMED_1_1 -#undef DEFINEFUNC_RENAMED_3_0 -#undef DEFINEFUNC_VARIADIC_3_0 - -// go_hash_sum copies ctx into ctx2 and calls EVP_DigestFinal using ctx2. -// This is necessary because Go hash.Hash mandates that Sum has no effect -// on the underlying stream. In particular it is OK to Sum, then Write more, -// then Sum again, and the second Sum acts as if the first didn't happen. -// It is written in C because Sum() tend to be in the hot path, -// and doing one cgo call instead of two is a significant performance win. -static inline int -go_hash_sum(GO_EVP_MD_CTX_PTR ctx, GO_EVP_MD_CTX_PTR ctx2, unsigned char *out) -{ - if (go_openssl_EVP_MD_CTX_copy(ctx2, ctx) != 1) - return 0; - // TODO: use EVP_DigestFinal_ex once we know why it leaks - // memory on OpenSSL 1.0.2. - return go_openssl_EVP_DigestFinal(ctx2, out, NULL); -} - -// These wrappers allocate out_len on the C stack to avoid having to pass a pointer from Go, which would escape to the heap. -// Use them only in situations where the output length can be safely discarded. -static inline int -go_openssl_EVP_EncryptUpdate_wrapper(GO_EVP_CIPHER_CTX_PTR ctx, unsigned char *out, const unsigned char *in, int in_len) -{ - int len; - return go_openssl_EVP_EncryptUpdate(ctx, out, &len, in, in_len); -} - -static inline int -go_openssl_EVP_DecryptUpdate_wrapper(GO_EVP_CIPHER_CTX_PTR ctx, unsigned char *out, const unsigned char *in, int in_len) -{ - int len; - return go_openssl_EVP_DecryptUpdate(ctx, out, &len, in, in_len); -} - -static inline int -go_openssl_EVP_CipherUpdate_wrapper(GO_EVP_CIPHER_CTX_PTR ctx, unsigned char *out, const unsigned char *in, int in_len) -{ - int len; - return go_openssl_EVP_CipherUpdate(ctx, out, &len, in, in_len); -} - -// These wrappers also allocate length variables on the C stack to avoid escape to the heap, but do return the result. -// A struct is returned that contains multiple return values instead of OpenSSL's approach of using pointers. - -typedef struct -{ - int result; - size_t keylen; -} go_openssl_EVP_PKEY_derive_wrapper_out; - -static inline go_openssl_EVP_PKEY_derive_wrapper_out -go_openssl_EVP_PKEY_derive_wrapper(GO_EVP_PKEY_CTX_PTR ctx, unsigned char *key, size_t keylen) -{ - go_openssl_EVP_PKEY_derive_wrapper_out r = {0, keylen}; - r.result = go_openssl_EVP_PKEY_derive(ctx, key, &r.keylen); - return r; -} - -typedef struct -{ - int result; - size_t len; -} go_openssl_EVP_PKEY_get_raw_key_out; - -static inline go_openssl_EVP_PKEY_get_raw_key_out -go_openssl_EVP_PKEY_get_raw_public_key_wrapper(const GO_EVP_PKEY_PTR pkey, unsigned char *pub, size_t len) -{ - go_openssl_EVP_PKEY_get_raw_key_out r = {0, len}; - r.result = go_openssl_EVP_PKEY_get_raw_public_key(pkey, pub, &r.len); - return r; -} - -static inline go_openssl_EVP_PKEY_get_raw_key_out -go_openssl_EVP_PKEY_get_raw_private_key_wrapper(const GO_EVP_PKEY_PTR pkey, unsigned char *priv, size_t len) -{ - go_openssl_EVP_PKEY_get_raw_key_out r = {0, len}; - r.result = go_openssl_EVP_PKEY_get_raw_private_key(pkey, priv, &r.len); - return r; -} - -typedef struct -{ - int result; - size_t siglen; -} go_openssl_EVP_DigestSign_wrapper_out; - -static inline go_openssl_EVP_DigestSign_wrapper_out -go_openssl_EVP_DigestSign_wrapper(GO_EVP_MD_CTX_PTR ctx, unsigned char *sigret, size_t siglen, const unsigned char *tbs, size_t tbslen) -{ - go_openssl_EVP_DigestSign_wrapper_out r = {0, siglen}; - r.result = go_openssl_EVP_DigestSign(ctx, sigret, &r.siglen, tbs, tbslen); - return r; -} - -// These wrappers allocate out_len on the C stack, and check that it matches the expected -// value, to avoid having to pass a pointer from Go, which would escape to the heap. - -static inline int -go_openssl_EVP_CIPHER_CTX_seal_wrapper(const GO_EVP_CIPHER_CTX_PTR ctx, - unsigned char *out, - const unsigned char *nonce, - const unsigned char *in, int in_len, - const unsigned char *aad, int aad_len) -{ - if (in_len == 0) in = (const unsigned char *)""; - if (aad_len == 0) aad = (const unsigned char *)""; - - if (go_openssl_EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, nonce) != 1) - return 0; - - int discard_len, out_len; - if (go_openssl_EVP_EncryptUpdate(ctx, NULL, &discard_len, aad, aad_len) != 1 - || go_openssl_EVP_EncryptUpdate(ctx, out, &out_len, in, in_len) != 1 - || go_openssl_EVP_EncryptFinal_ex(ctx, out + out_len, &discard_len) != 1) - { - return 0; - } - - if (in_len != out_len) - return 0; - - return go_openssl_EVP_CIPHER_CTX_ctrl(ctx, GO_EVP_CTRL_GCM_GET_TAG, 16, out + out_len); -} - -static inline int -go_openssl_EVP_CIPHER_CTX_open_wrapper(const GO_EVP_CIPHER_CTX_PTR ctx, - unsigned char *out, - const unsigned char *nonce, - const unsigned char *in, int in_len, - const unsigned char *aad, int aad_len, - const unsigned char *tag) -{ - if (in_len == 0) { - in = (const unsigned char *)""; - // OpenSSL 1.0.2 in FIPS mode contains a bug: it will fail to verify - // unless EVP_DecryptUpdate is called at least once with a non-NULL - // output buffer. OpenSSL will not dereference the output buffer when - // the input length is zero, so set it to an arbitrary non-NULL pointer - // to satisfy OpenSSL when the caller only has authenticated additional - // data (AAD) to verify. While a stack-allocated buffer could be used, - // that would risk a stack-corrupting buffer overflow if OpenSSL - // unexpectedly dereferenced it. Instead pass a value which would - // segfault if dereferenced on any modern platform where a NULL-pointer - // dereference would also segfault. - if (out == NULL) out = (unsigned char *)1; - } - if (aad_len == 0) aad = (const unsigned char *)""; - - if (go_openssl_EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, nonce) != 1) - return 0; - - // OpenSSL 1.0.x FIPS Object Module 2.0 versions below 2.0.5 require that - // the tag be set before the ciphertext, otherwise EVP_DecryptUpdate returns - // an error. At least one extant commercially-supported, FIPS validated - // build of OpenSSL 1.0.2 uses FIPS module version 2.0.1. Set the tag first - // to maximize compatibility with all OpenSSL version combinations. - if (go_openssl_EVP_CIPHER_CTX_ctrl(ctx, GO_EVP_CTRL_GCM_SET_TAG, 16, (unsigned char *)(tag)) != 1) - return 0; - - int discard_len, out_len; - if (go_openssl_EVP_DecryptUpdate(ctx, NULL, &discard_len, aad, aad_len) != 1 - || go_openssl_EVP_DecryptUpdate(ctx, out, &out_len, in, in_len) != 1) - { - return 0; - } - - if (go_openssl_EVP_DecryptFinal_ex(ctx, out + out_len, &discard_len) != 1) - return 0; - - if (out_len != in_len) - return 0; - - return 1; -} - -// Hand-roll custom wrappers for CRYPTO_malloc and CRYPTO_free which cast the -// function pointers to the correct signatures for OpenSSL 1.0.2. - -static inline void * -go_openssl_CRYPTO_malloc_legacy102(int num, const char *file, int line) { - return ((void *(*)(int, const char *, int))_g_CRYPTO_malloc)(num, file, line); -} - -static inline void -go_openssl_CRYPTO_free_legacy102(void *str) { - ((void (*)(void *))_g_CRYPTO_free)(str); -} \ No newline at end of file diff --git a/hash.go b/hash.go index 6fd3a51..5b90b79 100644 --- a/hash.go +++ b/hash.go @@ -1,9 +1,7 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( "crypto" "errors" @@ -12,6 +10,8 @@ import ( "strconv" "sync" "unsafe" + + "github.com/golang-fips/openssl/v2/internal/ossl" ) // NOTE: Implementation ported from https://go-review.googlesource.com/c/go/+/404295. @@ -26,7 +26,13 @@ import ( // This is all to preserve compatibility with the allocation behavior of the non-openssl implementations. func hashOneShot(ch crypto.Hash, p []byte, sum []byte) bool { - return C.go_openssl_EVP_Digest(unsafe.Pointer(&*addr(p)), C.size_t(len(p)), (*C.uchar)(unsafe.Pointer(&*addr(sum))), nil, cryptoHashToMD(ch), nil) != 0 + d := unsafe.Pointer(addr(p)) + s := unsafe.Pointer(addr(sum)) + var pinner runtime.Pinner + pinner.Pin(d) + pinner.Pin(s) + defer pinner.Unpin() + return ossl.EVP_Digest(d, len(p), (*byte)(s), nil, cryptoHashToMD(ch), nil) == nil } func MD4(p []byte) (sum [16]byte) { @@ -126,15 +132,12 @@ func isHashMarshallable(ch crypto.Hash) bool { if md == nil { return false } - prov := C.go_openssl_EVP_MD_get0_provider(md) - if prov == nil { - return false - } - cname := C.go_openssl_OSSL_PROVIDER_get0_name(prov) - if cname == nil { + prov, err := ossl.EVP_MD_get0_provider(md) + if err != nil { return false } - name := C.GoString(cname) + cname := ossl.OSSL_PROVIDER_get0_name(prov) + name := goString(cname) // We only know the memory layout of the built-in providers. // See evpHash.hashState for more details. marshallable := name == "default" || name == "fips" @@ -144,14 +147,15 @@ func isHashMarshallable(ch crypto.Hash) bool { // evpHash implements generic hash methods. type evpHash struct { - ctx C.GO_EVP_MD_CTX_PTR + ctx ossl.EVP_MD_CTX_PTR // ctx2 is used in evpHash.sum to avoid changing // the state of ctx. Having it here allows reusing the // same allocated object multiple times. - ctx2 C.GO_EVP_MD_CTX_PTR + ctx2 ossl.EVP_MD_CTX_PTR size int blockSize int marshallable bool + pinner runtime.Pinner } func newEvpHash(ch crypto.Hash) *evpHash { @@ -159,18 +163,25 @@ func newEvpHash(ch crypto.Hash) *evpHash { if md == nil { panic("openssl: unsupported hash function: " + strconv.Itoa(int(ch))) } - ctx := C.go_openssl_EVP_MD_CTX_new() - if C.go_openssl_EVP_DigestInit_ex(ctx, md, nil) != 1 { - C.go_openssl_EVP_MD_CTX_free(ctx) - panic(newOpenSSLError("EVP_DigestInit_ex")) + ctx, err := ossl.EVP_MD_CTX_new() + if err != nil { + panic(err) + } + if err := ossl.EVP_DigestInit_ex(ctx, md, nil); err != nil { + ossl.EVP_MD_CTX_free(ctx) + panic(err) + } + ctx2, err := ossl.EVP_MD_CTX_new() + if err != nil { + ossl.EVP_MD_CTX_free(ctx) + panic(err) } - ctx2 := C.go_openssl_EVP_MD_CTX_new() - blockSize := int(C.go_openssl_EVP_MD_get_block_size(md)) + blockSize := ossl.EVP_MD_get_block_size(md) h := &evpHash{ ctx: ctx, ctx2: ctx2, size: ch.Size(), - blockSize: blockSize, + blockSize: int(blockSize), marshallable: isHashMarshallable(ch), } runtime.SetFinalizer(h, (*evpHash).finalize) @@ -178,38 +189,47 @@ func newEvpHash(ch crypto.Hash) *evpHash { } func (h *evpHash) finalize() { - C.go_openssl_EVP_MD_CTX_free(h.ctx) - C.go_openssl_EVP_MD_CTX_free(h.ctx2) + ossl.EVP_MD_CTX_free(h.ctx) + ossl.EVP_MD_CTX_free(h.ctx2) } func (h *evpHash) Reset() { // There is no need to reset h.ctx2 because it is always reset after // use in evpHash.sum. - if C.go_openssl_EVP_DigestInit_ex(h.ctx, nil, nil) != 1 { - panic(newOpenSSLError("EVP_DigestInit_ex")) + if err := ossl.EVP_DigestInit_ex(h.ctx, nil, nil); err != nil { + panic(err) } runtime.KeepAlive(h) } func (h *evpHash) Write(p []byte) (int, error) { - if len(p) > 0 && C.go_openssl_EVP_DigestUpdate(h.ctx, unsafe.Pointer(&*addr(p)), C.size_t(len(p))) != 1 { - panic(newOpenSSLError("EVP_DigestUpdate")) + if len(p) == 0 { + return 0, nil + } + d := unsafe.Pointer(addr(p)) + h.pinner.Pin(d) + defer h.pinner.Unpin() + if err := ossl.EVP_DigestUpdate(h.ctx, d, len(p)); err != nil { + panic(err) } runtime.KeepAlive(h) return len(p), nil } func (h *evpHash) WriteString(s string) (int, error) { - if len(s) > 0 && C.go_openssl_EVP_DigestUpdate(h.ctx, unsafe.Pointer(unsafe.StringData(s)), C.size_t(len(s))) == 0 { - panic("openssl: EVP_DigestUpdate failed") + if len(s) == 0 { + return 0, nil + } + if err := ossl.EVP_DigestUpdate(h.ctx, (unsafe.Pointer)(unsafe.StringData(s)), len(s)); err != nil { + panic(err) } runtime.KeepAlive(h) return len(s), nil } func (h *evpHash) WriteByte(c byte) error { - if C.go_openssl_EVP_DigestUpdate(h.ctx, unsafe.Pointer(&c), 1) == 0 { - panic("openssl: EVP_DigestUpdate failed") + if err := ossl.EVP_DigestUpdate(h.ctx, unsafe.Pointer(&c), 1); err != nil { + panic(err) } runtime.KeepAlive(h) return nil @@ -224,8 +244,8 @@ func (h *evpHash) BlockSize() int { } func (h *evpHash) sum(out []byte) { - if C.go_hash_sum(h.ctx, h.ctx2, base(out)) != 1 { - panic(newOpenSSLError("go_hash_sum")) + if err := ossl.HashSum(h.ctx, h.ctx2, base(out)); err != nil { + panic(err) } runtime.KeepAlive(h) } @@ -234,18 +254,18 @@ func (h *evpHash) sum(out []byte) { // The duplicate object contains all state and data contained in the // original object at the point of duplication. func (h *evpHash) clone() (*evpHash, error) { - ctx := C.go_openssl_EVP_MD_CTX_new() - if ctx == nil { - return nil, newOpenSSLError("EVP_MD_CTX_new") + ctx, err := ossl.EVP_MD_CTX_new() + if err != nil { + return nil, err } - if C.go_openssl_EVP_MD_CTX_copy_ex(ctx, h.ctx) != 1 { - C.go_openssl_EVP_MD_CTX_free(ctx) - return nil, newOpenSSLError("EVP_MD_CTX_copy") + if err := ossl.EVP_MD_CTX_copy_ex(ctx, h.ctx); err != nil { + ossl.EVP_MD_CTX_free(ctx) + return nil, err } - ctx2 := C.go_openssl_EVP_MD_CTX_new() - if ctx2 == nil { - C.go_openssl_EVP_MD_CTX_free(ctx) - return nil, newOpenSSLError("EVP_MD_CTX_new") + ctx2, err := ossl.EVP_MD_CTX_new() + if err != nil { + ossl.EVP_MD_CTX_free(ctx) + return nil, err } cloned := &evpHash{ ctx: ctx, @@ -271,7 +291,7 @@ func (h *evpHash) hashState() unsafe.Pointer { // https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/crypto/evp/evp_local.h#L12. type mdCtx struct { _ [2]unsafe.Pointer - _ C.ulong + _ uint64 md_data unsafe.Pointer } return (*mdCtx)(unsafe.Pointer(h.ctx)).md_data @@ -279,7 +299,7 @@ func (h *evpHash) hashState() unsafe.Pointer { // https://github.com/openssl/openssl/blob/5675a5aaf6a2e489022bcfc18330dae9263e598e/crypto/evp/evp_local.h#L16. type mdCtx struct { _ [3]unsafe.Pointer - _ C.ulong + _ uint64 _ [3]unsafe.Pointer algctx unsafe.Pointer } diff --git a/hkdf.go b/hkdf.go index d4f8aa6..8f098ac 100644 --- a/hkdf.go +++ b/hkdf.go @@ -1,9 +1,7 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( "errors" "hash" @@ -11,6 +9,8 @@ import ( "runtime" "sync" "unsafe" + + "github.com/golang-fips/openssl/v2/internal/ossl" ) // SupprtHKDF reports whether the current OpenSSL version supports HKDF. @@ -26,53 +26,53 @@ func SupportsHKDF() bool { } } -func newHKDFCtx1(md C.GO_EVP_MD_PTR, mode C.int, secret, salt, pseudorandomKey, info []byte) (ctx C.GO_EVP_PKEY_CTX_PTR, err error) { +func newHKDFCtx1(md ossl.EVP_MD_PTR, mode int, secret, salt, pseudorandomKey, info []byte) (ctx ossl.EVP_PKEY_CTX_PTR, err error) { checkMajorVersion(1) - ctx = C.go_openssl_EVP_PKEY_CTX_new_id(C.GO_EVP_PKEY_HKDF, nil) - if ctx == nil { - return nil, newOpenSSLError("EVP_PKEY_CTX_new_id") + ctx, err = ossl.EVP_PKEY_CTX_new_id(ossl.EVP_PKEY_HKDF, nil) + if err != nil { + return nil, err } defer func() { if err != nil { - C.go_openssl_EVP_PKEY_CTX_free(ctx) + ossl.EVP_PKEY_CTX_free(ctx) } }() - if C.go_openssl_EVP_PKEY_derive_init(ctx) != 1 { - return ctx, newOpenSSLError("EVP_PKEY_derive_init") + if err := ossl.EVP_PKEY_derive_init(ctx); err != nil { + return ctx, err } - ctrlSlice := func(ctrl int, data []byte) C.int { + ctrlSlice := func(ctrl int, data []byte) error { if len(data) == 0 { - return 1 // No data to set. + return nil // No data to set. } - return C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, -1, C.GO1_EVP_PKEY_OP_DERIVE, C.int(ctrl), C.int(len(data)), unsafe.Pointer(base(data))) + return ossl.EVP_PKEY_CTX_ctrl(ctx, -1, ossl.GO1_EVP_PKEY_OP_DERIVE, int32(ctrl), int32(len(data)), unsafe.Pointer(base(data))) } - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, -1, C.GO1_EVP_PKEY_OP_DERIVE, C.GO_EVP_PKEY_CTRL_HKDF_MODE, mode, nil) != 1 { - return ctx, newOpenSSLError("EVP_PKEY_CTX_set_hkdf_mode") + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, -1, ossl.GO1_EVP_PKEY_OP_DERIVE, ossl.EVP_PKEY_CTRL_HKDF_MODE, int32(mode), nil); err != nil { + return ctx, err } - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, -1, C.GO1_EVP_PKEY_OP_DERIVE, C.GO_EVP_PKEY_CTRL_HKDF_MD, 0, unsafe.Pointer(md)) != 1 { - return ctx, newOpenSSLError("EVP_PKEY_CTX_set_hkdf_md") + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, -1, ossl.GO1_EVP_PKEY_OP_DERIVE, ossl.EVP_PKEY_CTRL_HKDF_MD, 0, unsafe.Pointer(md)); err != nil { + return ctx, err } - if ctrlSlice(C.GO_EVP_PKEY_CTRL_HKDF_KEY, secret) != 1 { - return ctx, newOpenSSLError("EVP_PKEY_CTX_set1_hkdf_key") + if err := ctrlSlice(ossl.EVP_PKEY_CTRL_HKDF_KEY, secret); err != nil { + return ctx, err } - if ctrlSlice(C.GO_EVP_PKEY_CTRL_HKDF_SALT, salt) != 1 { - return ctx, newOpenSSLError("EVP_PKEY_CTX_set1_hkdf_salt") + if err := ctrlSlice(ossl.EVP_PKEY_CTRL_HKDF_SALT, salt); err != nil { + return ctx, err } - if ctrlSlice(C.GO_EVP_PKEY_CTRL_HKDF_KEY, pseudorandomKey) != 1 { - return ctx, newOpenSSLError("EVP_PKEY_CTX_set1_hkdf_key") + if err := ctrlSlice(ossl.EVP_PKEY_CTRL_HKDF_KEY, pseudorandomKey); err != nil { + return ctx, err } - if ctrlSlice(C.GO_EVP_PKEY_CTRL_HKDF_INFO, info) != 1 { - return ctx, newOpenSSLError("EVP_PKEY_CTX_add1_hkdf_info") + if err := ctrlSlice(ossl.EVP_PKEY_CTRL_HKDF_INFO, info); err != nil { + return ctx, err } return ctx, nil } type hkdf1 struct { - ctx C.GO_EVP_PKEY_CTX_PTR + ctx ossl.EVP_PKEY_CTX_PTR hashLen int buf []byte @@ -80,7 +80,7 @@ type hkdf1 struct { func (c *hkdf1) finalize() { if c.ctx != nil { - C.go_openssl_EVP_PKEY_CTX_free(c.ctx) + ossl.EVP_PKEY_CTX_free(c.ctx) } } @@ -101,9 +101,9 @@ func (c *hkdf1) Read(p []byte) (int, error) { return 0, errors.New("hkdf: entropy limit reached") } c.buf = append(c.buf, make([]byte, needLen)...) - outLen := C.size_t(prevLen + needLen) - if C.go_openssl_EVP_PKEY_derive_wrapper(c.ctx, base(c.buf), outLen).result != 1 { - return 0, newOpenSSLError("EVP_PKEY_derive") + outLen := prevLen + needLen + if _, err := ossl.EVP_PKEY_derive_wrapper(c.ctx, base(c.buf), outLen); err != nil { + return 0, err } n := copy(p, c.buf[prevLen:outLen]) return n, nil @@ -121,29 +121,33 @@ func ExtractHKDF(h func() hash.Hash, secret, salt []byte) ([]byte, error) { switch vMajor { case 1: - ctx, err := newHKDFCtx1(md, C.GO_EVP_KDF_HKDF_MODE_EXTRACT_ONLY, secret, salt, nil, nil) + ctx, err := newHKDFCtx1(md, ossl.EVP_KDF_HKDF_MODE_EXTRACT_ONLY, secret, salt, nil, nil) if err != nil { return nil, err } - defer C.go_openssl_EVP_PKEY_CTX_free(ctx) - r := C.go_openssl_EVP_PKEY_derive_wrapper(ctx, nil, 0) - if r.result != 1 { - return nil, newOpenSSLError("EVP_PKEY_derive_init") + defer ossl.EVP_PKEY_CTX_free(ctx) + keyLength, err := ossl.EVP_PKEY_derive_wrapper(ctx, nil, 0) + if err != nil { + return nil, err } - out := make([]byte, r.keylen) - if C.go_openssl_EVP_PKEY_derive_wrapper(ctx, base(out), r.keylen).result != 1 { - return nil, newOpenSSLError("EVP_PKEY_derive") + out := make([]byte, keyLength) + if _, err := ossl.EVP_PKEY_derive_wrapper(ctx, base(out), keyLength); err != nil { + return nil, err } - return out[:r.keylen], nil + return out, nil case 3: - ctx, err := newHKDFCtx3(md, C.GO_EVP_KDF_HKDF_MODE_EXTRACT_ONLY, secret, salt, nil, nil) + ctx, err := newHKDFCtx3(md, ossl.EVP_KDF_HKDF_MODE_EXTRACT_ONLY, secret, salt, nil, nil) + if err != nil { + return nil, err + } + defer ossl.EVP_KDF_CTX_free(ctx) + size, err := ossl.EVP_KDF_CTX_get_kdf_size(ctx) if err != nil { return nil, err } - defer C.go_openssl_EVP_KDF_CTX_free(ctx) - out := make([]byte, C.go_openssl_EVP_KDF_CTX_get_kdf_size(ctx)) - if C.go_openssl_EVP_KDF_derive(ctx, base(out), C.size_t(len(out)), nil) != 1 { - return nil, newOpenSSLError("EVP_KDF_derive") + out := make([]byte, size) + if err := ossl.EVP_KDF_derive(ctx, base(out), len(out), nil); err != nil { + return nil, err } return out, nil default: @@ -165,22 +169,22 @@ func ExpandHKDFOneShot(h func() hash.Hash, pseudorandomKey, info []byte, keyLeng out := make([]byte, keyLength) switch vMajor { case 1: - ctx, err := newHKDFCtx1(md, C.GO_EVP_KDF_HKDF_MODE_EXPAND_ONLY, nil, nil, pseudorandomKey, info) + ctx, err := newHKDFCtx1(md, ossl.EVP_KDF_HKDF_MODE_EXPAND_ONLY, nil, nil, pseudorandomKey, info) if err != nil { return nil, err } - defer C.go_openssl_EVP_PKEY_CTX_free(ctx) - if C.go_openssl_EVP_PKEY_derive_wrapper(ctx, base(out), C.size_t(keyLength)).result != 1 { - return nil, newOpenSSLError("EVP_PKEY_derive") + defer ossl.EVP_PKEY_CTX_free(ctx) + if _, err := ossl.EVP_PKEY_derive_wrapper(ctx, base(out), keyLength); err != nil { + return nil, err } case 3: - ctx, err := newHKDFCtx3(md, C.GO_EVP_KDF_HKDF_MODE_EXPAND_ONLY, nil, nil, pseudorandomKey, info) + ctx, err := newHKDFCtx3(md, ossl.EVP_KDF_HKDF_MODE_EXPAND_ONLY, nil, nil, pseudorandomKey, info) if err != nil { return nil, err } - defer C.go_openssl_EVP_KDF_CTX_free(ctx) - if C.go_openssl_EVP_KDF_derive(ctx, base(out), C.size_t(keyLength), nil) != 1 { - return nil, newOpenSSLError("EVP_KDF_derive") + defer ossl.EVP_KDF_CTX_free(ctx) + if err := ossl.EVP_KDF_derive(ctx, base(out), keyLength, nil); err != nil { + return nil, err } default: panic(errUnsupportedVersion()) @@ -200,19 +204,19 @@ func ExpandHKDF(h func() hash.Hash, pseudorandomKey, info []byte) (io.Reader, er switch vMajor { case 1: - ctx, err := newHKDFCtx1(md, C.GO_EVP_KDF_HKDF_MODE_EXPAND_ONLY, nil, nil, pseudorandomKey, info) + ctx, err := newHKDFCtx1(md, ossl.EVP_KDF_HKDF_MODE_EXPAND_ONLY, nil, nil, pseudorandomKey, info) if err != nil { return nil, err } - c := &hkdf1{ctx: ctx, hashLen: int(C.go_openssl_EVP_MD_get_size(md))} + c := &hkdf1{ctx: ctx, hashLen: int(ossl.EVP_MD_get_size(md))} runtime.SetFinalizer(c, (*hkdf1).finalize) return c, nil case 3: - ctx, err := newHKDFCtx3(md, C.GO_EVP_KDF_HKDF_MODE_EXPAND_ONLY, nil, nil, pseudorandomKey, info) + ctx, err := newHKDFCtx3(md, ossl.EVP_KDF_HKDF_MODE_EXPAND_ONLY, nil, nil, pseudorandomKey, info) if err != nil { return nil, err } - c := &hkdf3{ctx: ctx, hashLen: int(C.go_openssl_EVP_MD_get_size(md))} + c := &hkdf3{ctx: ctx, hashLen: int(ossl.EVP_MD_get_size(md))} runtime.SetFinalizer(c, (*hkdf3).finalize) return c, nil default: @@ -221,7 +225,7 @@ func ExpandHKDF(h func() hash.Hash, pseudorandomKey, info []byte) (io.Reader, er } type hkdf3 struct { - ctx C.GO_EVP_KDF_CTX_PTR + ctx ossl.EVP_KDF_CTX_PTR hashLen int buf []byte @@ -229,40 +233,38 @@ type hkdf3 struct { func (c *hkdf3) finalize() { if c.ctx != nil { - C.go_openssl_EVP_KDF_CTX_free(c.ctx) + ossl.EVP_KDF_CTX_free(c.ctx) } } // fetchHKDF3 fetches the HKDF algorithm. // It is safe to call this function concurrently. // The returned EVP_KDF_PTR shouldn't be freed. -var fetchHKDF3 = sync.OnceValues(func() (C.GO_EVP_KDF_PTR, error) { +var fetchHKDF3 = sync.OnceValues(func() (ossl.EVP_KDF_PTR, error) { checkMajorVersion(3) - name := C.CString("HKDF") - kdf := C.go_openssl_EVP_KDF_fetch(nil, name, nil) - C.free(unsafe.Pointer(name)) - if kdf == nil { - return nil, newOpenSSLError("EVP_KDF_fetch") + kdf, err := ossl.EVP_KDF_fetch(nil, cStringData(ossl.OSSL_KDF_NAME_HKDF), nil) + if err != nil { + return nil, err } return kdf, nil }) // newHKDFCtx3 implements HKDF for OpenSSL 3 using the EVP_KDF API. -func newHKDFCtx3(md C.GO_EVP_MD_PTR, mode C.int, secret, salt, pseudorandomKey, info []byte) (_ C.GO_EVP_KDF_CTX_PTR, err error) { +func newHKDFCtx3(md ossl.EVP_MD_PTR, mode int, secret, salt, pseudorandomKey, info []byte) (_ ossl.EVP_KDF_CTX_PTR, err error) { checkMajorVersion(3) kdf, err := fetchHKDF3() if err != nil { return nil, err } - ctx := C.go_openssl_EVP_KDF_CTX_new(kdf) - if ctx == nil { - return nil, newOpenSSLError("EVP_KDF_CTX_new") + ctx, err := ossl.EVP_KDF_CTX_new(kdf) + if err != nil { + return nil, err } defer func() { if err != nil { - C.go_openssl_EVP_KDF_CTX_free(ctx) + ossl.EVP_KDF_CTX_free(ctx) } }() @@ -270,28 +272,28 @@ func newHKDFCtx3(md C.GO_EVP_MD_PTR, mode C.int, secret, salt, pseudorandomKey, if err != nil { return ctx, err } - bld.addUTF8String(_OSSL_KDF_PARAM_DIGEST, C.go_openssl_EVP_MD_get0_name(md), 0) - bld.addInt32(_OSSL_KDF_PARAM_MODE, int32(mode)) + bld.addUTF8String(ossl.OSSL_KDF_PARAM_DIGEST, ossl.EVP_MD_get0_name(md), 0) + bld.addInt32(ossl.OSSL_KDF_PARAM_MODE, int32(mode)) if len(secret) > 0 { - bld.addOctetString(_OSSL_KDF_PARAM_KEY, secret) + bld.addOctetString(ossl.OSSL_KDF_PARAM_KEY, secret) } if len(salt) > 0 { - bld.addOctetString(_OSSL_KDF_PARAM_SALT, salt) + bld.addOctetString(ossl.OSSL_KDF_PARAM_SALT, salt) } if len(pseudorandomKey) > 0 { - bld.addOctetString(_OSSL_KDF_PARAM_KEY, pseudorandomKey) + bld.addOctetString(ossl.OSSL_KDF_PARAM_KEY, pseudorandomKey) } if len(info) > 0 { - bld.addOctetString(_OSSL_KDF_PARAM_INFO, info) + bld.addOctetString(ossl.OSSL_KDF_PARAM_INFO, info) } params, err := bld.build() if err != nil { return ctx, err } - defer C.go_openssl_OSSL_PARAM_free(params) + defer ossl.OSSL_PARAM_free(params) - if C.go_openssl_EVP_KDF_CTX_set_params(ctx, params) != 1 { - return ctx, newOpenSSLError("EVP_KDF_CTX_set_params") + if err := ossl.EVP_KDF_CTX_set_params(ctx, params); err != nil { + return ctx, err } return ctx, nil } @@ -313,9 +315,9 @@ func (c *hkdf3) Read(p []byte) (int, error) { return 0, errors.New("hkdf: entropy limit reached") } c.buf = append(c.buf, make([]byte, needLen)...) - outLen := C.size_t(prevLen + needLen) - if C.go_openssl_EVP_KDF_derive(c.ctx, base(c.buf), outLen, nil) != 1 { - return 0, newOpenSSLError("EVP_KDF_derive") + outLen := prevLen + needLen + if err := ossl.EVP_KDF_derive(c.ctx, base(c.buf), outLen, nil); err != nil { + return 0, err } n := copy(p, c.buf[prevLen:outLen]) return n, nil diff --git a/hmac.go b/hmac.go index b519ba3..22e9eec 100644 --- a/hmac.go +++ b/hmac.go @@ -1,14 +1,14 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( "hash" "runtime" "sync" "unsafe" + + "github.com/golang-fips/openssl/v2/internal/ossl" ) // NewHMAC returns a new HMAC using OpenSSL. @@ -28,7 +28,7 @@ func NewHMAC(fh func() hash.Hash, key []byte) hash.Hash { // HMAC_Init will try and reuse the key from the ctx. This is // not the behavior previously implemented, so as a workaround // we pass an "empty" key. - key = make([]byte, C.GO_EVP_MAX_MD_SIZE) + key = make([]byte, ossl.EVP_MAX_MD_SIZE) } hmac := &opensslHMAC{ @@ -58,12 +58,12 @@ func NewHMAC(fh func() hash.Hash, key []byte) hash.Hash { // hmacCtx3 is used for OpenSSL 1. type hmacCtx1 struct { - ctx C.GO_HMAC_CTX_PTR + ctx ossl.HMAC_CTX_PTR } // hmacCtx3 is used for OpenSSL 3. type hmacCtx3 struct { - ctx C.GO_EVP_MAC_CTX_PTR + ctx ossl.EVP_MAC_CTX_PTR key []byte // only set for OpenSSL 3.0.0, 3.0.1, and 3.0.2. } @@ -75,64 +75,57 @@ type opensslHMAC struct { sum []byte } -func newHMAC1(key []byte, md C.GO_EVP_MD_PTR) hmacCtx1 { +func newHMAC1(key []byte, md ossl.EVP_MD_PTR) hmacCtx1 { ctx := hmacCtxNew() - if ctx == nil { - panic("openssl: EVP_MAC_CTX_new failed") - } - if C.go_openssl_HMAC_Init_ex(ctx, unsafe.Pointer(&key[0]), C.int(len(key)), md, nil) == 0 { - panic(newOpenSSLError("HMAC_Init_ex failed")) + if err := ossl.HMAC_Init_ex(ctx, unsafe.Pointer(&key[0]), int32(len(key)), md, nil); err != nil { + panic(err) } return hmacCtx1{ctx} } var hmacDigestsSupported sync.Map -var fetchHMAC3 = sync.OnceValue(func() C.GO_EVP_MAC_PTR { - name := C.CString("HMAC") - mac := C.go_openssl_EVP_MAC_fetch(nil, name, nil) - C.free(unsafe.Pointer(name)) - if mac == nil { +var fetchHMAC3 = sync.OnceValue(func() ossl.EVP_MAC_PTR { + mac, err := ossl.EVP_MAC_fetch(nil, cStringData(ossl.OSSL_MAC_NAME_HMAC), nil) + if err != nil { panic("openssl: HMAC not supported") } return mac }) -func buildHMAC3Params(digest *C.char) (C.GO_OSSL_PARAM_PTR, error) { +func buildHMAC3Params(digest *byte) (ossl.OSSL_PARAM_PTR, error) { bld, err := newParamBuilder() if err != nil { return nil, err } defer bld.finalize() - bld.addUTF8String(_OSSL_MAC_PARAM_DIGEST, digest, 0) + bld.addUTF8String(ossl.OSSL_MAC_PARAM_DIGEST, digest, 0) return bld.build() } -func isHMAC3DigestSupported(digest string) bool { +func isHMAC3DigestSupported(digest *byte) bool { if v, ok := hmacDigestsSupported.Load(digest); ok { return v.(bool) } - ctx := C.go_openssl_EVP_MAC_CTX_new(fetchHMAC3()) - if ctx == nil { - panic(newOpenSSLError("EVP_MAC_CTX_new")) + ctx, err := ossl.EVP_MAC_CTX_new(fetchHMAC3()) + if err != nil { + panic(err) } - defer C.go_openssl_EVP_MAC_CTX_free(ctx) + defer ossl.EVP_MAC_CTX_free(ctx) - cdigest := C.CString(digest) - defer C.free(unsafe.Pointer(cdigest)) - params, err := buildHMAC3Params(cdigest) + params, err := buildHMAC3Params(digest) if err != nil { panic(err) } - defer C.go_openssl_OSSL_PARAM_free(params) + defer ossl.OSSL_PARAM_free(params) - supported := C.go_openssl_EVP_MAC_CTX_set_params(ctx, params) != 0 + supported := ossl.EVP_MAC_CTX_set_params(ctx, params) != nil hmacDigestsSupported.Store(digest, supported) return supported } -func newHMAC3(key []byte, md C.GO_EVP_MD_PTR) hmacCtx3 { - digest := C.go_openssl_EVP_MD_get0_name(md) - if !isHMAC3DigestSupported(C.GoString(digest)) { +func newHMAC3(key []byte, md ossl.EVP_MD_PTR) hmacCtx3 { + digest := ossl.EVP_MD_get0_name(md) + if !isHMAC3DigestSupported(digest) { // The digest is not supported by the HMAC provider. // Don't panic here so the Go standard library to // fall back to the Go implementation. @@ -143,16 +136,16 @@ func newHMAC3(key []byte, md C.GO_EVP_MD_PTR) hmacCtx3 { if err != nil { panic(err) } - defer C.go_openssl_OSSL_PARAM_free(params) + defer ossl.OSSL_PARAM_free(params) - ctx := C.go_openssl_EVP_MAC_CTX_new(fetchHMAC3()) - if ctx == nil { - panic(newOpenSSLError("EVP_MAC_CTX_new")) + ctx, err := ossl.EVP_MAC_CTX_new(fetchHMAC3()) + if err != nil { + panic(err) } - if C.go_openssl_EVP_MAC_init(ctx, base(key), C.size_t(len(key)), params) == 0 { - C.go_openssl_EVP_MAC_CTX_free(ctx) - panic(newOpenSSLError("EVP_MAC_init")) + if err := ossl.EVP_MAC_init(ctx, base(key), len(key), params); err != nil { + ossl.EVP_MAC_CTX_free(ctx) + panic(err) } var hkey []byte if vMinor == 0 && vPatch <= 2 { @@ -170,12 +163,12 @@ func newHMAC3(key []byte, md C.GO_EVP_MD_PTR) hmacCtx3 { func (h *opensslHMAC) Reset() { switch vMajor { case 1: - if C.go_openssl_HMAC_Init_ex(h.ctx1.ctx, nil, 0, nil, nil) == 0 { - panic(newOpenSSLError("HMAC_Init_ex failed")) + if err := ossl.HMAC_Init_ex(h.ctx1.ctx, nil, 0, nil, nil); err != nil { + panic(err) } case 3: - if C.go_openssl_EVP_MAC_init(h.ctx3.ctx, base(h.ctx3.key), C.size_t(len(h.ctx3.key)), nil) == 0 { - panic(newOpenSSLError("EVP_MAC_init failed")) + if err := ossl.EVP_MAC_init(h.ctx3.ctx, base(h.ctx3.key), len(h.ctx3.key), nil); err != nil { + panic(err) } default: panic(errUnsupportedVersion()) @@ -190,7 +183,7 @@ func (h *opensslHMAC) finalize() { case 1: hmacCtxFree(h.ctx1.ctx) case 3: - C.go_openssl_EVP_MAC_CTX_free(h.ctx3.ctx) + ossl.EVP_MAC_CTX_free(h.ctx3.ctx) default: panic(errUnsupportedVersion()) } @@ -200,9 +193,9 @@ func (h *opensslHMAC) Write(p []byte) (int, error) { if len(p) > 0 { switch vMajor { case 1: - C.go_openssl_HMAC_Update(h.ctx1.ctx, base(p), C.size_t(len(p))) + ossl.HMAC_Update(h.ctx1.ctx, base(p), len(p)) case 3: - C.go_openssl_EVP_MAC_update(h.ctx3.ctx, base(p), C.size_t(len(p))) + ossl.EVP_MAC_update(h.ctx3.ctx, base(p), len(p)) default: panic(errUnsupportedVersion()) } @@ -231,44 +224,45 @@ func (h *opensslHMAC) Sum(in []byte) []byte { switch vMajor { case 1: ctx2 := hmacCtxNew() - if ctx2 == nil { - panic("openssl: HMAC_CTX_new failed") - } defer hmacCtxFree(ctx2) - if C.go_openssl_HMAC_CTX_copy(ctx2, h.ctx1.ctx) == 0 { - panic("openssl: HMAC_CTX_copy failed") + if err := ossl.HMAC_CTX_copy(ctx2, h.ctx1.ctx); err != nil { + panic(err) } - C.go_openssl_HMAC_Final(ctx2, base(h.sum), nil) + ossl.HMAC_Final(ctx2, base(h.sum), nil) case 3: - ctx2 := C.go_openssl_EVP_MAC_CTX_dup(h.ctx3.ctx) - if ctx2 == nil { - panic("openssl: EVP_MAC_CTX_dup failed") + ctx2, err := ossl.EVP_MAC_CTX_dup(h.ctx3.ctx) + if err != nil { + panic(err) } - defer C.go_openssl_EVP_MAC_CTX_free(ctx2) - C.go_openssl_EVP_MAC_final(ctx2, base(h.sum), nil, C.size_t(len(h.sum))) + defer ossl.EVP_MAC_CTX_free(ctx2) + ossl.EVP_MAC_final(ctx2, base(h.sum), nil, len(h.sum)) default: panic(errUnsupportedVersion()) } return append(in, h.sum...) } -func hmacCtxNew() C.GO_HMAC_CTX_PTR { +func hmacCtxNew() ossl.HMAC_CTX_PTR { if vMajor == 1 && vMinor == 0 { // 0x120 is the sizeof value when building against OpenSSL 1.0.2 on Ubuntu 16.04. - ctx := (C.GO_HMAC_CTX_PTR)(C.malloc(0x120)) + ctx := (ossl.HMAC_CTX_PTR)(ossl.CRYPTO_malloc_legacy102(0x120, nil, 0)) if ctx != nil { - C.go_openssl_HMAC_CTX_init(ctx) + ossl.HMAC_CTX_init(ctx) } return ctx } - return C.go_openssl_HMAC_CTX_new() + ctx, err := ossl.HMAC_CTX_new() + if err != nil { + panic(err) + } + return ctx } -func hmacCtxFree(ctx C.GO_HMAC_CTX_PTR) { +func hmacCtxFree(ctx ossl.HMAC_CTX_PTR) { if vMajor == 1 && vMinor == 0 { - C.go_openssl_HMAC_CTX_cleanup(ctx) - C.free(unsafe.Pointer(ctx)) + ossl.HMAC_CTX_cleanup(ctx) + ossl.CRYPTO_free_legacy102(unsafe.Pointer(ctx)) return } - C.go_openssl_HMAC_CTX_free(ctx) + ossl.HMAC_CTX_free(ctx) } diff --git a/init.go b/init.go index a146632..9a2d031 100644 --- a/init.go +++ b/init.go @@ -1,11 +1,11 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( "errors" + + "github.com/golang-fips/openssl/v2/internal/ossl" ) // opensslInit loads and initialize OpenSSL. @@ -24,9 +24,9 @@ func opensslInit(file string) (major, minor, patch uint, err error) { // Notice that major and minor could not match with the version parameter // in case the name of the shared library file differs from the OpenSSL // version it contains. - imajor := int(C.go_openssl_version_major(handle)) - iminor := int(C.go_openssl_version_minor(handle)) - ipatch := int(C.go_openssl_version_patch(handle)) + imajor := ossl.Go_openssl_version_major(handle) + iminor := ossl.Go_openssl_version_minor(handle) + ipatch := ossl.Go_openssl_version_minor(handle) if imajor < 0 || iminor < 0 || ipatch < 0 { return 0, 0, 0, errors.New("openssl: can't retrieve OpenSSL version") } @@ -42,22 +42,18 @@ func opensslInit(file string) (major, minor, patch uint, err error) { return 0, 0, 0, errUnsupportedVersion() } - // Load the OpenSSL functions. - // See shims.go for the complete list of supported functions. - C.go_openssl_load_functions(handle, C.uint(major), C.uint(minor), C.uint(patch)) + ossl.LoadLcrypto(handle) // Initialize OpenSSL. - C.go_openssl_OPENSSL_init() + ossl.OPENSSL_init() if major == 1 && minor == 0 { - if C.go_openssl_thread_setup() != 1 { - return 0, 0, 0, fail("openssl: thread setup") - } - C.go_openssl_OPENSSL_add_all_algorithms_conf() - C.go_openssl_ERR_load_crypto_strings() + ossl.ThreadSetup() + ossl.OPENSSL_add_all_algorithms_conf() + ossl.ERR_load_crypto_strings() } else { - flags := C.uint64_t(C.GO_OPENSSL_INIT_ADD_ALL_CIPHERS | C.GO_OPENSSL_INIT_ADD_ALL_DIGESTS | C.GO_OPENSSL_INIT_LOAD_CONFIG | C.GO_OPENSSL_INIT_LOAD_CRYPTO_STRINGS) - if C.go_openssl_OPENSSL_init_crypto(flags, nil) != 1 { - return 0, 0, 0, fail("openssl: init crypto") + flags := ossl.OPENSSL_INIT_ADD_ALL_CIPHERS | ossl.OPENSSL_INIT_ADD_ALL_DIGESTS | ossl.OPENSSL_INIT_LOAD_CONFIG | ossl.OPENSSL_INIT_LOAD_CRYPTO_STRINGS + if err := ossl.OPENSSL_init_crypto(uint64(flags), nil); err != nil { + return 0, 0, 0, err } } return major, minor, patch, nil diff --git a/leak_check.h b/leak_check.h new file mode 100644 index 0000000..ba3f8ad --- /dev/null +++ b/leak_check.h @@ -0,0 +1,13 @@ +static inline void +go_openssl_do_leak_check(void) +{ +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#if (defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__) || \ + __has_feature(address_sanitizer) + extern void __lsan_do_leak_check(void); + __lsan_do_leak_check(); +#endif +} diff --git a/openssl.go b/openssl.go index 145b082..feb589d 100644 --- a/openssl.go +++ b/openssl.go @@ -1,9 +1,9 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo // Package openssl provides access to OpenSSL cryptographic functions. package openssl -// #include "goopenssl.h" +// #include "leak_check.h" import "C" import ( "encoding/binary" @@ -14,6 +14,8 @@ import ( "strings" "sync" "unsafe" + + "github.com/golang-fips/openssl/v2/internal/ossl" ) var ( @@ -38,7 +40,7 @@ func CheckVersion(version string) (exists, fips bool) { return false, false } defer dlclose(handle) - enabled := C.go_openssl_fips_enabled(handle) + enabled := ossl.Go_openssl_fips_enabled(handle) fips = enabled == 1 // If go_openssl_fips_enabled returns -1, it means that all or some of the necessary // functions are not available. This can be due to the version of OpenSSL being too old, @@ -96,16 +98,17 @@ func (e fail) Error() string { return "openssl: " + string(e) + " failed" } // VersionText returns the version text of the OpenSSL currently loaded. func VersionText() string { - return C.GoString(C.go_openssl_OpenSSL_version(0)) + v := ossl.OpenSSL_version(0) + return goString(v) } -var ( - providerNameFips = C.CString("fips") - providerNameDefault = C.CString("default") - propFIPS = C.CString("fips=yes") - propNoFIPS = C.CString("-fips") +const ( + providerNameFips = "fips\x00" + providerNameDefault = "default\x00" + propFIPS = "fips=yes\x00" + propNoFIPS = "-fips\x00" - algorithmSHA256 = C.CString("SHA2-256") + algorithmSHA256 = "SHA2-256\x00" ) // FIPS returns true if OpenSSL is running in FIPS mode and there is @@ -113,10 +116,10 @@ var ( func FIPS() bool { switch vMajor { case 1: - return C.go_openssl_FIPS_mode() == 1 + return ossl.FIPS_mode() == 1 case 3: // Check if the default properties contain `fips=1`. - if C.go_openssl_EVP_default_properties_is_fips_enabled(nil) != 1 { + if ossl.EVP_default_properties_is_fips_enabled(nil) != 1 { // Note that it is still possible that the provider used by default is FIPS-compliant, // but that wouldn't be a system or user requirement. return false @@ -140,9 +143,7 @@ func isProviderAvailable(name string) bool { if vMajor == 1 { return false } - providerName := C.CString(name) - defer C.free(unsafe.Pointer(providerName)) - return C.go_openssl_OSSL_PROVIDER_available(nil, providerName) == 1 + return ossl.OSSL_PROVIDER_available(nil, cStringData(name)) == 1 } // SetFIPS enables or disables FIPS mode. @@ -154,20 +155,17 @@ func SetFIPS(enable bool) error { // Already in the desired state. return nil } - var mode C.int + var mode int32 if enable { - mode = C.int(1) + mode = 1 } else { - mode = C.int(0) + mode = 0 } switch vMajor { case 1: - if C.go_openssl_FIPS_mode_set(mode) != 1 { - return newOpenSSLError("FIPS_mode_set") - } - return nil + return ossl.FIPS_mode_set(mode) case 3: - var shaProps, provName *C.char + var shaProps, provName string if enable { shaProps = propFIPS provName = providerNameFips @@ -175,19 +173,16 @@ func SetFIPS(enable bool) error { shaProps = propNoFIPS provName = providerNameDefault } - if !proveSHA256(shaProps) { + if !proveSHA256(cStringData(shaProps)) { // There is no provider available that supports the desired FIPS mode. // Try to load the built-in provider associated with the given mode. - if C.go_openssl_OSSL_PROVIDER_try_load(nil, provName, 1) == nil { + if _, err := ossl.OSSL_PROVIDER_try_load(nil, cStringData(provName), 1); err != nil { // The built-in provider was not loaded successfully, we can't enable FIPS mode. - C.go_openssl_ERR_clear_error() + ossl.ERR_clear_error() return errors.New("openssl: FIPS mode not supported by any provider") } } - if C.go_openssl_EVP_default_properties_enable_fips(nil, mode) != 1 { - return newOpenSSLError("EVP_default_properties_enable_fips") - } - return nil + return ossl.EVP_default_properties_enable_fips(nil, mode) default: panic(errUnsupportedVersion()) } @@ -195,13 +190,13 @@ func SetFIPS(enable bool) error { // proveSHA256 checks if the SHA-256 algorithm is available // using the given properties. -func proveSHA256(props *C.char) bool { - md := C.go_openssl_EVP_MD_fetch(nil, algorithmSHA256, props) - if md == nil { - C.go_openssl_ERR_clear_error() +func proveSHA256(props *byte) bool { + md, err := ossl.EVP_MD_fetch(nil, cStringData(algorithmSHA256), props) + if err != nil { + ossl.ERR_clear_error() return false } - C.go_openssl_EVP_MD_free(md) + ossl.EVP_MD_free(md) return true } @@ -233,18 +228,27 @@ func addr(p []byte) *byte { // base returns the address of the underlying array in b, // being careful not to panic when b has zero length. -func base(b []byte) *C.uchar { - if len(b) == 0 { - return nil - } - return (*C.uchar)(unsafe.Pointer(&b[0])) +func base(b []byte) *byte { + return unsafe.SliceData(b) } -func sbase(b []byte) *C.char { - if len(b) == 0 { +// stringData returns a pointer to the underlying bytes of s. +// If s is not empty it must end in a NUL byte. +// The returned pointer is valid for the lifetime of s. +// If s is empty, stringData returns nil. +func cStringData(s string) *byte { + if len(s) == 0 { return nil } - return (*C.char)(unsafe.Pointer(&b[0])) + if s[len(s)-1] != 0 { + panic("openssl: stringData not NUL-terminated") + } + for i := 0; i < len(s)-1; i++ { + if s[i] == 0 { + panic("openssl: string contains non-trailing NUL byte") + } + } + return unsafe.StringData(s) } func newOpenSSLError(msg string) error { @@ -253,15 +257,15 @@ func newOpenSSLError(msg string) error { b.WriteString("\nopenssl error(s):") for { var ( - e C.ulong - file *C.char - line C.int + e uint64 + file *byte + line int32 ) switch vMajor { case 1: - e = C.go_openssl_ERR_get_error_line(&file, &line) + e = ossl.ERR_get_error_line(&file, &line) case 3: - e = C.go_openssl_ERR_get_error_all(&file, &line, nil, nil, nil) + e = ossl.ERR_get_error_all(&file, &line, nil, nil, nil) default: panic(errUnsupportedVersion()) } @@ -270,12 +274,26 @@ func newOpenSSLError(msg string) error { } b.WriteByte('\n') var buf [256]byte - C.go_openssl_ERR_error_string_n(e, (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))) - b.WriteString(string(buf[:]) + "\n\t" + C.GoString(file) + ":" + strconv.Itoa(int(line))) + ossl.ERR_error_string_n(e, &buf[0], len(buf)) + b.WriteString(string(buf[:]) + "\n\t" + goString(file) + ":" + strconv.Itoa(int(line))) } return errors.New(b.String()) } +// goString converts a C null-terminated string to a Go string. +func goString(p *byte) string { + if p == nil { + return "" + } + end := unsafe.Pointer(p) + n := 0 + for *(*byte)(end) != 0 { + end = unsafe.Pointer(uintptr(end) + unsafe.Sizeof(*p)) + n++ + } + return string(unsafe.Slice(p, n)) +} + var unknownFile = "\000" // caller reports file and line number information about function invocations on @@ -284,7 +302,7 @@ var unknownFile = "\000" // the caller of caller. The return values report the file name and line number // within the file of the corresponding call. The returned file is a C string // with static storage duration. -func caller(skip int) (file *C.char, line C.int) { +func caller(skip int) (file *byte, line int32) { _, f, l, ok := runtime.Caller(skip + 1) if !ok { f = unknownFile @@ -292,9 +310,12 @@ func caller(skip int) (file *C.char, line C.int) { // The underlying bytes of the file string are null-terminated rodata with // static lifetimes, so can be safely passed to C without worrying about // leaking memory or use-after-free. - return (*C.char)(noescape(unsafe.Pointer(unsafe.StringData(f)))), C.int(l) + return (*byte)(noescape(unsafe.Pointer(unsafe.StringData(f)))), int32(l) } +//go:linkname runtime_throw runtime.throw +func runtime_throw(string) + // cryptoMalloc allocates n bytes of memory on the OpenSSL heap, which may be // different from the heap which C.malloc allocates on. The allocated object // must be freed using cryptoFree. cryptoMalloc is equivalent to the @@ -310,9 +331,9 @@ func cryptoMalloc(n int) unsafe.Pointer { file, line := caller(1) var p unsafe.Pointer if vMajor == 1 && vMinor == 0 { - p = C.go_openssl_CRYPTO_malloc_legacy102(C.int(n), file, line) + p = ossl.CRYPTO_malloc_legacy102(int32(n), file, line) } else { - p = C.go_openssl_CRYPTO_malloc(C.size_t(n), file, line) + p = ossl.CRYPTO_malloc(n, file, line) } if p == nil { // Un-recover()-ably crash the program in the same manner as the @@ -327,11 +348,11 @@ func cryptoMalloc(n int) unsafe.Pointer { // to the OPENSSL_free macro. func cryptoFree(p unsafe.Pointer) { if vMajor == 1 && vMinor == 0 { - C.go_openssl_CRYPTO_free_legacy102(p) + ossl.CRYPTO_free_legacy102(p) return } file, line := caller(1) - C.go_openssl_CRYPTO_free(p, file, line) + ossl.CRYPTO_free(p, file, line) } const wordBytes = bits.UintSize / 8 @@ -348,23 +369,23 @@ func (z BigInt) byteSwap() { } } -func wbase(b BigInt) *C.uchar { +func wbase(b BigInt) *byte { if len(b) == 0 { return nil } - return (*C.uchar)(unsafe.Pointer(&b[0])) + return (*byte)(unsafe.Pointer(&b[0])) } // bignum_st_1_0_2 is bignum_st (BIGNUM) memory layout in OpenSSL 1.0.2. type bignum_st_1_0_2 struct { d unsafe.Pointer // Pointer to an array of BN_ULONG bit chunks - top C.int // Index of last used d +1 - dmax C.int - neg C.int - flags C.int + top int32 // Index of last used d +1 + dmax int32 + neg int32 + flags int32 } -func bigToBN(x BigInt) C.GO_BIGNUM_PTR { +func bigToBN(x BigInt) ossl.BIGNUM_PTR { if len(x) == 0 { return nil } @@ -372,19 +393,19 @@ func bigToBN(x BigInt) C.GO_BIGNUM_PTR { if vMajor == 1 && vMinor == 0 { // OpenSSL 1.0.x does not export bn_lebin2bn on all platforms, // so we have to emulate it. - bn := C.go_openssl_BN_new() - if bn == nil { + bn, err := ossl.BN_new() + if err != nil { return nil } - if C.go_openssl_bn_expand2(bn, C.int(len(x))) == nil { - C.go_openssl_BN_free(bn) - panic(newOpenSSLError("BN_expand2")) + if _, err := ossl.BN_expand2(bn, int32(len(x))); err != nil { + ossl.BN_free(bn) + panic(err) } // The bytes of a BigInt are laid out in memory in the same order as a // BIGNUM, regardless of host endianness. bns := (*bignum_st_1_0_2)(unsafe.Pointer(bn)) d := unsafe.Slice((*uint)(bns.d), len(x)) - bns.top = C.int(copy(d, x)) + bns.top = int32(copy(d, x)) return bn } @@ -396,10 +417,11 @@ func bigToBN(x BigInt) C.GO_BIGNUM_PTR { } // Limbs are always ordered in LSB first, so we can safely apply // BN_lebin2bn regardless of host endianness. - return C.go_openssl_BN_lebin2bn(wbase(x), C.int(len(x)*wordBytes), nil) + bn, _ := ossl.BN_lebin2bn(wbase(x), int32(len(x)*wordBytes), nil) + return bn } -func bnToBig(bn C.GO_BIGNUM_PTR) BigInt { +func bnToBig(bn ossl.BIGNUM_PTR) BigInt { if bn == nil { return nil } @@ -416,8 +438,8 @@ func bnToBig(bn C.GO_BIGNUM_PTR) BigInt { // Limbs are always ordered in LSB first, so we can safely apply // BN_bn2lebinpad regardless of host endianness. - x := make(BigInt, C.go_openssl_BN_num_bits(bn)) - if C.go_openssl_BN_bn2lebinpad(bn, wbase(x), C.int(len(x)*wordBytes)) == 0 { + x := make(BigInt, ossl.BN_num_bits(bn)) + if _, err := ossl.BN_bn2lebinpad(bn, wbase(x), int32(len(x)*wordBytes)); err != nil { panic("openssl: bignum conversion failed") } if nativeEndian == binary.BigEndian { @@ -426,33 +448,33 @@ func bnToBig(bn C.GO_BIGNUM_PTR) BigInt { return x } -func bnNumBytes(bn C.GO_BIGNUM_PTR) int { - return (int(C.go_openssl_BN_num_bits(bn)) + 7) / 8 +func bnNumBytes(bn ossl.BIGNUM_PTR) int32 { + return (ossl.BN_num_bits(bn) + 7) / 8 } // bnToBinPad converts the absolute value of bn into big-endian form and stores // it at to, padding with zeroes if necessary. If len(to) is not large enough to // hold the result, an error is returned. -func bnToBinPad(bn C.GO_BIGNUM_PTR, to []byte) error { +func bnToBinPad(bn ossl.BIGNUM_PTR, to []byte) error { if vMajor == 1 && vMinor == 0 { // OpenSSL 1.0.x does not export bn_bn2binpad on all platforms, // so we have to emulate it. n := bnNumBytes(bn) - pad := len(to) - n + pad := int32(len(to)) - n if pad < 0 { return errors.New("openssl: destination buffer too small") } for i := range pad { to[i] = 0 } - if int(C.go_openssl_BN_bn2bin(bn, base(to[pad:]))) != n { + if ossl.BN_bn2bin(bn, base(to[pad:])) != n { return errors.New("openssl: BN_bn2bin short write") } return nil } - if C.go_openssl_BN_bn2binpad(bn, base(to), C.int(len(to))) < 0 { - return newOpenSSLError("BN_bn2binpad") + if _, err := ossl.BN_bn2binpad(bn, base(to), int32(len(to))); err != nil { + return err } return nil } diff --git a/params.go b/params.go index fa24a8c..0c68079 100644 --- a/params.go +++ b/params.go @@ -1,50 +1,17 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( + "errors" "runtime" "unsafe" -) -var ( - // KDF parameters - _OSSL_KDF_PARAM_DIGEST = C.CString("digest") - _OSSL_KDF_PARAM_SECRET = C.CString("secret") - _OSSL_KDF_PARAM_SEED = C.CString("seed") - _OSSL_KDF_PARAM_KEY = C.CString("key") - _OSSL_KDF_PARAM_INFO = C.CString("info") - _OSSL_KDF_PARAM_SALT = C.CString("salt") - _OSSL_KDF_PARAM_MODE = C.CString("mode") - - // PKEY parameters - _OSSL_PKEY_PARAM_PUB_KEY = C.CString("pub") - _OSSL_PKEY_PARAM_PRIV_KEY = C.CString("priv") - _OSSL_PKEY_PARAM_GROUP_NAME = C.CString("group") - _OSSL_PKEY_PARAM_EC_PUB_X = C.CString("qx") - _OSSL_PKEY_PARAM_EC_PUB_Y = C.CString("qy") - _OSSL_PKEY_PARAM_FFC_PBITS = C.CString("pbits") - _OSSL_PKEY_PARAM_FFC_QBITS = C.CString("qbits") - _OSSL_PKEY_PARAM_RSA_N = C.CString("n") - _OSSL_PKEY_PARAM_RSA_E = C.CString("e") - _OSSL_PKEY_PARAM_RSA_D = C.CString("d") - _OSSL_PKEY_PARAM_FFC_P = C.CString("p") - _OSSL_PKEY_PARAM_FFC_Q = C.CString("q") - _OSSL_PKEY_PARAM_FFC_G = C.CString("g") - _OSSL_PKEY_PARAM_RSA_FACTOR1 = C.CString("rsa-factor1") - _OSSL_PKEY_PARAM_RSA_FACTOR2 = C.CString("rsa-factor2") - _OSSL_PKEY_PARAM_RSA_EXPONENT1 = C.CString("rsa-exponent1") - _OSSL_PKEY_PARAM_RSA_EXPONENT2 = C.CString("rsa-exponent2") - _OSSL_PKEY_PARAM_RSA_COEFFICIENT1 = C.CString("rsa-coefficient1") - - // MAC parameters - _OSSL_MAC_PARAM_DIGEST = C.CString("digest") + "github.com/golang-fips/openssl/v2/internal/ossl" ) type bnParam struct { - value C.GO_BIGNUM_PTR + value ossl.BIGNUM_PTR private bool } @@ -53,7 +20,7 @@ type bnParam struct { // subsequent calls to add parameters are ignored // and build() will return the error. type paramBuilder struct { - bld C.GO_OSSL_PARAM_BLD_PTR + bld ossl.OSSL_PARAM_BLD_PTR pinner runtime.Pinner bnToFree []bnParam @@ -62,9 +29,9 @@ type paramBuilder struct { // newParamBuilder creates a new paramBuilder. func newParamBuilder() (*paramBuilder, error) { - bld := C.go_openssl_OSSL_PARAM_BLD_new() - if bld == nil { - return nil, newOpenSSLError("OSSL_PARAM_BLD_new") + bld, err := ossl.OSSL_PARAM_BLD_new() + if err != nil { + return nil, err } pb := ¶mBuilder{ bld: bld, @@ -80,12 +47,12 @@ func (b *paramBuilder) finalize() { b.pinner.Unpin() for _, bn := range b.bnToFree { if bn.private { - C.go_openssl_BN_clear_free(bn.value) + ossl.BN_clear_free(bn.value) } else { - C.go_openssl_BN_free(bn.value) + ossl.BN_free(bn.value) } } - C.go_openssl_OSSL_PARAM_BLD_free(b.bld) + ossl.OSSL_PARAM_BLD_free(b.bld) b.bld = nil } } @@ -109,69 +76,61 @@ func (b *paramBuilder) check() bool { // If an error occurred while adding parameters, the error is returned // and the OSSL_PARAM is nil. Once build() is called, the builder is finalized // and cannot be reused. -func (b *paramBuilder) build() (C.GO_OSSL_PARAM_PTR, error) { +func (b *paramBuilder) build() (ossl.OSSL_PARAM_PTR, error) { defer b.finalize() if !b.check() { return nil, b.err } - param := C.go_openssl_OSSL_PARAM_BLD_to_param(b.bld) - if param == nil { - return nil, newOpenSSLError("OSSL_PARAM_BLD_build") + param, err := ossl.OSSL_PARAM_BLD_to_param(b.bld) + if err != nil { + return nil, err } return param, nil } // addUTF8String adds a NUL-terminated UTF-8 string to the builder. // size should not include the terminating NUL byte. If size is zero, then it will be calculated. -func (b *paramBuilder) addUTF8String(name *C.char, value *C.char, size C.size_t) { +func (b *paramBuilder) addUTF8String(name string, value *byte, size int) { if !b.check() { return } // OSSL_PARAM_BLD_push_utf8_string calculates the size if it is zero. - if C.go_openssl_OSSL_PARAM_BLD_push_utf8_string(b.bld, name, value, size) != 1 { - b.err = newOpenSSLError("OSSL_PARAM_BLD_push_utf8_string(" + C.GoString(name) + ")") - } + b.err = ossl.OSSL_PARAM_BLD_push_utf8_string(b.bld, cStringData(name), value, size) } // addOctetString adds an octet string to the builder. // The value is pinned and will be unpinned when the builder is freed. -func (b *paramBuilder) addOctetString(name *C.char, value []byte) { +func (b *paramBuilder) addOctetString(name string, value []byte) { if !b.check() { return } if len(value) != 0 { b.pinner.Pin(&value[0]) } - if C.go_openssl_OSSL_PARAM_BLD_push_octet_string(b.bld, name, unsafe.Pointer(sbase(value)), C.size_t(len(value))) != 1 { - b.err = newOpenSSLError("OSSL_PARAM_BLD_push_octet_string(" + C.GoString(name) + ")") - } + b.err = ossl.OSSL_PARAM_BLD_push_octet_string(b.bld, cStringData(name), unsafe.Pointer(base(value)), len(value)) } // addInt32 adds an int32 to the builder. -func (b *paramBuilder) addInt32(name *C.char, value int32) { +func (b *paramBuilder) addInt32(name string, value int32) { if !b.check() { return } - if C.go_openssl_OSSL_PARAM_BLD_push_int32(b.bld, name, C.int32_t(value)) != 1 { - b.err = newOpenSSLError("OSSL_PARAM_BLD_push_int32(" + C.GoString(name) + ")") - } + b.err = ossl.OSSL_PARAM_BLD_push_int32(b.bld, cStringData(name), value) } // addBN adds a GO_BIGNUM_PTR to the builder. -func (b *paramBuilder) addBN(name *C.char, value C.GO_BIGNUM_PTR) { +func (b *paramBuilder) addBN(name string, value ossl.BIGNUM_PTR) { if !b.check() { return } - if C.go_openssl_OSSL_PARAM_BLD_push_BN(b.bld, name, value) != 1 { - b.err = newOpenSSLError("OSSL_PARAM_BLD_push_BN(" + C.GoString(name) + ")") - } + b.err = ossl.OSSL_PARAM_BLD_push_BN(b.bld, cStringData(name), value) } // addBin adds a byte slice to the builder. // The slice is converted to a BIGNUM using BN_bin2bn and freed when the builder is finalized. // If private is true, the BIGNUM will be cleared with BN_clear_free, // otherwise it will be freed with BN_free. -func (b *paramBuilder) addBin(name *C.char, value []byte, private bool) { +func (b *paramBuilder) addBin(name string, value []byte, private bool) { if !b.check() { return } @@ -179,9 +138,9 @@ func (b *paramBuilder) addBin(name *C.char, value []byte, private bool) { // Nothing to do. return } - bn := C.go_openssl_BN_bin2bn(base(value), C.int(len(value)), nil) - if bn == nil { - b.err = newOpenSSLError("BN_bin2bn") + bn, err := ossl.BN_bin2bn(base(value), int32(len(value)), nil) + if err != nil { + b.err = err return } b.bnToFree = append(b.bnToFree, bnParam{bn, private}) @@ -192,7 +151,7 @@ func (b *paramBuilder) addBin(name *C.char, value []byte, private bool) { // The BigInt is converted using bigToBN to a BIGNUM that is freed when the builder is finalized. // If private is true, the BIGNUM will be cleared with BN_clear_free, // otherwise it will be freed with BN_free. -func (b *paramBuilder) addBigInt(name *C.char, value BigInt, private bool) { +func (b *paramBuilder) addBigInt(name string, value BigInt, private bool) { if !b.check() { return } @@ -202,9 +161,13 @@ func (b *paramBuilder) addBigInt(name *C.char, value BigInt, private bool) { } bn := bigToBN(value) if bn == nil { - b.err = newOpenSSLError("bigToBN") + b.err = errors.New("bigToBN") return } b.bnToFree = append(b.bnToFree, bnParam{bn, private}) b.addBN(name, bn) } + +func getBnParam(pkey ossl.EVP_PKEY_PTR, name string, bn *ossl.BIGNUM_PTR) error { + return ossl.EVP_PKEY_get_bn_param(pkey, cStringData(name), bn) +} diff --git a/pbkdf2.go b/pbkdf2.go index 92276c6..9599d67 100644 --- a/pbkdf2.go +++ b/pbkdf2.go @@ -1,14 +1,13 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( "errors" "hash" "sync" - "unsafe" + + "github.com/golang-fips/openssl/v2/internal/ossl" ) // SupportsPBKDF2 reports whether the current OpenSSL version supports PBKDF2. @@ -27,14 +26,12 @@ func SupportsPBKDF2() bool { // fetchPBKDF2 fetches the PBKDF2 algorithm. // It is safe to call this function concurrently. // The returned EVP_KDF_PTR shouldn't be freed. -var fetchPBKDF2 = sync.OnceValues(func() (C.GO_EVP_KDF_PTR, error) { +var fetchPBKDF2 = sync.OnceValues(func() (ossl.EVP_KDF_PTR, error) { checkMajorVersion(3) - name := C.CString("PBKDF2") - kdf := C.go_openssl_EVP_KDF_fetch(nil, name, nil) - C.free(unsafe.Pointer(name)) - if kdf == nil { - return nil, newOpenSSLError("EVP_KDF_fetch") + kdf, err := ossl.EVP_KDF_fetch(nil, cStringData(ossl.OSSL_KDF_NAME_PBKDF2), nil) + if err != nil { + return nil, err } return kdf, nil }) @@ -51,12 +48,12 @@ func PBKDF2(password, salt []byte, iter, keyLen int, fh func() hash.Hash) ([]byt if len(password) == 0 && vMajor == 1 && vMinor == 0 { // x/crypto/pbkdf2 supports empty passwords, but OpenSSL 1.0.2 // does not. As a workaround, we pass an "empty" password. - password = make([]byte, C.GO_EVP_MAX_MD_SIZE) + password = make([]byte, ossl.EVP_MAX_MD_SIZE) } out := make([]byte, keyLen) - ok := C.go_openssl_PKCS5_PBKDF2_HMAC(sbase(password), C.int(len(password)), base(salt), C.int(len(salt)), C.int(iter), md, C.int(keyLen), base(out)) - if ok != 1 { - return nil, newOpenSSLError("PKCS5_PBKDF2_HMAC") + err = ossl.PKCS5_PBKDF2_HMAC(base(password), int32(len(password)), base(salt), int32(len(salt)), int32(iter), md, int32(keyLen), base(out)) + if err != nil { + return nil, err } return out, nil } diff --git a/rand.go b/rand.go index 9fd7096..073ed90 100644 --- a/rand.go +++ b/rand.go @@ -1,18 +1,19 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" -import "unsafe" +import "github.com/golang-fips/openssl/v2/internal/ossl" type randReader int func (randReader) Read(b []byte) (int, error) { + if len(b) == 0 { + return 0, nil + } // Note: RAND_bytes should never fail; the return value exists only for historical reasons. // We check it even so. - if len(b) > 0 && C.go_openssl_RAND_bytes((*C.uchar)(unsafe.Pointer(&b[0])), C.int(len(b))) == 0 { - return 0, newOpenSSLError("RAND_bytes") + if err := ossl.RAND_bytes(&b[0], int32(len(b))); err != nil { + return 0, err } return len(b), nil } diff --git a/rc4.go b/rc4.go index f1cd364..e75bc55 100644 --- a/rc4.go +++ b/rc4.go @@ -1,10 +1,13 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" -import "runtime" +import ( + "runtime" + "unsafe" + + "github.com/golang-fips/openssl/v2/internal/ossl" +) // SupportsRC4 returns true if NewRC4Cipher is supported. func SupportsRC4() bool { @@ -15,7 +18,7 @@ func SupportsRC4() bool { // A RC4Cipher is an instance of RC4 using a particular key. type RC4Cipher struct { - ctx C.GO_EVP_CIPHER_CTX_PTR + ctx ossl.EVP_CIPHER_CTX_PTR } // NewRC4Cipher creates and returns a new Cipher. @@ -31,14 +34,14 @@ func NewRC4Cipher(key []byte) (*RC4Cipher, error) { func (c *RC4Cipher) finalize() { if c.ctx != nil { - C.go_openssl_EVP_CIPHER_CTX_free(c.ctx) + ossl.EVP_CIPHER_CTX_free(c.ctx) } } // Reset zeros the key data and makes the Cipher unusable. func (c *RC4Cipher) Reset() { if c.ctx != nil { - C.go_openssl_EVP_CIPHER_CTX_free(c.ctx) + ossl.EVP_CIPHER_CTX_free(c.ctx) c.ctx = nil } } @@ -55,9 +58,9 @@ func (c *RC4Cipher) XORKeyStream(dst, src []byte) { // panic if len(dst) < len(src) with a runtime out of bound error, // which is what crypto/rc4 does. _ = dst[len(src)-1] - var outLen C.int - if C.go_openssl_EVP_EncryptUpdate(c.ctx, base(dst), &outLen, base(src), C.int(len(src))) != 1 { - panic("crypto/cipher: EncryptUpdate failed") + var outLen int32 + if err := ossl.EVP_EncryptUpdate(c.ctx, unsafe.SliceData(dst), &outLen, unsafe.SliceData(src), int32(len(src))); err != nil { + panic(err) } if int(outLen) != len(src) { panic("crypto/rc4: src not fully XORed") diff --git a/rsa.go b/rsa.go index da5c763..ec3b8a4 100644 --- a/rsa.go +++ b/rsa.go @@ -1,9 +1,7 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( "crypto" "crypto/subtle" @@ -11,65 +9,65 @@ import ( "hash" "runtime" "unsafe" + + "github.com/golang-fips/openssl/v2/internal/ossl" ) func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) { bad := func(e error) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) { return nil, nil, nil, nil, nil, nil, nil, nil, e } - pkey, err := generateEVPPKey(C.GO_EVP_PKEY_RSA, bits, "") + pkey, err := generateEVPPKey(ossl.EVP_PKEY_RSA, bits, "") if err != nil { return bad(err) } - defer C.go_openssl_EVP_PKEY_free(pkey) + defer ossl.EVP_PKEY_free(pkey) switch vMajor { case 1: - key := C.go_openssl_EVP_PKEY_get1_RSA(pkey) - if key == nil { + key, err := ossl.EVP_PKEY_get1_RSA(pkey) + if err != nil { return bad(newOpenSSLError("EVP_PKEY_get1_RSA failed")) } - defer C.go_openssl_RSA_free(key) - var n, e, d, p, q, dmp1, dmq1, iqmp C.GO_BIGNUM_PTR + defer ossl.RSA_free(key) + var n, e, d, p, q, dmp1, dmq1, iqmp ossl.BIGNUM_PTR if vMinor == 0 { r := (*rsa_st_1_0_2)(unsafe.Pointer(key)) n, e, d, p, q, dmp1, dmq1, iqmp = r.n, r.e, r.d, r.p, r.q, r.dmp1, r.dmq1, r.iqmp } else { - C.go_openssl_RSA_get0_key(key, &n, &e, &d) - C.go_openssl_RSA_get0_factors(key, &p, &q) - C.go_openssl_RSA_get0_crt_params(key, &dmp1, &dmq1, &iqmp) + ossl.RSA_get0_key(key, &n, &e, &d) + ossl.RSA_get0_factors(key, &p, &q) + ossl.RSA_get0_crt_params(key, &dmp1, &dmq1, &iqmp) } N, E, D = bnToBig(n), bnToBig(e), bnToBig(d) P, Q = bnToBig(p), bnToBig(q) Dp, Dq, Qinv = bnToBig(dmp1), bnToBig(dmq1), bnToBig(iqmp) case 3: - tmp := C.go_openssl_BN_new() - if tmp == nil { - return bad(newOpenSSLError("BN_new failed")) + tmp, err := ossl.BN_new() + if err != nil { + return bad(err) } defer func() { - C.go_openssl_BN_clear_free(tmp) + ossl.BN_clear_free(tmp) }() - var err error - setBigInt := func(bi *BigInt, param *C.char) bool { + setBigInt := func(bi *BigInt, param string) bool { if err != nil { return false } - if C.go_openssl_EVP_PKEY_get_bn_param(pkey, param, &tmp) != 1 { - err = newOpenSSLError("EVP_PKEY_get_bn_param failed") + if err = getBnParam(pkey, param, &tmp); err != nil { return false } *bi = bnToBig(tmp) - C.go_openssl_BN_clear(tmp) + ossl.BN_clear(tmp) return true } - if !(setBigInt(&N, _OSSL_PKEY_PARAM_RSA_N) && - setBigInt(&E, _OSSL_PKEY_PARAM_RSA_E) && - setBigInt(&D, _OSSL_PKEY_PARAM_RSA_D) && - setBigInt(&P, _OSSL_PKEY_PARAM_RSA_FACTOR1) && - setBigInt(&Q, _OSSL_PKEY_PARAM_RSA_FACTOR2) && - setBigInt(&Dp, _OSSL_PKEY_PARAM_RSA_EXPONENT1) && - setBigInt(&Dq, _OSSL_PKEY_PARAM_RSA_EXPONENT2) && - setBigInt(&Qinv, _OSSL_PKEY_PARAM_RSA_COEFFICIENT1)) { + if !(setBigInt(&N, ossl.OSSL_PKEY_PARAM_RSA_N) && + setBigInt(&E, ossl.OSSL_PKEY_PARAM_RSA_E) && + setBigInt(&D, ossl.OSSL_PKEY_PARAM_RSA_D) && + setBigInt(&P, ossl.OSSL_PKEY_PARAM_RSA_FACTOR1) && + setBigInt(&Q, ossl.OSSL_PKEY_PARAM_RSA_FACTOR2) && + setBigInt(&Dp, ossl.OSSL_PKEY_PARAM_RSA_EXPONENT1) && + setBigInt(&Dq, ossl.OSSL_PKEY_PARAM_RSA_EXPONENT2) && + setBigInt(&Qinv, ossl.OSSL_PKEY_PARAM_RSA_COEFFICIENT1)) { return bad(err) } default: @@ -80,29 +78,29 @@ func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) { type PublicKeyRSA struct { // _pkey MUST NOT be accessed directly. Instead, use the withKey method. - _pkey C.GO_EVP_PKEY_PTR + _pkey ossl.EVP_PKEY_PTR } func NewPublicKeyRSA(n, e BigInt) (*PublicKeyRSA, error) { - var pkey C.GO_EVP_PKEY_PTR + var pkey ossl.EVP_PKEY_PTR switch vMajor { case 1: - key := C.go_openssl_RSA_new() - if key == nil { - return nil, newOpenSSLError("RSA_new failed") + key, err := ossl.RSA_new() + if err != nil { + return nil, err } if !rsaSetKey(key, n, e, nil) { return nil, fail("RSA_set0_key") } - pkey = C.go_openssl_EVP_PKEY_new() - if pkey == nil { - C.go_openssl_RSA_free(key) - return nil, newOpenSSLError("EVP_PKEY_new failed") + pkey, err = ossl.EVP_PKEY_new() + if err != nil { + ossl.RSA_free(key) + return nil, err } - if C.go_openssl_EVP_PKEY_assign(pkey, C.GO_EVP_PKEY_RSA, (unsafe.Pointer)(key)) != 1 { - C.go_openssl_RSA_free(key) - C.go_openssl_EVP_PKEY_free(pkey) - return nil, newOpenSSLError("EVP_PKEY_assign failed") + if err := ossl.EVP_PKEY_assign(pkey, ossl.EVP_PKEY_RSA, (unsafe.Pointer)(key)); err != nil { + ossl.RSA_free(key) + ossl.EVP_PKEY_free(pkey) + return nil, err } case 3: var err error @@ -118,10 +116,10 @@ func NewPublicKeyRSA(n, e BigInt) (*PublicKeyRSA, error) { } func (k *PublicKeyRSA) finalize() { - C.go_openssl_EVP_PKEY_free(k._pkey) + ossl.EVP_PKEY_free(k._pkey) } -func (k *PublicKeyRSA) withKey(f func(C.GO_EVP_PKEY_PTR) C.int) C.int { +func (k *PublicKeyRSA) withKey(f func(ossl.EVP_PKEY_PTR) error) error { // Because of the finalizer, any time _pkey is passed to cgo, that call must // be followed by a call to runtime.KeepAlive, to make sure k is not // collected (and finalized) before the cgo call returns. @@ -131,16 +129,16 @@ func (k *PublicKeyRSA) withKey(f func(C.GO_EVP_PKEY_PTR) C.int) C.int { type PrivateKeyRSA struct { // _pkey MUST NOT be accessed directly. Instead, use the withKey method. - _pkey C.GO_EVP_PKEY_PTR + _pkey ossl.EVP_PKEY_PTR } func NewPrivateKeyRSA(n, e, d, p, q, dp, dq, qinv BigInt) (*PrivateKeyRSA, error) { - var pkey C.GO_EVP_PKEY_PTR + var pkey ossl.EVP_PKEY_PTR switch vMajor { case 1: - key := C.go_openssl_RSA_new() - if key == nil { - return nil, newOpenSSLError("RSA_new failed") + key, err := ossl.RSA_new() + if err != nil { + return nil, err } if !rsaSetKey(key, n, e, d) { return nil, fail("RSA_set0_key") @@ -155,15 +153,15 @@ func NewPrivateKeyRSA(n, e, d, p, q, dp, dq, qinv BigInt) (*PrivateKeyRSA, error return nil, fail("RSA_set0_crt_params") } } - pkey = C.go_openssl_EVP_PKEY_new() - if pkey == nil { - C.go_openssl_RSA_free(key) - return nil, newOpenSSLError("EVP_PKEY_new failed") + pkey, err = ossl.EVP_PKEY_new() + if err != nil { + ossl.RSA_free(key) + return nil, err } - if C.go_openssl_EVP_PKEY_assign(pkey, C.GO_EVP_PKEY_RSA, (unsafe.Pointer)(key)) != 1 { - C.go_openssl_RSA_free(key) - C.go_openssl_EVP_PKEY_free(pkey) - return nil, newOpenSSLError("EVP_PKEY_assign failed") + if err := ossl.EVP_PKEY_assign(pkey, ossl.EVP_PKEY_RSA, (unsafe.Pointer)(key)); err != nil { + ossl.RSA_free(key) + ossl.EVP_PKEY_free(pkey) + return nil, err } case 3: var err error @@ -179,10 +177,10 @@ func NewPrivateKeyRSA(n, e, d, p, q, dp, dq, qinv BigInt) (*PrivateKeyRSA, error } func (k *PrivateKeyRSA) finalize() { - C.go_openssl_EVP_PKEY_free(k._pkey) + ossl.EVP_PKEY_free(k._pkey) } -func (k *PrivateKeyRSA) withKey(f func(C.GO_EVP_PKEY_PTR) C.int) C.int { +func (k *PrivateKeyRSA) withKey(f func(ossl.EVP_PKEY_PTR) error) error { // Because of the finalizer, any time _pkey is passed to cgo, that call must // be followed by a call to runtime.KeepAlive, to make sure k is not // collected (and finalized) before the cgo call returns. @@ -191,23 +189,23 @@ func (k *PrivateKeyRSA) withKey(f func(C.GO_EVP_PKEY_PTR) C.int) C.int { } func DecryptRSAOAEP(h, mgfHash hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) { - return evpDecrypt(priv.withKey, C.GO_RSA_PKCS1_OAEP_PADDING, h, mgfHash, label, ciphertext) + return evpDecrypt(priv.withKey, ossl.RSA_PKCS1_OAEP_PADDING, h, mgfHash, label, ciphertext) } func EncryptRSAOAEP(h, mgfHash hash.Hash, pub *PublicKeyRSA, msg, label []byte) ([]byte, error) { - return evpEncrypt(pub.withKey, C.GO_RSA_PKCS1_OAEP_PADDING, h, mgfHash, label, msg) + return evpEncrypt(pub.withKey, ossl.RSA_PKCS1_OAEP_PADDING, h, mgfHash, label, msg) } func DecryptRSAPKCS1(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) { - return evpDecrypt(priv.withKey, C.GO_RSA_PKCS1_PADDING, nil, nil, nil, ciphertext) + return evpDecrypt(priv.withKey, ossl.RSA_PKCS1_PADDING, nil, nil, nil, ciphertext) } func EncryptRSAPKCS1(pub *PublicKeyRSA, msg []byte) ([]byte, error) { - return evpEncrypt(pub.withKey, C.GO_RSA_PKCS1_PADDING, nil, nil, nil, msg) + return evpEncrypt(pub.withKey, ossl.RSA_PKCS1_PADDING, nil, nil, nil, msg) } func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) { - ret, err := evpDecrypt(priv.withKey, C.GO_RSA_NO_PADDING, nil, nil, nil, ciphertext) + ret, err := evpDecrypt(priv.withKey, ossl.RSA_NO_PADDING, nil, nil, nil, ciphertext) if err != nil { return nil, err } @@ -231,10 +229,10 @@ func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) } func EncryptRSANoPadding(pub *PublicKeyRSA, msg []byte) ([]byte, error) { - return evpEncrypt(pub.withKey, C.GO_RSA_NO_PADDING, nil, nil, nil, msg) + return evpEncrypt(pub.withKey, ossl.RSA_NO_PADDING, nil, nil, nil, msg) } -func saltLength(saltLen int, sign bool) (C.int, error) { +func saltLength(saltLen int, sign bool) (int, error) { // A salt length of -2 is valid in OpenSSL, but not in crypto/rsa, so reject // it, and lengths < -2, before we convert to the OpenSSL sentinel values. if saltLen <= -2 { @@ -246,16 +244,16 @@ func saltLength(saltLen int, sign bool) (C.int, error) { if sign { if vMajor == 1 { // OpenSSL 1.x uses -2 to mean maximal size when signing where Go crypto uses 0. - return C.GO_RSA_PSS_SALTLEN_MAX_SIGN, nil + return ossl.RSA_PSS_SALTLEN_MAX_SIGN, nil } // OpenSSL 3.x deprecated RSA_PSS_SALTLEN_MAX_SIGN // and uses -3 to mean maximal size when signing where Go crypto uses 0. - return C.GO_RSA_PSS_SALTLEN_MAX, nil + return ossl.RSA_PSS_SALTLEN_MAX, nil } // OpenSSL uses -2 to mean auto-detect size when verifying where Go crypto uses 0. - return C.GO_RSA_PSS_SALTLEN_AUTO, nil + return ossl.RSA_PSS_SALTLEN_AUTO, nil } - return C.int(saltLen), nil + return saltLen, nil } func SignRSAPSS(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) { @@ -263,7 +261,7 @@ func SignRSAPSS(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) if err != nil { return nil, err } - return evpSign(priv.withKey, C.GO_RSA_PKCS1_PSS_PADDING, cSaltLen, h, hashed) + return evpSign(priv.withKey, ossl.RSA_PKCS1_PSS_PADDING, cSaltLen, h, hashed) } func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error { @@ -271,11 +269,11 @@ func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen if err != nil { return err } - return evpVerify(pub.withKey, C.GO_RSA_PKCS1_PSS_PADDING, cSaltLen, h, sig, hashed) + return evpVerify(pub.withKey, ossl.RSA_PKCS1_PSS_PADDING, cSaltLen, h, sig, hashed) } func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) { - return evpSign(priv.withKey, C.GO_RSA_PKCS1_PADDING, 0, h, hashed) + return evpSign(priv.withKey, ossl.RSA_PKCS1_PADDING, 0, h, hashed) } func HashSignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, msg []byte) ([]byte, error) { @@ -283,16 +281,16 @@ func HashSignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, msg []byte) ([]byte } func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error { - if pub.withKey(func(pkey C.GO_EVP_PKEY_PTR) C.int { - size := C.go_openssl_EVP_PKEY_get_size(pkey) + if err := pub.withKey(func(pkey ossl.EVP_PKEY_PTR) error { + size := ossl.EVP_PKEY_get_size(pkey) if len(sig) < int(size) { - return 0 + return errors.New("crypto/rsa: verification error") } - return 1 - }) == 0 { - return errors.New("crypto/rsa: verification error") + return nil + }); err != nil { + return err } - return evpVerify(pub.withKey, C.GO_RSA_PKCS1_PADDING, 0, h, sig, hashed) + return evpVerify(pub.withKey, ossl.RSA_PKCS1_PADDING, 0, h, sig, hashed) } func HashVerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, msg, sig []byte) error { @@ -301,26 +299,26 @@ func HashVerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, msg, sig []byte) er // rsa_st_1_0_2 is rsa_st memory layout in OpenSSL 1.0.2. type rsa_st_1_0_2 struct { - _ C.int - _ C.long + _ int32 + _ int64 _ [2]unsafe.Pointer - n, e, d C.GO_BIGNUM_PTR - p, q C.GO_BIGNUM_PTR - dmp1, dmq1, iqmp C.GO_BIGNUM_PTR + n, e, d ossl.BIGNUM_PTR + p, q ossl.BIGNUM_PTR + dmp1, dmq1, iqmp ossl.BIGNUM_PTR // It contains more fields, but we are not interesed on them. } -func bnSet(b1 *C.GO_BIGNUM_PTR, b2 BigInt) { +func bnSet(b1 *ossl.BIGNUM_PTR, b2 BigInt) { if b2 == nil { return } if *b1 != nil { - C.go_openssl_BN_clear_free(*b1) + ossl.BN_clear_free(*b1) } *b1 = bigToBN(b2) } -func rsaSetKey(key C.GO_RSA_PTR, n, e, d BigInt) bool { +func rsaSetKey(key ossl.RSA_PTR, n, e, d BigInt) bool { if vMajor == 1 && vMinor == 0 { r := (*rsa_st_1_0_2)(unsafe.Pointer(key)) // r.d and d will be nil for public keys. @@ -333,10 +331,10 @@ func rsaSetKey(key C.GO_RSA_PTR, n, e, d BigInt) bool { bnSet(&r.d, d) return true } - return C.go_openssl_RSA_set0_key(key, bigToBN(n), bigToBN(e), bigToBN(d)) == 1 + return ossl.RSA_set0_key(key, bigToBN(n), bigToBN(e), bigToBN(d)) == nil } -func rsaSetFactors(key C.GO_RSA_PTR, p, q BigInt) bool { +func rsaSetFactors(key ossl.RSA_PTR, p, q BigInt) bool { if vMajor == 1 && vMinor == 0 { r := (*rsa_st_1_0_2)(unsafe.Pointer(key)) if (r.p == nil && p == nil) || @@ -347,10 +345,10 @@ func rsaSetFactors(key C.GO_RSA_PTR, p, q BigInt) bool { bnSet(&r.q, q) return true } - return C.go_openssl_RSA_set0_factors(key, bigToBN(p), bigToBN(q)) == 1 + return ossl.RSA_set0_factors(key, bigToBN(p), bigToBN(q)) == nil } -func rsaSetCRTParams(key C.GO_RSA_PTR, dmp1, dmq1, iqmp BigInt) bool { +func rsaSetCRTParams(key ossl.RSA_PTR, dmp1, dmq1, iqmp BigInt) bool { if vMajor == 1 && vMinor == 0 { r := (*rsa_st_1_0_2)(unsafe.Pointer(key)) if (r.dmp1 == nil && dmp1 == nil) || @@ -363,18 +361,18 @@ func rsaSetCRTParams(key C.GO_RSA_PTR, dmp1, dmq1, iqmp BigInt) bool { bnSet(&r.iqmp, iqmp) return true } - return C.go_openssl_RSA_set0_crt_params(key, bigToBN(dmp1), bigToBN(dmq1), bigToBN(iqmp)) == 1 + return ossl.RSA_set0_crt_params(key, bigToBN(dmp1), bigToBN(dmq1), bigToBN(iqmp)) == nil } -func newRSAKey3(isPriv bool, n, e, d, p, q, dp, dq, qinv BigInt) (C.GO_EVP_PKEY_PTR, error) { +func newRSAKey3(isPriv bool, n, e, d, p, q, dp, dq, qinv BigInt) (ossl.EVP_PKEY_PTR, error) { bld, err := newParamBuilder() if err != nil { return nil, err } defer bld.finalize() - bld.addBigInt(_OSSL_PKEY_PARAM_RSA_N, n, false) - bld.addBigInt(_OSSL_PKEY_PARAM_RSA_E, e, false) - bld.addBigInt(_OSSL_PKEY_PARAM_RSA_D, d, false) + bld.addBigInt(ossl.OSSL_PKEY_PARAM_RSA_N, n, false) + bld.addBigInt(ossl.OSSL_PKEY_PARAM_RSA_E, e, false) + bld.addBigInt(ossl.OSSL_PKEY_PARAM_RSA_D, d, false) if p != nil && q != nil { allPrecomputedExists := dp != nil && dq != nil && qinv != nil @@ -385,13 +383,13 @@ func newRSAKey3(isPriv bool, n, e, d, p, q, dp, dq, qinv BigInt) (C.GO_EVP_PKEY_ // In OpenSSL 3.0 and 3.1, we must also omit P and Q if any precomputed // value is missing. See https://github.com/openssl/openssl/pull/22334 if vMinor >= 2 || allPrecomputedExists { - bld.addBigInt(_OSSL_PKEY_PARAM_RSA_FACTOR1, p, true) - bld.addBigInt(_OSSL_PKEY_PARAM_RSA_FACTOR2, q, true) + bld.addBigInt(ossl.OSSL_PKEY_PARAM_RSA_FACTOR1, p, true) + bld.addBigInt(ossl.OSSL_PKEY_PARAM_RSA_FACTOR2, q, true) } if allPrecomputedExists { - bld.addBigInt(_OSSL_PKEY_PARAM_RSA_EXPONENT1, dp, true) - bld.addBigInt(_OSSL_PKEY_PARAM_RSA_EXPONENT2, dq, true) - bld.addBigInt(_OSSL_PKEY_PARAM_RSA_COEFFICIENT1, qinv, true) + bld.addBigInt(ossl.OSSL_PKEY_PARAM_RSA_EXPONENT1, dp, true) + bld.addBigInt(ossl.OSSL_PKEY_PARAM_RSA_EXPONENT2, dq, true) + bld.addBigInt(ossl.OSSL_PKEY_PARAM_RSA_COEFFICIENT1, qinv, true) } } @@ -399,10 +397,10 @@ func newRSAKey3(isPriv bool, n, e, d, p, q, dp, dq, qinv BigInt) (C.GO_EVP_PKEY_ if err != nil { return nil, err } - defer C.go_openssl_OSSL_PARAM_free(params) - selection := C.GO_EVP_PKEY_PUBLIC_KEY + defer ossl.OSSL_PARAM_free(params) + selection := ossl.EVP_PKEY_PUBLIC_KEY if isPriv { - selection = C.GO_EVP_PKEY_KEYPAIR + selection = ossl.EVP_PKEY_KEYPAIR } - return newEvpFromParams(C.GO_EVP_PKEY_RSA, C.int(selection), params) + return newEvpFromParams(ossl.EVP_PKEY_RSA, selection, params) } diff --git a/shims.h b/shims.h deleted file mode 100644 index 7d2e0a4..0000000 --- a/shims.h +++ /dev/null @@ -1,410 +0,0 @@ -#include // size_t -#include // uint64_t - -// #include -enum { - GO_OPENSSL_INIT_LOAD_CRYPTO_STRINGS = 0x00000002L, - GO_OPENSSL_INIT_ADD_ALL_CIPHERS = 0x00000004L, - GO_OPENSSL_INIT_ADD_ALL_DIGESTS = 0x00000008L, - GO_OPENSSL_INIT_LOAD_CONFIG = 0x00000040L -}; - -// #include -enum { - GO_EVP_CTRL_GCM_GET_TAG = 0x10, - GO_EVP_CTRL_GCM_SET_TAG = 0x11, - GO_EVP_PKEY_CTRL_MD = 1, - GO_EVP_PKEY_RSA = 6, - GO_EVP_PKEY_EC = 408, - GO_EVP_PKEY_TLS1_PRF = 1021, - GO_EVP_PKEY_HKDF = 1036, - GO_EVP_PKEY_ED25519 = 1087, - GO_EVP_PKEY_DSA = 116, - /* This is defined differently in OpenSSL 3 (1 << 11), but in our - * code it is only used in OpenSSL 1. - */ - GO1_EVP_PKEY_OP_DERIVE = (1 << 10), - GO_EVP_MAX_MD_SIZE = 64, - - GO_EVP_PKEY_PUBLIC_KEY = 0x86, - GO_EVP_PKEY_KEYPAIR = 0x87 -}; - -// #include -enum { - GO_EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID = 0x1001 -}; - -// #include -enum { - GO_EVP_KDF_HKDF_MODE_EXTRACT_ONLY = 1, - GO_EVP_KDF_HKDF_MODE_EXPAND_ONLY = 2, - - GO_EVP_PKEY_CTRL_TLS_MD = 0x1000, - GO_EVP_PKEY_CTRL_TLS_SECRET = 0x1001, - GO_EVP_PKEY_CTRL_TLS_SEED = 0x1002, - GO_EVP_PKEY_CTRL_HKDF_MD = 0x1003, - GO_EVP_PKEY_CTRL_HKDF_SALT = 0x1004, - GO_EVP_PKEY_CTRL_HKDF_KEY = 0x1005, - GO_EVP_PKEY_CTRL_HKDF_INFO = 0x1006, - GO_EVP_PKEY_CTRL_HKDF_MODE = 0x1007 -}; - -typedef enum { - GO_POINT_CONVERSION_UNCOMPRESSED = 4, -} point_conversion_form_t; - -// #include -enum { - GO_NID_X9_62_prime256v1 = 415, - GO_NID_secp224r1 = 713, - GO_NID_secp384r1 = 715, - GO_NID_secp521r1 = 716 -}; - -// #include -enum { - GO_RSA_PKCS1_PADDING = 1, - GO_RSA_NO_PADDING = 3, - GO_RSA_PKCS1_OAEP_PADDING = 4, - GO_RSA_PKCS1_PSS_PADDING = 6, - GO_RSA_PSS_SALTLEN_DIGEST = -1, - GO_RSA_PSS_SALTLEN_AUTO = -2, - GO_RSA_PSS_SALTLEN_MAX_SIGN = -2, - GO_RSA_PSS_SALTLEN_MAX = -3, - GO_EVP_PKEY_CTRL_RSA_PADDING = 0x1001, - GO_EVP_PKEY_CTRL_RSA_PSS_SALTLEN = 0x1002, - GO_EVP_PKEY_CTRL_RSA_KEYGEN_BITS = 0x1003, - GO_EVP_PKEY_CTRL_RSA_MGF1_MD = 0x1005, - GO_EVP_PKEY_CTRL_RSA_OAEP_MD = 0x1009, - GO_EVP_PKEY_CTRL_RSA_OAEP_LABEL = 0x100A, - GO_EVP_PKEY_CTRL_DSA_PARAMGEN_BITS = 0x1001, - GO_EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS = 0x1002 -}; - -typedef void* GO_OPENSSL_INIT_SETTINGS_PTR; -typedef void* GO_OSSL_LIB_CTX_PTR; -typedef void* GO_OSSL_PROVIDER_PTR; -typedef void* GO_ENGINE_PTR; -typedef void* GO_EVP_PKEY_PTR; -typedef void* GO_EVP_PKEY_CTX_PTR; -typedef void* GO_EVP_MD_PTR; -typedef void* GO_EVP_MD_CTX_PTR; -typedef void* GO_HMAC_CTX_PTR; -typedef void* GO_EVP_CIPHER_PTR; -typedef void* GO_EVP_CIPHER_CTX_PTR; -typedef void* GO_EC_KEY_PTR; -typedef void* GO_EC_POINT_PTR; -typedef void* GO_EC_GROUP_PTR; -typedef void* GO_RSA_PTR; -typedef void* GO_BIGNUM_PTR; -typedef void* GO_BN_CTX_PTR; -typedef void* GO_EVP_MAC_PTR; -typedef void* GO_EVP_MAC_CTX_PTR; -typedef void* GO_OSSL_PARAM_BLD_PTR; -typedef void* GO_OSSL_PARAM_PTR; -typedef void* GO_CRYPTO_THREADID_PTR; -typedef void* GO_EVP_SIGNATURE_PTR; -typedef void* GO_DSA_PTR; -typedef void* GO_EVP_KDF_PTR; -typedef void* GO_EVP_KDF_CTX_PTR; - -// #include -typedef void* GO_MD5_CTX_PTR; - -// #include -typedef void* GO_SHA_CTX_PTR; - -// FOR_ALL_OPENSSL_FUNCTIONS is the list of all functions from libcrypto that are used in this package. -// Forgetting to add a function here results in build failure with message reporting the function -// that needs to be added. -// -// The purpose of FOR_ALL_OPENSSL_FUNCTIONS is to define all libcrypto functions -// without depending on the openssl headers so it is easier to use this package -// with an openssl version different that the one used at build time. -// -// The following macros may not be defined at this point, -// they are not resolved here but just accumulated in FOR_ALL_OPENSSL_FUNCTIONS. -// -// DEFINEFUNC defines and loads openssl functions that can be directly called from Go as their signatures match -// the OpenSSL API and do not require special logic. -// The process will be aborted if the function can't be loaded. -// -// DEFINEFUNC_LEGACY_1_1 acts like DEFINEFUNC but only aborts the process if the function can't be loaded -// when using 1.1.x. This indicates the function is required when using 1.1.x, but is unused when using later versions. -// It also might not exist in later versions. -// -// DEFINEFUNC_LEGACY_1_0 acts like DEFINEFUNC but only aborts the process if the function can't be loaded -// when using 1.0.x. This indicates the function is required when using 1.0.x, but is unused when using later versions. -// It also might not exist in later versions. -// -// DEFINEFUNC_LEGACY_1 acts like DEFINEFUNC but only aborts the process if the function can't be loaded -// when using 1.x. This indicates the function is required when using 1.x, but is unused when using later versions. -// It also might not exist in later versions. -// -// DEFINEFUNC_1_1 acts like DEFINEFUNC but only aborts the process if function can't be loaded -// when using 1.1.0 or higher. -// -// DEFINEFUNC_1_1_1 acts like DEFINEFUNC but only aborts the process if function can't be loaded -// when using 1.1.1 or higher. -// -// DEFINEFUNC_3_0 acts like DEFINEFUNC but only aborts the process if function can't be loaded -// when using 3.0.0 or higher. -// -// DEFINEFUNC_RENAMED_1_1 acts like DEFINEFUNC but tries to load the function using the new name when using >= 1.1.x -// and the old name when using 1.0.2. In both cases the function will have the new name. -// -// DEFINEFUNC_RENAMED_3_0 acts like DEFINEFUNC but tries to load the function using the new name when using >= 3.x -// and the old name when using 1.x. In both cases the function will have the new name. -// -// DEFINEFUNC_VARIADIC_3_0 defines a function that wraps an OpenSSL function with a different name and signature. -// It should only be used for functions that can't be directly called from Go because their signature is not -// compatible with cgo. The only known case are functions that take a variable number of arguments. See -// https://github.com/golang/go/issues/975. -// The process is aborted if the function can't be loaded when using 3.0.0 or higher. -// -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #if OPENSSL_VERSION_NUMBER >= 0x30000000L -// #include -// #include -// #endif -// #if OPENSSL_VERSION_NUMBER < 0x10100000L -// #include -// #endif -#define FOR_ALL_OPENSSL_FUNCTIONS \ -DEFINEFUNC(void, ERR_error_string_n, (unsigned long e, char *buf, size_t len), (e, buf, len)) \ -DEFINEFUNC(void, ERR_clear_error, (void), ()) \ -DEFINEFUNC_LEGACY_1(unsigned long, ERR_get_error_line, (const char **file, int *line), (file, line)) \ -DEFINEFUNC_3_0(unsigned long, ERR_get_error_all, (const char **file, int *line, const char **func, const char **data, int *flags), (file, line, func, data, flags)) \ -DEFINEFUNC_RENAMED_1_1(const char *, OpenSSL_version, SSLeay_version, (int type), (type)) \ -DEFINEFUNC(void, OPENSSL_init, (void), ()) \ -DEFINEFUNC_LEGACY_1_0(void, ERR_load_crypto_strings, (void), ()) \ -DEFINEFUNC_LEGACY_1_0(void, ERR_remove_thread_state, (const GO_CRYPTO_THREADID_PTR tid), (tid)) \ -DEFINEFUNC_LEGACY_1_0(int, CRYPTO_num_locks, (void), ()) \ -DEFINEFUNC_LEGACY_1_0(int, CRYPTO_THREADID_set_callback, (void (*threadid_func) (GO_CRYPTO_THREADID_PTR)), (threadid_func)) \ -DEFINEFUNC_LEGACY_1_0(void, CRYPTO_THREADID_set_numeric, (GO_CRYPTO_THREADID_PTR id, unsigned long val), (id, val)) \ -DEFINEFUNC_LEGACY_1_0(void, CRYPTO_set_locking_callback, (void (*locking_function)(int mode, int n, const char *file, int line)), (locking_function)) \ -/* CRYPTO_malloc argument num changes from int to size_t in OpenSSL 1.1.0, */ \ -/* and CRYPTO_free has file and line arguments added. */ \ -/* Exclude them from headercheck tool when using previous OpenSSL versions. */ \ -/*check:from=1.1.0*/ DEFINEFUNC(void *, CRYPTO_malloc, (size_t num, const char *file, int line), (num, file, line)) \ -/*check:from=1.1.0*/ DEFINEFUNC(void, CRYPTO_free, (void *str, const char *file, int line), (str, file, line)) \ -DEFINEFUNC_LEGACY_1_0(void, OPENSSL_add_all_algorithms_conf, (void), ()) \ -DEFINEFUNC_1_1(int, OPENSSL_init_crypto, (uint64_t ops, const GO_OPENSSL_INIT_SETTINGS_PTR settings), (ops, settings)) \ -DEFINEFUNC_LEGACY_1(int, FIPS_mode, (void), ()) \ -DEFINEFUNC_LEGACY_1(int, FIPS_mode_set, (int r), (r)) \ -DEFINEFUNC_3_0(int, EVP_default_properties_is_fips_enabled, (GO_OSSL_LIB_CTX_PTR libctx), (libctx)) \ -DEFINEFUNC_3_0(int, EVP_default_properties_enable_fips, (GO_OSSL_LIB_CTX_PTR libctx, int enable), (libctx, enable)) \ -DEFINEFUNC_3_0(int, OSSL_PROVIDER_available, (GO_OSSL_LIB_CTX_PTR libctx, const char *name), (libctx, name)) \ -DEFINEFUNC_3_0(GO_OSSL_PROVIDER_PTR, OSSL_PROVIDER_try_load, (GO_OSSL_LIB_CTX_PTR libctx, const char *name, int retain_fallbacks), (libctx, name, retain_fallbacks)) \ -DEFINEFUNC_3_0(const char *, OSSL_PROVIDER_get0_name, (const GO_OSSL_PROVIDER_PTR prov), (prov)) \ -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)) \ -DEFINEFUNC_3_0(void, EVP_MD_free, (GO_EVP_MD_PTR md), (md)) \ -DEFINEFUNC_3_0(const char *, EVP_MD_get0_name, (const GO_EVP_MD_PTR md), (md)) \ -DEFINEFUNC_3_0(const GO_OSSL_PROVIDER_PTR, EVP_MD_get0_provider, (const GO_EVP_MD_PTR md), (md)) \ -DEFINEFUNC_RENAMED_3_0(int, EVP_MD_get_size, EVP_MD_size, (const GO_EVP_MD_PTR md), (md)) \ -DEFINEFUNC_RENAMED_3_0(int, EVP_MD_get_block_size, EVP_MD_block_size, (const GO_EVP_MD_PTR md), (md)) \ -DEFINEFUNC(int, RAND_bytes, (unsigned char *arg0, int arg1), (arg0, arg1)) \ -DEFINEFUNC_RENAMED_1_1(GO_EVP_MD_CTX_PTR, EVP_MD_CTX_new, EVP_MD_CTX_create, (void), ()) \ -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(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)) \ -DEFINEFUNC(int, EVP_DigestUpdate, (GO_EVP_MD_CTX_PTR ctx, const void *d, size_t cnt), (ctx, d, cnt)) \ -DEFINEFUNC(int, EVP_DigestFinal, (GO_EVP_MD_CTX_PTR ctx, unsigned char *md, unsigned int *s), (ctx, md, s)) \ -DEFINEFUNC_1_1_1(int, EVP_DigestSign, (GO_EVP_MD_CTX_PTR ctx, unsigned char *sigret, size_t *siglen, const unsigned char *tbs, size_t tbslen), (ctx, sigret, siglen, tbs, tbslen)) \ -DEFINEFUNC(int, EVP_DigestSignInit, (GO_EVP_MD_CTX_PTR ctx, GO_EVP_PKEY_CTX_PTR *pctx, const GO_EVP_MD_PTR type, GO_ENGINE_PTR e, GO_EVP_PKEY_PTR pkey), (ctx, pctx, type, e, pkey)) \ -DEFINEFUNC(int, EVP_DigestSignFinal, (GO_EVP_MD_CTX_PTR ctx, unsigned char *sig, size_t *siglen), (ctx, sig, siglen)) \ -DEFINEFUNC(int, EVP_DigestVerifyInit, (GO_EVP_MD_CTX_PTR ctx, GO_EVP_PKEY_CTX_PTR *pctx, const GO_EVP_MD_PTR type, GO_ENGINE_PTR e, GO_EVP_PKEY_PTR pkey), (ctx, pctx, type, e, pkey)) \ -DEFINEFUNC(int, EVP_DigestVerifyFinal, (GO_EVP_MD_CTX_PTR ctx, const unsigned char *sig, size_t siglen), (ctx, sig, siglen)) \ -DEFINEFUNC_1_1_1(int, EVP_DigestVerify, (GO_EVP_MD_CTX_PTR ctx, const unsigned char *sigret, size_t siglen, const unsigned char *tbs, size_t tbslen), (ctx, sigret, siglen, tbs, tbslen)) \ -DEFINEFUNC_LEGACY_1_0(int, MD5_Init, (GO_MD5_CTX_PTR c), (c)) \ -DEFINEFUNC_LEGACY_1_0(int, MD5_Update, (GO_MD5_CTX_PTR c, const void *data, size_t len), (c, data, len)) \ -DEFINEFUNC_LEGACY_1_0(int, MD5_Final, (unsigned char *md, GO_MD5_CTX_PTR c), (md, c)) \ -DEFINEFUNC_LEGACY_1_0(int, SHA1_Init, (GO_SHA_CTX_PTR c), (c)) \ -DEFINEFUNC_LEGACY_1_0(int, SHA1_Update, (GO_SHA_CTX_PTR c, const void *data, size_t len), (c, data, len)) \ -DEFINEFUNC_LEGACY_1_0(int, SHA1_Final, (unsigned char *md, GO_SHA_CTX_PTR c), (md, c)) \ -DEFINEFUNC_1_1(const GO_EVP_MD_PTR, EVP_md5_sha1, (void), ()) \ -DEFINEFUNC(const GO_EVP_MD_PTR, EVP_md4, (void), ()) \ -DEFINEFUNC(const GO_EVP_MD_PTR, EVP_md5, (void), ()) \ -DEFINEFUNC(const GO_EVP_MD_PTR, EVP_sha1, (void), ()) \ -DEFINEFUNC(const GO_EVP_MD_PTR, EVP_sha224, (void), ()) \ -DEFINEFUNC(const GO_EVP_MD_PTR, EVP_sha256, (void), ()) \ -DEFINEFUNC(const GO_EVP_MD_PTR, EVP_sha384, (void), ()) \ -DEFINEFUNC(const GO_EVP_MD_PTR, EVP_sha512, (void), ()) \ -DEFINEFUNC_1_1_1(const GO_EVP_MD_PTR, EVP_sha3_224, (void), ()) \ -DEFINEFUNC_1_1_1(const GO_EVP_MD_PTR, EVP_sha3_256, (void), ()) \ -DEFINEFUNC_1_1_1(const GO_EVP_MD_PTR, EVP_sha3_384, (void), ()) \ -DEFINEFUNC_1_1_1(const GO_EVP_MD_PTR, EVP_sha3_512, (void), ()) \ -DEFINEFUNC_LEGACY_1_0(void, HMAC_CTX_init, (GO_HMAC_CTX_PTR arg0), (arg0)) \ -DEFINEFUNC_LEGACY_1_0(void, HMAC_CTX_cleanup, (GO_HMAC_CTX_PTR arg0), (arg0)) \ -DEFINEFUNC_LEGACY_1(int, HMAC_Init_ex, (GO_HMAC_CTX_PTR arg0, const void *arg1, int arg2, const GO_EVP_MD_PTR arg3, GO_ENGINE_PTR arg4), (arg0, arg1, arg2, arg3, arg4)) \ -DEFINEFUNC_LEGACY_1(int, HMAC_Update, (GO_HMAC_CTX_PTR arg0, const unsigned char *arg1, size_t arg2), (arg0, arg1, arg2)) \ -DEFINEFUNC_LEGACY_1(int, HMAC_Final, (GO_HMAC_CTX_PTR arg0, unsigned char *arg1, unsigned int *arg2), (arg0, arg1, arg2)) \ -DEFINEFUNC_LEGACY_1(int, HMAC_CTX_copy, (GO_HMAC_CTX_PTR dest, GO_HMAC_CTX_PTR src), (dest, src)) \ -DEFINEFUNC_LEGACY_1_1(void, HMAC_CTX_free, (GO_HMAC_CTX_PTR arg0), (arg0)) \ -DEFINEFUNC_LEGACY_1_1(GO_HMAC_CTX_PTR, HMAC_CTX_new, (void), ()) \ -DEFINEFUNC(GO_EVP_CIPHER_CTX_PTR, EVP_CIPHER_CTX_new, (void), ()) \ -DEFINEFUNC(int, EVP_CIPHER_CTX_set_padding, (GO_EVP_CIPHER_CTX_PTR x, int padding), (x, padding)) \ -DEFINEFUNC(int, EVP_CipherInit_ex, (GO_EVP_CIPHER_CTX_PTR ctx, const GO_EVP_CIPHER_PTR type, GO_ENGINE_PTR impl, const unsigned char *key, const unsigned char *iv, int enc), (ctx, type, impl, key, iv, enc)) \ -DEFINEFUNC(int, EVP_CipherUpdate, (GO_EVP_CIPHER_CTX_PTR ctx, unsigned char *out, int *outl, const unsigned char *in, int inl), (ctx, out, outl, in, inl)) \ -DEFINEFUNC(int, EVP_EncryptInit_ex, (GO_EVP_CIPHER_CTX_PTR ctx, const GO_EVP_CIPHER_PTR type, GO_ENGINE_PTR impl, const unsigned char *key, const unsigned char *iv), (ctx, type, impl, key, iv)) \ -DEFINEFUNC(int, EVP_EncryptUpdate, (GO_EVP_CIPHER_CTX_PTR ctx, unsigned char *out, int *outl, const unsigned char *in, int inl), (ctx, out, outl, in, inl)) \ -DEFINEFUNC(int, EVP_EncryptFinal_ex, (GO_EVP_CIPHER_CTX_PTR ctx, unsigned char *out, int *outl), (ctx, out, outl)) \ -DEFINEFUNC(int, EVP_DecryptInit_ex, (GO_EVP_CIPHER_CTX_PTR ctx, const GO_EVP_CIPHER_PTR type, GO_ENGINE_PTR impl, const unsigned char *key, const unsigned char *iv), (ctx, type, impl, key, iv)) \ -DEFINEFUNC(int, EVP_DecryptUpdate, (GO_EVP_CIPHER_CTX_PTR ctx, unsigned char *out, int *outl, const unsigned char *in, int inl), (ctx, out, outl, in, inl)) \ -DEFINEFUNC(int, EVP_DecryptFinal_ex, (GO_EVP_CIPHER_CTX_PTR ctx, unsigned char *outm, int *outl), (ctx, outm, outl)) \ -DEFINEFUNC_3_0(GO_EVP_CIPHER_PTR, EVP_CIPHER_fetch, (GO_OSSL_LIB_CTX_PTR ctx, const char *algorithm, const char *properties), (ctx, algorithm, properties)) \ -DEFINEFUNC_3_0(const char *, EVP_CIPHER_get0_name, (const GO_EVP_CIPHER_PTR cipher), (cipher)) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_aes_128_gcm, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_aes_128_cbc, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_aes_128_ctr, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_aes_128_ecb, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_aes_192_gcm, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_aes_192_cbc, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_aes_192_ctr, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_aes_192_ecb, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_aes_256_cbc, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_aes_256_ctr, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_aes_256_ecb, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_aes_256_gcm, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_des_ecb, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_des_cbc, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_des_ede3_ecb, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_des_ede3_cbc, (void), ()) \ -DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_rc4, (void), ()) \ -DEFINEFUNC_RENAMED_3_0(int, EVP_CIPHER_get_block_size, EVP_CIPHER_block_size, (const GO_EVP_CIPHER_PTR cipher), (cipher)) \ -DEFINEFUNC(int, EVP_CIPHER_CTX_set_key_length, (GO_EVP_CIPHER_CTX_PTR x, int keylen), (x, keylen)) \ -DEFINEFUNC(void, EVP_CIPHER_CTX_free, (GO_EVP_CIPHER_CTX_PTR arg0), (arg0)) \ -DEFINEFUNC(int, EVP_CIPHER_CTX_ctrl, (GO_EVP_CIPHER_CTX_PTR ctx, int type, int arg, void *ptr), (ctx, type, arg, ptr)) \ -DEFINEFUNC(GO_EVP_PKEY_PTR, EVP_PKEY_new, (void), ()) \ -DEFINEFUNC_1_1_1(GO_EVP_PKEY_PTR, EVP_PKEY_new_raw_private_key, (int type, GO_ENGINE_PTR e, const unsigned char *key, size_t keylen), (type, e, key, keylen)) \ -DEFINEFUNC_1_1_1(GO_EVP_PKEY_PTR, EVP_PKEY_new_raw_public_key, (int type, GO_ENGINE_PTR e, const unsigned char *key, size_t keylen), (type, e, key, keylen)) \ -/* EVP_PKEY_size and EVP_PKEY_get_bits pkey parameter is const since OpenSSL 1.1.1. */ \ -/* Exclude it from headercheck tool when using previous OpenSSL versions. */ \ -/*check:from=1.1.1*/ DEFINEFUNC_RENAMED_3_0(int, EVP_PKEY_get_size, EVP_PKEY_size, (const GO_EVP_PKEY_PTR pkey), (pkey)) \ -/*check:from=1.1.1*/ DEFINEFUNC_RENAMED_3_0(int, EVP_PKEY_get_bits, EVP_PKEY_bits, (const GO_EVP_PKEY_PTR pkey), (pkey)) \ -DEFINEFUNC(void, EVP_PKEY_free, (GO_EVP_PKEY_PTR arg0), (arg0)) \ -DEFINEFUNC_LEGACY_1(GO_RSA_PTR, EVP_PKEY_get1_RSA, (GO_EVP_PKEY_PTR pkey), (pkey)) \ -DEFINEFUNC_LEGACY_1(int, EVP_PKEY_assign, (GO_EVP_PKEY_PTR pkey, int type, void *key), (pkey, type, key)) \ -DEFINEFUNC(int, EVP_PKEY_verify, (GO_EVP_PKEY_CTX_PTR ctx, const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen), (ctx, sig, siglen, tbs, tbslen)) \ -DEFINEFUNC(GO_EVP_PKEY_CTX_PTR, EVP_PKEY_CTX_new, (GO_EVP_PKEY_PTR arg0, GO_ENGINE_PTR arg1), (arg0, arg1)) \ -DEFINEFUNC(GO_EVP_PKEY_CTX_PTR, EVP_PKEY_CTX_new_id, (int id, GO_ENGINE_PTR e), (id, e)) \ -DEFINEFUNC_3_0(GO_EVP_PKEY_CTX_PTR, EVP_PKEY_CTX_new_from_pkey, (GO_OSSL_LIB_CTX_PTR libctx, GO_EVP_PKEY_PTR pkey, const char *propquery), (libctx, pkey, propquery)) \ -DEFINEFUNC(int, EVP_PKEY_paramgen_init, (GO_EVP_PKEY_CTX_PTR ctx), (ctx)) \ -DEFINEFUNC(int, EVP_PKEY_paramgen, (GO_EVP_PKEY_CTX_PTR ctx, GO_EVP_PKEY_PTR *ppkey), (ctx, ppkey)) \ -DEFINEFUNC(int, EVP_PKEY_keygen_init, (GO_EVP_PKEY_CTX_PTR ctx), (ctx)) \ -DEFINEFUNC(int, EVP_PKEY_keygen, (GO_EVP_PKEY_CTX_PTR ctx, GO_EVP_PKEY_PTR *ppkey), (ctx, ppkey)) \ -DEFINEFUNC_VARIADIC_3_0(GO_EVP_PKEY_PTR, EVP_PKEY_Q_keygen, EVP_PKEY_Q_keygen, (GO_OSSL_LIB_CTX_PTR ctx, const char *propq, const char *type), (ctx, propq, type)) \ -DEFINEFUNC_VARIADIC_3_0(GO_EVP_PKEY_PTR, EVP_PKEY_Q_keygen, EVP_PKEY_Q_keygen_RSA, (GO_OSSL_LIB_CTX_PTR ctx, const char *propq, const char *type, size_t arg1), (ctx, propq, type, arg1)) \ -DEFINEFUNC_VARIADIC_3_0(GO_EVP_PKEY_PTR, EVP_PKEY_Q_keygen, EVP_PKEY_Q_keygen_EC, (GO_OSSL_LIB_CTX_PTR ctx, const char *propq, const char *type, const char *arg1), (ctx, propq, type, arg1)) \ -DEFINEFUNC(void, EVP_PKEY_CTX_free, (GO_EVP_PKEY_CTX_PTR arg0), (arg0)) \ -DEFINEFUNC(int, EVP_PKEY_CTX_ctrl, (GO_EVP_PKEY_CTX_PTR ctx, int keytype, int optype, int cmd, int p1, void *p2), (ctx, keytype, optype, cmd, p1, p2)) \ -DEFINEFUNC(int, EVP_PKEY_decrypt, (GO_EVP_PKEY_CTX_PTR arg0, unsigned char *arg1, size_t *arg2, const unsigned char *arg3, size_t arg4), (arg0, arg1, arg2, arg3, arg4)) \ -DEFINEFUNC(int, EVP_PKEY_encrypt, (GO_EVP_PKEY_CTX_PTR arg0, unsigned char *arg1, size_t *arg2, const unsigned char *arg3, size_t arg4), (arg0, arg1, arg2, arg3, arg4)) \ -DEFINEFUNC(int, EVP_PKEY_decrypt_init, (GO_EVP_PKEY_CTX_PTR arg0), (arg0)) \ -DEFINEFUNC(int, EVP_PKEY_encrypt_init, (GO_EVP_PKEY_CTX_PTR arg0), (arg0)) \ -DEFINEFUNC(int, EVP_PKEY_sign_init, (GO_EVP_PKEY_CTX_PTR arg0), (arg0)) \ -DEFINEFUNC(int, EVP_PKEY_verify_init, (GO_EVP_PKEY_CTX_PTR arg0), (arg0)) \ -DEFINEFUNC(int, EVP_PKEY_sign, (GO_EVP_PKEY_CTX_PTR arg0, unsigned char *arg1, size_t *arg2, const unsigned char *arg3, size_t arg4), (arg0, arg1, arg2, arg3, arg4)) \ -DEFINEFUNC(int, EVP_PKEY_derive_init, (GO_EVP_PKEY_CTX_PTR ctx), (ctx)) \ -DEFINEFUNC(int, EVP_PKEY_derive_set_peer, (GO_EVP_PKEY_CTX_PTR ctx, GO_EVP_PKEY_PTR peer), (ctx, peer)) \ -DEFINEFUNC(int, EVP_PKEY_derive, (GO_EVP_PKEY_CTX_PTR ctx, unsigned char *key, size_t *keylen), (ctx, key, keylen)) \ -DEFINEFUNC_LEGACY_1_0(void*, EVP_PKEY_get0, (GO_EVP_PKEY_PTR pkey), (pkey)) \ -DEFINEFUNC_LEGACY_1_1(GO_EC_KEY_PTR, EVP_PKEY_get0_EC_KEY, (GO_EVP_PKEY_PTR pkey), (pkey)) \ -DEFINEFUNC_LEGACY_1_1(GO_DSA_PTR, EVP_PKEY_get0_DSA, (GO_EVP_PKEY_PTR pkey), (pkey)) \ -DEFINEFUNC_3_0(int, EVP_PKEY_fromdata_init, (GO_EVP_PKEY_CTX_PTR ctx), (ctx)) \ -DEFINEFUNC_3_0(int, EVP_PKEY_fromdata, (GO_EVP_PKEY_CTX_PTR ctx, GO_EVP_PKEY_PTR *pkey, int selection, GO_OSSL_PARAM_PTR params), (ctx, pkey, selection, params)) \ -DEFINEFUNC_3_0(int, EVP_PKEY_set1_encoded_public_key, (GO_EVP_PKEY_PTR pkey, const unsigned char *pub, size_t publen), (pkey, pub, publen)) \ -DEFINEFUNC_3_0(size_t, EVP_PKEY_get1_encoded_public_key, (GO_EVP_PKEY_PTR pkey, unsigned char **ppub), (pkey, ppub)) \ -DEFINEFUNC_3_0(int, EVP_PKEY_get_bn_param, (const GO_EVP_PKEY_PTR pkey, const char *key_name, GO_BIGNUM_PTR *bn), (pkey, key_name, bn)) \ -DEFINEFUNC_LEGACY_1(GO_RSA_PTR, RSA_new, (void), ()) \ -DEFINEFUNC_LEGACY_1(void, RSA_free, (GO_RSA_PTR arg0), (arg0)) \ -DEFINEFUNC_LEGACY_1_1(int, RSA_set0_factors, (GO_RSA_PTR rsa, GO_BIGNUM_PTR p, GO_BIGNUM_PTR q), (rsa, p, q)) \ -DEFINEFUNC_LEGACY_1_1(int, RSA_set0_crt_params, (GO_RSA_PTR rsa, GO_BIGNUM_PTR dmp1, GO_BIGNUM_PTR dmp2, GO_BIGNUM_PTR iqmp), (rsa, dmp1, dmp2, iqmp)) \ -DEFINEFUNC_LEGACY_1_1(void, RSA_get0_crt_params, (const GO_RSA_PTR r, const GO_BIGNUM_PTR *dmp1, const GO_BIGNUM_PTR *dmq1, const GO_BIGNUM_PTR *iqmp), (r, dmp1, dmq1, iqmp)) \ -DEFINEFUNC_LEGACY_1_1(int, RSA_set0_key, (GO_RSA_PTR r, GO_BIGNUM_PTR n, GO_BIGNUM_PTR e, GO_BIGNUM_PTR d), (r, n, e, d)) \ -DEFINEFUNC_LEGACY_1_1(void, RSA_get0_factors, (const GO_RSA_PTR rsa, const GO_BIGNUM_PTR *p, const GO_BIGNUM_PTR *q), (rsa, p, q)) \ -DEFINEFUNC_LEGACY_1_1(void, RSA_get0_key, (const GO_RSA_PTR rsa, const GO_BIGNUM_PTR *n, const GO_BIGNUM_PTR *e, const GO_BIGNUM_PTR *d), (rsa, n, e, d)) \ -DEFINEFUNC(GO_BIGNUM_PTR, BN_new, (void), ()) \ -DEFINEFUNC(void, BN_free, (GO_BIGNUM_PTR arg0), (arg0)) \ -DEFINEFUNC(void, BN_clear, (GO_BIGNUM_PTR arg0), (arg0)) \ -DEFINEFUNC(void, BN_clear_free, (GO_BIGNUM_PTR arg0), (arg0)) \ -DEFINEFUNC(int, BN_num_bits, (const GO_BIGNUM_PTR arg0), (arg0)) \ -DEFINEFUNC(GO_BIGNUM_PTR, BN_bin2bn, (const unsigned char *arg0, int arg1, GO_BIGNUM_PTR arg2), (arg0, arg1, arg2)) \ -DEFINEFUNC_LEGACY_1_0(int, BN_bn2bin, (const GO_BIGNUM_PTR a, unsigned char *to), (a, to)) \ -DEFINEFUNC_LEGACY_1_0(GO_BIGNUM_PTR, bn_expand2, (GO_BIGNUM_PTR a, int n), (a, n)) \ -DEFINEFUNC_1_1(GO_BIGNUM_PTR, BN_lebin2bn, (const unsigned char *s, int len, GO_BIGNUM_PTR ret), (s, len, ret)) \ -DEFINEFUNC_1_1(int, BN_bn2lebinpad, (const GO_BIGNUM_PTR a, unsigned char *to, int tolen), (a, to, tolen)) \ -DEFINEFUNC_1_1(int, BN_bn2binpad, (const GO_BIGNUM_PTR a, unsigned char *to, int tolen), (a, to, tolen)) \ -DEFINEFUNC_LEGACY_1(int, EC_KEY_set_public_key_affine_coordinates, (GO_EC_KEY_PTR key, GO_BIGNUM_PTR x, GO_BIGNUM_PTR y), (key, x, y)) \ -DEFINEFUNC_LEGACY_1(int, EC_KEY_set_public_key, (GO_EC_KEY_PTR key, const GO_EC_POINT_PTR pub), (key, pub)) \ -DEFINEFUNC_LEGACY_1(void, EC_KEY_free, (GO_EC_KEY_PTR arg0), (arg0)) \ -DEFINEFUNC_LEGACY_1(const GO_EC_GROUP_PTR, EC_KEY_get0_group, (const GO_EC_KEY_PTR arg0), (arg0)) \ -DEFINEFUNC_LEGACY_1(const GO_BIGNUM_PTR, EC_KEY_get0_private_key, (const GO_EC_KEY_PTR arg0), (arg0)) \ -DEFINEFUNC_LEGACY_1(const GO_EC_POINT_PTR, EC_KEY_get0_public_key, (const GO_EC_KEY_PTR arg0), (arg0)) \ -DEFINEFUNC_LEGACY_1(GO_EC_KEY_PTR, EC_KEY_new_by_curve_name, (int arg0), (arg0)) \ -DEFINEFUNC_LEGACY_1(int, EC_KEY_set_private_key, (GO_EC_KEY_PTR arg0, const GO_BIGNUM_PTR arg1), (arg0, arg1)) \ -DEFINEFUNC(GO_EC_POINT_PTR, EC_POINT_new, (const GO_EC_GROUP_PTR arg0), (arg0)) \ -DEFINEFUNC(void, EC_POINT_free, (GO_EC_POINT_PTR arg0), (arg0)) \ -DEFINEFUNC(int, EC_POINT_mul, (const GO_EC_GROUP_PTR group, GO_EC_POINT_PTR r, const GO_BIGNUM_PTR n, const GO_EC_POINT_PTR q, const GO_BIGNUM_PTR m, GO_BN_CTX_PTR ctx), (group, r, n, q, m, ctx)) \ -DEFINEFUNC_LEGACY_1(int, EC_POINT_get_affine_coordinates_GFp, (const GO_EC_GROUP_PTR arg0, const GO_EC_POINT_PTR arg1, GO_BIGNUM_PTR arg2, GO_BIGNUM_PTR arg3, GO_BN_CTX_PTR arg4), (arg0, arg1, arg2, arg3, arg4)) \ -DEFINEFUNC_3_0(int, EC_POINT_set_affine_coordinates, (const GO_EC_GROUP_PTR arg0, GO_EC_POINT_PTR arg1, const GO_BIGNUM_PTR arg2, const GO_BIGNUM_PTR arg3, GO_BN_CTX_PTR arg4), (arg0, arg1, arg2, arg3, arg4)) \ -DEFINEFUNC(size_t, EC_POINT_point2oct, (const GO_EC_GROUP_PTR group, const GO_EC_POINT_PTR p, point_conversion_form_t form, unsigned char *buf, size_t len, GO_BN_CTX_PTR ctx), (group, p, form, buf, len, ctx)) \ -DEFINEFUNC(int, EC_POINT_oct2point, (const GO_EC_GROUP_PTR group, GO_EC_POINT_PTR p, const unsigned char *buf, size_t len, GO_BN_CTX_PTR ctx), (group, p, buf, len, ctx)) \ -DEFINEFUNC(const char *, OBJ_nid2sn, (int n), (n)) \ -DEFINEFUNC(GO_EC_GROUP_PTR, EC_GROUP_new_by_curve_name, (int nid), (nid)) \ -DEFINEFUNC(void, EC_GROUP_free, (GO_EC_GROUP_PTR group), (group)) \ -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)) \ -DEFINEFUNC_3_0(GO_EVP_MAC_CTX_PTR, EVP_MAC_CTX_new, (GO_EVP_MAC_PTR arg0), (arg0)) \ -DEFINEFUNC_3_0(int, EVP_MAC_CTX_set_params, (GO_EVP_MAC_CTX_PTR ctx, const GO_OSSL_PARAM_PTR params), (ctx, params)) \ -DEFINEFUNC_3_0(void, EVP_MAC_CTX_free, (GO_EVP_MAC_CTX_PTR arg0), (arg0)) \ -DEFINEFUNC_3_0(GO_EVP_MAC_CTX_PTR, EVP_MAC_CTX_dup, (const GO_EVP_MAC_CTX_PTR arg0), (arg0)) \ -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)) \ -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(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_BN, (GO_OSSL_PARAM_BLD_PTR bld, const char *key, const GO_BIGNUM_PTR bn), (bld, key, bn)) \ -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, 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)) \ -DEFINEFUNC_3_0(int, EVP_PKEY_CTX_set1_hkdf_salt, (GO_EVP_PKEY_CTX_PTR arg0, const unsigned char *arg1, int arg2), (arg0, arg1, arg2)) \ -DEFINEFUNC_3_0(int, EVP_PKEY_CTX_set1_hkdf_key, (GO_EVP_PKEY_CTX_PTR arg0, const unsigned char *arg1, int arg2), (arg0, arg1, arg2)) \ -DEFINEFUNC_3_0(int, EVP_PKEY_CTX_add1_hkdf_info, (GO_EVP_PKEY_CTX_PTR arg0, const unsigned char *arg1, int arg2), (arg0, arg1, arg2)) \ -DEFINEFUNC_3_0(int, EVP_PKEY_up_ref, (GO_EVP_PKEY_PTR key), (key)) \ -DEFINEFUNC_LEGACY_1(int, EVP_PKEY_set1_EC_KEY, (GO_EVP_PKEY_PTR pkey, GO_EC_KEY_PTR key), (pkey, key)) \ -DEFINEFUNC_3_0(int, EVP_PKEY_CTX_set0_rsa_oaep_label, (GO_EVP_PKEY_CTX_PTR ctx, void *label, int len), (ctx, label, len)) \ -DEFINEFUNC(int, PKCS5_PBKDF2_HMAC, (const char *pass, int passlen, const unsigned char *salt, int saltlen, int iter, const GO_EVP_MD_PTR digest, int keylen, unsigned char *out), (pass, passlen, salt, saltlen, iter, digest, keylen, out)) \ -DEFINEFUNC_1_1_1(int, EVP_PKEY_get_raw_public_key, (const GO_EVP_PKEY_PTR pkey, unsigned char *pub, size_t *len), (pkey, pub, len)) \ -DEFINEFUNC_1_1_1(int, EVP_PKEY_get_raw_private_key, (const GO_EVP_PKEY_PTR pkey, unsigned char *priv, size_t *len), (pkey, priv, len)) \ -DEFINEFUNC_3_0(GO_EVP_SIGNATURE_PTR, EVP_SIGNATURE_fetch, (GO_OSSL_LIB_CTX_PTR ctx, const char *algorithm, const char *properties), (ctx, algorithm, properties)) \ -DEFINEFUNC_3_0(void, EVP_SIGNATURE_free, (GO_EVP_SIGNATURE_PTR signature), (signature)) \ -DEFINEFUNC_LEGACY_1(GO_DSA_PTR, DSA_new, (void), ()) \ -DEFINEFUNC_LEGACY_1(void, DSA_free, (GO_DSA_PTR r), (r)) \ -DEFINEFUNC_LEGACY_1(int, DSA_generate_key, (GO_DSA_PTR a), (a)) \ -DEFINEFUNC_LEGACY_1_1(void, DSA_get0_pqg, (const GO_DSA_PTR d, const GO_BIGNUM_PTR *p, const GO_BIGNUM_PTR *q, const GO_BIGNUM_PTR *g), (d, p, q, g)) \ -DEFINEFUNC_LEGACY_1_1(int, DSA_set0_pqg, (GO_DSA_PTR d, GO_BIGNUM_PTR p, GO_BIGNUM_PTR q, GO_BIGNUM_PTR g), (d, p, q, g)) \ -DEFINEFUNC_LEGACY_1_1(void, DSA_get0_key, (const GO_DSA_PTR d, const GO_BIGNUM_PTR *pub_key, const GO_BIGNUM_PTR *priv_key), (d, pub_key, priv_key)) \ -DEFINEFUNC_LEGACY_1_1(int, DSA_set0_key, (GO_DSA_PTR d, GO_BIGNUM_PTR pub_key, GO_BIGNUM_PTR priv_key), (d, pub_key, priv_key)) \ -DEFINEFUNC_3_0(GO_EVP_KDF_PTR, EVP_KDF_fetch, (GO_OSSL_LIB_CTX_PTR libctx, const char *algorithm, const char *properties), (libctx, algorithm, properties)) \ -DEFINEFUNC_3_0(void, EVP_KDF_free, (GO_EVP_KDF_PTR kdf), (kdf)) \ -DEFINEFUNC_3_0(GO_EVP_KDF_CTX_PTR, EVP_KDF_CTX_new, (GO_EVP_KDF_PTR kdf), (kdf)) \ -DEFINEFUNC_3_0(int, EVP_KDF_CTX_set_params, (GO_EVP_KDF_CTX_PTR ctx, const GO_OSSL_PARAM_PTR params), (ctx, params)) \ -DEFINEFUNC_3_0(void, EVP_KDF_CTX_free, (GO_EVP_KDF_CTX_PTR ctx), (ctx)) \ -DEFINEFUNC_3_0(size_t, EVP_KDF_CTX_get_kdf_size, (GO_EVP_KDF_CTX_PTR ctx), (ctx)) \ -DEFINEFUNC_3_0(int, EVP_KDF_derive, (GO_EVP_KDF_CTX_PTR ctx, unsigned char *key, size_t keylen, const GO_OSSL_PARAM_PTR params), (ctx, key, keylen, params)) \ - diff --git a/tls1prf.go b/tls1prf.go index f342f22..34c2728 100644 --- a/tls1prf.go +++ b/tls1prf.go @@ -1,15 +1,15 @@ -//go:build !cmd_go_bootstrap +//go:build !cmd_go_bootstrap && cgo package openssl -// #include "goopenssl.h" -import "C" import ( "crypto" "errors" "hash" "sync" "unsafe" + + "github.com/golang-fips/openssl/v2/internal/ossl" ) func SupportsTLS1PRF() bool { @@ -28,7 +28,7 @@ func SupportsTLS1PRF() bool { // else it implements the TLS 1.2 pseudo-random function. // The pseudo-random number will be written to result and will be of length len(result). func TLS1PRF(result, secret, label, seed []byte, fh func() hash.Hash) error { - var md C.GO_EVP_MD_PTR + var md ossl.EVP_MD_PTR if fh == nil { // TLS 1.0/1.1 PRF doesn't allow to specify the hash function, // it always uses MD5SHA1. If h is nil, then assume @@ -58,53 +58,53 @@ func TLS1PRF(result, secret, label, seed []byte, fh func() hash.Hash) error { } // tls1PRF1 implements TLS1PRF for OpenSSL 1 using the EVP_PKEY API. -func tls1PRF1(result, secret, label, seed []byte, md C.GO_EVP_MD_PTR) error { +func tls1PRF1(result, secret, label, seed []byte, md ossl.EVP_MD_PTR) error { checkMajorVersion(1) - ctx := C.go_openssl_EVP_PKEY_CTX_new_id(C.GO_EVP_PKEY_TLS1_PRF, nil) - if ctx == nil { - return newOpenSSLError("EVP_PKEY_CTX_new_id") + ctx, err := ossl.EVP_PKEY_CTX_new_id(ossl.EVP_PKEY_TLS1_PRF, nil) + if err != nil { + return err } defer func() { - C.go_openssl_EVP_PKEY_CTX_free(ctx) + ossl.EVP_PKEY_CTX_free(ctx) }() - if C.go_openssl_EVP_PKEY_derive_init(ctx) != 1 { - return newOpenSSLError("EVP_PKEY_derive_init") - } - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, -1, - C.GO1_EVP_PKEY_OP_DERIVE, - C.GO_EVP_PKEY_CTRL_TLS_MD, - 0, unsafe.Pointer(md)) != 1 { - return newOpenSSLError("EVP_PKEY_CTX_set_tls1_prf_md") - } - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, -1, - C.GO1_EVP_PKEY_OP_DERIVE, - C.GO_EVP_PKEY_CTRL_TLS_SECRET, - C.int(len(secret)), unsafe.Pointer(base(secret))) != 1 { - return newOpenSSLError("EVP_PKEY_CTX_set1_tls1_prf_secret") - } - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, -1, - C.GO1_EVP_PKEY_OP_DERIVE, - C.GO_EVP_PKEY_CTRL_TLS_SEED, - C.int(len(label)), unsafe.Pointer(base(label))) != 1 { - return newOpenSSLError("EVP_PKEY_CTX_add1_tls1_prf_seed") - } - if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, -1, - C.GO1_EVP_PKEY_OP_DERIVE, - C.GO_EVP_PKEY_CTRL_TLS_SEED, - C.int(len(seed)), unsafe.Pointer(base(seed))) != 1 { - return newOpenSSLError("EVP_PKEY_CTX_add1_tls1_prf_seed") - } - outLen := C.size_t(len(result)) - if C.go_openssl_EVP_PKEY_derive_wrapper(ctx, base(result), outLen).result != 1 { - return newOpenSSLError("EVP_PKEY_derive") + if err := ossl.EVP_PKEY_derive_init(ctx); err != nil { + return err + } + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, -1, + ossl.GO1_EVP_PKEY_OP_DERIVE, + ossl.EVP_PKEY_CTRL_TLS_MD, + 0, unsafe.Pointer(md)); err != nil { + return err + } + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, -1, + ossl.GO1_EVP_PKEY_OP_DERIVE, + ossl.EVP_PKEY_CTRL_TLS_SECRET, + int32(len(secret)), unsafe.Pointer(base(secret))); err != nil { + return err + } + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, -1, + ossl.GO1_EVP_PKEY_OP_DERIVE, + ossl.EVP_PKEY_CTRL_TLS_SEED, + int32(len(label)), unsafe.Pointer(base(label))); err != nil { + return err + } + if err := ossl.EVP_PKEY_CTX_ctrl(ctx, -1, + ossl.GO1_EVP_PKEY_OP_DERIVE, + ossl.EVP_PKEY_CTRL_TLS_SEED, + int32(len(seed)), unsafe.Pointer(base(seed))); err != nil { + return err + } + outLen := len(result) + if outLen, err = ossl.EVP_PKEY_derive_wrapper(ctx, base(result), outLen); err != nil { + return err } // The Go standard library expects TLS1PRF to return the requested number of bytes, // fail if it doesn't. While there is no known situation where this will happen, // EVP_PKEY_derive handles multiple algorithms and there could be a subtle mismatch // after more code changes in the future. - if outLen != C.size_t(len(result)) { + if outLen != len(result) { return errors.New("tls1-prf: derived less bytes than requested") } return nil @@ -113,48 +113,43 @@ func tls1PRF1(result, secret, label, seed []byte, md C.GO_EVP_MD_PTR) error { // fetchTLS1PRF3 fetches the TLS1-PRF KDF algorithm. // It is safe to call this function concurrently. // The returned EVP_KDF_PTR shouldn't be freed. -var fetchTLS1PRF3 = sync.OnceValues(func() (C.GO_EVP_KDF_PTR, error) { +var fetchTLS1PRF3 = sync.OnceValues(func() (ossl.EVP_KDF_PTR, error) { checkMajorVersion(3) - name := C.CString("TLS1-PRF") - kdf := C.go_openssl_EVP_KDF_fetch(nil, name, nil) - C.free(unsafe.Pointer(name)) - if kdf == nil { - return nil, newOpenSSLError("EVP_KDF_fetch") + kdf, err := ossl.EVP_KDF_fetch(nil, cStringData(ossl.OSSL_KDF_NAME_TLS1_PRF), nil) + if err != nil { + return nil, err } return kdf, nil }) // tls1PRF3 implements TLS1PRF for OpenSSL 3 using the EVP_KDF API. -func tls1PRF3(result, secret, label, seed []byte, md C.GO_EVP_MD_PTR) error { +func tls1PRF3(result, secret, label, seed []byte, md ossl.EVP_MD_PTR) error { checkMajorVersion(3) kdf, err := fetchTLS1PRF3() if err != nil { return err } - ctx := C.go_openssl_EVP_KDF_CTX_new(kdf) - if ctx == nil { - return newOpenSSLError("EVP_KDF_CTX_new") + ctx, err := ossl.EVP_KDF_CTX_new(kdf) + if err != nil { + return err } - defer C.go_openssl_EVP_KDF_CTX_free(ctx) + defer ossl.EVP_KDF_CTX_free(ctx) bld, err := newParamBuilder() if err != nil { return err } - bld.addUTF8String(_OSSL_KDF_PARAM_DIGEST, C.go_openssl_EVP_MD_get0_name(md), 0) - bld.addOctetString(_OSSL_KDF_PARAM_SECRET, secret) - bld.addOctetString(_OSSL_KDF_PARAM_SEED, label) - bld.addOctetString(_OSSL_KDF_PARAM_SEED, seed) + bld.addUTF8String(ossl.OSSL_KDF_PARAM_DIGEST, ossl.EVP_MD_get0_name(md), 0) + bld.addOctetString(ossl.OSSL_KDF_PARAM_SECRET, secret) + bld.addOctetString(ossl.OSSL_KDF_PARAM_SEED, label) + bld.addOctetString(ossl.OSSL_KDF_PARAM_SEED, seed) params, err := bld.build() if err != nil { return err } - defer C.go_openssl_OSSL_PARAM_free(params) + defer ossl.OSSL_PARAM_free(params) - if C.go_openssl_EVP_KDF_derive(ctx, base(result), C.size_t(len(result)), params) != 1 { - return newOpenSSLError("EVP_KDF_derive") - } - return nil + return ossl.EVP_KDF_derive(ctx, base(result), len(result), params) }