Skip to content

Commit 858633f

Browse files
committed
Allow generating ML-DSA roots and intermediates
1 parent 8293bbf commit 858633f

4 files changed

Lines changed: 27 additions & 21 deletions

File tree

ca/ca.go

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ import (
77
"crypto/elliptic"
88
"crypto/rand"
99
"crypto/rsa"
10-
"crypto/sha1"
11-
"crypto/x509"
10+
"crypto/sha256"
1211
"crypto/x509/pkix"
1312
"encoding/asn1"
1413
"encoding/hex"
@@ -21,7 +20,10 @@ import (
2120
"strings"
2221
"time"
2322

23+
"github.com/cloudflare/circl/sign/mldsa/mldsa65"
24+
2425
"github.com/letsencrypt/pebble/v2/acme"
26+
"github.com/letsencrypt/pebble/v2/ca/x509pq"
2527
"github.com/letsencrypt/pebble/v2/core"
2628
"github.com/letsencrypt/pebble/v2/db"
2729
)
@@ -79,7 +81,7 @@ func makeSerial() *big.Int {
7981
// Taken from https://github.com/cloudflare/cfssl/blob/b94e044bb51ec8f5a7232c71b1ed05dbe4da96ce/signer/signer.go#L221-L244
8082
func makeSubjectKeyID(key crypto.PublicKey) ([]byte, error) {
8183
// Marshal the public key as ASN.1
82-
pubAsDER, err := x509.MarshalPKIXPublicKey(key)
84+
pubAsDER, err := x509pq.MarshalPKIXPublicKey(key)
8385
if err != nil {
8486
return nil, err
8587
}
@@ -94,9 +96,9 @@ func makeSubjectKeyID(key crypto.PublicKey) ([]byte, error) {
9496
return nil, err
9597
}
9698

97-
// Hash it according to https://tools.ietf.org/html/rfc5280#section-4.2.1.2 Method #1:
98-
ski := sha1.Sum(pubInfo.SubjectPublicKey.Bytes)
99-
return ski[:], nil
99+
// Hash it according to https://datatracker.ietf.org/doc/html/rfc7093#section-2 Method #1:
100+
skid := sha256.Sum256(pubInfo.SubjectPublicKey.Bytes)
101+
return skid[0:20:20], nil
100102
}
101103

102104
// makeKey and makeRootCert are adapted from MiniCA:
@@ -112,6 +114,8 @@ func makeKey(keyAlg string) (crypto.Signer, []byte, error) {
112114
key, err = rsa.GenerateKey(rand.Reader, 2048)
113115
case "ecdsa":
114116
key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
117+
case "mldsa":
118+
_, key, err = mldsa65.GenerateKey(rand.Reader)
115119
}
116120
if err != nil {
117121
return nil, nil, err
@@ -130,21 +134,21 @@ func (ca *CAImpl) makeCACert(
130134
signer *issuer,
131135
) (*core.Certificate, error) {
132136
serial := makeSerial()
133-
template := &x509.Certificate{
137+
template := &x509pq.Certificate{
134138
Subject: subject,
135139
SerialNumber: serial,
136140
NotBefore: time.Now(),
137141
NotAfter: time.Now().AddDate(30, 0, 0),
138142

139-
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
140-
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
143+
KeyUsage: x509pq.KeyUsageDigitalSignature | x509pq.KeyUsageCertSign,
144+
ExtKeyUsage: []x509pq.ExtKeyUsage{x509pq.ExtKeyUsageServerAuth},
141145
SubjectKeyId: subjectKeyID,
142146
BasicConstraintsValid: true,
143147
IsCA: true,
144148
}
145149

146150
var signerKey crypto.Signer
147-
var parent *x509.Certificate
151+
var parent *x509pq.Certificate
148152
if signer != nil && signer.key != nil && signer.cert != nil && signer.cert.Cert != nil {
149153
signerKey = signer.key
150154
parent = signer.cert.Cert
@@ -153,12 +157,12 @@ func (ca *CAImpl) makeCACert(
153157
parent = template
154158
}
155159

156-
der, err := x509.CreateCertificate(rand.Reader, template, parent, subjectKey.Public(), signerKey)
160+
der, err := x509pq.CreateCertificate(rand.Reader, template, parent, subjectKey.Public(), signerKey)
157161
if err != nil {
158162
return nil, err
159163
}
160164

161-
cert, err := x509.ParseCertificate(der)
165+
cert, err := x509pq.ParseCertificate(der)
162166
if err != nil {
163167
return nil, err
164168
}
@@ -306,15 +310,15 @@ func (ca *CAImpl) newCertificate(domains []string, ips []net.IP, key crypto.Publ
306310
}
307311

308312
serial := makeSerial()
309-
template := &x509.Certificate{
313+
template := &x509pq.Certificate{
310314
DNSNames: domains,
311315
IPAddresses: ips,
312316
SerialNumber: serial,
313317
NotBefore: certNotBefore,
314318
NotAfter: certNotAfter,
315319

316-
KeyUsage: x509.KeyUsageDigitalSignature,
317-
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
320+
KeyUsage: x509pq.KeyUsageDigitalSignature,
321+
ExtKeyUsage: []x509pq.ExtKeyUsage{x509pq.ExtKeyUsageServerAuth},
318322
ExtraExtensions: extensions,
319323
BasicConstraintsValid: true,
320324
IsCA: false,
@@ -340,11 +344,11 @@ func (ca *CAImpl) newCertificate(domains []string, ips []net.IP, key crypto.Publ
340344
template.OCSPServer = []string{ca.ocspResponderURL}
341345
}
342346

343-
der, err := x509.CreateCertificate(rand.Reader, template, issuer.cert.Cert, key, issuer.key)
347+
der, err := x509pq.CreateCertificate(rand.Reader, template, issuer.cert.Cert, key, issuer.key)
344348
if err != nil {
345349
return nil, err
346350
}
347-
cert, err := x509.ParseCertificate(der)
351+
cert, err := x509pq.ParseCertificate(der)
348352
if err != nil {
349353
return nil, err
350354
}

ca/ca_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"time"
1616

1717
"github.com/letsencrypt/pebble/v2/acme"
18+
x509pq "github.com/letsencrypt/pebble/v2/ca/x509pq"
1819
"github.com/letsencrypt/pebble/v2/core"
1920
"github.com/letsencrypt/pebble/v2/db"
2021
)
@@ -27,7 +28,7 @@ var (
2728
func makeCa() *CAImpl {
2829
logger := log.New(os.Stdout, "Pebble ", log.LstdFlags)
2930
db := db.NewMemoryStore()
30-
return New(logger, db, "", "ecdsa", 0, 1, map[string]Profile{"default": {}})
31+
return New(logger, db, "", "mldsa", 0, 1, map[string]Profile{"default": {}})
3132
}
3233

3334
func makeCertOrderWithExtensions(extensions []pkix.Extension) core.Order {
@@ -58,7 +59,7 @@ func makeCertOrderWithExtensions(extensions []pkix.Extension) core.Order {
5859
}
5960
}
6061

61-
func getOCSPMustStapleExtension(cert *x509.Certificate) *pkix.Extension {
62+
func getOCSPMustStapleExtension(cert *x509pq.Certificate) *pkix.Extension {
6263
for _, ext := range cert.Extensions {
6364
if ext.Id.Equal(ocspID) && bytes.Equal(ext.Value, ocspValue) {
6465
return &ext

cmd/pebble/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func main() {
109109
if keyAlg == "" {
110110
keyAlg = "rsa"
111111
}
112-
acceptableKeyAlgs := []string{"rsa", "ecdsa"}
112+
acceptableKeyAlgs := []string{"rsa", "ecdsa", "mldsa"}
113113
if !slices.Contains(acceptableKeyAlgs, keyAlg) {
114114
cmd.FailOnError(fmt.Errorf("%q is not one of %#v", keyAlg, acceptableKeyAlgs), "invalid key algorithm")
115115
}

core/types.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/go-jose/go-jose/v4"
1717

1818
"github.com/letsencrypt/pebble/v2/acme"
19+
x509pq "github.com/letsencrypt/pebble/v2/ca/x509pq"
1920
)
2021

2122
type Order struct {
@@ -145,7 +146,7 @@ func (ch *Challenge) ExpectedKeyAuthorization(key *jose.JSONWebKey) string {
145146

146147
type Certificate struct {
147148
ID string
148-
Cert *x509.Certificate
149+
Cert *x509pq.Certificate
149150
DER []byte
150151
IssuerChains [][]*Certificate
151152
AccountID string

0 commit comments

Comments
 (0)