Move X509Signer from ceremony to pkcs11helpers. (#5004)

This commit is contained in:
Jacob Hoffman-Andrews 2020-07-31 13:24:37 -07:00 committed by GitHub
parent 82e9e41597
commit ccec6cfa19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 256 additions and 256 deletions

View File

@ -1,8 +1,6 @@
package main
import (
"bytes"
"crypto"
"crypto/sha1"
"crypto/x509"
"crypto/x509/pkix"
@ -14,9 +12,6 @@ import (
"strconv"
"strings"
"time"
"github.com/letsencrypt/boulder/pkcs11helpers"
"github.com/miekg/pkcs11"
)
type policyInfoConfig struct {
@ -312,108 +307,3 @@ type failReader struct{}
func (fr *failReader) Read([]byte) (int, error) {
return 0, errors.New("Empty reader used by x509.CreateCertificate")
}
// x509Signer is a convenience wrapper used for converting between the
// PKCS#11 ECDSA signature format and the RFC 5480 one which is required
// for X.509 certificates
type x509Signer struct {
session *pkcs11helpers.Session
objectHandle pkcs11.ObjectHandle
keyType pkcs11helpers.KeyType
pub crypto.PublicKey
}
// Sign wraps pkcs11helpers.Sign. If the signing key is ECDSA then the signature
// is converted from the PKCS#11 format to the RFC 5480 format. For RSA keys a
// conversion step is not needed.
func (p *x509Signer) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
signature, err := p.session.Sign(p.objectHandle, p.keyType, digest, opts.HashFunc())
if err != nil {
return nil, err
}
if p.keyType == pkcs11helpers.ECDSAKey {
// Convert from the PKCS#11 format to the RFC 5480 format so that
// it can be used in a X.509 certificate
r := big.NewInt(0).SetBytes(signature[:len(signature)/2])
s := big.NewInt(0).SetBytes(signature[len(signature)/2:])
signature, err = asn1.Marshal(struct {
R, S *big.Int
}{R: r, S: s})
if err != nil {
return nil, fmt.Errorf("failed to convert signature to RFC 5480 format: %s", err)
}
}
return signature, nil
}
func (p *x509Signer) Public() crypto.PublicKey {
return p.pub
}
// newSigner constructs a x509Signer for the private key object associated with the
// given label and ID. Unlike letsencrypt/pkcs11key this method doesn't rely on
// having the actual public key object in order to retrieve the private key
// handle. This is because we already have the key pair object ID, and as such
// do not need to query the HSM to retrieve it.
func newSigner(session *pkcs11helpers.Session, label string, id []byte) (crypto.Signer, error) {
// Retrieve the private key handle that will later be used for the certificate
// signing operation
privateHandle, err := session.FindObject([]*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY),
pkcs11.NewAttribute(pkcs11.CKA_LABEL, label),
pkcs11.NewAttribute(pkcs11.CKA_ID, id),
})
if err != nil {
return nil, fmt.Errorf("failed to retrieve private key handle: %s", err)
}
attrs, err := session.GetAttributeValue(privateHandle, []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, nil)},
)
if err != nil {
return nil, fmt.Errorf("failed to retrieve key type: %s", err)
}
if len(attrs) == 0 {
return nil, errors.New("failed to retrieve key attributes")
}
// Retrieve the public key handle with the same CKA_ID as the private key
// and construct a {rsa,ecdsa}.PublicKey for use in x509.CreateCertificate
pubHandle, err := session.FindObject([]*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY),
pkcs11.NewAttribute(pkcs11.CKA_LABEL, label),
pkcs11.NewAttribute(pkcs11.CKA_ID, id),
pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, attrs[0].Value),
})
if err != nil {
return nil, fmt.Errorf("failed to retrieve public key handle: %s", err)
}
var pub crypto.PublicKey
var keyType pkcs11helpers.KeyType
switch {
// 0x00000000, CKK_RSA
case bytes.Equal(attrs[0].Value, []byte{0, 0, 0, 0, 0, 0, 0, 0}):
keyType = pkcs11helpers.RSAKey
pub, err = session.GetRSAPublicKey(pubHandle)
if err != nil {
return nil, fmt.Errorf("failed to retrieve public key: %s", err)
}
// 0x00000003, CKK_ECDSA
case bytes.Equal(attrs[0].Value, []byte{3, 0, 0, 0, 0, 0, 0, 0}):
keyType = pkcs11helpers.ECDSAKey
pub, err = session.GetECDSAPublicKey(pubHandle)
if err != nil {
return nil, fmt.Errorf("failed to retrieve public key: %s", err)
}
default:
return nil, errors.New("unsupported key type")
}
return &x509Signer{
session: session,
objectHandle: privateHandle,
keyType: keyType,
pub: pub,
}, nil
}

