X Tutup
Skip to content

Commit ccec6cf

Browse files
authored
Move X509Signer from ceremony to pkcs11helpers. (letsencrypt#5004)
1 parent 82e9e41 commit ccec6cf

File tree

5 files changed

+256
-256
lines changed

5 files changed

+256
-256
lines changed

cmd/ceremony/cert.go

Lines changed: 0 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package main
22

33
import (
4-
"bytes"
5-
"crypto"
64
"crypto/sha1"
75
"crypto/x509"
86
"crypto/x509/pkix"
@@ -14,9 +12,6 @@ import (
1412
"strconv"
1513
"strings"
1614
"time"
17-
18-
"github.com/letsencrypt/boulder/pkcs11helpers"
19-
"github.com/miekg/pkcs11"
2015
)
2116

2217
type policyInfoConfig struct {
@@ -312,108 +307,3 @@ type failReader struct{}
312307
func (fr *failReader) Read([]byte) (int, error) {
313308
return 0, errors.New("Empty reader used by x509.CreateCertificate")
314309
}
315-
316-
// x509Signer is a convenience wrapper used for converting between the
317-
// PKCS#11 ECDSA signature format and the RFC 5480 one which is required
318-
// for X.509 certificates
319-
type x509Signer struct {
320-
session *pkcs11helpers.Session
321-
objectHandle pkcs11.ObjectHandle
322-
keyType pkcs11helpers.KeyType
323-
324-
pub crypto.PublicKey
325-
}
326-
327-
// Sign wraps pkcs11helpers.Sign. If the signing key is ECDSA then the signature
328-
// is converted from the PKCS#11 format to the RFC 5480 format. For RSA keys a
329-
// conversion step is not needed.
330-
func (p *x509Signer) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
331-
signature, err := p.session.Sign(p.objectHandle, p.keyType, digest, opts.HashFunc())
332-
if err != nil {
333-
return nil, err
334-
}
335-
336-
if p.keyType == pkcs11helpers.ECDSAKey {
337-
// Convert from the PKCS#11 format to the RFC 5480 format so that
338-
// it can be used in a X.509 certificate
339-
r := big.NewInt(0).SetBytes(signature[:len(signature)/2])
340-
s := big.NewInt(0).SetBytes(signature[len(signature)/2:])
341-
signature, err = asn1.Marshal(struct {
342-
R, S *big.Int
343-
}{R: r, S: s})
344-
if err != nil {
345-
return nil, fmt.Errorf("failed to convert signature to RFC 5480 format: %s", err)
346-
}
347-
}
348-
return signature, nil
349-
}
350-
351-
func (p *x509Signer) Public() crypto.PublicKey {
352-
return p.pub
353-
}
354-
355-
// newSigner constructs a x509Signer for the private key object associated with the
356-
// given label and ID. Unlike letsencrypt/pkcs11key this method doesn't rely on
357-
// having the actual public key object in order to retrieve the private key
358-
// handle. This is because we already have the key pair object ID, and as such
359-
// do not need to query the HSM to retrieve it.
360-
func newSigner(session *pkcs11helpers.Session, label string, id []byte) (crypto.Signer, error) {
361-
// Retrieve the private key handle that will later be used for the certificate
362-
// signing operation
363-
privateHandle, err := session.FindObject([]*pkcs11.Attribute{
364-
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY),
365-
pkcs11.NewAttribute(pkcs11.CKA_LABEL, label),
366-
pkcs11.NewAttribute(pkcs11.CKA_ID, id),
367-
})
368-
if err != nil {
369-
return nil, fmt.Errorf("failed to retrieve private key handle: %s", err)
370-
}
371-
attrs, err := session.GetAttributeValue(privateHandle, []*pkcs11.Attribute{
372-
pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, nil)},
373-
)
374-
if err != nil {
375-
return nil, fmt.Errorf("failed to retrieve key type: %s", err)
376-
}
377-
if len(attrs) == 0 {
378-
return nil, errors.New("failed to retrieve key attributes")
379-
}
380-
381-
// Retrieve the public key handle with the same CKA_ID as the private key
382-
// and construct a {rsa,ecdsa}.PublicKey for use in x509.CreateCertificate
383-
pubHandle, err := session.FindObject([]*pkcs11.Attribute{
384-
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY),
385-
pkcs11.NewAttribute(pkcs11.CKA_LABEL, label),
386-
pkcs11.NewAttribute(pkcs11.CKA_ID, id),
387-
pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, attrs[0].Value),
388-
})
389-
if err != nil {
390-
return nil, fmt.Errorf("failed to retrieve public key handle: %s", err)
391-
}
392-
var pub crypto.PublicKey
393-
var keyType pkcs11helpers.KeyType
394-
switch {
395-
// 0x00000000, CKK_RSA
396-
case bytes.Equal(attrs[0].Value, []byte{0, 0, 0, 0, 0, 0, 0, 0}):
397-
keyType = pkcs11helpers.RSAKey
398-
pub, err = session.GetRSAPublicKey(pubHandle)
399-
if err != nil {
400-
return nil, fmt.Errorf("failed to retrieve public key: %s", err)
401-
}
402-
// 0x00000003, CKK_ECDSA
403-
case bytes.Equal(attrs[0].Value, []byte{3, 0, 0, 0, 0, 0, 0, 0}):
404-
keyType = pkcs11helpers.ECDSAKey
405-
pub, err = session.GetECDSAPublicKey(pubHandle)
406-
if err != nil {
407-
return nil, fmt.Errorf("failed to retrieve public key: %s", err)
408-
}
409-
default:
410-
return nil, errors.New("unsupported key type")
411-
}
412-
413-
return &x509Signer{
414-
session: session,
415-
objectHandle: privateHandle,
416-
keyType: keyType,
417-
pub: pub,
418-
}, nil
419-
}

