用证书授权签署证书请求



我想使用TLS相互认证对GO中的API进行身份验证客户端。我已经创建了一个证书授权,假设鲍勃有一个他想与客户使用的关键对。鲍勃创建了证书请求,并希望我验证他的证书以获得授权和在API上进行身份验证。

我已经用它来创建我的证书授权:

openssl genrsa -aes256 -out ca.key 4096
openssl req -new -x509 -sha256 -days 730 -key ca.key -out ca.crt

鲍勃用它来创建他的证书和证书请求:

openssl genrsa -out bob.key 4096
openssl req -new -key bob.key -out bob.csr

我想实现这一目标,但在GO中:

openssl x509 -req -days 365 -sha256 -in bob.csr -CA ca.crt -CAkey ca.key -set_serial 3 -out bob.crt

目前,使用这些命令,Bob可以创建与我的API的TLS连接,该连接使用此tls.config:

func createTLSConfig(certFile string, keyFile string, clientCAFilepath string) (config *tls.Config, err error) {
    cer, err := tls.LoadX509KeyPair(certFile, keyFile)
    if err != nil {
        return nil, err
    }
    clientCAFile, err := ioutil.ReadFile(clientCAFilepath)
    if err != nil {
        return nil, err
    }
    clientCAPool := x509.NewCertPool()
    clientCAPool.AppendCertsFromPEM(clientCAFile)
    config = &tls.Config{
        Certificates: []tls.Certificate{cer},
        ClientAuth: tls.RequireAndVerifyClientCert,
        ClientCAs:  clientCAPool,
        CipherSuites: []uint16{
            tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
            tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
        },
        PreferServerCipherSuites: true,
        SessionTicketsDisabled:   false,
        MinVersion:               tls.VersionTLS12,
        CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384},
    }
    return config, nil
}

但是,如果朱莉娅现在想登录怎么办?她将不得不创建一个CSR,将其发送给我,我也必须手动将她的企业社会责任验证到CRT。为了避免此手动操作,这个想法是要有一个登记端终点,朱莉娅可以在其中提交她的企业社会责任并恢复有效的CRT。端点基本上看起来像这样:

func Register(c echo.Context) (err error) {
    // get Julia's csr from POST body
    csr := certificateFromBody(c.Body)
    // valid csr with ca to generate the crt
    crt := signCSR(csr, config.ClientCAPath)
    // return the crt to julia
    return c.JSON(http.StatusCreated, base64.StdEncoding.EncodeToString(crt))
}

我花了一些时间来了解OpenSSL如何使用CA从CRS创建CRT,而无需成功。

golang在Crypto/X509软件包中有一个CERTIFATETEREQUEST对象,我可以使用ParseCertificateRequest创建,但我找不到将此对象和我的CA返回证书的功能。

谢谢您的帮助!

现在起作用,这是一种基本解决方案,可以从具有CA的CRT验证CSR:

  • 加载CA证书
  • 加载ca私钥(带密码)
  • 加载Bob CSR
  • 使用CSR和CA Informations创建一个证书模板
  • 从模板和CA私钥生成证书
  • 保存鲍勃的证书

一个工作示例:

