summaryrefslogtreecommitdiffstats
path: root/server/resty/openssl/provider.lua
blob: 2879ac34abcf308285c88b5aab1c1532c7b5962d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
local ffi = require "ffi"
local C = ffi.C

require "resty.openssl.include.provider"
local param_lib = require "resty.openssl.param"
local ctx_lib = require "resty.openssl.ctx"
local null = require("resty.openssl.auxiliary.ctypes").null
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
local format_error = require("resty.openssl.err").format_error

if not OPENSSL_3X then
  error("provider is only supported since OpenSSL 3.0")
end

local _M = {}
local mt = {__index = _M}

local ossl_provider_ctx_ct = ffi.typeof('OSSL_PROVIDER*')

function _M.load(name, try)
  local ctx
  local libctx = ctx_lib.get_libctx()
  if try then
    ctx = C.OSSL_PROVIDER_try_load(libctx, name)
    if ctx == nil then
      return nil, format_error("provider.try_load")
    end
  else
    ctx = C.OSSL_PROVIDER_load(libctx, name)
    if ctx == nil then
      return nil, format_error("provider.load")
    end
  end

  return setmetatable({
    ctx = ctx,
    param_types = nil,
  }, mt), nil
end

function _M.set_default_search_path(path)
  C.OSSL_PROVIDER_set_default_search_path(ctx_lib.get_libctx(), path)
end

function _M.is_available(name)
  return C.OSSL_PROVIDER_available(ctx_lib.get_libctx(), name) == 1
end

function _M.istype(l)
  return l and l.ctx and ffi.istype(ossl_provider_ctx_ct, l.ctx)
end

function _M:unload()
  if C.OSSL_PROVIDER_unload(self.ctx) == nil then
    return false, format_error("provider:unload")
  end
  return true
end

function _M:self_test()
  if C.OSSL_PROVIDER_self_test(self.ctx) == nil then
    return false, format_error("provider:self_test")
  end
  return true
end

local params_well_known = {
  -- Well known parameter names that core passes to providers
  ["openssl-version"] = param_lib.OSSL_PARAM_UTF8_PTR,
  ["provider-name"]   = param_lib.OSSL_PARAM_UTF8_PTR,
  ["module-filename"] = param_lib.OSSL_PARAM_UTF8_PTR,

  -- Well known parameter names that Providers can define
  ["name"]                = param_lib.OSSL_PARAM_UTF8_PTR,
  ["version"]             = param_lib.OSSL_PARAM_UTF8_PTR,
  ["buildinfo"]           = param_lib.OSSL_PARAM_UTF8_PTR,
  ["status"]              = param_lib.OSSL_PARAM_INTEGER,
  ["security-checks"]     = param_lib.OSSL_PARAM_INTEGER,
}

local function load_gettable_names(ctx)
  local schema = {}
  for k, v in pairs(params_well_known) do
    schema[k] = v
  end

  local err
  schema, err = param_lib.parse_params_schema(
    C.OSSL_PROVIDER_gettable_params(ctx), schema)
  if err then
    return nil, err
  end

  return schema
end

function _M:get_params(...)
  local keys = {...}
  local key_length = #keys
  if key_length == 0 then
    return nil, "provider:get_params: at least one key is required"
  end

  if not self.param_types then
    local param_types, err = load_gettable_names(self.ctx)
    if err then
      return nil, "provider:get_params: " .. err
    end
    self.param_types = param_types
  end

  local buffers = {}
  for _, key in ipairs(keys) do
    buffers[key] = null
  end
  local req, err = param_lib.construct(buffers, key_length, self.param_types)
  if not req then
    return nil, "provider:get_params: failed to construct params: " .. err
  end

  if C.OSSL_PROVIDER_get_params(self.ctx, req) ~= 1 then
    return nil, format_error("provider:get_params")
  end

  buffers, err = param_lib.parse(buffers, key_length, self.param_types)
  if err then
    return nil, "provider:get_params: failed to parse params: " .. err
  end

  if key_length == 1 then
    return buffers[keys[1]]
  end
  return buffers
end

return _M