Skip to content

Commit

Permalink
Merge pull request #98 from corhere/windows-support
Browse files Browse the repository at this point in the history
Support Unix and Windows
  • Loading branch information
qmuntal authored Aug 25, 2023
2 parents 758238f + f15d212 commit 816703e
Show file tree
Hide file tree
Showing 35 changed files with 358 additions and 88 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,39 @@ jobs:
$ok
env:
GO_OPENSSL_VERSION_OVERRIDE: ${{ matrix.openssl-version }}
wintest:
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
go-version: [1.20.x]
openssl-version: [libcrypto-1_1-x64.dll, libcrypto-3-x64.dll]
steps:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@v3
- name: Run Test
run: go test -gcflags=all=-d=checkptr -count 10 -v ./...
env:
GO_OPENSSL_VERSION_OVERRIDE: ${{ matrix.openssl-version }}
mactest:
strategy:
fail-fast: false
matrix:
go-version: [1.20.x]
openssl-version: [libcrypto.3.dylib]
runs-on: macos-12
steps:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@v3
- name: Run Test
run: go test -gcflags=all=-d=checkptr -count 10 -v ./...
env:
GO_OPENSSL_VERSION_OVERRIDE: ${{ matrix.openssl-version }}
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ This feature does not require any additional configuration, but it only works wi

## Limitations

OpenSSL is used for a given build only in limited circumstances:

- The platform must be `GOOS=linux`.
- Only Unix, Unix-like and Windows platforms are supported.
- The build must set `CGO_ENABLED=1`.

## Acknowledgements
Expand Down
2 changes: 1 addition & 1 deletion aes.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build linux && !cmd_go_bootstrap
//go:build !cmd_go_bootstrap

package openssl

Expand Down
2 changes: 0 additions & 2 deletions aes_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//go:build linux

package openssl

