-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
--
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

-- 外部依赖
local log = require 'mc.logging'
local mdb_service = require 'mc.mdb.mdb_service'
local cjson = require 'cjson'

-- SSL证书路径
local SSL_PATH<const> = '/bmc/kepler/Managers/1/NetworkProtocol/HTTPS/Certificates/1'
-- CA证书路径
local CA_PATH<const> = '/bmc/kepler/Managers/1/Certificates/%d'

local m = {}

function m.get_ssl_cert_info(destination, subject_destination)
    local ok, rsp = pcall(mdb_service.is_valid_path, bus, SSL_PATH)
    if not ok or not rsp.Result then
        return {}
    end
    local client_cert_info = destination
    client_cert_info.AlternativeNames = subject_destination.AlternativeNames
    return { ClientCert = client_cert_info }
end

function m.is_valid_cert(id)
    local id_number = tonumber(id)
    if not id_number then
        log:error('the id(%s) of cert is invalid', id)
        return false
    end
    if id_number < 1 or id_number > 32 then
        log:error('the id(%u) of cert is invalid', id_number)
        return false
    end
    local path = string.format(CA_PATH, id_number)
    local ok, rsp = pcall(mdb_service.is_valid_path, bus, path)
    if not ok or not rsp.Result then
        log:error('the id(%u) of cert is invalid', id_number)
        return false
    end
    return true
end

local function drop_cert_table_keys(cert_info)
    if not cert_info then
        return nil
    end
    return {
        Issuer = cert_info.Issuer,
        Subject = cert_info.Subject,
        ValidNotBefore = cert_info.ValidNotBefore,
        ValidNotAfter = cert_info.ValidNotAfter,
        SerialNumber = cert_info.SerialNumber
    }
end

function m.get_cert_chain_info(cert_info, subject_destination)
    local cert_infos = cjson.decode(cert_info)
    local server_info = drop_cert_table_keys(cert_infos['ServerCert'])
    local root_info = drop_cert_table_keys(cert_infos['RootCert'])
    local intermediate_info = {}
    if cert_infos['IntermediateCert'] then
        for idx, c_info in ipairs(cert_infos['IntermediateCert']) do
            intermediate_info[idx] = drop_cert_table_keys(c_info)
        end
    end
    local server_cert_info = server_info
    server_cert_info.AlternativeNames = subject_destination.AlternativeNames
    return {ServerCert = server_cert_info, IntermediateCert = intermediate_info, RootCert = root_info}
end

local function gm_tls_supported(tls_capabilities)
    for _, st in pairs(tls_capabilities) do
        if st.TlsName == 'GMTLS' and st.IsSupported then
            return true
        end
    end
    return false
end

function m.get_gm_cert_chain_info(sig_cert_info, enc_cert_info, sig_subject, enc_subject, tls_caps)
    local sig_cert_infos = cjson.decode(sig_cert_info)
    local enc_cert_infos = cjson.decode(enc_cert_info)
    local sig_server_info = drop_cert_table_keys(sig_cert_infos['ServerCert'])
    local sig_root_info = drop_cert_table_keys(sig_cert_infos['RootCert'])
    local enc_server_info = drop_cert_table_keys(enc_cert_infos['ServerCert'])
    local enc_root_info = drop_cert_table_keys(enc_cert_infos['RootCert'])
    local sig_intermediate_info = {}
    local enc_intermediate_info = {}
    if sig_cert_infos['IntermediateCert'] then
        for idx, c_info in ipairs(sig_cert_infos['IntermediateCert']) do
            sig_intermediate_info[idx] = drop_cert_table_keys(c_info)
        end
    end
    if enc_cert_infos['IntermediateCert'] then
        for idx, c_info in ipairs(enc_cert_infos['IntermediateCert']) do
            enc_intermediate_info[idx] = drop_cert_table_keys(c_info)
        end
    end

    sig_server_info.AlternativeNames = sig_subject.AlternativeNames
    enc_server_info.AlternativeNames = enc_subject.AlternativeNames
    return {SignatureServerCert = sig_server_info,
            SignatureIntermediateCert = sig_intermediate_info,
            SignatureRootCert = sig_root_info,
            EnciphermentServerCert = enc_server_info,
            EnciphermentIntermediateCert = enc_intermediate_info,
            EnciphermentRootCert = enc_root_info,
            GmTlsSupported = gm_tls_supported(tls_caps.TlsCapabilities)}
end

return m
