200 lines
6.7 KiB
Go
200 lines
6.7 KiB
Go
package cert
|
|
|
|
import (
|
|
"bytes"
|
|
cryptorand "crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/pem"
|
|
"io/ioutil"
|
|
"math/big"
|
|
"math/rand"
|
|
"net"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
func CreateSignCertToFile(rootCa *x509.Certificate, rootKey *rsa.PrivateKey, domainOrIP string, expireDays int, name string) (err error) {
|
|
cert, key, err := CreateSignCert(rootCa, rootKey, domainOrIP, expireDays)
|
|
if err != nil {
|
|
return
|
|
}
|
|
err = ioutil.WriteFile(name+".crt", cert, 0755)
|
|
if err != nil {
|
|
return
|
|
}
|
|
err = ioutil.WriteFile(name+".key", key, 0755)
|
|
return
|
|
}
|
|
func CreateSignCert(rootCa *x509.Certificate, rootKey *rsa.PrivateKey, domainOrIP string, expireDays int) (certBytes []byte, keyBytes []byte, err error) {
|
|
cer := &x509.Certificate{
|
|
SerialNumber: big.NewInt(rand.Int63()), //证书序列号
|
|
Subject: pkix.Name{
|
|
Country: []string{getCountry()},
|
|
Organization: []string{domainOrIP},
|
|
OrganizationalUnit: []string{domainOrIP},
|
|
CommonName: domainOrIP,
|
|
},
|
|
NotBefore: time.Now().Add(-time.Hour),
|
|
NotAfter: time.Now().Add(time.Hour * 24 * time.Duration(expireDays)),
|
|
BasicConstraintsValid: true,
|
|
IsCA: false,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
|
//KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageDataEncipherment,
|
|
EmailAddresses: []string{},
|
|
IPAddresses: []net.IP{},
|
|
}
|
|
if ip := net.ParseIP(domainOrIP); ip != nil {
|
|
cer.IPAddresses = append(cer.IPAddresses, ip)
|
|
} else {
|
|
cer.DNSNames = append(cer.DNSNames, domainOrIP)
|
|
}
|
|
|
|
// cer.IPAddresses = append(cer.IPAddresses, alternateIPs...)
|
|
// cer.DNSNames = append(cer.DNSNames, alternateDNS...)
|
|
|
|
//生成公钥私钥对
|
|
priKey, err := rsa.GenerateKey(cryptorand.Reader, 2048)
|
|
if err != nil {
|
|
return
|
|
}
|
|
certBytes, err = x509.CreateCertificate(cryptorand.Reader, cer, rootCa, &priKey.PublicKey, rootKey)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
//编码证书文件和私钥文件
|
|
caPem := &pem.Block{
|
|
Type: "CERTIFICATE",
|
|
Bytes: certBytes,
|
|
}
|
|
certBytes = pem.EncodeToMemory(caPem)
|
|
|
|
buf := x509.MarshalPKCS1PrivateKey(priKey)
|
|
keyPem := &pem.Block{
|
|
Type: "PRIVATE KEY",
|
|
Bytes: buf,
|
|
}
|
|
keyBytes = pem.EncodeToMemory(keyPem)
|
|
return
|
|
}
|
|
func CreateCaToFile(name, domainOrIP string, expireDays int) (err error) {
|
|
ca, key, err := CreateCa(domainOrIP, expireDays)
|
|
if err != nil {
|
|
return
|
|
}
|
|
err = ioutil.WriteFile(name+".crt", ca, 0755)
|
|
if err != nil {
|
|
return
|
|
}
|
|
err = ioutil.WriteFile(name+".key", key, 0755)
|
|
return
|
|
}
|
|
func CreateCa(organization string, expireDays int) (certBytes []byte, keyBytes []byte, err error) {
|
|
priv, err := rsa.GenerateKey(cryptorand.Reader, 2048)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
template := x509.Certificate{
|
|
SerialNumber: big.NewInt(1),
|
|
Subject: pkix.Name{
|
|
CommonName: organization,
|
|
Organization: []string{organization},
|
|
OrganizationalUnit: []string{organization},
|
|
Country: []string{getCountry()},
|
|
},
|
|
NotBefore: time.Now().Add(-time.Hour),
|
|
NotAfter: time.Now().Add(time.Hour * 24 * time.Duration(expireDays)),
|
|
|
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
|
BasicConstraintsValid: true,
|
|
IsCA: true,
|
|
}
|
|
|
|
derBytes, err := x509.CreateCertificate(cryptorand.Reader, &template, &template, &priv.PublicKey, priv)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Generate cert
|
|
certBuffer := bytes.Buffer{}
|
|
if err := pem.Encode(&certBuffer, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Generate key
|
|
keyBuffer := bytes.Buffer{}
|
|
if err := pem.Encode(&keyBuffer, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return certBuffer.Bytes(), keyBuffer.Bytes(), nil
|
|
}
|
|
func ParseCertAndKeyBytes(certPemFileByes, keyFileBytes []byte) (cert *x509.Certificate, privateKey *rsa.PrivateKey, err error) {
|
|
//解析根证书
|
|
cert, err = ParseCertBytes(certPemFileByes)
|
|
if err != nil {
|
|
return
|
|
}
|
|
//解析私钥
|
|
privateKey, err = ParseKeyBytes(keyFileBytes)
|
|
return
|
|
}
|
|
func ParseCertAndKey(certPemFile, keyFile string) (cert *x509.Certificate, privateKey *rsa.PrivateKey, err error) {
|
|
//解析根证书
|
|
cert, err = ParseCert(certPemFile)
|
|
if err != nil {
|
|
return
|
|
}
|
|
//解析私钥
|
|
privateKey, err = ParseKey(keyFile)
|
|
return
|
|
}
|
|
func ParseCert(certPemFile string) (cert *x509.Certificate, err error) {
|
|
//解析证书
|
|
certFile_, err := ioutil.ReadFile(certPemFile)
|
|
if err != nil {
|
|
return
|
|
}
|
|
cert, err = ParseCertBytes(certFile_)
|
|
return
|
|
}
|
|
func ParseKey(keyFile string) (key *rsa.PrivateKey, err error) {
|
|
//解析证书
|
|
keyFile_, err := ioutil.ReadFile(keyFile)
|
|
if err != nil {
|
|
return
|
|
}
|
|
key, err = ParseKeyBytes(keyFile_)
|
|
return
|
|
}
|
|
func ParseCertBytes(certPemFileBytes []byte) (cert *x509.Certificate, err error) {
|
|
caBlock, _ := pem.Decode(certPemFileBytes)
|
|
cert, err = x509.ParseCertificate(caBlock.Bytes)
|
|
return
|
|
}
|
|
func ParseKeyBytes(keyFileBytes []byte) (praKey *rsa.PrivateKey, err error) {
|
|
keyBlock, _ := pem.Decode(keyFileBytes)
|
|
praKey, err = x509.ParsePKCS1PrivateKey(keyBlock.Bytes)
|
|
return
|
|
}
|
|
func getCountry() string {
|
|
CList := []string{"AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BR", "BS", "BW", "BY", "BZ", "CA", "CF", "CG", "CH", "CK", "CL", "CM", "CN", "CO", "CR", "CS", "CU", "CY", "CZ", "DE", "DJ", "DK", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FR", "GA", "GB", "GD", "GE", "GF", "GH", "GI", "GM", "GN", "GR", "GT", "GU", "GY", "HK", "HN", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IR", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KP", "KR", "KT", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "MG", "ML", "MM", "MN", "MO", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PR", "PT", "PY", "QA", "RO", "RU", "SA", "SB", "SC", "SD", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SO", "SR", "ST", "SV", "SY", "SZ", "TD", "TG", "TH", "TJ", "TM", "TN", "TO", "TR", "TT", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "YE", "YU", "ZA", "ZM", "ZR", "ZW"}
|
|
return CList[int(randInt(4))%len(CList)]
|
|
}
|
|
func randInt(strLen int) int64 {
|
|
codes := "123456789"
|
|
codeLen := len(codes)
|
|
data := make([]byte, strLen)
|
|
rand.Seed(time.Now().UnixNano() + rand.Int63() + rand.Int63() + rand.Int63() + rand.Int63())
|
|
for i := 0; i < strLen; i++ {
|
|
idx := rand.Intn(codeLen)
|
|
data[i] = byte(codes[idx])
|
|
}
|
|
i, _ := strconv.ParseInt(string(data), 10, 64)
|
|
return i
|
|
}
|