go - 使用证书颁发机构签署证书请求

标签 go x509certificate tls1.2 pki mutual-authentication

我想使用 TLS 相互身份验证在 go 中制作的 API 上对客户端进行身份验证。我已经创建了一个证书颁发机构,假设 Bob 有一个他想与客户端一起使用的 key 对。 Bob 创建了一个证书请求并希望我验证他的证书以便获得授权和 在 API 上进行身份验证。

我用它来创建我的证书颁发机构:

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

Bob 使用它来创建他的证书和证书请求:

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

我想实现这个,但是在进行中:

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
}

但是如果 Julia 现在想登录怎么办?她将必须创建一个 CSR,将其发送给我,我也必须手动将她的 CSR 验证到 CRT。为了避免这种手动操作,我们的想法是拥有一个注册端点,Julia 可以在其中提交她的 CSR 并取回有效的 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 有一个 CertificateRequest object来 self 可以使用 ParseCertificateRequest 创建的 crypto/x509 包但我找不到获取此对象和我的 CA 并返回证书的函数。

感谢您的帮助!

最佳答案

它现在可以工作了,这里是使用 CA 从 CRT 验证 CSR 的基本解决方案:

  • 加载CA证书
  • 加载ca私钥(带密码)
  • 加载鲍勃 CSR
  • 使用 CSR 和 CA 信息创建证书模板
  • 使用模板和 CA 私钥生成证书
  • 保存bob的证书

一个工作示例:

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()
}

谢谢马克!

关于go - 使用证书颁发机构签署证书请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42643048/

相关文章:

database - Go 中多线程 LevelDB 的合适方法是什么?

Go Dep - 在 dep 确保后缺少子包 "chi/middleware"

Golang gin 代理处理 svelte 前端和 Golang api

c# System.Security.Cryptography.X509Certificates.X509ContentType.Cert 这是 DER 吗?

java - 如何在我的 android studio 应用程序中实现 TLS V1.1 和 V1.2?

security - 将客户端证书的 DN 传递给 Tomcat 中已部署的应用程序

ssl - 具有本地 IP 的设备的自签名证书

go - 如何在本地连接字符串和整数?

java - 对于非证书输入,CertificateFactory 返回 null

bash - 通过 OpenSSL 自动生成 x509 证书