How to bind openssl c binding via CGO in golang

huangapple go评论76阅读模式
英文:

How to bind openssl c binding via CGO in golang

问题

情况:

  • 需要在GoLang中使用EdDSA 448 JSON Web加密,参考
  • 在GoLang中找不到支持此功能的JWT库
  • 我们在Python中使用jwcrypto,需要类似的库在Go中

任务:

  • 在Go中解密和验证有效载荷

操作:

  • 在Rust中使用了josekit-rs,可以解决这个问题
  • 通过safer_ffi创建了C API
  • 通过CGO在Go中绑定了该库

结果:

  • 当使用简单函数(不使用openssl)时,整个绑定过程都可以工作
$ go build . 
# go-jose-kit/jose-kit-ffi
Undefined symbols for architecture arm64:
  "_AES_ige_encrypt", referenced from:
      openssl::aes::aes_ige::h356a909c3f173638 in libjose_kit_ffi.a(openssl-83ba33f9169f6e94.openssl.2a7d90ad-cgu.15.rcgu.o)
  "_AES_set_decrypt_key", referenced from:
      openssl::aes::AesKey::new_decrypt::h6be3702416d4e43e in libjose_kit_ffi.a(openssl-83ba33f9169f6e94.openssl.2a7d90ad-cgu.15.rcgu.o)
  "_AES_set_encrypt_key", referenced from:
      openssl::aes::AesKey::new_encrypt::heb205e6bc2f989db in libjose_kit_ffi.a(openssl-83ba33f9169f6e94.openssl.2a7d90ad-cgu.15.rcgu.o)
  "_AES_unwrap_key", referenced from:
. . .
. . .
enssl-83ba33f9169f6e94.openssl.2a7d90ad-cgu.13.rcgu.o)
  "_i2d_X509_REQ", referenced from:
      openssl::x509::X509ReqRef::to_der::h5e65612242296419 in libjose_kit_ffi.a(openssl-83ba33f9169f6e94.openssl.2a7d90ad-cgu.13.rcgu.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

看起来CGO无法找到Rust二进制文件使用的外部方法(符号)。

尝试创建静态库,但无法将openssl链接到Rust编译的对象中。

在main.go文件中添加了以下头文件。

#cgo CFLAGS: -I/opt/homebrew/opt/openssl@3/include
#cgo LDFLAGS: -L/opt/homebrew/opt/openssl@3/lib -L ./target/debug -l jose_kit_ffi -l pthread -l dl -lm
#include "./jose_kit_ffi.h"
$ go env
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/{USERNAME}/Library/Caches/go-build"
GOENV="/Users/{USERNAME}/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/{USERNAME}/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/{USERNAME}/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/homebrew/Cellar/go/1.18.1/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go/1.18.1/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.18.1"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/{PATH}/go.mod"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/8l/_xp4ll7n4c3dqjxrs8klhkqh0000gn/T/go-build3058634703=/tmp/go-build -gno-record-gcc-switches -fno-common"
英文:

Situation:

  • Need to use EdDSA 448 JSON web encryption in GoLang, ref
  • Couldn't find JWT library which supports this in GoLang
  • We are using jwcrypto in Python, need similar lib in GO
# Example header
{
  "alg": "ECDH-ES",
  "enc": "A256CBC-HS512",
  "epk": {
    "crv": "X448",
    "kty": "OKP",
    "x": "PNJPrNo7grr4y9m9CaxetWdMWA91aAkBf9xM2bsaJHzcLx5RZWyaBfOMhaGDioPEnOT6alPJ0sE"
  }
}

Task:

  • Decrypt and verify payload in GO

Actions:

  • Used josekit-rs in Rust which can solve this
  • Created C API via safer_ffi
  • Bind the library via CGO in Golang

Result:

  • Whole binding thing works when used simple function (without openssl)
$ go build . 
# go-jose-kit/jose-kit-ffi
Undefined symbols for architecture arm64:
  "_AES_ige_encrypt", referenced from:
      openssl::aes::aes_ige::h356a909c3f173638 in libjose_kit_ffi.a(openssl-83ba33f9169f6e94.openssl.2a7d90ad-cgu.15.rcgu.o)
  "_AES_set_decrypt_key", referenced from:
      openssl::aes::AesKey::new_decrypt::h6be3702416d4e43e in libjose_kit_ffi.a(openssl-83ba33f9169f6e94.openssl.2a7d90ad-cgu.15.rcgu.o)
  "_AES_set_encrypt_key", referenced from:
      openssl::aes::AesKey::new_encrypt::heb205e6bc2f989db in libjose_kit_ffi.a(openssl-83ba33f9169f6e94.openssl.2a7d90ad-cgu.15.rcgu.o)
  "_AES_unwrap_key", referenced from:
. . .
. . .
enssl-83ba33f9169f6e94.openssl.2a7d90ad-cgu.13.rcgu.o)
  "_i2d_X509_REQ", referenced from:
      openssl::x509::X509ReqRef::to_der::h5e65612242296419 in libjose_kit_ffi.a(openssl-83ba33f9169f6e94.openssl.2a7d90ad-cgu.13.rcgu.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

It seems CGO is unable to find external methods (symbols) used by rust binary.

Tried to create static lib but it isn't possible to link openssl within rust compiled object.

In main.go file have added these headers.

#cgo CFLAGS: -I/opt/homebrew/opt/openssl@3/include
#cgo LDFLAGS: -L/opt/homebrew/opt/openssl@3/lib -L ./target/debug -l jose_kit_ffi -l pthread -l dl -lm
#include "./jose_kit_ffi.h"
$ go env
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/{USERNAME}/Library/Caches/go-build"
GOENV="/Users/{USERNAME}/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/{USERNAME}/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/{USERNAME}/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/homebrew/Cellar/go/1.18.1/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go/1.18.1/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.18.1"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/{PATH}/go.mod"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/8l/_xp4ll7n4c3dqjxrs8klhkqh0000gn/T/go-build3058634703=/tmp/go-build -gno-record-gcc-switches -fno-common"

答案1

得分: 1

通过创建动态链接库(dylib)而不是静态库(static lib)来解决了这个问题。

[package]
name = "jose-kit-ffi"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
# crate-type = ["staticlib"] -> 不起作用
crate-type = ["dylib"] ->
# ^ 它不会在二进制文件中包含openssl符号。

[dependencies]
safer-ffi = { version = "0.0.10", features = ["proc_macros"] }
josekit = "0.8.1"
serde_json = "1.0"


[features]
c-headers = ["safer-ffi/headers"]

结果

go run .
2022/08/21 22:19:14 Hello, from GO!
JwkSecret { priv_key: "--", pub_key: "--" }
Encrypted JWT: eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiZXBrIjp7Imt0eSI6Ik9LUCIsImNydiI6Ilg0NDgiLCJ4IjoiTmdjRlE4bFY3WWtjUWMtNXR6RlhuUnZvcEI0NlZVTnhPWHFKajgwSzNLQnR4YWh1al9zM3ZNRVY4WVA0cnVvNkttS0FNR0FCN1M4In0sImFsZyI6IkVDREgtRVMifQ..q9BgTEh2UPjiSgLNfu0BTw.rLDyrLQYwtWpi4Qyo43csmERW-VNXowQQBPmqu7zj7U.epX8cMdNA9o9xzMTVdaxJALdtgruVyox5JaPYxKpwZ8
Some("eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiZXBrIjp7Imt0eSI6Ik9LUCIsImNydiI6Ilg0NDgiLCJ4IjoiTmdjRlE4bFY3WWtjUWMtNXR6RlhuUnZvcEI0NlZVTnhPWHFKajgwSzNLQnR4YWh1al9zM3ZNRVY4WVA0cnVvNkttS0FNR0FCN1M4In0sImFsZyI6IkVDREgtRVMifQ..q9BgTEh2UPjiSgLNfu0BTw.rLDyrLQYwtWpi4Qyo43csmERW-VNXowQQBPmqu7zj7U.epX8cMdNA9o9xzMTVdaxJALdtgruVyox5JaPYxKpwZ8")
英文:

Solved it via creating dylib instead of static lib.

[package]
name = "jose-kit-ffi"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
# crate-type = ["staticlib"] -> Doesn't work
crate-type = ["dylib"] -> 
# ^ It won't include openssl symbols in binary.

[dependencies]
safer-ffi = { version = "0.0.10", features = ["proc_macros"] }
josekit = "0.8.1"
serde_json = "1.0"


[features]
c-headers = ["safer-ffi/headers"]

Result

go run .
2022/08/21 22:19:14 Hello, from GO!
JwkSecret { priv_key: "--", pub_key: "--" }
Encrypted JWT: eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiZXBrIjp7Imt0eSI6Ik9LUCIsImNydiI6Ilg0NDgiLCJ4IjoiTmdjRlE4bFY3WWtjUWMtNXR6RlhuUnZvcEI0NlZVTnhPWHFKajgwSzNLQnR4YWh1al9zM3ZNRVY4WVA0cnVvNkttS0FNR0FCN1M4In0sImFsZyI6IkVDREgtRVMifQ..q9BgTEh2UPjiSgLNfu0BTw.rLDyrLQYwtWpi4Qyo43csmERW-VNXowQQBPmqu7zj7U.epX8cMdNA9o9xzMTVdaxJALdtgruVyox5JaPYxKpwZ8
Some("eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiZXBrIjp7Imt0eSI6Ik9LUCIsImNydiI6Ilg0NDgiLCJ4IjoiTmdjRlE4bFY3WWtjUWMtNXR6RlhuUnZvcEI0NlZVTnhPWHFKajgwSzNLQnR4YWh1al9zM3ZNRVY4WVA0cnVvNkttS0FNR0FCN1M4In0sImFsZyI6IkVDREgtRVMifQ..q9BgTEh2UPjiSgLNfu0BTw.rLDyrLQYwtWpi4Qyo43csmERW-VNXowQQBPmqu7zj7U.epX8cMdNA9o9xzMTVdaxJALdtgruVyox5JaPYxKpwZ8")

答案2

得分: 0

嗨,我建议你使用github.com/golang-jwt/jwt/v4库。我认为这是很受欢迎的。如果你需要更多选择,你可以在https://jwt.io上找到其他推荐的JWT库。

英文:

Hei, I suggest u using github.com/golang-jwt/jwt/v4 lib. this popular i think. And Recommended as the one in https://jwt.io or if u need more, u can see another recommendation library JWT in there.

huangapple
  • 本文由 发表于 2022年8月22日 00:01:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/73436055.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定