Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b1a2039c7d | |||
| 46c9976e73 | |||
| 5a5dd5e6ea | |||
| 3317b8c33b | |||
| fb1b1ffcad | |||
| 7bb6973341 |
@@ -1,5 +1,14 @@
|
||||
CHANGELOG
|
||||
|
||||
v1.15.6 - 2025-11-19
|
||||
certlib: add FileKind function to determine file type.
|
||||
|
||||
v1.15.5 - 2025-11-19
|
||||
certlib/bundler: add support for crt files that are pem-encoded.
|
||||
|
||||
v1.15.4 - 2025-11-19
|
||||
Quality of life fixes for CSR generation.
|
||||
|
||||
v1.15.3 - 2025-11-19
|
||||
Minor bug fixes.
|
||||
|
||||
|
||||
@@ -422,6 +422,24 @@ func encodeCertsToFiles(
|
||||
name: baseName + ".pem",
|
||||
content: pemContent,
|
||||
})
|
||||
case "crt":
|
||||
pemContent := encodeCertsToPEM(certs)
|
||||
files = append(files, fileEntry{
|
||||
name: baseName + ".crt",
|
||||
content: pemContent,
|
||||
})
|
||||
case "pemcrt":
|
||||
pemContent := encodeCertsToPEM(certs)
|
||||
files = append(files, fileEntry{
|
||||
name: baseName + ".pem",
|
||||
content: pemContent,
|
||||
})
|
||||
|
||||
pemContent = encodeCertsToPEM(certs)
|
||||
files = append(files, fileEntry{
|
||||
name: baseName + ".crt",
|
||||
content: pemContent,
|
||||
})
|
||||
case "der":
|
||||
if isSingle {
|
||||
// For single file in DER, concatenate all cert DER bytes
|
||||
|
||||
@@ -63,12 +63,7 @@ type CertificateRequest struct {
|
||||
Profile Profile `yaml:"profile"`
|
||||
}
|
||||
|
||||
func (cs CertificateRequest) Generate() (crypto.PrivateKey, *x509.CertificateRequest, error) {
|
||||
pub, priv, err := cs.KeySpec.Generate()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
func (cs CertificateRequest) Request(priv crypto.PrivateKey) (*x509.CertificateRequest, error) {
|
||||
subject := pkix.Name{}
|
||||
subject.CommonName = cs.Subject.CommonName
|
||||
subject.Country = []string{cs.Subject.Country}
|
||||
@@ -81,13 +76,13 @@ func (cs CertificateRequest) Generate() (crypto.PrivateKey, *x509.CertificateReq
|
||||
for i, ip := range cs.Subject.IPAddresses {
|
||||
ipAddresses = append(ipAddresses, net.ParseIP(ip))
|
||||
if ipAddresses[i] == nil {
|
||||
return nil, nil, fmt.Errorf("invalid IP address: %s", ip)
|
||||
return nil, fmt.Errorf("invalid IP address: %s", ip)
|
||||
}
|
||||
}
|
||||
|
||||
req := &x509.CertificateRequest{
|
||||
PublicKeyAlgorithm: 0,
|
||||
PublicKey: pub,
|
||||
PublicKey: getPublic(priv),
|
||||
Subject: subject,
|
||||
DNSNames: cs.Subject.DNSNames,
|
||||
IPAddresses: ipAddresses,
|
||||
@@ -95,12 +90,26 @@ func (cs CertificateRequest) Generate() (crypto.PrivateKey, *x509.CertificateReq
|
||||
|
||||
reqBytes, err := x509.CreateCertificateRequest(rand.Reader, req, priv)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create certificate request: %w", err)
|
||||
return nil, fmt.Errorf("failed to create certificate request: %w", err)
|
||||
}
|
||||
|
||||
req, err = x509.ParseCertificateRequest(reqBytes)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse certificate request: %w", err)
|
||||
return nil, fmt.Errorf("failed to parse certificate request: %w", err)
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (cs CertificateRequest) Generate() (crypto.PrivateKey, *x509.CertificateRequest, error) {
|
||||
_, priv, err := cs.KeySpec.Generate()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
req, err := cs.Request(priv)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return priv, req, nil
|
||||
|
||||
@@ -71,3 +71,16 @@ func GenerateKey(algorithm x509.PublicKeyAlgorithm, bitSize int) (crypto.PublicK
|
||||
|
||||
return pub, key, nil
|
||||
}
|
||||
|
||||
func getPublic(priv crypto.PrivateKey) crypto.PublicKey {
|
||||
switch priv := priv.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return &priv.PublicKey
|
||||
case *ecdsa.PrivateKey:
|
||||
return &priv.PublicKey
|
||||
case *ed25519.PrivateKey:
|
||||
return priv.Public()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"git.wntrmute.dev/kyle/goutils/certlib/certerr"
|
||||
)
|
||||
@@ -131,3 +132,79 @@ func LoadCSR(path string) (*x509.CertificateRequest, error) {
|
||||
req, _, err := ParseCSR(in)
|
||||
return req, err
|
||||
}
|
||||
|
||||
func ExportCSRAsPEM(req *x509.CertificateRequest) []byte {
|
||||
return pem.EncodeToMemory(&pem.Block{Type: pemTypeCertificateRequest, Bytes: req.Raw})
|
||||
}
|
||||
|
||||
type FileFormat uint8
|
||||
|
||||
const (
|
||||
FormatPEM FileFormat = iota + 1
|
||||
FormatDER
|
||||
)
|
||||
|
||||
func (f FileFormat) String() string {
|
||||
switch f {
|
||||
case FormatPEM:
|
||||
return "PEM"
|
||||
case FormatDER:
|
||||
return "DER"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
type FileType struct {
|
||||
Format FileFormat
|
||||
Type string
|
||||
}
|
||||
|
||||
func (ft FileType) String() string {
|
||||
if ft.Type == "" {
|
||||
return ft.Format.String()
|
||||
}
|
||||
return fmt.Sprintf("%s (%s)", ft.Type, ft.Format)
|
||||
}
|
||||
|
||||
// FileKind returns the file type of the given file.
|
||||
func FileKind(path string) (*FileType, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(data)
|
||||
if block != nil {
|
||||
return &FileType{
|
||||
Format: FormatPEM,
|
||||
Type: strings.ToLower(strings.TrimSpace(block.Type)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
_, err = x509.ParseCertificate(data)
|
||||
if err == nil {
|
||||
return &FileType{
|
||||
Format: FormatDER,
|
||||
Type: strings.ToLower(pemTypeCertificate),
|
||||
}, nil
|
||||
}
|
||||
|
||||
_, err = x509.ParseCertificateRequest(data)
|
||||
if err == nil {
|
||||
return &FileType{
|
||||
Format: FormatDER,
|
||||
Type: strings.ToLower(pemTypeCertificateRequest),
|
||||
}, nil
|
||||
}
|
||||
|
||||
_, err = x509.ParsePKCS8PrivateKey(data)
|
||||
if err == nil {
|
||||
return &FileType{
|
||||
Format: FormatDER,
|
||||
Type: strings.ToLower(pemTypePrivateKey),
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("certlib; unknown file type")
|
||||
}
|
||||
|
||||
@@ -76,8 +76,9 @@ var DelegationExtension = pkix.Extension{
|
||||
}
|
||||
|
||||
const (
|
||||
pemTypeCertificate = "CERTIFICATE"
|
||||
pemTypePrivateKey = "PRIVATE KEY"
|
||||
pemTypeCertificate = "CERTIFICATE"
|
||||
pemTypeCertificateRequest = "CERTIFICATE REQUEST"
|
||||
pemTypePrivateKey = "PRIVATE KEY"
|
||||
)
|
||||
|
||||
// InclusiveDate returns the time.Time representation of a date - 1
|
||||
|
||||
3
cmd/cert-bundler/testdata/bundle.yaml
vendored
3
cmd/cert-bundler/testdata/bundle.yaml
vendored
@@ -12,6 +12,7 @@ chains:
|
||||
include_single: true
|
||||
include_individual: true
|
||||
manifest: true
|
||||
encoding: pemcrt
|
||||
formats:
|
||||
- zip
|
||||
- tgz
|
||||
@@ -53,4 +54,4 @@ chains:
|
||||
manifest: false
|
||||
encoding: both
|
||||
formats:
|
||||
- zip
|
||||
- zip
|
||||
|
||||
Reference in New Issue
Block a user