From f8ce495b0e620b3144096208e6df38f8aae58661 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 21 May 2026 19:01:58 +0200 Subject: [PATCH 01/10] Run wolfSSL_Init and wolfSSL_Cleanup in x509 examples Fixes F#1861 --- examples/x509/certVerify.go | 4 ++++ examples/x509/extractKey.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/examples/x509/certVerify.go b/examples/x509/certVerify.go index 1ad0842..776f52a 100644 --- a/examples/x509/certVerify.go +++ b/examples/x509/certVerify.go @@ -42,6 +42,8 @@ func loadX509(certData []byte) *wolfSSL.WOLFSSL_X509 { } func main() { + wolfSSL.WolfSSL_Init() + caPath := "../certs/ca-cert.pem" int1Path := "../certs/ca-int-cert.pem" int2Path := "../certs/ca-int2-cert.pem" @@ -117,5 +119,7 @@ func main() { } fmt.Println("Certificate chain verified successfully.") + + wolfSSL.WolfSSL_Cleanup() } diff --git a/examples/x509/extractKey.go b/examples/x509/extractKey.go index f2054f9..0e75c2b 100644 --- a/examples/x509/extractKey.go +++ b/examples/x509/extractKey.go @@ -42,6 +42,8 @@ func loadX509(certData []byte) *wolfSSL.WOLFSSL_X509 { } func main() { + wolfSSL.WolfSSL_Init() + leafPath := "../certs/server-ecc.pem" @@ -98,5 +100,7 @@ func main() { fmt.Println("Successfully imported ECC public key structure from DER buffer") wolfSSL.Wc_ecc_free(&pubKey) + + wolfSSL.WolfSSL_Cleanup() } From 28f7ffb26d025c9497c7ab9d48cef9d27442f246 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 21 May 2026 21:16:50 +0200 Subject: [PATCH 02/10] Exit on error, don't just print Fixes F#1863 --- examples/server/server-psk.go | 1 + examples/server/server.go | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/server/server-psk.go b/examples/server/server-psk.go index 117ff97..27bf153 100644 --- a/examples/server/server-psk.go +++ b/examples/server/server-psk.go @@ -91,6 +91,7 @@ func main() { conn, err := l.Accept() if err != nil { fmt.Println("Error accepting: ", err.Error()) + os.Exit(1) } /* Create a WOLFSSL object */ diff --git a/examples/server/server.go b/examples/server/server.go index 38d03fd..4dc638c 100644 --- a/examples/server/server.go +++ b/examples/server/server.go @@ -78,6 +78,7 @@ func main() { conn, err := l.Accept() if err != nil { fmt.Println("Error accepting: ", err.Error()) + os.Exit(1) } /* Create a WOLFSSL object */ From abe8a571d52d5e4b4197f455283bfb528afb27cb Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Mon, 25 May 2026 21:16:17 +0200 Subject: [PATCH 03/10] Fix concurrent wolfSSL_Read/Write race Fixes F#3730 --- README.md | 2 +- wolftls/README.md | 6 ++++++ wolftls/conn.go | 43 +++++++++++++++++++++++++++++++++++++------ wolftls/tls_test.go | 4 ++++ 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a126b22..a7a36fc 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ To use the wolfSSL go module, first build and install wolfSSL as shown below. ``` git clone https://github.com/wolfSSL/wolfssl ./autogen.sh -./configure +./configure --enable-writedup make sudo make install ``` diff --git a/wolftls/README.md b/wolftls/README.md index c483e53..2e343a9 100644 --- a/wolftls/README.md +++ b/wolftls/README.md @@ -15,3 +15,9 @@ whose entire handshake and record I/O runs through wolfSSL. - Per-connection callbacks: SNI (`Config.GetCertificate` / `GetConfigForClient`) and cert-setup; trampolines and Go I/O bridging are implemented in `callbacks.go`. + +## Build requirements + +Running `Read` and `Write` concurrently on a single `Conn` requires wolfSSL +built with `--enable-writedup`; otherwise the two calls will serialize on a +shared mutex. diff --git a/wolftls/conn.go b/wolftls/conn.go index 84e5015..9370349 100644 --- a/wolftls/conn.go +++ b/wolftls/conn.go @@ -87,9 +87,15 @@ type Conn struct { // a past deadline on c.conn. mu sync.RWMutex + // muRead/muWrite serialize wolfSSL_read/wolfSSL_write. Aliased to the + // same mutex when HAVE_WRITE_DUP unavailable. + muRead *sync.Mutex + muWrite *sync.Mutex + // wolfSSL objects — created during handshake - ctx *wolfSSL.WOLFSSL_CTX - ssl *wolfSSL.WOLFSSL + ctx *wolfSSL.WOLFSSL_CTX + ssl *wolfSSL.WOLFSSL + sslWrite *wolfSSL.WOLFSSL // == ssl when HAVE_WRITE_DUP unavailable // callback registration IDs (0 = none) ioConnID int @@ -402,6 +408,19 @@ func (c *Conn) doHandshake() error { } } + // Split off a write-only WOLFSSL when HAVE_WRITE_DUP is built in; + // otherwise fall back to a single mutex serializing Read and Write. + if dup := wolfSSL.WolfSSL_write_dup(c.ssl); dup != nil { + c.sslWrite = dup + c.muRead = &sync.Mutex{} + c.muWrite = &sync.Mutex{} + } else { + c.sslWrite = c.ssl + shared := &sync.Mutex{} + c.muRead = shared + c.muWrite = shared + } + return nil } @@ -462,6 +481,8 @@ func (c *Conn) Read(b []byte) (int, error) { if c.ssl == nil { return 0, net.ErrClosed } + c.muRead.Lock() + defer c.muRead.Unlock() n := wolfSSL.WolfSSL_read(c.ssl, b, uintptr(len(b))) if n > 0 { return n, nil @@ -490,14 +511,16 @@ func (c *Conn) Write(b []byte) (int, error) { } c.mu.RLock() defer c.mu.RUnlock() - if c.ssl == nil { + if c.sslWrite == nil { return 0, net.ErrClosed } + c.muWrite.Lock() + defer c.muWrite.Unlock() total := 0 for total < len(b) { - n := wolfSSL.WolfSSL_write(c.ssl, b[total:], uintptr(len(b)-total)) + n := wolfSSL.WolfSSL_write(c.sslWrite, b[total:], uintptr(len(b)-total)) if n <= 0 { - errCode := wolfSSL.WolfSSL_get_error(c.ssl, n) + errCode := wolfSSL.WolfSSL_get_error(c.sslWrite, n) errMsg := wolfSSL.WolfSSL_ERR_error_string(errCode, nil) return total, fmt.Errorf("wolftls: write error: %s (%d)", errMsg, errCode) } @@ -602,10 +625,18 @@ func (c *Conn) freeSSLLocked() { if c.conn != nil { c.conn.SetDeadline(time.Now().Add(100 * time.Millisecond)) } - wolfSSL.WolfSSL_shutdown(c.ssl) + shutdownSSL := c.ssl + if c.sslWrite != nil { + shutdownSSL = c.sslWrite + } + wolfSSL.WolfSSL_shutdown(shutdownSSL) if c.conn != nil { c.conn.SetDeadline(time.Time{}) // clear deadline } + if c.sslWrite != nil && c.sslWrite != c.ssl { + wolfSSL.WolfSSL_free(c.sslWrite) + } + c.sslWrite = nil wolfSSL.WolfSSL_free(c.ssl) c.ssl = nil } diff --git a/wolftls/tls_test.go b/wolftls/tls_test.go index 449f180..5a6b876 100644 --- a/wolftls/tls_test.go +++ b/wolftls/tls_test.go @@ -1139,6 +1139,10 @@ func TestConcurrentReadWrite(t *testing.T) { cli, srv, cleanup := setupPair(t) defer cleanup() + if cli.sslWrite == cli.ssl { + t.Skip("wolfSSL built without HAVE_WRITE_DUP; concurrent Read+Write serialized") + } + const messages = 100 const msgSize = 512 From c0afcb5ffbe1cb96d154d17c4ebd0a48e6f144e9 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Mon, 25 May 2026 22:33:44 +0200 Subject: [PATCH 04/10] Fix AES-GCM appended-tag encrypt with oversized outCipher Fixes F#3020 --- aes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aes.go b/aes.go index b268544..bf616a0 100644 --- a/aes.go +++ b/aes.go @@ -239,7 +239,7 @@ func Wc_AesGcm_Appended_Tag_Encrypt(aes *C.struct_Aes, outCipher, inPlain, inIv, if len(outCipher) < (len(inPlain) + AES_BLOCK_SIZE) { longOutCipher = make([]byte, len(inPlain) + AES_BLOCK_SIZE) } else { - longOutCipher = outCipher + longOutCipher = outCipher[:len(inPlain) + AES_BLOCK_SIZE] } ret := Wc_AesGcmEncrypt(aes, longOutCipher[:(len(longOutCipher)-AES_BLOCK_SIZE)], inPlain, inIv, outAuthTag[:], inAAD) From a9cb96aedae49e466e7982b7c77174e4322d50fd Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Tue, 26 May 2026 04:44:54 +0200 Subject: [PATCH 05/10] Remove WC_CTC_NAME_SIZE=256 override Fixes F#3943 --- wolfx509/certgen_wolfcrypt.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfx509/certgen_wolfcrypt.go b/wolfx509/certgen_wolfcrypt.go index 2c8f366..236bbb8 100644 --- a/wolfx509/certgen_wolfcrypt.go +++ b/wolfx509/certgen_wolfcrypt.go @@ -21,7 +21,7 @@ package wolfx509 -// #cgo CFLAGS: -g -Wall -DWC_CTC_NAME_SIZE=256 -I/usr/include -I/usr/include/wolfssl -I/usr/local/include -I/usr/local/include/wolfssl +// #cgo CFLAGS: -g -Wall -I/usr/include -I/usr/include/wolfssl -I/usr/local/include -I/usr/local/include/wolfssl // #cgo LDFLAGS: -L/usr/local/lib -lwolfssl -lm // #include // #include From a38040b3a8e8aef8ffc41b1fd1fbc48078392a7e Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Tue, 26 May 2026 18:30:00 +0200 Subject: [PATCH 06/10] Add missing ExtKeyUsage Fixes F#3942 --- wolfx509/certgen.go | 4 ++++ wolfx509/certgen_wolfcrypt.go | 2 ++ 2 files changed, 6 insertions(+) diff --git a/wolfx509/certgen.go b/wolfx509/certgen.go index eb9e66d..9275496 100644 --- a/wolfx509/certgen.go +++ b/wolfx509/certgen.go @@ -217,6 +217,10 @@ func translateExtKeyUsage(uses []ExtKeyUsage) int { out |= wcExtKeyUsageCodeSigning case ExtKeyUsageEmailProtection: out |= wcExtKeyUsageEmailProt + case ExtKeyUsageTimeStamping: + out |= wcExtKeyUsageTimestamp + case ExtKeyUsageOCSPSigning: + out |= wcExtKeyUsageOCSPSign } } return out diff --git a/wolfx509/certgen_wolfcrypt.go b/wolfx509/certgen_wolfcrypt.go index 236bbb8..cb8950e 100644 --- a/wolfx509/certgen_wolfcrypt.go +++ b/wolfx509/certgen_wolfcrypt.go @@ -87,6 +87,8 @@ const ( wcExtKeyUsageClientAuth = 0x04 wcExtKeyUsageCodeSigning = 0x08 wcExtKeyUsageEmailProt = 0x10 + wcExtKeyUsageTimestamp = 0x20 + wcExtKeyUsageOCSPSign = 0x40 ) // sigTypeFor maps a key algorithm to its wolfCrypt CTC_* sigType. From cf3ee0644ae1a386447c6de509d1bcf1c0f98e23 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Tue, 26 May 2026 18:40:59 +0200 Subject: [PATCH 07/10] Add wc_Sha256Copy stub for NO_SHA256 builds Fixes F#4399 --- sha.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sha.go b/sha.go index 80e36ee..815f541 100644 --- a/sha.go +++ b/sha.go @@ -37,6 +37,9 @@ package wolfSSL // int wc_Sha256Final(wc_Sha256* sha, byte* hash) { // return -174; // } +// int wc_Sha256Copy(wc_Sha256* src, wc_Sha256* dst) { +// return -174; +// } // #endif import "C" import ( From 3b77a50f01ad585c6b6e5363fe73b1fc915c56f2 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Tue, 26 May 2026 18:57:30 +0200 Subject: [PATCH 08/10] Add missing stubs for #ifndef HAVE_ECC Fixes F#4400 --- ecc.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ecc.go b/ecc.go index 0f4ea86..9c67c6b 100644 --- a/ecc.go +++ b/ecc.go @@ -81,6 +81,27 @@ package wolfSSL // byte* out, word32* outlen) { // return -174; // } +// int wc_ecc_export_public_raw(ecc_key* key, byte* qx, word32* qxLen, +// byte* qy, word32* qyLen) { +// return -174; +// } +// int wc_EccPrivateKeyDecode(const byte* input, word32* inOutIdx, +// ecc_key* key, word32 inSz) { +// return -174; +// } +// int wc_EccKeyToDer(ecc_key* key, byte* output, word32 inLen) { +// return -174; +// } +// int wc_EccPrivateKeyToDer(ecc_key* key, byte* output, word32 inLen) { +// return -174; +// } +// int wc_EccKeyToPKCS8(ecc_key* key, byte* output, word32* outLen) { +// return -174; +// } +// int wc_EccPublicKeyToDer(ecc_key* key, byte* output, word32 inLen, +// int with_AlgCurve) { +// return -174; +// } // #endif // // /* Negate an ECC private key: d' = order - d, then regenerate the public key */ From 1d4d4681dd487e9f398522e9f37450cb7a03932e Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Tue, 26 May 2026 20:10:34 +0200 Subject: [PATCH 09/10] Add mutex read lock to Conn commit messages Fixes F#4401 --- wolftls/conn.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/wolftls/conn.go b/wolftls/conn.go index 9370349..2d36d77 100644 --- a/wolftls/conn.go +++ b/wolftls/conn.go @@ -560,6 +560,8 @@ func (c *Conn) Close() error { // LocalAddr returns the local network address of the underlying connection. func (c *Conn) LocalAddr() net.Addr { + c.mu.RLock() + defer c.mu.RUnlock() if c.conn == nil { return nil } @@ -568,6 +570,8 @@ func (c *Conn) LocalAddr() net.Addr { // RemoteAddr returns the remote network address of the underlying connection. func (c *Conn) RemoteAddr() net.Addr { + c.mu.RLock() + defer c.mu.RUnlock() if c.conn == nil { return nil } @@ -577,6 +581,8 @@ func (c *Conn) RemoteAddr() net.Addr { // SetDeadline sets the read and write deadlines on the underlying connection. // wolfSSL will observe these via the file descriptor's socket timeout. func (c *Conn) SetDeadline(t time.Time) error { + c.mu.RLock() + defer c.mu.RUnlock() if c.conn == nil { return errors.New("wolftls: connection closed") } @@ -585,6 +591,8 @@ func (c *Conn) SetDeadline(t time.Time) error { // SetReadDeadline sets the read deadline on the underlying connection. func (c *Conn) SetReadDeadline(t time.Time) error { + c.mu.RLock() + defer c.mu.RUnlock() if c.conn == nil { return errors.New("wolftls: connection closed") } @@ -593,6 +601,8 @@ func (c *Conn) SetReadDeadline(t time.Time) error { // SetWriteDeadline sets the write deadline on the underlying connection. func (c *Conn) SetWriteDeadline(t time.Time) error { + c.mu.RLock() + defer c.mu.RUnlock() if c.conn == nil { return errors.New("wolftls: connection closed") } @@ -601,6 +611,8 @@ func (c *Conn) SetWriteDeadline(t time.Time) error { // NetConn returns the underlying net.Conn, or nil if the connection is closed. func (c *Conn) NetConn() net.Conn { + c.mu.RLock() + defer c.mu.RUnlock() if rc, ok := c.conn.(*recordingConn); ok { return rc.Conn } From 4987d092a14f38a9c5e976250bbf62673bf9ed64 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Tue, 26 May 2026 23:14:51 +0200 Subject: [PATCH 10/10] Relax writedup requirement --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a7a36fc..d839562 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,15 @@ To use the wolfSSL go module, first build and install wolfSSL as shown below. ``` git clone https://github.com/wolfSSL/wolfssl ./autogen.sh -./configure --enable-writedup +./configure make sudo make install ``` +If you plan to use the `wolftls` subpackage and need concurrent `Read` and +`Write` on a single `Conn` to run in parallel, add `--enable-writedup` to the +`./configure` line above. Otherwise, the calls will be serialized. + Then clone the go-wolfssl repo and run the `./generateOptions.sh` script to customize go-wolfssl to the same feature set as wolfSSL. This script will generate an `options.go` file that will keep go-wolfssl and wolfSSL in sync. `generateOptions` should be run any time you change your wolfSSL configure options. If the path to your wolfSSL directory is `../wolfssl`, just run: ``` git clone https://github.com/wolfSSL/go-wolfssl