View File

@ -2,16 +2,11 @@ package main
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"encoding/hex"
"errors"
"math/big"
"testing"
"github.com/letsencrypt/boulder/pkcs11helpers"
@ -19,54 +14,6 @@ import (
"github.com/miekg/pkcs11"
)
func TestX509Signer(t *testing.T) {
s, ctx := pkcs11helpers.NewSessionWithMock()
// test that x509Signer.Sign properly converts the PKCS#11 format signature to
// the RFC 5480 format signature
ctx.SignInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Mechanism, pkcs11.ObjectHandle) error {
return nil
}
tk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
test.AssertNotError(t, err, "Failed to generate test key")
ctx.SignFunc = func(_ pkcs11.SessionHandle, digest []byte) ([]byte, error) {
r, s, err := ecdsa.Sign(rand.Reader, tk, digest[:])
if err != nil {
return nil, err
}
rBytes := r.Bytes()
sBytes := s.Bytes()
// http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/os/pkcs11-curr-v2.40-os.html
// Section 2.3.1: EC Signatures
// "If r and s have different octet length, the shorter of both must be padded with
// leading zero octets such that both have the same octet length."
switch {
case len(rBytes) < len(sBytes):
padding := make([]byte, len(sBytes)-len(rBytes))
rBytes = append(padding, rBytes...)
case len(rBytes) > len(sBytes):
padding := make([]byte, len(rBytes)-len(sBytes))
sBytes = append(padding, sBytes...)
}
return append(rBytes, sBytes...), nil
}
digest := sha256.Sum256([]byte("hello"))
signer := &x509Signer{session: s, keyType: pkcs11helpers.ECDSAKey, pub: tk.Public()}
signature, err := signer.Sign(nil, digest[:], crypto.SHA256)
test.AssertNotError(t, err, "x509Signer.Sign failed")
var rfcFormat struct {
R, S *big.Int
}
rest, err := asn1.Unmarshal(signature, &rfcFormat)
test.AssertNotError(t, err, "asn1.Unmarshal failed trying to parse signature")
test.Assert(t, len(rest) == 0, "Signature had trailing garbage")
verified := ecdsa.Verify(&tk.PublicKey, digest[:], rfcFormat.R, rfcFormat.S)
test.Assert(t, verified, "Failed to verify RFC format signature")
// For the sake of coverage
test.AssertEquals(t, signer.Public(), tk.Public())
}
func TestParseOID(t *testing.T) {
_, err := parseOID("")
test.AssertError(t, err, "parseOID accepted an empty OID")
@ -458,94 +405,3 @@ func TestVerifyProfile(t *testing.T) {
}
}
}
func TestGetKey(t *testing.T) {
s, ctx := pkcs11helpers.NewSessionWithMock()
// test newSigner fails when pkcs11helpers.FindObject for private key handle fails
ctx.FindObjectsInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Attribute) error {
return errors.New("broken")
}
_, err := newSigner(s, "label", []byte{255, 255})
test.AssertError(t, err, "newSigner didn't fail when pkcs11helpers.FindObject for private key handle failed")
// test newSigner fails when GetAttributeValue fails
ctx.FindObjectsInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Attribute) error {
return nil
}
ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
return []pkcs11.ObjectHandle{1}, false, nil
}
ctx.FindObjectsFinalFunc = func(pkcs11.SessionHandle) error {
return nil
}
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
return nil, errors.New("broken")
}
_, err = newSigner(s, "label", []byte{255, 255})
test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key type failed")
// test newSigner fails when GetAttributeValue returns no attributes
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
return nil, nil
}
_, err = newSigner(s, "label", []byte{255, 255})
test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key type returned no attributes")
// test newSigner fails when pkcs11helpers.FindObject for public key handle fails
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC)}, nil
}
ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, tmpl []*pkcs11.Attribute) error {
if bytes.Equal(tmpl[0].Value, []byte{2, 0, 0, 0, 0, 0, 0, 0}) {
return errors.New("broken")
}
return nil
}
_, err = newSigner(s, "label", []byte{255, 255})
test.AssertError(t, err, "newSigner didn't fail when pkcs11helpers.FindObject for public key handle failed")
// test newSigner fails when pkcs11helpers.FindObject for private key returns unknown CKA_KEY_TYPE
ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, tmpl []*pkcs11.Attribute) error {
return nil
}
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{2, 0, 0, 0, 0, 0, 0, 0})}, nil
}
_, err = newSigner(s, "label", []byte{255, 255})
test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key returned unknown key type")
// test newSigner fails when GetRSAPublicKey fails
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{0, 0, 0, 0, 0, 0, 0, 0})}, nil
}
_, err = newSigner(s, "label", []byte{255, 255})
test.AssertError(t, err, "newSigner didn't fail when GetRSAPublicKey fails")
// test newSigner fails when GetECDSAPublicKey fails
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{3, 0, 0, 0, 0, 0, 0, 0})}, nil
}
_, err = newSigner(s, "label", []byte{255, 255})
test.AssertError(t, err, "newSigner didn't fail when GetECDSAPublicKey fails")
// test newSigner works when everything... works
ctx.GetAttributeValueFunc = func(_ pkcs11.SessionHandle, _ pkcs11.ObjectHandle, attrs []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
var returns []*pkcs11.Attribute
for _, attr := range attrs {
switch attr.Type {
case pkcs11.CKA_KEY_TYPE:
returns = append(returns, pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{0, 0, 0, 0, 0, 0, 0, 0}))
case pkcs11.CKA_PUBLIC_EXPONENT:
returns = append(returns, pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, []byte{1, 2, 3}))
case pkcs11.CKA_MODULUS:
returns = append(returns, pkcs11.NewAttribute(pkcs11.CKA_MODULUS, []byte{4, 5, 6}))
default:
return nil, errors.New("GetAttributeValue got unexpected attribute type")
}
}
return returns, nil
}
_, err = newSigner(s, "label", []byte{255, 255})
test.AssertNotError(t, err, "newSigner failed when everything worked properly")
}

