diff options
Diffstat (limited to 'server/resty/openssl/digest.lua')
-rw-r--r-- | server/resty/openssl/digest.lua | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/server/resty/openssl/digest.lua b/server/resty/openssl/digest.lua new file mode 100644 index 0000000..cfef9ae --- /dev/null +++ b/server/resty/openssl/digest.lua @@ -0,0 +1,116 @@ +local ffi = require "ffi" +local C = ffi.C +local ffi_gc = ffi.gc +local ffi_str = ffi.string + +require "resty.openssl.include.evp.md" +local ctypes = require "resty.openssl.auxiliary.ctypes" +local ctx_lib = require "resty.openssl.ctx" +local format_error = require("resty.openssl.err").format_error +local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10 +local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER +local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X + +local _M = {} +local mt = {__index = _M} + +local md_ctx_ptr_ct = ffi.typeof('EVP_MD_CTX*') + +function _M.new(typ, properties) + local ctx + if OPENSSL_11_OR_LATER then + ctx = C.EVP_MD_CTX_new() + ffi_gc(ctx, C.EVP_MD_CTX_free) + elseif OPENSSL_10 then + ctx = C.EVP_MD_CTX_create() + ffi_gc(ctx, C.EVP_MD_CTX_destroy) + end + if ctx == nil then + return nil, "digest.new: failed to create EVP_MD_CTX" + end + + local err_new = string.format("digest.new: invalid digest type \"%s\"", typ) + + local algo + if typ == "null" then + algo = C.EVP_md_null() + else + if OPENSSL_3X then + algo = C.EVP_MD_fetch(ctx_lib.get_libctx(), typ or 'sha1', properties) + else + algo = C.EVP_get_digestbyname(typ or 'sha1') + end + if algo == nil then + return nil, format_error(err_new) + end + end + + local code = C.EVP_DigestInit_ex(ctx, algo, nil) + if code ~= 1 then + return nil, format_error(err_new) + end + + return setmetatable({ + ctx = ctx, + algo = algo, + buf = ctypes.uchar_array(OPENSSL_3X and C.EVP_MD_get_size(algo) or C.EVP_MD_size(algo)), + }, mt), nil +end + +function _M.istype(l) + return l and l.ctx and ffi.istype(md_ctx_ptr_ct, l.ctx) +end + +function _M:get_provider_name() + if not OPENSSL_3X then + return false, "digest:get_provider_name is not supported" + end + local p = C.EVP_MD_get0_provider(self.algo) + if p == nil then + return nil + end + return ffi_str(C.OSSL_PROVIDER_get0_name(p)) +end + +if OPENSSL_3X then + local param_lib = require "resty.openssl.param" + _M.settable_params, _M.set_params, _M.gettable_params, _M.get_param = param_lib.get_params_func("EVP_MD_CTX") +end + +function _M:update(...) + for _, s in ipairs({...}) do + if C.EVP_DigestUpdate(self.ctx, s, #s) ~= 1 then + return false, format_error("digest:update") + end + end + return true, nil +end + +local result_length = ctypes.ptr_of_uint() + +function _M:final(s) + if s then + if C.EVP_DigestUpdate(self.ctx, s, #s) ~= 1 then + return false, format_error("digest:final") + end + end + + -- no return value of EVP_DigestFinal_ex + C.EVP_DigestFinal_ex(self.ctx, self.buf, result_length) + if result_length[0] == nil or result_length[0] <= 0 then + return nil, format_error("digest:final: EVP_DigestFinal_ex") + end + return ffi_str(self.buf, result_length[0]) +end + + +function _M:reset() + local code = C.EVP_DigestInit_ex(self.ctx, self.algo, nil) + if code ~= 1 then + return false, format_error("digest:reset") + end + + return true +end + +return _M |