package cert
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"io/ioutil"
"math/big"
rd "math/rand"
"net"
"os"
"time"
)
func init() {
rd.Seed(time.Now().UnixNano())
}
type CertInformation struct {
Country []string
Organization []string
OrganizationalUnit []string
EmailAddress []string
Province []string
Locality []string
CommonName string
CrtName, KeyName string
IsCA bool
Names []pkix.AttributeTypeAndValue
IPAddresses []net.IP
Domains []string
}
func CreateCRT(RootCa *x509.Certificate, RootKey *rsa.PrivateKey, info CertInformation) error {
Crt := newCertificate(info)
Key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return err
}
var buf []byte
if RootCa == nil || RootKey == nil {
buf, err = x509.CreateCertificate(rand.Reader, Crt, Crt, &Key.PublicKey, Key)
if err != nil {
return err
}
keybuf := x509.MarshalPKCS1PrivateKey(Key)
err = write(info.KeyName, "PRIVATE KEY", keybuf)
} else {
buf, err = x509.CreateCertificate(rand.Reader, Crt, RootCa, &Key.PublicKey, RootKey)
if err != nil {
return err
}
keybuf := x509.MarshalPKCS1PrivateKey(Key)
err = write(info.KeyName, "RSA PRIVATE KEY", keybuf)
}
if err != nil {
return err
}
err = write(info.CrtName, "CERTIFICATE", buf)
if err != nil {
return err
}
return nil
}
func write(filename, Type string, p []byte) error {
File, err := os.Create(filename)
defer File.Close()
if err != nil {
return err
}
var b = &pem.Block{Bytes: p, Type: Type}
return pem.Encode(File, b)
}
func Parse(crtPath, keyPath string) (rootcertificate *x509.Certificate, rootPrivateKey *rsa.PrivateKey, err error) {
rootcertificate, err = ParseCrt(crtPath)
if err != nil {
return
}
rootPrivateKey, err = ParseKey(keyPath)
return
}
func ParseCrt(path string) (*x509.Certificate, error) {
buf, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
p := &pem.Block{}
p, buf = pem.Decode(buf)
return x509.ParseCertificate(p.Bytes)
}
func ParseKey(path string) (*rsa.PrivateKey, error) {
buf, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
p, buf := pem.Decode(buf)
return x509.ParsePKCS1PrivateKey(p.Bytes)
}
func newCertificate(info CertInformation) *x509.Certificate {
return &x509.Certificate{
SerialNumber: big.NewInt(rd.Int63()),
Subject: pkix.Name{
Country: info.Country,
Organization: info.Organization,
OrganizationalUnit: info.OrganizationalUnit,
Province: info.Province,
CommonName: info.CommonName,
Locality: info.Locality,
ExtraNames: info.Names,
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(20, 0, 0),
BasicConstraintsValid: true,
IsCA: info.IsCA,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
EmailAddresses: info.EmailAddress,
IPAddresses: info.IPAddresses,
DNSNames: info.Domains,
}
}