|
1 | 1 | local ffi = require "ffi"
|
2 | 2 | local C = ffi.C
|
| 3 | +local ffi_gc = ffi.gc |
3 | 4 | local ffi_cast = ffi.cast
|
| 5 | +local ffi_str = ffi.string |
4 | 6 |
|
| 7 | +require "resty.openssl.include.x509" |
5 | 8 | require "resty.openssl.include.x509v3"
|
6 |
| -require "resty.openssl.include.asn1" |
| 9 | +local asn1_macro = require "resty.openssl.include.asn1" |
7 | 10 | local stack_lib = require "resty.openssl.stack"
|
8 | 11 | local altname_macro = require "resty.openssl.include.x509.altname"
|
9 | 12 |
|
10 | 13 | local _M = {}
|
11 |
| -local mt = { __index = _M } |
| 14 | +local mt |
12 | 15 |
|
13 | 16 | local general_names_ptr_ct = ffi.typeof("GENERAL_NAMES*")
|
14 | 17 |
|
15 | 18 | local STACK = "GENERAL_NAME"
|
16 | 19 | local new = stack_lib.new_of(STACK)
|
17 | 20 | local add = stack_lib.add_of(STACK)
|
| 21 | +local dup = stack_lib.dup_of(STACK) |
18 | 22 |
|
19 | 23 | local types = altname_macro.types
|
20 | 24 |
|
| 25 | +local gn_decode = function(ctx) |
| 26 | + local typ = ctx.type |
| 27 | + local k = altname_macro.literals[typ] |
| 28 | + local v |
| 29 | + if typ == types.DNS then |
| 30 | + v = ffi_str(asn1_macro.ASN1_STRING_get0_data(ctx.d.dNSName)) |
| 31 | + elseif typ == types.URI then |
| 32 | + v = ffi_str(asn1_macro.ASN1_STRING_get0_data(ctx.d.uniformResourceIdentifier)) |
| 33 | + elseif typ == types.RFC822Name then |
| 34 | + v = ffi_str(asn1_macro.ASN1_STRING_get0_data(ctx.d.rfc822Name)) |
| 35 | + elseif typ == types.IP then |
| 36 | + error("NYI") |
| 37 | + elseif typ == types.DirName then |
| 38 | + error("NYI") |
| 39 | + else |
| 40 | + error("unknown type" .. typ) |
| 41 | + end |
| 42 | + return { k, v } |
| 43 | +end |
| 44 | + |
| 45 | +-- shared with info_access |
| 46 | +_M.gn_decode = gn_decode |
| 47 | + |
| 48 | +mt = stack_lib.mt_of(STACK, gn_decode, _M) |
| 49 | +local mt__pairs = mt.__pairs |
| 50 | +mt.__pairs = function(tbl) |
| 51 | + local f = mt__pairs(tbl) |
| 52 | + return function() |
| 53 | + local _, e = f() |
| 54 | + if not e then return end |
| 55 | + return unpack(e) |
| 56 | + end |
| 57 | +end |
| 58 | + |
21 | 59 | function _M.new()
|
22 |
| - local raw = new() |
23 |
| - if raw == nil then |
| 60 | + local ctx = new() |
| 61 | + if ctx == nil then |
24 | 62 | return nil, "OPENSSL_sk_new_null() failed"
|
25 | 63 | end
|
26 |
| - local ctx = ffi_cast("GENERAL_NAMES*", raw) |
| 64 | + local cast = ffi_cast("GENERAL_NAMES*", ctx) |
27 | 65 |
|
28 | 66 | local self = setmetatable({
|
29 | 67 | ctx = ctx,
|
30 |
| - raw = raw |
| 68 | + cast = cast, |
| 69 | + _is_dup = false, |
31 | 70 | }, mt)
|
32 | 71 |
|
33 | 72 | return self, nil
|
34 | 73 | end
|
35 | 74 |
|
36 | 75 | function _M.istype(l)
|
37 |
| - return l and l.ctx and ffi.istype(general_names_ptr_ct, l.ctx) |
| 76 | + return l and l.cast and ffi.istype(general_names_ptr_ct, l.cast) |
38 | 77 | end
|
39 | 78 |
|
40 |
| -function _M:add(typ, value) |
| 79 | +function _M.dup(ctx) |
| 80 | + if ctx == nil or not ffi.istype(general_names_ptr_ct, ctx) then |
| 81 | + return nil, "expect a GENERAL_NAMES* ctx at #1" |
| 82 | + end |
| 83 | + ctx = dup(ctx) |
| 84 | + |
| 85 | + return setmetatable({ |
| 86 | + cast = ffi_cast("GENERAL_NAMES*", ctx), |
| 87 | + ctx = ctx, |
| 88 | + _is_dup = true, |
| 89 | + _elem_refs = {}, |
| 90 | + _elem_refs_idx = 1, |
| 91 | + }, mt), nil |
| 92 | +end |
| 93 | + |
| 94 | +local function gn_set(gn, typ, value) |
41 | 95 | if not typ then
|
42 |
| - return nil, "expect a string at #1" |
| 96 | + return "expect a string at #1" |
43 | 97 | end
|
44 | 98 | typ = typ:lower()
|
45 | 99 | if type(value) ~= 'string' then
|
46 |
| - return nil, "except a string at #2" |
| 100 | + return "except a string at #2" |
47 | 101 | end
|
48 | 102 |
|
49 | 103 | local txt = value
|
50 |
| - local gen_type = types[typ] |
51 |
| - if not gen_type then |
52 |
| - return nil, "unknown type " .. typ |
| 104 | + local gn_type = types[typ] |
| 105 | + if not gn_type then |
| 106 | + return "unknown type " .. typ |
| 107 | + end |
| 108 | + |
| 109 | + gn.type = gn_type |
| 110 | + |
| 111 | + local asn1_string = C.ASN1_IA5STRING_new() |
| 112 | + if asn1_string == nil then |
| 113 | + C.GENERAL_NAME_free(gn) |
| 114 | + return "ASN1_STRING_type_new() failed" |
| 115 | + end |
| 116 | + |
| 117 | + gn.d.ia5 = asn1_string |
| 118 | + |
| 119 | + local code = C.ASN1_STRING_set(gn.d.ia5, txt, #txt) |
| 120 | + if code ~= 1 then |
| 121 | + C.GENERAL_NAME_free(gn) |
| 122 | + return "ASN1_STRING_set() failed: " .. code |
53 | 123 | end
|
| 124 | +end |
| 125 | + |
| 126 | +-- shared with info_access |
| 127 | +_M.gn_set = gn_set |
| 128 | + |
| 129 | +function _M:add(typ, value) |
54 | 130 |
|
55 | 131 | -- the stack element stays with stack
|
56 | 132 | -- we shouldn't add gc handler if it's already been
|
57 | 133 | -- pushed to stack. instead, rely on the gc handler
|
58 | 134 | -- of the stack to release all memories
|
59 |
| - local gen = C.GENERAL_NAME_new() |
60 |
| - if gen == nil then |
| 135 | + local gn = C.GENERAL_NAME_new() |
| 136 | + if gn == nil then |
61 | 137 | return nil, "GENERAL_NAME_new() failed"
|
62 | 138 | end
|
63 | 139 |
|
64 |
| - gen.type = gen_type |
65 |
| - |
66 |
| - -- #define V_ASN1_IA5STRING 22 |
67 |
| - local asn1_string = C.ASN1_STRING_type_new(22) |
68 |
| - if asn1_string == nil then |
69 |
| - C.GENERAL_NAME_free(gen) |
70 |
| - return nil, "ASN1_STRING_type_new() failed" |
71 |
| - end |
72 |
| - |
73 |
| - gen.d.ia5 = asn1_string |
74 |
| - |
75 |
| - local code = C.ASN1_STRING_set(gen.d.ia5, txt, #txt) |
76 |
| - if code ~= 1 then |
77 |
| - C.GENERAL_NAME_free(gen) |
78 |
| - return nil, "ASN1_STRING_set() failed: " .. code |
| 140 | + local err = gn_set(gn, typ, value) |
| 141 | + if err then |
| 142 | + return err |
79 | 143 | end
|
80 | 144 |
|
81 |
| - local _, err = add(self.ctx, gen) |
| 145 | + local _, err = add(self.ctx, gn) |
82 | 146 | if err then
|
83 |
| - C.GENERAL_NAME_free(gen) |
| 147 | + C.GENERAL_NAME_free(gn) |
84 | 148 | return nil, err
|
85 | 149 | end
|
| 150 | + |
| 151 | + -- if the stack is duplicated, the gc handler is not pop_free |
| 152 | + -- handle the gc by ourselves |
| 153 | + if self._is_dup then |
| 154 | + ffi_gc(gn, C.GENERAL_NAME_free) |
| 155 | + self._elem_refs[self._elem_refs_idx] = gn |
| 156 | + self._elem_refs_idx = self._elem_refs_idx + 1 |
| 157 | + end |
86 | 158 | return self
|
87 | 159 | end
|
88 | 160 |
|
| 161 | +_M.all = function(stack) |
| 162 | + local ret = {} |
| 163 | + local _next = mt.__ipairs(stack) |
| 164 | + while true do |
| 165 | + local i, e = _next() |
| 166 | + if i then |
| 167 | + ret[i] = e |
| 168 | + else |
| 169 | + break |
| 170 | + end |
| 171 | + end |
| 172 | + return ret |
| 173 | +end |
| 174 | + |
89 | 175 | return _M
|
0 commit comments