toolkit/certificates/utils.go (65 lines of code) (raw):
package certificates
import (
"bytes"
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math/big"
"time"
"github.com/Azure/webhook-tls-manager/toolkit/log"
)
// IsPEMCertificateExpired check if a pem certificate expired
func IsPEMCertificateExpired(ctx context.Context, encodedCert, certName string, expirationTime time.Time) (bool, error) {
logger := log.MustGetLogger(ctx)
if encodedCert == "" {
logger.Errorf(ctx, "cert is empty")
return false, fmt.Errorf("empty cert of %s", certName)
}
block, leftover := pem.Decode([]byte(encodedCert))
if len(leftover) > 0 {
logger.Warningf(ctx, "leftover string in cert of %s", certName)
}
if block == nil || len(block.Bytes) < 1 {
return false, fmt.Errorf("failed to pem decode cert of %s", certName)
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return false, fmt.Errorf("failed to parse cert of %s, error: %s", certName, err)
}
logger.Infof(ctx, "cert.NotAfter: %s", cert.NotAfter.String())
if cert.NotAfter.Before(expirationTime) {
return true, nil
}
return false, nil
}
func GetPEMCertificateString(expirationTime time.Time) (string, error) {
priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
if err != nil {
return "", err
}
template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
Organization: []string{"Acme Co"},
},
NotBefore: expirationTime.Add(-time.Hour * 24 * 30),
NotAfter: expirationTime,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
if err != nil {
return "", err
}
out := &bytes.Buffer{}
err = pem.Encode(out, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
if err != nil {
return "", err
}
return out.String(), nil
}