mirror of
https://github.com/ehang-io/nps.git
synced 2025-07-02 04:00:42 +00:00
109 lines
2.6 KiB
Go
109 lines
2.6 KiB
Go
package cert
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/pem"
|
|
"errors"
|
|
"math/big"
|
|
"time"
|
|
)
|
|
|
|
var _ Generator = (*X509Generator)(nil)
|
|
|
|
type Generator interface {
|
|
CreateRootCa() ([]byte, []byte, error)
|
|
CreateCert(dnsName string) ([]byte, []byte, error)
|
|
InitRootCa(rootCa []byte, rootKey []byte) error
|
|
}
|
|
|
|
type X509Generator struct {
|
|
rootCert *x509.Certificate
|
|
rootRsaPrivate *rsa.PrivateKey
|
|
subject pkix.Name
|
|
}
|
|
|
|
func NewX509Generator(subject pkix.Name) *X509Generator {
|
|
return &X509Generator{
|
|
subject: subject,
|
|
}
|
|
}
|
|
|
|
func (cg *X509Generator) InitRootCa(rootCa []byte, rootKey []byte) error {
|
|
var err error
|
|
caBlock, _ := pem.Decode(rootCa)
|
|
cg.rootCert, err = x509.ParseCertificate(caBlock.Bytes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
keyBlock, _ := pem.Decode(rootKey)
|
|
cg.rootRsaPrivate, err = x509.ParsePKCS1PrivateKey(keyBlock.Bytes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (cg *X509Generator) CreateCert(dnsName string) ([]byte, []byte, error) {
|
|
return cg.create(false, dnsName)
|
|
}
|
|
|
|
func (cg *X509Generator) CreateRootCa() ([]byte, []byte, error) {
|
|
return cg.create(true, "")
|
|
}
|
|
|
|
func (cg *X509Generator) create(isRootCa bool, dnsName string) ([]byte, []byte, error) {
|
|
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
|
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
|
template := &x509.Certificate{
|
|
SerialNumber: serialNumber,
|
|
Subject: cg.subject,
|
|
NotBefore: time.Now(),
|
|
NotAfter: time.Now().AddDate(3, 0, 0),
|
|
BasicConstraintsValid: true,
|
|
IsCA: false,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
|
|
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageDataEncipherment,
|
|
DNSNames: []string{dnsName},
|
|
}
|
|
|
|
if isRootCa {
|
|
template.IsCA = true
|
|
template.KeyUsage |= x509.KeyUsageCertSign
|
|
}
|
|
|
|
priKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
var ca []byte
|
|
if !isRootCa {
|
|
if cg.rootCert == nil || cg.rootRsaPrivate == nil {
|
|
return nil, nil, errors.New("root ca is not exist")
|
|
}
|
|
ca, err = x509.CreateCertificate(rand.Reader, template, cg.rootCert, &priKey.PublicKey, cg.rootRsaPrivate)
|
|
} else {
|
|
ca, err = x509.CreateCertificate(rand.Reader, template, template, &priKey.PublicKey, priKey)
|
|
}
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
caPem := &pem.Block{
|
|
Type: "CERTIFICATE",
|
|
Bytes: ca,
|
|
}
|
|
ca = pem.EncodeToMemory(caPem)
|
|
|
|
buf := x509.MarshalPKCS1PrivateKey(priKey)
|
|
keyPem := &pem.Block{
|
|
Type: "PRIVATE KEY",
|
|
Bytes: buf,
|
|
}
|
|
key := pem.EncodeToMemory(keyPem)
|
|
return ca, key, nil
|
|
}
|