View File

@ -352,7 +352,7 @@ func openSigner(cfg PKCS11SigningConfig, issuer *x509.Certificate) (crypto.Signe
if err != nil {
return nil, nil, fmt.Errorf("failed to decode key-id: %s", err)
}
signer, err := newSigner(session, cfg.SigningLabel, keyID)
signer, err := session.NewSigner(cfg.SigningLabel, keyID)
if err != nil {
return nil, nil, fmt.Errorf("failed to retrieve private key handle: %s", err)
}
@ -414,7 +414,7 @@ func rootCeremony(configBytes []byte) error {
if err != nil {
return err
}
signer, err := newSigner(session, config.PKCS11.StoreLabel, keyInfo.id)
signer, err := session.NewSigner(config.PKCS11.StoreLabel, keyInfo.id)
if err != nil {
return fmt.Errorf("failed to retrieve signer: %s", err)
}

View File

@ -1,6 +1,7 @@
package pkcs11helpers
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
@ -8,6 +9,7 @@ import (
"encoding/asn1"
"errors"
"fmt"
"io"
"math/big"
"github.com/miekg/pkcs11"
@ -222,6 +224,111 @@ func (s *Session) FindObject(tmpl []*pkcs11.Attribute) (pkcs11.ObjectHandle, err
return handles[0], nil
}
// X509Signer is a convenience wrapper used for converting between the
// PKCS#11 ECDSA signature format and the RFC 5480 one which is required
// for X.509 certificates
type X509Signer struct {
session *Session
objectHandle pkcs11.ObjectHandle
keyType KeyType
pub crypto.PublicKey
}
// Sign signs a digest. If the signing key is ECDSA then the signature
// is converted from the PKCS#11 format to the RFC 5480 format. For RSA keys a
// conversion step is not needed.
func (p *X509Signer) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
signature, err := p.session.Sign(p.objectHandle, p.keyType, digest, opts.HashFunc())
if err != nil {
return nil, err
}
if p.keyType == ECDSAKey {
// Convert from the PKCS#11 format to the RFC 5480 format so that
// it can be used in a X.509 certificate
r := big.NewInt(0).SetBytes(signature[:len(signature)/2])
s := big.NewInt(0).SetBytes(signature[len(signature)/2:])
signature, err = asn1.Marshal(struct {
R, S *big.Int
}{R: r, S: s})
if err != nil {
return nil, fmt.Errorf("failed to convert signature to RFC 5480 format: %s", err)
}
}
return signature, nil
}
func (p *X509Signer) Public() crypto.PublicKey {
return p.pub
}
// NewSigner constructs an X509Signer for the private key object associated with the
// given label and ID. Unlike letsencrypt/pkcs11key this method doesn't rely on
// having the actual public key object in order to retrieve the private key
// handle. This is because we already have the key pair object ID, and as such
// do not need to query the HSM to retrieve it.
func (s *Session) NewSigner(label string, id []byte) (crypto.Signer, error) {
// Retrieve the private key handle that will later be used for the certificate
// signing operation
privateHandle, err := s.FindObject([]*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY),
pkcs11.NewAttribute(pkcs11.CKA_LABEL, label),
pkcs11.NewAttribute(pkcs11.CKA_ID, id),
})
if err != nil {
return nil, fmt.Errorf("failed to retrieve private key handle: %s", err)
}
attrs, err := s.GetAttributeValue(privateHandle, []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, nil)},
)
if err != nil {
return nil, fmt.Errorf("failed to retrieve key type: %s", err)
}
if len(attrs) == 0 {
return nil, errors.New("failed to retrieve key attributes")
}
// Retrieve the public key handle with the same CKA_ID as the private key
// and construct a {rsa,ecdsa}.PublicKey for use in x509.CreateCertificate
pubHandle, err := s.FindObject([]*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY),
pkcs11.NewAttribute(pkcs11.CKA_LABEL, label),
pkcs11.NewAttribute(pkcs11.CKA_ID, id),
pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, attrs[0].Value),
})
if err != nil {
return nil, fmt.Errorf("failed to retrieve public key handle: %s", err)
}
var pub crypto.PublicKey
var keyType KeyType
switch {
// 0x00000000, CKK_RSA
case bytes.Equal(attrs[0].Value, []byte{0, 0, 0, 0, 0, 0, 0, 0}):
keyType = RSAKey
pub, err = s.GetRSAPublicKey(pubHandle)
if err != nil {
return nil, fmt.Errorf("failed to retrieve public key: %s", err)
}
// 0x00000003, CKK_ECDSA
case bytes.Equal(attrs[0].Value, []byte{3, 0, 0, 0, 0, 0, 0, 0}):
keyType = ECDSAKey
pub, err = s.GetECDSAPublicKey(pubHandle)
if err != nil {
return nil, fmt.Errorf("failed to retrieve public key: %s", err)
}
default:
return nil, errors.New("unsupported key type")
}
return &X509Signer{
session: s,
objectHandle: privateHandle,
keyType: keyType,
pub: pub,
}, nil
}
func NewMock() *MockCtx {
return &MockCtx{}
}

