certgen/client.go

73 lines
2.0 KiB
Go
Raw Permalink Normal View History

2022-03-13 02:24:11 +00:00
package certgen
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
2022-03-13 02:24:11 +00:00
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"fmt"
2022-03-13 02:24:11 +00:00
"math/big"
"time"
)
// MakeClientTls generates a client TLS certificate using a CA to sign it
// If ca is nil then the client will sign its own certificate
func MakeClientTls(ca *CertGen, bits int, name pkix.Name, serialNumber *big.Int, future Future) (*CertGen, error) {
// generate rsa private key
clientPrivKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, fmt.Errorf("failed to generate client private key: %w", err)
}
// generate SubjectKeyId from sha1 hash of public key bytes
pubKeyBytes := x509.MarshalPKCS1PublicKey(&clientPrivKey.PublicKey)
pubKeyHash := sha1.Sum(pubKeyBytes)
// base certificate data
now := time.Now()
2022-03-13 02:24:11 +00:00
cert := &x509.Certificate{
2022-03-13 10:22:53 +00:00
SerialNumber: serialNumber,
Subject: name,
NotBefore: now,
NotAfter: future(now),
SubjectKeyId: pubKeyHash[:],
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
2022-03-13 02:24:11 +00:00
KeyUsage: x509.KeyUsageDigitalSignature,
}
// use current certificate as CA if nil
if ca == nil {
ca = &CertGen{cert: cert, key: clientPrivKey}
}
// create certificate bytes
clientBytes, err := x509.CreateCertificate(rand.Reader, cert, ca.cert, clientPrivKey.Public(), ca.key)
2022-03-13 02:24:11 +00:00
if err != nil {
return nil, fmt.Errorf("failed to generate client certificate bytes: %w", err)
2022-03-13 02:24:11 +00:00
}
// add the raw certificate bytes so `*x509.Certificate.Equal(*x509.Certificate)` is valid
cert.Raw = clientBytes
// get private key bytes
2022-03-13 02:24:11 +00:00
privKeyBytes := x509.MarshalPKCS1PrivateKey(clientPrivKey)
gen := &CertGen{cert: cert, certBytes: clientBytes, key: clientPrivKey, keyBytes: privKeyBytes}
// generate pem blocks
2022-03-13 02:24:11 +00:00
err = gen.generatePem()
if err != nil {
return nil, fmt.Errorf("failed to generate PEM encoding: %w", err)
2022-03-13 02:24:11 +00:00
}
// generate key pair
2022-03-13 02:24:11 +00:00
caKeyPair, err := tls.X509KeyPair(gen.certPem, gen.keyPem)
if err != nil {
return nil, fmt.Errorf("failed to generate client key pair: %w", err)
2022-03-13 02:24:11 +00:00
}
2022-03-13 02:24:11 +00:00
gen.tlsCert = caKeyPair
return gen, nil
}