import (
Expand Down
2 changes: 1 addition & 1 deletion ec.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build linux && !cmd_go_bootstrap
//go:build !cmd_go_bootstrap

package openssl

Expand Down
8 changes: 4 additions & 4 deletions ecdh.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build linux && !cmd_go_bootstrap
//go:build !cmd_go_bootstrap

package openssl

Expand Down Expand Up @@ -101,7 +101,7 @@ func (k *PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) {
return nil, newOpenSSLError("EVP_PKEY_get_octet_string_param")
}
bytes = C.GoBytes(unsafe.Pointer(cbytes), C.int(n))
C.free(unsafe.Pointer(cbytes))
cryptoFree(unsafe.Pointer(cbytes))
default:
panic(errUnsupportedVersion())
}
Expand Down Expand Up @@ -314,8 +314,8 @@ func GenerateKeyECDH(curve string) (*PrivateKeyECDH, []byte, error) {
// generating a private ECDH key.
bits := C.go_openssl_EVP_PKEY_get_bits(pkey)
bytes := make([]byte, (bits+7)/8)
if C.go_openssl_BN_bn2binpad(priv, base(bytes), C.int(len(bytes))) == 0 {
return nil, nil, newOpenSSLError("BN_bn2binpad")
if err := bnToBinPad(priv, bytes); err != nil {
return nil, nil, err
}
k = &PrivateKeyECDH{pkey, curve, true}
runtime.SetFinalizer(k, (*PrivateKeyECDH).finalize)
Expand Down
2 changes: 0 additions & 2 deletions ecdh_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//go:build linux

package openssl_test

import (
Expand Down
2 changes: 1 addition & 1 deletion ecdsa.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build linux && !cmd_go_bootstrap
//go:build !cmd_go_bootstrap

package openssl

Expand Down
2 changes: 0 additions & 2 deletions ecdsa_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//go:build linux

package openssl_test

import (
Expand Down
9 changes: 4 additions & 5 deletions evp.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build linux && !cmd_go_bootstrap
//go:build !cmd_go_bootstrap

package openssl

Expand Down Expand Up @@ -197,12 +197,11 @@ func setupEVP(withKey withKeyFunc, padding C.int,
}
}
// ctx takes ownership of label, so malloc a copy for OpenSSL to free.
// OpenSSL 1.1.1 and higher does not take ownership of the label if the length is zero,
// 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 {
// Go guarantees C.malloc never returns nil.
clabel = (*C.uchar)(C.malloc(C.size_t(len(label))))
clabel = (*C.uchar)(cryptoMalloc(len(label)))
copy((*[1 << 30]byte)(unsafe.Pointer(clabel))[:len(label)], label)
}
var ret C.int
Expand All @@ -212,7 +211,7 @@ func setupEVP(withKey withKeyFunc, padding C.int,
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 {
C.free(unsafe.Pointer(clabel))
cryptoFree(unsafe.Pointer(clabel))
return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl failed")
}
case C.GO_RSA_PKCS1_PSS_PADDING:
Expand Down
9 changes: 7 additions & 2 deletions goopenssl.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
//go:build linux
//go:build unix || windows

#include "goopenssl.h"

#include <dlfcn.h> // dlsym
#ifdef _WIN32
# include <windows.h>
# define dlsym (void*)GetProcAddress
#else
# include <dlfcn.h> // dlsym
#endif
#include <stdio.h> // fprintf

// Approach taken from .Net System.Security.Cryptography.Native
Expand Down
21 changes: 17 additions & 4 deletions goopenssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ go_openssl_EVP_CIPHER_CTX_seal_wrapper(const GO_EVP_CIPHER_CTX_PTR ctx,
const unsigned char *in, int in_len,
const unsigned char *aad, int aad_len)
{
if (in_len == 0) in = "";
if (aad_len == 0) aad = "";
if (in_len == 0) in = (const unsigned char *)"";
if (aad_len == 0) aad = (const unsigned char *)"";

if (go_openssl_EVP_CipherInit_ex(ctx, NULL, NULL, NULL, nonce, GO_AES_ENCRYPT) != 1)
return 0;
Expand All @@ -144,8 +144,8 @@ go_openssl_EVP_CIPHER_CTX_open_wrapper(const GO_EVP_CIPHER_CTX_PTR ctx,
const unsigned char *aad, int aad_len,
const unsigned char *tag)
{
if (in_len == 0) in = "";
if (aad_len == 0) aad = "";
if (in_len == 0) in = (const unsigned char *)"";
if (aad_len == 0) aad = (const unsigned char *)"";

if (go_openssl_EVP_CipherInit_ex(ctx, NULL, NULL, NULL, nonce, GO_AES_DECRYPT) != 1)
return 0;
Expand All @@ -168,3 +168,16 @@ go_openssl_EVP_CIPHER_CTX_open_wrapper(const GO_EVP_CIPHER_CTX_PTR ctx,

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);
}
2 changes: 1 addition & 1 deletion hkdf.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build linux && !cmd_go_bootstrap
//go:build !cmd_go_bootstrap

package openssl

Expand Down
2 changes: 0 additions & 2 deletions hkdf_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//go:build linux

package openssl_test

import (
Expand Down
2 changes: 1 addition & 1 deletion hmac.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build linux && !cmd_go_bootstrap
//go:build !cmd_go_bootstrap

package openssl

Expand Down
2 changes: 0 additions & 2 deletions hmac_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//go:build linux

package openssl

import (
Expand Down
21 changes: 6 additions & 15 deletions init.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
//go:build linux && !cmd_go_bootstrap
//go:build !cmd_go_bootstrap

package openssl

// #include "goopenssl.h"
// #include <dlfcn.h>
import "C"
import (
"errors"
"unsafe"
)

// opensslInit loads and initialize OpenSSL.
// If successful, it returns the major and minor OpenSSL version
// as reported by the OpenSSL API.
//
// See Init() for details about version.
func opensslInit(version string) (major, minor, patch int, err error) {
// See Init() for details about file.
func opensslInit(file string) (major, minor, patch int, err error) {
// Load the OpenSSL shared library using dlopen.
handle := dlopen(version)
if handle == nil {
errstr := C.GoString(C.dlerror())
return 0, 0, 0, errors.New("openssl: can't load libcrypto.so." + version + ": " + errstr)
handle, err := dlopen(file)
if err != nil {
return 0, 0, 0, err
}

// Retrieve the loaded OpenSSL version and check if it is supported.
Expand Down Expand Up @@ -64,9 +61,3 @@ func opensslInit(version string) (major, minor, patch int, err error) {
}
return major, minor, patch, nil
}

func dlopen(version string) unsafe.Pointer {
cv := C.CString("libcrypto.so." + version)
defer C.free(unsafe.Pointer(cv))
return C.dlopen(cv, C.RTLD_LAZY|C.RTLD_LOCAL)
}
31 changes: 31 additions & 0 deletions init_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//go:build unix && !cmd_go_bootstrap

package openssl

// #cgo LDFLAGS: -ldl
// #include <stdlib.h>
// #include <dlfcn.h>
import "C"
import (
"errors"
"unsafe"
)

func dlopen(file string) (handle unsafe.Pointer, err error) {
cv := C.CString(file)
defer C.free(unsafe.Pointer(cv))
handle = C.dlopen(cv, C.RTLD_LAZY|C.RTLD_LOCAL)
if handle == nil {
errstr := C.GoString(C.dlerror())
return nil, errors.New("openssl: can't load " + file + ": " + errstr)
}
return handle, nil
}

func dlclose(handle unsafe.Pointer) error {
if C.dlclose(handle) != 0 {
errstr := C.GoString(C.dlerror())
return errors.New("openssl: can't close libcrypto: " + errstr)
}
return nil
}
36 changes: 36 additions & 0 deletions init_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//go:build !cmd_go_bootstrap

package openssl

import (
"syscall"
"unsafe"
)

type dlopenError struct {
file string
err error
}

func (e *dlopenError) Error() string {
return "openssl: can't load " + e.file + ": " + e.err.Error()
}

func (e *dlopenError) Unwrap() error {
return e.err
}

func dlopen(file string) (handle unsafe.Pointer, err error) {
// As Windows generally does not ship with a system OpenSSL library, let
// alone a FIPS 140 certified one, use the default library search order so
// that we preferentially load the DLL bundled with the application.
h, err := syscall.LoadLibrary(file)
if err != nil {
return nil, &dlopenError{file: file, err: err}
}
return unsafe.Pointer(h), nil
}

func dlclose(handle unsafe.Pointer) error {
return syscall.FreeLibrary(syscall.Handle(handle))
}
Loading

0 comments on commit 816703e

Please sign in to comment.