Skip to content

Commit

Permalink
feat(err) standardize error format and add new API to get reason and
Browse files Browse the repository at this point in the history
library name
  • Loading branch information
fffonion committed Dec 13, 2023
1 parent 3c0027d commit d155657
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 31 deletions.
69 changes: 69 additions & 0 deletions README.md
Expand Up @@ -30,6 +30,11 @@ Table of Contents
* [resty.openssl.ctx](#restyopensslctx)
+ [ctx.new](#ctxnew)
+ [ctx.free](#ctxfree)
* [resty.openssl.err](#restyopensslerr)
+ [err.format_error](#errformat_error)
+ [err.get_last_error_code](#errget_last_error_code)
+ [err.get_lib_error_string](#errget_lib_error_string)
+ [err.get_reason_error_string](#errget_reason_error_string)
* [resty.openssl.version](#restyopensslversion)
+ [version_num](#version_num)
+ [version_text](#version_text)
Expand Down Expand Up @@ -556,6 +561,70 @@ Free the context that was previously created by [ctx.new](#ctxnew).

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

## resty.openssl.err

A module to provide error messages.

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

### err.format_error

**syntax**: *msg = err.format_error(ctx_msg?, return_code?, all_errors?)*
**syntax**: *msg = err.format_all_errors(ctx_msg?, return_code?)*

Return the latest error message from the last error code. Errors are formatted as:

[ctx_msg]: code: [return_code]: error:[error code]:[library name]:[func name]:[reason string]:[file name]:[line number]:

On OpenSSL prior to 3.x, errors are formatted as:

[ctx_msg]: code: [return_code]: [file name]:[line number]:error:[error code]:[library name]:[func name]:[reason string]:


If `all_errors` is set to `true`, all errors no just the latest one will be returned in a single string. All errors thrown
by this library internally only thrown the latest error.

For example:

```lua
local f = io.open("t/fixtures/ec_key_encrypted.pem"):read("*a")
local privkey, err = require("resty.openssl.pkey").new(f, {
format = "PEM",
type = "pr",
passphrase = "wrongpasswrod",
})
ngx.say(err)
-- pkey.new:load_key: error:4800065:PEM routines:PEM_do_header:bad decrypt:crypto/pem/pem_lib.c:467:
```

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

### err.get_last_error_code

**syntax**: *code = err.get_last_error_code()*

Return the last error code.

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

### err.get_lib_error_string

**syntax**: *lib_error_message = err.get_lib_error_string(code?)*

Return the library name of the last error code as string. If `code` is set, return the library name
corresponding to provided error code instead.

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

### err.get_reason_error_string

**syntax**: *reason_error_message = err.get_reason_error_string(code?)*

Return the reason of the last error code as string. If `code` is set, return the reason
corresponding to provided error code instead.

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

## resty.openssl.version

A module to provide version info.
Expand Down
79 changes: 69 additions & 10 deletions lib/resty/openssl/err.lua
Expand Up @@ -5,38 +5,94 @@ local ffi_sizeof = ffi.sizeof

local ctypes = require "resty.openssl.auxiliary.ctypes"
require "resty.openssl.include.err"
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X

local constchar_ptrptr = ffi.typeof("const char*[1]")

local buf = ffi.new('char[256]')
local last_err_code = 0

local function get_last_error_code()
local code = C.ERR_peek_last_error()
last_err_code = code == 0 and last_err_code or code

return last_err_code
end

local function get_lib_error_string(code)
code = code or get_last_error_code()

local msg = C.ERR_lib_error_string(code)
if msg == nil then
return "unknown library"
end

return ffi_str(msg)
end

local function get_reason_error_string(code)
code = code or get_last_error_code()

local msg = C.ERR_reason_error_string(code)
if msg == nil then
return ""
end

return ffi_str(msg)
end

local function format_error(ctx, code, all_errors)
local errors = {}
if code then
table.insert(errors, string.format("code: %d", code or 0))
end

local line = ctypes.ptr_of_int()
local path = constchar_ptrptr()
local func = constchar_ptrptr()

-- get the OpenSSL errors
while C.ERR_peek_error() ~= 0 do
local line = ctypes.ptr_of_int()
local path = constchar_ptrptr()
local code
if all_errors then
code = C.ERR_get_error_line(path, line)
if OPENSSL_3X then
code = C.ERR_get_error_all(path, line, func, nil, nil)
else
code = C.ERR_get_error_line(path, line)
end
else
code = C.ERR_peek_last_error_line(path, line)
if OPENSSL_3X then
code = C.ERR_peek_last_error_all(path, line, func, nil, nil)
else
code = C.ERR_peek_last_error_line(path, line)
end
end

last_err_code = code

local abs_path = ffi_str(path[0])
-- ../crypto/asn1/a_d2i_fp.c => crypto/asn1/a_d2i_fp.c
local start = abs_path:find("/")
if start then
abs_path = abs_path:sub(start+1)
end

C.ERR_error_string_n(code, buf, ffi_sizeof(buf))
table.insert(errors, string.format("%s:%d:%s",
abs_path, line[0], ffi_str(buf))
)
local err_line

if OPENSSL_3X then
local reason_msg = get_reason_error_string(code)
local lib_msg = get_lib_error_string(code)
-- error:04800065:PEM routines:PEM_do_header:bad decrypt:crypto/pem/pem_lib.c:467:
err_line = string.format("error:%X:%s:%s:%s:%s:%d:",
code, lib_msg, ffi_str(func[0]), reason_msg, abs_path, line[0])
else
local buf = ffi.new('char[256]')

C.ERR_error_string_n(code, buf, ffi_sizeof(buf))
err_line = string.format("%s:%d:%s",
abs_path, line[0], ffi_str(buf))
end

table.insert(errors, err_line)

if not all_errors then
break
Expand All @@ -59,4 +115,7 @@ end
return {
format_error = format_error,
format_all_error = format_all_error,
}
get_last_error_code = get_last_error_code,
get_lib_error_string = get_lib_error_string,
get_reason_error_string = get_reason_error_string,
}
25 changes: 23 additions & 2 deletions lib/resty/openssl/include/err.lua
@@ -1,9 +1,30 @@
local ffi = require "ffi"

require "resty.openssl.include.ossl_typ"
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X

ffi.cdef [[
unsigned long ERR_peek_error(void);
unsigned long ERR_peek_last_error_line(const char **file, int *line);
unsigned long ERR_get_error_line(const char **file, int *line);
unsigned long ERR_peek_last_error(void);
void ERR_clear_error(void);
void ERR_error_string_n(unsigned long e, char *buf, size_t len);
const char *ERR_lib_error_string(unsigned long e);
const char *ERR_reason_error_string(unsigned long e);
]]

if OPENSSL_3X then
ffi.cdef [[
unsigned long ERR_get_error_all(const char **file, int *line,
const char **func,
const char **data, int *flags);
unsigned long ERR_peek_last_error_all(const char **file, int *line,
const char **func,
const char **data, int *flags);
]]

else
ffi.cdef [[
unsigned long ERR_get_error_line(const char **file, int *line);
unsigned long ERR_peek_last_error_line(const char **file, int *line);
]]
end
8 changes: 4 additions & 4 deletions t/openssl/cipher.t
Expand Up @@ -122,7 +122,7 @@ cipher:update: cipher not initalized, call cipher:init first
GET /t
--- response_body_like eval
"nil
.+(?:data not multiple of block length|wrong final block length|DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH)
.+(?:data not multiple of block length|wrong final block length).*
VhGyRCcMvlAgUjTYrqiWpg=="
--- no_error_log
[error]
Expand Down Expand Up @@ -253,7 +253,7 @@ nothing
hiabcdefghiabcde
fghiabcdefghiabc
nothing
.+(wrong final block length|WRONG_FINAL_BLOCK_LENGTH)
.+wrong final block length.*
nil
final
defghi
Expand Down Expand Up @@ -409,8 +409,8 @@ default
--- request
GET /t
--- response_body_like
.+ivlen.+
.+padding.+
.+ivlen.*
.+padding.*
--- no_error_log
[error]
Expand Down
2 changes: 1 addition & 1 deletion t/openssl/kdf.t
Expand Up @@ -421,7 +421,7 @@ cDRFLQ7NWt+AP4i0TdBzog==
--- request
GET /t
--- response_body_like
.+missing salt
.+missing salt.*
cDRFLQ7NWt\+AP4i0TdBzog==
--- no_error_log
[error]
8 changes: 4 additions & 4 deletions t/openssl/pkcs12.t
Expand Up @@ -78,9 +78,9 @@ __DATA__
GET /t
--- response_body_like eval
'true
pkcs12.decode.+(mac verify failure|INCORRECT_PASSWORD)
pkcs12.decode.+mac verify failure.*
true
pkcs12.decode.+(mac verify failure|INCORRECT_PASSWORD)
pkcs12.decode.+mac verify failure.*
'
--- no_error_log
[error]
Expand Down Expand Up @@ -186,7 +186,7 @@ pkcs12.decode.+(mac verify failure|INCORRECT_PASSWORD)
2
myname
true
pkcs12.decode.+(mac verify failure|INCORRECT_PASSWORD)
pkcs12.decode.+mac verify failure.*
'
--- no_error_log
[error]
Expand Down Expand Up @@ -217,7 +217,7 @@ pkcs12.decode.+(mac verify failure|INCORRECT_PASSWORD)
--- request
GET /t
--- response_body_like eval
'true.+(key values mismatch|KEY_VALUES_MISMATCH)
'true.+key values mismatch.*
'
--- no_error_log
[error]
Expand Down
6 changes: 3 additions & 3 deletions t/openssl/pkey.t
Expand Up @@ -206,7 +206,7 @@ pkey.new:load_key: .+
--- request
GET /t
--- response_body_like eval
"pkey.new.+(?:bad decrypt|failed|BAD_DECRYPT)
"pkey.new.+(?:bad decrypt|failed).*
ok
"
--- no_error_log
Expand Down Expand Up @@ -240,7 +240,7 @@ ok
--- request
GET /t
--- response_body_like eval
"pkey.new.+(?:bad decrypt|failed|BAD_DECRYPT)
"pkey.new.+(?:bad decrypt|failed).*
ok
"
--- no_error_log
Expand Down Expand Up @@ -1033,7 +1033,7 @@ true
GET /t
--- response_body_like eval
"errored out with too many callbacks
pkey.new.+(?:bad decrypt|failed|BAD_DECRYPT|no start line|NO_START_LINE|DECODER routines::unsupported)
pkey.new.+(?:bad decrypt|failed|no start line|DECODER routines:OSSL_DECODER_from_bio:unsupported).*
ok
ok
"
Expand Down
4 changes: 2 additions & 2 deletions t/openssl/provider.t
Expand Up @@ -97,7 +97,7 @@ true
location =/t {
content_by_lua_block {
if not require("resty.openssl.version").OPENSSL_3X then
ngx.say("true\ncommon libcrypto routines::init fail")
ngx.say("true\ncommon libcrypto routines:provider_init:")
ngx.exit(0)
end
Expand All @@ -112,7 +112,7 @@ true
GET /t
--- response_body_like
true
.+(?:init fail|common libcrypto routines::reason\(\d+\))
.*(?:init fail|common libcrypto routines:provider_init).*
--- no_error_log
[error]
Expand Down
6 changes: 3 additions & 3 deletions t/openssl/x509.t
Expand Up @@ -107,7 +107,7 @@ __DATA__
GET /t
--- response_body_like eval
"expect nil or a string at #1
x509.new: .*(not enough data|NOT_ENOUGH_DATA)
x509.new: .*not enough data.*
"
--- no_error_log
[error]
Expand Down Expand Up @@ -480,8 +480,8 @@ nil
"true
nil
false
.+(key type mismatch|KEY_TYPE_MISMATCH)
.+(key values mismatch|KEY_VALUES_MISMATCH)
.+key type mismatch.*
.+key values mismatch.*
"
--- no_error_log
[error]
Expand Down
4 changes: 2 additions & 2 deletions t/openssl/x509/csr.t
Expand Up @@ -362,8 +362,8 @@ nil
"true
nil
false
.+(key type mismatch|KEY_TYPE_MISMATCH)
.+(key values mismatch|KEY_VALUES_MISMATCH)
.+key type mismatch.*
.+key values mismatch.*
"
--- no_error_log
[error]
Expand Down

0 comments on commit d155657

Please sign in to comment.