Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kms: export GenerateCertificate function #18

Merged
merged 1 commit into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 1 addition & 48 deletions kms/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,9 @@ import (
"bytes"
"compress/gzip"
"context"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"fmt"
"math/big"
"net"
"net/http"
"net/url"
Expand Down Expand Up @@ -68,7 +63,7 @@ func NewClient(conf *Config) (*Client, error) {

tlsConf := conf.TLS.Clone()
if conf.APIKey != nil {
cert, err := generateCertificate(conf.APIKey)
cert, err := GenerateCertificate(conf.APIKey, nil)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1460,45 +1455,3 @@ func httpsURL(endpoint string) string {
}
return endpoint
}

func generateCertificate(key APIKey) (tls.Certificate, error) {
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return tls.Certificate{}, err
}

template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
CommonName: key.Identity().String(),
},
NotBefore: time.Now().UTC(),
NotAfter: time.Now().UTC().Add(90 * 24 * time.Hour),
KeyUsage: x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{
x509.ExtKeyUsageClientAuth,
},
BasicConstraintsValid: true,
}

certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, key.Public(), key.Private())
if err != nil {
return tls.Certificate{}, err
}
privPKCS8, err := x509.MarshalPKCS8PrivateKey(key.Private())
if err != nil {
return tls.Certificate{}, err
}
cert, err := tls.X509KeyPair(
pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}),
pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privPKCS8}),
)
if err != nil {
return tls.Certificate{}, err
}
if cert.Leaf == nil {
cert.Leaf, _ = x509.ParseCertificate(cert.Certificate[0])
}
return cert, nil
}
55 changes: 55 additions & 0 deletions kms/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,20 @@ package kms
import (
"crypto"
"crypto/ed25519"
"crypto/rand"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/base64"
"encoding/pem"
"errors"
"io"
"math/big"
"strconv"
"strings"
"time"
)

// An Identity uniquely identifies a private/public key pair.
Expand Down Expand Up @@ -178,6 +184,55 @@ func ParseAPIKey(s string) (APIKey, error) {
}, nil
}

// GenerateCertificate generates a new self-signed TLS certificate
// from the given template using the APIKey's private and public key.
//
// The template may be nil. In such a case the returned certificate
// is generated using a default template and valid for 90 days.
func GenerateCertificate(key APIKey, template *x509.Certificate) (tls.Certificate, error) {
if template == nil {
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return tls.Certificate{}, err
}

template = &x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
CommonName: key.Identity().String(),
},
NotBefore: time.Now().UTC(),
NotAfter: time.Now().UTC().Add(90 * 24 * time.Hour),
KeyUsage: x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{
x509.ExtKeyUsageClientAuth,
},
BasicConstraintsValid: true,
}
}

certDER, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key.Private())
if err != nil {
return tls.Certificate{}, err
}
privPKCS8, err := x509.MarshalPKCS8PrivateKey(key.Private())
if err != nil {
return tls.Certificate{}, err
}
cert, err := tls.X509KeyPair(
pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}),
pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privPKCS8}),
)
if err != nil {
return tls.Certificate{}, err
}
if cert.Leaf == nil {
cert.Leaf, _ = x509.ParseCertificate(cert.Certificate[0])
}
return cert, nil
}

// apiKey is an APIKey implementation using Ed25519 public/private keys.
type apiKey struct {
key ed25519.PrivateKey
Expand Down
Loading