将 OpenSSL 与 webassembly 链接

Posted

技术标签:

【中文标题】将 OpenSSL 与 webassembly 链接【英文标题】:Linking OpenSSL with webassembly 【发布时间】:2019-02-18 23:46:27 【问题描述】:

将 OpenSSL 链接到 webassembly

在问这个问题之前,我只想说我做了一些功课。这个问题与这里已经提出的问题非常相似 IE。 How to link OpenSSL with emscripten?

在我在这里找到了一个非常好的和详细的手册如何将 OpenSSL 编译为 webassemly 之后 https://www.ip6.li/node/129

我能够成功运行所有步骤,即

1)首先进入最新emscripten下载的目录,设置一些路径变量:

~/emscripten/emsdk$ source ./emsdk_env.sh

2) 然后执行上面手册中的脚本

./mk-openssl-webassemby.sh:

基本上,所有编译都没有任何错误,但有一个特定的警告。编译后我可以 cd 到 crypto/sha 目录和 看到文件被编译成所谓的中间表示:

/openssl/openssl-1.1.0h/openssl/crypto/sha$ file sha256.o 
sha256.o: LLVM IR bitcode

在阅读其他在线资源时,我希望该文件具有 .bc 扩展名,但似乎 .o 也是正确的。不确定。

我确实在编译过程中看到了以下警告:

make[2]: Entering directory '/openssl/openssl-1.1.0h/openssl'
( :; LIBDEPS="$LIBDEPS:--L. -lssl -L. -lcrypto -lsocket -lnsl "; LDCMD="$LDCMD:-emcc"; LDFLAGS="$LDFLAGS:--DNDEBUG -DOPENSSL_NO_DYNAMIC_ENGINE -DOPENSSL_API_COMPAT=0x10100000L -DOPENSSLDIR="\"/tmp\"" -DENGINESDIR="\"/usr/local/lib/engines-1.1\"" -g -Wall   "; LIBPATH=`for x in $LIBDEPS; do echo $x; done | sed -e 's/^ *-L//;t' -e d | uniq`; LIBPATH=`echo $LIBPATH | sed -e 's/ /:/g'`; echo LD_LIBRARY_PATH=$LIBPATH:$LD_LIBRARY_PATH $LDCMD $LDFLAGS -o $APPNAME:=test/buildtest_x509_vfy test/buildtest_x509_vfy.o $LIBDEPS; LD_LIBRARY_PATH=$LIBPATH:$LD_LIBRARY_PATH $LDCMD $LDFLAGS -o $APPNAME:=test/buildtest_x509_vfy test/buildtest_x509_vfy.o $LIBDEPS )
LD_LIBRARY_PATH=.: emcc -DNDEBUG -DOPENSSL_NO_DYNAMIC_ENGINE -DOPENSSL_API_COMPAT=0x10100000L -DOPENSSLDIR="/tmp" -DENGINESDIR="/usr/local/lib/engines-1.1" -g -Wall -o test/buildtest_x509_vfy test/buildtest_x509_vfy.o -L. -lssl -L. -lcrypto -lsocket -lnsl
WARNING:root:emcc: cannot find library "socket"
WARNING:root:emcc: cannot find library "nsl"

基本上,它说我找不到库套接字和 nsl。这里要提到的重要一点是编译完成时没有错误,即只有那些警告。如果我手动编辑 Makefile 并删除这些库并点击编译,编译完成而没有任何警告。这意味着现在无论代码之前存在的任何外部库现在都不会链接到某些 x86 或 ARM 架构,即,都需要特定于 wasm VM。

export CC=emcc
export CXX=emcc
export LINK=$CXX
export ARCH_FLAGS=""
export ARCH_LINK=""
export CPPFLAGS=" $ARCH_FLAGS "
export CXXFLAGS=" $ARCH_FLAGS "
export CFLAGS=" $ARCH_FLAGS "
export LDFLAGS=" $ARCH_LINK "
echo  $OSTYPE | grep -i darwin > /dev/null 2> /dev/null

./Configure purify --openssldir=/tmp --api=1.1.0 no-engine no-dso no-dgram no-sock no-srtp no-stdio no-ui no-err no-ocsp no-psk no-stdio no-ts

Configuring OpenSSL version 1.1.0h (0x1010008fL)
    no-afalgeng     [forced]   OPENSSL_NO_AFALGENG
    no-apps         [forced]   OPENSSL_NO_APPS
    no-asan         [default]  OPENSSL_NO_ASAN
    no-capieng      [forced]   OPENSSL_NO_CAPIENG
    no-crypto-mdebug [default]  OPENSSL_NO_CRYPTO_MDEBUG
    no-crypto-mdebug-backtrace [default]  OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE
    no-dgram        [option]   OPENSSL_NO_DGRAM
    no-dso          [option]  
    no-dtls         [forced]   OPENSSL_NO_DTLS
    no-dtls1        [forced]   OPENSSL_NO_DTLS1
    no-dtls1_2      [forced]   OPENSSL_NO_DTLS1_2
    no-dynamic-engine [forced]  
    no-ec_nistp_64_gcc_128 [default]  OPENSSL_NO_EC_NISTP_64_GCC_128
    no-egd          [default]  OPENSSL_NO_EGD
    no-engine       [option]   OPENSSL_NO_ENGINE (skip engines)
    no-err          [option]   OPENSSL_NO_ERR
    no-fuzz-afl     [default]  OPENSSL_NO_FUZZ_AFL
    no-fuzz-libfuzzer [default]  OPENSSL_NO_FUZZ_LIBFUZZER
    no-heartbeats   [default]  OPENSSL_NO_HEARTBEATS
    no-md2          [default]  OPENSSL_NO_MD2 (skip dir)
    no-msan         [default]  OPENSSL_NO_MSAN
    no-ocsp         [option]   OPENSSL_NO_OCSP (skip dir)
    no-psk          [option]   OPENSSL_NO_PSK
    no-rc5          [default]  OPENSSL_NO_RC5 (skip dir)
    no-sctp         [default]  OPENSSL_NO_SCTP
    no-sock         [option]   OPENSSL_NO_SOCK
    no-srtp         [option]   OPENSSL_NO_SRTP
    no-ssl-trace    [default]  OPENSSL_NO_SSL_TRACE
    no-ssl3         [default]  OPENSSL_NO_SSL3
    no-ssl3-method  [default]  OPENSSL_NO_SSL3_METHOD
    no-stdio        [option]   OPENSSL_NO_STDIO
    no-tests        [forced]   OPENSSL_NO_TESTS
    no-ts           [option]   OPENSSL_NO_TS (skip dir)
    no-ubsan        [default]  OPENSSL_NO_UBSAN
    no-ui           [option]   OPENSSL_NO_UI (skip dir)
    no-unit-test    [default]  OPENSSL_NO_UNIT_TEST
    no-weak-ssl-ciphers [default]  OPENSSL_NO_WEAK_SSL_CIPHERS
    no-zlib         [default] 
    no-zlib-dynamic [default] 
Configuring for purify
CC            =emcc
CFLAG         =-g -Wall 
SHARED_CFLAG  =
DEFINES       =NDEBUG OPENSSL_NO_DYNAMIC_ENGINE OPENSSL_API_COMPAT=0x10100000L
LFLAG         =
PLIB_LFLAG    =
EX_LIBS       =  -lsocket -lnsl 
APPS_OBJ      =
CPUID_OBJ     =mem_clr.o
UPLINK_OBJ    =
BN_ASM        =bn_asm.o
EC_ASM        =
DES_ENC       =des_enc.o fcrypt_b.o
AES_ENC       =aes_core.o aes_cbc.o
BF_ENC        =bf_enc.o
CAST_ENC      =c_enc.o
RC4_ENC       =rc4_enc.o rc4_skey.o
RC5_ENC       =rc5_enc.o
MD5_OBJ_ASM   =
SHA1_OBJ_ASM  =
RMD160_OBJ_ASM=
CMLL_ENC      =camellia.o cmll_misc.o cmll_cbc.o
MODES_OBJ     =
PADLOCK_OBJ   =
CHACHA_ENC    =chacha_enc.o
POLY1305_OBJ  =
BLAKE2_OBJ    =
PROCESSOR     =
RANLIB        =ranlib
ARFLAGS       =
PERL          =/usr/bin/perl

THIRTY_TWO_BIT mode

Configured for purify.

The library could not be configured for supporting multi-threaded
applications as the compiler options required on this system are not known.
See file INSTALL for details if you need multi-threading.

The options 'shared', 'pic' and 'dynamic-engine' aren't supported on this
the platform, so we will pretend you gave the option 'no-pic', which also disables
'shared' and 'dynamic-engine'.  If you know how to implement shared libraries
or independent position code, please let us know (but please first make sure
you have tried with a current version of OpenSSL).

OpenSSL 编译后,我确实在目录中看到了以下文件

libcrypto.a
libcrypto.pc
libssl.a
libssl.pc

如果我测试以查看文件的内容,即查看这是我需要链接到的存档

file libcrypto.a
libcrypto.a: current ar archive

如果我测试一下符号是否存在,即

     llvm-nm libcrypto.a 

        sham_sha1.o:
         U EVP_MD_CTX_md_data
-------- T EVP_sha1
-------- T EVP_sha224
-------- T EVP_sha256
-------- T EVP_sha384
-------- T EVP_sha512
         U OPENSSL_cleanse
         U SHA1_Final
         U SHA1_Init
         U SHA1_Update
         U SHA224_Final
         U SHA224_Init
         U SHA224_Update
         U SHA256_Final
         U SHA256_Init
         U SHA256_Update
         U SHA384_Final
         U SHA384_Init
         U SHA384_Update
         U SHA512_Final
         U SHA512_Init
         U SHA512_Update
-------- t ctrl
-------- t final
-------- t final224
-------- t final256
-------- t final384
-------- t final512
-------- t init
-------- t init224
-------- t init256
-------- t init384
-------- t init512
-------- d sha1_md
-------- d sha224_md
-------- d sha256_md
-------- d sha384_md
-------- d sha512_md
-------- t update
-------- t update224
-------- t update256
-------- t update384
-------- t update512
...
sha256.o:
    ...
    -------- d K256
             U OPENSSL_cleanse
    -------- T SHA224
    -------- d SHA224.m
    -------- T SHA224_Final
    -------- T SHA224_Init
    -------- T SHA224_Update
    -------- T SHA256
    -------- d SHA256.m
    -------- T SHA256_Final
    -------- T SHA256_Init
    -------- T SHA256_Transform
    -------- T SHA256_Update
    -------- t sha256_block_data_order
    -------- d sha256_block_data_order.is_endian
...

llvm-nm libcrypto.a  |grep -i SHA256_Update
         U SHA256_Update
-------- T SHA256_Update

3) 当我尝试在我的 cmake 中链接到它时问题就开始了,即

