Signing certificate request with certificate authority

一笑奈何 提交于 2019-12-05 05:05:28

You may be able to use x509.CreateCertificate.

One of the parameters to CreateCertificate is a 'template' certificate.

You can set the fields of the template certificate using the fields from Julia's CertificateRequest.

Go's generate cert script shows an example usage CreateCertificate.

This assumes the API request from Julia is really from Julia, and sufficiently trusted to sign the request and return a certificate.

Also, Using your own PKI for TLS in Go may be of help.

It work now, here is a basic solution to validate a CSR from a CRT with a CA:

  • load ca certificate
  • load ca private key (with password)
  • load bob CSR
  • create a certificate template with the CSR and CA informations
  • generate the certificate from the template and with the CA private key
  • save the bob's certificate

A working example:

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

Thanks Mark!

Here's a snippet of code from a demo program I wrote for a blog post about PKI. Full post: https://anchorloop.com/2017/09/25/security-iq-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.")

Basically:

  • The CSR gets created and sent by the client.
  • The owner of the signing certificate parses it and builds a new x509.Certificate from a mixture of properties from the CSR and signing certificate.
  • The private key of the signer is passed to x509.CreateCertificate to sign it.
  • After that, you can send it back to the client.

I hope that helps.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!