Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
go.osspkg.com/ioutils v0.7.3
go.osspkg.com/random v0.5.0
go.osspkg.com/syncing v0.4.3
golang.org/x/crypto v0.43.0
golang.org/x/crypto v0.46.0
)

require golang.org/x/sys v0.37.0 // indirect
require golang.org/x/sys v0.39.0 // indirect
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ go.osspkg.com/random v0.5.0 h1:6x2CQ5Vb6PVyuGi6Ao3K6Pr2fzVviBPCEEJC5HQNSmg=
go.osspkg.com/random v0.5.0/go.mod h1:lsg3FI87PQdjhVWIVo2GXyPBclipljUxjMlWqRl2cck=
go.osspkg.com/syncing v0.4.3 h1:XioXG9zje1LNCsfQhNHkNPCQqPSJZHWTzM8Xig2zvAU=
go.osspkg.com/syncing v0.4.3/go.mod h1:/LBmgCAHFW6nQgVDILpEuo6eRCFK1yyFeNbDs4eVNls=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
14 changes: 7 additions & 7 deletions pki/alg_ecdsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,17 @@ func (*_ecdsa) IsValidPair(key crypto.Signer, cert x509.Certificate) bool {
return reflect.DeepEqual(pk, ck)
}

func (*_ecdsa) Generate(ct CertType) (crypto.Signer, error) {
func (*_ecdsa) Generate(alg x509.SignatureAlgorithm) (crypto.Signer, error) {
var curve elliptic.Curve
switch ct {
case RootCaCert:
switch alg {
case x509.ECDSAWithSHA256:
curve = elliptic.P256()
case InterCACert:
case x509.ECDSAWithSHA384:
curve = elliptic.P384()
case ClientCert:
curve = elliptic.P256()
case x509.ECDSAWithSHA512:
curve = elliptic.P521()
default:
return nil, fmt.Errorf("unknown certificate curve for '%s'", ct)
return nil, fmt.Errorf("unknown certificate curve for '%s'", alg.String())
}

return ecdsa.GenerateKey(curve, rand.Reader)
Expand Down
13 changes: 6 additions & 7 deletions pki/alg_rsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,16 @@ func (*_rsa) IsValidPair(key crypto.Signer, cert x509.Certificate) bool {
return reflect.DeepEqual(pk, ck)
}

func (*_rsa) Generate(ct CertType) (crypto.Signer, error) {
func (*_rsa) Generate(alg x509.SignatureAlgorithm) (crypto.Signer, error) {
var bits int
switch ct {
case RootCaCert:
switch alg {
case x509.SHA512WithRSA, x509.SHA384WithRSA,
x509.SHA512WithRSAPSS, x509.SHA384WithRSAPSS:
bits = 4096
case InterCACert:
case x509.SHA256WithRSA:
bits = 3072
case ClientCert:
bits = 2048
default:
return nil, fmt.Errorf("unknown certificate bits for '%s'", ct)
return nil, fmt.Errorf("unknown certificate bits for '%s'", alg.String())
}

return rsa.GenerateKey(rand.Reader, bits)
Expand Down
13 changes: 4 additions & 9 deletions pki/alg_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ func Register(k x509.SignatureAlgorithm, v Algorithm) {

func init() {
Register(x509.SHA256WithRSA, &_rsa{})
Register(x509.SHA256WithRSAPSS, &_rsa{})
Register(x509.SHA384WithRSA, &_rsa{})
Register(x509.SHA384WithRSAPSS, &_rsa{})
Register(x509.SHA512WithRSA, &_rsa{})
Register(x509.SHA512WithRSAPSS, &_rsa{})
Register(x509.ECDSAWithSHA256, &_ecdsa{})
Register(x509.ECDSAWithSHA384, &_ecdsa{})
Register(x509.ECDSAWithSHA512, &_ecdsa{})
Expand All @@ -37,13 +40,5 @@ type Algorithm interface {
IsRequest(cert x509.CertificateRequest) bool
IsCertificate(cert x509.Certificate) bool
IsValidPair(key crypto.Signer, cert x509.Certificate) bool
Generate(ct CertType) (crypto.Signer, error)
Generate(alg x509.SignatureAlgorithm) (crypto.Signer, error)
}

type CertType string

const (
RootCaCert CertType = "root_ca_cert"
InterCACert CertType = "intermediate_ca_cert"
ClientCert CertType = "client_cert"
)
28 changes: 27 additions & 1 deletion pki/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,36 @@ import (
_ "crypto/sha1"
_ "crypto/sha256"
_ "crypto/sha512"
"encoding/asn1"

_ "golang.org/x/crypto/blake2b"
_ "golang.org/x/crypto/blake2s"
_ "golang.org/x/crypto/md4"
_ "golang.org/x/crypto/ripemd160"
_ "golang.org/x/crypto/sha3"
)

type policyQualifierInfo struct {
PolicyQualifierID asn1.ObjectIdentifier
Qualifier string `asn1:"ia5"`
}
type policyInformation struct {
PolicyIdentifier asn1.ObjectIdentifier
PolicyQualifiers []policyQualifierInfo `asn1:"optional"`
}

func marshalPolicyCPSUrl(urls ...string) []byte {
info := policyInformation{
PolicyIdentifier: asn1.ObjectIdentifier{2, 23, 140, 1, 2, 1},
PolicyQualifiers: make([]policyQualifierInfo, 0, len(urls)),
}

for _, url := range urls {
info.PolicyQualifiers = append(info.PolicyQualifiers, policyQualifierInfo{
PolicyQualifierID: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 2, 1},
Qualifier: url,
})
}

bytes, _ := asn1.Marshal([]policyInformation{info})
return bytes
}
23 changes: 12 additions & 11 deletions pki/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ type Config struct {
PostalCode string `yaml:"postal_code,omitempty" json:"postal_code,omitempty"`
CommonName string `yaml:"common_name,omitempty" json:"common_name,omitempty"`

EmailAddress []string `yaml:"email_address,omitempty" json:"email_address,omitempty"`
OCSPServerURLs []string `yaml:"ocsp_server_ur_ls,omitempty" json:"ocsp_server_ur_ls,omitempty"`
IssuingCertificateURLs []string `yaml:"issuing_certificate_urls,omitempty" json:"issuing_certificate_urls,omitempty"`
CRLDistributionPointURLs []string `yaml:"crl_distribution_point_ur_ls,omitempty" json:"crl_distribution_point_ur_ls,omitempty"`
Expand Down Expand Up @@ -61,18 +60,20 @@ func (v Config) Subject() pkix.Name {
return result
}

func (v Config) ExtraExtensions() []pkix.Extension {
func (v Config) extraExtensions() []pkix.Extension {
var result []pkix.Extension

if len(v.IssuingCertificateURLs) > 0 {
for _, value := range stringsPrepare(v.CertificatePoliciesURLs) {
result = append(result, pkix.Extension{
Id: asn1.ObjectIdentifier{2, 23, 140, 1, 1},
Critical: true,
Value: []byte(value),
})
}

if len(v.CertificatePoliciesURLs) > 0 {
result = append(result, pkix.Extension{
Id: asn1.ObjectIdentifier{2, 5, 29, 32},
Critical: false,
Value: marshalPolicyCPSUrl(stringsPrepare(v.CertificatePoliciesURLs)...),
})
} else {
result = append(result, pkix.Extension{
Id: asn1.ObjectIdentifier{2, 5, 29, 32, 0},
Critical: false,
})
}

return result
Expand Down
13 changes: 6 additions & 7 deletions pki/encoders.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,12 @@ func MarshalKeyPEM(key crypto.Signer) ([]byte, error) {
}

var prefix string
for name, a := range algorithms.Yield() {
if !a.IsPrivateKey(key) {
continue
}

prefix = name.String()
}
//for name, a := range algorithms.Yield() {
// if !a.IsPrivateKey(key) {
// continue
// }
// prefix = name.String()
//}

return CreatePEMBlock(b, PrivateKeyPEMBlock, prefix), nil
}
Expand Down
31 changes: 18 additions & 13 deletions pki/generate_ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package pki

import (
"crypto/rand"
"crypto/sha256"
"crypto/x509"
"fmt"
"math/big"
Expand All @@ -17,8 +18,9 @@ func NewCA(
conf Config,
deadline time.Duration,
serialNumber int64,
withIntermediate bool,
intermediateCount int,
) (*Certificate, error) {
intermediateCount = max(0, intermediateCount)

currTime := time.Now()
template := &x509.Certificate{
Expand All @@ -29,35 +31,38 @@ func NewCA(
Subject: conf.Subject(),
NotBefore: currTime,
NotAfter: currTime.Add(deadline),
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
OCSPServer: stringsPrepare(conf.OCSPServerURLs),
IssuingCertificateURL: stringsPrepare(conf.IssuingCertificateURLs),
CRLDistributionPoints: stringsPrepare(conf.CRLDistributionPointURLs),
ExtraExtensions: conf.ExtraExtensions(),
EmailAddresses: stringsPrepare(conf.EmailAddress),
MaxPathLenZero: false,
MaxPathLen: 1,
ExtraExtensions: conf.extraExtensions(),
MaxPathLen: intermediateCount,
MaxPathLenZero: intermediateCount <= 0,
}

if withIntermediate {
template.MaxPathLen = 2
}

algName, ok := signatures.Get(conf.SignatureAlgorithm)
algName, ok := signatures.Get(template.SignatureAlgorithm)
if !ok {
return nil, fmt.Errorf("unknown signature algorithm: %s", conf.SignatureAlgorithm.String())
return nil, fmt.Errorf("unknown signature algorithm: %s", template.SignatureAlgorithm.String())
}

alg, ok := algorithms.Get(algName)
if !ok {
return nil, fmt.Errorf("unknown signature algorithm: %s", algName.String())
}

key, err := alg.Generate(RootCaCert)
key, err := alg.Generate(template.SignatureAlgorithm)
if err != nil {
return nil, fmt.Errorf("failed generating private key: %w", err)
}

publicKeyBytes, err := x509.MarshalPKIXPublicKey(key.Public())
if err != nil {
return nil, fmt.Errorf("failed marshaling public key: %w", err)
}
publicKeyHash := sha256.Sum256(publicKeyBytes)
template.SubjectKeyId = publicKeyHash[:20]
template.AuthorityKeyId = publicKeyHash[:20]

b, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key)
if err != nil {
return nil, fmt.Errorf("failed generating certificate: %w", err)
Expand Down
22 changes: 14 additions & 8 deletions pki/generate_ca_inter.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,30 @@ func NewIntermediateCA(
deadline time.Duration,
serialNumber int64,
) (*Certificate, error) {
confSigAlg := conf.SignatureAlgorithm
if confSigAlg == x509.UnknownSignatureAlgorithm {
confSigAlg = rootCA.Crt.SignatureAlgorithm
}

level := rootCA.Crt.MaxPathLen - 1

currTime := time.Now()
template := &x509.Certificate{
IsCA: true,
BasicConstraintsValid: true,
SignatureAlgorithm: rootCA.Crt.SignatureAlgorithm,
SignatureAlgorithm: confSigAlg,
SerialNumber: big.NewInt(serialNumber),
Subject: conf.Subject(),
NotBefore: currTime,
NotAfter: currTime.Add(deadline),
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
OCSPServer: stringsPrepare(conf.OCSPServerURLs),
IssuingCertificateURL: stringsPrepare(conf.IssuingCertificateURLs),
CRLDistributionPoints: stringsPrepare(conf.CRLDistributionPointURLs),
ExtraExtensions: conf.ExtraExtensions(),
EmailAddresses: stringsPrepare(conf.EmailAddress),
MaxPathLenZero: false,
MaxPathLen: 1,
ExtraExtensions: conf.extraExtensions(),
MaxPathLenZero: level <= 0,
MaxPathLen: level,
}

if !rootCA.IsValidPair() {
Expand All @@ -47,7 +53,7 @@ func NewIntermediateCA(
return nil, fmt.Errorf("invalid Root CA certificate: is not CA")
}

if rootCA.Crt.MaxPathLen != 2 {
if template.MaxPathLen < 0 {
return nil, fmt.Errorf("invalid Root CA certificate: not supported Intermediate CA")
}

Expand All @@ -65,7 +71,7 @@ func NewIntermediateCA(
return nil, fmt.Errorf("unknown signature algorithm: %s", algName.String())
}

key, err := alg.Generate(InterCACert)
key, err := alg.Generate(template.SignatureAlgorithm)
if err != nil {
return nil, fmt.Errorf("failed generating private key: %w", err)
}
Expand Down
24 changes: 18 additions & 6 deletions pki/generate_crt.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package pki

import (
"crypto/rand"
"crypto/sha256"
"crypto/x509"
"fmt"
"math/big"
Expand All @@ -28,26 +29,30 @@ func NewCRT(
return nil, fmt.Errorf("invalid Root CA certificate: is not CA")
}

if rootCA.Crt.MaxPathLen != 1 {
if rootCA.Crt.MaxPathLen != 0 {
return nil, fmt.Errorf("invalid Root CA certificate: not supported generate client certificate")
}

confSigAlg := conf.SignatureAlgorithm
if confSigAlg == x509.UnknownSignatureAlgorithm {
confSigAlg = rootCA.Crt.SignatureAlgorithm
}

currTime := time.Now()
template := &x509.Certificate{
IsCA: false,
BasicConstraintsValid: true,
SignatureAlgorithm: rootCA.Crt.SignatureAlgorithm,
SignatureAlgorithm: confSigAlg,
SerialNumber: big.NewInt(serialNumber),
Subject: conf.Subject(),
NotBefore: currTime,
NotAfter: currTime.Add(deadline),
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
OCSPServer: stringsPrepare(conf.OCSPServerURLs),
IssuingCertificateURL: stringsPrepare(conf.IssuingCertificateURLs),
CRLDistributionPoints: stringsPrepare(conf.CRLDistributionPointURLs),
ExtraExtensions: conf.ExtraExtensions(),
EmailAddresses: stringsPrepare(conf.EmailAddress),
ExtraExtensions: conf.extraExtensions(),
}

if template.NotAfter.After(rootCA.Crt.NotAfter) {
Expand Down Expand Up @@ -76,11 +81,18 @@ func NewCRT(
return nil, fmt.Errorf("unknown signature algorithm: %s", algName.String())
}

key, err := alg.Generate(ClientCert)
key, err := alg.Generate(template.SignatureAlgorithm)
if err != nil {
return nil, fmt.Errorf("failed generating private key: %w", err)
}

publicKeyBytes, err := x509.MarshalPKIXPublicKey(key.Public())
if err != nil {
return nil, fmt.Errorf("failed marshaling public key: %w", err)
}
publicKeyHash := sha256.Sum256(publicKeyBytes)
template.SubjectKeyId = publicKeyHash[:20]

b, err := x509.CreateCertificate(rand.Reader, template, rootCA.Crt, key.Public(), rootCA.Key)
if err != nil {
return nil, fmt.Errorf("failed generating certificate: %w", err)
Expand Down
Loading