-
Notifications
You must be signed in to change notification settings - Fork 170
/
Copy pathtls.lua
171 lines (131 loc) · 4.26 KB
/
tls.lua
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
-- This is a tls description.
local policy = require('apicast.policy')
local _M = policy.new('tls', "builtin")
local tab_new = require('table.new')
local ssl = require('ngx.ssl')
local cjson = require('cjson')
local data_url = require('resty.data_url')
local util = require('apicast.util')
local insert = table.insert
local pack = table.pack
local ipairs = ipairs
local setmetatable = setmetatable
local null = ngx.null
local empty = {}
local new = _M.new
--- Create a Struct like Class, that extract required properties from a table or returns and error.
local function Config(...)
local properties = pack(...)
local m = { }
local mt = { __index = m }
function m.new(config)
if not config and properties then return nil, 'missing table' end
local self = { }
for _,property in ipairs(properties) do
if config[property] ~= null then
self[property] = config[property]
end
if self[property] == nil then
return nil, 'missing property'
end
end
return setmetatable(self, mt)
end
return m
end
local EmbeddedCertificates = Config('certificate', 'certificate_key')
local LocalFilesystemCertificates = Config('certificate_path', 'certificate_key_path')
local function parse_certificates(self, certificate, private_key)
local err
self.certificate, err = ssl.parse_pem_cert(certificate)
if err then return nil, err end
self.certificate_key, err = ssl.parse_pem_priv_key(private_key)
if err then return nil, err end
return true
end
local function parse_data_url(url)
local uri, err = data_url.parse(url)
if err then return nil, err end
return uri.data
end
function EmbeddedCertificates:parse()
local certificate, certificate_key, err
certificate, err = parse_data_url(self.certificate)
if err then return nil, err end
certificate_key, err = parse_data_url(self.certificate_key)
if err then return nil, err end
return parse_certificates(self, certificate, certificate_key)
end
function LocalFilesystemCertificates:parse()
local certificate, certificate_key, err
certificate, err = util.read_file(self.certificate_path)
if err then return nil, err end
certificate_key, err = util.read_file(self.certificate_key_path)
if err then return nil, err end
return parse_certificates(self, certificate, certificate_key)
end
local Configurations = { EmbeddedCertificates, LocalFilesystemCertificates }
local function parse_config(table)
for _, class in ipairs(Configurations) do
local config, _ = class.new(table)
if config and config:parse() then
return config
end
end
return nil, 'configuration does not match any supported type'
end
local function parse_config_certificates(configs)
local certificates = tab_new(#configs, 0)
for _, config in ipairs(configs)do
local cert, err = parse_config(config)
if err then
ngx.log(ngx.WARN, 'could not parse certificate ', cjson.encode(config))
else
insert(certificates, cert)
end
end
return certificates
end
--- Initialize a TLS policy
-- @tparam[opt] table config Policy configuration.
function _M.new(config)
local self = new(config)
self.certificates = parse_config_certificates(config and config.certificates or empty)
if #self.certificates == 0 then
ngx.log(ngx.WARN, "No valid certificates loaded")
end
return self
end
-- Set the given certificate to be the default one for the request.
-- @tparam cert: certificate table with certificates in der format
local function set_certificate(cert)
local ok, err = ssl.set_cert(cert.certificate)
if not ok then
ngx.log(ngx.ERR, "failed to set certificate: ", err)
return false
end
ok, err = ssl.set_priv_key(cert.certificate_key)
if not ok then
ngx.log(ngx.ERR, "failed to set DER private key: ", err)
return false
end
return true
end
function _M:ssl_certificate()
if #self.certificates == 0 then
-- No valid certificates in place, continue.
return
end
local ok, err = ssl.clear_certs()
if not ok then
ngx.log(ngx.ERR, "failed to clear existing (fallback) certificates, err: ", err)
return ngx.exit(ngx.ERROR)
end
for _, cert in ipairs(self.certificates) do
if set_certificate(cert) then
-- Certificate is set correctly, use this one and end the loop.
break
end
end
end
return _M