certlib and other updates

This commit is contained in:
2025-11-21 16:56:39 -08:00
parent d6efbd22fd
commit 91f954391e
5 changed files with 66 additions and 7 deletions

View File

@@ -19,13 +19,21 @@ type KeySpec struct {
Size int `yaml:"size"` Size int `yaml:"size"`
} }
func (ks KeySpec) String() string {
if strings.ToLower(ks.Algorithm) == nameEd25519 {
return nameEd25519
}
return fmt.Sprintf("%s-%d", ks.Algorithm, ks.Size)
}
func (ks KeySpec) Generate() (crypto.PublicKey, crypto.PrivateKey, error) { func (ks KeySpec) Generate() (crypto.PublicKey, crypto.PrivateKey, error) {
switch strings.ToLower(ks.Algorithm) { switch strings.ToLower(ks.Algorithm) {
case "rsa": case "rsa":
return GenerateKey(x509.RSA, ks.Size) return GenerateKey(x509.RSA, ks.Size)
case "ecdsa": case "ecdsa":
return GenerateKey(x509.ECDSA, ks.Size) return GenerateKey(x509.ECDSA, ks.Size)
case "ed25519": case nameEd25519:
return GenerateKey(x509.Ed25519, 0) return GenerateKey(x509.Ed25519, 0)
default: default:
return nil, nil, fmt.Errorf("unknown key algorithm: %s", ks.Algorithm) return nil, nil, fmt.Errorf("unknown key algorithm: %s", ks.Algorithm)
@@ -38,7 +46,7 @@ func (ks KeySpec) SigningAlgorithm() (x509.SignatureAlgorithm, error) {
return x509.SHA512WithRSAPSS, nil return x509.SHA512WithRSAPSS, nil
case "ecdsa": case "ecdsa":
return x509.ECDSAWithSHA512, nil return x509.ECDSAWithSHA512, nil
case "ed25519": case nameEd25519:
return x509.PureEd25519, nil return x509.PureEd25519, nil
default: default:
return 0, fmt.Errorf("unknown key algorithm: %s", ks.Algorithm) return 0, fmt.Errorf("unknown key algorithm: %s", ks.Algorithm)
@@ -88,6 +96,10 @@ func (cs CertificateRequest) Request(priv crypto.PrivateKey) (*x509.CertificateR
IPAddresses: ipAddresses, IPAddresses: ipAddresses,
} }
if cs.Subject.Email != "" {
req.EmailAddresses = []string{cs.Subject.Email}
}
reqBytes, err := x509.CreateCertificateRequest(rand.Reader, req, priv) reqBytes, err := x509.CreateCertificateRequest(rand.Reader, req, priv)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create certificate request: %w", err) return nil, fmt.Errorf("failed to create certificate request: %w", err)

View File

@@ -16,6 +16,10 @@ import (
// oidEd25519 = asn1.ObjectIdentifier{1, 3, 101, 110} // oidEd25519 = asn1.ObjectIdentifier{1, 3, 101, 110}
//) //)
const (
nameEd25519 = "ed25519"
)
func GenerateKey(algorithm x509.PublicKeyAlgorithm, bitSize int) (crypto.PublicKey, crypto.PrivateKey, error) { func GenerateKey(algorithm x509.PublicKeyAlgorithm, bitSize int) (crypto.PublicKey, crypto.PrivateKey, error) {
var key crypto.PrivateKey var key crypto.PrivateKey
var pub crypto.PublicKey var pub crypto.PublicKey

View File

@@ -6,6 +6,7 @@ import (
"crypto/ed25519" "crypto/ed25519"
"crypto/rsa" "crypto/rsa"
"crypto/sha1" // #nosec G505 this is the standard "crypto/sha1" // #nosec G505 this is the standard
"crypto/tls"
"crypto/x509" "crypto/x509"
"crypto/x509/pkix" "crypto/x509/pkix"
"encoding/asn1" "encoding/asn1"
@@ -15,7 +16,9 @@ import (
"git.wntrmute.dev/kyle/goutils/certlib" "git.wntrmute.dev/kyle/goutils/certlib"
"git.wntrmute.dev/kyle/goutils/die" "git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/goutils/fileutil"
"git.wntrmute.dev/kyle/goutils/lib" "git.wntrmute.dev/kyle/goutils/lib"
"git.wntrmute.dev/kyle/goutils/lib/fetch"
) )
const ( const (
@@ -53,6 +56,30 @@ func (k *KeyInfo) SKI(displayMode lib.HexEncodeMode) (string, error) {
return pubHashString, nil return pubHashString, nil
} }
func Lookup(path string, tcfg *tls.Config) (*KeyInfo, error) {
if fileutil.FileDoesExist(path) {
return ParsePEM(path)
}
server, err := fetch.ParseServer(path, tcfg)
if err != nil {
return nil, err
}
cert, err := server.Get()
if err != nil {
return nil, err
}
material := &KeyInfo{
FileType: "certificate",
}
material.PublicKey, material.KeyType = parseCertificate(cert)
return material, nil
}
// ParsePEM parses a PEM file and returns the public key and its type. // ParsePEM parses a PEM file and returns the public key and its type.
func ParsePEM(path string) (*KeyInfo, error) { func ParsePEM(path string) (*KeyInfo, error) {
material := &KeyInfo{} material := &KeyInfo{}
@@ -79,7 +106,7 @@ func ParsePEM(path string) (*KeyInfo, error) {
material.PublicKey, material.KeyType = parseKey(data) material.PublicKey, material.KeyType = parseKey(data)
material.FileType = "private key" material.FileType = "private key"
case "CERTIFICATE": case "CERTIFICATE":
material.PublicKey, material.KeyType = parseCertificate(data) material.PublicKey, material.KeyType = parseCertificateFile(data)
material.FileType = "certificate" material.FileType = "certificate"
case "CERTIFICATE REQUEST": case "CERTIFICATE REQUEST":
material.PublicKey, material.KeyType = parseCSR(data) material.PublicKey, material.KeyType = parseCSR(data)
@@ -113,12 +140,17 @@ func parseKey(data []byte) ([]byte, string) {
return public, kt return public, kt
} }
func parseCertificate(data []byte) ([]byte, string) { func parseCertificateFile(data []byte) ([]byte, string) {
cert, err := x509.ParseCertificate(data) cert, err := x509.ParseCertificate(data)
die.If(err) die.If(err)
return parseCertificate(cert)
}
func parseCertificate(cert *x509.Certificate) ([]byte, string) {
pub := cert.PublicKey pub := cert.PublicKey
var kt string var kt string
switch pub.(type) { switch pub.(type) {
case *rsa.PublicKey: case *rsa.PublicKey:
kt = keyTypeRSA kt = keyTypeRSA

View File

@@ -2,6 +2,7 @@ package main
import ( import (
"archive/zip" "archive/zip"
"errors"
"flag" "flag"
"fmt" "fmt"
"io" "io"
@@ -10,6 +11,8 @@ import (
"strings" "strings"
) )
var unrestrictedDecompression bool
var keepArchive bool var keepArchive bool
func removedir(dir string, existed bool) { func removedir(dir string, existed bool) {
@@ -62,14 +65,21 @@ func unpackFile(path string) error {
return err return err
} }
out, err := os.Create(filepath.Join(dir, f.FileHeader.Name)) if f.UncompressedSize64 > (f.CompressedSize64*32) && !unrestrictedDecompression {
rc.Close()
removedir(dir, existed)
return errors.New("file is too large to decompress (maybe a zip bomb)")
}
var out *os.File
out, err = os.Create(filepath.Join(dir, f.FileHeader.Name))
if err != nil { if err != nil {
rc.Close() rc.Close()
removedir(dir, existed) removedir(dir, existed)
return err return err
} }
_, err = io.Copy(out, rc) _, err = io.Copy(out, rc) // #nosec G110: handled with size check above
if err != nil { if err != nil {
rc.Close() rc.Close()
removedir(dir, existed) removedir(dir, existed)
@@ -88,6 +98,7 @@ func unpackFile(path string) error {
func main() { func main() {
flag.BoolVar(&keepArchive, "k", false, "don't remove the archive file after unpacking") flag.BoolVar(&keepArchive, "k", false, "don't remove the archive file after unpacking")
flag.BoolVar(&unrestrictedDecompression, "u", false, "allow unrestricted decompression")
flag.Parse() flag.Parse()
for _, path := range flag.Args() { for _, path := range flag.Args() {

View File

@@ -111,7 +111,7 @@ func buildExtraForPath(st unix.Stat_t, path string, setUID, setGID int) []byte {
ctns = clampToInt32(ft.Changed.Nanosecond()) ctns = clampToInt32(ft.Changed.Nanosecond())
} }
return buildKGExtra(uid, gid, mode, cts, ctns) return buildKGExtra(uid, gid, uint32(mode), cts, ctns)
} }
// parseKGExtra scans a gzip Extra blob and returns kgz metadata if present. // parseKGExtra scans a gzip Extra blob and returns kgz metadata if present.