aboutsummaryrefslogtreecommitdiffstats
path: root/server/resty/openssl/ssl_ctx.lua
diff options
context:
space:
mode:
Diffstat (limited to 'server/resty/openssl/ssl_ctx.lua')
-rw-r--r--server/resty/openssl/ssl_ctx.lua95
1 files changed, 95 insertions, 0 deletions
diff --git a/server/resty/openssl/ssl_ctx.lua b/server/resty/openssl/ssl_ctx.lua
new file mode 100644
index 0000000..dd110f9
--- /dev/null
+++ b/server/resty/openssl/ssl_ctx.lua
@@ -0,0 +1,95 @@
+local ffi = require "ffi"
+local C = ffi.C
+local new_tab = table.new
+local char = string.char
+local concat = table.concat
+
+require "resty.openssl.include.ssl"
+
+local nginx_aux = require("resty.openssl.auxiliary.nginx")
+
+local _M = {}
+local mt = {__index = _M}
+
+local ssl_ctx_ptr_ct = ffi.typeof('SSL_CTX*')
+
+function _M.from_request()
+ -- don't GC this
+ local ctx, err = nginx_aux.get_req_ssl_ctx()
+ if err ~= nil then
+ return nil, err
+ end
+
+ return setmetatable({
+ ctx = ctx,
+ -- the cdata is not manage by Lua, don't GC on Lua side
+ _managed = false,
+ -- this is the Server SSL session
+ _server = true,
+ }, mt)
+end
+
+function _M.from_socket(socket)
+ if not socket then
+ return nil, "expect a ngx.socket.tcp instance at #1"
+ end
+ -- don't GC this
+ local ctx, err = nginx_aux.get_socket_ssl_ctx(socket)
+ if err ~= nil then
+ return nil, err
+ end
+
+ return setmetatable({
+ ctx = ctx,
+ -- the cdata is not manage by Lua, don't GC on Lua side
+ _managed = false,
+ -- this is the client SSL session
+ _server = false,
+ }, mt)
+end
+
+function _M.istype(l)
+ return l and l.ctx and ffi.istype(ssl_ctx_ptr_ct, l.ctx)
+end
+
+local function encode_alpn_wire(alpns)
+ local ret = new_tab(#alpns*2, 0)
+ for i, alpn in ipairs(alpns) do
+ ret[i*2-1] = char(#alpn)
+ ret[i*2] = alpn
+ end
+
+ return concat(ret, "")
+end
+
+function _M:set_alpns(alpns)
+ if not self._server then
+ return nil, "ssl_ctx:set_alpns is only supported on server side"
+ end
+
+ alpns = encode_alpn_wire(alpns)
+
+ if self._alpn_select_cb then
+ self._alpn_select_cb:free()
+ end
+
+ local alpn_select_cb = ffi.cast("SSL_CTX_alpn_select_cb_func", function(_, out, outlen, client, client_len)
+ local code = ffi.C.SSL_select_next_proto(
+ ffi.cast("unsigned char **", out), outlen,
+ alpns, #alpns,
+ client, client_len)
+ if code ~= 1 then -- OPENSSL_NPN_NEGOTIATED
+ return 3 -- SSL_TLSEXT_ERR_NOACK
+ end
+ return 0 -- SSL_TLSEXT_ERR_OK
+ end)
+
+ C.SSL_CTX_set_alpn_select_cb(self.ctx, alpn_select_cb, nil)
+ -- store the reference to avoid it being GC'ed
+ self._alpn_select_cb = alpn_select_cb
+
+ return true
+end
+
+
+return _M \ No newline at end of file