Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ Table of Contents
+ [ssl_ctx.from_request](#ssl_ctxfrom_request)
+ [ssl_ctx.from_socket](#ssl_ctxfrom_socket)
+ [ssl_ctx:set_alpns](#ssl_ctxset_alpns)
* [resty.openssl.crypto](#restyopensslcrypto)
+ [crypto.memcmp](#cryptomemcmp)
* [Functions for stack-like objects](#functions-for-stack-like-objects)
+ [metamethods](#metamethods)
+ [each](#each)
Expand Down Expand Up @@ -4518,6 +4520,23 @@ literal for the protocol, like `"h2"`.

[Back to TOC](#table-of-contents)

## resty.openssl.crypto

Module to interact with utility openssl functions.

[Back to TOC](#table-of-contents)

### crypto.memcmp

**syntax**: *res, err = crypto.memcmp(a, b, len)*

Performs constant-time comparison of 2 memory regions a and b with len bytes. See [CRYPTO_memcmp](https://docs.openssl.org/3.2/man3/CRYPTO_memcmp)
for more info. The 2 memory regions must be of type string or cdata.

Returns 0 if the memory regions are equal and nonzero otherwise.

[Back to TOC](#table-of-contents)

## Functions for stack-like objects

[Back to TOC](#table-of-contents)
Expand Down
19 changes: 19 additions & 0 deletions lib/resty/openssl/crypto.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
local ffi = require "ffi"
local ffi_cast = ffi.cast
local C = ffi.C
require "resty.openssl.include.crypto"

local _M = {}

function _M.memcmp(a, b, len)
if type(len) ~= "number" or len < 1 then
return nil, "crypto:memcmp arg 'len' must be a number > 0"
end
if type(a) ~= "string" and type(a) ~= "cdata" then
return nil, "crypto:memcmp only strings and cdata types are supported"
end

return C.CRYPTO_memcmp(ffi_cast("void*", a), ffi_cast("void*", b), len)
end

return _M
1 change: 1 addition & 0 deletions lib/resty/openssl/include/crypto.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ ffi.cdef [[
int FIPS_mode(void);
int FIPS_mode_set(int ONOFF);
void CRYPTO_free(void *ptr, const char *file, int line);
int CRYPTO_memcmp(const void *a, const void *b, size_t len);
]]

local OPENSSL_free = function(ptr)
Expand Down
147 changes: 147 additions & 0 deletions t/openssl/crypto.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# vim:set ft= ts=4 sw=4 et fdm=marker:

use Test::Nginx::Socket::Lua 'no_plan';
use Cwd qw(cwd);


my $pwd = cwd();

my $use_luacov = $ENV{'TEST_NGINX_USE_LUACOV'} // '';

our $HttpConfig = qq{
lua_package_path "$pwd/lib/?.lua;$pwd/lib/?/init.lua;;";
init_by_lua_block {
if "1" == "$use_luacov" then
require 'luacov.tick'
jit.off()
end
}
};

run_tests();

__DATA__

=== TEST 1: memcmp: memory regions are equal
--- http_config eval: $::HttpConfig
--- config
location =/t {
content_by_lua_block {
local ffi = require("ffi")
local crypto = require("resty.openssl.crypto")
local res, err

-- test string
res, err = crypto.memcmp("abc", "abc", 3)
ngx.say(res)
ngx.say(err)

-- test cdata
local ffi_string_a = ffi.new("char[?]", 3)
ffi.copy(ffi_string_a, "abc")
local ffi_string_b = ffi.new("char[?]", 3)
ffi.copy(ffi_string_b, "abc")
res, err = crypto.memcmp(ffi_string_a, ffi_string_b, 3)
ngx.say(res)
ngx.say(err)
}
}
--- request
GET /t
--- response_body
0
nil
0
nil
--- no_error_log
[error]

=== TEST 2: memcmp: memory regions are not equal
--- http_config eval: $::HttpConfig
--- config
location =/t {
content_by_lua_block {
local ffi = require("ffi")
local crypto = require("resty.openssl.crypto")
local res, err

-- test string
res, err = crypto.memcmp("abc", "acc", 3)
ngx.say(res)
ngx.say(err)

-- test cdata
local ffi_string_a = ffi.new("char[?]", 3)
ffi.copy(ffi_string_a, "abc")
local ffi_string_b = ffi.new("char[?]", 3)
ffi.copy(ffi_string_b, "acc")
res, err = crypto.memcmp(ffi_string_a, ffi_string_b, 3)
ngx.say(res)
ngx.say(err)

ffi_string_a = ffi.new("char[?]", 4)
ffi.copy(ffi_string_a, "abc")
ffi_string_b = ffi.new("char[?]", 4)
ffi.copy(ffi_string_b, "abcd")
res, err = crypto.memcmp(ffi_string_a, ffi_string_b, 4)
ngx.say(res)
ngx.say(err)
}
}
--- request
GET /t
--- response_body
1
nil
1
nil
1
nil
--- no_error_log
[error]

=== TEST 3: memcmp: invalid arg len
--- http_config eval: $::HttpConfig
--- config
location =/t {
content_by_lua_block {
local crypto = require("resty.openssl.crypto")
local res, err = crypto.memcmp("123123123123", "123", -1)
ngx.say(res)
ngx.say(err)
}
}
--- request
GET /t
--- response_body
nil
crypto:memcmp arg 'len' must be a number > 0
--- no_error_log
[error]

=== TEST 4: memcmp: invalid arg types
--- http_config eval: $::HttpConfig
--- config
location =/t {
content_by_lua_block {
local crypto = require("resty.openssl.crypto")
res, err = crypto.memcmp(100, 102, 1)
ngx.say(res)
ngx.say(err)

local table_a = { "a", b=1, 101 }
local table_b = { "a", b=1, 102 }
res, err = crypto.memcmp(table_a, table_b, 2)
ngx.say(res)
ngx.say(err)
}
}
--- request
GET /t
--- response_body
nil
crypto:memcmp only strings and cdata types are supported
nil
crypto:memcmp only strings and cdata types are supported
--- no_error_log
[error]
Loading