Skip to content

Commit 11ea9ae

Browse files
committed
feat(*) add x509.digest and bn.to_hex
digest buffer now uses the exact block size of that algorithm
1 parent 7687573 commit 11ea9ae

File tree

11 files changed

+213
-16
lines changed

11 files changed

+213
-16
lines changed

README.md

+43-8
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Table of Contents
3232
+ [bn.istype](#bnistype)
3333
+ [bn.from_binary](#bnfrom_binary)
3434
+ [bn:to_binary](#bnto_binary)
35+
+ [bn:to_hex](#bnto_hex)
3536
* [resty.openssl.cipher](#restyopensslcipher)
3637
+ [cipher.new](#ciphernew)
3738
+ [cipher.istype](#cipheristype)
@@ -56,6 +57,8 @@ Table of Contents
5657
+ [x509.new](#x509new)
5758
+ [x509.istype](#x509istype)
5859
+ [x509:add_extension](#x509add_extension)
60+
+ [x509:digest](#x509digest)
61+
+ [x509:pubkey_digest](#x509pubkey_digest)
5962
+ [x509:get_*, x509:set_*](#x509get_-x509set_)
6063
+ [x509:get_lifetime](#x509get_lifetime)
6164
+ [x509:set_lifetime](#x509set_lifetime)
@@ -185,11 +188,11 @@ and `DIR` are supported.
185188
```lua
186189
local version = require("resty.openssl.version")
187190
ngx.say(string.format("%x", version.version_num))
188-
-- Outputs 101000bf
191+
-- outputs "101000bf"
189192
ngx.say(version.version_text)
190-
-- Outputs OpenSSL 1.1.0k 28 May 2019
193+
-- outputs "OpenSSL 1.1.0k 28 May 2019"
191194
ngx.say(version.version(version.PLATFORM))
192-
-- Outputs darwin64-x86_64-cc
195+
-- outputs "darwin64-x86_64-cc"
193196
```
194197

195198
### OPENSSL_11
@@ -336,11 +339,21 @@ ngx.say(ngx.encode_base64(bin))
336339

337340
Export the BIGNUM value in binary string.
338341

342+
343+
### bn:to_hex
344+
345+
**syntax**: *hex, err = bn:to_hex()*
346+
347+
Export the BIGNUM value in hex encoded string.
348+
339349
```lua
340350
local b, err = require("resty.openssl.bn").new(23333)
341351
local bin, err = b:to_binary()
342352
ngx.say(ngx.encode_base64(bin))
343353
-- outputs "WyU="
354+
local hex, err = b:to_hex()
355+
ngx.say(hex)
356+
-- outputs "5B25"
344357
```
345358

346359
## resty.openssl.cipher
@@ -449,7 +462,7 @@ ngx.say(cipher)
449462

450463
## resty.openssl.digest
451464

452-
Module to interact with message digest (EVP_MD).
465+
Module to interact with message digest (EVP_MD_CTX).
453466

454467
### digest.new
455468

@@ -581,6 +594,28 @@ local x509, err = require("resty.openssl.x509").new()
581594
local ok, err = x509:add_extension(extension)
582595
```
583596

597+
### x509:digest
598+
599+
**syntax**: *d, err = x509:digest(digest_name?)*
600+
601+
Returns a digest of the DER representation of the X509 certificate object in raw binary text.
602+
603+
`digest_name` is a case-insensitive string of digest algorithm name.
604+
To view a list of digest algorithms implemented, use `openssl list -digest-algorithms`.
605+
606+
If `digest_name` is omitted, it's by default to `sha1`.
607+
608+
### x509:pubkey_digest
609+
610+
**syntax**: *d, err = x509:pubkey_digest(digest_name?)*
611+
612+
Returns a digest of the DER representation of the pubkey in the X509 object in raw binary text.
613+
614+
`digest_name` is a case-insensitive string of digest algorithm name.
615+
To view a list of digest algorithms implemented, use `openssl list -digest-algorithms`.
616+
617+
If `digest_name` is omitted, it's by default to `sha1`.
618+
584619
### x509:get_*, x509:set_*
585620

586621
**syntax**: *ok, err = x509:set_attribute(instance)*
@@ -605,7 +640,7 @@ local x509, err = require("resty.openssl.x509").new()
605640
err = x509:set_not_before(ngx.time())
606641
local not_before, err = x509:get_not_before()
607642
ngx.say(not_before)
608-
-- Outputs 1571875065
643+
-- outputs 1571875065
609644
```
610645

611646
### x509:get_lifetime
@@ -712,7 +747,7 @@ Returns `true` if table is an instance of `altname`. Returns `false` otherwise.
712747

713748
**syntax**: *altname, err = altname:add(key, value)*
714749

715-
Adds a name to altname stack, first argument is case-insensitive and can be selection of
750+
Adds a name to altname stack, first argument is case-insensitive and can be one of
716751

717752
RFC822Name
718753
RFC822
@@ -845,8 +880,8 @@ If you plan to use this library on an untested version of OpenSSL (like custom b
845880
TODO
846881
====
847882

848-
- review get0 function calls to ensure there's no double free
849-
- find a way to test memory leak
883+
- test memory leak
884+
- add tests for x509 getters/setters
850885

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

lib/resty/openssl/bn.lua

+8
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ function _M:to_binary()
4545
return buf, nil
4646
end
4747

48+
function _M:to_hex()
49+
local buf = C.BN_bn2hex(self.ctx)
50+
if buf == nil then
51+
return nil, format_error("bn:to_hex")
52+
end
53+
return ffi_str(buf), nil
54+
end
55+
4856
function _M.from_binary(s)
4957
if type(s) ~= "string" then
5058
return nil, "expect a string at #1"

lib/resty/openssl/digest.lua

+7-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ local ffi_gc = ffi.gc
44
local ffi_new = ffi.new
55
local ffi_str = ffi.string
66

7-
require "resty.openssl.include.evp"
7+
local evp_macro = require "resty.openssl.include.evp"
88
local format_error = require("resty.openssl.err").format_error
99
local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10
1010
local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11
@@ -37,7 +37,10 @@ function _M.new(typ)
3737
return nil, format_error("digest.new")
3838
end
3939

40-
return setmetatable({ ctx = ctx }, mt), nil
40+
return setmetatable({
41+
ctx = ctx,
42+
md_size = C.EVP_MD_size(dtyp),
43+
}, mt), nil
4144
end
4245

4346
function _M.istype(l)
@@ -62,8 +65,8 @@ function _M:final(s)
6265
return nil, err
6366
end
6467
end
65-
-- # define EVP_MAX_MD_SIZE 64/* longest known is SHA512 */
66-
local buf = ffi_new('unsigned char[?]', 64)
68+
69+
local buf = ffi_new('unsigned char[?]', self.md_size)
6770
local length = uint_ptr()
6871
-- no return value of EVP_DigestFinal_ex
6972
C.EVP_DigestFinal_ex(self.ctx, buf, length)

lib/resty/openssl/hmac.lua

+7-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ local ffi_new = ffi.new
55
local ffi_str = ffi.string
66

77
require "resty.openssl.include.hmac"
8+
local evp_macro = require "resty.openssl.include.evp"
89
local format_error = require("resty.openssl.err").format_error
910
local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10
1011
local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11
@@ -38,7 +39,10 @@ function _M.new(key, typ)
3839
return nil, format_error("hmac.new")
3940
end
4041

41-
return setmetatable({ ctx = ctx }, mt), nil
42+
return setmetatable({
43+
ctx = ctx,
44+
md_size = C.EVP_MD_size(dtyp),
45+
}, mt), nil
4246
end
4347

4448
function _M.istype(l)
@@ -63,8 +67,8 @@ function _M:final(s)
6367
return nil, err
6468
end
6569
end
66-
-- # define EVP_MAX_MD_SIZE 64/* longest known is SHA512 */
67-
local buf = ffi_new('unsigned char[?]', 64)
70+
71+
local buf = ffi_new('unsigned char[?]', self.md_size)
6872
local length = uint_ptr()
6973
if C.HMAC_Final(self.ctx, buf, length) ~= 1 then
7074
return nil, format_error("hmac:final: HMAC_Final")

lib/resty/openssl/include/bn.lua

+1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ ffi.cdef(
1919
int BN_num_bits(const BIGNUM *a);
2020
BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
2121
int BN_bn2bin(const BIGNUM *a, unsigned char *to);
22+
char *BN_bn2hex(const BIGNUM *a);
2223
]]
2324
)

lib/resty/openssl/include/evp.lua

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ ffi.cdef [[
3030
EVP_PKEY *pkey);
3131
/*__owur*/ int EVP_VerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sigbuf,
3232
unsigned int siglen, EVP_PKEY *pkey);
33+
int EVP_MD_size(const EVP_MD *md);
3334

3435
int EVP_PKEY_get_default_digest_nid(EVP_PKEY *pkey, int *pnid);
3536
const EVP_MD *EVP_get_digestbyname(const char *name);

lib/resty/openssl/include/x509/init.lua

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ ffi.cdef [[
3737
int X509_set_subject_name(X509 *x, X509_NAME *name);
3838
int X509_set_issuer_name(X509 *x, X509_NAME *name);
3939

40+
int X509_pubkey_digest(const X509 *data, const EVP_MD *type,
41+
unsigned char *md, unsigned int *len);
42+
int X509_digest(const X509 *data, const EVP_MD *type,
43+
unsigned char *md, unsigned int *len);
4044
]]
4145

4246
if OPENSSL_11 then

lib/resty/openssl/x509/init.lua

+43
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
local ffi = require "ffi"
22
local C = ffi.C
33
local ffi_gc = ffi.gc
4+
local ffi_new = ffi.new
5+
local ffi_str = ffi.string
46

57
require "resty.openssl.include.x509"
8+
local evp_macro = require "resty.openssl.include.evp"
69
local asn1_lib = require("resty.openssl.asn1")
710
local digest_lib = require("resty.openssl.digest")
811
local util = require("resty.openssl.util")
@@ -337,6 +340,46 @@ function _M:sign(pkey, digest)
337340
return true
338341
end
339342

343+
local uint_ptr = ffi.typeof("unsigned int[1]")
344+
345+
local function digest(self, cfunc, typ)
346+
-- TODO: dedup the following with resty.openssl.digest
347+
local ctx
348+
if OPENSSL_11 then
349+
ctx = C.EVP_MD_CTX_new()
350+
ffi_gc(ctx, C.EVP_MD_CTX_free)
351+
elseif OPENSSL_10 then
352+
ctx = C.EVP_MD_CTX_create()
353+
ffi_gc(ctx, C.EVP_MD_CTX_destroy)
354+
end
355+
if ctx == nil then
356+
return nil, "failed to create EVP_MD_CTX"
357+
end
358+
359+
local dtyp = C.EVP_get_digestbyname(typ or 'sha1')
360+
if dtyp == nil then
361+
return nil, string.format("invalid digest type \"%s\"", typ)
362+
end
363+
364+
local md_size = C.EVP_MD_size(dtyp)
365+
local buf = ffi_new('unsigned char[?]', md_size)
366+
local length = uint_ptr()
367+
368+
if cfunc(self.ctx, dtyp, buf, length) ~= 1 then
369+
return nil, format_error("x509:digest")
370+
end
371+
372+
return ffi_str(buf, length[0])
373+
end
374+
375+
function _M:digest(typ)
376+
return digest(self, C.X509_digest, typ)
377+
end
378+
379+
function _M:pubkey_digest(typ)
380+
return digest(self, C.X509_pubkey_digest, typ)
381+
end
382+
340383
function _M:to_PEM()
341384
return util.read_using_bio(C.PEM_write_bio_X509, self.ctx)
342385
end

t/openssl/bn.t

+25
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,29 @@ bn:to_binary failed
119119
--- response_body eval
120120
"WyU="
121121
--- no_error_log
122+
[error]
123+
124+
=== TEST 5: Export as hex string
125+
--- http_config eval: $::HttpConfig
126+
--- config
127+
location =/t {
128+
content_by_lua_block {
129+
local bn, err = require("resty.openssl.bn").new(0x5b25)
130+
if err then
131+
ngx.log(ngx.ERR, err)
132+
return
133+
end
134+
local b, err = bn:to_hex()
135+
if err then
136+
ngx.log(ngx.ERR, err)
137+
return
138+
end
139+
ngx.print(b)
140+
}
141+
}
142+
--- request
143+
GET /t
144+
--- response_body eval
145+
"5B25"
146+
--- no_error_log
122147
[error]

t/openssl/pkey.t

+1-1
Original file line numberDiff line numberDiff line change
@@ -268,4 +268,4 @@ expect a digest instance at #2
268268
--- response_body_like eval
269269
"-----BEGIN PUBLIC KEY-----"
270270
--- no_error_log
271-
[error]
271+
[error]

0 commit comments

Comments
 (0)