mirror of
https://github.com/yusing/godoxy.git
synced 2025-05-21 04:52:35 +02:00
139 lines
3.4 KiB
Go
139 lines
3.4 KiB
Go
package agent
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/base64"
|
|
"encoding/pem"
|
|
"errors"
|
|
"math/big"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
CertsDNSName = "godoxy.agent"
|
|
KeySize = 2048
|
|
)
|
|
|
|
func toPEMPair(certDER []byte, key *rsa.PrivateKey) *PEMPair {
|
|
return &PEMPair{
|
|
Cert: pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}),
|
|
Key: pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}),
|
|
}
|
|
}
|
|
|
|
func b64Encode(data []byte) string {
|
|
return base64.StdEncoding.EncodeToString(data)
|
|
}
|
|
|
|
func b64Decode(data string) ([]byte, error) {
|
|
return base64.StdEncoding.DecodeString(data)
|
|
}
|
|
|
|
type PEMPair struct {
|
|
Cert, Key []byte
|
|
}
|
|
|
|
func (p *PEMPair) String() string {
|
|
return b64Encode(p.Cert) + ";" + b64Encode(p.Key)
|
|
}
|
|
|
|
func (p *PEMPair) Load(data string) (err error) {
|
|
parts := strings.Split(data, ";")
|
|
if len(parts) != 2 {
|
|
return errors.New("invalid PEM pair")
|
|
}
|
|
p.Cert, err = b64Decode(parts[0])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
p.Key, err = b64Decode(parts[1])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *PEMPair) ToTLSCert() (*tls.Certificate, error) {
|
|
cert, err := tls.X509KeyPair(p.Cert, p.Key)
|
|
return &cert, err
|
|
}
|
|
|
|
func NewAgent() (ca, srv, client *PEMPair, err error) {
|
|
// Create the CA's certificate
|
|
caTemplate := &x509.Certificate{
|
|
SerialNumber: big.NewInt(1),
|
|
Subject: pkix.Name{
|
|
Organization: []string{"GoDoxy"},
|
|
CommonName: CertsDNSName,
|
|
},
|
|
NotBefore: time.Now(),
|
|
NotAfter: time.Now().AddDate(1000, 0, 0), // 1000 years
|
|
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
|
|
BasicConstraintsValid: true,
|
|
IsCA: true,
|
|
}
|
|
|
|
caKey, err := rsa.GenerateKey(rand.Reader, KeySize)
|
|
if err != nil {
|
|
return nil, nil, nil, err
|
|
}
|
|
|
|
caDER, err := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, &caKey.PublicKey, caKey)
|
|
if err != nil {
|
|
return nil, nil, nil, err
|
|
}
|
|
|
|
ca = toPEMPair(caDER, caKey)
|
|
|
|
// Generate a new private key for the server certificate
|
|
serverKey, err := rsa.GenerateKey(rand.Reader, KeySize)
|
|
if err != nil {
|
|
return nil, nil, nil, err
|
|
}
|
|
|
|
srvTemplate := &x509.Certificate{
|
|
SerialNumber: big.NewInt(2),
|
|
Issuer: caTemplate.Subject,
|
|
Subject: caTemplate.Subject,
|
|
DNSNames: []string{CertsDNSName},
|
|
NotBefore: time.Now(),
|
|
NotAfter: time.Now().AddDate(1000, 0, 0), // Add validity period
|
|
KeyUsage: x509.KeyUsageDigitalSignature,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
|
}
|
|
|
|
srvCertDER, err := x509.CreateCertificate(rand.Reader, srvTemplate, caTemplate, &serverKey.PublicKey, caKey)
|
|
if err != nil {
|
|
return nil, nil, nil, err
|
|
}
|
|
|
|
srv = toPEMPair(srvCertDER, serverKey)
|
|
|
|
clientKey, err := rsa.GenerateKey(rand.Reader, KeySize)
|
|
if err != nil {
|
|
return nil, nil, nil, err
|
|
}
|
|
|
|
clientTemplate := &x509.Certificate{
|
|
SerialNumber: big.NewInt(3),
|
|
Issuer: caTemplate.Subject,
|
|
Subject: caTemplate.Subject,
|
|
DNSNames: []string{CertsDNSName},
|
|
NotBefore: time.Now(),
|
|
NotAfter: time.Now().AddDate(1000, 0, 0),
|
|
KeyUsage: x509.KeyUsageDigitalSignature,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
|
}
|
|
clientCertDER, err := x509.CreateCertificate(rand.Reader, clientTemplate, caTemplate, &clientKey.PublicKey, caKey)
|
|
if err != nil {
|
|
return nil, nil, nil, err
|
|
}
|
|
|
|
client = toPEMPair(clientCertDER, clientKey)
|
|
return
|
|
}
|