warning: unresolved symbol: SHA256_Final
warning: unresolved symbol: SHA256_Init
warning: unresolved symbol: SHA256_Update

或带有详细输出:

VERBOSE is on, this generates a lot of output and can slow down compilation
warning: unresolved symbol: SHA256_Final
adding _SHA256_Final and deps  : function _SHA256_Final() 
err('missing 
warning: unresolved symbol: SHA256_Init
adding _SHA256_Init and deps  : function _SHA256_Init() 
err('missing f
warning: unresolved symbol: SHA256_Update
adding _SHA256_Update and deps  : function _SHA256_Update() 
err('missing
adding ___buildEnvironment and deps $ENV : function ___buildEnvironment(environ) 

有趣的是,webassembly 加载并且我能够执行不依赖于 OpenSSL 的方法,但是一旦我尝试执行一些 OpenSSL 方法,我就会在 Firefox 控制台中收到以下错误:

missing function: SHA256_Init

在我的 CmakeLists.txt 中,我使用了两个目录,即

set( OPENSSL_INCLUDE_DIR  /openssl/openssl-1.1.0h/openssl/include )
set( OPENSSL_LINK_DIR /openssl/openssl-1.1.0h/openssl )

我的目标命令看起来像

set_target_properties(mainTest PROPERTIES LINK_FLAGS " -s WASM=1  -s NO_EXIT_RUNTIME=1 -s VERBOSE=1 -lssl -lcrypto --pre-js preModule.js")

它构建了 wasm,但我不能使用这些方法。我想知道为什么我会得到那些“未解决的符号”的交战。任何帮助深表感谢。

【问题讨论】:

【参考方案1】:

解决方案非常简单。我忘记在 cmake 文件中添加以下内容

target_link_libraries(mainTest 加密) 之后,这一切都在没有警告的情况下工作。

【讨论】:

我正在尝试使用我的 Rust wasm 代码中的 openssl...您的解决方案是否涵盖了这一点,或者它是否特定于您的问题?

以上是关于将 OpenSSL 与 webassembly 链接的主要内容,如果未能解决你的问题,请参考以下文章

不只是Web,WebAssembly在区块链上还有这些用处

为什么我说WebAssembly是区块链计算的未来

如何将 C++ 文件编译为 WebAssembly?

使用Mono将C#编译运行至WebAssembly平台

快速上手 WebAssembly 应用开发:Emscripten 使用入门

将 QT WebAssembly 与 Emscripten 关联