cert-manager/test/unit/gen/csr.go
Tim Ramlot e0cdfd37bf
introduce gen.CSRForCertificate and gen.CSRWithSignerForCertificate and use it to deduplicate test code
Signed-off-by: Tim Ramlot <42113979+inteon@users.noreply.github.com>
2024-06-14 15:53:18 +02:00

231 lines
5.7 KiB
Go

/*
Copyright 2020 The cert-manager Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gen
import (
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"net"
"net/url"
v1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
"github.com/cert-manager/cert-manager/pkg/util/pki"
)
type CSRModifier func(*x509.CertificateRequest) error
var defaultGenerateCSROptions = []pki.GenerateCSROption{
pki.WithEncodeBasicConstraintsInRequest(true),
pki.WithNameConstraints(true),
pki.WithOtherNames(true),
pki.WithUseLiteralSubject(true),
}
func CSRForCertificate(crt *v1.Certificate, mods ...CSRModifier) (csr []byte, sk crypto.Signer, err error) {
cr, err := pki.GenerateCSR(crt, defaultGenerateCSROptions...)
if err != nil {
return nil, nil, err
}
modifiers := []CSRModifier{}
modifiers = append(modifiers, func(c *x509.CertificateRequest) error {
*c = *cr
return nil
})
modifiers = append(modifiers, mods...)
return CSR(cr.PublicKeyAlgorithm, modifiers...)
}
func CSRWithSignerForCertificate(crt *v1.Certificate, sk crypto.Signer, mods ...CSRModifier) (csr []byte, err error) {
cr, err := pki.GenerateCSR(crt, defaultGenerateCSROptions...)
if err != nil {
return nil, err
}
modifiers := []CSRModifier{}
modifiers = append(modifiers, func(c *x509.CertificateRequest) error {
if c.PublicKeyAlgorithm != cr.PublicKeyAlgorithm {
return fmt.Errorf("public key algorithm mismatch: %s != %s", c.PublicKeyAlgorithm, cr.PublicKeyAlgorithm)
}
if c.SignatureAlgorithm != cr.SignatureAlgorithm {
return fmt.Errorf("signature algorithm mismatch: %s != %s", c.SignatureAlgorithm, cr.SignatureAlgorithm)
}
*c = *cr
return nil
})
modifiers = append(modifiers, mods...)
return CSRWithSigner(sk, modifiers...)
}
func CSR(keyAlgorithm x509.PublicKeyAlgorithm, mods ...CSRModifier) (csr []byte, sk crypto.Signer, err error) {
switch keyAlgorithm {
case x509.RSA:
sk, err = pki.GenerateRSAPrivateKey(pki.MinRSAKeySize)
if err != nil {
return nil, nil, err
}
case x509.ECDSA:
sk, err = pki.GenerateECPrivateKey(pki.ECCurve256)
if err != nil {
return nil, nil, err
}
case x509.Ed25519:
sk, err = pki.GenerateEd25519PrivateKey()
if err != nil {
return nil, nil, err
}
default:
return nil, nil, fmt.Errorf("unrecognised key algorithm: %s", keyAlgorithm)
}
csr, err = CSRWithSigner(sk, mods...)
return
}
func CSRWithSigner(sk crypto.Signer, mods ...CSRModifier) (csr []byte, err error) {
var keyAlgorithm x509.PublicKeyAlgorithm
var signatureAlgorithm x509.SignatureAlgorithm
switch pub := sk.Public().(type) {
case *rsa.PublicKey:
keyAlgorithm = x509.RSA
keySize := pub.N.BitLen()
switch {
case keySize >= 4096:
signatureAlgorithm = x509.SHA512WithRSA
case keySize >= 3072:
signatureAlgorithm = x509.SHA384WithRSA
case keySize >= 2048:
signatureAlgorithm = x509.SHA256WithRSA
default:
signatureAlgorithm = x509.SHA1WithRSA
}
case *ecdsa.PublicKey:
keyAlgorithm = x509.ECDSA
switch pub.Curve {
case elliptic.P256():
signatureAlgorithm = x509.ECDSAWithSHA256
case elliptic.P384():
signatureAlgorithm = x509.ECDSAWithSHA384
case elliptic.P521():
signatureAlgorithm = x509.ECDSAWithSHA512
default:
signatureAlgorithm = x509.ECDSAWithSHA1
}
case ed25519.PublicKey:
keyAlgorithm = x509.Ed25519
signatureAlgorithm = x509.PureEd25519
default:
return nil, fmt.Errorf("unrecognised public key type: %T", sk)
}
cr := &x509.CertificateRequest{
Version: 0,
SignatureAlgorithm: signatureAlgorithm,
PublicKeyAlgorithm: keyAlgorithm,
PublicKey: sk.Public(),
}
for _, mod := range mods {
err = mod(cr)
if err != nil {
return
}
}
csrBytes, err := pki.EncodeCSR(cr, sk)
if err != nil {
return nil, err
}
csr = pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE REQUEST", Bytes: csrBytes,
})
return
}
func SetCSRDNSNames(dnsNames ...string) CSRModifier {
return func(c *x509.CertificateRequest) error {
c.DNSNames = dnsNames
return nil
}
}
func SetCSRIPAddresses(ips ...net.IP) CSRModifier {
return func(c *x509.CertificateRequest) error {
c.IPAddresses = ips
return nil
}
}
func SetCSRIPAddressesFromStrings(ips ...string) CSRModifier {
return func(c *x509.CertificateRequest) error {
var certIPs []net.IP
for _, ip := range ips {
if certIP := net.ParseIP(ip); certIP == nil {
return fmt.Errorf("invalid ip: %s", ip)
} else {
certIPs = append(certIPs, certIP)
}
}
c.IPAddresses = certIPs
return nil
}
}
func SetCSRURIs(uris ...*url.URL) CSRModifier {
return func(c *x509.CertificateRequest) error {
c.URIs = uris
return nil
}
}
func SetCSRURIsFromStrings(uris ...string) CSRModifier {
return func(c *x509.CertificateRequest) error {
var certUris []*url.URL
for _, uri := range uris {
parsed, err := url.Parse(uri)
if err != nil {
return err
}
certUris = append(certUris, parsed)
}
c.URIs = certUris
return nil
}
}
func SetCSRCommonName(commonName string) CSRModifier {
return func(c *x509.CertificateRequest) error {
c.Subject.CommonName = commonName
return nil
}
}
func SetCSREmails(emails []string) CSRModifier {
return func(c *x509.CertificateRequest) error {
c.EmailAddresses = emails
return nil
}
}