当前位置:网站首页>Create Ca and issue certificate through go language

Create Ca and issue certificate through go language

2022-07-04 22:40:00 Hermokrates

In this article , Will describe how to use go establish CA, And use CA Signed certificate . In the use of openssl When creating a certificate , The steps to follow are Create secret key > establish CA > Generate the secret key to issue the certificate > Use CA grant a certificate . Such steps , So let's try it now .

The authority that created the certificate

First , Will be created from CA Start .CA Will be used to sign other certificates

//  Sign the certificate 
ca := &x509.Certificate{
    
	SerialNumber: big.NewInt(2019),
	Subject: pkix.Name{
    
        CommonName:    "domain name",
		Organization:  []string{
    "Company, INC."},
		Country:       []string{
    "US"},
		Province:      []string{
    ""},
		Locality:      []string{
    "San Francisco"},
		StreetAddress: []string{
    "Golden Gate Bridge"},
		PostalCode:    []string{
    "94016"},
	},
	NotBefore:             time.Now(),  //  entry-into-force time 
	NotAfter:              time.Now().AddDate(10, 0, 0), //  Expiration time   Specific date 
	IsCA:                  true, //  For CA
    // openssl  Medium  extendedKeyUsage = clientAuth, serverAuth  Field 
	ExtKeyUsage:           []x509.ExtKeyUsage{
    x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
    // openssl  Medium  keyUsage  Field 
	KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
	BasicConstraintsValid: true,
}

Next, you need to generate public and private keys for the certificate

caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
    
	return err
}

And then generate the certificate :

caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey)
if err != nil {
    
	return err
}

The certificate we see is PEM Encoding , Now? caBytes We have the generated certificate , We'll do it PEM Code for later use :

caPEM := new(bytes.Buffer)
pem.Encode(caPEM, &pem.Block{
    
	Type:  "CERTIFICATE",
	Bytes: caBytes,
})

caPrivKeyPEM := new(bytes.Buffer)
pem.Encode(caPrivKeyPEM, &pem.Block{
    
	Type:  "RSA PRIVATE KEY",
	Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey),
})

Create certificate

Certificate x509.Certificate And CA Of x509.Certificate Properties are slightly different , Some changes are needed

cert := &x509.Certificate{
    
	SerialNumber: big.NewInt(1658),
	Subject: pkix.Name{
    
        CommonName:    "domain name",
		Organization:  []string{
    "Company, INC."},
		Country:       []string{
    "US"},
		Province:      []string{
    ""},
		Locality:      []string{
    "San Francisco"},
		StreetAddress: []string{
    "Golden Gate Bridge"},
		PostalCode:    []string{
    "94016"},
	},
    IPAddresses:  []net.IP{
    }, //  Here is the openssl In profile  subjectAltName  Inside  IP:/IP=
    DNSNames:     []string{
    }, //  Here is the openssl In profile  subjectAltName  Inside  DNS:/DNS=
	NotBefore:    time.Now(),
	NotAfter:     time.Now().AddDate(10, 0, 0),
	SubjectKeyId: []byte{
    1, 2, 3, 4, 6},
    //  Here is the openssl Medium extendedKeyUsage 
	ExtKeyUsage:  []x509.ExtKeyUsage{
    x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
	KeyUsage:     x509.KeyUsageDigitalSignature,
}

notes : Here, the certificate will be specially added DNS and IP ( This is not necessary ), The addition of this option means that our certificate can support multiple domain names

Create a private and public key for the certificate :

certPrivKey, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
    
	return err
}

Use CA Signed certificate

With the above content , You can create certificates and use CA To sign

certBytes, err := x509.CreateCertificate(rand.Reader, cert, ca, &certPrivKey.PublicKey, caPrivKey)
if err != nil {
    
	return err
}

To save in certificate format, you need to do PEM code

certPEM := new(bytes.Buffer)
pem.Encode(certPEM, &pem.Block{
    
	Type:  "CERTIFICATE",
	Bytes: certBytes,
})

certPrivKeyPEM := new(bytes.Buffer)
pem.Encode(certPrivKeyPEM, &pem.Block{
    
	Type:  "RSA PRIVATE KEY",
	Bytes: x509.MarshalPKCS1PrivateKey(certPrivKey),
})

Integrate the above contents

Create a ca.go Inside is create ca And the logic of issuing certificates

package main

import (
	"bytes"
	cr "crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"math/big"
	"math/rand"
	"net"
	"os"
	"time"
)

type CERT struct {
    
	CERT       []byte
	CERTKEY    *rsa.PrivateKey
	CERTPEM    *bytes.Buffer
	CERTKEYPEM *bytes.Buffer
	CSR        *x509.Certificate
}