cmd/ceremony/cert_test.go

Lines changed: 0 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -2,71 +2,18 @@ package main
22

33
import (
44
"bytes"
5-
"crypto"
6-
"crypto/ecdsa"
7-
"crypto/elliptic"
85
"crypto/rand"
9-
"crypto/sha256"
106
"crypto/x509"
117
"encoding/asn1"
128
"encoding/hex"
139
"errors"
14-
"math/big"
1510
"testing"
1611

1712
"github.com/letsencrypt/boulder/pkcs11helpers"
1813
"github.com/letsencrypt/boulder/test"
1914
"github.com/miekg/pkcs11"
2015
)
2116

22-
func TestX509Signer(t *testing.T) {
23-
s, ctx := pkcs11helpers.NewSessionWithMock()
24-
25-
// test that x509Signer.Sign properly converts the PKCS#11 format signature to
26-
// the RFC 5480 format signature
27-
ctx.SignInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Mechanism, pkcs11.ObjectHandle) error {
28-
return nil
29-
}
30-
tk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
31-
test.AssertNotError(t, err, "Failed to generate test key")
32-
ctx.SignFunc = func(_ pkcs11.SessionHandle, digest []byte) ([]byte, error) {
33-
r, s, err := ecdsa.Sign(rand.Reader, tk, digest[:])
34-
if err != nil {
35-
return nil, err
36-
}
37-
rBytes := r.Bytes()
38-
sBytes := s.Bytes()
39-
// http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/os/pkcs11-curr-v2.40-os.html
40-
// Section 2.3.1: EC Signatures
41-
// "If r and s have different octet length, the shorter of both must be padded with
42-
// leading zero octets such that both have the same octet length."
43-
switch {
44-
case len(rBytes) < len(sBytes):
45-
padding := make([]byte, len(sBytes)-len(rBytes))
46-
rBytes = append(padding, rBytes...)
47-
case len(rBytes) > len(sBytes):
48-
padding := make([]byte, len(rBytes)-len(sBytes))
49-
sBytes = append(padding, sBytes...)
50-
}
51-
return append(rBytes, sBytes...), nil
52-
}
53-
digest := sha256.Sum256([]byte("hello"))
54-
signer := &x509Signer{session: s, keyType: pkcs11helpers.ECDSAKey, pub: tk.Public()}
55-
signature, err := signer.Sign(nil, digest[:], crypto.SHA256)
56-
test.AssertNotError(t, err, "x509Signer.Sign failed")
57-
58-
var rfcFormat struct {
59-
R, S *big.Int
60-
}
61-
rest, err := asn1.Unmarshal(signature, &rfcFormat)
62-
test.AssertNotError(t, err, "asn1.Unmarshal failed trying to parse signature")
63-
test.Assert(t, len(rest) == 0, "Signature had trailing garbage")
64-
verified := ecdsa.Verify(&tk.PublicKey, digest[:], rfcFormat.R, rfcFormat.S)
65-
test.Assert(t, verified, "Failed to verify RFC format signature")
66-
// For the sake of coverage
67-
test.AssertEquals(t, signer.Public(), tk.Public())
68-
}
69-
7017
func TestParseOID(t *testing.T) {
7118
_, err := parseOID("")
7219
test.AssertError(t, err, "parseOID accepted an empty OID")
@@ -458,94 +405,3 @@ func TestVerifyProfile(t *testing.T) {
458405
}
459406
}
460407
}
461-
462-
func TestGetKey(t *testing.T) {
463-
s, ctx := pkcs11helpers.NewSessionWithMock()
464-
465-
// test newSigner fails when pkcs11helpers.FindObject for private key handle fails
466-
ctx.FindObjectsInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Attribute) error {
467-
return errors.New("broken")
468-
}
469-
_, err := newSigner(s, "label", []byte{255, 255})
470-
test.AssertError(t, err, "newSigner didn't fail when pkcs11helpers.FindObject for private key handle failed")
471-
472-
// test newSigner fails when GetAttributeValue fails
473-
ctx.FindObjectsInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Attribute) error {
474-
return nil
475-
}
476-
ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
477-
return []pkcs11.ObjectHandle{1}, false, nil
478-
}
479-
ctx.FindObjectsFinalFunc = func(pkcs11.SessionHandle) error {
480-
return nil
481-
}
482-
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
483-
return nil, errors.New("broken")
484-
}
485-
_, err = newSigner(s, "label", []byte{255, 255})
486-
test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key type failed")
487-
488-
// test newSigner fails when GetAttributeValue returns no attributes
489-
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
490-
return nil, nil
491-
}
492-
_, err = newSigner(s, "label", []byte{255, 255})
493-
test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key type returned no attributes")
494-
495-
// test newSigner fails when pkcs11helpers.FindObject for public key handle fails
496-
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
497-
return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC)}, nil
498-
}
499-
ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, tmpl []*pkcs11.Attribute) error {
500-
if bytes.Equal(tmpl[0].Value, []byte{2, 0, 0, 0, 0, 0, 0, 0}) {
501-
return errors.New("broken")
502-
}
503-
return nil
504-
}
505-
_, err = newSigner(s, "label", []byte{255, 255})
506-
test.AssertError(t, err, "newSigner didn't fail when pkcs11helpers.FindObject for public key handle failed")
507-
508-
// test newSigner fails when pkcs11helpers.FindObject for private key returns unknown CKA_KEY_TYPE
509-
ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, tmpl []*pkcs11.Attribute) error {
510-
return nil
511-
}
512-
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
513-
return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{2, 0, 0, 0, 0, 0, 0, 0})}, nil
514-
}
515-
_, err = newSigner(s, "label", []byte{255, 255})
516-
test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key returned unknown key type")
517-
518-
// test newSigner fails when GetRSAPublicKey fails
519-
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
520-
return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{0, 0, 0, 0, 0, 0, 0, 0})}, nil
521-
}
522-
_, err = newSigner(s, "label", []byte{255, 255})
523-
test.AssertError(t, err, "newSigner didn't fail when GetRSAPublicKey fails")
524-
525-
// test newSigner fails when GetECDSAPublicKey fails
526-
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
527-
return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{3, 0, 0, 0, 0, 0, 0, 0})}, nil
528-
}
529-
_, err = newSigner(s, "label", []byte{255, 255})
530-
test.AssertError(t, err, "newSigner didn't fail when GetECDSAPublicKey fails")
531-
532-
// test newSigner works when everything... works
533-
ctx.GetAttributeValueFunc = func(_ pkcs11.SessionHandle, _ pkcs11.ObjectHandle, attrs []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
534-
var returns []*pkcs11.Attribute
535-
for _, attr := range attrs {
536-
switch attr.Type {
537-
case pkcs11.CKA_KEY_TYPE:
538-
returns = append(returns, pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{0, 0, 0, 0, 0, 0, 0, 0}))
539-
case pkcs11.CKA_PUBLIC_EXPONENT:
540-
returns = append(returns, pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, []byte{1, 2, 3}))
541-
case pkcs11.CKA_MODULUS:
542-
returns = append(returns, pkcs11.NewAttribute(pkcs11.CKA_MODULUS, []byte{4, 5, 6}))
543-
default:
544-
return nil, errors.New("GetAttributeValue got unexpected attribute type")
545-
}
546-
}
547-
return returns, nil
548-
}
549-
_, err = newSigner(s, "label", []byte{255, 255})
550-
test.AssertNotError(t, err, "newSigner failed when everything worked properly")
551-
}

cmd/ceremony/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ func openSigner(cfg PKCS11SigningConfig, issuer *x509.Certificate) (crypto.Signe
352352
if err != nil {
353353
return nil, nil, fmt.Errorf("failed to decode key-id: %s", err)
354354
}
355-
signer, err := newSigner(session, cfg.SigningLabel, keyID)
355+
signer, err := session.NewSigner(cfg.SigningLabel, keyID)
356356
if err != nil {
357357
return nil, nil, fmt.Errorf("failed to retrieve private key handle: %s", err)
358358
}
@@ -414,7 +414,7 @@ func rootCeremony(configBytes []byte) error {
414414
if err != nil {
415415
return err
416416
}
417-
signer, err := newSigner(session, config.PKCS11.StoreLabel, keyInfo.id)
417+
signer, err := session.NewSigner(config.PKCS11.StoreLabel, keyInfo.id)
418418
if err != nil {
419419
return fmt.Errorf("failed to retrieve signer: %s", err)
420420
}

0 commit comments

Comments
 (0)
X Tutup