• mindxdlcommonweb_cert_utils.go


    // Copyright (c) 2021. Huawei Technologies Co., Ltd. All rights reserved.

    // Package common this file define WebCertUtil
    package common

    import (
    "crypto/tls"
    "crypto/x509"
    "encoding/pem"
    "errors"
    "fmt"
    "github.com/gin-gonic/gin"
    "huawei.com/npu-exporter/hwlog"
    "huawei.com/npu-exporter/limiter"
    "huawei.com/npu-exporter/utils"
    "io/ioutil"
    "net/http"
    "strconv"
    "strings"
    "time"
    )

    const keyLength = 4096

    var webCert *WebCertUtil

    // WebCertUtil WebCertUtil
    type WebCertUtil struct {
    *CertificateUtils
    }

    // NewWebCertUtil NewWebCertUtil
    func NewWebCertUtil(dnsName, dirName string, overdueTime int) *WebCertUtil {
    ws := &WebCertUtil{
    CertificateUtils: NewCertificateUtils(dnsName, dirName, overdueTime),
    }
    if err := utils.MakeSureDir(ws.KeyStore); err != nil {
    hwlog.RunLog.Fatal(err)
    }

    return ws
    }

    // GetWebCertUtil return webCert
    func GetWebCertUtil() *WebCertUtil {
    return webCert
    }

    // CheckCertValidityPeriod CheckCertValidityPeriod
    func (ws *WebCertUtil) CheckCertValidityPeriod(interval time.Duration) {
    hwlog.RunLog.Info("start cert period check...")
    ticker := time.NewTicker(interval)
    defer ticker.Stop()
    hasTask := false
    for {
    _, ok := <-ticker.C
    if !ok {
    return
    }
    if hasTask {
    continue
    }
    ws.Lock.RLock()
    if ws.Cert == nil {
    ws.Lock.RUnlock()
    continue
    }
    x509Cert, err := x509.ParseCertificate(ws.Cert.Certificate[0])
    if err != nil {
    ws.Lock.RUnlock()
    continue
    }
    err = utils.CheckValidityPeriodWithError(x509Cert, ws.OverdueTime)
    ws.Lock.RUnlock()
    if err == nil {
    continue
    }
    hwlog.RunLog.Warn(err)
    go func() {
    hasTask = true
    defer func() {
    hasTask = false
    hwlog.RunLog.Info("apply for a new certificate success")
    }()
    hwlog.RunLog.Info("apply for a new certificate because the certificate has expired")
    if err = ws.ApplyForCertificateByRequest(); err != nil {
    hwlog.RunLog.Error(err)
    }
    }()
    }
    }

    // GetCaByRequest get ca by request
    func (ws *WebCertUtil) GetCaByRequest() ([]byte, error) {
    caByte, err := DefaultClsMgrClient.GetRootCertificate()
    if err != nil {
    return nil, err
    }
    hwlog.RunLog.Info("succeeded in getting ca certificate by request")
    if err = ioutil.WriteFile(ws.CaStore, caByte, utils.RWMode); err != nil {
    return nil, errors.New("write caBytes to file failed")
    }
    hwlog.RunLog.Info("succeeded in saving ca certificate to file")
    ws.CaBytes = caByte
    return caByte, nil
    }

    // ApplyForCertificateByRequest apply for certificate by request
    func (ws *WebCertUtil) ApplyForCertificateByRequest() error {
    certPem, err := DefaultClsMgrClient.ApplyForCertificatePemByte(ws.DNSName, ws.CaBytes, ws.PrivateKey)
    if err != nil {
    return err
    }
    hwlog.RunLog.Info("succeeded in getting certificate by request")

    derStream := x509.MarshalPKCS1PrivateKey(ws.PrivateKey)
    block := &pem.Block{
    Type: RSAPrivateKey,
    Bytes: derStream,
    }
    keyPem := pem.EncodeToMemory(block)
    tlsCert, err := utils.ValidateCertPair(certPem, keyPem, false, ws.OverdueTime)
    if err != nil {
    return err
    }
    if err = ioutil.WriteFile(ws.CertStore, certPem, utils.RWMode); err != nil {
    return errors.New("write certBytes to file failed ")
    }
    hwlog.RunLog.Info("succeeded in saving certificate to file")

    ws.Lock.RLock()
    defer ws.Lock.RUnlock()

    ws.refreshCertStatus(tlsCert)
    ws.Cert = tlsCert
    return nil
    }

    func (ws *WebCertUtil) refreshCertStatus(tlsCert *tls.Certificate) {
    // clear cert status record
    ws.ClearCertificateMap()

    caCert, err := utils.LoadCertsFromPEM(ws.CaBytes)
    if err == nil {
    // refresh ca record
    err = utils.AddToCertStatusTrace(caCert)
    }
    if err != nil {
    hwlog.RunLog.Error("prepare refresh ca info failed: " + err.Error())
    }

    x509Cert, err := x509.ParseCertificate(tlsCert.Certificate[0])
    if err == nil {
    // refresh certificate record
    err = utils.AddToCertStatusTrace(x509Cert)
    }
    if err != nil {
    hwlog.RunLog.Error("prepare refresh certificate info failed: " + err.Error())
    }
    hwlog.RunLog.Info("succeeded in refresh ca/cert info")
    }

    // SetHTTPSServer set http server config for one or two way auth
    func (ws *WebCertUtil) SetHTTPSServer(s *http.Server, concurrency, maxConcurrency int,
    cipherSuites []uint16, ginObj *gin.Engine) error {
    tlsConfig, err := utils.NewTLSConfigV2(ws.CaBytes, *ws.Cert, cipherSuites)
    if err != nil {
    return err
    }

    tlsConfig.Certificates = nil
    tlsConfig.GetCertificate = ws.GetCertificateFunc()
    s.Handler = limiter.NewLimitHandler(concurrency, maxConcurrency, utils.Interceptor(ginObj, ws.CrlList), false)
    s.TLSConfig = tlsConfig

    return nil
    }

    // ReApplyCertificate reapply certificate
    func (ws *WebCertUtil) ReApplyCertificate(algorithm int) error {
    hwlog.RunLog.Info("prepare to reapply a new certificate")
    if ws.PrivateKey == nil {
    if _, err := ws.GenerateRSAPrivateKey(keyLength, algorithm); err != nil {
    return err
    }
    }
    if err := ws.ApplyForCertificateByRequest(); err != nil {
    return err
    }

    return nil
    }

    // GetRequestClient get http client for request
    func (ws *WebCertUtil) GetRequestClient(authMode string) (*http.Client, error) {
    // https auth two way
    if authMode == TwoWay {
    requestClient, err := ws.GetTwoWayAuthRequestClient()
    if err != nil {
    return nil, err
    }

    return requestClient, nil
    }

    // https auth one way
    pool, err := x509.SystemCertPool()
    if err != nil {
    return nil, fmt.Errorf("cannot get system trusted certificates pool: %w", err)
    }
    if !pool.AppendCertsFromPEM(ws.CaBytes) {
    return nil, fmt.Errorf("failed to append to certificates pool")
    }
    c := &http.Client{
    Transport: &http.Transport{
    TLSClientConfig: &tls.Config{
    RootCAs: pool,
    },
    },
    }

    return c, nil
    }

    // InitCert init cert and ca
    func InitCert(sp *ServerParam) error {
    ws := NewWebCertUtil(sp.DNSName, sp.DirName, sp.OverdueTime)
    var reApply bool
    var caBytes []byte
    // load ca
    _, err := ws.LoadCAOnStart(sp.AuthMode)
    if err != nil && strings.Contains(err.Error(), ReApply) {
    reApply = true
    }
    // reapply ca
    if reApply {
    caBytes, err = ws.GetCaByRequest()
    if len(caBytes) == 0 || err != nil {
    return err
    }
    reApply = false
    }
    if err != nil {
    return err
    }
    // load cert and private key
    _, err = ws.LoadCertAndKeyOnStart(sp.EncryptAlgorithm)
    if err != nil && strings.Contains(err.Error(), ReApply) {
    reApply = true
    }
    // reapply cert
    if reApply {
    if err = ws.ReApplyCertificate(sp.EncryptAlgorithm); err != nil {
    return err
    }
    }
    if err != nil {
    return err
    }

    // init global WebCertUtil
    webCert = ws
    return nil
    }

    // StartServerListen StartServerListen
    func StartServerListen(sp *ServerParam, engine *gin.Engine) {
    s := &http.Server{
    ReadTimeout: sp.ReadTimeOut * time.Second,
    WriteTimeout: sp.WriteTimeOut * time.Second,
    Addr: sp.IP + ":" + strconv.Itoa(sp.Port),
    Handler: limiter.NewLimitHandler(sp.Concurrency, sp.MaxConcurrency, engine, false),
    }
    // http
    if sp.EnableHTTP {
    // http
    hwlog.RunLog.Warn("Service started with an insecure http server enabled")
    if err := s.ListenAndServe(); err != nil {
    hwlog.RunLog.Error("Http server error and stopped")
    }
    return
    }

    // init web cert util
    err := InitCert(sp)
    if err != nil {
    hwlog.RunLog.Error(err)
    return
    }
    ParseTLSParams(sp)
    wc := GetWebCertUtil()
    if err = wc.SetHTTPSServer(s, sp.Concurrency, sp.MaxConcurrency, sp.CipherSuites,
    engine); err != nil {
    hwlog.RunLog.Error(err)
    return
    }
    hwlog.RunLog.Info("start https server now...")
    // start certificate period check
    go wc.CheckCertValidityPeriod(sp.CheckCertPeriod)

    if err = s.ListenAndServeTLS("", ""); err != nil {
    hwlog.RunLog.Error("Https server error by: %s and stopped", err.Error())
    }
    }
  • 相关阅读:
    LAMP 环境搭建备忘 -- Linux的安装(一)
    Qt 的一些浅知识点
    chm 转 txt
    SQL 语句 (二) --- SELECT
    SQL语句 (一)
    量子电路
    量子隐形传态 Quantum Teleportation
    量子逻辑门
    量子纠缠2——CHSH不等式
    量子纠缠1——量子比特、Bell态、EPR佯谬
  • 原文地址:https://www.cnblogs.com/gongxianjin/p/16683183.html
Copyright © 2020-2023  润新知