func CreateCA(sub *pkix.Name, expire int) (*CERT, error) {
    
	var (
		ca  = new(CERT)
		err error
	)

	if expire < 1 {
    
		expire = 1
	}
	//  by ca Generate private key 
	ca.CERTKEY, err = rsa.GenerateKey(cr.Reader, 4096)
	if err != nil {
    
		return nil, err
	}

	//  Sign the certificate 
	ca.CSR = &x509.Certificate{
    
		SerialNumber: big.NewInt(rand.Int63n(2000)),
		Subject:      *sub,
		NotBefore:    time.Now(),                       //  entry-into-force time 
		NotAfter:     time.Now().AddDate(expire, 0, 0), //  Expiration time 
		IsCA:         true,                             //  For CA
		// openssl  Medium  extendedKeyUsage = clientAuth, serverAuth  Field 
		ExtKeyUsage: []x509.ExtKeyUsage{
    x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
		// openssl  Medium  keyUsage  Field 
		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
		BasicConstraintsValid: true,
	}
	//  Create certificate 
	// caBytes  Is the generated certificate 
	ca.CERT, err = x509.CreateCertificate(cr.Reader, ca.CSR, ca.CSR, &ca.CERTKEY.PublicKey, ca.CERTKEY)
	if err != nil {
    
		return nil, err
	}
	ca.CERTPEM = new(bytes.Buffer)
	pem.Encode(ca.CERTPEM, &pem.Block{
    
		Type:  "CERTIFICATE",
		Bytes: ca.CERT,
	})
	ca.CERTKEYPEM = new(bytes.Buffer)
	pem.Encode(ca.CERTKEYPEM, &pem.Block{
    
		Type:  "RSA PRIVATE KEY",
		Bytes: x509.MarshalPKCS1PrivateKey(ca.CERTKEY),
	})

	//  Conduct PEM code , Coding is direct cat What is shown in the certificate 
	return ca, nil
}

func Req(ca *x509.Certificate, sub *pkix.Name, expire int, dns []string, ip []net.IP) (*CERT, error) {
    
	var (
		cert = &CERT{
    }
		err  error
	)
	cert.CERTKEY, err = rsa.GenerateKey(cr.Reader, 4096)
	if err != nil {
    
		return nil, err
	}
	if expire < 1 {
    
		expire = 1
	}
	cert.CSR = &x509.Certificate{
    
		SerialNumber: big.NewInt(rand.Int63n(2000)),
		Subject:      *sub,
		IPAddresses:  ip,
		DNSNames:     dns,
		NotBefore:    time.Now(),
		NotAfter:     time.Now().AddDate(expire, 0, 0),
		SubjectKeyId: []byte{
    1, 2, 3, 4, 6},
		ExtKeyUsage:  []x509.ExtKeyUsage{
    x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
		KeyUsage:     x509.KeyUsageDigitalSignature,
	}

	cert.CERT, err = x509.CreateCertificate(cr.Reader, cert.CSR, ca, &cert.CERTKEY.PublicKey, cert.CERTKEY)
	if err != nil {
    
		return nil, err
	}

	cert.CERTPEM = new(bytes.Buffer)
	pem.Encode(cert.CERTPEM, &pem.Block{
    
		Type:  "CERTIFICATE",
		Bytes: cert.CERT,
	})
	cert.CERTKEYPEM = new(bytes.Buffer)
	pem.Encode(cert.CERTKEYPEM, &pem.Block{
    
		Type:  "RSA PRIVATE KEY",
		Bytes: x509.MarshalPKCS1PrivateKey(cert.CERTKEY),
	})
	return cert, nil
}

func Write(cert *CERT, file string) error {
    
	keyFileName := file + ".key"
	certFIleName := file + ".crt"
	kf, err := os.Create(keyFileName)
	if err != nil {
    
		return err
	}
	defer kf.Close()

	if _, err := kf.Write(cert.CERTKEYPEM.Bytes()); err != nil {
    
		return err
	}

	cf, err := os.Create(certFIleName)
	if err != nil {
    
		return err
	}
	if _, err := cf.Write(cert.CERTPEM.Bytes()); err != nil {
    
		return err
	}
	return nil
}

If needed , You can reference these functions

package main

import (
	"crypto/x509/pkix"
	"log"
	"net"
)

func main() {
    
	subj := &pkix.Name{
    
		CommonName:    "chinamobile.com",
		Organization:  []string{
    "Company, INC."},
		Country:       []string{
    "US"},
		Province:      []string{
    ""},
		Locality:      []string{
    "San Francisco"},
		StreetAddress: []string{
    "Golden Gate Bridge"},
		PostalCode:    []string{
    "94016"},
	}
	ca, err := CreateCA(subj, 10)
	if err != nil {
    
		log.Panic(err)
	}

	Write(ca, "./ca")

	crt, err := Req(ca.CSR, subj, 10, []string{
    "test.default.svc", "test"}, []net.IP{
    })

	if err != nil {
    
		log.Panic(err)
	}

	Write(crt, "./tls")
}

Problems encountered

panic: x509: unsupported public key type: rsa.PublicKey

This is because x509.CreateCertificate Parameters of privatekey You need to pass in reference variables , What is passed in is a common variable

notes :x509: only RSA and ECDSA public keys supported

The meaning of some parameters

extendedKeyUsage : Enhanced key usage ( See "new_oids" Field ): Server authentication 、 Client authentication 、 Time stamp .

extendedKeyUsage = critical,serverAuth, clientAuth, timeStamping

keyUsage : Key usage , Anti denial (nonRepudiation)、 digital signature (digitalSignature)、 Key encryption (keyEncipherment).

keyUsage = nonRepudiation, digitalSignature, keyEncipherment

Reference

golang ca and signed cert go

package x509

原网站

版权声明
本文为[Hermokrates]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/185/202207042206415219.html