diff options
Diffstat (limited to 'server/resty/openssl/ssl_ctx.lua')
-rw-r--r-- | server/resty/openssl/ssl_ctx.lua | 95 |
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 |