Skip to content

Commit c66d7f2

Browse files
authored
feat(crypto) add crypto.memcmp bindings
1 parent 1c9e3f5 commit c66d7f2

4 files changed

Lines changed: 186 additions & 0 deletions

File tree

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ Table of Contents
282282
+ [ssl_ctx.from_request](#ssl_ctxfrom_request)
283283
+ [ssl_ctx.from_socket](#ssl_ctxfrom_socket)
284284
+ [ssl_ctx:set_alpns](#ssl_ctxset_alpns)
285+
* [resty.openssl.crypto](#restyopensslcrypto)
286+
+ [crypto.memcmp](#cryptomemcmp)
285287
* [Functions for stack-like objects](#functions-for-stack-like-objects)
286288
+ [metamethods](#metamethods)
287289
+ [each](#each)
@@ -4518,6 +4520,23 @@ literal for the protocol, like `"h2"`.
45184520

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

4523+
## resty.openssl.crypto
4524+
4525+
Module to interact with utility openssl functions.
4526+
4527+
[Back to TOC](#table-of-contents)
4528+
4529+
### crypto.memcmp
4530+
4531+
**syntax**: *res, err = crypto.memcmp(a, b, len)*
4532+
4533+
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)
4534+
for more info. The 2 memory regions must be of type string or cdata.
4535+
4536+
Returns 0 if the memory regions are equal and nonzero otherwise.
4537+
4538+
[Back to TOC](#table-of-contents)
4539+
45214540
## Functions for stack-like objects
45224541

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

lib/resty/openssl/crypto.lua

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
local ffi = require "ffi"
2+
local ffi_cast = ffi.cast
3+
local C = ffi.C
4+
require "resty.openssl.include.crypto"
5+
6+
local _M = {}
7+
8+
function _M.memcmp(a, b, len)
9+
if type(len) ~= "number" or len < 1 then
10+
return nil, "crypto:memcmp arg 'len' must be a number > 0"
11+
end
12+
if type(a) ~= "string" and type(a) ~= "cdata" then
13+
return nil, "crypto:memcmp only strings and cdata types are supported"
14+
end
15+
16+
return C.CRYPTO_memcmp(ffi_cast("void*", a), ffi_cast("void*", b), len)
17+
end
18+
19+
return _M

lib/resty/openssl/include/crypto.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ ffi.cdef [[
55
int FIPS_mode(void);
66
int FIPS_mode_set(int ONOFF);
77
void CRYPTO_free(void *ptr, const char *file, int line);
8+
int CRYPTO_memcmp(const void *a, const void *b, size_t len);
89
]]
910

1011
local OPENSSL_free = function(ptr)

t/openssl/crypto.t

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# vim:set ft= ts=4 sw=4 et fdm=marker:
2+
3+
use Test::Nginx::Socket::Lua 'no_plan';
4+
use Cwd qw(cwd);
5+
6+
7+
my $pwd = cwd();
8+
9+
my $use_luacov = $ENV{'TEST_NGINX_USE_LUACOV'} // '';
10+
11+
our $HttpConfig = qq{
12+
lua_package_path "$pwd/lib/?.lua;$pwd/lib/?/init.lua;;";
13+
init_by_lua_block {
14+
if "1" == "$use_luacov" then
15+
require 'luacov.tick'
16+
jit.off()
17+
end
18+
}
19+
};
20+
21+
run_tests();
22+
23+
__DATA__
24+
25+
=== TEST 1: memcmp: memory regions are equal
26+
--- http_config eval: $::HttpConfig
27+
--- config
28+
location =/t {
29+
content_by_lua_block {
30+
local ffi = require("ffi")
31+
local crypto = require("resty.openssl.crypto")
32+
local res, err
33+
34+
-- test string
35+
res, err = crypto.memcmp("abc", "abc", 3)
36+
ngx.say(res)
37+
ngx.say(err)
38+
39+
-- test cdata
40+
local ffi_string_a = ffi.new("char[?]", 3)
41+
ffi.copy(ffi_string_a, "abc")
42+
local ffi_string_b = ffi.new("char[?]", 3)
43+
ffi.copy(ffi_string_b, "abc")
44+
res, err = crypto.memcmp(ffi_string_a, ffi_string_b, 3)
45+
ngx.say(res)
46+
ngx.say(err)
47+
}
48+
}
49+
--- request
50+
GET /t
51+
--- response_body
52+
0
53+
nil
54+
0
55+
nil
56+
--- no_error_log
57+
[error]
58+
59+
=== TEST 2: memcmp: memory regions are not equal
60+
--- http_config eval: $::HttpConfig
61+
--- config
62+
location =/t {
63+
content_by_lua_block {
64+
local ffi = require("ffi")
65+
local crypto = require("resty.openssl.crypto")
66+
local res, err
67+
68+
-- test string
69+
res, err = crypto.memcmp("abc", "acc", 3)
70+
ngx.say(res)
71+
ngx.say(err)
72+
73+
-- test cdata
74+
local ffi_string_a = ffi.new("char[?]", 3)
75+
ffi.copy(ffi_string_a, "abc")
76+
local ffi_string_b = ffi.new("char[?]", 3)
77+
ffi.copy(ffi_string_b, "acc")
78+
res, err = crypto.memcmp(ffi_string_a, ffi_string_b, 3)
79+
ngx.say(res)
80+
ngx.say(err)
81+
82+
ffi_string_a = ffi.new("char[?]", 4)
83+
ffi.copy(ffi_string_a, "abc")
84+
ffi_string_b = ffi.new("char[?]", 4)
85+
ffi.copy(ffi_string_b, "abcd")
86+
res, err = crypto.memcmp(ffi_string_a, ffi_string_b, 4)
87+
ngx.say(res)
88+
ngx.say(err)
89+
}
90+
}
91+
--- request
92+
GET /t
93+
--- response_body
94+
1
95+
nil
96+
1
97+
nil
98+
1
99+
nil
100+
--- no_error_log
101+
[error]
102+
103+
=== TEST 3: memcmp: invalid arg len
104+
--- http_config eval: $::HttpConfig
105+
--- config
106+
location =/t {
107+
content_by_lua_block {
108+
local crypto = require("resty.openssl.crypto")
109+
local res, err = crypto.memcmp("123123123123", "123", -1)
110+
ngx.say(res)
111+
ngx.say(err)
112+
}
113+
}
114+
--- request
115+
GET /t
116+
--- response_body
117+
nil
118+
crypto:memcmp arg 'len' must be a number > 0
119+
--- no_error_log
120+
[error]
121+
122+
=== TEST 4: memcmp: invalid arg types
123+
--- http_config eval: $::HttpConfig
124+
--- config
125+
location =/t {
126+
content_by_lua_block {
127+
local crypto = require("resty.openssl.crypto")
128+
res, err = crypto.memcmp(100, 102, 1)
129+
ngx.say(res)
130+
ngx.say(err)
131+
132+
local table_a = { "a", b=1, 101 }
133+
local table_b = { "a", b=1, 102 }
134+
res, err = crypto.memcmp(table_a, table_b, 2)
135+
ngx.say(res)
136+
ngx.say(err)
137+
}
138+
}
139+
--- request
140+
GET /t
141+
--- response_body
142+
nil
143+
crypto:memcmp only strings and cdata types are supported
144+
nil
145+
crypto:memcmp only strings and cdata types are supported
146+
--- no_error_log
147+
[error]

0 commit comments

Comments
 (0)