-- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, -- software distributed under the License is distributed on an -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -- KIND, either express or implied. See the License for the -- specific language governing permissions and limitations -- under the License. -- local common libs local require = require local pcall = pcall local ffi = require("ffi") local C = ffi.C local get_request = require("resty.core.base").get_request local core = require("apisix.core") local radixtree_sni = require("apisix.ssl.router.radixtree_sni") local apisix_ssl = require("apisix.ssl") local _, ssl = pcall(require, "resty.apisix.ssl") local error = error ffi.cdef[[ unsigned long Tongsuo_version_num(void) ]] -- local function local function set_pem_ssl_key(sni, enc_cert, enc_pkey, sign_cert, sign_pkey) local r = get_request() if r == nil then return false, "no request found" end local parsed_enc_cert, err = apisix_ssl.fetch_cert(sni, enc_cert) if not parsed_enc_cert then return false, "failed to parse enc PEM cert: " .. err end local parsed_sign_cert, err = apisix_ssl.fetch_cert(sni, sign_cert) if not parsed_sign_cert then return false, "failed to parse sign PEM cert: " .. err end local ok, err = ssl.set_gm_cert(parsed_enc_cert, parsed_sign_cert) if not ok then return false, "failed to set PEM cert: " .. err end local parsed_enc_pkey, err = apisix_ssl.fetch_pkey(sni, enc_pkey) if not parsed_enc_pkey then return false, "failed to parse enc PEM priv key: " .. err end local parsed_sign_pkey, err = apisix_ssl.fetch_pkey(sni, sign_pkey) if not parsed_sign_pkey then return false, "failed to parse sign PEM priv key: " .. err end ok, err = ssl.set_gm_priv_key(parsed_enc_pkey, parsed_sign_pkey) if not ok then return false, "failed to set PEM priv key: " .. err end return true end local original_set_cert_and_key local function set_cert_and_key(sni, value) if value.gm then -- process as GM certificate -- For GM dual certificate, the `cert` and `key` will be encryption cert/key. -- The first item in `certs` and `keys` will be sign cert/key. local enc_cert = value.cert local enc_pkey = value.key local sign_cert = value.certs[1] local sign_pkey = value.keys[1] return set_pem_ssl_key(sni, enc_cert, enc_pkey, sign_cert, sign_pkey) end return original_set_cert_and_key(sni, value) end local original_check_ssl_conf local function check_ssl_conf(in_dp, conf) if conf.gm then -- process as GM certificate -- For GM dual certificate, the `cert` and `key` will be encryption cert/key. -- The first item in `certs` and `keys` will be sign cert/key. local ok, err = original_check_ssl_conf(in_dp, conf) -- check cert/key first in the original method if not ok then return nil, err end -- Currently, APISIX doesn't check the cert type (ECDSA / RSA). So we skip the -- check for now in this plugin. local num_certs = conf.certs and #conf.certs or 0 local num_keys = conf.keys and #conf.keys or 0 if num_certs ~= 1 or num_keys ~= 1 then return nil, "sign cert/key are required" end return true end return original_check_ssl_conf(in_dp, conf) end -- module define local plugin_name = "gm" -- plugin schema local plugin_schema = { type = "object", properties = { }, } local _M = { version = 0.1, -- plugin version priority = -43, name = plugin_name, -- plugin name schema = plugin_schema, -- plugin schema } function _M.init() if not pcall(function () return C.Tongsuo_version_num end) then error("need to build Tongsuo (https://github.com/Tongsuo-Project/Tongsuo) " .. "into the APISIX-Runtime") end ssl.enable_ntls() original_set_cert_and_key = radixtree_sni.set_cert_and_key radixtree_sni.set_cert_and_key = set_cert_and_key original_check_ssl_conf = apisix_ssl.check_ssl_conf apisix_ssl.check_ssl_conf = check_ssl_conf if core.schema.ssl.properties.gm ~= nil then error("Field 'gm' is occupied") end -- inject a mark to distinguish GM certificate core.schema.ssl.properties.gm = { type = "boolean" } end function _M.destroy() ssl.disable_ntls() radixtree_sni.set_cert_and_key = original_set_cert_and_key apisix_ssl.check_ssl_conf = original_check_ssl_conf core.schema.ssl.properties.gm = nil end -- module interface for schema check -- @param `conf` user defined conf data -- @param `schema_type` defined in `apisix/core/schema.lua` -- @return function _M.check_schema(conf, schema_type) return core.schema.check(plugin_schema, conf) end return _M