package main
import (
    "crypto/rand"
    "crypto/x509"
    "encoding/pem"
    "io/ioutil"
    "math/big"
    "os"
    "time"
)
func crsToCrtExample() {
    // load CA key pair
    //      public key
    caPublicKeyFile, err := ioutil.ReadFile("certs/ca-root.crt")
    if err != nil {
        panic(err)
    }
    pemBlock, _ := pem.Decode(caPublicKeyFile)
    if pemBlock == nil {
        panic("pem.Decode failed")
    }
    caCRT, err := x509.ParseCertificate(pemBlock.Bytes)
    if err != nil {
        panic(err)
    }
    //      private key
    caPrivateKeyFile, err := ioutil.ReadFile("certs/ca-mutu.key")
    if err != nil {
        panic(err)
    }
    pemBlock, _ = pem.Decode(caPrivateKeyFile)
    if pemBlock == nil {
        panic("pem.Decode failed")
    }
    der, err := x509.DecryptPEMBlock(pemBlock, []byte("ca private key password"))
    if err != nil {
        panic(err)
    }
    caPrivateKey, err := x509.ParsePKCS1PrivateKey(der)
    if err != nil {
        panic(err)
    }
    // load client certificate request
    clientCSRFile, err := ioutil.ReadFile("certs/bob.csr")
    if err != nil {
        panic(err)
    }
    pemBlock, _ = pem.Decode(clientCSRFile)
    if pemBlock == nil {
        panic("pem.Decode failed")
    }
    clientCSR, err := x509.ParseCertificateRequest(pemBlock.Bytes)
    if err != nil {
        panic(err)
    }
    if err = clientCSR.CheckSignature(); err != nil {
        panic(err)
    }
    // create client certificate template
    clientCRTTemplate := x509.Certificate{
        Signature:          clientCSR.Signature,
        SignatureAlgorithm: clientCSR.SignatureAlgorithm,
        PublicKeyAlgorithm: clientCSR.PublicKeyAlgorithm,
        PublicKey:          clientCSR.PublicKey,
        SerialNumber: big.NewInt(2),
        Issuer:       caCRT.Subject,
        Subject:      clientCSR.Subject,
        NotBefore:    time.Now(),
        NotAfter:     time.Now().Add(24 * time.Hour),
        KeyUsage:     x509.KeyUsageDigitalSignature,
        ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
    }
    // create client certificate from template and CA public key
    clientCRTRaw, err := x509.CreateCertificate(rand.Reader, &clientCRTTemplate, caCRT, clientCSR.PublicKey, caPrivateKey)
    if err != nil {
        panic(err)
    }
    // save the certificate
    clientCRTFile, err := os.Create("certs/bob.crt")
    if err != nil {
        panic(err)
    }
    pem.Encode(clientCRTFile, &pem.Block{Type: "CERTIFICATE", Bytes: clientCRTRaw})
    clientCRTFile.Close()
}

谢谢Mark!

您可以使用x509.CreateCertificate。

创建的参数之一是"模板"证书。

您可以使用Julia的CertifateRequest中的字段设置模板证书的字段。

go的生成证书脚本显示一个示例用法createCertificate。

这假设朱莉娅的API请求确实来自朱莉娅,并且足够信任签署请求并返回证书。

另外,在GO中使用自己的PKI进行TLS可能会有所帮助。

这是我为有关PKI的博客文章编写的演示程序中的代码段。完整文章:https://anchorloop.com/2017/09/25/security-iq-iiq-ii-public-key-infrastructure/

// Now read that number of bytes and parse the certificate request
asn1Data := make([]byte, asn1DataSize)
_, err = reader.Read(asn1Data)
if err != nil {
    return err
}
fmt.Println("Received Certificate Signing Request.")
certReq, err := x509.ParseCertificateRequest(asn1Data)
if err != nil {
    return err
}
// Create template for certificate creation, uses properties from the request and root certificate.
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
    return err
}
template := x509.Certificate {
    Signature: certReq.Signature,
    SignatureAlgorithm: certReq.SignatureAlgorithm,
    PublicKeyAlgorithm: certReq.PublicKeyAlgorithm,
    PublicKey: certReq.PublicKey,
    SerialNumber: serialNumber,
    Issuer: rootCert.Subject,
    Subject: certReq.Subject,
    NotBefore: time.Now(),
    NotAfter: time.Now().Add(time.Hour * 24 * 365),
    KeyUsage: x509.KeyUsageDigitalSignature,
    ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}
// Create certificate from template and root certificate, signed by the RootCA's private key.
certData, err := x509.CreateCertificate(rand.Reader, &template, rootCert, template.PublicKey, privateKey)
if err != nil {
    return err
}
fmt.Println("Created Certificate from CSR, signed by RootCA's Private Key.")

基本上:

  • CSR由客户创建和发送。
  • 签名证书的所有者对其进行解析,并从CSR和签名证书中的混合物中构建新的X509。
  • 签名者的私钥将传递给x509.CreateCertificate签名。
  • 之后,您可以将其发送回客户。

我希望有帮助。

相关内容

  • 没有找到相关文章

最新更新