├── test ├── certs │ ├── ca2-serial │ ├── ca2-database.txt.attr │ ├── ca1-cert.srl │ ├── ca2-cert.srl │ ├── ca2-database.txt │ ├── ca2-crl.pem │ ├── agent1.cnf │ ├── agent2.cnf │ ├── agent3.cnf │ ├── ca1.cnf │ ├── agent4.cnf │ ├── ca2.cnf │ ├── ca1-cert.pem │ ├── ca2-cert.pem │ ├── ca1-key.pem │ ├── ca2-key.pem │ ├── agent1-csr.pem │ ├── agent2-csr.pem │ ├── agent3-csr.pem │ ├── agent4-csr.pem │ ├── agent1-cert.pem │ ├── agent3-cert.pem │ ├── agent4-cert.pem │ ├── agent2-cert.pem │ ├── alice.crt │ ├── agent.key │ ├── agent4-key.pem │ ├── agent1-key.pem │ ├── agent2-key.pem │ ├── agent3-key.pem │ └── Makefile ├── dsa.lua ├── 5.x509_store.lua ├── sslcli.lua ├── 0.tcp_c.lua ├── 2.mac.lua ├── 0.tcp_s.lua ├── 1.x509_algor.lua ├── 2.hmac.lua ├── dh.lua ├── 8.ssl_options.lua ├── memleaks.lua ├── 7.pkcs12.lua ├── 9.srp.lua ├── 8.bio_c.lua ├── 1.x509_attr.lua ├── 8.bio_dtls_c.lua ├── 8.ssl_uv_c.lua ├── test.lua ├── provider_check.lua ├── 8.ssl_uv_s.lua ├── 8.bio_dtls_s.lua ├── 8.bio_s.lua ├── issue#185.lua ├── 0.engine.lua ├── 0.tcp.lua ├── utils │ └── ca.lua ├── 1.x509_name.lua ├── 2.asn1.lua ├── 0.bn.lua ├── 8.ssl_s.lua ├── 8.ssl_c.lua ├── 0.bio.lua ├── 6.pkcs7.lua ├── helper.lua ├── 0.misc.lua ├── sm2.lua ├── 9.ocsp.lua ├── sslctx.lua ├── 1.x509_extension.lua ├── 2.param.lua ├── 9.issue.lua ├── 2.digest.lua ├── 5.x509_crl.lua ├── 6.cms.lua └── rsa.lua ├── .gitattributes ├── .luacheckrc ├── .gitmodules ├── src ├── config.ld ├── oids.txt ├── util.c ├── openssl.h ├── point.c ├── ssl_options.h ├── pkcs12.c ├── callback.c └── ec_util.c ├── .github ├── asan.supp ├── shell │ ├── setup_uv.sh │ ├── build.sh │ ├── setenv_lua.sh │ ├── make_rockspec.sh │ ├── setup_ssl.sh │ └── setup_lua.sh ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── workflows │ ├── libressl.yml │ ├── ci.yml │ ├── codeql.yml │ └── check.yml └── PULL_REQUEST_TEMPLATE.md ├── config.win ├── .gitignore ├── .ldoc.css ├── .neoconf.json ├── appveyor.yml ├── Makefile.win ├── CMakeLists.txt ├── openssl-scm-0.rockspec ├── cmake └── Modules │ └── FindLuaJIT.cmake ├── .clang-format └── docs └── OSSL_PARAM_USAGE.md /test/certs/ca2-serial: -------------------------------------------------------------------------------- 1 | 01 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.h linguist-language=C 2 | -------------------------------------------------------------------------------- /test/certs/ca2-database.txt.attr: -------------------------------------------------------------------------------- 1 | unique_subject = yes 2 | -------------------------------------------------------------------------------- /test/certs/ca1-cert.srl: -------------------------------------------------------------------------------- 1 | 2D78A3B6F75B7EE1C742D5F02098E925A4C68316 2 | -------------------------------------------------------------------------------- /test/certs/ca2-cert.srl: -------------------------------------------------------------------------------- 1 | 6134E5E892D1C4DF4A515F94B83B29428B61D552 2 | -------------------------------------------------------------------------------- /test/certs/ca2-database.txt: -------------------------------------------------------------------------------- 1 | R 490604164002Z 220118164005Z 6134E5E892D1C4DF4A515F94B83B29428B61D552 unknown /C=US/ST=CA/L=SF/O=Joyent/OU=Node.js/CN=agent4/emailAddress=ry@tinyclouds.org 2 | -------------------------------------------------------------------------------- /.luacheckrc: -------------------------------------------------------------------------------- 1 | std = "max" 2 | self = false 3 | ignore = {"[Tt]est[%w_]+"} 4 | 5 | files = { 6 | ["test/*.lua"] = { 7 | ignore = {"EXPORT_ASSERT_TO_GLOBALS", "assert[%w_]+", "v", "y"} 8 | }, 9 | } 10 | 11 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/auxiliar"] 2 | path = deps/auxiliar 3 | url = https://github.com/zhaozg/lua-auxiliar.git 4 | [submodule "deps/lua-compat"] 5 | path = deps/lua-compat 6 | url = https://github.com/keplerproject/lua-compat-5.3.git 7 | -------------------------------------------------------------------------------- /src/config.ld: -------------------------------------------------------------------------------- 1 | project='lua-openssl' 2 | title='lua-openssl Documentation' 3 | description='OpenSSL binding for Lua' 4 | format='discount' 5 | backtick_references=false 6 | dir='doc' 7 | readme='README.md' 8 | style='!pale' 9 | kind_names={topic='Manual',module='Libraries'} 10 | -------------------------------------------------------------------------------- /.github/asan.supp: -------------------------------------------------------------------------------- 1 | # OpenSSL v1.1 2 | leak:X509_REQ_dup 3 | 4 | # github ci OpenSSL v3.0 5 | leak:OPENSSL_init_ssl 6 | 7 | # OpenSSL v3.0 fetch API - provider initialization leaks 8 | leak:EVP_MD_fetch 9 | leak:EVP_CIPHER_fetch 10 | leak:OSSL_PROVIDER_load 11 | 12 | ## MacOS 13 | #leak:_objc_init 14 | #leak:localtime_r 15 | #leak:pthread_once 16 | -------------------------------------------------------------------------------- /test/dsa.lua: -------------------------------------------------------------------------------- 1 | local openssl = require("openssl") 2 | local dsa = require("openssl").dsa 3 | local helper = require("helper") 4 | 5 | TestDSA = {} 6 | function TestDSA:Testdsa() 7 | local k = dsa.generate_key(1024) 8 | 9 | local t = k:parse() 10 | assert(t.bits == 1024) 11 | 12 | if openssl.engine then 13 | k:set_engine(openssl.engine("openssl")) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /.github/shell/setup_uv.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | source .travis/platform.sh 4 | 5 | cd $TRAVIS_BUILD_DIR 6 | 7 | if [[ "$PLATFORM" == "linux" && -z "$SSL" ]]; then 8 | git clone https://github.com/luvit/luv 9 | cd luv 10 | git submodule update --init --recursive 11 | git submodule update --recursive 12 | sudo add-apt-repository --yes ppa:kalakris/cmake 13 | sudo apt-get update -qq 14 | sudo apt-get install cmake 15 | make 16 | fi 17 | 18 | cp luv.so $TRAVIS_BUILD_DIR 19 | cd $TRAVIS_BUILD_DIR 20 | -------------------------------------------------------------------------------- /config.win: -------------------------------------------------------------------------------- 1 | # Installation directories 2 | # System's libraries directory (where binary libraries are installed) 3 | 4 | # Lua includes and lib 5 | LUA_INC= "c:\luajit\src" 6 | LUA_LIB= "c:\luajit\src\lua51.lib" 7 | 8 | # Openssl include and lib 9 | OPENSSL_INC="c:\openssl-win32\include" 10 | OPENSSL_LIB="c:\openssl-win32\lib\libeay32.lib c:\openssl-win32\lib\ssleay32.lib" 11 | 12 | LIBNAME= $T.dll 13 | 14 | # Compilation directives 15 | WARN= /O2 16 | INCS= /I$(LUA_INC) /I$(OPENSSL_INC) /Ideps 17 | CFLAGS= /DWIN32_LEAN_AND_MEAN /MD $(WARN) $(INCS) 18 | CC= cl 19 | 20 | -------------------------------------------------------------------------------- /test/certs/ca2-crl.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN X509 CRL----- 2 | MIIBaDCB0jANBgkqhkiG9w0BAQQFADB6MQswCQYDVQQGEwJVUzELMAkGA1UECAwC 3 | Q0ExCzAJBgNVBAcMAlNGMQ8wDQYDVQQKDAZKb3llbnQxEDAOBgNVBAsMB05vZGUu 4 | anMxDDAKBgNVBAMMA2NhMjEgMB4GCSqGSIb3DQEJARYRcnlAdGlueWNsb3Vkcy5v 5 | cmcXDTIyMDExODE2NDAwN1oXDTI0MTAxMzE2NDAwN1owJzAlAhRhNOXoktHE30pR 6 | X5S4OylCi2HVUhcNMjIwMTE4MTY0MDA1WjANBgkqhkiG9w0BAQQFAAOBgQC5mP6X 7 | e0aCLk8zIL2s6UQSt09nBkVavp+prxz6Y9oWdfAhMt+m0LLM1ucoD7AIwNZEygeX 8 | s3c4H1P735AJUXvJRI0yeVljHCWbwzLII6zSQq+aLas79Iw7Pq1Jz+MTXWX++Ima 9 | DyGpGJfyY6S+ybc92HUvlLdmy1SDKKTgiSliZw== 10 | -----END X509 CRL----- 11 | -------------------------------------------------------------------------------- /test/certs/agent1.cnf: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 1024 3 | days = 999 4 | distinguished_name = req_distinguished_name 5 | attributes = req_attributes 6 | prompt = no 7 | 8 | [ req_distinguished_name ] 9 | C = US 10 | ST = CA 11 | L = SF 12 | O = Joyent 13 | OU = Node.js 14 | CN = agent1 15 | emailAddress = ry@tinyclouds.org 16 | 17 | [ req_attributes ] 18 | challengePassword = A challenge password 19 | 20 | -------------------------------------------------------------------------------- /test/certs/agent2.cnf: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 1024 3 | days = 999 4 | distinguished_name = req_distinguished_name 5 | attributes = req_attributes 6 | prompt = no 7 | 8 | [ req_distinguished_name ] 9 | C = US 10 | ST = CA 11 | L = SF 12 | O = Joyent 13 | OU = Node.js 14 | CN = agent2 15 | emailAddress = ry@tinyclouds.org 16 | 17 | [ req_attributes ] 18 | challengePassword = A challenge password 19 | 20 | -------------------------------------------------------------------------------- /test/certs/agent3.cnf: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 1024 3 | days = 999 4 | distinguished_name = req_distinguished_name 5 | attributes = req_attributes 6 | prompt = no 7 | 8 | [ req_distinguished_name ] 9 | C = US 10 | ST = CA 11 | L = SF 12 | O = Joyent 13 | OU = Node.js 14 | CN = agent3 15 | emailAddress = ry@tinyclouds.org 16 | 17 | [ req_attributes ] 18 | challengePassword = A challenge password 19 | 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Libraries 8 | *.lib 9 | *.a 10 | 11 | # Shared objects (inc. Windows DLLs) 12 | *.dll 13 | *.so 14 | *.so.* 15 | *.dylib 16 | 17 | # Executables 18 | *.exe 19 | *.out 20 | *.app 21 | *.i*86 22 | *.x86_64 23 | *.hex 24 | 25 | #MSVC 26 | msvc/ 27 | 28 | #ldoc 29 | doc 30 | 31 | #lake deps 32 | *.d 33 | 34 | #misc 35 | *.orgi 36 | 37 | #coverage 38 | *.gc* 39 | 40 | #devel temp 41 | oscca/ 42 | tmp/ 43 | /src/custom.c 44 | /src/custom.h 45 | .nvimrc 46 | _codeql_build_dir/ 47 | _codeql_detected_source_root 48 | 49 | #build directory 50 | build/ 51 | -------------------------------------------------------------------------------- /test/certs/ca1.cnf: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 1024 3 | days = 999 4 | distinguished_name = req_distinguished_name 5 | attributes = req_attributes 6 | prompt = no 7 | output_password = password 8 | 9 | [ req_distinguished_name ] 10 | C = US 11 | ST = CA 12 | L = SF 13 | O = Joyent 14 | OU = Node.js 15 | CN = ca1 16 | emailAddress = ry@tinyclouds.org 17 | 18 | [ req_attributes ] 19 | challengePassword = A challenge password 20 | 21 | -------------------------------------------------------------------------------- /test/certs/agent4.cnf: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 1024 3 | days = 999 4 | distinguished_name = req_distinguished_name 5 | attributes = req_attributes 6 | prompt = no 7 | 8 | [ req_distinguished_name ] 9 | C = US 10 | ST = CA 11 | L = SF 12 | O = Joyent 13 | OU = Node.js 14 | CN = agent4 15 | emailAddress = ry@tinyclouds.org 16 | 17 | [ req_attributes ] 18 | challengePassword = A challenge password 19 | 20 | [ ext_key_usage ] 21 | extendedKeyUsage = clientAuth 22 | -------------------------------------------------------------------------------- /test/5.x509_store.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | 3 | local openssl = require("openssl") 4 | local helper = require("helper") 5 | 6 | TestStore = {} 7 | 8 | function TestStore:testAll() 9 | local ca = helper.get_ca() 10 | local store = ca:get_store() 11 | assert(store:trust(true)) 12 | store:add(ca.cacert) 13 | store:add(ca.crl) 14 | assert(store:load("certs/agent1-cert.pem", "certs")) 15 | assert(store:add_lookup("certs", "dir", "pem")) 16 | assert(store:add_lookup("certs/agent1-cert.pem", "file", "pem")) 17 | assert(store:depth(9)) 18 | assert(store:flags(0)) 19 | store:add({ ca.cacert, ca.crl }) 20 | 21 | assert(store:purpose(1)) 22 | end 23 | -------------------------------------------------------------------------------- /.github/shell/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PKG_CONFIG_PATH=$HOME/.usr/lib64/pkgconfig:$HOME/.usr/lib/pkgconfig 4 | 5 | if [[ "$RUNNER_OS" == "macOS" ]]; then 6 | if [[ -z "$SSL" ]]; then 7 | PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig:$PKG_CONFIG_PATH 8 | fi 9 | fi 10 | 11 | if [[ "$RUNNER_OS" == "Linux" && "$SSL" == "openssl-1.0.2u" ]]; then 12 | export CFLAGS="-g -fPIC -fprofile-arcs -ftest-coverage" 13 | export LDFLAGS="-g -fprofile-arcs" 14 | fi 15 | 16 | export PATH=$HOME/.usr/bin:$PATH 17 | export LD_LIBRARY_PATH=$HOME/.usr/lib 18 | export PKG_CONFIG_PATH 19 | 20 | make install PREFIX=$HOME/.usr PKG_CONFIG="PKG_CONFIG_PATH=$PKG_CONFIG_PATH pkg-config" 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/shell/setenv_lua.sh: -------------------------------------------------------------------------------- 1 | source .travis/platform.sh 2 | 3 | export PATH=$HOME/.usr/bin:${PATH} 4 | export PKG_CONFIG_PATH=$HOME/.usr/lib/pkgconfig:$PKG_CONFIG_PATH 5 | export LD_LIBRARY_PATH=$HOME/.usr/lib:$LD_LIBRARY_PATH 6 | 7 | if [ "$PLATFORM" == "macosx" ]; then 8 | if [ -z "$SSL" ]; then 9 | export PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig:$PKG_CONFIG_PATH 10 | export LD_LIBRARY_PATH=/usr/local/opt/openssl/lib:$LD_LIBRARY_PATH 11 | fi 12 | fi 13 | if [[ "$PLATFORM" == "linux" ]]; then 14 | sudo apt-get -y update 15 | sudo apt install -y valgrind 16 | fi 17 | 18 | bash .travis/setup_lua.sh 19 | if [ -x $HOME/.usr/bin/luarocks ]; then 20 | eval $($HOME/.usr/bin/luarocks path) 21 | fi 22 | -------------------------------------------------------------------------------- /test/sslcli.lua: -------------------------------------------------------------------------------- 1 | local openssl = require("openssl") 2 | 3 | -- prepare a SSL_CTX object 4 | local ctx = assert(openssl.ssl.ctx_new("TLSv1_2_client")) 5 | 6 | -- make a TCP connection, and do connect first 7 | local cli = assert(openssl.bio.connect("echo.websocket.org:443", true)) 8 | 9 | -- make a SSL connection over TCP 10 | local ssl = ctx:ssl(cli) 11 | -- set SNI name 12 | ssl:set("hostname", "echo.websocket.org") 13 | 14 | -- do SSL handshake 15 | assert(ssl:connect()) 16 | 17 | -- send a HTTP request over SSL connection 18 | assert(ssl:write("GET / HTTP/1.1\r\nHost: echo.websocket.org\r\nConnection: close\r\n\r\n")) 19 | 20 | -- read response 21 | print(ssl:read(4096)) 22 | 23 | -- shutdown SSL connection and close TCP connection 24 | ssl:shutdown() 25 | cli:close() 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a bug/problem in lua-openssl 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | 13 | - `uname -a` or OS info: 14 | - `openssl version` or OPENSSL_VERSION_TEXT in your opensslv.h: 15 | - `lua -v` or `luajit -v`: 16 | - `lua -e "print(require'openssl'.version())" or `luajit -e "print(require'openssl'.version())"`: 17 | 18 | **Problem details** 19 | A clear and concise description of what the bug is. 20 | 21 | **Steps/codes to reproduce the bug** 22 | 23 | 1. ... 24 | 2. ... 25 | 26 | **Expected result** 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /test/0.tcp_c.lua: -------------------------------------------------------------------------------- 1 | local openssl = require("openssl") 2 | local bio = openssl.bio 3 | local host, port, loop 4 | local arg = assert(arg) 5 | 6 | host = arg[1] or "127.0.0.1" -- only ip 7 | port = arg[2] or "8383" 8 | loop = arg[3] and tonumber(arg[3]) or 100 9 | print(string.format("CONNECT to %s:%s", host, port)) 10 | 11 | local function mk_connection(_host, _port) 12 | local cli = assert(bio.connect(_host .. ":" .. _port, true)) 13 | if cli then 14 | local s = "aaa" 15 | io.write(".") 16 | for _ = 1, 100 do 17 | assert(cli:write(s)) 18 | assert(cli:flush()) 19 | assert(cli:read()) 20 | end 21 | cli:shutdown() 22 | cli:close() 23 | collectgarbage() 24 | end 25 | end 26 | 27 | for _ = 1, loop do 28 | mk_connection(host, port) 29 | end 30 | print(openssl.errors()) 31 | -------------------------------------------------------------------------------- /.github/shell/make_rockspec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | version=$1 4 | if [ -z "$version" ]; then 5 | echo "must specify a version" >&2 6 | exit 1 7 | fi 8 | 9 | # .rockspec 10 | cp openssl-scm-0.rockspec openssl-${version}.rockspec 11 | script="/^version/s@\"[^\"]\\+\"@\"${version}\"@" 12 | sed -e "${script}" -i.bak openssl-${version}.rockspec 13 | script="s@https://github.com/zhaozg/lua-openssl/archive/master.zip@https://github.com/zhaozg/lua-openssl/releases/download/$version/openssl-$version.tar.gz@" 14 | sed -e "${script}" -i.bak openssl-${version}.rockspec 15 | 16 | # .tar.gz 17 | rm -rf openssl-${version} 18 | mkdir -p openssl-${version}/deps 19 | cp -r LICENSE README.md *.win test Makefile src deps openssl-${version}/ 20 | COPYFILE_DISABLE=true tar -czf openssl-${version}.tar.gz openssl-${version} 21 | rm -rf openssl-${version} 22 | -------------------------------------------------------------------------------- /src/oids.txt: -------------------------------------------------------------------------------- 1 | # Do not edit this file, add your own OIDs in /etc/xca/oids.txt 2 | # or $HOME/xca 3 | 4 | # OID short name long name 5 | 1.3.6.1.4.1.311.20.2: dom: Domain Controller 6 | 1.3.6.1.4.1.311.21.1: MsCaV: Microsoft CA Version 7 | 1.3.6.1.4.1.311.20.2.3: msUPN: Microsoft Universal Principal Name 8 | 1.3.6.1.4.1.311.10.3.4.1:msEFSFR: Microsoft EFS File Recovery 9 | 1.3.6.1.5.5.8.2.2: iKEIntermediate: IP security end entity 10 | 1.3.6.1.5.5.7.3.1: serverAuth: Microsoft Server 11 | 1.3.6.1.5.5.7.3.2: clientAuth: Microsoft Client 12 | 1.3.6.1.4.1.311.20.2.2: msSmartcardLogin: Smart Card Logon 13 | 2.5.4.44: generationQualifier: generation Qualifier 14 | 2.5.4.45: x500UniqueIdentifier: x500 Unique Identifier 15 | 2.5.4.65: pseudonym: pseudonym 16 | 0.2.262.1.10.7.20: nameDistinguisher: Name distinguisher 17 | -------------------------------------------------------------------------------- /test/2.mac.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | 3 | local openssl = require("openssl") 4 | local mac = require("openssl").mac 5 | if not mac then 6 | return 7 | end 8 | 9 | TestMAC = {} 10 | function TestMAC:setUp() 11 | self.msg = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" 12 | self.alg = "aes-128-cbc" 13 | self.key = "\x0F\x0E\x0D\x0C\x0B\x0A\x00\x08\x07\x06\x05\x04\x03\x02\x01\x00" 14 | end 15 | 16 | function TestMAC:tearDown() end 17 | 18 | function TestMAC:testCMAC() 19 | local a, b, c, err 20 | 21 | openssl.clear_error() 22 | a, err = mac.ctx(self.alg, self.key) 23 | if a then 24 | b = a:final(self.msg) 25 | lu.assertEquals(b, "21a805600f5a650854142d7ec00a4224") 26 | 27 | c = a:final(self.msg, true) 28 | assert(c, openssl.hex(b)) 29 | else 30 | print("Bugs, " .. err) 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /.ldoc.css: -------------------------------------------------------------------------------- 1 | /* custom.css */ 2 | body { 3 | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; 4 | line-height: 1.6; 5 | color: #333; 6 | background-color: #f9f9f9; 7 | } 8 | 9 | table { 10 | width: 100%; 11 | border-collapse: collapse; 12 | margin: 20px 0; 13 | box-shadow: 0 2px 5px rgba(0,0,0,0.1); 14 | background-color: white; 15 | } 16 | 17 | th, td { 18 | padding: 12px 15px; 19 | text-align: left; 20 | border-bottom: 1px solid #ddd; 21 | } 22 | 23 | th { 24 | background-color: #0056b3; 25 | color: white; 26 | font-weight: 600; 27 | font-size: 1.1em; 28 | } 29 | 30 | tr:hover { 31 | background-color: #f1f5f9; 32 | } 33 | 34 | .function-name { 35 | font-weight: bold; 36 | color: #0056b3; 37 | font-family: monospace; 38 | } 39 | 40 | .function-desc { 41 | color: #444; 42 | font-size: 0.95em; 43 | } 44 | -------------------------------------------------------------------------------- /test/certs/ca2.cnf: -------------------------------------------------------------------------------- 1 | [ ca ] 2 | default_ca = CA_default 3 | 4 | [ CA_default ] 5 | serial = ca2-serial 6 | crl = ca2-crl.pem 7 | database = ca2-database.txt 8 | name_opt = CA_default 9 | cert_opt = CA_default 10 | default_crl_days = 999 11 | default_md = sha256 12 | 13 | 14 | [ req ] 15 | default_bits = 1024 16 | days = 999 17 | distinguished_name = req_distinguished_name 18 | attributes = req_attributes 19 | prompt = no 20 | output_password = password 21 | 22 | [ req_distinguished_name ] 23 | C = US 24 | ST = CA 25 | L = SF 26 | O = Joyent 27 | OU = Node.js 28 | CN = ca2 29 | emailAddress = ry@tinyclouds.org 30 | 31 | [ req_attributes ] 32 | challengePassword = A challenge password 33 | 34 | -------------------------------------------------------------------------------- /test/0.tcp_s.lua: -------------------------------------------------------------------------------- 1 | local openssl = require("openssl") 2 | local bio = openssl.bio 3 | local host, port, loop 4 | local arg = assert(arg) 5 | 6 | host = arg[1] or "127.0.0.1" -- only ip 7 | port = arg[2] or "8383" 8 | loop = arg[3] and tonumber(arg[3]) or 100 9 | 10 | print(string.format("Listen at %s:%s", host, port)) 11 | local i = 0 12 | local srv = assert(bio.accept(host .. ":" .. port)) 13 | if srv then 14 | -- make real listen 15 | if srv:accept(true) then 16 | print("accepting...") 17 | io.flush() 18 | while i < loop do 19 | local cli = assert(srv:accept()) 20 | repeat 21 | local s = cli:read() 22 | if s then 23 | cli:write(s) 24 | cli:flush() 25 | end 26 | until not s 27 | cli:close() 28 | collectgarbage() 29 | i = i + 1 30 | end 31 | else 32 | print(openssl.errors()) 33 | end 34 | srv:close() 35 | end 36 | -------------------------------------------------------------------------------- /test/certs/ca1-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICdjCCAd8CFCpUAKAgSnNgcKLk+ZcbpQqMIKxyMA0GCSqGSIb3DQEBCwUAMHox 3 | CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDzANBgNVBAoM 4 | BkpveWVudDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwDY2ExMSAwHgYJKoZI 5 | hvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzAeFw0yMjAxMTgxNjQwMDFaFw00OTA2 6 | MDQxNjQwMDFaMHoxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwC 7 | U0YxDzANBgNVBAoMBkpveWVudDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwD 8 | Y2ExMSAwHgYJKoZIhvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzCBnzANBgkqhkiG 9 | 9w0BAQEFAAOBjQAwgYkCgYEAxnUIMB7OMAxA8mXnzcmUOIpGZNkOWo7OsItG1BPZ 10 | hTnHscGsudh7kihfQhqOFvB6YjjEPK58zJzQulvOe+ZZtLQk4BUtMnfH9zELo6+C 11 | IJ+/Crj9HR5nkZdnjT4/OpbwGeShnQFQzv+wyf9qAK4kNNjB7Ye4yC9G9tVt4smr 12 | y2ECAwEAATANBgkqhkiG9w0BAQsFAAOBgQAhvCXOk0wMxULv53i39fL7v9mw0Q40 13 | 2Dg9n7IzxOhVVdUhUrFcZA93R/bumnmwWA5ZBfEkX+VxfiMI/a3x4mc2eLb1KeEq 14 | /fzD30Ht3o5929k74MCgR1dsLGcY9o0gmLhZ+0MdpZ/0nVtBGnIK2OWcrzv7zjZZ 15 | ftf6ZbM0r3p48w== 16 | -----END CERTIFICATE----- 17 | -------------------------------------------------------------------------------- /test/certs/ca2-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICdjCCAd8CFCaO8lg7sAv6UOmCDYMOPHIXdsXnMA0GCSqGSIb3DQEBCwUAMHox 3 | CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDzANBgNVBAoM 4 | BkpveWVudDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwDY2EyMSAwHgYJKoZI 5 | hvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzAeFw0yMjAxMTgxNjQwMDJaFw00OTA2 6 | MDQxNjQwMDJaMHoxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwC 7 | U0YxDzANBgNVBAoMBkpveWVudDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwD 8 | Y2EyMSAwHgYJKoZIhvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzCBnzANBgkqhkiG 9 | 9w0BAQEFAAOBjQAwgYkCgYEAxS+SbYtVM9ktJ5x9sg+eoMtzc+seUPaJovNUWBZQ 10 | bj3ZE6P364mBMDSGa+v2MfHLoMp6/A6nL3Yo/W9NdEJaiq2+hEwaSvtwskNgrr40 11 | pDMFN34s+PfsRbhlxVYdS4EIoiIchXxKJp+X6M+Q6y3Pul+d8HodaT9w70fLV0kK 12 | G70CAwEAATANBgkqhkiG9w0BAQsFAAOBgQAl7Uyjpuu7Y4sUetKQvv4ZXoZSs1V2 13 | TVL+0/DbbyCMFD8A3n0ls41/2ml5oxg+ZPzLfse3HE+cJKPGymcZqhLW36QvbFEc 14 | TxxGLKh8m8V+IXK2wqw+Ccm1Tp6dw9V5ozAWP72jU5+cr80SjboWhkLdq0ewIpEv 15 | FCPzUmAvZNPHvA== 16 | -----END CERTIFICATE----- 17 | -------------------------------------------------------------------------------- /test/1.x509_algor.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local algor = require("openssl").x509.algor 4 | 5 | TestX509Algor = {} 6 | 7 | function TestX509Algor:testAll() 8 | local alg1 = algor.new() 9 | assert(alg1:dup() == nil) 10 | local alg2 = algor.new() 11 | if alg1.equals then 12 | assert(alg1:equals(alg2)) 13 | assert(alg1 == alg2) 14 | end 15 | 16 | alg1:md("sha1") 17 | alg2:md("sha256") 18 | 19 | assert(alg1 ~= alg2) 20 | 21 | local o1 = openssl.asn1.new_object("C") 22 | alg1:set(o1) 23 | local a, b = alg1:get() 24 | assert(tostring(a):match("openssl.asn1_object:")) 25 | assert(b == nil) 26 | 27 | local s = openssl.asn1.new_string("CN", openssl.asn1.UTF8STRING) 28 | alg1:set(o1, s) 29 | 30 | a, b = alg1:get() 31 | assert(tostring(a):match("openssl.asn1_object")) 32 | assert(o1 == a) 33 | assert(b == s) 34 | 35 | local b = alg2:get() 36 | assert(a ~= b) 37 | alg2 = assert(alg1:dup()) 38 | assert(alg2 == alg1) 39 | end 40 | -------------------------------------------------------------------------------- /test/2.hmac.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | 3 | local openssl = require("openssl") 4 | local hmac = require("openssl").hmac 5 | 6 | TestHMACCompat = {} 7 | function TestHMACCompat:setUp() 8 | self.msg = "abcd" 9 | self.alg = "sha1" 10 | self.key = "abcdefg" 11 | end 12 | 13 | function TestHMACCompat:tearDown() end 14 | 15 | function TestHMACCompat:testDigest() 16 | local a, b, c 17 | a = hmac.hmac(self.alg, self.msg, self.key, true) 18 | lu.assertEquals(#a, 20) 19 | 20 | b = hmac.hmac(self.alg, self.msg, self.key, false) 21 | lu.assertEquals(#b, 40) 22 | lu.assertEquals(openssl.hex(a):lower(), b) 23 | 24 | a = assert(hmac.new(self.alg, self.key)) 25 | assert(a:size() > 0) 26 | a:update(self.msg) 27 | c = a:final() 28 | lu.assertEquals(c, b) 29 | 30 | a = assert(hmac.new(self.alg, self.key)) 31 | c = a:final(self.msg) 32 | lu.assertEquals(c, b) 33 | 34 | a = assert(hmac.new(self.alg, self.key)) 35 | c = a:final(self.msg, true) 36 | lu.assertEquals(openssl.hex(c), b) 37 | end 38 | -------------------------------------------------------------------------------- /.neoconf.json: -------------------------------------------------------------------------------- 1 | { 2 | "lspconfig": { 3 | "enable": true, 4 | "lua_ls": { 5 | "Lua": { 6 | "runtime": { 7 | "version": "LuaJIT" 8 | }, 9 | "diagnostics": { 10 | "enable": true, 11 | "globals": [ 12 | ] 13 | }, 14 | "format": { 15 | "format": false 16 | }, 17 | "workspace": { 18 | "checkThirdParty": false, 19 | "ignoreDir": [ 20 | "/.luacheckrc" 21 | ], 22 | "useGitIgnore": true, 23 | "maxPreload": 1024, 24 | "preloadFileSize": 64 25 | }, 26 | "completion": { 27 | "callSnippet": "Replace" 28 | } 29 | } 30 | }, 31 | "null-ls": { 32 | "clang_format": { 33 | }, 34 | "filetype": [ "lua", "c" ], 35 | "sources" : [ 36 | "null-ls.builtins.formatting.stylua", 37 | "null-ls.diagnostics.luacheck", 38 | "null-ls.builtins.formatting.clang_format" 39 | ] 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/certs/ca1-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIC1DBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQI9pyd98U+C7kCAggA 3 | MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECLUICG6QLOqkBIICgMYQhRWqTCF7 4 | GPYGwcI1rJw9pa3QBqMzfiBiIOTph8/q4d1IKHC5Zb4jxbg39JH46wiBkxyf5Bld 5 | FsZgLtrSrHFzihc5lMfU6bDbaNC3nB8BfZpyRcJXIVjiLyBzocx8EW68sZU3H3le 6 | m9RW1PUrRLz12nrPG4RkOGVCzLzRKyKrGYMhiyJ7doO1xe1jmtIntzfWagjUalm+ 7 | k0fA5bJ04hrO655V+X3xrU8pwL0iuMEkHgz6dXuOJfNGhZIQUkLARZnWJGBnYcrC 8 | XzWSxE39asihJtLV1qRVJasmDKod9Xy0CkISOt8TLAG+Hec7NGP6xd0Cj22faBXb 9 | kpYnGoKMrv1GkiLkdOHr252Bpk8mfJdTNpukCmCSAJcC/WwzqRcac3cCmKFKrZY5 10 | KldyPvVbfYRs5DEA9iVwW9Cq1L0UABaV2FIms3dGO05bO+GEIO823XFxapmkIXq0 11 | jpslDN8kiO32IbnmB1gOeLJVAR/7dtlVhpmCxQL69PDjzoRAeiI8loY0GV1vI7PS 12 | X1dceOC22yjIIlNPajAM/HSXTiOxwMtTNMKoeArPkbk+xiJk1rY6/CFZu5Z3GqtS 13 | zEFcPfB6O0vOCqihC8r62IFAOCXNG22jC4JyNCEGtZ5Huv6galRdQAYVdAXGKYII 14 | vo9xPmWnJFagkDGQ1KhLs+O/5sQLHpaBr06io63m1oaIz60FNtcezY+6gZ59J3e2 15 | dD1WYC9gDWgE79DrZ3X6XrFa1ewhrDYXlE6ne/6eeNeyIR6LKdHSTfM2O3SX76uc 16 | OfKigoII05q9Z9/w/AchMv0LbRCOx771yedaUWYh2HogGI7HcdOFE2RN0FhSCNpm 17 | fY7LiJy2xgQ= 18 | -----END ENCRYPTED PRIVATE KEY----- 19 | -------------------------------------------------------------------------------- /test/certs/ca2-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIC1DBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIjPgni1mjLvQCAggA 3 | MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECJJ+LigU1NvABIICgGOT6+XRN2PJ 4 | TvZf9TWYfOrx8UmbEbgDO3F8zuLZJZn0aTO9MJjIorlmQdc4jXAC8Rj5dMEyYeac 5 | mVc8pyDtikoH4JgFwQMtu2b2Pc3e0s8fRHNbwPfsz53JIQsRLWgJzUYvBgxURcJQ 6 | tuEnJtBkQxr2Mb/hHVbYp72u3+nH8BrMiKCO2AcFifZxGeJT7/lf4ErS24Zvn3Bd 7 | B0qiYxmY/FN2NIXutikQ4/PPgasFjAiUscsHAYkOT5h4I7J08+bthSvayohFefKA 8 | xxFqKSjkrQqOqQsEZlMFjYU9ui2aJZdM/D5yKLbO+SYPMceVAjCdVVctuS8Epj/4 9 | VeQVRo4DPpzi6rqdYtvR+ZVKaD4iDv7cKNNjSGFCq33Q53wtx6Q0u70JYwNjTSeU 10 | dtcalB53UXYYz1d6Vr+JbU80nlC0q9NemIkzEqLTIe/6FdbOyMxjVyCx4AOhPfOR 11 | nGTUAaS02cH5M10arJgLLpgf4WqeCNON+2fU4wG0OFannpNqonmbC/em6e/i3LeS 12 | dndffMocWz0kFPI/DnYtG87I8Z4wj27mYpudCXftX3FC5XSuMZhneBJsj1PtZkoN 13 | LA6P+zL5VzRhxznXCMRImxKCdUR9aCr3jf1V/7qoMrhEmnOyafcTVCJCOJrmWiWa 14 | EaselSUQ3zGhTiB2NpM6YVwqkSHnqq5Su1YsrbL2qxHsfBHS7tff30zprDwWYyBj 15 | Idv4XFyGGbOS3Q0/Hj36p/UZUU7s8M5vhasyrzi6Yo/c949J7+KgLz98SVPmtrhP 16 | ARtnhaqgbdUA5eGyolPepDr8RW4YWd/dEusOzKBiZKquh4tkX0uYwoHs/GhZfez5 17 | A8/FxxugQcc= 18 | -----END ENCRYPTED PRIVATE KEY----- 19 | -------------------------------------------------------------------------------- /test/certs/agent1-csr.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIC5zCCAc8CAQAwfTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH 3 | DAJTRjEPMA0GA1UECgwGSm95ZW50MRAwDgYDVQQLDAdOb2RlLmpzMQ8wDQYDVQQD 4 | DAZhZ2VudDExIDAeBgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMIIBIjAN 5 | BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApfPLPMcUlFH4HbZYy3iM5zxoPkOn 6 | nD1qeaYW+MTV+eoa9e2Pj5z99tqiV0oTWC2OeQJOeRHioxDo5vPriEdzp4uw8gxc 7 | xpuGT5H+Ccs1I4gst4VnVSPoXHuovqlngQUH/Ods9YmEp2ESnJH5hZ8ETEBeHtso 8 | vFFdKPHxSdYjlNzTgj1QnVsbp0tr/WkvxR4oJUR9KqD/L/gU/oBF/0/DDPM2DBlQ 9 | U+VQe9gCU5b0Q8kY5HK6AiiX+CJZvmxrsWGj0iu8BnyZPTpNk2fYCuo23sSLVzFO 10 | qC6MbEXwj8RDGMhfLDB4z8/GzMUrpoml0GcpNEo0GDBhRlHwugq5J7+ZOQIDAQAB 11 | oCUwIwYJKoZIhvcNAQkHMRYMFEEgY2hhbGxlbmdlIHBhc3N3b3JkMA0GCSqGSIb3 12 | DQEBCwUAA4IBAQBl7kRNzZHVgtML2bG1USt5l7C5VIjfiHfyuYFU6mHiOZbGkURJ 13 | oBBfWBV97GcyelFZkZkcR4bSTWeWO/ADso+xLA2gtdhhp/vc6QIEQztfbisXGCcF 14 | V+2Y4BdCLlNQltSYrfe5ly6pSKiSve7Dzk59Q78Z2x6y06IAGZ4G/7vlww7rjz7F 15 | RS8IbhBMaRqww+CDAQCmDgHpSdRHL2k2SJioXkKsNfTqlME1nEvyMGOVGJ7002vH 16 | K3CiCvU/39m6W+n01RRCwzCngwNfrlu2RqBBZB+uhNUNx6E/t2E5UqQasoaobNt/ 17 | lWbYiSgq9Y0z9k/6o3ZaqgASm/o3cMQTjFJ7 18 | -----END CERTIFICATE REQUEST----- 19 | -------------------------------------------------------------------------------- /test/certs/agent2-csr.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIC5zCCAc8CAQAwfTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH 3 | DAJTRjEPMA0GA1UECgwGSm95ZW50MRAwDgYDVQQLDAdOb2RlLmpzMQ8wDQYDVQQD 4 | DAZhZ2VudDIxIDAeBgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMIIBIjAN 5 | BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7Rws2WBn28xuaQ1jCFiIPo7Aa0v7 6 | K3X9AYsFfZBFbZ5GrJpTN8L9QbuhXi2RfKmnO8UUaCyT/p8D4MzffdY/9hxJGiHo 7 | xHrWRZqVIUekQjxtkeMOaR5GbIKQWOKpjqxFbujRAmlp2ZYEFi3KjTaAdG5FyC11 8 | P+xSEM69TndzYeys4h3drv5WnLHLT4KhHkVEbPQ8tXdUqr/LjnFTKY2pW3Aven/0 9 | APyZ6abStnRGGFAcerw/k5FadcnShTULLcjTQJTuycgA/kvm7y06Jv8d4UItNfr1 10 | EA7ZSDyX9Pp6cMfdgAs6bhPguteXbD0kV9WjfomBHxMIwH/+c3cbjbMdswIDAQAB 11 | oCUwIwYJKoZIhvcNAQkHMRYMFEEgY2hhbGxlbmdlIHBhc3N3b3JkMA0GCSqGSIb3 12 | DQEBCwUAA4IBAQBu6FXobvV5jxHyn6Oi8cxJIkbbC3dxbQ4kdv1jj7Fh4iy+6DYU 13 | S8gfL13j3kuxU4L7KFBlZScpGHrDsEjRY6Jq3HyThDBjMmsjZJg/0kUxRc2XbZt/ 14 | jWbpioxOUwwadQVcr0IWx5tUH29BD99sIprgayBHGjMWDDfbY2N+1pzz5hVzqiUy 15 | NWqXttLRE0giy3Re06Q9e/Nv6HsZeMMK1oZqVsYpAvNQbWP5nZHyOC8yJqxBmj5w 16 | Ds3UV63gKsn4OS3K4FjFJNoQPbY24vI5iTtvVHQ6+BybdSeUXlXCuu1ksl1ruY61 17 | KxtKnFa6JMpNxIFGw0n+Qvjpfvi52HGZpb+L 18 | -----END CERTIFICATE REQUEST----- 19 | -------------------------------------------------------------------------------- /test/certs/agent3-csr.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIC5zCCAc8CAQAwfTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH 3 | DAJTRjEPMA0GA1UECgwGSm95ZW50MRAwDgYDVQQLDAdOb2RlLmpzMQ8wDQYDVQQD 4 | DAZhZ2VudDMxIDAeBgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMIIBIjAN 5 | BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy3v4wSahEpYARj6NnGlJHaiDEsE0 6 | OgyKBV4YnowQv/2myIsaFd3cGHpy8KflQ9bfNI5SyH1olwODeARIR7bFL6VU6QeP 7 | aAWYeskGuJ8dESTLibraSqnA7AW2Hhlf7j/5biQsBAFnY4cAO/FVC4npDQoszwcS 8 | y8LPI0+O0dve4d2hYD5f/gK2ULzFfiNrkQJZad9Kktwo5tsIUjzmN4QN5V9gw1nw 9 | viIizKH0e/pv+kubbEXmTZ0a0BK7NMGj2QUtX9Endj8gmFqup0XvJZfMZGES3cFx 10 | VaL7s62OyKw6JQWq/ghizlqCLjSwSCJYp/fpIK1j8kDszxWbUYBgI7CltQIDAQAB 11 | oCUwIwYJKoZIhvcNAQkHMRYMFEEgY2hhbGxlbmdlIHBhc3N3b3JkMA0GCSqGSIb3 12 | DQEBCwUAA4IBAQChgyXraRZzH80Dj94Gx1hn7aLU0EveeSJdFcRHhFAD7WKvRezU 13 | aUp10hXSdfTe17/9supcal6cjVZ+g9WUW02Q5wkHB8Wy7U0K3+ZqFHTykNgyWekG 14 | u7DoZrP2ml5Pi+Gkk34HDZrLw4iI9n3nx8P0nlMP323Idz2+rHZYe3dkl/iu4/qV 15 | xnD0qZJbwdn4ULEv7g37F8FTwZqdxJeeZA2YNQmA2RD0yk+zBQfU3DA6EkBKyoQ1 16 | b4eB4nrUsrKZN6MxvPLnJoXpJRX+K+wFj9HrAaBjLyJAxon4yjW0Zfz5PJdXAGi9 17 | jKD6t9yIbUZJbxu6anzX7XnGnihB3a1C7k1A 18 | -----END CERTIFICATE REQUEST----- 19 | -------------------------------------------------------------------------------- /test/certs/agent4-csr.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIC5zCCAc8CAQAwfTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH 3 | DAJTRjEPMA0GA1UECgwGSm95ZW50MRAwDgYDVQQLDAdOb2RlLmpzMQ8wDQYDVQQD 4 | DAZhZ2VudDQxIDAeBgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMIIBIjAN 5 | BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4qJBL0cGPeKfujOqlQqck7hc0Egv 6 | xtctZo/Cwp0oxz90KFgxl3n4cJiyfJfUbGnbvRJtId/wNIzlSanXd9x2Z6jJkUrL 7 | 7EZI4vnZBN8gXGvG2GV2ON19PC2/Mv8dDx875F8r8iH6XPQJR8RulvcK/MfzwTuC 8 | HLnos85e/KLTGAUcan+Hm/Nev+Y+uXJBkUA8WVhWAAMbBM6wpvhu1uXQojF1KHZx 9 | QWsxBXBqpFP3prOwQ9EzwlVp3n8Pjd/M6CEo///uCvriZYlZjWRHnqOs9iWrJyYK 10 | ybkZ5gk3RQWskcykrceKTj0p+N1EciyckviOvje6OLA2qmNSuTlMcsV1mQIDAQAB 11 | oCUwIwYJKoZIhvcNAQkHMRYMFEEgY2hhbGxlbmdlIHBhc3N3b3JkMA0GCSqGSIb3 12 | DQEBCwUAA4IBAQC5DxS46KuTS7McVvF9ytMx8mSJlyEjE/xE10tt76vfwglcQd0u 13 | myI1K9nxIJD14Gu6vGzfpY1+8RDKExj2dSt1OiIWg3w5pUoxrEtHctCHogrQIPA3 14 | Ir0rLdd70cDAqFVSfZqEOBw6qEs0qO81O1r6tJJya4VpWIPqdcwgooPReO4LBUpD 15 | 17FwXO1i/lSj7fjmhK8k2rQile/Sr2m0j9Pq/EbaP52La74KLZ6ionYA1d7aU/jL 16 | +ZYf54mlEWgZSiUqWPKZokV+0auV6D2aYaPukZflXe4usmDeJCWFwXpvqk3Z7fWV 17 | S2oeuAnekJ3M0choDK0Pa95ZCqgqICcvhTP8 18 | -----END CERTIFICATE REQUEST----- 19 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.4.{build} 2 | configuration: Release 3 | image: Visual Studio 2019 4 | platform: x86 5 | clone_depth: 2 6 | clone_folder: C:\lua-openssl 7 | install: 8 | - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat" 9 | - cd C:\ 10 | - git clone https://github.com/LuaJIT/LuaJIT.git C:\luajit 11 | - cd c:\luajit\src 12 | - msvcbuild.bat 13 | - copy luajit.exe C:\ 14 | - copy lua51.* C:\ 15 | - curl https://www.openssl.org/source/old/1.0.2/openssl-1.0.2u.tar.gz > openssl-1.0.2u.tar.gz 16 | - 7z x "openssl-1.0.2u.tar.gz" -so | 7z x -aoa -si -ttar 17 | - cd openssl-1.0.2u 18 | - ls . 19 | - perl Configure --prefix=C:\openssl-win32 no-asm no-shared VC-WIN32 20 | - ms\do_ms.bat 21 | - nmake -f ms\nt.mak 22 | - nmake -f ms\nt.mak install 23 | - ls C:\openssl-win32\lib 24 | - ls C:\openssl-win32\bin 25 | - cd c:\lua-openssl 26 | - git submodule update --init --recursive 27 | - git submodule update --recursive 28 | build_script: 29 | - cd c:\lua-openssl 30 | - nmake -f makefile.win 31 | - copy src\openssl.dll c:\ 32 | test_script: 33 | - cd test\ 34 | - set LUA_PATH=?.lua; 35 | - set LUA_CPATH=C:\?.dll; 36 | - c:\luajit.exe test.lua 37 | -------------------------------------------------------------------------------- /test/certs/agent1-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC/TCCAmYCFC14o7b3W37hx0LV8CCY6SWkxoMWMA0GCSqGSIb3DQEBCwUAMHox 3 | CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDzANBgNVBAoM 4 | BkpveWVudDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwDY2ExMSAwHgYJKoZI 5 | hvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzAeFw0yMjAxMTgxNjQwMDJaFw00OTA2 6 | MDQxNjQwMDJaMH0xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwC 7 | U0YxDzANBgNVBAoMBkpveWVudDEQMA4GA1UECwwHTm9kZS5qczEPMA0GA1UEAwwG 8 | YWdlbnQxMSAwHgYJKoZIhvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzCCASIwDQYJ 9 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKXzyzzHFJRR+B22WMt4jOc8aD5Dp5w9 10 | anmmFvjE1fnqGvXtj4+c/fbaoldKE1gtjnkCTnkR4qMQ6Obz64hHc6eLsPIMXMab 11 | hk+R/gnLNSOILLeFZ1Uj6Fx7qL6pZ4EFB/znbPWJhKdhEpyR+YWfBExAXh7bKLxR 12 | XSjx8UnWI5Tc04I9UJ1bG6dLa/1pL8UeKCVEfSqg/y/4FP6ARf9PwwzzNgwZUFPl 13 | UHvYAlOW9EPJGORyugIol/giWb5sa7Fho9IrvAZ8mT06TZNn2ArqNt7Ei1cxTqgu 14 | jGxF8I/EQxjIXywweM/PxszFK6aJpdBnKTRKNBgwYUZR8LoKuSe/mTkCAwEAATAN 15 | BgkqhkiG9w0BAQsFAAOBgQARwCh6vPL+KyAR0Qo0pnfmsDsTUvBeVPjc5bnK4Wm5 16 | FJCFfXafdyubeqgUY42USBN9GuU7yQm22G7zunkNdzYmuxIisYSzxfiiIYW5n51P 17 | lIpmys4vSSz7aXhaCqQ/fZxDDRQxQDL2U73Zi3OuwO5K20QOmsSlXrlocbrD+m1s 18 | rQ== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /test/certs/agent3-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC/TCCAmYCFGE05eiS0cTfSlFflLg7KUKLYdVRMA0GCSqGSIb3DQEBCwUAMHox 3 | CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDzANBgNVBAoM 4 | BkpveWVudDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwDY2EyMSAwHgYJKoZI 5 | hvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzAeFw0yMjAxMTgxNjQwMDJaFw00OTA2 6 | MDQxNjQwMDJaMH0xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwC 7 | U0YxDzANBgNVBAoMBkpveWVudDEQMA4GA1UECwwHTm9kZS5qczEPMA0GA1UEAwwG 8 | YWdlbnQzMSAwHgYJKoZIhvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzCCASIwDQYJ 9 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMt7+MEmoRKWAEY+jZxpSR2ogxLBNDoM 10 | igVeGJ6MEL/9psiLGhXd3Bh6cvCn5UPW3zSOUsh9aJcDg3gESEe2xS+lVOkHj2gF 11 | mHrJBrifHREky4m62kqpwOwFth4ZX+4/+W4kLAQBZ2OHADvxVQuJ6Q0KLM8HEsvC 12 | zyNPjtHb3uHdoWA+X/4CtlC8xX4ja5ECWWnfSpLcKObbCFI85jeEDeVfYMNZ8L4i 13 | Isyh9Hv6b/pLm2xF5k2dGtASuzTBo9kFLV/RJ3Y/IJharqdF7yWXzGRhEt3BcVWi 14 | +7OtjsisOiUFqv4IYs5agi40sEgiWKf36SCtY/JA7M8Vm1GAYCOwpbUCAwEAATAN 15 | BgkqhkiG9w0BAQsFAAOBgQCClvcKDWDqw37/sSGot0ArC9SCw+h7/+BxnbJ+MsaY 16 | V0BLylVMUKWq8ETETRKE1bTmPT+H918MOnVjYDF5/JSYEBRXLLRdG19EkwxwbGDr 17 | wA+UXD/j0X4WkCsx8cqKTndfP/8zfR1SnuyOzVLK2XD/WYqZev7zQ8pn38Dqr3I8 18 | 9g== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /test/certs/agent4-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDGzCCAoSgAwIBAgIUYTTl6JLRxN9KUV+UuDspQoth1VIwDQYJKoZIhvcNAQEL 3 | BQAwejELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjEPMA0G 4 | A1UECgwGSm95ZW50MRAwDgYDVQQLDAdOb2RlLmpzMQwwCgYDVQQDDANjYTIxIDAe 5 | BgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMB4XDTIyMDExODE2NDAwMloX 6 | DTQ5MDYwNDE2NDAwMlowfTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYD 7 | VQQHDAJTRjEPMA0GA1UECgwGSm95ZW50MRAwDgYDVQQLDAdOb2RlLmpzMQ8wDQYD 8 | VQQDDAZhZ2VudDQxIDAeBgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMIIB 9 | IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4qJBL0cGPeKfujOqlQqck7hc 10 | 0EgvxtctZo/Cwp0oxz90KFgxl3n4cJiyfJfUbGnbvRJtId/wNIzlSanXd9x2Z6jJ 11 | kUrL7EZI4vnZBN8gXGvG2GV2ON19PC2/Mv8dDx875F8r8iH6XPQJR8RulvcK/Mfz 12 | wTuCHLnos85e/KLTGAUcan+Hm/Nev+Y+uXJBkUA8WVhWAAMbBM6wpvhu1uXQojF1 13 | KHZxQWsxBXBqpFP3prOwQ9EzwlVp3n8Pjd/M6CEo///uCvriZYlZjWRHnqOs9iWr 14 | JyYKybkZ5gk3RQWskcykrceKTj0p+N1EciyckviOvje6OLA2qmNSuTlMcsV1mQID 15 | AQABoxcwFTATBgNVHSUEDDAKBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOBgQC0 16 | D4G2sIR1oQYePQjCeF5fweQ3JIFbA/DFA22jfwNd/idmKs6+SblDRb69CvniN5Jy 17 | vm/qlAXHSCkKtXL2eHVyJVxE3LC31Li+i2HDgL3pH42ryBMSrjyhbAO0MHFiSkJS 18 | /Sr9ft/nLPnB1zUZL/KJcREhA5QWR0TipfJ+5bJOUA== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /.github/workflows/libressl.yml: -------------------------------------------------------------------------------- 1 | name: LibreSSL 2 | 3 | on: 4 | push: 5 | branches: [ "master", "ci" ] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [ "master" ] 9 | 10 | jobs: 11 | build: 12 | runs-on: macos-15-intel 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | luarocks_version: [3.12.0] 17 | lua_version: [luajit2.1] 18 | openssl_version: 19 | - libressl-3.8.4 20 | - libressl-3.9.2 21 | - libressl-4.1.2 22 | - libressl-4.2.1 23 | env: 24 | MACOSX_DEPLOYMENT_TARGET: 10.12 25 | LUAROCKS: ${{ matrix.luarocks_version }} 26 | LUA: ${{ matrix.lua_version }} 27 | SSL: ${{ matrix.openssl_version }} 28 | 29 | steps: 30 | - uses: actions/checkout@v4 31 | with: 32 | submodules: recursive 33 | 34 | - name: Setup 35 | run: 36 | .github/shell/setup_lua.sh && .github/shell/setup_ssl.sh 37 | 38 | - name: Build 39 | run: 40 | .github/shell/build.sh 41 | 42 | - name: Test 43 | run: 44 | PKG_CONFIG_PATH=$HOME/.usr/lib64/pkgconfig:$HOME/.usr/lib/pkgconfig PATH=$HOME/.usr/bin:$PATH LD_LIBRARY_PATH=$HOME/.usr/lib64:$HOME/.usr/lib make test 45 | -------------------------------------------------------------------------------- /test/dh.lua: -------------------------------------------------------------------------------- 1 | local openssl = require("openssl") 2 | local helper = require("helper") 3 | local dh = openssl.dh 4 | local pkey = openssl.pkey 5 | local unpack = table.unpack or unpack 6 | 7 | TestDH = {} 8 | function TestDH:testDH() 9 | local bits = 1024 10 | 11 | local p = dh.generate_parameters(bits) 12 | local k = p:generate_key() 13 | 14 | assert(k:check()) 15 | 16 | local t = k:parse() 17 | assert(t.bits == bits) 18 | assert(t.size == bits / 8) 19 | assert(t.g) 20 | assert(t.p) 21 | assert(t.pub_key) 22 | assert(t.priv_key) 23 | assert(k:check(t.pub_key)) 24 | 25 | dh = assert(pkey.new("dh", bits)) 26 | 27 | local k1 = pkey.get_public(dh) 28 | assert(not k1:is_private()) 29 | local t = dh:parse() 30 | assert(t.bits == bits) 31 | assert(t.type == "DH") 32 | assert(t.size) 33 | 34 | local r = t.dh 35 | t = r:parse() 36 | 37 | t.alg = "dh" 38 | local r2 = pkey.new(t) 39 | assert(r2:is_private()) 40 | r2 = openssl.pkey.new(r) 41 | assert(r2:is_private()) 42 | 43 | local pem = assert(dh:export("pem")) 44 | assert(openssl.pkey.read(pem, true)) 45 | pem = assert(dh:get_public():export("pem")) 46 | assert(openssl.pkey.read(pem, false)) 47 | t = openssl.dh.problems(0xFF) 48 | assert(#t == 7 or #t == 4) 49 | t = openssl.dh.problems(0xF, true) 50 | assert(#t == 3 or #t == 2) 51 | end 52 | -------------------------------------------------------------------------------- /test/certs/agent2-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDgTCCAmkCFF8mikbMTlIMq5Xv3yE4fi9RCJ9NMA0GCSqGSIb3DQEBCwUAMH0x 3 | CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDzANBgNVBAoM 4 | BkpveWVudDEQMA4GA1UECwwHTm9kZS5qczEPMA0GA1UEAwwGYWdlbnQyMSAwHgYJ 5 | KoZIhvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzAeFw0yMjAxMTgxNjQwMDJaFw00 6 | OTA2MDQxNjQwMDJaMH0xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UE 7 | BwwCU0YxDzANBgNVBAoMBkpveWVudDEQMA4GA1UECwwHTm9kZS5qczEPMA0GA1UE 8 | AwwGYWdlbnQyMSAwHgYJKoZIhvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzCCASIw 9 | DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO0cLNlgZ9vMbmkNYwhYiD6OwGtL 10 | +yt1/QGLBX2QRW2eRqyaUzfC/UG7oV4tkXyppzvFFGgsk/6fA+DM333WP/YcSRoh 11 | 6MR61kWalSFHpEI8bZHjDmkeRmyCkFjiqY6sRW7o0QJpadmWBBYtyo02gHRuRcgt 12 | dT/sUhDOvU53c2HsrOId3a7+Vpyxy0+CoR5FRGz0PLV3VKq/y45xUymNqVtwL3p/ 13 | 9AD8memm0rZ0RhhQHHq8P5ORWnXJ0oU1Cy3I00CU7snIAP5L5u8tOib/HeFCLTX6 14 | 9RAO2Ug8l/T6enDH3YALOm4T4LrXl2w9JFfVo36JgR8TCMB//nN3G42zHbMCAwEA 15 | ATANBgkqhkiG9w0BAQsFAAOCAQEAGSpTjvwr6ImymqhT8eBoOtzSmLZU6+jDCTGv 16 | FJOCVTgYm0MHSPqukyHm6NGuJoZs6ylMx5Z2qtkipNsEGkMQtjahsN7ngTY3dwGf 17 | anYuxpUUCbHnOgHrFmJfFHn/Wzq4LcbedmVlEVjDlNINLj0hhi16YuL6nGH8qDD+ 18 | nSZHD97CCYaknRh9500ivnzhM5UlmmKdNMEiMRJBvamgmXxQ7IW0rkEk1oeM3kfO 19 | dB2mNbZlrNJae7OQftnuRafuCKi5teEczW7vRlNTpl1NjOF30oK8e2CkZGxrFQ6F 20 | oT+dYX7y5pdx3IdDxZxuJdVnzf2KJpFZOnwl43sDsA6zwBm5DQ== 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /Makefile.win: -------------------------------------------------------------------------------- 1 | T= openssl 2 | 3 | include config.win 4 | 5 | OBJS= \ 6 | deps\auxiliar\auxiliar.obj src\asn1.obj src\bio.obj src\cipher.obj src\cms.obj \ 7 | src\compat.obj src\crl.obj src\csr.obj src\dh.obj src\digest.obj src\dsa.obj \ 8 | src\ec.obj src\engine.obj src\hmac.obj src\lbn.obj src\lhash.obj src\misc.obj \ 9 | src\ocsp.obj src\openssl.obj src\ots.obj src\pkcs12.obj src\pkcs7.obj \ 10 | src\pkey.obj src\rsa.obj src\ssl.obj src\th-lock.obj src\util.obj src\x509.obj \ 11 | src\xattrs.obj src\xexts.obj src\xname.obj src\xstore.obj src\xalgor.obj \ 12 | src\callback.obj src\srp.obj src\kdf.obj src\param.obj src\mac.obj \ 13 | deps\auxiliar\subsidiar.obj 14 | 15 | 16 | lib: src\$T.dll 17 | 18 | .c.obj: 19 | $(CC) /nologo /c /I"deps/lua-compat/c-api" /I"deps/auxiliar" /DLUA_BUILD_AS_DLL /DLUA_LIB /Fo$@ $(CFLAGS) $< 20 | 21 | src\$T.dll: $(OBJS) 22 | link /DLL /out:src\$T.dll $(OBJS) "$(LUA_LIB)" "$(OPENSSL_LIB)" \ 23 | crypt32.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib 24 | IF EXIST src\$T.dll.manifest mt -manifest src\$T.dll.manifest -outputresource:src\$T.dll;2 25 | 26 | install: src\$T.dll 27 | IF NOT EXIST "$(LUA_LIBDIR)" mkdir "$(LUA_LIBDIR)" 28 | copy src\$T.dll "$(LUA_LIBDIR)" 29 | 30 | clean: 31 | del src\$T.dll $(OBJS) src\$T.lib src\$T.exp 32 | IF EXIST src\$T.dll.manifest del src\$T.dll.manifest 33 | -------------------------------------------------------------------------------- /test/8.ssl_options.lua: -------------------------------------------------------------------------------- 1 | -- Testcase 2 | local lu = require("luaunit") 3 | local openssl = require("openssl") 4 | local ssl = openssl.ssl 5 | local helper = require("helper") 6 | 7 | local proto = helper.sslProtocol() 8 | 9 | local SET = function(t) 10 | local s = {} 11 | for _, k in ipairs(t) do 12 | s[k] = true 13 | end 14 | return s 15 | end 16 | local libressl = helper.libressl 17 | 18 | TestSSLOptions = {} 19 | function TestSSLOptions:setUp() 20 | self.ctx = assert(ssl.ctx_new(proto)) 21 | end 22 | 23 | function TestSSLOptions:testSet() 24 | local t, e = self.ctx:options() 25 | assert(type(t) == "table", e or type(t)) 26 | t = SET(t) 27 | lu.assertIsTable(t) 28 | lu.assertEquals(0, #t) 29 | 30 | t = self.ctx:options(ssl.no_sslv3, "no_ticket") 31 | t = SET(t) 32 | lu.assertIsTable(t) 33 | assert(libressl or t.no_sslv3) 34 | assert(t.no_ticket) 35 | 36 | assert(not pcall(self.ctx.options, self.ctx, true, nil)) 37 | lu.assertIsTable(t) 38 | assert(libressl or t.no_sslv3) 39 | assert(t.no_ticket) 40 | end 41 | 42 | function TestSSLOptions:testClear() 43 | self.ctx:options(true, ssl.no_sslv3, "no_ticket") 44 | 45 | local t = SET(assert(self.ctx:options())) 46 | lu.assertIsTable(t) 47 | assert(not t.no_sslv3) 48 | assert(not t.no_ticket) 49 | end 50 | 51 | function TestSSLOptions:testCiphersuites() 52 | if helper.supportTLSv1_3() then 53 | local ctx = openssl.ssl.ctx_new("TLS", "TLS_AES_128_GCM_SHA256:ECDHE-RSA-AES128-SHA256") 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /test/certs/alice.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID8DCCAtigAwIBAgIJALmw0zKhqlY1MA0GCSqGSIb3DQEBBQUAMFgxDjAMBgNV 3 | BAMTBWFsaWNlMUYwRAYDVR0RFD11bmlmb3JtUmVzb3VyY2VJZGVudGlmaWVyOmh0 4 | dHA6Ly9sb2NhbGhvc3Q6ODAwMC9hbGljZS5mb2FmI21lMB4XDTExMDgyNDA1NTUx 5 | NFoXDTExMDkyMzA1NTUxNFowWDEOMAwGA1UEAxMFYWxpY2UxRjBEBgNVHREUPXVu 6 | aWZvcm1SZXNvdXJjZUlkZW50aWZpZXI6aHR0cDovL2xvY2FsaG9zdDo4MDAwL2Fs 7 | aWNlLmZvYWYjbWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDP4tdk 8 | 6NxAImrf5kpQVpuPvWij97H9ewFwWq0FOGONPD0JURXB89BCnhfC0+IHbTi+dhfB 9 | DX9HY11NCoJm7juXv0uywv+7Zrlj37Q0RTedADmp237UUATRzmh7E+KZc6tHcZZ8 10 | rPs+ZnY7TXXsh4JRRc8blTy6aEN7/iYMXhk0mIpzjTha2Gq5OqBLustBkeFnoPQS 11 | cac6TOWbEkxg80dI5jX/qK901RRwLztrA0QDeWB+HLbkjIErdAlz5pgo1Nu3vQt6 12 | vLdu7bBYsUa2Y2IaVBNLgmzEiZGwQJMjvbs5tLv8VYBCypb4I4vRJrkG4wWsUimM 13 | +sR7SKHu9FFt2ZdHAgMBAAGjgbwwgbkwHQYDVR0OBBYEFA51eHepg7Tp5bi6Ao5F 14 | B01/5+GoMIGJBgNVHSMEgYEwf4AUDnV4d6mDtOnluLoCjkUHTX/n4aihXKRaMFgx 15 | DjAMBgNVBAMTBWFsaWNlMUYwRAYDVR0RFD11bmlmb3JtUmVzb3VyY2VJZGVudGlm 16 | aWVyOmh0dHA6Ly9sb2NhbGhvc3Q6ODAwMC9hbGljZS5mb2FmI21lggkAubDTMqGq 17 | VjUwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAreudH4Y7R9Vl2GJo 18 | 2xRUEwZiMj/ogomZ7B+IZtcuMIR8X2mzQ30xmPKaCy/fjbueqBroIDdxFeQ4eWZf 19 | MD3AK/q5lJXwSInDjnn7jE9gNgLdQeCnajV0/QH+eDxIe/Alvx+RuvrDiNOudEs4 20 | vhqv5zEaL6VEXoWVb4/cghDbynQucSpyOMmGGPYYw2zmg0nNXdQauYWDUZIaDwQ6 21 | tM/pi2ewYubHPZdwJv5jvxTN3Z7RuuGHM+aLAZSAqSgAi0ml8PYYd2eRzXMaEI0c 22 | eajcEvVa405aYT6dxuF1qqRDYx14As/R7O5RKCpz7wsxD6ICD/Ynv3GCUGxANQim 23 | bcCjpg== 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /test/memleaks.lua: -------------------------------------------------------------------------------- 1 | local openssl = require("openssl") 2 | local lu = require("luaunit") 3 | 4 | openssl.rand_load() 5 | 6 | dofile("0.engine.lua") 7 | dofile("0.misc.lua") 8 | dofile("1.asn1.lua") 9 | dofile("2.asn1.lua") 10 | dofile("1.x509_name.lua") 11 | dofile("1.x509_extension.lua") 12 | dofile("1.x509_attr.lua") 13 | dofile("2.digest.lua") 14 | dofile("2.hmac.lua") 15 | dofile("3.cipher.lua") 16 | dofile("4.pkey.lua") 17 | dofile("rsa.lua") 18 | dofile("ec.lua") 19 | 20 | dofile("5.x509_req.lua") 21 | dofile("5.x509_crl.lua") 22 | dofile("5.x509.lua") 23 | dofile("5.ts.lua") 24 | dofile("6.pkcs7.lua") 25 | dofile("7.pkcs12.lua") 26 | dofile("8.ssl_options.lua") 27 | 28 | collectgarbage() 29 | collectgarbage() 30 | 31 | local mem_start, mem_current, mem_previos 32 | mem_start = collectgarbage("count") 33 | mem_previos = mem_start 34 | 35 | local count = 1000 36 | local step = 10 37 | assert(step < count / 9, string.format("step should be %d", math.floor(count / 10))) 38 | 39 | local runner = lu.LuaUnit.new() 40 | runner:setOutputType("nil") 41 | 42 | for _ = 1, count do 43 | runner:runSuite() 44 | collectgarbage() 45 | collectgarbage() 46 | mem_current = collectgarbage("count") 47 | if _ % step == 0 then 48 | print(string.format("** %d\tincrement %.04f%%", _, (mem_current - mem_previos) / mem_previos)) 49 | mem_previos = mem_current 50 | end 51 | end 52 | 53 | collectgarbage() 54 | collectgarbage() 55 | mem_current = collectgarbage("count") 56 | print( 57 | string.format("****From %d to %d, increment=%.04f%%", mem_start, mem_current, (mem_current - mem_start) / mem_start) 58 | ) 59 | -------------------------------------------------------------------------------- /test/7.pkcs12.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local csr = openssl.x509.req 4 | local helper = require("helper") 5 | 6 | TestPKCS12 = {} 7 | function TestPKCS12:setUp() 8 | self.alg = "sha1" 9 | self.dn = openssl.x509.name.new({ { commonName = "DEMO" }, { C = "CN" } }) 10 | 11 | self.ca = helper.get_ca() 12 | self.digest = "sha1WithRSAEncryption" 13 | end 14 | 15 | function TestPKCS12:testNew() 16 | local extensions = { 17 | { 18 | object = "nsCertType", 19 | value = "email", 20 | -- critical = true 21 | }, 22 | { object = "extendedKeyUsage", value = "emailProtection" }, 23 | } 24 | 25 | local cert, pkey = helper.sign(self.dn, extensions) 26 | 27 | local ss = assert(openssl.pkcs12.export(cert, pkey, "secret", "USER")) 28 | local tt = assert(openssl.pkcs12.read(ss, "secret")) 29 | lu.assertIsTable(tt) 30 | lu.assertStrContains(tostring(tt.cert), "openssl.x509") 31 | lu.assertStrContains(tostring(tt.pkey), "openssl.evp_pkey") 32 | 33 | ss = assert(openssl.pkcs12.export(cert, pkey, "secret", "USER", { self.ca.cacert })) 34 | tt = assert(openssl.pkcs12.read(ss, "secret")) 35 | lu.assertIsTable(tt) 36 | lu.assertStrContains(tostring(tt.cert), "openssl.x509") 37 | lu.assertStrContains(tostring(tt.pkey), "openssl.evp_pkey") 38 | 39 | ss = assert(openssl.pkcs12.export(cert, pkey, "secret", nil, { self.ca.cacert })) 40 | tt = assert(openssl.pkcs12.read(ss, "secret")) 41 | lu.assertIsTable(tt) 42 | lu.assertStrContains(tostring(tt.cert), "openssl.x509") 43 | lu.assertStrContains(tostring(tt.pkey), "openssl.evp_pkey") 44 | end 45 | -------------------------------------------------------------------------------- /src/util.c: -------------------------------------------------------------------------------- 1 | /*** 2 | util module with internal utility functions for lua-openssl 3 | 4 | This module provides internal utility functions for value management, 5 | memory handling, and registry operations used throughout the 6 | lua-openssl library. 7 | */ 8 | #include "private.h" 9 | 10 | int 11 | openssl_newvalue(lua_State *L, const void *p) 12 | { 13 | lua_rawgetp(L, LUA_REGISTRYINDEX, p); 14 | if (lua_isnil(L, -1)) { 15 | lua_newtable(L); 16 | lua_rawsetp(L, LUA_REGISTRYINDEX, p); 17 | } 18 | lua_pop(L, 1); 19 | return 0; 20 | } 21 | 22 | int 23 | openssl_freevalue(lua_State *L, const void *p) 24 | { 25 | lua_pushnil(L); 26 | lua_rawsetp(L, LUA_REGISTRYINDEX, p); 27 | 28 | return 0; 29 | } 30 | 31 | int 32 | openssl_valueset(lua_State *L, const void *p, const char *field) 33 | { 34 | lua_rawgetp(L, LUA_REGISTRYINDEX, p); 35 | lua_pushstring(L, field); 36 | lua_pushvalue(L, -3); 37 | lua_rawset(L, -3); 38 | lua_pop(L, 2); 39 | return 0; 40 | } 41 | 42 | int 43 | openssl_valueget(lua_State *L, const void *p, const char *field) 44 | { 45 | lua_rawgetp(L, LUA_REGISTRYINDEX, p); 46 | if (!lua_isnil(L, -1)) { 47 | lua_pushstring(L, field); 48 | lua_rawget(L, -2); 49 | lua_remove(L, -2); 50 | } 51 | return lua_type(L, -1); 52 | } 53 | 54 | int 55 | openssl_valueseti(lua_State *L, const void *p, int i) 56 | { 57 | lua_rawgetp(L, LUA_REGISTRYINDEX, p); 58 | lua_pushvalue(L, -2); 59 | lua_rawseti(L, -2, i); 60 | lua_pop(L, 2); 61 | return 0; 62 | } 63 | 64 | int 65 | openssl_valuegeti(lua_State *L, const void *p, int i) 66 | { 67 | lua_rawgetp(L, LUA_REGISTRYINDEX, p); 68 | if (!lua_isnil(L, -1)) { 69 | lua_rawgeti(L, -1, i); 70 | lua_remove(L, -2); 71 | } 72 | return lua_type(L, -1); 73 | } 74 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Please provide a clear and concise description of your changes. 4 | 5 | ## Related Issue 6 | 7 | Fixes #(issue number) 8 | 9 | ## Type of Change 10 | 11 | - [ ] Bug fix 12 | - [ ] New feature 13 | - [ ] Documentation update 14 | - [ ] Code review/analysis 15 | - [ ] Performance improvement 16 | - [ ] Code refactoring 17 | - [ ] Other (please describe) 18 | 19 | ## Changes Made 20 | 21 | Please list the specific changes made in this PR: 22 | 23 | - 24 | - 25 | - 26 | 27 | ## Testing 28 | 29 | Please describe the tests you ran to verify your changes: 30 | 31 | - [ ] Existing tests pass 32 | - [ ] Added new tests 33 | - [ ] Manual testing performed 34 | 35 | ## Checklist 36 | 37 | - [ ] My code follows the style guidelines of this project (clang-format) 38 | - [ ] I have performed a self-review of my own code 39 | - [ ] I have commented my code, particularly in hard-to-understand areas 40 | - [ ] I have made corresponding changes to the documentation 41 | - [ ] My changes generate no new warnings 42 | - [ ] I have added tests that prove my fix is effective or that my feature works 43 | - [ ] New and existing unit tests pass locally with my changes 44 | - [ ] Any dependent changes have been merged and published 45 | 46 | ## OpenSSL Compatibility 47 | 48 | Please indicate which OpenSSL versions were tested (if applicable): 49 | 50 | - [ ] OpenSSL 1.0.2u 51 | - [ ] OpenSSL 1.1.1w 52 | - [ ] OpenSSL 3.0.x 53 | - [ ] OpenSSL 3.5+ 54 | - [ ] LibreSSL 3.3.6+ 55 | 56 | ## Additional Notes 57 | 58 | Add any other context about the pull request here. 59 | 60 | --- 61 | 62 | **For development roadmap and planning, see:** 63 | - [ROADMAP.md](../ROADMAP.md) (English) 64 | - [ROADMAP_CN.md](../ROADMAP_CN.md) (Chinese) 65 | -------------------------------------------------------------------------------- /test/9.srp.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local srp = openssl.srp 4 | if srp == nil then 5 | print("Skip test srp") 6 | return 7 | end 8 | 9 | local GN = assert(srp.get_default_gN("1024")) 10 | 11 | TestSRP = {} 12 | function TestSRP:setUp() 13 | self.user = "zhaozg" 14 | self.pass = "password" 15 | end 16 | 17 | function TestSRP:tearDown() end 18 | 19 | function TestSRP:test_1_SRV_CreateVerifier() 20 | self.salt, self.verifier = GN:create_verifier(self.user, self.pass) 21 | assert(self.salt) 22 | assert(self.verifier) 23 | end 24 | 25 | function TestSRP:test_2_SRV_Calc_b() 26 | self.Bpub, self.Brnd = GN:calc_b(self.verifier) 27 | assert(self.Bpub) 28 | assert(self.Brnd) 29 | end 30 | 31 | function TestSRP:test_3_CLI_Calc_a() 32 | self.Apub, self.Arnd = GN:calc_a() 33 | assert(self.Apub) 34 | assert(self.Arnd) 35 | end 36 | 37 | function TestSRP:test_4_Calc_u() 38 | self.u = assert(GN:calc_u(self.Apub, self.Bpub)) 39 | end 40 | 41 | function TestSRP:test_5_cli_key() 42 | local x = assert(GN:calc_x(self.salt, self.user, self.pass)) 43 | self.Kclient = assert(GN:calc_client_key(self.Bpub, x, self.Arnd, self.u)) 44 | end 45 | 46 | function TestSRP:test_6_srv_key() 47 | local Kserver = assert(GN:calc_server_key(self.Apub, self.verifier, self.u, self.Brnd)) 48 | assert(Kserver == self.Kclient) 49 | end 50 | 51 | function TestSRP:test_7_cli_key() 52 | local x = assert(srp.calc_x(self.salt, self.user, self.pass .. "1")) 53 | self.Kclient = assert(GN:calc_client_key(self.Bpub, x, self.Arnd, self.u)) 54 | end 55 | 56 | function TestSRP:test_8_srv_key() 57 | local Kserver = assert(GN:calc_server_key(self.Apub, self.verifier, self.u, self.Brnd)) 58 | assert(Kserver ~= self.Kclient) 59 | end 60 | -------------------------------------------------------------------------------- /test/certs/agent.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAz+LXZOjcQCJq3+ZKUFabj71oo/ex/XsBcFqtBThjjTw9CVEV 3 | wfPQQp4XwtPiB204vnYXwQ1/R2NdTQqCZu47l79LssL/u2a5Y9+0NEU3nQA5qdt+ 4 | 1FAE0c5oexPimXOrR3GWfKz7PmZ2O0117IeCUUXPG5U8umhDe/4mDF4ZNJiKc404 5 | WthquTqgS7rLQZHhZ6D0EnGnOkzlmxJMYPNHSOY1/6ivdNUUcC87awNEA3lgfhy2 6 | 5IyBK3QJc+aYKNTbt70Lery3bu2wWLFGtmNiGlQTS4JsxImRsECTI727ObS7/FWA 7 | QsqW+COL0Sa5BuMFrFIpjPrEe0ih7vRRbdmXRwIDAQABAoIBAGe4+9VqZfJN+dsq 8 | 8Osyuz01uQ8OmC0sAWTIqUlQgENIyf9rCJsUBlYmwR5BT6Z69XP6QhHdpSK+TiAR 9 | XUz0EqG9HYzcxHIBaACP7j6iRoQ8R4kbbiWKo0z3WqQGIOqFjvD/mKEuQdE5mEYw 10 | eOUCG6BnX1WY2Yr8WKd2AA/tp0/Y4d8z04u9eodMpSTbHTzYMJb5SbBN1vo6FY7q 11 | 8zSuO0BMzXlAxUsCwHsk1GQHFr8Oh3zIR7bQGtMBouI+6Lhh7sjFYsfxJboqMTBV 12 | IKaA216M6ggHG7MU1/jeKcMGDmEfqQLQoyWp29rMK6TklUgipME2L3UD7vTyAVzz 13 | xbVOpZkCgYEA8CXW4sZBBrSSrLR5SB+Ubu9qNTggLowOsC/kVKB2WJ4+xooc5HQo 14 | mFhq1v/WxPQoWIxdYsfg2odlL+JclK5Qcy6vXmRSdAQ5lK9gBDKxZSYc3NwAw2HA 15 | zyHCTK+I0n8PBYQ+yGcrxu0WqTGnlLW+Otk4CejO34WlgHwbH9bbY5UCgYEA3ZvT 16 | C4+OoMHXlmICSt29zUrYiL33IWsR3/MaONxTEDuvgkOSXXQOl/8Ebd6Nu+3WbsSN 17 | bjiPC/JyL1YCVmijdvFpl4gjtgvfJifs4G+QHvO6YfsYoVANk4u6g6rUuBIOwNK4 18 | RwYxwDc0oysp+g7tPxoSgDHReEVKJNzGBe9NGGsCgYEA4O4QP4gCEA3B9BF2J5+s 19 | n9uPVxmiyvZUK6Iv8zP4pThTBBMIzNIf09G9AHPQ7djikU2nioY8jXKTzC3xGTHM 20 | GJZ5m6fLsu7iH+nDvSreDSeNkTBfZqGAvoGYQ8uGE+L+ZuRfCcXYsxIOT5s6o4c3 21 | Dle2rVFpsuKzCY00urW796ECgYBn3go75+xEwrYGQSer6WR1nTgCV29GVYXKPooy 22 | zmmMOT1Yw80NSkEw0pFD4cTyqVYREsTrPU0mn1sPfrOXxnGfZSVFpcR/Je9QVfQ7 23 | eW7GYxwfom335aqHVj10SxRqteP+UoWWnHujCPz94VRKZMakBddYCIGSan+G6YdS 24 | 7sdmwwKBgBc2qj0wvGXDF2kCLwSGfWoMf8CS1+5fIiUIdT1e/+7MfDdbmLMIFVjF 25 | QKS3zVViXCbrG5SY6wS9hxoc57f6E2A8vcaX6zy2xkZlGHQCpWRtEM5R01OWJQaH 26 | HsHMmQZGUQVoDm1oRkDhrTFK4K3ukc3rAxzeTZ96utOQN8/KJsTv 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /test/certs/agent4-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA4qJBL0cGPeKfujOqlQqck7hc0EgvxtctZo/Cwp0oxz90KFgx 3 | l3n4cJiyfJfUbGnbvRJtId/wNIzlSanXd9x2Z6jJkUrL7EZI4vnZBN8gXGvG2GV2 4 | ON19PC2/Mv8dDx875F8r8iH6XPQJR8RulvcK/MfzwTuCHLnos85e/KLTGAUcan+H 5 | m/Nev+Y+uXJBkUA8WVhWAAMbBM6wpvhu1uXQojF1KHZxQWsxBXBqpFP3prOwQ9Ez 6 | wlVp3n8Pjd/M6CEo///uCvriZYlZjWRHnqOs9iWrJyYKybkZ5gk3RQWskcykrceK 7 | Tj0p+N1EciyckviOvje6OLA2qmNSuTlMcsV1mQIDAQABAoIBABO6fiQocaGnfbIO 8 | 11WcE99EGEhFUGtlxdz8vL6GQct+eZUdgEuoYXkjwb3Y1bQOTwOZfAiL3vQkI72S 9 | 3F/hwCjr54gPU8sgny2rBDpJVh7VfvzNcEoo9cLsVI2S6ausU2Fg64lrbcjzsW8e 10 | 6WWY4cr5eP2kOYJYqKomV9x0LB4WAeBzzIEJ+ET8tm1aQQUGOCMo0Dy3ZyuSwAMI 11 | +Ioe2f3dosXm9PjghAw45dxYKVzQgP9gPsRSI2FjyEWckj7cG4OCGAbxgiR+qwiL 12 | FAuZ7GUpFHalE6bwyZnoKplUkWjMTVnu1Byt2YX7g5dL883R4c/PwhQjg02iYScP 13 | FXwTTVECgYEA8imgKK+Ln4dbvqWOGDmnbOFWRjvPMUvKYqBuIYhxPIH8tg475qPC 14 | CpSzUVwVVkbYZwZMlGrKvoU6D7A0xl7NYuZINMNpWyDF5U9eztRzRLgX8834DBBQ 15 | YAgXMx+IDC3JorohC6yIy1OZe8ntm+NHF79oyk5b6A7QiLHrG3rjUS0CgYEA75V4 16 | +QY7FaXlqdn5gRnizHH/TnmYY3bJuCjeabT48t1/KXjVOVvD8VKWJTUgtpm0KlQI 17 | itrBHRPu/kcU4xzDiRctcj566JkLF6jy0rrBE+Cm1ugH4nQbBtZ2R2N/Y2RWu9mG 18 | uP0RSt04OcpTPGCkJ3MMawGi/ow9uD07aPZpgZ0CgYAClELqbAQ2rMBjZWwAAg0w 19 | ca3zjYuFYONE7aR+ou9hz5ibb8dfi3rzleXbBfoMMzD21/BU3FZQdSbLJ/tH6ZaS 20 | aRV3ymUC3XR+HrxJw6V+o99Nb3Im3r2caDmnB7zxNEOjggv8DdhfIgLOeLYZJPCK 21 | 5jT9gpwj+pRqAEsavdJR+QKBgAXOJWRDVmMr5ei7s2QBcJFrobgREjQ2yKSBuQHu 22 | tKmN3Grw1pnRM2pBignUw7oo90ifSKW0r0E5Hm1i44qtQ7+qpBtEkE3ah35HRbr9 23 | c3g71U8XyDkgfxcnUy5fptKNt9xNZQpOd4DM43PjBylLXi7mhsKBA6YPV9+C/FGK 24 | xvuxAoGBAPAfQye6yZqlflNQ8K3y3oJ2i3A5gwtCw1Y6+R46o7Uk+t3DwZE+9lHZ 25 | AOsTignO07r3Cc64Kj9XnQIIvNrLxhitMhSWkAY9fvXOyTWkdEv27YfWAx0s0UF8 26 | dgAvZ/asDuF8UUuYgkqHBEsrChxfSYWD79IIRWhuSllfbWeJIABG 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /test/certs/agent1-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEApfPLPMcUlFH4HbZYy3iM5zxoPkOnnD1qeaYW+MTV+eoa9e2P 3 | j5z99tqiV0oTWC2OeQJOeRHioxDo5vPriEdzp4uw8gxcxpuGT5H+Ccs1I4gst4Vn 4 | VSPoXHuovqlngQUH/Ods9YmEp2ESnJH5hZ8ETEBeHtsovFFdKPHxSdYjlNzTgj1Q 5 | nVsbp0tr/WkvxR4oJUR9KqD/L/gU/oBF/0/DDPM2DBlQU+VQe9gCU5b0Q8kY5HK6 6 | AiiX+CJZvmxrsWGj0iu8BnyZPTpNk2fYCuo23sSLVzFOqC6MbEXwj8RDGMhfLDB4 7 | z8/GzMUrpoml0GcpNEo0GDBhRlHwugq5J7+ZOQIDAQABAoIBAHh7UuZBMrOr/xKz 8 | PCwczU9kD9qEi79m51KCPtNFNIRIbmJ1onCFbew2Nv5gjULLcFByWD6VuZDhyfVC 9 | yZEbLuBJDqHsT77xUsWaHHFH0sCFMNHcTHUHqL7cGFqz6q1E1dPKwNRSjrhmRXje 10 | keVs2VXytWJ5gk2WVKhRXvhYO2Tq8lB14U/C14pwskzyYtMcnq5pF0ChJrlBysnb 11 | SMtd0yYZFxIU5PN6IOxP/Ef+wDLGy3NC7P4+mNfZzLZC7xZml7hNaYiLfFUewOVh 12 | qgeDTem5l0W5bBCg0ba1Qib2OZzbR8NKRc0RWGoQcfNpy5+bU3x3wIjcY0DR9zhQ 13 | kqAEKvECgYEA05adL8+rS+HAMV3Dt24Dl3OpcYa6xQ5e/6l7gFOUdQwQQvH6SWVC 14 | QfluDDNfklHNCA7xO2LCpCrjxkR/VDc2Nzpbbuz06sCOXf2wEuAOYG23svc1KCET 15 | wNCAkXWM5yz4vinjlW+D7eFpL6ZiBqTymn7hN7zORR0LavSTVkHHf4MCgYEAyMj/ 16 | Ae6+QaLDe4urq2cu9UUHuIkwVF/sAYi5WJW48f+zmIAXSNRXqgiCqkMbruYAo0yd 17 | iTR7HPAd5zd4HUJl4xjfdsxTjSsRAyAyJTvVB3ZeYqe8AaDtBxjLtzt8l1NpVU2z 18 | hODOf05wuy2cH6V9Gz8AiSt4mXmsfezaIiLyS5MCgYBXcd6inNPxd2ojvNmfHGN1 19 | m0KC/aiAujC+vn+hCGnJeePalwDWhne8pmY5up2b7hyrYOmHnohMqsEZ9sMcvfi1 20 | GHQjQuDxiAUOiULUei7W4WFTIGGipRDx1fnco9VI0Ug35z38S2sdy9PZ8ox+rHrr 21 | KNbRX0FsRNWsLUobEvJtGwKBgQCnKT+1OjDHsFyTZQr9XqBnrpro9b544Is6E7xL 22 | lgst3raFBk9cYPzDIOa4HbrUd8ScL9MQQdMlmnsq3rFvmrH8yd5xp1cANpSpR4q4 23 | GQIYfmHCPOd3a6UqvWgNGsd1rQoK7O/Cdu80affMvgI3Dq4DmwY1LS3wiK4lAKXy 24 | uamDZQKBgQC3LGXejkT0bfEFaioqYkWloZowMtH9gGa4e1CR309Nrt+wYLQXHEn0 25 | R6UmAEw7xVfGY2hrIbvqyrbk77YSOF7Prd8X+8WKE43HjyXISifOuq+MVuyW19VG 26 | ZzNgGXoaZU8We1cOQsF8kQ1G6ezNIqfjJ3DstJ4th5xTv0Wiwwu/qw== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /test/certs/agent2-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEA7Rws2WBn28xuaQ1jCFiIPo7Aa0v7K3X9AYsFfZBFbZ5GrJpT 3 | N8L9QbuhXi2RfKmnO8UUaCyT/p8D4MzffdY/9hxJGiHoxHrWRZqVIUekQjxtkeMO 4 | aR5GbIKQWOKpjqxFbujRAmlp2ZYEFi3KjTaAdG5FyC11P+xSEM69TndzYeys4h3d 5 | rv5WnLHLT4KhHkVEbPQ8tXdUqr/LjnFTKY2pW3Aven/0APyZ6abStnRGGFAcerw/ 6 | k5FadcnShTULLcjTQJTuycgA/kvm7y06Jv8d4UItNfr1EA7ZSDyX9Pp6cMfdgAs6 7 | bhPguteXbD0kV9WjfomBHxMIwH/+c3cbjbMdswIDAQABAoIBADFJlQ0OnCg1Y5IU 8 | xUw70v5mABuNrMVI/nGuq1KBhd0WdIx2e+vwbWKXlSCVilOGlIu5GNfaxFy+Qzkc 9 | fSyUN7F6CbwT5mXJPvcy/eLwGHXoR8J2l01EjNELhuPjIenVZ415edDthqJDK9BM 10 | bnlSJfuN3JWS1XeXMSvrPbCs5eApwwytUhZLYbEgnUYV19l8RDE7AodzW0/b/wTV 11 | ZQwKGulSCXyhFRzMLLTBxQ1Bs++9ghrPmwXNmp5AX63wYgSlEEJIxDgsB9bJ9WVD 12 | PmEGqt+iixUXEfrNwZENT8p4OSF79hdsADpZeraUYYQR9yIK/nzi019dm4J0IQtT 13 | 5ICGOSkCgYEA9oAIKGoR/XyIhL63TfQYE5pTrh4yeeZeaH2ojTk2Ke2MXqhKJaC2 14 | IN9Ri4WqKS7tWd2hl58tvDrhXjkrbUMvyYnrQptzi0VETuPOcu5LQzyzQ7MT/3eo 15 | 1vKovS/RjEAaIyL/7NM3+nwn12xgoVmImfwdODRbSCnR+LmJM14RaeUCgYEA9j+A 16 | QwD7dPv2auob9iOw8hr4u36Y+IxIAGl+CmhmQA40CpMPKAik2rPOlRnGM1wGoI6a 17 | MuSmDsufmZe/lAM7dPOVzNxpeATNQsg3HZVTgrq0tSoW6iJ8NskhXAFP39uIDvm6 18 | X6g+hG7F2OipzsfDz1BMrBibjFisfapaJpEcD7cCgYEAt/RcIizmOBGTn9zj1tzu 19 | itKE2E/Yw3fTxI7iFmI3tZp9Qra8ftAsmuONa13Y2tsWbhYj3Y8BBpO6VCK98dBN 20 | /U1bsF1qIOkUTPtcuhBzQj4uWbtulRureJ2mp2jkLJI57zbTXt1RzTCSWwWaJ081 21 | zhSDicooxPXQqJltdlQhErECgYAQTpw707DTSmxDIEXBwxNQtSCLqhKPQxrxjArg 22 | vZEn5Mjlel+ikw/3u7iOfyp09D8sGsVzYVjt2eYz0azKLHyffhIJgv8pB4hgR8n+ 23 | l4j0O1EEPklOMAJxzlf7M8sKVAtqkncZJpcdRgisGJxGKUx6SiMJsod6f9TMbZ+S 24 | tkFZeQKBgQCBfUhbfcGeKMzq++uwFXuQjqseWpd3oov2MLoeIjDVNYfFnfhZFbdZ 25 | QgWmE8yh4oEKbjJiAOYUq9RcCLB8UG6hysYkwCZXk8PbVsUHVpL7P8Phd1mepnaT 26 | +sN/JmWwiZEjll3Ygwp8u8rhTCvFi+YNP69yT3n/inL0tSnuXlUrkg== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /test/certs/agent3-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAy3v4wSahEpYARj6NnGlJHaiDEsE0OgyKBV4YnowQv/2myIsa 3 | Fd3cGHpy8KflQ9bfNI5SyH1olwODeARIR7bFL6VU6QePaAWYeskGuJ8dESTLibra 4 | SqnA7AW2Hhlf7j/5biQsBAFnY4cAO/FVC4npDQoszwcSy8LPI0+O0dve4d2hYD5f 5 | /gK2ULzFfiNrkQJZad9Kktwo5tsIUjzmN4QN5V9gw1nwviIizKH0e/pv+kubbEXm 6 | TZ0a0BK7NMGj2QUtX9Endj8gmFqup0XvJZfMZGES3cFxVaL7s62OyKw6JQWq/ghi 7 | zlqCLjSwSCJYp/fpIK1j8kDszxWbUYBgI7CltQIDAQABAoIBAQChIXJBwQ0bYpyl 8 | AzOv/89eJOpmF4f7z6Ibzf9AzTkWTw2bEEt/tUdsOsp5tvndVnE5dNoo2OXRb37T 9 | stBpuVk7+Xfbb5knjgbIdBdWaujhgnmKfuQM649RVtR30TAdwZsKlKomIdZ1AZo1 10 | 3Uyy7moVYVFKPxerMoBEPeOiWrGLuEHuUF0W17s4bQkH1McGLJLaaU9xQRh8Q0oa 11 | yf9FbHl+OVWZ4YnvEwth1aVGq+D21HLFfsBxoLHI5uM4FxAkF6fvO7rb3ujkOwmH 12 | y5tMReKoeFqkN5bnSSFwBoWl7aYtUmU/H7MB18ZAvuui1CrivcxzrzfsgXMyNd4u 13 | H/nAlSkBAoGBAPobM64sxh4wA0SQ7hw8EGk0EENv3iFA8Pl49Liq2VT14ZsGVqFp 14 | Sy7sviTXhDAReiLnuBWnyj1i0G0MHP7iCe0L8awpni6a+lXVoxhyvCaw7wAyCRoN 15 | sP2FfnNnSl/1zR+v2WD7X3sT7TzxSTZyYaOzahHFX5hG1oupgy6aWN5tAoGBANBH 16 | hEPWGzzE2iwYbn+KrTorfPlZ7ENARux8SR1paE+D3DqxQc0jXgYzd/YtUNcKnJ8G 17 | TXXNAWApYN6FfVZqsIbk2A1bGmP8A+UZCi2tSa1JO/4WdTzOefD0VKX0VAUREWI3 18 | Y4XIWeXK+Kjh9UhMCdMN3IpGK2edUIqk9Z36xDdpAoGBAJfA65GyXx+v+DuhSKjf 19 | FQIQchHJDdnVgqGMb8ig+a+gZZxfsy7LKbA2O4U1M2LLJ/WH7d1N6ttmWprf77QD 20 | yQwI5EGXGwCiTmTIdOZ/r4Q2dT4EHhut1Qdu+XPiZ3FkPmsMkvRScfPG+nqw2MBt 21 | lKr0UNapkMBfswwY9ZzQUD3dAoGAD569caT2B/mvbw0qBFCvKySly8GNsYF5kDTF 22 | +vmzw/rcol421B6p54cmoQTHAkmec2KynnoQd1jDFg0m2DtKH+O7vEyvzv3QgPb+ 23 | x2wukVtjr2uZwUSu6n44dvW682JTTm1e/mKHM2+kdG31ykVBm113w7r9eFjY+Hzk 24 | msN6wbkCgYBy4707uVy7//NFfqn6JhHX8DRZ2c0TRLBpSpWsyzOZTj9DgKD1Fk43 25 | YFD41nYPi7+18cvGIhVBDCvVEaI9OK2BB7jy2CW5qettSqHsJKZAFzPDtt4K4nFI 26 | Hf5zrxhxHvzeZoAVKv4sNw5KhO8gcabVHXf5+iqjXh2V+lILxDX7PA== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /test/8.bio_c.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local bio, ssl = openssl.bio, openssl.ssl 4 | local sslctx = require("sslctx") 5 | local host, port, loop 6 | 7 | local arg = arg 8 | 9 | host = arg[1] or "127.0.0.1" -- only ip 10 | port = arg[2] or "8383" 11 | loop = arg[3] and tonumber(arg[3]) or 100 12 | 13 | local _, _, opensslv = openssl.version(true) 14 | 15 | local params = sslctx.client 16 | 17 | local certstore = nil 18 | if opensslv > 0x10002000 then 19 | certstore = openssl.x509.store:new() 20 | local cas = require("root_ca") 21 | for i = 1, #cas do 22 | local cert = assert(openssl.x509.read(cas[i])) 23 | assert(certstore:add(cert)) 24 | end 25 | end 26 | local ctx = assert(sslctx.new(params)) 27 | if certstore then 28 | ctx:cert_store(certstore) 29 | end 30 | 31 | ctx:verify_mode(ssl.peer, function(_arg) 32 | --[[ 33 | --do some check 34 | for k,v in pairs(arg) do 35 | print(k,v) 36 | end 37 | --]] 38 | return true -- return false will fail ssh handshake 39 | end) 40 | 41 | print(string.format("CONNECT to %s:%s with %s", host, port, tostring(ctx))) 42 | 43 | local function mk_connection(_host, _port, i) 44 | local cli = assert(ctx:bio(_host .. ":" .. _port)) 45 | if cli then 46 | assert(cli:handshake()) 47 | ---[[ 48 | if i % 2 == 2 then 49 | assert(cli:handshake()) 50 | else 51 | assert(cli:connect()) 52 | end 53 | -- ]] 54 | local s = "aaa" 55 | io.write(".") 56 | io.flush() 57 | for _ = 1, 100 do 58 | assert(cli:write(s)) 59 | assert(cli:read()) 60 | end 61 | assert(cli:ssl()) 62 | cli:shutdown() 63 | cli:free() 64 | end 65 | openssl.errors() 66 | end 67 | 68 | for i = 1, loop do 69 | mk_connection(host, port, i) 70 | end 71 | print() 72 | print("SSL bio client done") 73 | collectgarbage() 74 | os.exit(0, true) 75 | -------------------------------------------------------------------------------- /test/1.x509_attr.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local attr = require("openssl").x509.attribute 4 | local asn1 = require("openssl").asn1 5 | 6 | TestX509attr = {} 7 | function TestX509attr:setUp() 8 | self.timeStamping = openssl.asn1.new_string("timeStamping", asn1.IA5STRING) 9 | self.cafalse = openssl.asn1.new_string("CA:FALSE", asn1.OCTET_STRING) 10 | self.time = { 11 | object = "extendedKeyUsage", 12 | type = asn1.IA5STRING, 13 | value = "timeStamping", 14 | } 15 | self.ca = { 16 | object = "basicConstraints", 17 | type = asn1.OCTET_STRING, 18 | value = self.cafalse, 19 | } 20 | self.cas = { 21 | object = "basicConstraints", 22 | type = asn1.OCTET_STRING, 23 | value = "CA:FALSE", 24 | } 25 | self.attrs = { self.time, self.ca, self.cas } 26 | end 27 | 28 | function TestX509attr:tearDown() end 29 | 30 | function TestX509attr:testAll() 31 | local n1 = attr.new_attribute(self.ca) 32 | lu.assertStrContains(tostring(n1), "openssl.x509_attribute") 33 | local info = n1:info() 34 | lu.assertIsTable(info) 35 | lu.assertEquals(info.object:ln(), "X509v3 Basic Constraints") 36 | lu.assertEquals(#info.value, 1) 37 | lu.assertEquals(info.value[1].type, asn1.OCTET_STRING) 38 | lu.assertEquals(info.value[1].value, "CA:FALSE") 39 | local n2 = n1:dup() 40 | lu.assertEquals(n2:info(), info) 41 | 42 | local t = n1:type(0) 43 | lu.assertIsTable(t) 44 | lu.assertEquals(t.type, asn1.OCTET_STRING) 45 | lu.assertEquals(t.value, "CA:FALSE") 46 | 47 | n2 = attr.new_attribute(self.cas) 48 | lu.assertEquals(n1:info(), n2:info()) 49 | 50 | lu.assertEquals(n1:object():ln(), "X509v3 Basic Constraints") 51 | n1:object("extendedKeyUsage") 52 | lu.assertEquals(n1:object():sn(), "extendedKeyUsage") 53 | 54 | lu.assertEquals(n1:data(0, asn1.OCTET_STRING):tostring(), "CA:FALSE") 55 | 56 | assert(n1:data(0, "ABCD")) 57 | end 58 | -------------------------------------------------------------------------------- /test/8.bio_dtls_c.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local bio, ssl = openssl.bio, openssl.ssl 4 | local sslctx = require("sslctx") 5 | local host, port, loop 6 | 7 | local arg = arg 8 | 9 | host = arg[1] or "127.0.0.1" -- only ip 10 | port = arg[2] or "8383" 11 | loop = arg[3] and tonumber(arg[3]) or 100 12 | 13 | local _, _, opensslv = openssl.version(true) 14 | 15 | local params = sslctx.client 16 | 17 | local certstore = nil 18 | if opensslv > 0x10002000 then 19 | certstore = openssl.x509.store:new() 20 | local cas = require("root_ca") 21 | for i = 1, #cas do 22 | local cert = assert(openssl.x509.read(cas[i])) 23 | assert(certstore:add(cert)) 24 | end 25 | end 26 | 27 | local ctx = assert(sslctx.new(params, "DTLS")) 28 | ctx = assert(sslctx.new(params, "DTLS_client")) 29 | if certstore then 30 | ctx:cert_store(certstore) 31 | end 32 | 33 | ctx:verify_mode(ssl.peer, function(_arg) 34 | --[[ 35 | --do some check 36 | for k,v in pairs(arg) do 37 | print(k,v) 38 | end 39 | --]] 40 | return true -- return false will fail ssh handshake 41 | end) 42 | 43 | print(string.format("CONNECT to %s:%s with %s", host, port, tostring(ctx))) 44 | 45 | local function mk_connection(_host, _port, i) 46 | local cli = assert(ctx:bio(_host .. ":" .. _port)) 47 | if cli then 48 | assert(cli:handshake()) 49 | ---[[ 50 | if i % 2 == 2 then 51 | assert(cli:handshake()) 52 | else 53 | assert(cli:connect()) 54 | end 55 | -- ]] 56 | local s = "aaa" 57 | io.write(".") 58 | io.flush() 59 | for _ = 1, 100 do 60 | assert(cli:write(s)) 61 | assert(cli:read()) 62 | end 63 | cli:shutdown() 64 | cli:free() 65 | end 66 | openssl.errors() 67 | end 68 | 69 | for i = 1, loop do 70 | mk_connection(host, port, i) 71 | end 72 | print() 73 | print("SSL bio client done") 74 | collectgarbage() 75 | os.exit(0, true) 76 | -------------------------------------------------------------------------------- /test/8.ssl_uv_c.lua: -------------------------------------------------------------------------------- 1 | local uv = require("luv") 2 | local helper = require("helper") 3 | local ssl = require("luv.ssl") 4 | ----------------------------------------------- 5 | local count, concurancy = 0, 0 6 | local ncount = arg[3] and tonumber(arg[3]) or 1000 7 | local step = 100 / 2 8 | local tmp = true 9 | 10 | local function setInterval(fn, ms) 11 | local handle = uv.new_timer() 12 | uv.timer_start(handle, ms, ms, fn) 13 | return handle 14 | end 15 | 16 | -------------------------------------------------------------- 17 | host = arg[1] or "127.0.0.1" --only ip 18 | port = arg[2] or "8383" 19 | 20 | local address = { 21 | port = tonumber(port), 22 | address = host, 23 | } 24 | 25 | local ctx = ssl.new_ctx({ 26 | protocol = helper.sslProtocol(false), 27 | verify = ssl.none, 28 | -- options = {"all", "no_sslv2"} 29 | }) 30 | 31 | local new_connection 32 | 33 | function new_connection(i) 34 | local scli = ssl.connect(address.address, address.port, ctx, function(self) 35 | count = count + 1 36 | concurancy = concurancy + 1 37 | self:write("GET / HTTP/1.0\r\n\r\n") 38 | if tmp then 39 | self:close() 40 | end 41 | 42 | if concurancy <= ncount then 43 | new_connection(i) 44 | end 45 | end) 46 | 47 | function scli:ondata(chunk) end 48 | 49 | function scli:onerror(err) 50 | print("onerror", err) 51 | end 52 | 53 | function scli:onend() 54 | self:close() 55 | end 56 | 57 | function scli:onclose() 58 | count = count - 1 59 | end 60 | 61 | return scli 62 | end 63 | 64 | tmp = true 65 | local conns = {} 66 | 67 | for i = 1, step do 68 | new_connection(i) 69 | end 70 | 71 | local timer 72 | timer = setInterval(function() 73 | print(os.date(), count, concurancy) 74 | print(ssl.error()) 75 | collectgarbage() 76 | if concurancy >= ncount then 77 | timer:close() 78 | end 79 | end, 1000) 80 | 81 | uv.run("default") 82 | 83 | print("done") 84 | -------------------------------------------------------------------------------- /.github/shell/setup_ssl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$SSL" ]; then 4 | echo '$SSL not set, use default openssl' >&2 5 | exit 0 6 | fi 7 | 8 | case "$SSL" in 9 | openssl-*) 10 | # Remove prefix and suffix 11 | version="${SSL#openssl-}" 12 | version="${version%.tar.gz}" 13 | case "$version" in 14 | 0.9.*|1.0.0*|1.0.1*|1.0.2*|1.1.1*) 15 | converted="${version//./_}" 16 | SSLURL=https://github.com/openssl/openssl/releases/download/OpenSSL_$converted/$SSL.tar.gz 17 | ;; 18 | *) 19 | SSLURL=https://github.com/openssl/openssl/releases/download/$SSL/$SSL.tar.gz 20 | ;; 21 | esac 22 | ;; 23 | libressl-*) 24 | SSLURL=https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/$SSL.tar.gz 25 | LIBRESSL=$SSL 26 | ;; 27 | *) 28 | echo $SSL where to download? 29 | exit 1 30 | ;; 31 | esac 32 | 33 | if [ ! -d "$HOME/opt/$SSL" ]; then 34 | echo "Downloading... $SSLURL" 35 | wget "$SSLURL" || exit 1 36 | tar -xzf "$SSL.tar.gz" || exit 1 37 | cd "$SSL" || exit 1 38 | export OPENSSL_DIR=$HOME/.usr 39 | if [ "$RUNNER_OS" == "Linux" ]; then 40 | case "$SSL" in 41 | openssl-1.0*) 42 | FLAGS=shared 43 | ;; 44 | *) 45 | FLAGS=no-shared 46 | esac 47 | ./config zlib no-tests $FLAGS --prefix="$OPENSSL_DIR" || exit 1 48 | fi 49 | if [ "$RUNNER_OS" == "macOS" ]; then 50 | if [ -z "$LIBRESSL" ]; then 51 | ./Configure zlib darwin64-x86_64-cc no-tests no-shared --prefix="$OPENSSL_DIR" || exit 1 52 | else 53 | ./config zlib no-tests no-shared --prefix="$OPENSSL_DIR" || exit 1 54 | fi 55 | fi 56 | make && make install_sw || { 57 | rm -rf "$OPENSSL_DIR" 58 | exit 1 59 | } 60 | cd .. 61 | fi 62 | 63 | # vim: ts=8 sw=8 noet tw=79 fen fdm=marker 64 | -------------------------------------------------------------------------------- /test/test.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | --2021.09.26 uncommit this block will cause ci fail 3 | --Should be bug in LuaJIT 4 | --https://github.com/LuaJIT/LuaJIT/commits/v2.1 5 | collectgarbage('setpause', 0) 6 | collectgarbage('setstepmul', 10000000000000) 7 | --]] 8 | 9 | local lu = require("luaunit") 10 | local openssl = require("openssl") 11 | local helper = require("helper") 12 | 13 | openssl.rand_load() 14 | print("VERSION:", openssl.version()) 15 | assert(openssl.rand_status()) 16 | 17 | if not (helper.openssl3 or helper.libressl) then 18 | assert(openssl.FIPS_mode() == false) 19 | assert(openssl.FIPS_mode(false)) 20 | assert(openssl.FIPS_mode() == false) 21 | end 22 | 23 | dofile("0.bio.lua") 24 | dofile("0.bn.lua") 25 | dofile("0.engine.lua") 26 | dofile("0.misc.lua") 27 | dofile("0.tcp.lua") 28 | dofile("1.asn1.lua") 29 | dofile("2.asn1.lua") 30 | dofile("1.x509_algor.lua") 31 | dofile("1.x509_name.lua") 32 | dofile("1.x509_extension.lua") 33 | dofile("1.x509_attr.lua") 34 | dofile("2.digest.lua") 35 | dofile("2.hmac.lua") 36 | dofile("2.mac.lua") 37 | dofile("2.kdf.lua") 38 | dofile("3.cipher.lua") 39 | dofile("4.pkey.lua") 40 | dofile("4.pkey_ctx.lua") 41 | dofile("5.x509_req.lua") 42 | dofile("5.x509_crl.lua") 43 | dofile("5.x509_store.lua") 44 | dofile("5.x509.lua") 45 | dofile("5.ts.lua") 46 | dofile("6.pkcs7.lua") 47 | dofile("6.cms.lua") 48 | dofile("7.pkcs12.lua") 49 | dofile("8.ssl_options.lua") 50 | dofile("8.ssl.lua") 51 | dofile("9.error_handling.lua") 52 | dofile("9.ocsp.lua") 53 | dofile("9.srp.lua") 54 | dofile("9.issue.lua") 55 | 56 | dofile("issues_cipher.lua") 57 | dofile("issue#185.lua") 58 | 59 | dofile("dh.lua") 60 | dofile("dsa.lua") 61 | dofile("rsa.lua") 62 | dofile("group.lua") 63 | dofile("point.lua") 64 | dofile("provider.lua") 65 | dofile("ec.lua") 66 | dofile("sm2.lua") 67 | dofile("fetchable.lua") 68 | 69 | local runner = lu.LuaUnit.new() 70 | runner:setOutputType("tap") 71 | local retcode = runner:runSuite() 72 | assert(openssl.rand_write()) 73 | print(openssl.errors()) 74 | openssl.clear_error() 75 | collectgarbage() 76 | os.exit(retcode, true) 77 | -------------------------------------------------------------------------------- /test/provider_check.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | -- Quick test to verify provider module availability 3 | local openssl = require('openssl') 4 | 5 | print("\n" .. string.rep("=", 70)) 6 | print("OpenSSL Provider Module Availability Test") 7 | print(string.rep("=", 70)) 8 | 9 | -- Get version info 10 | local ver_str, lua_ver, ssl_ver = openssl.version() 11 | local ver_num, lua_num, ssl_num = openssl.version(true) 12 | 13 | print("\nVersion Information:") 14 | print(" Lua version: " .. lua_ver) 15 | print(" OpenSSL version: " .. ssl_ver) 16 | print(" Version number: " .. string.format("0x%08X", ssl_num)) 17 | 18 | -- Check if this is LibreSSL 19 | local is_libressl = string.match(ssl_ver, "LibreSSL") ~= nil 20 | print(" LibreSSL: " .. (is_libressl and "Yes" or "No")) 21 | 22 | -- Check if provider module is available 23 | print("\nProvider Module Status:") 24 | if openssl.provider then 25 | if openssl.provider._error then 26 | print(" Status: Available (stub)") 27 | print(" Error: " .. openssl.provider._error) 28 | else 29 | print(" Status: Available and functional") 30 | print(" Module type: " .. type(openssl.provider)) 31 | 32 | -- Try to list providers 33 | local ok, result = pcall(function() return openssl.provider.list() end) 34 | if ok and result then 35 | print(" Available providers:") 36 | for i, name in ipairs(result) do 37 | print(" " .. i .. ". " .. name) 38 | end 39 | end 40 | end 41 | else 42 | print(" Status: Not available") 43 | print(" Reason: Requires OpenSSL 3.0+ (not LibreSSL)") 44 | end 45 | 46 | -- Version compatibility check 47 | print("\nCompatibility Check:") 48 | if ssl_num >= 0x30000000 and not is_libressl then 49 | print(" ✓ OpenSSL 3.0+ detected - Provider API should be available") 50 | elseif is_libressl then 51 | print(" ⚠ LibreSSL detected - Provider API not supported") 52 | else 53 | print(" ⚠ OpenSSL < 3.0 detected - Provider API not available") 54 | end 55 | 56 | print(string.rep("=", 70) .. "\n") 57 | -------------------------------------------------------------------------------- /test/8.ssl_uv_s.lua: -------------------------------------------------------------------------------- 1 | local uv = require("luv") 2 | local helper = require("helper") 3 | local ssl = require("luv.ssl") 4 | 5 | ----------------------------------------------- 6 | ---[[ 7 | local count = 0 8 | 9 | local function setInterval(fn, ms) 10 | local handle = uv.new_timer() 11 | uv.timer_start(handle, ms, ms, fn) 12 | return handle 13 | end 14 | 15 | --]] 16 | -------------------------------------------------------------- 17 | host = arg[1] or "127.0.0.1" --only ip 18 | port = arg[2] or "8383" 19 | 20 | local address = { 21 | port = tonumber(port), 22 | address = host, 23 | } 24 | 25 | local ctx = ssl.new_ctx({ 26 | protocol = helper.sslProtocol(true), 27 | key = "certs/agent1-key.pem", 28 | certificate = "certs/agent1-cert.pem", 29 | cafile = "certs/agent1-ca.pem", 30 | verify = ssl.none, 31 | -- options = {"all", "no_sslv2"} 32 | }) 33 | 34 | function create_server(host, port, on_connection) 35 | local server = uv.new_tcp() 36 | uv.tcp_bind(server, host, port) 37 | uv.listen(server, 64, function(self) 38 | local client = uv.new_tcp() 39 | uv.accept(server, client) 40 | on_connection(client) 41 | end) 42 | return server 43 | end 44 | 45 | local p = print 46 | local server 47 | server = create_server(address.address, address.port, function(client) 48 | local scli = ssl.new_ssl(ctx, client, true) 49 | scli:handshake(function(scli) 50 | count = count + 1 51 | end) 52 | 53 | function scli:ondata(chunk) 54 | self:close() 55 | end 56 | 57 | function scli:onerror(err) 58 | print("onerr", err, ssl.error()) 59 | end 60 | 61 | function scli:onend() 62 | uv.shutdown(client, function() 63 | uv.close(client) 64 | end) 65 | end 66 | end) 67 | 68 | local address = uv.tcp_getsockname(server) 69 | p("server", server, address) 70 | 71 | local timer, limit = nil, 0 72 | timer = setInterval(function() 73 | print(os.date(), count) 74 | collectgarbage() 75 | if limit > 5 then 76 | timer:close() 77 | server:close() 78 | end 79 | limit = limit + 1 80 | end, 1000) 81 | 82 | uv.run("default") 83 | 84 | print("done") 85 | -------------------------------------------------------------------------------- /test/8.bio_dtls_s.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local ssl = openssl.ssl 4 | local sslctx = require("sslctx") 5 | local _, _, opensslv = openssl.version(true) 6 | local host, port, loop 7 | 8 | local arg = assert(arg) 9 | host = arg[1] or "127.0.0.1" -- only ip 10 | port = arg[2] or "8383" 11 | loop = arg[3] and tonumber(arg[3]) or 100 12 | 13 | local params = sslctx.server 14 | 15 | -- 16 | local certstore 17 | if opensslv > 0x10002000 then 18 | certstore = openssl.x509.store:new() 19 | local cas = require("root_ca") 20 | for i = 1, #cas do 21 | local cert = assert(openssl.x509.read(cas[i])) 22 | assert(certstore:add(cert)) 23 | end 24 | end 25 | 26 | local ctx = assert(sslctx.new(params, "DTLS_server")) 27 | if certstore then 28 | ctx:cert_store(certstore) 29 | end 30 | assert(ctx:cert_store()) 31 | ctx:timeout(60) 32 | assert(ctx:timeout() == 60) 33 | ctx:quiet_shutdown(1) 34 | assert(ctx:quiet_shutdown() == 1) 35 | 36 | ctx:verify_mode(ssl.peer, function(_arg) 37 | --[[ 38 | --do some check 39 | for k,v in pairs(arg) do 40 | print(k,v) 41 | end 42 | --]] 43 | return true -- return false will fail ssh handshake 44 | end) 45 | 46 | print(string.format("Listen at %s:%s with %s", host, port, tostring(ctx))) 47 | ctx:set_cert_verify({ 48 | always_continue = true, 49 | verify_depth = 9, 50 | }) 51 | 52 | local function ssl_mode() 53 | local srv = assert(ctx:bio(host .. ":" .. port, true)) 54 | local i = 0 55 | if srv then 56 | print("listen BIO:", srv) 57 | assert(srv:accept(true), "Error in accept BIO") -- make real listen 58 | print("accpeting...") 59 | io.flush() 60 | while i < loop do 61 | local cli = assert(srv:accept(), "Error in ssl connection") -- bio tcp 62 | io.write("+") 63 | io.flush() 64 | assert(cli:handshake(), "handshake fail") 65 | repeat 66 | local d = cli:read() 67 | if d then 68 | assert(#d == cli:write(d)) 69 | end 70 | until not d 71 | cli:shutdown() 72 | cli:close(true) 73 | collectgarbage() 74 | i = i + 1 75 | end 76 | srv:close() 77 | end 78 | end 79 | 80 | ssl_mode() 81 | print(openssl.errors()) 82 | -------------------------------------------------------------------------------- /test/8.bio_s.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local ssl = openssl.ssl 4 | local sslctx = require("sslctx") 5 | local _, _, opensslv = openssl.version(true) 6 | local host, port, loop 7 | 8 | local arg = assert(arg) 9 | host = arg[1] or "127.0.0.1" -- only ip 10 | port = arg[2] or "8383" 11 | loop = arg[3] and tonumber(arg[3]) or 100 12 | 13 | local params = sslctx.server 14 | 15 | -- 16 | local certstore 17 | if opensslv > 0x10002000 then 18 | certstore = openssl.x509.store:new() 19 | local cas = require("root_ca") 20 | for i = 1, #cas do 21 | local cert = assert(openssl.x509.read(cas[i])) 22 | assert(certstore:add(cert)) 23 | end 24 | end 25 | 26 | local ctx = assert(sslctx.new(params)) 27 | if certstore then 28 | ctx:cert_store(certstore) 29 | end 30 | assert(ctx:cert_store()) 31 | ctx:timeout(60) 32 | assert(ctx:timeout() == 60) 33 | ctx:quiet_shutdown(1) 34 | assert(ctx:quiet_shutdown() == 1) 35 | 36 | ctx:verify_mode(ssl.peer, function(_arg) 37 | --[[ 38 | --do some check 39 | for k,v in pairs(arg) do 40 | print(k,v) 41 | end 42 | --]] 43 | return true -- return false will fail ssh handshake 44 | end) 45 | 46 | print(string.format("Listen at %s:%s with %s", host, port, tostring(ctx))) 47 | ctx:set_cert_verify({ 48 | always_continue = true, 49 | verify_depth = 9, 50 | }) 51 | 52 | local function ssl_mode() 53 | local srv = assert(ctx:bio(host .. ":" .. port, true)) 54 | local i = 0 55 | if srv then 56 | print("listen BIO:", srv) 57 | assert(srv:accept(true), "Error in accept BIO") -- make real listen 58 | print("accpeting...") 59 | io.flush() 60 | while i < loop do 61 | local cli = assert(srv:accept(), "Error in ssl connection") -- bio tcp 62 | io.write("+") 63 | io.flush() 64 | assert(cli:handshake(), "handshake fail") 65 | repeat 66 | local d = cli:read() 67 | if d then 68 | assert(#d == cli:write(d)) 69 | end 70 | until not d 71 | assert(cli:ssl()) 72 | cli:shutdown() 73 | cli:close(true) 74 | collectgarbage() 75 | i = i + 1 76 | end 77 | srv:close() 78 | end 79 | end 80 | 81 | ssl_mode() 82 | print(openssl.errors()) 83 | -------------------------------------------------------------------------------- /test/issue#185.lua: -------------------------------------------------------------------------------- 1 | local openssl = require("openssl") 2 | local cms = openssl.cms 3 | local x509 = openssl.x509 4 | 5 | local console_public_key_data = [[-----BEGIN CERTIFICATE----- 6 | MIIBmzCCAUGgAwIBAgIUceXybAulcsDfhFapwpZRqPNMkV4wCgYIKoZIzj0EAwIw 7 | IjEgMB4GA1UEAwwXbWVzaC1jb25zb2xlLjIyMzYwMzY2NzMwIBcNMTcwMTAxMDAw 8 | MDAwWhgPMjExODEwMjMwNzQzMTZaMCIxIDAeBgNVBAMMF21lc2gtY29uc29sZS4y 9 | MjM2MDM2NjczMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEtpMry4ECQ94FyzjS 10 | 3gTgfomQnfkW2W1803j4XLK1kupo0/blLIsz5djdV6vS9n9qoJo4W6Mbt7h4qolg 11 | ILsXUaNTMFEwHQYDVR0OBBYEFDAI4nhDcrvQPhydcsuRnB+Zftp0MA8GA1UdEwEB 12 | /wQFMAMBAf8wHwYDVR0jBBgwFoAUMAjieENyu9A+HJ1yy5GcH5l+2nQwCgYIKoZI 13 | zj0EAwIDSAAwRQIhAOU3gVO+llWqLJGLe2uPEEyCFQO1h9Ll/JodizfZv7j5AiBx 14 | LPd0OELmajQzwJuRLiA5l4B2wUrIjdCFtKEVIuGF+w== 15 | -----END CERTIFICATE----- 16 | ]] 17 | 18 | local ver_blob = [[-----BEGIN CMS----- 19 | MIAGCSqGSIb3DQEHAqCAMIACAQMxDTALBglghkgBZQMEAgEwgAYJKoZIhvcNAQcB 20 | oIAkgAQGMTA3OTI1AAAAAAAAoIIBnzCCAZswggFBoAMCAQICFHHl8mwLpXLA34RW 21 | qcKWUajzTJFeMAoGCCqGSM49BAMCMCIxIDAeBgNVBAMMF21lc2gtY29uc29sZS4y 22 | MjM2MDM2NjczMCAXDTE3MDEwMTAwMDAwMFoYDzIxMTgxMDIzMDc0MzE2WjAiMSAw 23 | HgYDVQQDDBdtZXNoLWNvbnNvbGUuMjIzNjAzNjY3MzBZMBMGByqGSM49AgEGCCqG 24 | SM49AwEHA0IABLaTK8uBAkPeBcs40t4E4H6JkJ35FtltfNN4+FyytZLqaNP25SyL 25 | M+XY3Ver0vZ/aqCaOFujG7e4eKqJYCC7F1GjUzBRMB0GA1UdDgQWBBQwCOJ4Q3K7 26 | 0D4cnXLLkZwfmX7adDAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFDAI4nhD 27 | crvQPhydcsuRnB+Zftp0MAoGCCqGSM49BAMCA0gAMEUCIQDlN4FTvpZVqiyRi3tr 28 | jxBMghUDtYfS5fyaHYs32b+4+QIgcSz3dDhC5mo0M8CbkS4gOZeAdsFKyI3QhbSh 29 | FSLhhfsxfTB7AgEDgBQwCOJ4Q3K70D4cnXLLkZwfmX7adDALBglghkgBZQMEAgEw 30 | CgYIKoZIzj0EAwIERzBFAiBtZ3lJ14NbPvG53u4fBZ8dVCEWCRW+A9jm22gr1HTg 31 | dgIhAPEBU53+71sigZYYn5CEM7+Np9dR+2iKFBTh47OpL1TIAAAAAAAA 32 | -----END CMS----- 33 | ]] 34 | 35 | function testIssue185() 36 | local store = assert(x509.store.new({ 37 | assert(x509.read(console_public_key_data, "pem")), 38 | })) 39 | local i = 0 40 | collectgarbage() 41 | collectgarbage() 42 | collectgarbage() 43 | local b = collectgarbage("count") 44 | local box = assert(cms.read(ver_blob, "pem")) 45 | while i < 10 do 46 | assert(cms.verify(box, {}, store)) 47 | i = i + 1 48 | end 49 | collectgarbage() 50 | collectgarbage() 51 | collectgarbage() 52 | local e = collectgarbage("count") 53 | assert(e - b <= 0.2, "Memleaks " .. tostring(e - b)) 54 | end 55 | -------------------------------------------------------------------------------- /test/0.engine.lua: -------------------------------------------------------------------------------- 1 | local openssl = require("openssl") 2 | local helper = require("helper") 3 | if not openssl.engine then 4 | return 5 | end 6 | 7 | TestEngine = {} 8 | function TestEngine:testAll() 9 | local eng = assert(openssl.engine("openssl")) 10 | assert(eng:id() == "openssl") 11 | assert(eng:id("openssl")) 12 | assert(eng:set_default("RSA")) 13 | local v = eng:name() 14 | assert(eng:name(v)) 15 | v = eng:flags() 16 | assert(eng:flags(v)) 17 | assert(eng:init()) 18 | assert(eng:finish()) 19 | local _, sslv 20 | _, _, sslv = openssl.version(true) 21 | if sslv >= 0x10100000 and not helper.libressl then 22 | assert(eng:set_default("EC")) 23 | else 24 | assert(eng:set_default("ECDSA")) 25 | end 26 | assert(eng:remove()) 27 | assert(eng:add()) 28 | assert(eng:id() == "openssl") 29 | 30 | local list = { 31 | "RSA", 32 | "DSA", 33 | "DH", 34 | "RAND", 35 | "ciphers", 36 | "digests", 37 | "complete", 38 | } 39 | if sslv >= 0x10100000 and not helper.libressl then 40 | table.insert(list, 2, "EC") 41 | table.insert(list, 2, "PKEY") 42 | table.insert(list, 2, "ASN1") 43 | else 44 | table.insert(list, 2, "ECDH") 45 | table.insert(list, 2, "ECDSA") 46 | table.insert(list, 2, "STORE") 47 | end 48 | 49 | for _, v in pairs(list) do 50 | eng:register(false, v) 51 | eng:register(true, v) 52 | end 53 | for i = #list, 1, -1 do 54 | local v = list[i] 55 | if v == "STORE" or v == "PKEY" or v == "ASN1" or v == "complete" then 56 | table.remove(list, i) 57 | end 58 | end 59 | local unpack = unpack or table.unpack 60 | eng:set_default(unpack(list)) 61 | eng:set_rand_engine() 62 | eng:load_public_key("public_key") 63 | eng:load_private_key("private_key") 64 | print(openssl.errors()) 65 | 66 | -- just cover code 67 | -- ENGINE_CTRL_HAS_CTRL_FUNCTION 10 68 | local num, val = 10, 0 69 | val = eng:ctrl(num) 70 | -- ENGINE_CTRL_GET_FIRST_CMD_TYPE 11 71 | num = 11 72 | val = eng:ctrl(num, 0) 73 | 74 | val = eng:ctrl("CMD", 0) 75 | val = eng:ctrl("CMD", 0, eng) 76 | val = eng:ctrl("CMD", "", 0) 77 | openssl.errors() 78 | end 79 | 80 | function TestEngine:testLoop() 81 | local e = openssl.engine(true) 82 | while e do 83 | e = e:next() 84 | end 85 | 86 | e = openssl.engine(false) 87 | while e do 88 | e = e:prev() 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /test/0.tcp.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local helper = require("helper") 3 | 4 | local ok, uv = pcall(require, "luv") 5 | if not ok then 6 | uv = nil 7 | end 8 | 9 | local LUA = arg and arg[-1] or nil 10 | TestTCP = {} 11 | 12 | if not LUA then 13 | return 14 | end 15 | 16 | if uv then 17 | local function set_timeout(timeout, callback) 18 | local timer = uv.new_timer() 19 | local function ontimeout() 20 | uv.timer_stop(timer) 21 | uv.close(timer) 22 | callback(timer) 23 | end 24 | uv.timer_start(timer, timeout, 0, ontimeout) 25 | return timer 26 | end 27 | 28 | function TestTCP:testUVTcp() 29 | local port = math.random(8000, 9000) 30 | helper.spawn(LUA, { "0.tcp_s.lua", "127.0.0.1", port }, "accepting...", function() 31 | print("started") 32 | helper.spawn(LUA, { "0.tcp_c.lua", "127.0.0.1", port }) 33 | end) 34 | uv.run() 35 | end 36 | end 37 | 38 | local luv 39 | ok, luv = pcall(require, "lluv") 40 | if not ok then 41 | luv = nil 42 | end 43 | 44 | if luv then 45 | local function P(pipe, read) 46 | return { 47 | stream = pipe, 48 | flags = luv.CREATE_PIPE + (read and luv.READABLE_PIPE or luv.WRITABLE_PIPE), 49 | } 50 | end 51 | 52 | local lua_spawn = function(f, o, e, c) 53 | return luv.spawn({ 54 | file = LUA, 55 | args = { f }, 56 | stdio = { {}, P(o, false), P(e, false) }, 57 | }, c) 58 | end 59 | 60 | function TestTCP:testLUVTCP() 61 | local function onread(pipe, err, chunk) 62 | if err then 63 | if err:name() ~= "EOF" then 64 | assert(not err, tostring(err)) 65 | end 66 | end 67 | if chunk then 68 | print(chunk) 69 | end 70 | end 71 | 72 | local function onclose(child, err, status) 73 | if err then 74 | return print("Error spawn:", err) 75 | end 76 | lu.assertEquals(status, 0) 77 | child:close() 78 | end 79 | 80 | local stdout1 = luv.pipe() 81 | local stderr1 = luv.pipe() 82 | local stdout2 = luv.pipe() 83 | local stderr2 = luv.pipe() 84 | 85 | lua_spawn("0.tcp_s.lua", stdout1, stderr1, onclose) 86 | lua_spawn("0.tcp_c.lua", stdout2, stderr2, onclose) 87 | 88 | stdout1:start_read(onread) 89 | stderr1:start_read(onread) 90 | stdout2:start_read(onread) 91 | stderr2:start_read(onread) 92 | 93 | luv.run() 94 | luv.close() 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /test/utils/ca.lua: -------------------------------------------------------------------------------- 1 | local openssl = require'openssl' 2 | local ext = openssl.x509.extension 3 | 4 | local M = {} 5 | 6 | M.caexts = { 7 | { 8 | object='basicConstraints', 9 | value='CA:true', 10 | critical = true 11 | }, 12 | { 13 | object='keyUsage', 14 | value='keyCertSign' 15 | } 16 | } 17 | 18 | M.cadn = { 19 | {commonName = 'CA'}, 20 | {OU = "lua"}, 21 | {O = "openssl"}, 22 | {C = 'CN'} 23 | } 24 | 25 | function M.to_extensions(exts) 26 | exts = exts or M.caexts 27 | local ret = {} 28 | for i=1, #exts do 29 | ret[i] = ext.new_extension(exts[i]) 30 | end 31 | return ret 32 | end 33 | 34 | function M:new() 35 | local cadn = openssl.x509.name.new(M.cadn) 36 | --cacert, self sign 37 | local pkey = assert(openssl.pkey.new()) 38 | local req = assert(openssl.x509.req.new(cadn, pkey)) 39 | local cacert = openssl.x509.new( 40 | 1, --serialNumber 41 | req --copy name and extensions 42 | ) 43 | cacert:extensions(M.to_extensions()) 44 | cacert:notbefore(os.time()) 45 | cacert:notafter(os.time() + 3600*24*365) 46 | assert(cacert:sign(pkey, cacert)) --self sign 47 | self.pkey, self.cacert = pkey, cacert 48 | assert(cacert:check(pkey), 'self sign check failed') 49 | 50 | self.crl = openssl.x509.crl.new() 51 | assert(self.crl:issuer(cacert:issuer())) 52 | assert(self.crl:version(0)) 53 | assert(self.crl:updateTime(os.time())) 54 | assert(self.crl:lastUpdate(os.time())) 55 | assert(self.crl:nextUpdate(os.time() + 24*3600)) 56 | return self 57 | end 58 | 59 | function M:get_store() 60 | if not self.store then 61 | self.store = openssl.x509.store.new({self.cacert}, {self.crl}) 62 | assert(self.cacert:check(self.store)) 63 | end 64 | return self.store 65 | end 66 | 67 | function M:sign(csr, extensions) 68 | assert(self.pkey and self.cacert, "CA not initlized") 69 | if type(csr)=='string' then 70 | csr = openssl.x509.req.read(csr) 71 | end 72 | 73 | local sn = openssl.random(16) 74 | sn = openssl.bn.text(sn) 75 | 76 | local cert = openssl.x509.new(sn, csr) 77 | cert:notbefore(os.time()) 78 | if extensions then 79 | cert:extensions(M.to_extensions(extensions)) 80 | end 81 | cert:validat(os.time(), os.time() + 3600 * 24 * 360) 82 | assert(cert:sign(self.pkey, self.cacert)) 83 | return cert 84 | end 85 | 86 | function M:revoke(sn) 87 | assert(self.crl:add(sn, os.time())) 88 | assert(self.crl:lastUpdate(os.time())) 89 | end 90 | 91 | return M 92 | -------------------------------------------------------------------------------- /test/1.x509_name.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local name = require("openssl").x509.name 4 | local asn1 = require("openssl").asn1 5 | 6 | TestX509Name = {} 7 | function TestX509Name:setUp() 8 | self.names = { { C = "CN" }, { O = "kkhub.com" }, { CN = "zhaozg" } } 9 | end 10 | 11 | function TestX509Name:tearDown() end 12 | 13 | function TestX509Name:testAll() 14 | local n1 = name.new(self.names) 15 | lu.assertEquals(n1:tostring(), n1:oneline()) 16 | local der = n1:i2d() 17 | local n2 = name.d2i(der) 18 | assert(n1:cmp(n2) == (n1 == n2)) 19 | n2 = assert(n1:dup()) 20 | assert(n1:cmp(n2) == (n1 == n2)) 21 | lu.assertEquals(n1, n2) 22 | lu.assertEquals(n1:oneline(), "/C=CN/O=kkhub.com/CN=zhaozg") 23 | 24 | lu.assertIsNumber(n1:hash()) 25 | lu.assertEquals(#n1:digest("SHA1"), 20) 26 | 27 | lu.assertEquals(n2:toprint(), "C=CN, O=kkhub.com, CN=zhaozg") 28 | 29 | local info = n1:info() 30 | lu.assertIsTable(info) 31 | assert(n1:entry_count(), 3) 32 | 33 | lu.assertEquals(n1:get_text("CN"), "zhaozg") 34 | lu.assertEquals(n1:get_text("C"), "CN") 35 | lu.assertEquals(n1:get_text("OU"), nil) 36 | 37 | lu.assertIsTable(n1:get_entry(0)) 38 | 39 | lu.assertIsTable(n1:get_entry(1)) 40 | lu.assertIsTable(n1:get_entry(2)) 41 | lu.assertIsNil(n1:get_entry(3)) 42 | 43 | local s2 = asn1.new_string("中文名字", asn1.BMPSTRING) 44 | local utf_cn = s2:toutf8() 45 | local s3 = asn1.new_string(utf_cn, asn1.UTF8STRING) 46 | assert(s3) 47 | 48 | assert(n1:add_entry("OU", utf_cn, true)) 49 | local S, i = n1:get_text("OU") 50 | lu.assertEquals(i, 3) 51 | assert(S == utf_cn) 52 | 53 | local t = n1:info() 54 | for _ = 1, #t do 55 | v = t[_] 56 | lu.assertIsTable(v) 57 | for K, V in pairs(v) do 58 | assert(type(K) == "string") 59 | assert(type(V) == "string") 60 | end 61 | end 62 | 63 | t = n1:info(true) 64 | for _ = 1, #t do 65 | v = t[_] 66 | for K, V in pairs(v) do 67 | assert(type(K) == "userdata") 68 | assert(type(V) == "userdata") 69 | end 70 | end 71 | 72 | local k, v = n1:delete_entry(3) 73 | lu.assertStrContains(tostring(k), "openssl.asn1_object") 74 | local _, _, opensslv = openssl.version(true) 75 | if opensslv > 0x10002000 then 76 | lu.assertEquals(v:toprint(), [[\UE4B8\UADE6\U9687\UE590\U8DE5\UAD97]]) 77 | lu.assertEquals(v:tostring(), v:toutf8()) 78 | end 79 | 80 | k, v = name.new({ { XXXX = "SHOULDERROR" } }) 81 | assert(k == nil) 82 | assert(v:match("can't add to openssl.x509_name with value")) 83 | end 84 | -------------------------------------------------------------------------------- /test/2.asn1.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local asn1, hex, base64 = openssl.asn1, openssl.hex, openssl.base64 4 | 5 | local pem = "MHcCAQEEINUs3GRVhC8h1y84gcW89XB9cyjUifwO3ZEH/Redb7w8oAoGCCqBHM9VAYItoUQDQgAE" 6 | .. "9YFSq5ZO6I+YXsIpYFzCYTcgtotrg6UW5xX8+e8arpoU5SsojLjRG1PA028kbi139zZlH2Gh/JPNiMEzRClIVg==" 7 | 8 | local ss = base64(pem, false) 9 | local d = {} 10 | local first = false 11 | local function asn1parse(s, off, last, indent) 12 | off = off or 1 13 | last = last or #s 14 | indent = indent or 0 15 | local tab = " " 16 | local tag, cls, start, stop, cons 17 | cons, tag, cls = pcall(asn1.get_object, s, off, last) 18 | if not tag then 19 | assert(type(cls) == "string") 20 | return 21 | end 22 | 23 | tag, cls, start, stop, cons = asn1.get_object(s, off, last) 24 | assert(tag, string.format("%d-%d", off, last)) 25 | 26 | if first then 27 | print( 28 | string.format( 29 | "%sTAG=%s CLS=%s START=%s STOP=%s, %s", 30 | string.rep(tab, indent), 31 | asn1.tostring(tag, "tag"), 32 | asn1.tostring(cls, "class"), 33 | start, 34 | stop, 35 | cons and "CONS" or "PRIM" 36 | ) 37 | ) 38 | assert(asn1.tostring(tag, "tag") == asn1.tostring(tag)) 39 | end 40 | if cons then 41 | table.insert(d, asn1.put_object(tag, cls, stop - start + 1, true)) 42 | stop = asn1parse(s, start, stop, indent + 1) 43 | else 44 | if first then 45 | print(string.format("%sVAL:%s", string.rep(tab, indent + 1), hex(string.sub(s, start, stop)))) 46 | end 47 | table.insert(d, asn1.put_object(tag, cls, string.sub(s, start, stop))) 48 | end 49 | 50 | while stop < last do 51 | stop = asn1parse(s, stop + 1, last, indent) 52 | end 53 | return stop 54 | end 55 | 56 | TestAsn1_2 = {} 57 | function TestAsn1_2.testParse() 58 | assert(#ss > 0) 59 | -- fire error 60 | lu.assertErrorMsgEquals( 61 | "2.asn1.lua:23: bad argument #2 to 'get_object' (start out of length of asn1 string)", 62 | asn1parse, 63 | ss, 64 | 0 65 | ) 66 | lu.assertErrorMsgEquals( 67 | "2.asn1.lua:23: bad argument #2 to 'get_object' (start out of length of asn1 string)", 68 | asn1parse, 69 | ss, 70 | #ss 71 | ) 72 | lu.assertErrorMsgEquals( 73 | "2.asn1.lua:23: bad argument #3 to 'get_object' (stop out of length of asn1 string)", 74 | asn1parse, 75 | ss, 76 | 1, 77 | #ss + 1 78 | ) 79 | 80 | d = {} 81 | asn1parse(ss) 82 | local s1 = table.concat(d, "") 83 | 84 | lu.assertEquals(ss, s1) 85 | first = false 86 | end 87 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ "master", "ci" ] 6 | tags: 7 | - v?[0-9].[0-9]+.[0-9]+-[0-9]+ 8 | pull_request: 9 | # The branches below must be a subset of the branches above 10 | branches: [ "master" ] 11 | 12 | jobs: 13 | build: 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | matrix: 17 | os: [macos-15-intel, ubuntu-latest] 18 | luarocks_version: [3.12.0] 19 | lua_version: [luajit2.1, lua5.1, lua5.3, lua5.4] 20 | openssl_version: [openssl-1.0.2u, openssl-1.1.1w, openssl-3.0.18, openssl-3.5.4, openssl-3.6.0] 21 | env: 22 | MACOSX_DEPLOYMENT_TARGET: 10.12 23 | LUAROCKS: ${{ matrix.luarocks_version }} 24 | LUA: ${{ matrix.lua_version }} 25 | SSL: ${{ matrix.openssl_version }} 26 | 27 | steps: 28 | - uses: actions/checkout@v4 29 | with: 30 | submodules: recursive 31 | 32 | - name: Setup 33 | run: 34 | .github/shell/setup_lua.sh && .github/shell/setup_ssl.sh 35 | 36 | - name: Build 37 | run: 38 | .github/shell/build.sh 39 | 40 | - name: Test 41 | run: 42 | PKG_CONFIG_PATH=$HOME/.usr/lib64/pkgconfig:$HOME/.usr/lib/pkgconfig PATH=$HOME/.usr/bin:$PATH LD_LIBRARY_PATH=$HOME/.usr/lib64:$HOME/.usr/lib make test 43 | 44 | deploy: 45 | if: startsWith(github.ref, 'refs/tags/') 46 | needs: [build] 47 | runs-on: ubuntu-latest 48 | env: 49 | WITH_LUA_ENGINE: LuaJIT 50 | LUA: luajit2.1 51 | LUAROCKS: 3.12.0 52 | steps: 53 | - uses: actions/checkout@v4 54 | with: 55 | submodules: recursive 56 | 57 | - name: Get version 58 | id: get_version 59 | run: echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/} 60 | 61 | - name: Setup 62 | run: 63 | .github/shell/setup_lua.sh 64 | 65 | - name: Package 66 | run: 67 | .github/shell/make_rockspec.sh ${{ steps.get_version.outputs.VERSION }} 68 | 69 | - name: Github Release 70 | id: create_release 71 | uses: softprops/action-gh-release@v2 72 | env: 73 | GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} 74 | with: 75 | files: openssl-${{ steps.get_version.outputs.VERSION }}.tar.gz 76 | draft: false 77 | prerelease: false 78 | 79 | - name: Luarocks Release 80 | # lua-cjson is required for luarocks upload 81 | run: | 82 | export PATH=$HOME/.usr/bin:$PATH 83 | export LUA_CPATH=$HOME/.usr/lib/lua/5.1/?.so 84 | luarocks install lua-cjson 85 | luarocks build 86 | luarocks test 87 | luarocks upload openssl-${{ steps.get_version.outputs.VERSION }}.rockspec --api-key=${{ secrets.LUAROCKS_TOKEN }} 88 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(lua-openssl C) 3 | 4 | set(CMAKE_MACOSX_RPATH 1) 5 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} 6 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules") 7 | option(BUILD_SHARED_LUA_OPENSSL "Shared or Static lua-openssl" ON) 8 | option(BUILD_LINK_LUA_LIBRARIES "Link Lua libraries during build-time" OFF) 9 | if(WIN32) 10 | set(BUILD_LINK_LUA_LIBRARIES ON) 11 | endif() 12 | 13 | include(GNUInstallDirs) 14 | 15 | find_package(LuaJIT) 16 | if(NOT LUAJIT_FOUND) 17 | find_package(Lua REQUIRED) 18 | endif() 19 | find_package(OpenSSL REQUIRED) 20 | 21 | set(CMAKE_THREAD_PREFER_PTHREAD TRUE) 22 | set(THREADS_PREFER_PTHREAD_FLAG TRUE) 23 | find_package(Threads REQUIRED) 24 | 25 | if(BUILD_SHARED_LUA_OPENSSL) 26 | set(LUA_OPENSSL_LIBTYPE MODULE) 27 | if(WIN32) 28 | add_definitions(-DLUA_BUILD_AS_DLL) 29 | set(EXTRA_LIBS "ws2_32.lib" "crypt32.lib") 30 | endif() 31 | else() 32 | set(LUA_OPENSSL_LIBTYPE STATIC) 33 | endif() 34 | 35 | add_library(lua-openssl ${LUA_OPENSSL_LIBTYPE} 36 | deps/auxiliar/auxiliar.c 37 | deps/auxiliar/subsidiar.c 38 | src/asn1.c 39 | src/bio.c 40 | src/callback.c 41 | src/cipher.c 42 | src/cms.c 43 | src/compat.c 44 | src/crl.c 45 | src/csr.c 46 | src/dh.c 47 | src/digest.c 48 | src/dsa.c 49 | src/ec.c 50 | src/engine.c 51 | src/mac.c 52 | src/hmac.c 53 | src/kdf.c 54 | src/lbn.c 55 | src/lhash.c 56 | src/misc.c 57 | src/ocsp.c 58 | src/oids.txt 59 | src/openssl.c 60 | src/ots.c 61 | src/param.c 62 | src/pkcs12.c 63 | src/pkcs7.c 64 | src/pkey.c 65 | src/private.h 66 | src/provider.c 67 | src/rsa.c 68 | src/sk.h 69 | src/srp.c 70 | src/ssl.c 71 | src/th-lock.c 72 | src/util.c 73 | src/x509.c 74 | src/xattrs.c 75 | src/xexts.c 76 | src/xname.c 77 | src/xalgor.c 78 | src/xstore.c) 79 | 80 | target_include_directories( 81 | lua-openssl PUBLIC ${OPENSSL_INCLUDE_DIR} ${LUA_INCLUDE_DIR} deps 82 | deps/lua-compat/c-api deps/auxiliar) 83 | 84 | target_link_libraries(lua-openssl PUBLIC ${OPENSSL_LIBRARIES} ${EXTRA_LIBS} 85 | Threads::Threads) 86 | 87 | if(BUILD_LINK_LUA_LIBRARIES) 88 | target_link_libraries(lua-openssl PUBLIC ${LUA_LIBRARIES}) 89 | if(UNIX) 90 | target_link_options(lua-openssl PUBLIC -Wl,--no-undefined) 91 | endif() 92 | else() 93 | if(APPLE) 94 | target_link_options(lua-openssl PUBLIC -bundle -undefined dynamic_lookup) 95 | endif() 96 | endif() 97 | 98 | target_compile_options(lua-openssl PRIVATE -DLUA_LIB) 99 | 100 | set_target_properties(lua-openssl PROPERTIES PREFIX "" OUTPUT_NAME "openssl") 101 | 102 | install( 103 | TARGETS lua-openssl 104 | LIBRARY 105 | DESTINATION 106 | ${CMAKE_INSTALL_LIBDIR}/lua/${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}) 107 | -------------------------------------------------------------------------------- /test/0.bn.lua: -------------------------------------------------------------------------------- 1 | -- test bn library 2 | local openssl = require("openssl") 3 | local bn = openssl.bn 4 | 5 | local lu = require("luaunit") 6 | ------------------------------------------------------------------------------ 7 | function testOpenSSL_BIGNUM() 8 | local p, q, m, mx, e, d, t, x, y, message, encoded 9 | assert(type(bn.version) == "string") 10 | 11 | p = bn.random(32) 12 | q = p:totext() 13 | assert(#q == 4 or #q == 3) 14 | 15 | p = bn.aprime(100) 16 | assert(p:bits() == 100) 17 | assert(p:isprime()) 18 | q = bn.aprime(250) 19 | assert(q:bits() == 250) 20 | assert(q:isprime()) 21 | m = p * q 22 | mx = (p - 1) * (q - 1) 23 | e = bn.number("X10001") 24 | d = bn.invmod(e, mx) 25 | assert(bn.mulmod(e, d, mx):isone()) 26 | t = bn.number(2) 27 | x = bn.powmod(t, e, m) 28 | y = bn.powmod(x, d, m) 29 | assert(t == y) 30 | 31 | message = "The quick brown fox jumps over the lazy dog" 32 | encoded = bn.text(message) 33 | assert(message) 34 | assert(encoded < m) 35 | assert(message == bn.totext(encoded)) 36 | 37 | x = bn.powmod(encoded, e, m) 38 | assert(x) 39 | 40 | y = bn.powmod(x, d, m) 41 | assert(y) 42 | assert(y == encoded) 43 | y = bn.totext(y) 44 | assert(y == message) 45 | 46 | d = bn.number( 47 | "X816f0d36f0874f9f2a78acf5643acda3b59b9bcda66775b7720f57d8e9015536160e728230ac529a6a3c935774ee0a2d8061ea3b11c63eed69c9f791c1f8f5145cecc722a220d2bc7516b6d05cbaf38d2ab473a3f07b82ec3fd4d04248d914626d2840b1bd337db3a5195e05828c9abf8de8da4702a7faa0e54955c3a01bf121" 48 | ) 49 | m = bn.number( 50 | "Xbfedeb9c79e1c6e425472a827baa66c1e89572bbfe91e84da94285ffd4c7972e1b9be3da762444516bb37573196e4bef082e5a664790a764dd546e0d167bde1856e9ce6b9dc9801e4713e3c8cb2f12459788a02d2e51ef37121a0f7b086784f0e35e76980403041c3e5e98dfa43ab9e6e85558c5dc00501b2f2a2959a11db21f" 51 | ) 52 | t = bn.number(2) 53 | x = bn.powmod(t, e, m) 54 | y = bn.powmod(x, d, m) 55 | assert(t == y) 56 | 57 | x = bn.number("X10") 58 | y = x:tohex() 59 | assert(y == "10") 60 | y = x:tostring() 61 | assert(y == "16") 62 | y = x:tonumber() 63 | assert(y == 16) 64 | assert(not x:isodd()) 65 | assert(not x:isneg()) 66 | assert(x:compare(16) == 0) 67 | assert(x:sqr():compare(256) == 0) 68 | assert(x:sqrmod(2):compare(0) == 0) 69 | assert(x:sqrtmod(2):compare(0) == 0) 70 | y = x:neg() 71 | assert(y:isneg()) 72 | assert(y:abs():compare(16) == 0) 73 | assert(x:add(1):compare(17) == 0) 74 | 75 | assert(x:div(4):compare(4) == 0) 76 | assert(x:mod(17):compare(x) == 0) 77 | assert(x:mod(18):compare(16) == 0) 78 | p, q = x:divmod(3) 79 | assert(p:compare(5) == 0) 80 | assert(q:compare(1) == 0) 81 | assert(x:gcd(4):compare(4) == 0) 82 | assert(x:pow(2):compare(256) == 0) 83 | assert(x:addmod(1, 18):compare(17) == 0) 84 | assert(x:submod(1, 16):compare(15) == 0) 85 | assert(x:sqrmod(256):compare(0) == 0) 86 | assert(not x:iszero()) 87 | assert(x:rmod(256):compare(16) == 0) 88 | end 89 | -------------------------------------------------------------------------------- /test/8.ssl_s.lua: -------------------------------------------------------------------------------- 1 | local openssl = require("openssl") 2 | local bio, ssl = openssl.bio, openssl.ssl 3 | local sslctx = require("sslctx") 4 | local _, _, opensslv = openssl.version(true) 5 | local host, port, loop 6 | 7 | local arg = assert(arg) 8 | host = arg[1] or "127.0.0.1" -- only ip 9 | port = arg[2] or "8383" 10 | loop = arg[3] and tonumber(arg[3]) or 100 11 | 12 | local params = sslctx.server 13 | local params01 = sslctx.server01 14 | local params02 = sslctx.server02 15 | 16 | local certstore 17 | if opensslv > 0x10002000 then 18 | certstore = openssl.x509.store:new() 19 | local cas = require("root_ca") 20 | for i = 1, #cas do 21 | local cert = assert(openssl.x509.read(cas[i])) 22 | assert(certstore:add(cert)) 23 | end 24 | end 25 | 26 | local function ssl_mode() 27 | local ctx = assert(sslctx.new(params)) 28 | 29 | assert(ctx:verify_mode()) 30 | assert(ctx:verify_depth(9) == 9) 31 | 32 | local ctx01 = assert(sslctx.new(params01)) 33 | local ctx02 = assert(sslctx.new(params02)) 34 | 35 | ctx:set_servername_callback({ 36 | ["servera.br"] = ctx01, 37 | ["serveraa.br"] = ctx02, 38 | }) 39 | 40 | if certstore then 41 | ctx:cert_store(certstore) 42 | end 43 | -- ctx:set_cert_verify({always_continue=true,verify_depth=4}) 44 | ctx:set_cert_verify(function(arg) 45 | -- do some check 46 | --[[ 47 | for k,v in pairs(arg) do 48 | print(k,v) 49 | end 50 | --]] 51 | return true -- return false will fail ssh handshake 52 | end) 53 | if opensslv >= 0x10002000 then 54 | ctx:set_alpn_select_cb(function(protos) 55 | --print('protos', table.concat(protos, ', ')) 56 | return protos[1] 57 | end) 58 | end 59 | 60 | print(string.format("Listen at %s:%s SSL", host, port)) 61 | local srv = assert(bio.accept(host .. ":" .. port)) 62 | local i = 0 63 | if srv then 64 | -- make real listen 65 | if srv:accept(true) then 66 | print("accpeting...") 67 | io.flush() 68 | while i < loop do 69 | local cli = assert(srv:accept()) -- bio tcp 70 | io.write("+") 71 | io.flush() 72 | local s = ctx:ssl(cli, true) 73 | if i % 2 == 0 then 74 | assert(s:handshake()) 75 | else 76 | assert(s:accept()) 77 | end 78 | repeat 79 | local d = s:read() 80 | if d then 81 | assert(#d == s:write(d)) 82 | end 83 | until not d 84 | assert(type(tostring(s)) == "string") 85 | s:shutdown() 86 | cli:close() 87 | cli = nil 88 | assert(cli == nil) 89 | collectgarbage() 90 | i = i + 1 91 | end 92 | end 93 | srv:shutdown() 94 | srv:close() 95 | end 96 | end 97 | 98 | ssl_mode() 99 | print(openssl.errors()) 100 | print("SSL Server done") 101 | 102 | os.exit(0, true) 103 | -------------------------------------------------------------------------------- /test/8.ssl_c.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local bio, ssl = openssl.bio, openssl.ssl 4 | local sslctx = require("sslctx") 5 | local _, _, opensslv = openssl.version(true) 6 | local host, port, loop, name 7 | 8 | local arg = arg 9 | 10 | host = arg[1] or "127.0.0.1" -- only ip 11 | port = arg[2] or "8383" 12 | loop = arg[3] and tonumber(arg[3]) or 100 13 | name = arg[4] 14 | 15 | local params = sslctx.client 16 | 17 | print(string.format("CONNECT to %s:%s", host, port)) 18 | 19 | local certstore = nil 20 | if opensslv > 0x10002000 then 21 | certstore = openssl.x509.store:new() 22 | local cas = require("root_ca") 23 | for i = 1, #cas do 24 | local cert = assert(openssl.x509.read(cas[i])) 25 | assert(certstore:add(cert)) 26 | end 27 | end 28 | 29 | local function mk_connection(_host, _port, i) 30 | local ctx = assert(sslctx.new(params)) 31 | if certstore then 32 | ctx:cert_store(certstore) 33 | end 34 | ctx:verify_mode(ssl.peer, function(_arg) 35 | --[[ 36 | --do some check 37 | for k,v in pairs(arg) do 38 | print(k,v) 39 | end 40 | --]] 41 | return true -- return false will fail ssh handshake 42 | end) 43 | ctx:set_cert_verify(function(arg) 44 | -- do some check 45 | --[[ 46 | for k,v in pairs(arg) do 47 | print(k,v) 48 | end 49 | --]] 50 | return true -- return false will fail ssh handshake 51 | end) 52 | if opensslv >= 0x10002000 then 53 | ctx:set_alpn_protos({ "http/1.1", "h2" }) 54 | end 55 | 56 | local cli = assert(bio.connect(_host .. ":" .. _port, true)) 57 | if cli then 58 | local S = ctx:ssl(cli, false) 59 | if name then 60 | cli:set("hostname", name) 61 | end 62 | if i % 2 == 2 then 63 | assert(S:handshake()) 64 | else 65 | assert(S:connect()) 66 | end 67 | if opensslv >= 0x10002000 then 68 | local proto = S:get_alpn_selected() 69 | if proto then 70 | assert(proto == "http/1.1" or proto == "h2") 71 | end 72 | end 73 | local succ, errs = S:getpeerverification() 74 | if type(errs) == "table" then 75 | for i, err in pairs(errs) do 76 | for j, msg in ipairs(err) do 77 | print("depth = " .. i, "error = " .. msg) 78 | end 79 | end 80 | end 81 | local s = "aaa" 82 | io.write(".") 83 | io.flush() 84 | for _ = 1, 100 do 85 | assert(S:write(s)) 86 | assert(S:read()) 87 | end 88 | local t = S:current_cipher() 89 | assert(type(t) == "table") 90 | assert(S:getfd()) 91 | assert(not S:is_server()) 92 | S:get("side") 93 | S:shutdown() 94 | cli:shutdown() 95 | cli:close() 96 | collectgarbage() 97 | end 98 | openssl.errors() 99 | end 100 | 101 | for i = 1, loop do 102 | mk_connection(host, port, i) 103 | end 104 | 105 | print() 106 | print("SSL Client done") 107 | os.exit(0, true) 108 | -------------------------------------------------------------------------------- /test/0.bio.lua: -------------------------------------------------------------------------------- 1 | local openssl = require("openssl") 2 | local bio = openssl.bio 3 | 4 | local lu = require("luaunit") 5 | ------------------------------------------------------------------------------ 6 | TestBIO = {} 7 | 8 | function TestBIO:testMem() 9 | local m = bio.mem(4) 10 | local s = m:get_mem() 11 | assert(s == "") 12 | 13 | m = bio.mem("abcd") 14 | s = m:get_mem() 15 | assert(s == "abcd") 16 | local rp, wp = m:pending() 17 | assert(rp == 4) 18 | assert(wp == 0) 19 | 20 | m:write("aa") 21 | s = m:read() 22 | assert(s == "abcdaa") 23 | 24 | m:puts("aa") 25 | s = m:gets(1024) 26 | assert(s == "aa") 27 | assert(m:type() == "memory buffer") 28 | m:reset() 29 | end 30 | 31 | function TestBIO:testNetwork() 32 | local cli = bio.connect("kkhub.com", false) 33 | cli:retry() 34 | assert(cli) 35 | cli = bio.connect({ 36 | hostname = "kkhub.com", 37 | port = "12345", 38 | }, false) 39 | assert(cli:nbio(false)) 40 | cli:retry() 41 | assert(cli) 42 | cli = bio.connect() 43 | assert(cli:nbio(true)) 44 | cli:shutdown() 45 | assert(cli) 46 | end 47 | 48 | function TestBIO:testFilter() 49 | local m 50 | 51 | local buf = bio.filter("buffer") 52 | buf:close() 53 | 54 | local b64 = bio.filter("base64") 55 | local mem = bio.mem() 56 | b64 = assert(b64:push(mem)) 57 | b64:write("abcd") 58 | b64:flush() 59 | local s = b64:get_mem() 60 | assert(s == "YWJjZA==\n") 61 | b64:free() 62 | 63 | local md = bio.filter("md", "sha1") 64 | mem = bio.mem("abcd") 65 | md = assert(md:push(mem)) 66 | md:write("abcd") 67 | md:flush() 68 | md, m = md:get_md() 69 | assert(md) 70 | assert(m) 71 | assert(md:next():get_md() == nil) 72 | 73 | md = md:pop() 74 | assert(md) 75 | assert(nil == md:pop()) 76 | md:free() 77 | 78 | m = "1234567812345678" 79 | local cipher = bio.filter("cipher", "aes-128-ecb", "1234567812345678", "1234567812345678", true) 80 | mem = bio.mem() 81 | 82 | cipher = assert(cipher:push(mem)) 83 | mem:write(m) 84 | assert(cipher:cipher_status()) 85 | s = cipher:read() 86 | assert(#s == 16) 87 | cipher:free() 88 | 89 | cipher = bio.filter("cipher", "aes-128-ecb", "1234567812345678", "1234567812345678", false) 90 | mem = bio.mem(s) 91 | 92 | cipher = assert(cipher:push(mem)) 93 | assert(cipher:cipher_status()) 94 | s = cipher:read() 95 | assert(s) 96 | cipher:free() 97 | end 98 | 99 | function TestBIO:testSocket() 100 | local s = bio.socket(555) 101 | s:close() 102 | 103 | local d = bio.dgram(555) 104 | d:close() 105 | 106 | s = bio.accept(899) 107 | s:close() 108 | end 109 | 110 | function TestBIO:testFile() 111 | local f = bio.fd(2) 112 | assert(2 == f:fd()) 113 | assert(1 == f:fd(1)) 114 | f:close() 115 | 116 | f = bio.file("./test.lua") 117 | assert(f:seek(0)) 118 | assert(f:tell()) 119 | f:close() 120 | end 121 | 122 | function TestBIO:testNull() 123 | local n = bio.null() 124 | n:write("abcd") 125 | assert(n:read() == nil) 126 | n:close() 127 | end 128 | -------------------------------------------------------------------------------- /openssl-scm-0.rockspec: -------------------------------------------------------------------------------- 1 | package = "openssl" 2 | version = "scm-0" 3 | rockspec_format = "3.0" 4 | 5 | source = { 6 | url = "https://github.com/zhaozg/lua-openssl/archive/master.zip" 7 | } 8 | 9 | description = { 10 | summary = "Openssl binding for Lua", 11 | homepage = "https://github.com/zhaozg/lua-openssl", 12 | license = "MIT", 13 | maintainer = "George Zhao", 14 | detailed = [[ 15 | Full openssl bindings for luajit and lua 5.1/5.2/5.3/5.4. 16 | 17 | This library makes openssl available to lua scripts. 18 | ]], 19 | } 20 | 21 | dependencies = { 22 | "lua >= 5.1, <= 5.4" 23 | } 24 | 25 | external_dependencies = { 26 | OPENSSL = { 27 | header = "openssl/evp.h" 28 | } 29 | } 30 | 31 | build = { 32 | type = "builtin", 33 | 34 | modules = { 35 | openssl = { 36 | sources = { 37 | "deps/auxiliar/auxiliar.c", 38 | "deps/auxiliar/subsidiar.c", 39 | "src/asn1.c", 40 | "src/bio.c", 41 | "src/callback.c", 42 | "src/cipher.c", 43 | "src/cms.c", 44 | "src/compat.c", 45 | "src/crl.c", 46 | "src/csr.c", 47 | "src/dh.c", 48 | "src/digest.c", 49 | "src/dsa.c", 50 | "src/ec.c", 51 | "src/engine.c", 52 | "src/mac.c", 53 | "src/hmac.c", 54 | "src/kdf.c", 55 | "src/lbn.c", 56 | "src/lhash.c", 57 | "src/misc.c", 58 | "src/ocsp.c", 59 | "src/openssl.c", 60 | "src/ots.c", 61 | "src/param.c", 62 | "src/pkcs7.c", 63 | "src/pkcs12.c", 64 | "src/pkey.c", 65 | "src/rsa.c", 66 | "src/srp.c", 67 | "src/ssl.c", 68 | "src/th-lock.c", 69 | "src/util.c", 70 | "src/x509.c", 71 | "src/xalgor.c", 72 | "src/xattrs.c", 73 | "src/xexts.c", 74 | "src/xname.c", 75 | "src/xstore.c" 76 | }, 77 | incdirs = {"$(OPENSSL_DIR)/include", "deps/auxiliar", "deps/lua-compat/c-api"}, 78 | defines = {}, 79 | libraries = {"ssl", "crypto"}, 80 | } 81 | }, 82 | 83 | platforms = { 84 | windows = { 85 | modules = { 86 | openssl = { 87 | libraries = {"libeay32", "ssleay32", "ws2_32", "kernel32", "user32", "gdi32", "advapi32"}, 88 | defines = {"LUA_BUILD_AS_DLL", "LUA_LIB", "WIN32_LEAN_AND_MEAN"}, 89 | incdirs = {"$(OPENSSL_DIR)/include"}, 90 | libdirs = {"$(OPENSSL_DIR)/lib"}, 91 | } 92 | } 93 | }, 94 | linux = { 95 | modules = { 96 | openssl = { 97 | incdirs = {"$(OPENSSL_DIR)/include"}, 98 | libdirs = {"$(OPENSSL_DIR)/lib"}, 99 | } 100 | } 101 | }, 102 | macosx = { 103 | modules = { 104 | openssl = { 105 | incdirs = {"$(OPENSSL_DIR)/include"}, 106 | libdirs = {"$(OPENSSL_DIR)/lib"}, 107 | } 108 | } 109 | } 110 | }, 111 | } 112 | 113 | test = { 114 | type = "command", 115 | command = "LUA=`luarocks config LUA` && cd test && $LUA test.lua" 116 | } 117 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '21 12 * * 2' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'cpp' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Use only 'java' to analyze code written in Java, Kotlin or both 38 | # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both 39 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 40 | 41 | steps: 42 | - name: Checkout repository 43 | uses: actions/checkout@v4 44 | with: 45 | submodules: recursive 46 | 47 | # Initializes the CodeQL tools for scanning. 48 | - name: Initialize CodeQL 49 | uses: github/codeql-action/init@v3 50 | with: 51 | languages: ${{ matrix.language }} 52 | # If you wish to specify custom queries, you can do so here or in a config file. 53 | # By default, queries listed here will override any specified in a config file. 54 | # Prefix the list here with "+" to use these queries and those in the config file. 55 | 56 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 57 | # queries: security-extended,security-and-quality 58 | 59 | 60 | - name: depends 61 | run: sudo apt update && sudo apt install -y libssl-dev luajit libluajit-5.1-dev 62 | 63 | - name: run 64 | run: make test 65 | 66 | # ℹ️ Command-line programs to run using the OS shell. 67 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 68 | 69 | # If the Autobuild fails above, remove it and uncomment the following three lines. 70 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 71 | 72 | # - run: | 73 | # echo "Run, Build Application using script" 74 | # ./location_of_script_within_repo/buildscript.sh 75 | 76 | - name: Perform CodeQL Analysis 77 | uses: github/codeql-action/analyze@v2 78 | with: 79 | category: "/language:${{matrix.language}}" 80 | -------------------------------------------------------------------------------- /test/6.pkcs7.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | 3 | local openssl = require("openssl") 4 | local pkcs7 = openssl.pkcs7 5 | local helper = require("helper") 6 | 7 | TestPKCS7 = {} 8 | function TestPKCS7:setUp() 9 | self.alg = "sha1" 10 | self.dn = { { commonName = "DEMO" }, { C = "CN" } } 11 | 12 | self.digest = "sha1WithRSAEncryption" 13 | end 14 | 15 | function TestPKCS7:testNew() 16 | local ca = helper.get_ca() 17 | local store = ca:get_store() 18 | assert(store:trust(true)) 19 | store:add(ca.cacert) 20 | store:add(ca.crl) 21 | 22 | local e = openssl.x509.extension.new_extension({ object = "keyUsage", value = "smimesign" }, false) 23 | assert(e) 24 | local extensions = { 25 | { 26 | object = "nsCertType", 27 | value = "email", 28 | -- critical = true 29 | }, 30 | { object = "extendedKeyUsage", value = "emailProtection" }, 31 | } 32 | -- extensions:push(e) 33 | 34 | local cert, pkey = helper.sign(self.dn, extensions) 35 | 36 | local msg = "abcd" 37 | 38 | local skcert = { cert } 39 | local p7 = assert(pkcs7.encrypt(msg, skcert)) 40 | local ret = assert(pkcs7.decrypt(p7, cert, pkey)) 41 | lu.assertEquals(msg, ret) 42 | assert(p7:parse()) 43 | ------------------------------------- 44 | p7 = assert(pkcs7.sign(msg, cert, pkey)) 45 | assert(p7:export()) 46 | ret = assert(p7:verify(skcert, store)) 47 | assert(ret == msg) 48 | assert(p7:parse()) 49 | 50 | p7 = assert(pkcs7.sign(msg, cert, pkey, nil, openssl.pkcs7.DETACHED)) 51 | assert(p7:export()) 52 | ret = assert(p7:verify(skcert, store, msg, openssl.pkcs7.DETACHED)) 53 | assert(type(ret) == "boolean") 54 | assert(ret) 55 | assert(p7:parse()) 56 | 57 | local der = assert(p7:export("der")) 58 | p7 = assert(openssl.pkcs7.read(der, "der")) 59 | 60 | der = assert(p7:export("smime")) 61 | p7 = assert(openssl.pkcs7.read(der, "smime")) 62 | 63 | der = assert(p7:export()) 64 | assert(openssl.pkcs7.read(der, "auto")) 65 | 66 | local p = openssl.pkcs7.new("signed", "data") 67 | p:add(ca.cacert) 68 | p:add(cert) 69 | p:add(ca.crl) 70 | assert(p:parse()) 71 | -- FIXME: illegal zero content 72 | -- assert(p:export()) 73 | -- assert(p:export('der')) 74 | local ln, sn = p:type() 75 | assert(ln) 76 | assert(sn) 77 | 78 | p7 = openssl.pkcs7.create({ 79 | ca.cacert, 80 | cert, 81 | }, { ca.crl }) 82 | assert(p7:parse()) 83 | 84 | -- TODO: enable below 85 | -- p7:set_content(p) 86 | 87 | -- FIXME: illegal zero content 88 | -- assert(p7:export()) 89 | -- assert(p7:export('der')) 90 | ln, sn = p7:type() 91 | assert(ln) 92 | assert(sn) 93 | end 94 | 95 | function TestPKCS7:testData() 96 | local p = openssl.pkcs7.new("signed", "data") 97 | assert(p:final("content")) 98 | local conent = p:parse().contents:parse() 99 | 100 | assert("content" == conent.data:tostring()) 101 | end 102 | 103 | function TestPKCS7:testDigest() 104 | local p = openssl.pkcs7.new("signed", "data") 105 | assert(p:set_digest("sha256")) 106 | assert(p:final("content")) 107 | local conent = p:parse().contents:parse() 108 | 109 | assert("content" == conent.data:tostring()) 110 | end 111 | -------------------------------------------------------------------------------- /cmake/Modules/FindLuaJIT.cmake: -------------------------------------------------------------------------------- 1 | # Locate Lua library This module defines LUAJIT_FOUND, if false, do not try to 2 | # link to Lua LUAJIT_LIBRARIES LUAJIT_INCLUDE_DIRS, where to find lua.h 3 | # 4 | # Note that the expected include convention is #include "lua.h" and not #include 5 | # This is because, the lua location is not standardized and may 6 | # exist in locations other than lua/ 7 | 8 | # ============================================================================= 9 | # Copyright 2007-2009 Kitware, Inc. 10 | # 11 | # Distributed under the OSI-approved BSD License (the "License"); see 12 | # accompanying file Copyright.txt for details. 13 | # 14 | # This software is distributed WITHOUT ANY WARRANTY; without even the implied 15 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # License for more information. 17 | # ============================================================================= 18 | # (To distributed this file outside of CMake, substitute the full License text 19 | # for the above reference.) 20 | # 21 | # ############################################################################## 22 | # 2010 - modified for cronkite to find luajit instead of lua, as it was before. 23 | # 24 | 25 | find_path( 26 | LUAJIT_INCLUDE_DIRS lua.h 27 | PATHS /usr/local/include/luajit-2.0 28 | /usr/local/include/luajit2.0 29 | /usr/local/include/luajit-2.1 30 | /usr/local/include/luajit2.1 31 | /usr/local/include/luajit 32 | /usr/include/luajit-2.0 33 | /usr/include/luajit2.0 34 | /usr/include/luajit-2.1 35 | /usr/include/luajit2.1 36 | /usr/include/luajit 37 | /opt/include/luajit-2.0 38 | /opt/include/luajit2.0 39 | /opt/include/luajit-2.1 40 | /opt/include/luajit2.1 41 | /opt/include/luajit 42 | NO_DEFAULT_PATH) 43 | 44 | find_library( 45 | LUAJIT_LIBRARY 46 | NAMES luajit-51 luajit-5.1 luajit 47 | HINTS $ENV{LUAJIT_ROOT_DIR} 48 | PATH_SUFFIXES lib64 lib 49 | PATHS ~/Library/Frameworks 50 | /Library/Frameworks 51 | /usr/local 52 | /usr 53 | /sw 54 | /opt/local 55 | /opt/csw 56 | /opt) 57 | 58 | if(LUAJIT_LIBRARY) 59 | # include the math library for Unix 60 | if(UNIX AND NOT APPLE) 61 | find_library(LUAJIT_MATH_LIBRARY m) 62 | set(LUAJIT_LIBRARIES 63 | "${LUAJIT_LIBRARY};${LUAJIT_MATH_LIBRARY}" 64 | CACHE STRING "Lua Libraries") 65 | # For Windows and Mac, don't need to explicitly include the math library 66 | else() 67 | set(LUAJIT_LIBRARIES 68 | "${LUAJIT_LIBRARY}" 69 | CACHE STRING "Lua Libraries") 70 | endif() 71 | set(LUA_INCLUDE_DIR ${LUAJIT_INCLUDE_DIRS}) 72 | set(LUA_LIBRARIES ${LUAJIT_LIBRARIES}) 73 | set(LUA_VERSION_MAJOR "5") 74 | set(LUA_VERSION_MINOR "1") 75 | set(LUAJIT_FOUND ON) 76 | else() 77 | set(LUAJIT_FOUND OFF) 78 | endif() 79 | 80 | include(FindPackageHandleStandardArgs) 81 | # handle the QUIETLY and REQUIRED arguments and set LUAJIT_FOUND to TRUE if all 82 | # listed variables are TRUE 83 | find_package_handle_standard_args(LuaJIT DEFAULT_MSG LUAJIT_LIBRARIES 84 | LUAJIT_INCLUDE_DIRS) 85 | 86 | mark_as_advanced(LUAJIT_INCLUDE_DIRS LUAJIT_LIBRARIES LUAJIT_LIBRARY 87 | LUAJIT_MATH_LIBRARY) 88 | -------------------------------------------------------------------------------- /test/helper.lua: -------------------------------------------------------------------------------- 1 | local openssl = require("openssl") 2 | local ca = require("utils.ca") 3 | 4 | local M = {} 5 | 6 | M.luaopensslv, M.luav, M.opensslv = openssl.version() 7 | M._luaopensslv, M._luav, M._opensslv = openssl.version(true) 8 | M.libressl = M.opensslv:find("^LibreSSL") 9 | M.openssl3 = M.opensslv:find("^OpenSSL 3") 10 | 11 | function M.sslProtocol(srv, protocol) 12 | protocol = protocol or openssl.ssl.default 13 | if M.opensslv:match("1.0.2") then 14 | protocol = protocol:gsub("DTLS", "DTLSv1_2") 15 | end 16 | if srv == true then 17 | return protocol .. "_server" 18 | elseif srv == false then 19 | return protocol .. "_client" 20 | elseif srv == nil then 21 | return protocol 22 | end 23 | assert(nil) 24 | end 25 | 26 | function M.supportTLSv1_3() 27 | return M._opensslv > 0x10100000 28 | end 29 | 30 | function M.get_ca() 31 | if not M.ca then 32 | M.ca = ca:new() 33 | end 34 | return M.ca 35 | end 36 | 37 | function M.new_req(subject, exts, attrs) 38 | local pkey = openssl.pkey.new() 39 | if type(subject) == "table" then 40 | subject = openssl.x509.name.new(subject) 41 | end 42 | local req = assert(openssl.x509.req.new(subject)) 43 | if exts then 44 | req:extensions(exts) 45 | end 46 | if attrs then 47 | req:attributes(attrs) 48 | end 49 | assert(req:sign(pkey)) 50 | return req, pkey 51 | end 52 | 53 | function M.sign(subject, extensions) 54 | local CA = M.get_ca() 55 | if not type(subject):match("x509.req") then 56 | local req, pkey = M.new_req(subject) 57 | local cert = CA:sign(req, extensions) 58 | return cert, pkey 59 | end 60 | return CA:sign(subject, extensions) 61 | end 62 | 63 | function M.spawn(cmd, args, pattern, after_start, after_close, env) 64 | local uv = require("luv") 65 | env = env or {} 66 | if os.getenv("ASAN_LIB") then 67 | env[#env + 1] = "DYLD_INSERT_LIBRARIES=" .. os.getenv("ASAN_LIB") 68 | end 69 | env[#env + 1] = "LUA_CPATH=" .. package.cpath 70 | env[#env + 1] = "LUA_PATH=" .. package.path 71 | 72 | local function stderr_read(err, chunk) 73 | assert(not err, err) 74 | if chunk then 75 | io.write(chunk) 76 | io.flush() 77 | end 78 | end 79 | 80 | local resutls = "" 81 | local function stdout_read(err, chunk) 82 | assert(not err, err) 83 | if chunk then 84 | io.write(chunk) 85 | io.flush() 86 | resutls = resutls .. chunk 87 | if pattern and resutls:match(pattern) then 88 | print("matched.ing") 89 | if after_start then 90 | after_start() 91 | end 92 | resutls = "" 93 | end 94 | end 95 | end 96 | 97 | local stdin = uv.new_pipe(false) 98 | local stdout = uv.new_pipe(false) 99 | local stderr = uv.new_pipe(false) 100 | 101 | local handle, pid 102 | handle, pid = assert(uv.spawn(cmd, { 103 | args = args, 104 | env = env, 105 | cwd = uv.cwd(), 106 | stdio = { stdin, stdout, stderr }, 107 | }, function(code, signal) 108 | uv.close(handle) 109 | if after_close then 110 | after_close(code, signal) 111 | end 112 | end)) 113 | uv.read_start(stdout, stdout_read) 114 | uv.read_start(stderr, stderr_read) 115 | return handle, pid 116 | end 117 | 118 | return M 119 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # .clang-format 2 | # ======================================== 3 | # 基础配置 4 | # ======================================== 5 | BasedOnStyle: GNU 6 | Language: C # 关键:显式声明为 C 语言项目 7 | ColumnLimit: 100 # 单行最大宽度(Google 默认 80,适当放宽) 8 | IndentWidth: 2 # 缩进宽度为 2 空格 9 | UseTab: Never # 禁止使用 Tab,强制空格缩进 10 | TabWidth: 8 # Tab 显示宽度(仅影响编辑器显示) 11 | 12 | ConstructorInitializerIndentWidth: 2 13 | ContinuationIndentWidth: 2 14 | 15 | # ======================================== 16 | # 大括号与代码块格式 17 | # ======================================== 18 | BreakBeforeBraces: Custom # Linux 内核风格(函数左大括号不换行) 19 | AllowShortFunctionsOnASingleLine: Empty # 仅空函数体单行显示(如 `void init() {}`) 20 | AllowShortIfStatementsOnASingleLine: WithoutElse # 无 else 的短 if 可单行(如 `if (x) return;`) 21 | AllowShortLoopsOnASingleLine: true # 允许短循环单行(如 `while (p) p = p->next;`) 22 | AlignEscapedNewlinesLeft: false 23 | PenaltyReturnTypeOnItsOwnLine: 200 24 | AllowAllParametersOfDeclarationOnNextLine: false 25 | AlignArrayOfStructures: Left 26 | 27 | # ======================================== 28 | # 控制数组/结构体初始化换行和对齐 29 | # ======================================== 30 | AlignConsecutiveDeclarations: true # 对齐连续声明(字段对齐) 31 | BraceWrapping: 32 | AfterStruct: true # 结构体定义后换行 33 | AfterEnum: true 34 | AfterFunction: true 35 | AfterClass: true 36 | AfterUnion: true 37 | AfterControlStatement: MultiLine 38 | AfterObjCDeclaration: true 39 | BeforeCatch: false 40 | BeforeElse: false 41 | IndentBraces: false 42 | 43 | # ======================================== 44 | # 指针与空格规则 45 | # ======================================== 46 | PointerAlignment: Right # 指针右对齐(如 `char *ptr;`) 47 | SpaceBeforeParens: ControlStatementsExceptControlMacros # 控制语句括号前加空格(如 `if (...)`) 48 | 49 | # ======================================== 50 | # 函数与参数格式 51 | # ======================================== 52 | BinPackParameters: false # 函数参数每行一个(提高可读性) 53 | BinPackArguments: false # 函数调用参数每行一个 54 | 55 | # ======================================== 56 | # 预处理指令 57 | # ======================================== 58 | IndentPPDirectives: None # 预处理指令不缩进(如 `#ifdef` 顶格) 59 | PPIndentWidth: 0 # 预处理指令缩进宽度为 0 60 | 61 | # ======================================== 62 | # 头文件排序规则 63 | # ======================================== 64 | SortIncludes: true # 启用头文件排序 65 | IncludeCategories: 66 | - Regex: '' # 优先级 0:OpenSSL 系统头文件 67 | Priority: 0 68 | - Regex: '^"lua_.*' # 优先级 1:Lua 绑定头文件 69 | Priority: 1 70 | - Regex: '^".*' # 优先级 2:其他项目头文件 71 | Priority: 2 72 | 73 | # ======================================== 74 | # 注释对齐 75 | # ======================================== 76 | AlignTrailingComments: false # 禁用行尾注释对齐(减少格式干扰) 77 | SpacesBeforeTrailingComments: 2 # 行尾注释前保留 2 空格(如 `code(); // comment`) 78 | 79 | # ======================================== 80 | # 其他关键配置 81 | # ======================================== 82 | IndentCaseLabels: false # case 标签不额外缩进(与 switch 对齐) 83 | BreakBeforeBinaryOperators: true # 在二元运算符前换行(如 `a && b` 换行为 `a\n&& b`) 84 | BreakBeforeTernaryOperators: true # 在三元运算符前换行(如 `a ? b : c` 换行为 `a\n? b : c`) 85 | AlignConsecutiveMacros: AcrossEmptyLines # 连续宏跨空行对齐 86 | ForEachMacros: 87 | - TAB2SK 88 | - SK2TAB 89 | -------------------------------------------------------------------------------- /test/0.misc.lua: -------------------------------------------------------------------------------- 1 | local openssl = require("openssl") 2 | local helper = require("helper") 3 | local lu = require("luaunit") 4 | 5 | local msg = "The quick brown fox jumps over the lazy dog." 6 | 7 | function testHex() 8 | local ano = openssl.hex(msg) 9 | lu.assertEquals(openssl.hex(msg, true), ano) 10 | local raw = openssl.hex(ano, false) 11 | lu.assertEquals(raw, msg) 12 | lu.assertEquals(#msg * 2, #ano) 13 | lu.assertEquals("", openssl.hex("")) 14 | end 15 | 16 | function testBase64() 17 | local ano = openssl.base64(msg) 18 | -- default without newline 19 | assert(#ano > #msg) 20 | assert(not string.find(ano, "\n")) 21 | lu.assertEquals(openssl.base64(msg, true), ano) 22 | local raw = openssl.base64(ano, false) 23 | lu.assertEquals(raw, msg) 24 | 25 | -- without newline 26 | ano = openssl.base64(msg, true, true) 27 | assert(#ano > #msg) 28 | assert(not string.find(ano, "\n")) 29 | lu.assertEquals(openssl.base64(msg, true, true), ano) 30 | raw = openssl.base64(ano, false, true) 31 | lu.assertEquals(raw, msg) 32 | 33 | -- with newline 34 | ano = openssl.base64(msg, true, false) 35 | assert(#ano > #msg) 36 | assert(string.find(ano, "\n")) 37 | lu.assertEquals(openssl.base64(msg, true, false), ano) 38 | raw = openssl.base64(ano, false, false) 39 | lu.assertEquals(raw, msg) 40 | 41 | ano = openssl.base64(msg) 42 | -- default without newline 43 | assert(#ano > #msg) 44 | assert(not string.find(ano, "\n")) 45 | lu.assertEquals(openssl.base64(msg, true), ano) 46 | raw = openssl.base64(ano, false) 47 | lu.assertEquals(raw, msg) 48 | 49 | -- without newline 50 | ano = openssl.base64(msg, true, true) 51 | assert(#ano > #msg) 52 | assert(not string.find(ano, "\n")) 53 | lu.assertEquals(openssl.base64(msg, true, true), ano) 54 | raw = openssl.base64(ano, false, true) 55 | lu.assertEquals(raw, msg) 56 | 57 | -- with newline 58 | ano = openssl.base64(msg, true, false) 59 | assert(#ano > #msg) 60 | assert(string.find(ano, "\n")) 61 | lu.assertEquals(openssl.base64(msg, true, false), ano) 62 | raw = openssl.base64(ano, false, false) 63 | lu.assertEquals(raw, msg) 64 | end 65 | 66 | function testAll() 67 | local t = openssl.list("digests") 68 | assert(type(t) == "table") 69 | if not helper.openssl3 and not helper.libressl then 70 | assert(type(openssl.FIPS_mode()) == "boolean") 71 | end 72 | local rand = openssl.random(1024) 73 | openssl.rand_add(rand) 74 | openssl.random(16, true) 75 | 76 | local f = io.open("certs/ca2.cnf", "r") 77 | if f then 78 | local data = f:read("*a") 79 | f:close() 80 | 81 | if not openssl.lhash_read then 82 | return 83 | end 84 | 85 | local conf = assert(openssl.lhash_read(data)) 86 | local t = conf:parse(false) 87 | lu.assertIsTable(t) 88 | -- print_r(t) 89 | t = conf:parse() 90 | lu.assertIsTable(t) 91 | 92 | t = conf:parse(true) 93 | lu.assertIsTable(t) 94 | 95 | assert(conf:get_string("ca", "default_ca") == "CA_default") 96 | assert(conf:get_number("CA_default", "default_crl_days") == 999) 97 | assert(conf:get_number("req", "default_bits") == 1024) 98 | 99 | local c1 = openssl.lhash_load("certs/ca1.cnf") 100 | t = c1:parse() 101 | assert(type(c1:export()) == "string") 102 | lu.assertIsTable(t) 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /src/openssl.h: -------------------------------------------------------------------------------- 1 | /* vim: set filetype=c : */ 2 | 3 | /*=========================================================================*\ 4 | * x509 routines 5 | * lua-openssl toolkit 6 | * 7 | * This product includes PHP software, freely available from 8 | * Author: george zhao 9 | \*=========================================================================*/ 10 | #ifndef LUA_EAY_H 11 | #define LUA_EAY_H 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | /* OpenSSL includes */ 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #if !defined(OPENSSL_NO_COMP) 27 | #include 28 | #endif 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | /*- 38 | * Numeric release version identifier: 39 | * MNNFFPPS: major minor fix patch status 40 | * The status nibble has one of the values 0 for development, 1 to e for betas 41 | * 1 to 14, and f for release. The patch level is exactly that. 42 | * For example: 43 | * 0.9.3-dev 0x00903000 44 | * 0.9.3-beta1 0x00903001 45 | * 0.9.3-beta2-dev 0x00903002 46 | * 0.9.3-beta2 0x00903002 (same as ...beta2-dev) 47 | * 0.9.3 0x0090300f 48 | * 0.9.3a 0x0090301f 49 | * 0.9.4 0x0090400f 50 | * 1.2.3z 0x102031af 51 | */ 52 | 53 | /*History 54 | 2017-04-18 update to 0.7.1 55 | 2017-08-04 update to 0.7.3 56 | 2019-03-24 update to 0.7.5-1 57 | 2019-05-19 update to 0.7.5-2 58 | 2019-08-20 update to 0.7.6 59 | */ 60 | 61 | /* MNNFFPPS */ 62 | #define LOPENSSL_VERSION_NUM 0x00a0100f 63 | #ifndef LOPENSSL_VERSION 64 | #define LOPENSSL_VERSION "0.10.2" 65 | #endif 66 | 67 | #if OPENSSL_VERSION_NUMBER >= 0x10000000L 68 | #include 69 | #define OPENSSL_HAVE_TS 70 | #define LHASH LHASH_OF(CONF_VALUE) 71 | #endif 72 | 73 | 74 | 75 | int openssl_s2i_revoke_reason(const char*s); 76 | 77 | LUALIB_API int luaopen_openssl(lua_State *L); 78 | int luaopen_digest(lua_State *L); 79 | int luaopen_hmac(lua_State *L); 80 | int luaopen_cipher(lua_State *L); 81 | int luaopen_bn(lua_State *L); 82 | int luaopen_pkey(lua_State *L); 83 | int luaopen_x509(lua_State *L); 84 | int luaopen_pkcs7(lua_State *L); 85 | int luaopen_pkcs12(lua_State *L); 86 | int luaopen_bio(lua_State *L); 87 | int luaopen_asn1(lua_State *L); 88 | 89 | int luaopen_ts(lua_State *L); 90 | int luaopen_x509_req(lua_State *L); 91 | int luaopen_x509_crl(lua_State *L); 92 | int luaopen_ocsp(lua_State *L); 93 | int luaopen_cms(lua_State *L); 94 | int luaopen_ssl(lua_State *L); 95 | int luaopen_ec(lua_State *L); 96 | int luaopen_group(lua_State *L); 97 | int luaopen_point(lua_State *L); 98 | int luaopen_rsa(lua_State *L); 99 | int luaopen_dsa(lua_State *L); 100 | int luaopen_dh(lua_State *L); 101 | #if (OPENSSL_VERSION_NUMBER >= 0x30000000L) && !defined(LIBRESSL_VERSION_NUMBER) 102 | int luaopen_mac(lua_State *L); 103 | int luaopen_param(lua_State *L); 104 | int luaopen_provider(lua_State *L); 105 | #endif 106 | int luaopen_kdf(lua_State *L); 107 | int luaopen_srp(lua_State *L); 108 | 109 | #endif 110 | -------------------------------------------------------------------------------- /src/point.c: -------------------------------------------------------------------------------- 1 | /*** 2 | EC_POINT module for Lua OpenSSL binding. 3 | 4 | This module provides a complete wrapper for OpenSSL's EC_POINT operations, 5 | enabling elliptic curve point mathematical operations. 6 | 7 | @module ec.point 8 | @usage 9 | point = require('openssl').ec.point 10 | */ 11 | 12 | /* This file is included in ec.c */ 13 | 14 | #define MYTYPE_POINT "openssl.ec_point" 15 | #define MYVERSION_POINT MYTYPE_POINT " library for " LUA_VERSION " / Nov 2024" 16 | 17 | /*** 18 | Create a new EC point on a given group. 19 | 20 | @function new 21 | @tparam ec_group group the EC group 22 | @treturn ec_point new elliptic curve point (at infinity) 23 | @usage 24 | group = require('openssl').group 25 | point = require('openssl').point 26 | g = group.new('prime256v1') 27 | p = point.new(g) 28 | */ 29 | 30 | /*** 31 | Copy one EC point to another. 32 | 33 | @function copy 34 | @tparam ec_point dest destination point 35 | @tparam ec_point src source point 36 | @treturn ec_point destination point (self) 37 | */ 38 | int openssl_point_copy(lua_State *L) 39 | { 40 | EC_POINT *dest = CHECK_OBJECT(1, EC_POINT, MYTYPE_POINT); 41 | const EC_POINT *src = CHECK_OBJECT(2, EC_POINT, MYTYPE_POINT); 42 | 43 | if (EC_POINT_copy(dest, src)) { 44 | lua_pushvalue(L, 1); 45 | return 1; 46 | } 47 | 48 | return 0; 49 | } 50 | 51 | int openssl_point_free(lua_State *L) 52 | { 53 | EC_POINT *point = CHECK_OBJECT(1, EC_POINT, MYTYPE_POINT); 54 | EC_POINT_free(point); 55 | return 0; 56 | } 57 | 58 | /*** 59 | Convert EC point to string (internal, called by __tostring). 60 | 61 | @function tostring 62 | @treturn string string representation 63 | */ 64 | static int openssl_point_tostring(lua_State *L) 65 | { 66 | lua_pushfstring(L, "openssl.ec_point: %p", lua_touserdata(L, 1)); 67 | return 1; 68 | } 69 | 70 | /* Method table */ 71 | static luaL_Reg point_methods[] = { 72 | /* Object methods */ 73 | {"copy", openssl_point_copy}, 74 | 75 | /* Metamethods */ 76 | {"__gc", openssl_point_free}, 77 | {"__tostring", auxiliar_tostring}, 78 | 79 | {NULL, NULL} 80 | }; 81 | 82 | /* Module functions */ 83 | static luaL_Reg point_functions[] = { 84 | {"new", openssl_group_point_new}, 85 | {"dup", openssl_group_point_dup}, 86 | {"equal", openssl_group_point_equal}, 87 | {"add", openssl_point_add}, 88 | {"dbl", openssl_point_dbl}, 89 | {"invert", openssl_point_invert}, 90 | {"mul", openssl_point_mul}, 91 | 92 | {"is_at_infinity", openssl_point_is_at_infinity}, 93 | {"is_on_curve", openssl_point_is_on_curve}, 94 | 95 | {"point2oct", openssl_group_point2oct}, 96 | {"oct2point", openssl_group_oct2point}, 97 | {"point2bn", openssl_group_point2bn}, 98 | {"bn2point", openssl_group_bn2point}, 99 | {"point2hex", openssl_group_point2hex}, 100 | {"hex2point", openssl_group_hex2point}, 101 | 102 | {"affine_coordinates", openssl_group_affine_coordinates}, 103 | {"set_to_infinity", openssl_point_set_to_infinity}, 104 | 105 | {NULL, NULL} 106 | }; 107 | 108 | int 109 | luaopen_ec_point(lua_State *L) { 110 | auxiliar_newclass(L, MYTYPE_POINT, point_methods); 111 | lua_newtable(L); 112 | luaL_setfuncs(L, point_functions, 0); 113 | return 1; 114 | } 115 | 116 | -------------------------------------------------------------------------------- /.github/shell/setup_lua.sh: -------------------------------------------------------------------------------- 1 | #MACOSX_DEPLOYMENT_TARGET! /bin/bash 2 | 3 | # A script for setting up environment for travis-ci testing. 4 | # Sets up Lua and Luarocks. 5 | # LUA must be "lua5.1", "lua5.2" or "luajit". 6 | # luajit2.0 - master v2.0 7 | # luajit2.1 - master v2.1 8 | 9 | set -eufo pipefail 10 | 11 | LUAJIT_VERSION="2.0.5" 12 | LUAJIT_BASE="LuaJIT-$LUAJIT_VERSION" 13 | 14 | LUA_HOME_DIR=$HOME/.usr 15 | LR_HOME_DIR=$HOME/.usr 16 | 17 | LUAJIT="no" 18 | PLATFORM=linux 19 | 20 | if [ "$RUNNER_OS" == "macOS" ]; then 21 | if [ "$LUA" == "luajit" ]; then 22 | LUAJIT="yes" 23 | fi 24 | if [ "$LUA" == "luajit2.0" ]; then 25 | LUAJIT="yes" 26 | fi 27 | if [ "$LUA" == "luajit2.1" ]; then 28 | LUAJIT="yes" 29 | fi 30 | PLATFORM=macosx 31 | elif [ "$(expr substr $LUA 1 6)" == "luajit" ]; then 32 | LUAJIT="yes" 33 | fi 34 | 35 | mkdir -p "$LUA_HOME_DIR" 36 | 37 | if [ "$LUAJIT" == "yes" ]; then 38 | 39 | if [ "$LUA" == "luajit" ]; then 40 | curl --location https://github.com/LuaJIT/LuaJIT/archive/v$LUAJIT_VERSION.tar.gz | tar xz 41 | else 42 | git clone https://github.com/LuaJIT/LuaJIT.git $LUAJIT_BASE 43 | fi 44 | 45 | cd $LUAJIT_BASE 46 | 47 | if [ "$LUA" == "luajit2.1" ]; then 48 | git checkout v2.1 49 | fi 50 | 51 | make && make install PREFIX="$LUA_HOME_DIR" 52 | ln -s $LUA_HOME_DIR/bin/luajit $LUA_HOME_DIR/bin/lua 53 | else 54 | 55 | if [ "$LUA" == "lua5.1" ]; then 56 | curl https://www.lua.org/ftp/lua-5.1.5.tar.gz | tar xz 57 | cd lua-5.1.5 58 | elif [ "$LUA" == "lua5.2" ]; then 59 | curl https://www.lua.org/ftp/lua-5.2.4.tar.gz | tar xz 60 | cd lua-5.2.4 61 | elif [ "$LUA" == "lua5.3" ]; then 62 | curl https://www.lua.org/ftp/lua-5.3.6.tar.gz | tar xz 63 | cd lua-5.3.6 64 | elif [ "$LUA" == "lua5.4" ]; then 65 | curl https://www.lua.org/ftp/lua-5.4.8.tar.gz | tar xz 66 | cd lua-5.4.8 67 | fi 68 | 69 | if [ "$PLATFORM" == "linux" ]; then 70 | sudo apt-get -y update 71 | sudo apt install -y libreadline-dev 72 | fi 73 | 74 | # Build Lua without backwards compatibility for testing 75 | perl -i -pe 's/-DLUA_COMPAT_(ALL|5_2)//' src/Makefile 76 | make $PLATFORM 77 | make INSTALL_TOP="$LUA_HOME_DIR" install 78 | fi 79 | 80 | export PATH=$LUA_HOME_DIR/bin:$PATH 81 | 82 | lua -v 83 | 84 | if [[ -n "$LUAROCKS" ]]; then 85 | LUAROCKS_BASE=luarocks-$LUAROCKS 86 | 87 | curl --location https://luarocks.org/releases/$LUAROCKS_BASE.tar.gz | tar xz 88 | 89 | cd $LUAROCKS_BASE 90 | 91 | if [ "$LUA" == "luajit" ]; then 92 | ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.0" --prefix="$LR_HOME_DIR" 93 | elif [ "$LUA" == "luajit2.0" ]; then 94 | ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.0" --prefix="$LR_HOME_DIR" 95 | elif [ "$LUA" == "luajit2.1" ]; then 96 | ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.1" --prefix="$LR_HOME_DIR" 97 | else 98 | ./configure --with-lua="$LUA_HOME_DIR" --prefix="$LR_HOME_DIR" 99 | fi 100 | 101 | make build && make install 102 | 103 | luarocks --version 104 | 105 | rm -rf $LUAROCKS_BASE 106 | fi 107 | 108 | if [ "$LUAJIT" == "yes" ]; then 109 | rm -rf $LUAJIT_BASE 110 | elif [ "$LUA" == "lua5.1" ]; then 111 | rm -rf lua-5.1.5 112 | elif [ "$LUA" == "lua5.2" ]; then 113 | rm -rf lua-5.2.4 114 | elif [ "$LUA" == "lua5.3" ]; then 115 | rm -rf lua-5.3.6 116 | elif [ "$LUA" == "lua5.4" ]; then 117 | rm -rf lua-5.4.8 118 | fi 119 | -------------------------------------------------------------------------------- /test/sm2.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local pkey = openssl.pkey 4 | local unpack = unpack or table.unpack 5 | local helper = require("helper") 6 | 7 | local _, _, opensslv = openssl.version(true) 8 | if opensslv <= 0x3000a000 or helper.libressl then 9 | print("SKIP SM2") 10 | return 11 | end 12 | 13 | TestSM2 = {} 14 | 15 | function TestSM2:TestSM2() 16 | local nec = { "ec", "SM2" } 17 | 18 | local ec = pkey.new(unpack(nec)) 19 | local t = ec:parse() 20 | if helper.openssl3 then 21 | lu.assertEquals(t.type, "SM2") 22 | t = t.sm2:parse(true) --make basic table 23 | else 24 | lu.assertEquals(t.type, "EC") 25 | t = t.ec:parse(true) --make basic table 26 | end 27 | lu.assertEquals(type(t.curve_name), "number") 28 | lu.assertStrContains(t.x.version, "bn library") 29 | lu.assertStrContains(t.y.version, "bn library") 30 | lu.assertStrContains(t.d.version, "bn library") 31 | 32 | local k1 = pkey.get_public(ec) 33 | assert(not k1:is_private()) 34 | t = k1:parse() 35 | assert(not k1:missing_paramaters()) 36 | assert(t.bits == 256) 37 | assert(t.type == (helper.openssl3 and "SM2" or "EC"), t.type) 38 | assert(t.size == 72) 39 | local r = helper.openssl3 and t.sm2 or t.ec 40 | t = r:parse(true) --make basic table 41 | lu.assertEquals(type(t.curve_name), "number") 42 | lu.assertStrContains(t.x.version, "bn library") 43 | lu.assertStrContains(t.y.version, "bn library") 44 | lu.assertEquals(t.d, nil) 45 | t = r:parse() 46 | lu.assertStrContains(tostring(t.pub_key), "openssl.ec_point") 47 | lu.assertStrContains(tostring(t.group), "openssl.ec_group") 48 | local x, y = t.group:affine_coordinates(t.pub_key) 49 | lu.assertStrContains(x.version, "bn library") 50 | lu.assertStrContains(y.version, "bn library") 51 | local ec2p = { 52 | alg = "ec", 53 | ec_name = t.group:parse().curve_name, 54 | x = x, 55 | y = y, 56 | } 57 | local ec2 = pkey.new(ec2p) 58 | assert(not ec2:is_private()) 59 | 60 | t = ec:parse() 61 | t = helper.openssl3 and t.sm2 or t.ec 62 | ec2p.d = t:parse().priv_key 63 | local ec2priv = pkey.new(ec2p) 64 | assert(ec2priv:is_private()) 65 | 66 | nec = { "ec", "SM2" } 67 | local key1 = pkey.new(unpack(nec)) 68 | local key2 = pkey.new(unpack(nec)) 69 | local ec1 70 | if helper.openssl3 then 71 | ec1 = key1:parse().sm2 72 | ec2 = key2:parse().sm2 73 | else 74 | ec1 = key1:parse().ec 75 | ec2 = key2:parse().ec 76 | end 77 | local secret1 = ec1:compute_key(ec2) 78 | local secret2 = ec2:compute_key(ec1) 79 | assert(secret1 == secret2) 80 | 81 | local pub1 = pkey.get_public(key1) 82 | local pub2 = pkey.get_public(key2) 83 | if helper.openssl3 then 84 | pub1 = pub1:parse().sm2 85 | pub2 = pub2:parse().sm2 86 | else 87 | pub1 = pub1:parse().ec 88 | pub2 = pub2:parse().ec 89 | end 90 | 91 | secret1 = ec1:compute_key(pub2) 92 | secret2 = ec2:compute_key(pub1) 93 | assert(secret1 == secret2) 94 | end 95 | 96 | function TestSM2:TestSM2_SignVerify() 97 | local nec = { "ec", "SM2" } 98 | local pri = pkey.new(unpack(nec)) 99 | local pub = pri:get_public() 100 | local msg = openssl.random(33) 101 | 102 | local sig 103 | if not helper.openssl3 then 104 | sig = assert(pri:sign(msg, "sha256")) 105 | assert(pub:verify(msg, sig, "sha256")) 106 | end 107 | 108 | if pri.as_sm2 then 109 | -- OpenSSL v1.1.1 110 | assert(pri:as_sm2()) 111 | assert(pub:as_sm2()) 112 | end 113 | 114 | sig = assert(pri:sign(msg, "sm3")) 115 | assert(pub:verify(msg, sig, "sm3")) 116 | end 117 | -------------------------------------------------------------------------------- /test/9.ocsp.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local helper = require("helper") 4 | local ocsp = openssl.ocsp 5 | if ocsp == nil then 6 | print("Skip test srp") 7 | return 8 | end 9 | 10 | TestOCSP = {} 11 | 12 | function TestOCSP:setUp() 13 | self.ca = helper.get_ca() 14 | self.alicedn = { { commonName = "Alice" }, { C = "CN" } } 15 | self.bobdn = { { commonName = "Bob" }, { C = "CN" } } 16 | self.ocspdn = { { commonName = "OCSP" }, { C = "CN" } } 17 | end 18 | 19 | function TestOCSP:tearDown() end 20 | 21 | function TestOCSP:testAll() 22 | local req, pkey = helper.new_req(self.alicedn) 23 | local cert = self.ca:sign(req) 24 | self.alice = { key = pkey, cert = cert, id = assert(ocsp.certid_new(cert, self.ca.cacert)) } 25 | 26 | cert, pkey = assert(helper.sign(self.bobdn)) 27 | local sn = cert:serial(false) 28 | self.bob = { key = pkey, cert = cert, id = assert(ocsp.certid_new(sn, self.ca.cacert)) } 29 | assert(type(self.bob.id:info()) == "table") 30 | 31 | local oreq = ocsp.request_new() 32 | assert(oreq) 33 | local one = assert(oreq:add(self.alice.id)) 34 | one = assert(oreq:add(self.bob.id)) 35 | assert(oreq:is_signed() == false) 36 | 37 | assert(type(oreq:parse()) == "table") 38 | 39 | local ocert, okey = helper.sign(self.ocspdn) 40 | 41 | assert(type(oreq:export(true))) 42 | 43 | assert(oreq:add_ext(openssl.x509.extension.new_extension({ 44 | object = "subjectAltName", 45 | value = "IP:192.168.0.1", 46 | }))) 47 | assert(type(oreq:export(true)) == "string") 48 | assert(type(oreq:parse().extensions) == "table") 49 | 50 | local der = assert(oreq:export(false)) 51 | assert(type(der) == "string") 52 | 53 | -- avoid resign a ocsp request object 54 | oreq = assert(ocsp.request_read(der, false)) 55 | assert(oreq:sign(ocert, okey)) 56 | oreq = assert(ocsp.request_read(der, false)) 57 | assert(oreq:sign(ocert, okey, { self.ca.cert })) 58 | oreq = assert(ocsp.request_read(der, false)) 59 | assert(oreq:sign(ocert, okey, { self.ca.cert }, 0)) 60 | oreq = assert(ocsp.request_read(der, false)) 61 | assert(oreq:sign(ocert, okey, { self.ca.cert }, 0, "sha256")) 62 | der = oreq:export(true) 63 | assert(type(der) == "string") 64 | 65 | assert(type(oreq:parse()) == "table") 66 | 67 | oreq = ocsp.request_read(der, true) 68 | assert(oreq) 69 | local t = oreq:parse() 70 | assert(type(t) == "table") 71 | 72 | --OCSP_SINGLERESP_add1_ext_i2d(single, NID_invalidity_date, invtm, 0, 0); 73 | --OCSP_SINGLERESP_add1_ext_i2d(single, NID_hold_instruction_code, inst, 0, 0); 74 | local sn1 = tostring(self.bob.cert:serial()) 75 | local sn2 = tostring(self.alice.cert:serial()) 76 | local basic = assert(ocsp.basicresp_new()) 77 | 78 | assert(basic:add(self.alice.id, ocsp.GOOD, ocsp.NOSTATUS, nil)) 79 | local single = assert(basic:add(self.bob.id, ocsp.REVOKED, ocsp.UNSPECIFIED, os.time())) 80 | assert(single:add_ext(openssl.x509.extension.new_extension({ 81 | object = "subjectAltName", 82 | value = "IP:192.168.0.1", 83 | }))) 84 | assert(type(single:info()) == "table") 85 | 86 | assert(basic:add_ext(openssl.x509.extension.new_extension({ 87 | object = "subjectAltName", 88 | value = "IP:192.168.0.1", 89 | }))) 90 | assert(basic:copy_nonce(oreq)) 91 | assert(basic:sign(ocert, okey)) 92 | assert(type(basic:info()) == "table") 93 | 94 | resp = assert(basic:response()) 95 | 96 | der = assert(resp:export(false)) 97 | resp = ocsp.response_read(der, false) 98 | 99 | assert(resp:export(true)) 100 | assert(resp:export(false)) 101 | 102 | local t = resp:parse() 103 | assert(type(t) == "table") 104 | end 105 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: Check 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | Coverage: 7 | # look at https://github.com/eddyxu/cpp-coveralls 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | openssl_version: [openssl-1.0.2u, openssl-1.1.1w, openssl-3.0.18, openssl-3.5.4] 12 | env: 13 | COVERALLS_GIT_BRANCH: "${{ github.ref }}" 14 | COVERALLS_REPO_TOKEN: "${{ secrets.COVERALLS_TOKEN }}" 15 | WITH_LUA_ENGINE: LuaJIT 16 | LUA: luajit2.1 17 | LUAROCKS: 3.12.0 18 | SSL: ${{ matrix.openssl_version }} 19 | COVERALLS_PARALLEL: ON 20 | COVERALLS_SERVICE_NAME: github 21 | TRAVIS_JOB_ID: ${{ github.run_id }} 22 | steps: 23 | - uses: actions/checkout@v4 24 | with: 25 | submodules: recursive 26 | - name: cpp-coveralls 27 | run: pip install cpp-coveralls PyYAML 28 | - name: depends 29 | run: sudo apt update && sudo apt install -y libuv1-dev 30 | - name: setup 31 | run: 32 | .github/shell/setup_lua.sh && .github/shell/setup_ssl.sh 33 | - name: run 34 | run: | 35 | export PATH=$HOME/.usr/bin:$PATH 36 | $HOME/.usr/bin/luarocks install luv 37 | ln -s $HOME/.usr/lib/lua/5.1/luv.so 38 | export PKG_CONFIG_PATH=$HOME/.usr/lib/pkgconfig 39 | export LD_LIBRARY_PATH=$HOME/.usr/lib 40 | make coveralls 41 | coveralls -b . -i src --gcov-options '\-lp' 42 | finish: 43 | needs: Coverage 44 | if: ${{ always() }} 45 | runs-on: ubuntu-latest 46 | steps: 47 | - name: Close parallel build 48 | uses: coverallsapp/github-action@master 49 | with: 50 | github-token: ${{ secrets.COVERALLS_TOKEN }} 51 | parallel-finished: true 52 | 53 | Valgrind: 54 | runs-on: ubuntu-latest 55 | steps: 56 | - uses: actions/checkout@v4 57 | with: 58 | submodules: recursive 59 | - name: depends 60 | run: sudo apt update && sudo apt install -y luajit libluajit-5.1-dev valgrind 61 | - name: run 62 | run: make valgrind 63 | 64 | Document: 65 | runs-on: ubuntu-latest 66 | env: 67 | WITH_LUA_ENGINE: LuaJIT 68 | LUA: luajit2.1 69 | LUAROCKS: 3.12.0 70 | steps: 71 | - uses: actions/checkout@v4 72 | with: 73 | submodules: recursive 74 | - name: run 75 | run: | 76 | .github/shell/setup_lua.sh 77 | export PATH=$HOME/.usr/bin:$PATH 78 | $HOME/.usr/bin/luarocks install lpeg 79 | $HOME/.usr/bin/luarocks install ldoc 80 | eval $($HOME/.usr/bin/luarocks path) 81 | $HOME/.usr/bin/luajit .github/shell/analyze_ldoc.lua src 82 | make doc 83 | 84 | clang-asan: 85 | runs-on: ubuntu-latest 86 | env: 87 | ASAN_OPTIONS: detect_leaks=1:check_initialization_order=1 88 | UBSAN_OPTIONS: print_stacktrace=1 89 | CC: clang 90 | CXX: clang++ 91 | steps: 92 | - uses: actions/checkout@v4 93 | with: 94 | submodules: recursive 95 | - name: depends 96 | run: sudo apt update && sudo apt install -y luajit libluajit-5.1-dev 97 | - name: Test 98 | run: make asan 99 | 100 | clang-tsan: 101 | runs-on: ubuntu-latest 102 | continue-on-error: true # FIXME: OpenSSL-3 103 | env: 104 | CC: clang 105 | CXX: clang++ 106 | TSAN_OPTIONS: atexit_sleep_ms=2000 flush_memory_ms=2000 107 | steps: 108 | - uses: actions/checkout@v4 109 | with: 110 | submodules: recursive 111 | - name: depends 112 | run: sudo apt update && sudo apt install -y luajit libluajit-5.1-dev 113 | - name: Test 114 | run: make tsan 115 | -------------------------------------------------------------------------------- /test/sslctx.lua: -------------------------------------------------------------------------------- 1 | local openssl = require("openssl") 2 | local helper = require("helper") 3 | local ssl, pkey, x509 = openssl.ssl, openssl.pkey, openssl.x509 4 | 5 | local M = {} 6 | 7 | local function load(path) 8 | local f = assert(io.open(path, "r")) 9 | if f then 10 | local c = f:read("*all") 11 | f:close() 12 | return c 13 | end 14 | end 15 | 16 | function M.new(params, protocol) 17 | --[[ 18 | local params = { 19 | mode = "server", 20 | protocol = ssl.default, 21 | key = "../certs/serverAkey.pem", 22 | certificate = "../certs/serverA.pem", 23 | cafile = "../certs/rootA.pem", 24 | verify = {"peer", "fail_if_no_peer_cert"}, 25 | options = {"all", "no_sslv2"}, 26 | password = 'password' 27 | } 28 | --]] 29 | protocol = protocol 30 | or ( 31 | params.protocol and string.upper(string.sub(params.protocol, 1, 3)) .. string.sub(params.protocol, 4, -1) 32 | or helper.sslProtocol() 33 | ) 34 | local ctx = ssl.ctx_new(protocol, params.ciphers) 35 | local xkey = nil 36 | if type(params.password) == "nil" then 37 | xkey = assert(pkey.read(load(params.key), true, "pem")) 38 | elseif type(params.password) == "string" then 39 | xkey = assert(pkey.read(load(params.key), true, "pem", params.password)) 40 | elseif type(params.password) == "function" then 41 | local p = assert(params.password()) 42 | xkey = assert(pkey.read(load(params.key), true, "pem", p)) 43 | end 44 | 45 | assert(xkey) 46 | local xcert = nil 47 | if params.certificate then 48 | xcert = assert(x509.read(load(params.certificate))) 49 | end 50 | assert(ctx:use(xkey, xcert)) 51 | 52 | if params.cafile or params.capath then 53 | ctx:verify_locations(params.cafile, params.capath) 54 | end 55 | 56 | local unpack = unpack or table.unpack 57 | if params.verify then 58 | ctx:verify_mode(params.verify) 59 | end 60 | if params.options then 61 | local args = {} 62 | for i = 1, #params.options do 63 | table.insert(arg, params.options[i]) 64 | end 65 | ctx:options(unpack(args)) 66 | end 67 | if params.verifyext then 68 | for k, v in pairs(params.verifyext) do 69 | params.verifyext[k] = string.gsub(v, "lsec_", "") 70 | end 71 | ctx:set_cert_verify(params.verifyext) 72 | end 73 | if params.dhparam then 74 | ctx:set_tmp("dh", params.dhparam) 75 | end 76 | if params.curve then 77 | ctx:set_tmp("ecdh", params.curve) 78 | end 79 | if ctx.set_tmp then 80 | ctx:set_tmp() 81 | ctx:set_tmp("ecdh") 82 | end 83 | return ctx 84 | end 85 | 86 | M.client = { 87 | mode = "client", 88 | protocol = ssl.default, 89 | key = "certs/agent4-key.pem", 90 | certificate = "certs/agent4-cert.pem", 91 | cafile = "certs/ca2-cert.pem", 92 | verify = ssl.peer + ssl.fail, 93 | options = { "all", "no_sslv2" }, 94 | ciphers = "ALL:!ECDHE", 95 | } 96 | 97 | M.server = { 98 | mode = "server", 99 | protocol = ssl.default, 100 | key = "certs/agent3-key.pem", 101 | certificate = "certs/agent3-cert.pem", 102 | cafile = "certs/ca2-cert.pem", 103 | verify = ssl.peer + ssl.fail, 104 | options = { "all", "no_sslv2" }, 105 | } 106 | 107 | M.server01 = { 108 | mode = "server", 109 | protocol = ssl.default, 110 | key = "certs/agent3-key.pem", 111 | certificate = "certs/agent3-cert.pem", 112 | cafile = "certs/ca2-cert.pem", 113 | verify = ssl.none, 114 | options = { "all", "no_sslv2" }, 115 | ciphers = "ALL:!ADH:@STRENGTH", 116 | } 117 | 118 | M.server02 = { 119 | mode = "server", 120 | protocol = ssl.default, 121 | key = "certs/agent1-key.pem", 122 | certificate = "certs/agent1-cert.pem", 123 | cafile = "certs/ca1-cert.pem", 124 | verify = ssl.none, 125 | options = { "all", "no_sslv2" }, 126 | ciphers = "ALL:!ADH:@STRENGTH", 127 | } 128 | 129 | return M 130 | -------------------------------------------------------------------------------- /test/1.x509_extension.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local ext = require("openssl").x509.extension 4 | local asn1 = require("openssl").asn1 5 | 6 | TestX509ext = {} 7 | 8 | function TestX509ext:setUp() 9 | self.timeStamping = openssl.asn1.new_string("timeStamping", asn1.IA5STRING) 10 | self.cafalse = openssl.asn1.new_string("CA:FALSE", asn1.OCTET_STRING) 11 | self.time = { 12 | object = "extendedKeyUsage", 13 | critical = true, 14 | value = "timeStamping", 15 | } 16 | self.ca = { object = "basicConstraints", value = self.cafalse } 17 | self.cas = { object = "basicConstraints", value = "CA:FALSE" } 18 | self.exts = { self.time, self.ca, self.cas } 19 | end 20 | 21 | function TestX509ext:tearDown() end 22 | 23 | function TestX509ext:testSupport() 24 | local supports = ext.support() 25 | assert(#supports > 0) 26 | assert(supports[1].sname) 27 | assert(supports[1].lname) 28 | assert(supports[1].nid) 29 | 30 | local caext = ext.new_extension(self.ca) 31 | assert(ext.support(caext)) 32 | 33 | local obj = openssl.asn1.new_object("extendedKeyUsage") 34 | assert(ext.support(obj)) 35 | obj = openssl.asn1.new_object("emailAddress") 36 | assert(obj) 37 | assert(not ext.support(obj)) 38 | 39 | local exts = { 40 | { 41 | object = "subjectAltName", 42 | value = "IP:192.168.1.1,RID:1.2.3.4", 43 | }, 44 | { 45 | object = "subjectAltName", 46 | value = "IP:192.168.1.1", 47 | }, 48 | { 49 | object = "subjectAltName", 50 | value = "DNS:abc.xyz", 51 | }, 52 | { 53 | object = "subjectAltName", 54 | value = "URI:http://my.url.here/", 55 | }, 56 | { 57 | object = "subjectAltName", 58 | value = "otherName:1.2.3.4;UTF8:some other identifier", 59 | }, 60 | { 61 | object = "subjectAltName", 62 | value = "email:123@abc.com", 63 | }, 64 | --{ 65 | -- object = 'subjectAltName', 66 | -- value = 'x400Name:C=US/O=Organization/G=Nuno/CN=demo' 67 | --}, 68 | --{ 69 | -- object = 'subjectAltName', 70 | -- value = 'EdiPartyName:123@abc.com' 71 | --}, 72 | --{ 73 | -- object = 'subjectAltName', 74 | -- value = 'dirName:/C=NZ/CN=Jackov al-Trades' 75 | --} 76 | } 77 | 78 | for i = 1, #exts do 79 | local obj = ext.new_extension(exts[i]) 80 | assert(ext.support(obj)) 81 | lu.assertIsTable(obj:info()) 82 | end 83 | end 84 | 85 | function TestX509ext:testAll() 86 | local n1 = ext.new_extension(self.ca) 87 | lu.assertStrContains(tostring(n1), "openssl.x509_extension") 88 | local info = n1:info() 89 | lu.assertIsTable(info) 90 | lu.assertEquals(info.object:ln(), "X509v3 Basic Constraints") 91 | lu.assertEquals(info.critical, false) 92 | lu.assertEquals(info.value:tostring(), "CA:FALSE") 93 | 94 | local n2 = n1:dup() 95 | lu.assertEquals(n2:info(), info) 96 | lu.assertEquals(n1:critical(), false) 97 | n1:critical(true) 98 | lu.assertEquals(n1:critical(), true) 99 | 100 | assert(ext.new_extension(self.cas)) 101 | lu.assertEquals(n1:object():ln(), "X509v3 Basic Constraints") 102 | n1:object("extendedKeyUsage") 103 | lu.assertEquals(n1:object():sn(), "extendedKeyUsage") 104 | 105 | lu.assertEquals(n1:data():tostring(), "CA:FALSE") 106 | lu.assertErrorMsgEquals( 107 | "bad argument #2 to '?' (only accpet asn1 octet string if is a asn1 string)", 108 | n1.data, 109 | n1, 110 | self.timeStamping 111 | ) 112 | assert(n1:data("CA:FALSE")) 113 | lu.assertEquals(n1:data(), self.cafalse) 114 | 115 | local time = ext.new_extension(self.time) 116 | lu.assertEquals(time:critical(), true) 117 | local der = time:export() 118 | local t1 = ext.read_extension(der) 119 | assert(der == t1:export()) 120 | 121 | assert(n1:data(asn1.new_string("CA:FALSE", asn1.OCTET_STRING))) 122 | end 123 | -------------------------------------------------------------------------------- /test/certs/Makefile: -------------------------------------------------------------------------------- 1 | all: agent1-cert.pem agent2-cert.pem agent3-cert.pem agent4-cert.pem ca2-crl.pem 2 | 3 | 4 | # 5 | # Create Certificate Authority: ca1 6 | # ('password' is used for the CA password.) 7 | # 8 | ca1-cert.pem: ca1.cnf 9 | openssl req -new -x509 -days 9999 -config ca1.cnf -keyout ca1-key.pem -out ca1-cert.pem 10 | 11 | # 12 | # Create Certificate Authority: ca2 13 | # ('password' is used for the CA password.) 14 | # 15 | ca2-cert.pem: ca2.cnf 16 | openssl req -new -x509 -days 9999 -config ca2.cnf -keyout ca2-key.pem -out ca2-cert.pem 17 | echo '01' > ca2-serial 18 | touch ca2-database.txt 19 | 20 | 21 | # 22 | # agent1 is signed by ca1. 23 | # 24 | 25 | agent1-key.pem: 26 | openssl genrsa -out agent1-key.pem 27 | 28 | agent1-csr.pem: agent1.cnf agent1-key.pem 29 | openssl req -new -config agent1.cnf -key agent1-key.pem -out agent1-csr.pem 30 | 31 | agent1-cert.pem: agent1-csr.pem ca1-cert.pem ca1-key.pem 32 | openssl x509 -req \ 33 | -days 9999 \ 34 | -passin "pass:password" \ 35 | -in agent1-csr.pem \ 36 | -CA ca1-cert.pem \ 37 | -CAkey ca1-key.pem \ 38 | -CAcreateserial \ 39 | -out agent1-cert.pem 40 | 41 | agent1-verify: agent1-cert.pem ca1-cert.pem 42 | openssl verify -CAfile ca1-cert.pem agent1-cert.pem 43 | 44 | 45 | # 46 | # agent2 has a self signed cert 47 | # 48 | # Generate new private key 49 | agent2-key.pem: 50 | openssl genrsa -out agent2-key.pem 51 | 52 | # Create a Certificate Signing Request for the key 53 | agent2-csr.pem: agent2-key.pem agent2.cnf 54 | openssl req -new -config agent2.cnf -key agent2-key.pem -out agent2-csr.pem 55 | 56 | # Create a Certificate for the agent. 57 | agent2-cert.pem: agent2-csr.pem agent2-key.pem 58 | openssl x509 -req \ 59 | -days 9999 \ 60 | -in agent2-csr.pem \ 61 | -signkey agent2-key.pem \ 62 | -out agent2-cert.pem 63 | 64 | agent2-verify: agent2-cert.pem 65 | openssl verify -CAfile agent2-cert.pem agent2-cert.pem 66 | 67 | # 68 | # agent3 is signed by ca2. 69 | # 70 | 71 | agent3-key.pem: 72 | openssl genrsa -out agent3-key.pem 73 | 74 | agent3-csr.pem: agent3.cnf agent3-key.pem 75 | openssl req -new -config agent3.cnf -key agent3-key.pem -out agent3-csr.pem 76 | 77 | agent3-cert.pem: agent3-csr.pem ca2-cert.pem ca2-key.pem 78 | openssl x509 -req \ 79 | -days 9999 \ 80 | -passin "pass:password" \ 81 | -in agent3-csr.pem \ 82 | -CA ca2-cert.pem \ 83 | -CAkey ca2-key.pem \ 84 | -CAcreateserial \ 85 | -out agent3-cert.pem 86 | 87 | agent3-verify: agent3-cert.pem ca2-cert.pem 88 | openssl verify -CAfile ca2-cert.pem agent3-cert.pem 89 | 90 | 91 | # 92 | # agent4 is signed by ca2 (client cert) 93 | # 94 | 95 | agent4-key.pem: 96 | openssl genrsa -out agent4-key.pem 97 | 98 | agent4-csr.pem: agent4.cnf agent4-key.pem 99 | openssl req -new -config agent4.cnf -key agent4-key.pem -out agent4-csr.pem 100 | 101 | agent4-cert.pem: agent4-csr.pem ca2-cert.pem ca2-key.pem 102 | openssl x509 -req \ 103 | -days 9999 \ 104 | -passin "pass:password" \ 105 | -in agent4-csr.pem \ 106 | -CA ca2-cert.pem \ 107 | -CAkey ca2-key.pem \ 108 | -CAcreateserial \ 109 | -extfile agent4.cnf \ 110 | -extensions ext_key_usage \ 111 | -out agent4-cert.pem 112 | 113 | agent4-verify: agent4-cert.pem ca2-cert.pem 114 | openssl verify -CAfile ca2-cert.pem agent4-cert.pem 115 | 116 | # 117 | # Make CRL with agent4 being rejected 118 | # 119 | ca2-crl.pem: ca2-key.pem ca2-cert.pem ca2.cnf 120 | openssl ca -revoke agent4-cert.pem \ 121 | -keyfile ca2-key.pem \ 122 | -cert ca2-cert.pem \ 123 | -config ca2.cnf 124 | openssl ca \ 125 | -keyfile ca2-key.pem \ 126 | -cert ca2-cert.pem \ 127 | -config ca2.cnf \ 128 | -gencrl \ 129 | -out ca2-crl.pem 130 | 131 | clean: 132 | rm -f *.pem *.srl ca2-database.txt ca2-serial 133 | 134 | test: agent1-verify agent2-verify agent3-verify agent4-verify 135 | 136 | 137 | .PHONY: all clean test agent1-verify agent2-verify agent3-verify agent4-verify 138 | -------------------------------------------------------------------------------- /test/2.param.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | 4 | TestParam = {} 5 | 6 | function TestParam:setUp() 7 | -- Skip tests if not OpenSSL 3.0+ 8 | local _, _, version = openssl.version(true) 9 | if version < 0x30000000 then 10 | lu.skip("OpenSSL 3.0+ required for OSSL_PARAM tests") 11 | end 12 | end 13 | 14 | function TestParam:testParamModuleExists() 15 | local param = require("openssl").param 16 | lu.assertNotNil(param, "param module should be available in OpenSSL 3.0+") 17 | end 18 | 19 | function TestParam:testKDFParamsExist() 20 | local param = require("openssl").param 21 | lu.assertNotNil(param.kdf, "KDF parameters should be available") 22 | lu.assertNotNil(param.kdf.pass, "pass parameter should exist") 23 | lu.assertNotNil(param.kdf.salt, "salt parameter should exist") 24 | end 25 | 26 | function TestParam:testRSAParamsExist() 27 | local param = require("openssl").param 28 | lu.assertNotNil(param.rsa, "RSA parameters should be available") 29 | lu.assertNotNil(param.rsa.n, "n parameter should exist") 30 | lu.assertNotNil(param.rsa.e, "e parameter should exist") 31 | lu.assertNotNil(param.rsa.d, "d parameter should exist") 32 | end 33 | 34 | function TestParam:testRSAParseWithOSSLPARAM() 35 | -- Generate an RSA key 36 | local rsa = require("openssl").rsa.generate_key(2048) 37 | lu.assertNotNil(rsa, "RSA key generation should succeed") 38 | 39 | -- Parse the key to get parameters 40 | local params = rsa:parse() 41 | lu.assertNotNil(params, "RSA parse should return a table") 42 | lu.assertNotNil(params.n, "n parameter should be present") 43 | lu.assertNotNil(params.e, "e parameter should be present") 44 | lu.assertEquals(params.bits, 2048, "Key size should be 2048 bits") 45 | 46 | -- Check that we have a BIGNUM object for n 47 | local n_type = type(params.n) 48 | lu.assertTrue(n_type == "userdata" or n_type == "table", 49 | "n should be a BIGNUM object (userdata or table)") 50 | end 51 | 52 | function TestParam:testRSAParsePrivateKey() 53 | -- Generate an RSA private key 54 | local rsa = require("openssl").rsa.generate_key(2048) 55 | local params = rsa:parse() 56 | 57 | -- Private key should have d, p, q, dmp1, dmq1, iqmp 58 | lu.assertNotNil(params.d, "Private key should have d parameter") 59 | lu.assertNotNil(params.p, "Private key should have p parameter") 60 | lu.assertNotNil(params.q, "Private key should have q parameter") 61 | lu.assertNotNil(params.dmp1, "Private key should have dmp1 parameter") 62 | lu.assertNotNil(params.dmq1, "Private key should have dmq1 parameter") 63 | lu.assertNotNil(params.iqmp, "Private key should have iqmp parameter") 64 | end 65 | 66 | function TestParam:testRSAParsePublicKey() 67 | -- Generate a key pair 68 | local rsa = require("openssl").rsa.generate_key(1024) 69 | lu.assertNotNil(rsa, "RSA key generation should succeed") 70 | 71 | -- Parse the private key first 72 | local priv_params = rsa:parse() 73 | lu.assertNotNil(priv_params.n, "Private key should have n parameter") 74 | lu.assertNotNil(priv_params.e, "Private key should have e parameter") 75 | lu.assertNotNil(priv_params.d, "Private key should have d parameter") 76 | end 77 | 78 | function TestParam:testRSACompatibilityMode() 79 | -- Test that parsing works consistently regardless of how the key was created 80 | -- This ensures backward compatibility with keys created using OpenSSL 1.x API 81 | 82 | local rsa1 = require("openssl").rsa.generate_key(1024) 83 | local params1 = rsa1:parse() 84 | 85 | -- Export and re-import to potentially trigger different code paths 86 | local pem1 = rsa1:export(true) -- export private key as PEM 87 | local rsa2 = require("openssl").rsa.read(pem1, true) 88 | local params2 = rsa2:parse() 89 | 90 | -- Both should have the same parameters available 91 | lu.assertNotNil(params1.n, "Original key should have n") 92 | lu.assertNotNil(params2.n, "Reimported key should have n") 93 | lu.assertNotNil(params1.e, "Original key should have e") 94 | lu.assertNotNil(params2.e, "Reimported key should have e") 95 | end 96 | 97 | os.exit(lu.LuaUnit.run()) 98 | -------------------------------------------------------------------------------- /src/ssl_options.h: -------------------------------------------------------------------------------- 1 | /* vim: set filetype=c : */ 2 | 3 | #ifndef OPENSSL_OPTIONS_H 4 | #define OPENSSL_OPTIONS_H 5 | 6 | #include 7 | #include "auxiliar.h" 8 | 9 | static LuaL_Enumeration ssl_options[] = 10 | { 11 | #if defined(SSL_OP_ALL) 12 | {"all", SSL_OP_ALL}, 13 | #endif 14 | #if defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) 15 | {"allow_unsafe_legacy_renegotiation", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION}, 16 | #endif 17 | #if defined(SSL_OP_CIPHER_SERVER_PREFERENCE) 18 | {"cipher_server_preference", SSL_OP_CIPHER_SERVER_PREFERENCE}, 19 | #endif 20 | #if defined(SSL_OP_CISCO_ANYCONNECT) 21 | {"cisco_anyconnect", SSL_OP_CISCO_ANYCONNECT}, 22 | #endif 23 | #if defined(SSL_OP_COOKIE_EXCHANGE) 24 | {"cookie_exchange", SSL_OP_COOKIE_EXCHANGE}, 25 | #endif 26 | #if defined(SSL_OP_CRYPTOPRO_TLSEXT_BUG) 27 | {"cryptopro_tlsext_bug", SSL_OP_CRYPTOPRO_TLSEXT_BUG}, 28 | #endif 29 | #if defined(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) 30 | {"dont_insert_empty_fragments", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS}, 31 | #endif 32 | #if defined(SSL_OP_EPHEMERAL_RSA) 33 | {"ephemeral_rsa", SSL_OP_EPHEMERAL_RSA}, 34 | #endif 35 | #if defined(SSL_OP_LEGACY_SERVER_CONNECT) 36 | {"legacy_server_connect", SSL_OP_LEGACY_SERVER_CONNECT}, 37 | #endif 38 | #if defined(SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) 39 | {"microsoft_big_sslv3_buffer", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER}, 40 | #endif 41 | #if defined(SSL_OP_MICROSOFT_SESS_ID_BUG) 42 | {"microsoft_sess_id_bug", SSL_OP_MICROSOFT_SESS_ID_BUG}, 43 | #endif 44 | #if defined(SSL_OP_MSIE_SSLV2_RSA_PADDING) 45 | {"msie_sslv2_rsa_padding", SSL_OP_MSIE_SSLV2_RSA_PADDING}, 46 | #endif 47 | #if defined(SSL_OP_NETSCAPE_CA_DN_BUG) 48 | {"netscape_ca_dn_bug", SSL_OP_NETSCAPE_CA_DN_BUG}, 49 | #endif 50 | #if defined(SSL_OP_NETSCAPE_CHALLENGE_BUG) 51 | {"netscape_challenge_bug", SSL_OP_NETSCAPE_CHALLENGE_BUG}, 52 | #endif 53 | #if defined(SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG) 54 | {"netscape_demo_cipher_change_bug", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG}, 55 | #endif 56 | #if defined(SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG) 57 | {"netscape_reuse_cipher_change_bug", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG}, 58 | #endif 59 | #if defined(SSL_OP_NO_COMPRESSION) 60 | {"no_compression", SSL_OP_NO_COMPRESSION}, 61 | #endif 62 | #if defined(SSL_OP_NO_QUERY_MTU) 63 | {"no_query_mtu", SSL_OP_NO_QUERY_MTU}, 64 | #endif 65 | #if defined(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION) 66 | {"no_session_resumption_on_renegotiation", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION}, 67 | #endif 68 | #if defined(SSL_OP_NO_SSLv2) 69 | {"no_sslv2", SSL_OP_NO_SSLv2}, 70 | #endif 71 | #if defined(SSL_OP_NO_SSLv3) 72 | {"no_sslv3", SSL_OP_NO_SSLv3}, 73 | #endif 74 | #if defined(SSL_OP_NO_TICKET) 75 | {"no_ticket", SSL_OP_NO_TICKET}, 76 | #endif 77 | #if defined(SSL_OP_NO_TLSv1) 78 | {"no_tlsv1", SSL_OP_NO_TLSv1}, 79 | #endif 80 | #if defined(SSL_OP_NO_TLSv1_1) 81 | {"no_tlsv1_1", SSL_OP_NO_TLSv1_1}, 82 | #endif 83 | #if defined(SSL_OP_NO_TLSv1_2) 84 | {"no_tlsv1_2", SSL_OP_NO_TLSv1_2}, 85 | #endif 86 | #if defined(SSL_OP_PKCS1_CHECK_1) 87 | {"pkcs1_check_1", SSL_OP_PKCS1_CHECK_1}, 88 | #endif 89 | #if defined(SSL_OP_PKCS1_CHECK_2) 90 | {"pkcs1_check_2", SSL_OP_PKCS1_CHECK_2}, 91 | #endif 92 | #if defined(SSL_OP_SINGLE_DH_USE) 93 | {"single_dh_use", SSL_OP_SINGLE_DH_USE}, 94 | #endif 95 | #if defined(SSL_OP_SINGLE_ECDH_USE) 96 | {"single_ecdh_use", SSL_OP_SINGLE_ECDH_USE}, 97 | #endif 98 | #if defined(SSL_OP_SSLEAY_080_CLIENT_DH_BUG) 99 | {"ssleay_080_client_dh_bug", SSL_OP_SSLEAY_080_CLIENT_DH_BUG}, 100 | #endif 101 | #if defined(SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG) 102 | {"sslref2_reuse_cert_type_bug", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG}, 103 | #endif 104 | #if defined(SSL_OP_TLS_BLOCK_PADDING_BUG) 105 | {"tls_block_padding_bug", SSL_OP_TLS_BLOCK_PADDING_BUG}, 106 | #endif 107 | #if defined(SSL_OP_TLS_D5_BUG) 108 | {"tls_d5_bug", SSL_OP_TLS_D5_BUG}, 109 | #endif 110 | #if defined(SSL_OP_TLS_ROLLBACK_BUG) 111 | {"tls_rollback_bug", SSL_OP_TLS_ROLLBACK_BUG}, 112 | #endif 113 | {NULL, 0L} 114 | }; 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /test/9.issue.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local unpack = unpack or table.unpack 4 | 5 | TestIssuer = {} 6 | local function dump(t, i) 7 | i = i or 0 8 | for k, v in pairs(t) do 9 | if type(v) == "table" then 10 | print(string.rep("\t", i), k .. "={") 11 | dump(v, i + 1) 12 | print(string.rep("\t", i), "}") 13 | elseif type(v) == "userdata" then 14 | local s = tostring(v) 15 | if s:match("^openssl.asn1_") then 16 | if type(k) == "userdata" and tostring(k):match("^openssl.asn1_object") then 17 | print(string.rep("\t", i), k:sn() .. "=" .. v:data()) 18 | elseif s:match("^openssl.asn1_integer") then 19 | print(string.rep("\t", i), tostring(k) .. "=" .. tostring(v), v:bn()) 20 | else 21 | print(string.rep("\t", i), tostring(k) .. "=" .. tostring(v), v:data()) 22 | end 23 | elseif s:match("^openssl.x509_name") then 24 | print(string.rep("\t", i), k .. "=" .. v:oneline()) 25 | print(string.rep("\t", i), k .. "={") 26 | dump(v:info(true), i + 1) 27 | print(string.rep("\t", i), k .. "=}") 28 | elseif s:match("^openssl.x509_extension") then 29 | print(string.rep("\t", i), k .. "={") 30 | dump(v:info(true), i + 1) 31 | print(string.rep("\t", i), "}") 32 | elseif s:match("^openssl.x509_algor") then 33 | print(string.rep("\t", i), k .. "=" .. v:tostring()) 34 | else 35 | print(string.rep("\t", i), k .. "=" .. v) 36 | end 37 | else 38 | print(string.rep("\t", i), k .. "=" .. tostring(v)) 39 | end 40 | end 41 | end 42 | 43 | function TestIssuer:test75() 44 | local certasstring = [[ 45 | -----BEGIN CERTIFICATE----- 46 | MIIDATCCArCgAwIBAgITEgAFDVkfna1KLEIuKgAAAAUNWTAIBgYqhQMCAgMwfzEj 47 | MCEGCSqGSIb3DQEJARYUc3VwcG9ydEBjcnlwdG9wcm8ucnUxCzAJBgNVBAYTAlJV 48 | MQ8wDQYDVQQHEwZNb3Njb3cxFzAVBgNVBAoTDkNSWVBUTy1QUk8gTExDMSEwHwYD 49 | VQQDExhDUllQVE8tUFJPIFRlc3QgQ2VudGVyIDIwHhcNMTUwNjEzMTczNjQ4WhcN 50 | MTUwOTEzMTc0NjQ4WjATMREwDwYDVQQDEwhuZ2F0ZS5ydTBjMBwGBiqFAwICEzAS 51 | BgcqhQMCAiQABgcqhQMCAh4BA0MABEBn4s6r6zCgimGfiHg4o0FpNaGv1jGzmqSD 52 | chsnAiqcV8fQ4Y6p/o0x8CZEXAC+hzdf5w2f1VxzbJaGCTQslmNYo4IBbTCCAWkw 53 | EwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgQwMB0GA1UdDgQWBBT4x4Lz 54 | iE6QcS3Qnmz03HNroSojbzAfBgNVHSMEGDAWgBQVMXywjRreZtcVnElSlxckuQF6 55 | gzBZBgNVHR8EUjBQME6gTKBKhkhodHRwOi8vdGVzdGNhLmNyeXB0b3Byby5ydS9D 56 | ZXJ0RW5yb2xsL0NSWVBUTy1QUk8lMjBUZXN0JTIwQ2VudGVyJTIwMi5jcmwwgakG 57 | CCsGAQUFBwEBBIGcMIGZMGEGCCsGAQUFBzAChlVodHRwOi8vdGVzdGNhLmNyeXB0 58 | b3Byby5ydS9DZXJ0RW5yb2xsL3Rlc3QtY2EtMjAxNF9DUllQVE8tUFJPJTIwVGVz 59 | dCUyMENlbnRlciUyMDIuY3J0MDQGCCsGAQUFBzABhihodHRwOi8vdGVzdGNhLmNy 60 | eXB0b3Byby5ydS9vY3NwL29jc3Auc3JmMAgGBiqFAwICAwNBAA+nkIdgmqgVr/2J 61 | FlwzT6GFy4Cv0skv+KuUyfrd7kX4jcY/oGwxpxBv5WfNYDnHrVK90bNsXTqlon2M 62 | veFd3yM= 63 | -----END CERTIFICATE----- 64 | ]] 65 | local x = openssl.x509.read(certasstring) 66 | local t = x:parse() 67 | assert(type(t) == "table") 68 | -- dump(t,0) 69 | end 70 | 71 | function TestIssuer:test141() 72 | local c = openssl.cipher.decrypt_new("aes-128-cbc", "secret_key", "iv") 73 | local out = c:update("msg") 74 | local final = c:final() 75 | assert(out or final) 76 | c:close() 77 | collectgarbage("collect") 78 | end 79 | 80 | function TestIssuer:test166() 81 | local pkey = openssl.pkey 82 | local ec_key = pkey.new(unpack({ "EC", "secp521r1" })) 83 | local public_key = pkey.get_public(ec_key) 84 | 85 | local key_details = public_key:parse().ec:parse() 86 | local x, y = key_details.group:affine_coordinates(key_details.pub_key) 87 | 88 | local ec_jwk = { 89 | kty = "EC", 90 | crv = "P-521", 91 | x = openssl.base64(x:totext()), 92 | y = openssl.base64(y:totext()), 93 | } 94 | 95 | local factor = { 96 | alg = "EC", 97 | ec_name = 716, 98 | x = assert(openssl.base64(ec_jwk.x, false)), 99 | y = assert(openssl.base64(ec_jwk.y, false)), 100 | } 101 | 102 | local pub = assert(pkey.new(factor)) 103 | assert(pub:export() == public_key:export()) 104 | end 105 | -------------------------------------------------------------------------------- /src/pkcs12.c: -------------------------------------------------------------------------------- 1 | /*** 2 | pkcs12 module to create and parse PKCS#12(PFX) files. 3 | 4 | @module pkcs12 5 | @usage 6 | pkcs12 = require('openssl').pkcs12 7 | */ 8 | 9 | #include "openssl.h" 10 | #include "private.h" 11 | 12 | /*** 13 | create and export pkcs12 data 14 | 15 | @function export 16 | @tparam x509 cert 17 | @tparam evp_pkey pkey 18 | @tparam string password 19 | @tparam[opt=nil] string friendlyname 20 | @tparam[opt] table|stak_of_x509 extracerts 21 | @tparam[opt] boolean keytype flag to private key used by MSIE, true for KEY_SIG, or KEY_EX 22 | @treturn string data 23 | */ 24 | static int openssl_pkcs12_export(lua_State *L) 25 | { 26 | X509 *cert = CHECK_OBJECT(1, X509, "openssl.x509"); 27 | EVP_PKEY *priv_key = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey"); 28 | char *pass = (char *)luaL_checkstring(L, 3); 29 | int keytype = 0; 30 | int top = lua_gettop(L); 31 | 32 | BIO *bio_out = NULL; 33 | PKCS12 *p12 = NULL; 34 | const char *friendly_name = NULL; 35 | STACK_OF(X509) *ca = NULL; 36 | int ret = 0; 37 | 38 | luaL_argcheck(L, openssl_pkey_is_private(priv_key), 2, "must be private key"); 39 | 40 | if (top > 3) { 41 | int idx = 4; 42 | if (lua_isstring(L, idx)) { 43 | friendly_name = lua_tostring(L, idx); 44 | idx++; 45 | } 46 | 47 | if (lua_istable(L, idx)) { 48 | ca = openssl_sk_x509_fromtable(L, idx); 49 | if (ca == NULL) luaL_argerror(L, idx, "must be table contians x509 object as cacets"); 50 | idx++; 51 | } 52 | 53 | if (lua_isboolean(L, idx)) { 54 | keytype = lua_toboolean(L, idx) ? KEY_SIG : KEY_EX; 55 | } 56 | } 57 | 58 | if (cert && !X509_check_private_key(cert, priv_key)) { 59 | luaL_error(L, "private key does not correspond to cert"); 60 | } 61 | 62 | /* end parse extra config */ 63 | 64 | /* 65 | * PKCS12 *PKCS12_create(char *pass, 66 | * char *name, 67 | * EVP_PKEY *pkey, 68 | * X509 *cert, 69 | * STACK_OF(X509) *ca, 70 | * int nid_key, 71 | * int nid_cert, 72 | * int iter, 73 | * int mac_iter, 74 | * int keytype); 75 | */ 76 | 77 | p12 = PKCS12_create( 78 | pass, (char *)friendly_name, priv_key, cert, ca, NID_aes_128_cbc, 0, 0, 0, keytype); 79 | if (!p12) luaL_error(L, "PKCS12_create failed,pleases get more error info"); 80 | 81 | bio_out = BIO_new(BIO_s_mem()); 82 | if (i2d_PKCS12_bio(bio_out, p12)) { 83 | BUF_MEM *bio_buf; 84 | 85 | BIO_get_mem_ptr(bio_out, &bio_buf); 86 | lua_pushlstring(L, bio_buf->data, bio_buf->length); 87 | ret = 1; 88 | } 89 | if (ca != NULL) sk_X509_pop_free(ca, X509_free); 90 | BIO_free(bio_out); 91 | PKCS12_free(p12); 92 | 93 | return ret; 94 | } 95 | 96 | /*** 97 | parse pkcs12 data as lua table 98 | 99 | @function read 100 | @tparam string|bio input pkcs12 content 101 | @tparam string password for pkcs12 102 | @treturn table result contain 'cert', 'pkey', 'extracerts' keys 103 | */ 104 | static int openssl_pkcs12_read(lua_State *L) 105 | { 106 | PKCS12 *p12 = NULL; 107 | EVP_PKEY *pkey = NULL; 108 | X509 *cert = NULL; 109 | STACK_OF(X509) *ca = NULL; 110 | int ret = 0; 111 | 112 | BIO *bio_in = load_bio_object(L, 1); 113 | const char *pass = luaL_checkstring(L, 2); 114 | 115 | if (d2i_PKCS12_bio(bio_in, &p12) && PKCS12_parse(p12, pass, &pkey, &cert, &ca)) { 116 | lua_newtable(L); 117 | 118 | AUXILIAR_SETOBJECT(L, cert, "openssl.x509", -1, "cert"); 119 | AUXILIAR_SETOBJECT(L, pkey, "openssl.evp_pkey", -1, "pkey"); 120 | if (ca != NULL) { 121 | lua_pushstring(L, "extracerts"); 122 | openssl_sk_x509_totable(L, ca); 123 | lua_rawset(L, -3); 124 | sk_X509_pop_free(ca, X509_free); 125 | } 126 | 127 | ret = 1; 128 | } 129 | BIO_free(bio_in); 130 | PKCS12_free(p12); 131 | return ret; 132 | } 133 | 134 | static luaL_Reg R[] = { 135 | { "read", openssl_pkcs12_read }, 136 | { "export", openssl_pkcs12_export }, 137 | 138 | { NULL, NULL } 139 | }; 140 | 141 | int 142 | luaopen_pkcs12(lua_State *L) 143 | { 144 | lua_newtable(L); 145 | luaL_setfuncs(L, R, 0); 146 | 147 | return 1; 148 | } 149 | -------------------------------------------------------------------------------- /src/callback.c: -------------------------------------------------------------------------------- 1 | /*=========================================================================*\ 2 | * callback.c 3 | * callback for lua-openssl binding 4 | * 5 | * Author: george zhao 6 | \*=========================================================================*/ 7 | 8 | /*** 9 | callback module for lua-openssl binding 10 | 11 | This module provides callback functionality for SSL/TLS operations, 12 | including certificate verification callbacks and other SSL event handling. 13 | These callbacks allow customization of SSL/TLS behavior from Lua. 14 | 15 | @module callback 16 | @usage 17 | -- Internal module used by SSL module 18 | */ 19 | #include 20 | 21 | #include "openssl.h" 22 | #include "private.h" 23 | 24 | #include 25 | 26 | static int 27 | verify_cb(int preverify_ok, X509_STORE_CTX *xctx, lua_State *L, SSL *ssl, SSL_CTX *ctx) 28 | { 29 | int err = X509_STORE_CTX_get_error(xctx); 30 | int depth = X509_STORE_CTX_get_error_depth(xctx); 31 | X509 *current = X509_STORE_CTX_get_current_cert(xctx); 32 | 33 | if (L) { 34 | /* get verify_cert state */ 35 | openssl_valueget(L, ssl, "verify_cert"); 36 | if (lua_isnil(L, -1)) { 37 | lua_newtable(L); 38 | openssl_valueset(L, ssl, "verify_cert"); 39 | openssl_valueget(L, ssl, "verify_cert"); 40 | } 41 | 42 | /* create current verify state table */ 43 | lua_newtable(L); 44 | if (preverify_ok != -1) { 45 | lua_pushboolean(L, preverify_ok); 46 | lua_setfield(L, -2, "preverify_ok"); 47 | } 48 | lua_pushinteger(L, err); 49 | lua_setfield(L, -2, "error"); 50 | lua_pushstring(L, X509_verify_cert_error_string(err)); 51 | lua_setfield(L, -2, "error_string"); 52 | lua_pushinteger(L, X509_STORE_CTX_get_error_depth(xctx)); 53 | lua_setfield(L, -2, "error_depth"); 54 | if (current) { 55 | PUSH_OBJECT(current, "openssl.x509"); 56 | X509_up_ref(current); 57 | lua_setfield(L, -2, "current_cert"); 58 | } 59 | 60 | openssl_valueget(L, ctx, preverify_ok == -1 ? "cert_verify_cb" : "verify_cb"); 61 | if (lua_isfunction(L, -1)) { 62 | /* this is set by SSL_CTX_set_verify */ 63 | lua_pushvalue(L, -2); /* current verify state */ 64 | if (lua_pcall(L, 1, 1, 0) == 0) { 65 | preverify_ok = lua_toboolean(L, -1); 66 | lua_pop(L, 1); 67 | } else 68 | luaL_error(L, lua_tostring(L, -1)); 69 | } else { 70 | int always_continue, verify_depth; 71 | openssl_valueget(L, ctx, "verify_cb_flags"); 72 | /* 73 | int verify_depth; 74 | int always_continue; 75 | */ 76 | if (lua_istable(L, -1)) { 77 | lua_getfield(L, -1, "always_continue"); 78 | always_continue = lua_toboolean(L, -1); 79 | lua_pop(L, 1); 80 | 81 | lua_getfield(L, -1, "verify_depth"); 82 | verify_depth = lua_toboolean(L, -1); 83 | lua_pop(L, 1); 84 | 85 | if (depth > verify_depth) { 86 | preverify_ok = 0; 87 | X509_STORE_CTX_set_error(xctx, X509_V_ERR_CERT_CHAIN_TOO_LONG); 88 | } 89 | if (always_continue) preverify_ok = 1; 90 | } 91 | lua_pop(L, 1); 92 | } 93 | 94 | /* set current state to chain */ 95 | lua_rawseti(L, -2, lua_rawlen(L, -2) + 1); 96 | 97 | /* balance lua stack */ 98 | lua_pop(L, 1); 99 | } 100 | 101 | return preverify_ok; 102 | } 103 | 104 | int 105 | openssl_verify_cb(int preverify_ok, X509_STORE_CTX *xctx) 106 | { 107 | SSL *ssl = X509_STORE_CTX_get_ex_data(xctx, SSL_get_ex_data_X509_STORE_CTX_idx()); 108 | SSL_CTX *ctx = ssl ? SSL_get_SSL_CTX(ssl) : NULL; 109 | lua_State *L = ctx ? SSL_CTX_get_app_data(ctx) : NULL; 110 | if (ssl) openssl_newvalue(L, ssl); 111 | return ctx ? verify_cb(preverify_ok, xctx, L, ssl, ctx) : 0; 112 | }; 113 | 114 | /*** 115 | certificate verification callback function 116 | @function cert_verify_cb 117 | @tparam x509_store_ctx ctx X509 store context for verification 118 | @tparam userdata u user data passed to callback 119 | @treturn number verification result (1 for success, 0 for failure) 120 | */ 121 | int 122 | openssl_cert_verify_cb(X509_STORE_CTX *xctx, void *u) 123 | { 124 | int preverify_ok = 0; 125 | lua_State *L = (lua_State *)u; 126 | SSL *ssl = X509_STORE_CTX_get_ex_data(xctx, SSL_get_ex_data_X509_STORE_CTX_idx()); 127 | SSL_CTX *ctx = ssl ? SSL_get_SSL_CTX(ssl) : NULL; 128 | if (ssl) openssl_newvalue(L, ssl); 129 | preverify_ok = ctx ? verify_cb(-1, xctx, L, ssl, ctx) : 0; 130 | return preverify_ok == -1 ? 0 : preverify_ok; 131 | }; 132 | -------------------------------------------------------------------------------- /src/ec_util.c: -------------------------------------------------------------------------------- 1 | #include "openssl.h" 2 | 3 | int openssl_to_group_asn1_flag(lua_State *L, int i, const char *defval) 4 | { 5 | const char *const flag[] = {"explicit", "named_curve", NULL}; 6 | int f = luaL_checkoption(L, i, defval, flag); 7 | int form = 0; 8 | 9 | if (f == 0) 10 | form = 0; 11 | else if (f == 1) 12 | form = OPENSSL_EC_NAMED_CURVE; 13 | else 14 | luaL_argerror(L, i, "invalid parameter, only accept 'explicit' or 'named_curve'"); 15 | 16 | return form; 17 | } 18 | 19 | int openssl_push_group_asn1_flag(lua_State *L, int flag) 20 | { 21 | if (flag == 0) 22 | lua_pushstring(L, "explicit"); 23 | else if (flag == 1) 24 | lua_pushstring(L, "named_curve"); 25 | else 26 | lua_pushnil(L); 27 | 28 | return 1; 29 | } 30 | 31 | point_conversion_form_t openssl_to_point_conversion_form(lua_State *L, int i, const char *defval) 32 | { 33 | const char *options[] = {"compressed", "uncompressed", "hybrid", NULL}; 34 | int f = luaL_checkoption(L, i, defval, options); 35 | point_conversion_form_t form = 0; 36 | 37 | if (f == 0) 38 | form = POINT_CONVERSION_COMPRESSED; 39 | else if (f == 1) 40 | form = POINT_CONVERSION_UNCOMPRESSED; 41 | else if (f == 2) 42 | form = POINT_CONVERSION_HYBRID; 43 | else 44 | luaL_argerror(L, i, "invalid parameter, only support 'compressed', 'uncompressed' or 'hybrid'"); 45 | 46 | return form; 47 | } 48 | 49 | int openssl_push_point_conversion_form(lua_State *L, point_conversion_form_t form) 50 | { 51 | if (form == POINT_CONVERSION_COMPRESSED) 52 | lua_pushstring(L, "compressed"); 53 | else if (form == POINT_CONVERSION_UNCOMPRESSED) 54 | lua_pushstring(L, "uncompressed"); 55 | else if (form == POINT_CONVERSION_HYBRID) 56 | lua_pushstring(L, "hybrid"); 57 | else 58 | lua_pushnil(L); 59 | 60 | return 1; 61 | } 62 | 63 | EC_GROUP * 64 | openssl_get_ec_group(lua_State *L, int ec_name_idx, int conv_form_idx, int asn1_flags_idx) 65 | { 66 | int nid = NID_undef; 67 | EC_GROUP *g = NULL; 68 | 69 | /* ec_name can be number|string|evp_pkey|ec_key */ 70 | if (lua_isnumber(L, ec_name_idx)) 71 | nid = lua_tointeger(L, ec_name_idx); 72 | else if (lua_isstring(L, ec_name_idx)) { 73 | const char *name = luaL_checkstring(L, ec_name_idx); 74 | nid = OBJ_txt2nid(name); 75 | } else if (lua_isuserdata(L, ec_name_idx)) { 76 | if (auxiliar_getclassudata(L, "openssl.evp_pkey", ec_name_idx)) { 77 | EVP_PKEY *pkey = CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey"); 78 | EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(pkey); 79 | if (ec_key) { 80 | g = (EC_GROUP *)EC_KEY_get0_group(ec_key); 81 | EC_KEY_free(ec_key); 82 | } 83 | } else if (auxiliar_getclassudata(L, "openssl.ec_key", ec_name_idx)) { 84 | EC_KEY *ec_key = CHECK_OBJECT(1, EC_KEY, "openssl.ec_key"); 85 | g = (EC_GROUP *)EC_KEY_get0_group(ec_key); 86 | } 87 | if (g) g = EC_GROUP_dup(g); 88 | } 89 | 90 | if (g == NULL && nid != NID_undef) g = EC_GROUP_new_by_curve_name(nid); 91 | 92 | if (g) { 93 | /* conv_form can be number|string|nil */ 94 | if (conv_form_idx) { 95 | int form = 0; 96 | int type = lua_type(L, conv_form_idx); 97 | if (type == LUA_TSTRING) { 98 | form = openssl_to_point_conversion_form(L, conv_form_idx, NULL); 99 | EC_GROUP_set_point_conversion_form(g, form); 100 | } else if (type == LUA_TNUMBER) { 101 | form = luaL_checkint(L, conv_form_idx); 102 | EC_GROUP_set_point_conversion_form(g, form); 103 | } else if (lua_isnoneornil(L, conv_form_idx)) { 104 | EC_GROUP_set_point_conversion_form(g, POINT_CONVERSION_UNCOMPRESSED); 105 | } else 106 | luaL_argerror(L, conv_form_idx, "not accept type of point_conversion_form"); 107 | } else 108 | EC_GROUP_set_point_conversion_form(g, POINT_CONVERSION_UNCOMPRESSED); 109 | 110 | /* asn1_flags can be number|string|nil */ 111 | if (asn1_flags_idx) { 112 | int asn1_flag = 0; 113 | int type = lua_type(L, asn1_flags_idx); 114 | if (type == LUA_TSTRING) { 115 | asn1_flag = openssl_to_group_asn1_flag(L, asn1_flags_idx, NULL); 116 | EC_GROUP_set_asn1_flag(g, asn1_flag); 117 | } else if (type == LUA_TNUMBER) { 118 | asn1_flag = luaL_checkint(L, asn1_flags_idx); 119 | EC_GROUP_set_asn1_flag(g, asn1_flag); 120 | } else if (lua_isnoneornil(L, asn1_flags_idx)) { 121 | EC_GROUP_set_asn1_flag(g, OPENSSL_EC_NAMED_CURVE); 122 | } else 123 | luaL_argerror(L, asn1_flags_idx, "not accept type of asn1 flag"); 124 | } else 125 | EC_GROUP_set_asn1_flag(g, OPENSSL_EC_NAMED_CURVE); 126 | } 127 | 128 | return g; 129 | } 130 | 131 | -------------------------------------------------------------------------------- /docs/OSSL_PARAM_USAGE.md: -------------------------------------------------------------------------------- 1 | # OSSL_PARAM API Usage Guide 2 | 3 | ## Overview 4 | 5 | Starting with OpenSSL 3.0, the OSSL_PARAM API is the modern way to access cryptographic key parameters. lua-openssl now supports this API while maintaining backward compatibility with OpenSSL 1.x. 6 | 7 | ## What is OSSL_PARAM? 8 | 9 | OSSL_PARAM is OpenSSL 3.0's unified parameter system that replaces many legacy key access functions. It provides a consistent interface for accessing parameters across different key types (RSA, EC, DH, etc.). 10 | 11 | ## Supported Parameters 12 | 13 | ### RSA Key Parameters 14 | 15 | The following RSA parameters are accessible via the param module: 16 | 17 | ```lua 18 | local param = require("openssl").param 19 | 20 | -- Available RSA parameters: 21 | -- param.rsa.n - Modulus (public) 22 | -- param.rsa.e - Public exponent 23 | -- param.rsa.d - Private exponent 24 | -- param.rsa["rsa-factor1"] - Prime p 25 | -- param.rsa["rsa-factor2"] - Prime q 26 | -- param.rsa["rsa-exponent1"] - dmp1 (d mod (p-1)) 27 | -- param.rsa["rsa-exponent2"] - dmq1 (d mod (q-1)) 28 | -- param.rsa["rsa-coefficient1"] - iqmp (q^-1 mod p) 29 | ``` 30 | 31 | ### KDF Parameters 32 | 33 | KDF parameters continue to work as before. See `test/2.kdf.lua` for examples. 34 | 35 | ## Usage Examples 36 | 37 | ### Parsing RSA Key Parameters 38 | 39 | ```lua 40 | local openssl = require("openssl") 41 | local rsa = openssl.rsa 42 | 43 | -- Generate an RSA key 44 | local key = rsa.generate_key(2048) 45 | 46 | -- Parse the key to access parameters 47 | local params = key:parse() 48 | 49 | -- Access parameters 50 | print("Key size:", params.size, "bytes") 51 | print("Key bits:", params.bits) 52 | 53 | -- Access public parameters (always available) 54 | print("Modulus n:", params.n) -- BIGNUM object 55 | print("Exponent e:", params.e) -- BIGNUM object 56 | 57 | -- Access private parameters (only for private keys) 58 | if params.d then 59 | print("Private exponent d:", params.d) 60 | print("Prime p:", params.p) 61 | print("Prime q:", params.q) 62 | print("CRT exponent dmp1:", params.dmp1) 63 | print("CRT exponent dmq1:", params.dmq1) 64 | print("CRT coefficient iqmp:", params.iqmp) 65 | end 66 | ``` 67 | 68 | ### Checking Parameter Availability 69 | 70 | ```lua 71 | local param = require("openssl").param 72 | 73 | -- Check what RSA parameters are defined 74 | for name, info in pairs(param.rsa) do 75 | print(string.format("Parameter: %s, Type: %d", name, info.type)) 76 | if info.number_type then 77 | print(string.format(" Number type: %s", info.number_type)) 78 | end 79 | end 80 | ``` 81 | 82 | ## Implementation Details 83 | 84 | ### OpenSSL 3.0+ Path 85 | 86 | When running on OpenSSL 3.0 or later, `rsa:parse()` uses the modern `EVP_PKEY_get_bn_param()` API to extract parameters. This is the recommended approach for new code. 87 | 88 | ### OpenSSL 1.x Path 89 | 90 | On OpenSSL 1.x, or when the PARAM API fails (e.g., for legacy keys), the implementation automatically falls back to the traditional `RSA_get0_key()`, `RSA_get0_factors()`, and `RSA_get0_crt_params()` functions. 91 | 92 | ### Compatibility 93 | 94 | The dual-path implementation ensures: 95 | - ✅ Works with OpenSSL 1.x (using legacy API) 96 | - ✅ Works with OpenSSL 3.0+ (using PARAM API) 97 | - ✅ Handles keys created with either API version 98 | - ✅ No changes required to existing code 99 | - ✅ Same behavior across versions 100 | 101 | ## Testing 102 | 103 | The implementation includes comprehensive tests in `test/2.param.lua`: 104 | 105 | ```bash 106 | # Run param tests 107 | cd test 108 | lua 2.param.lua 109 | ``` 110 | 111 | ## Future Enhancements 112 | 113 | The current implementation focuses on RSA parameters. Future updates may include: 114 | - EC (Elliptic Curve) key parameters 115 | - DH (Diffie-Hellman) parameters 116 | - DSA parameters 117 | - General-purpose OSSL_PARAM array creation from Lua 118 | 119 | ## References 120 | 121 | - [OpenSSL 3.0 Migration Guide](https://www.openssl.org/docs/man3.0/man7/migration_guide.html) 122 | - [OSSL_PARAM Documentation](https://www.openssl.org/docs/man3.0/man3/OSSL_PARAM.html) 123 | - [lua-openssl ROADMAP](ROADMAP.md) 124 | - [Task 2.5 Details](ROADMAP_CN.md#25-openssl-30-ossl_param-api-绑定) 125 | 126 | ## Contributing 127 | 128 | To extend OSSL_PARAM support to other key types: 129 | 130 | 1. Add parameter definitions to `src/param.c` (similar to `rsa_params[]`) 131 | 2. Update `get_param_type()` to recognize the new parameters 132 | 3. Export parameters in `luaopen_param()` 133 | 4. Implement parameter access in the relevant module (e.g., `src/ec.c` for EC keys) 134 | 5. Add tests to verify functionality 135 | 136 | See the RSA implementation as a reference example. 137 | -------------------------------------------------------------------------------- /test/2.digest.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | local openssl = require("openssl") 3 | local digest = require("openssl").digest 4 | local helper = require("helper") 5 | local unpack = unpack or table.unpack 6 | 7 | TestDigestCompat = {} 8 | function TestDigestCompat:setUp() 9 | self.msg = "abcd" 10 | self.alg = "sha1" 11 | end 12 | 13 | function TestDigestCompat:tearDown() end 14 | 15 | function TestDigestCompat:testDigest() 16 | local a, b, c 17 | a = digest.digest(self.alg, self.msg) 18 | lu.assertEquals(#a, 40) 19 | 20 | b = digest.digest(self.alg, self.msg, false) 21 | lu.assertEquals(#b, 40) 22 | lu.assertEquals(a, b) 23 | c = digest.digest(self.alg, self.msg, true) 24 | lu.assertEquals(#c, 20) 25 | 26 | local o = openssl.asn1.new_object(self.alg) 27 | assert(type(o:nid()) == "number") 28 | 29 | c = digest.digest(o:nid(), self.msg, true) 30 | lu.assertEquals(#c, 20) 31 | 32 | c = digest.digest(o, self.msg, true) 33 | lu.assertEquals(#c, 20) 34 | end 35 | 36 | function TestDigestCompat:testObject() 37 | local a, b, c, aa, bb 38 | local obj = digest.new(self.alg) 39 | assert(obj:update(self.msg)) 40 | a = obj:final() 41 | obj:reset() 42 | b = obj:final(self.msg, false) 43 | assert(a == b) 44 | assert(#a == 40) 45 | 46 | obj:reset() 47 | assert(obj:update(self.msg)) 48 | c = obj:final(self.msg, true) 49 | lu.assertEquals(2 * #c, #a) 50 | 51 | obj:reset() 52 | obj:update(self.msg) 53 | aa = obj:final(self.msg) 54 | 55 | obj:reset() 56 | bb = obj:final(self.msg .. self.msg) 57 | lu.assertEquals(aa, bb) 58 | end 59 | 60 | TestDigestMY = {} 61 | function TestDigestMY:testList() 62 | local t1, t2, t3, t 63 | t1 = digest.list(true) 64 | t2 = digest.list() 65 | assert(#t1 == #t2) 66 | t3 = digest.list(false) 67 | assert(#t1 > #t3) 68 | local md = digest.get("sha1") 69 | t = md:info() 70 | assert(t.size == 20) 71 | t = md:digest("abcd") 72 | assert(type(t) == "string") 73 | assert(#t == 20) 74 | 75 | local ctx1 = md:new() 76 | t1 = ctx1:info() 77 | assert(ctx1:update("ab")) 78 | local dat = ctx1:data() 79 | if dat then 80 | local ctx = digest.new("sha1") 81 | t2 = ctx:info() 82 | for k, _ in pairs(t1) do 83 | if k ~= "digest" then 84 | assert(t1[k] == t2[k]) 85 | end 86 | end 87 | assert(ctx:data(dat)) 88 | assert(t1.size == 20) 89 | assert(ctx:update("cd")) 90 | t2 = ctx:final(true) 91 | assert(t == t2) 92 | end 93 | end 94 | 95 | local function mk_key(args) 96 | assert(type(args), "table") 97 | 98 | local k = assert(openssl.pkey.new(unpack(args))) 99 | return k 100 | end 101 | 102 | TestDigestSignVry = {} 103 | function TestDigestSignVry:setUp() 104 | self.msg = "abcd" 105 | self.alg = "sha1" 106 | self.prik = mk_key({ "rsa", 2048, 3 }) 107 | self.pubk = assert(openssl.pkey.get_public(self.prik)) 108 | end 109 | 110 | function TestDigestSignVry:testSignVry() 111 | local md = assert(digest.get(self.alg)) 112 | local sctx = digest.signInit(md, self.prik) 113 | assert(sctx:signUpdate(self.msg)) 114 | assert(sctx:signUpdate(self.msg)) 115 | local sig = sctx:signFinal() 116 | lu.assertEquals(#sig, 256) 117 | local vctx = digest.verifyInit(md, self.pubk) 118 | assert(vctx:verifyUpdate(self.msg)) 119 | assert(vctx:verifyUpdate(self.msg)) 120 | assert(vctx:verifyFinal(sig)) 121 | end 122 | 123 | function TestDigestSignVry:testSignVry1() 124 | local md = digest.get(self.alg) 125 | local sctx = md:signInit(self.prik) 126 | assert(sctx:signUpdate(self.msg)) 127 | assert(sctx:signUpdate(self.msg)) 128 | local sig = sctx:signFinal() 129 | lu.assertEquals(#sig, 256) 130 | local vctx = md:verifyInit(self.pubk) 131 | assert(vctx:verifyUpdate(self.msg)) 132 | assert(vctx:verifyUpdate(self.msg)) 133 | assert(vctx:verifyFinal(sig)) 134 | end 135 | 136 | function TestDigestOneShotSignVry_ED25519() 137 | local pkey = openssl.pkey 138 | if pkey.ED25519 and not helper.libressl then 139 | local ctx = assert(pkey.ctx_new("ED25519")) 140 | local k = assert(ctx:keygen()) 141 | local msg = "abcd" 142 | 143 | local sctx = assert(digest.signInit(nil, k)) 144 | local sig = assert(sctx:sign(msg)) 145 | 146 | local vctx = digest.verifyInit(nil, k) 147 | assert(vctx:verify(sig, msg)) 148 | end 149 | end 150 | 151 | function TestDigestOneShotSignVry_ED448() 152 | local pkey = openssl.pkey 153 | if pkey.ED448 and not helper.libressl then 154 | local ctx = assert(pkey.ctx_new("ED448")) 155 | local k = assert(ctx:keygen()) 156 | local msg = "abcd" 157 | 158 | local sctx = assert(digest.signInit(nil, k)) 159 | local sig = assert(sctx:sign(msg)) 160 | 161 | local vctx = digest.verifyInit(nil, k) 162 | assert(vctx:verify(sig, msg)) 163 | end 164 | end 165 | -------------------------------------------------------------------------------- /test/5.x509_crl.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | 3 | local helper = require("helper") 4 | local openssl = require("openssl") 5 | local crl, csr = openssl.x509.crl, openssl.x509.req 6 | 7 | TestCRL = {} 8 | function TestCRL:setUp() 9 | self.alg = "sha1" 10 | 11 | self.dn = openssl.x509.name.new({ { commonName = "DEMO" }, { C = "CN" } }) 12 | 13 | self.digest = "sha1WithRSAEncryption" 14 | self.fake_subject = openssl.x509.name.new({ { commonName = "Fake" }, { C = "CN" } }) 15 | end 16 | 17 | function TestCRL:testReason() 18 | local reasons = crl.reason() 19 | assert(#reasons >= 10) 20 | end 21 | 22 | function TestCRL:testNew() 23 | local ca = helper.get_ca() 24 | 25 | local pkey = assert(openssl.pkey.new()) 26 | local fake = assert(csr.new(self.fake_subject, pkey)) 27 | fake = assert(fake:to_x509(pkey, 3650)) -- self sign 28 | 29 | local other = crl.new() 30 | assert(other:issuer(ca.cacert)) 31 | assert(other:version(0)) 32 | assert(other:lastUpdate(os.time())) 33 | assert(other:nextUpdate(os.time() + 24 * 3600)) 34 | local ret, err = other:sign(ca.pkey, fake) 35 | assert(not ret) 36 | lu.assertStrMatches("private key not match with cacert", err) 37 | 38 | local list = assert(crl.new({ 39 | { sn = 1, time = os.time() }, 40 | { sn = 2, time = os.time() }, 41 | { sn = 3, time = os.time() }, 42 | { sn = 4, time = os.time() }, 43 | }, ca.cacert, ca.pkey)) 44 | assert(#list == 4) 45 | -- print_r(list:parse()) 46 | other = crl.new() 47 | assert(other:issuer(ca.cacert:issuer())) 48 | issuer = other:issuer() 49 | assert(other:issuer(ca.cacert)) 50 | assert(issuer:cmp(other:issuer())) 51 | assert(other:version(0)) 52 | assert(other:lastUpdate(os.time())) 53 | assert(other:nextUpdate(os.time() + 24 * 3600)) 54 | 55 | assert(other:add("21234", os.time())) 56 | assert(other:add("31234", os.time())) 57 | assert(other:add("41234", os.time())) 58 | assert(other:add("11234", os.time())) 59 | 60 | assert(other:sign(ca.pkey, ca.cacert)) 61 | assert(other:verify(ca.cacert)) 62 | local pem = other:export() 63 | 64 | assert(other:updateTime(3600)) 65 | assert(other:updateTime(os.time(), 3600)) 66 | 67 | assert(other:extensions({ 68 | openssl.x509.extension.new_extension({ object = "basicConstraints", value = "CA:FALSE" }), 69 | })) 70 | 71 | local exts = other:extensions() 72 | assert(#exts == 1) 73 | assert(tostring(exts[1]):match("openssl.x509_extension")) 74 | 75 | assert(other:add("21234", os.time())) 76 | assert(other:sort()) 77 | assert(other:sign(ca.pkey, ca.cacert:issuer())) 78 | assert(other:verify(ca.cacert)) 79 | assert(other:verify(ca.pkey)) 80 | 81 | assert(other:export()) 82 | local info = other:parse() 83 | 84 | assert(type(info.revoked) == "table") 85 | assert(type(info.extensions) == "table") 86 | local t = other:get(0, true) 87 | lu.assertIsTable(t) 88 | assert(type(other:digest()) == "string") 89 | local r = other:get(0) 90 | info = r:info() 91 | assert(type(info) == "table") 92 | assert(info.code) 93 | assert(info.reason) 94 | assert(info.revocationDate) 95 | assert(info.serialNumber) 96 | assert(info.extensions) 97 | 98 | local code, reason = r:reason() 99 | assert(type(code) == "number") 100 | assert(type(reason) == "string") 101 | assert(r:revocationDate()) 102 | assert(r:serialNumber()) 103 | assert(r:extensions()) 104 | 105 | if other.diff then 106 | local crx = crl.read(pem) 107 | local diff = other:diff(crx, ca.pkey) 108 | if diff then 109 | diff = diff:get("21234") 110 | assert(type(diff) == "table") 111 | 112 | assert(#diff == 1) 113 | end 114 | end 115 | end 116 | 117 | function TestCRL:testRead() 118 | local dat = [[ 119 | -----BEGIN X509 CRL----- 120 | MIIBNDCBnjANBgkqhkiG9w0BAQIFADBFMSEwHwYDVQQKExhFdXJvcGVhbiBJQ0Ut 121 | VEVMIFByb2plY3QxIDAeBgNVBAsTF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05 122 | NzA2MDkxNDQyNDNaFw05NzA3MDkxNDQyNDNaMCgwEgIBChcNOTcwMzAzMTQ0MjU0 123 | WjASAgEJFw05NjEwMDIxMjI5MjdaMA0GCSqGSIb3DQEBAgUAA4GBAH4vgWo2Tej/ 124 | i7kbiw4Imd30If91iosjClNpBFwvwUDBclPEeMuYimHbLOk4H8Nofc0fw11+U/IO 125 | KSNouUDcqG7B64oY7c4SXKn+i1MWOb5OJiWeodX3TehHjBlyWzoNMWCnYA8XqFP1 126 | mOKp8Jla1BibEZf14+/HqCi2hnZUiEXh 127 | -----END X509 CRL----- 128 | ]] 129 | local r = crl.read(dat) 130 | lu.assertIsTable(r:parse()) 131 | -- print_r(r:parse()) 132 | local e = r:export() 133 | lu.assertEquals(e, dat) 134 | e = r:export("der") 135 | local r1 = crl.read(e) 136 | assert(r:cmp(r1) == (r == r1)) 137 | assert(r == r1) 138 | 139 | lu.assertEquals(r:version(), 0) 140 | lu.assertEquals(r:issuer():tostring(), "/O=European ICE-TEL Project/OU=Certification Authority") 141 | lu.assertEquals(r:lastUpdate():toprint(), "Jun 9 14:42:43 1997 GMT") 142 | lu.assertEquals(r:nextUpdate():toprint(), "Jul 9 14:42:43 1997 GMT") 143 | lu.assertEquals(r:extensions(), nil) 144 | local l, n = r:updateTime() 145 | lu.assertEquals(r:lastUpdate(), l) 146 | lu.assertEquals(r:nextUpdate(), n) 147 | 148 | lu.assertEquals(r:count(), #r) 149 | lu.assertEquals(#r, 2) 150 | end 151 | -------------------------------------------------------------------------------- /test/6.cms.lua: -------------------------------------------------------------------------------- 1 | local lu = require("luaunit") 2 | 3 | local openssl = require("openssl") 4 | local cms, csr = openssl.cms, openssl.x509.req 5 | local helper = require("helper") 6 | if not cms then 7 | print("Skip cms test") 8 | return 9 | end 10 | 11 | TestCMS = {} 12 | 13 | -- need OpenSSL build with zlib support 14 | 15 | function TestCMS:testCompress() 16 | local msg = openssl.random(1000) 17 | 18 | if cms.compression then 19 | for i = 1, #cms.compression do 20 | local comp_alg = cms.compression[i] 21 | local cs, err, code = cms.compress(msg, comp_alg, cms.flags.binary) 22 | if cs then 23 | local ret = assert(cms.uncompress(cs)) 24 | lu.assertEquals(msg, ret) 25 | else 26 | local tips = "WARNING: %d:%s, maybe openssl without compress support" 27 | print(string.format(tips, code, err)) 28 | end 29 | end 30 | end 31 | 32 | msg = "hello world" 33 | local cs, err, code = cms.compress(msg) 34 | if cs then 35 | local ret = assert(cms.uncompress(cs)) 36 | lu.assertEquals(msg, ret) 37 | else 38 | local tips = "WARNING: %d:%s, maybe openssl without compress support" 39 | print(string.format(tips, code, err)) 40 | end 41 | end 42 | 43 | function TestCMS:setUp() 44 | self.alg = "sha1" 45 | self.cadn = { { commonName = "CA" }, { C = "CN" } } 46 | self.alicedn = { { commonName = "Alice" }, { C = "CN" } } 47 | self.bobdn = { { commonName = "Bob" }, { C = "CN" } } 48 | 49 | local ca = helper.get_ca() 50 | 51 | self.ca = ca 52 | 53 | local req, pkey = helper.new_req(self.alicedn) 54 | local cert = ca:sign(req) 55 | self.alice = { key = pkey, cert = cert } 56 | 57 | cert, pkey = assert(helper.sign(self.bobdn)) 58 | self.bob = { key = pkey, cert = cert } 59 | 60 | self.msg = openssl.hex(openssl.random(128)) 61 | self.digest = "sha1WithRSAEncryption" 62 | self.castore = assert(ca:get_store()) 63 | 64 | local c = cms.new() 65 | assert(c) 66 | end 67 | 68 | function TestCMS:testEncrypt() 69 | local opts = { 70 | self.alice.cert, 71 | key = "1234567890abcdef", 72 | keyid = "aes-128-cbc", 73 | password = "secret", 74 | } 75 | local msg = assert(cms.encrypt(self.msg, opts)) 76 | local smime = assert(cms.export(msg)) 77 | local ss = assert(cms.read(smime, "smime")) 78 | local raw = assert(cms.decrypt(ss, self.alice.key, self.alice.cert, nil, 0, opts)) 79 | lu.assertEquals(raw, self.msg) 80 | end 81 | 82 | function TestCMS:testSign() 83 | local c1 = assert(cms.sign(self.bob.cert, self.bob.key, self.msg, {})) 84 | assert(cms.export(c1)) 85 | local msg = assert(cms.verify(c1, { self.bob.cert }, self.castore)) 86 | lu.assertEquals(msg, self.msg) 87 | msg = assert(cms.verify(c1, {}, self.castore)) 88 | lu.assertEquals(msg, self.msg) 89 | assert(c1:get_signers()[1] == self.bob.cert) 90 | end 91 | 92 | function TestCMS:testSignReceipt() 93 | local c1 = assert(cms.sign(self.bob.cert, self.bob.key, self.msg, { self.ca.cert })) 94 | assert(c1:add_receipt({ "alice" }, { "bob" })) 95 | 96 | local rc = assert(c1:sign_receipt(self.alice.cert, self.alice.key, { self.ca.cert }, 0)) 97 | assert(rc:verify_receipt(c1, { self.bob.cert }, self.castore, 0)) 98 | end 99 | 100 | function TestCMS:testEncryptedData() 101 | local key = openssl.random(16) 102 | local c1 = assert(cms.EncryptedData_encrypt(self.msg, key)) 103 | assert(cms.export(c1)) 104 | local msg = assert(cms.EncryptedData_decrypt(c1, key)) 105 | lu.assertEquals(msg, self.msg) 106 | end 107 | 108 | function TestCMS:testDigest() 109 | local key = openssl.random(24) 110 | assert(key) 111 | local c1 = assert(cms.digest_create(self.msg)) 112 | local smime = assert(cms.export(c1)) 113 | assert(smime) 114 | local msg = assert(cms.digest_verify(c1)) 115 | lu.assertEquals(msg, self.msg) 116 | 117 | c1 = assert(cms.digest_create(self.msg, "sha1")) 118 | smime = assert(cms.export(c1)) 119 | assert(smime) 120 | msg = assert(c1:digest_verify()) 121 | lu.assertEquals(msg, self.msg) 122 | 123 | assert(c1:detached(true)) 124 | assert(c1:detached() == true) 125 | msg = assert(c1:digest_verify(self.msg)) 126 | lu.assertEquals(msg, self.msg) 127 | end 128 | 129 | function TestCMS:testData() 130 | local c = cms.data("data") 131 | assert(c) 132 | assert(c:detached() == false) 133 | assert(c:type()) 134 | assert(c:data() == "data") 135 | assert(c:content() == "data") 136 | 137 | local d = assert(c:export("data", 0, "der")) 138 | assert(cms.read(d, "auto")) 139 | d = cms.read(d, "der") 140 | assert(d) 141 | d = assert(c:export("data", 0, "pem")) 142 | d = cms.read(d, "pem") 143 | assert(d) 144 | d = assert(c:export("data", 0, "smime")) 145 | d = cms.read(d, "smime") 146 | assert(d) 147 | 148 | assert(c:detached(true)) 149 | assert(c:detached() == true) 150 | -- NOTES: deatched not support data 151 | -- d = assert(c:export("data", 0, "der")) 152 | -- assert(d) 153 | 154 | c = assert(cms.data("data", cms.flags.stream + cms.flags.partial)) 155 | assert(c:final("aaaa")) 156 | assert(c:data() == "aaaa") 157 | end 158 | -------------------------------------------------------------------------------- /test/rsa.lua: -------------------------------------------------------------------------------- 1 | local openssl = require("openssl") 2 | local rsa = require("openssl").rsa 3 | local helper = require("helper") 4 | 5 | local function checkRSA(r, c) 6 | local t = r:parse() 7 | for _, v in pairs(t) do 8 | if type(v) == "userdata" then 9 | if c then 10 | print(_, v:bits()) 11 | end 12 | if _ == "q" or _ == "p" or _ == "dmp1" or _ == "dmq1" or _ == "iqmp" then 13 | if v:bits() ~= t.bits / 2 then 14 | print(_, v:bits(), t.bits / 2) 15 | return false 16 | end 17 | elseif _ == "d" and v:bits() ~= t.bits then 18 | print(_, v:bits(), t.bits) 19 | return false 20 | elseif _ ~= "e" and v:bits() + 7 < t.bits then 21 | print(_, v:bits(), t.bits) 22 | return false 23 | end 24 | end 25 | end 26 | return true 27 | end 28 | 29 | TestRSA = {} 30 | function TestRSA:TestRSA() 31 | local k = rsa.generate_key(2048) 32 | --repeat 33 | -- k= rsa.generate_key(2048) 34 | --until checkRSA(k) 35 | 36 | assert(k:isprivate()) 37 | 38 | local t = k:parse() 39 | assert(t.bits == 2048) 40 | assert(t.size == 256) 41 | 42 | if rsa.encrypt then 43 | assert(k:size() == 256) 44 | 45 | local padding = { 46 | "sslv23", 47 | "pkcs1", 48 | "x931", 49 | "oaep", 50 | "no", 51 | } 52 | 53 | if openssl.engine then 54 | k:set_engine(openssl.engine("openssl")) 55 | end 56 | 57 | for _ = 1, #padding + 1 do 58 | local pad = padding[_] 59 | local msg = string.char(0) .. openssl.random(pad == "no" and 255 or 200) 60 | 61 | local out, raw 62 | if pad ~= "oaep" and pad ~= "sslv23" then 63 | local n = openssl.bn.text(msg) 64 | assert(n:bits() < t.n:bits()) 65 | out = assert(rsa.encrypt(k, msg, pad, true), pad) 66 | raw = assert(k:decrypt(out, pad, false)) 67 | assert(msg == raw) 68 | end 69 | 70 | if pad ~= "sslv23" and pad ~= "x931" then 71 | out = assert(rsa.encrypt(k, msg, pad, false), pad) 72 | raw = assert(k:decrypt(out, pad, true)) 73 | assert(msg == raw) 74 | end 75 | 76 | msg = openssl.random(32) 77 | out = assert(rsa.sign(k, msg, "sha256")) 78 | assert(k:verify(msg, out, "sha256")) 79 | end 80 | end 81 | 82 | local der = k:export() 83 | assert(rsa.read(der)) 84 | 85 | der = k:export(false) 86 | k = rsa.read(der, false) 87 | assert(not k:isprivate()) 88 | end 89 | 90 | function TestRSA:TestPad_pkcs1() 91 | local msg = openssl.random(128) 92 | local padded = rsa.padding_add(msg, "pkcs1", 256, true) 93 | local raw = rsa.padding_check(padded, "pkcs1", 256, true) 94 | assert(msg == raw) 95 | 96 | padded = rsa.padding_add(msg, "pkcs1", 256, false) 97 | raw = rsa.padding_check(padded, "pkcs1", 256, false) 98 | assert(msg == raw) 99 | end 100 | 101 | function TestRSA:TestPad_x931() 102 | if helper.libressl and helper._opensslv > 0x30800000 then 103 | return 104 | end 105 | local msg = openssl.random(128) 106 | local padded = rsa.padding_add(msg, "x931", 256) 107 | local raw = rsa.padding_check(padded, "x931", 256) 108 | assert(msg == raw) 109 | end 110 | 111 | function TestRSA:TestPad_none() 112 | local msg = openssl.random(256) 113 | local padded = rsa.padding_add(msg, "no", 256) 114 | local raw = rsa.padding_check(padded, "no", 256) 115 | assert(msg == raw) 116 | end 117 | 118 | function TestRSA:TestPad_oaep() 119 | local msg = openssl.random(128) 120 | local padded = rsa.padding_add(msg, "oaep", 256) 121 | local raw = rsa.padding_check(padded, "oaep", 256) 122 | assert(msg == raw) 123 | 124 | padded = rsa.padding_add(msg, "oaep", 256, "abcd") 125 | raw = rsa.padding_check(padded, "oaep", 256, "abcd") 126 | assert(msg == raw) 127 | 128 | padded = rsa.padding_add(msg, "oaep", 256, "abcd", "sha1") 129 | raw = rsa.padding_check(padded, "oaep", 256, "abcd", "sha1") 130 | assert(msg == raw) 131 | 132 | padded = rsa.padding_add(msg, "oaep", 256, "abcd", "sha256") 133 | raw = rsa.padding_check(padded, "oaep", 256, "abcd", "sha256") 134 | assert(msg == raw) 135 | end 136 | 137 | function TestRSA:TestOAEP_encrypt() 138 | local k = rsa.generate_key(2048) 139 | assert(k:isprivate()) 140 | 141 | local t = k:parse() 142 | assert(t.bits == 2048) 143 | assert(t.size == 256) 144 | 145 | local msg = openssl.random(128) 146 | local padded = rsa.padding_add(msg, "oaep", 256) 147 | 148 | local encrypted = assert(rsa.encrypt(k, padded, "no", false)) -- Public Encrypt 149 | local plain = assert(k:decrypt(encrypted, "no", true)) -- Private Decrypt 150 | 151 | assert(plain == padded) 152 | local raw = rsa.padding_check(padded, "oaep", 256) 153 | assert(msg == raw) 154 | end 155 | 156 | function TestRSA:TestPSS_sign() 157 | local k = rsa.generate_key(2048) 158 | assert(k:isprivate()) 159 | 160 | local t = k:parse() 161 | assert(t.bits == 2048) 162 | assert(t.size == 256) 163 | 164 | local msg = openssl.random(20) 165 | local padded = assert(rsa.padding_add(msg, "pss", k, "sha1")) 166 | local raw = assert(rsa.padding_check(padded, "pss", k, msg, "sha1")) 167 | assert(raw == true) 168 | 169 | local signed = assert(rsa.encrypt(k, padded, "no", false)) -- Private Encrypt 170 | local plain = assert(k:decrypt(signed, "no", true)) -- Public Decrypt 171 | 172 | assert(rsa.padding_check(plain, "pss", k, msg, "sha1")) 173 | end 174 | --------------------------------------------------------------------------------