diff --git a/README.md b/README.md index d4bf4761..0ab6afef 100644 --- a/README.md +++ b/README.md @@ -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) @@ -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. diff --git a/lib/resty/openssl/err.lua b/lib/resty/openssl/err.lua index a047a7c0..61dad9b6 100644 --- a/lib/resty/openssl/err.lua +++ b/lib/resty/openssl/err.lua @@ -5,27 +5,70 @@ 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("/") @@ -33,10 +76,23 @@ local function format_error(ctx, code, all_errors) 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 @@ -59,4 +115,7 @@ end return { format_error = format_error, format_all_error = format_all_error, -} \ No newline at end of file + get_last_error_code = get_last_error_code, + get_lib_error_string = get_lib_error_string, + get_reason_error_string = get_reason_error_string, +} diff --git a/lib/resty/openssl/include/err.lua b/lib/resty/openssl/include/err.lua index 142098c5..59232960 100644 --- a/lib/resty/openssl/include/err.lua +++ b/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 \ No newline at end of file diff --git a/t/openssl/cipher.t b/t/openssl/cipher.t index da46e592..886d4d8b 100644 --- a/t/openssl/cipher.t +++ b/t/openssl/cipher.t @@ -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] @@ -253,7 +253,7 @@ nothing hiabcdefghiabcde fghiabcdefghiabc nothing -.+(wrong final block length|WRONG_FINAL_BLOCK_LENGTH) +.+wrong final block length.* nil final defghi @@ -409,8 +409,8 @@ default --- request GET /t --- response_body_like -.+ivlen.+ -.+padding.+ +.+ivlen.* +.+padding.* --- no_error_log [error] diff --git a/t/openssl/kdf.t b/t/openssl/kdf.t index 51676834..52c610dc 100644 --- a/t/openssl/kdf.t +++ b/t/openssl/kdf.t @@ -421,7 +421,7 @@ cDRFLQ7NWt+AP4i0TdBzog== --- request GET /t --- response_body_like -.+missing salt +.+missing salt.* cDRFLQ7NWt\+AP4i0TdBzog== --- no_error_log [error] diff --git a/t/openssl/pkcs12.t b/t/openssl/pkcs12.t index 4acedef5..dca3b397 100644 --- a/t/openssl/pkcs12.t +++ b/t/openssl/pkcs12.t @@ -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] @@ -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] @@ -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] diff --git a/t/openssl/pkey.t b/t/openssl/pkey.t index 5c425b8d..26aa36d7 100644 --- a/t/openssl/pkey.t +++ b/t/openssl/pkey.t @@ -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 @@ -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 @@ -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 " diff --git a/t/openssl/provider.t b/t/openssl/provider.t index 8a86d96c..b2f34c63 100644 --- a/t/openssl/provider.t +++ b/t/openssl/provider.t @@ -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 @@ -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] diff --git a/t/openssl/x509.t b/t/openssl/x509.t index 3ef58771..69019215 100644 --- a/t/openssl/x509.t +++ b/t/openssl/x509.t @@ -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] @@ -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] diff --git a/t/openssl/x509/csr.t b/t/openssl/x509/csr.t index 42d8239e..c56828c6 100644 --- a/t/openssl/x509/csr.t +++ b/t/openssl/x509/csr.t @@ -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]