Compare commits

...

6 Commits

Author SHA1 Message Date
b1a2039c7d Update CHANGELOG for v1.15.6. 2025-11-19 09:46:09 -08:00
46c9976e73 certlib: Add file kind functionality. 2025-11-19 09:45:57 -08:00
5a5dd5e6ea Update CHANGELOG for v1.15.5. 2025-11-19 08:45:08 -08:00
3317b8c33b certlib/bundler: add support for pemcrt. 2025-11-19 08:43:46 -08:00
fb1b1ffcad Update CHANGELOG for v1.15.4. 2025-11-19 02:57:40 -08:00
7bb6973341 QoL for CSR generation. 2025-11-19 02:57:26 -08:00
7 changed files with 141 additions and 13 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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")
}

View File

@@ -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

View File

@@ -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