View File

@ -1,7 +1,15 @@
package pkcs11helpers
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"encoding/asn1"
"errors"
"math/big"
"strings"
"testing"
@ -230,3 +238,142 @@ func TestFindObjectSucceeds(t *testing.T) {
test.AssertNotError(t, err, "FindObject failed when everything worked as expected")
test.AssertEquals(t, handle, pkcs11.ObjectHandle(1))
}
func TestGetKey(t *testing.T) {
s, ctx := NewSessionWithMock()
// test newSigner fails when FindObject for private key handle fails
ctx.FindObjectsInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Attribute) error {
return errors.New("broken")
}
_, err := s.NewSigner("label", []byte{255, 255})
test.AssertError(t, err, "newSigner didn't fail when FindObject for private key handle failed")
// test newSigner fails when GetAttributeValue fails
ctx.FindObjectsInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Attribute) error {
return nil
}
ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
return []pkcs11.ObjectHandle{1}, false, nil
}
ctx.FindObjectsFinalFunc = func(pkcs11.SessionHandle) error {
return nil
}
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
return nil, errors.New("broken")
}
_, err = s.NewSigner("label", []byte{255, 255})
test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key type failed")
// test newSigner fails when GetAttributeValue returns no attributes
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
return nil, nil
}
_, err = s.NewSigner("label", []byte{255, 255})
test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key type returned no attributes")
// test newSigner fails when FindObject for public key handle fails
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC)}, nil
}
ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, tmpl []*pkcs11.Attribute) error {
if bytes.Equal(tmpl[0].Value, []byte{2, 0, 0, 0, 0, 0, 0, 0}) {
return errors.New("broken")
}
return nil
}
_, err = s.NewSigner("label", []byte{255, 255})
test.AssertError(t, err, "newSigner didn't fail when FindObject for public key handle failed")
// test newSigner fails when FindObject for private key returns unknown CKA_KEY_TYPE
ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, tmpl []*pkcs11.Attribute) error {
return nil
}
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{2, 0, 0, 0, 0, 0, 0, 0})}, nil
}
_, err = s.NewSigner("label", []byte{255, 255})
test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key returned unknown key type")
// test newSigner fails when GetRSAPublicKey fails
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{0, 0, 0, 0, 0, 0, 0, 0})}, nil
}
_, err = s.NewSigner("label", []byte{255, 255})
test.AssertError(t, err, "newSigner didn't fail when GetRSAPublicKey fails")
// test newSigner fails when GetECDSAPublicKey fails
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{3, 0, 0, 0, 0, 0, 0, 0})}, nil
}
_, err = s.NewSigner("label", []byte{255, 255})
test.AssertError(t, err, "newSigner didn't fail when GetECDSAPublicKey fails")
// test newSigner works when everything... works
ctx.GetAttributeValueFunc = func(_ pkcs11.SessionHandle, _ pkcs11.ObjectHandle, attrs []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
var returns []*pkcs11.Attribute
for _, attr := range attrs {
switch attr.Type {
case pkcs11.CKA_KEY_TYPE:
returns = append(returns, pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{0, 0, 0, 0, 0, 0, 0, 0}))
case pkcs11.CKA_PUBLIC_EXPONENT:
returns = append(returns, pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, []byte{1, 2, 3}))
case pkcs11.CKA_MODULUS:
returns = append(returns, pkcs11.NewAttribute(pkcs11.CKA_MODULUS, []byte{4, 5, 6}))
default:
return nil, errors.New("GetAttributeValue got unexpected attribute type")
}
}
return returns, nil
}
_, err = s.NewSigner("label", []byte{255, 255})
test.AssertNotError(t, err, "newSigner failed when everything worked properly")
}
func TestX509Signer(t *testing.T) {
s, ctx := NewSessionWithMock()
// test that x509Signer.Sign properly converts the PKCS#11 format signature to
// the RFC 5480 format signature
ctx.SignInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Mechanism, pkcs11.ObjectHandle) error {
return nil
}
tk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
test.AssertNotError(t, err, "Failed to generate test key")
ctx.SignFunc = func(_ pkcs11.SessionHandle, digest []byte) ([]byte, error) {
r, s, err := ecdsa.Sign(rand.Reader, tk, digest[:])
if err != nil {
return nil, err
}
rBytes := r.Bytes()
sBytes := s.Bytes()
// http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/os/pkcs11-curr-v2.40-os.html
// Section 2.3.1: EC Signatures
// "If r and s have different octet length, the shorter of both must be padded with
// leading zero octets such that both have the same octet length."
switch {
case len(rBytes) < len(sBytes):
padding := make([]byte, len(sBytes)-len(rBytes))
rBytes = append(padding, rBytes...)
case len(rBytes) > len(sBytes):
padding := make([]byte, len(rBytes)-len(sBytes))
sBytes = append(padding, sBytes...)
}
return append(rBytes, sBytes...), nil
}
digest := sha256.Sum256([]byte("hello"))
signer := &X509Signer{session: s, keyType: ECDSAKey, pub: tk.Public()}
signature, err := signer.Sign(nil, digest[:], crypto.SHA256)
test.AssertNotError(t, err, "x509Signer.Sign failed")
var rfcFormat struct {
R, S *big.Int
}
rest, err := asn1.Unmarshal(signature, &rfcFormat)
test.AssertNotError(t, err, "asn1.Unmarshal failed trying to parse signature")
test.Assert(t, len(rest) == 0, "Signature had trailing garbage")
verified := ecdsa.Verify(&tk.PublicKey, digest[:], rfcFormat.R, rfcFormat.S)
test.Assert(t, verified, "Failed to verify RFC format signature")
// For the sake of coverage
test.AssertEquals(t, signer.Public(), tk.Public())
}