Commit cef15faa authored by Paul van Brouwershaven's avatar Paul van Brouwershaven Committed by Adam Langley

crypto/x509: implement crypto.Signer

Signer is an interface to support opaque private keys.
These keys typically result from being kept in special hardware
(i.e. a TPM) although sometimes operating systems provide a
similar interface using process isolation for security rather
than hardware boundaries.

This changes provides updates implements crypto.Signer in
CreateCRL and CreateCertificate so that they can be used with
opaque keys.

This CL has been discussed at: http://golang.org/cl/145910043

Change-Id: Ie4a4a583fb120ff484a5ccf267ecd2a9c5a3902b
Reviewed-on: https://go-review.googlesource.com/2254Reviewed-by: default avatarAdam Langley <agl@golang.org>
parent 8128b011
...@@ -12,7 +12,7 @@ import ( ...@@ -12,7 +12,7 @@ import (
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic" "crypto/elliptic"
"crypto/rsa" "crypto/rsa"
"crypto/sha1" _ "crypto/sha1"
_ "crypto/sha256" _ "crypto/sha256"
_ "crypto/sha512" _ "crypto/sha512"
"crypto/x509/pkix" "crypto/x509/pkix"
...@@ -1389,14 +1389,14 @@ func subjectBytes(cert *Certificate) ([]byte, error) { ...@@ -1389,14 +1389,14 @@ func subjectBytes(cert *Certificate) ([]byte, error) {
return asn1.Marshal(cert.Subject.ToRDNSequence()) return asn1.Marshal(cert.Subject.ToRDNSequence())
} }
// signingParamsForPrivateKey returns the parameters to use for signing with // signingParamsForPublicKey returns the parameters to use for signing with
// priv. If requestedSigAlgo is not zero then it overrides the default // priv. If requestedSigAlgo is not zero then it overrides the default
// signature algorithm. // signature algorithm.
func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) { func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
var pubType PublicKeyAlgorithm var pubType PublicKeyAlgorithm
switch priv := priv.(type) { switch pub := pub.(type) {
case *rsa.PrivateKey: case *rsa.PublicKey:
pubType = RSA pubType = RSA
hashFunc = crypto.SHA256 hashFunc = crypto.SHA256
sigAlgo.Algorithm = oidSignatureSHA256WithRSA sigAlgo.Algorithm = oidSignatureSHA256WithRSA
...@@ -1404,10 +1404,10 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo ...@@ -1404,10 +1404,10 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo
Tag: 5, Tag: 5,
} }
case *ecdsa.PrivateKey: case *ecdsa.PublicKey:
pubType = ECDSA pubType = ECDSA
switch priv.Curve { switch pub.Curve {
case elliptic.P224(), elliptic.P256(): case elliptic.P224(), elliptic.P256():
hashFunc = crypto.SHA256 hashFunc = crypto.SHA256
sigAlgo.Algorithm = oidSignatureECDSAWithSHA256 sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
...@@ -1422,7 +1422,7 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo ...@@ -1422,7 +1422,7 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo
} }
default: default:
err = errors.New("x509: only RSA and ECDSA private keys supported") err = errors.New("x509: only RSA and ECDSA keys supported")
} }
if err != nil { if err != nil {
...@@ -1469,10 +1469,10 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo ...@@ -1469,10 +1469,10 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo
// //
// The returned slice is the certificate in DER encoding. // The returned slice is the certificate in DER encoding.
// //
// The only supported key types are RSA and ECDSA (*rsa.PublicKey or // All keys types that are implemented via crypto.Signer are supported (This
// *ecdsa.PublicKey for pub, *rsa.PrivateKey or *ecdsa.PrivateKey for priv). // includes *rsa.PublicKey and *ecdsa.PublicKey.)
func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interface{}, priv interface{}) (cert []byte, err error) { func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interface{}, priv crypto.Signer) (cert []byte, err error) {
hashFunc, signatureAlgorithm, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm) hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), template.SignatureAlgorithm)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -1482,10 +1482,6 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf ...@@ -1482,10 +1482,6 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf
return nil, err return nil, err
} }
if err != nil {
return
}
if len(parent.SubjectKeyId) > 0 { if len(parent.SubjectKeyId) > 0 {
template.AuthorityKeyId = parent.SubjectKeyId template.AuthorityKeyId = parent.SubjectKeyId
} }
...@@ -1529,19 +1525,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf ...@@ -1529,19 +1525,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf
digest := h.Sum(nil) digest := h.Sum(nil)
var signature []byte var signature []byte
signature, err = priv.Sign(rand, digest, hashFunc)
switch priv := priv.(type) {
case *rsa.PrivateKey:
signature, err = rsa.SignPKCS1v15(rand, priv, hashFunc, digest)
case *ecdsa.PrivateKey:
var r, s *big.Int
if r, s, err = ecdsa.Sign(rand, priv, digest); err == nil {
signature, err = asn1.Marshal(ecdsaSignature{r, s})
}
default:
panic("internal error")
}
if err != nil { if err != nil {
return return
} }
...@@ -1588,18 +1572,15 @@ func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) { ...@@ -1588,18 +1572,15 @@ func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) {
// CreateCRL returns a DER encoded CRL, signed by this Certificate, that // CreateCRL returns a DER encoded CRL, signed by this Certificate, that
// contains the given list of revoked certificates. // contains the given list of revoked certificates.
// func (c *Certificate) CreateCRL(rand io.Reader, priv crypto.Signer, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
// The only supported key type is RSA (*rsa.PrivateKey for priv). hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), 0)
func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) { if err != nil {
rsaPriv, ok := priv.(*rsa.PrivateKey) return nil, err
if !ok {
return nil, errors.New("x509: non-RSA private keys not supported")
} }
tbsCertList := pkix.TBSCertificateList{ tbsCertList := pkix.TBSCertificateList{
Version: 1, Version: 1,
Signature: pkix.AlgorithmIdentifier{ Signature: signatureAlgorithm,
Algorithm: oidSignatureSHA1WithRSA,
},
Issuer: c.Subject.ToRDNSequence(), Issuer: c.Subject.ToRDNSequence(),
ThisUpdate: now.UTC(), ThisUpdate: now.UTC(),
NextUpdate: expiry.UTC(), NextUpdate: expiry.UTC(),
...@@ -1611,21 +1592,20 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [ ...@@ -1611,21 +1592,20 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [
return return
} }
h := sha1.New() h := hashFunc.New()
h.Write(tbsCertListContents) h.Write(tbsCertListContents)
digest := h.Sum(nil) digest := h.Sum(nil)
signature, err := rsa.SignPKCS1v15(rand, rsaPriv, crypto.SHA1, digest) var signature []byte
signature, err = priv.Sign(rand, digest, hashFunc)
if err != nil { if err != nil {
return return
} }
return asn1.Marshal(pkix.CertificateList{ return asn1.Marshal(pkix.CertificateList{
TBSCertList: tbsCertList, TBSCertList: tbsCertList,
SignatureAlgorithm: pkix.AlgorithmIdentifier{ SignatureAlgorithm: signatureAlgorithm,
Algorithm: oidSignatureSHA1WithRSA, SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
},
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
}) })
} }
...@@ -1699,26 +1679,19 @@ var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14} ...@@ -1699,26 +1679,19 @@ var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
// //
// The returned slice is the certificate request in DER encoding. // The returned slice is the certificate request in DER encoding.
// //
// The only supported key types are RSA (*rsa.PrivateKey) and ECDSA // All keys types that are implemented via crypto.Signer are supported (This
// (*ecdsa.PrivateKey). // includes *rsa.PublicKey and *ecdsa.PublicKey.)
func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) { func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv crypto.Signer) (csr []byte, err error) {
hashFunc, sigAlgo, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm) var hashFunc crypto.Hash
var sigAlgo pkix.AlgorithmIdentifier
hashFunc, sigAlgo, err = signingParamsForPublicKey(priv.Public(), template.SignatureAlgorithm)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var publicKeyBytes []byte var publicKeyBytes []byte
var publicKeyAlgorithm pkix.AlgorithmIdentifier var publicKeyAlgorithm pkix.AlgorithmIdentifier
publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(priv.Public())
switch priv := priv.(type) {
case *rsa.PrivateKey:
publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(&priv.PublicKey)
case *ecdsa.PrivateKey:
publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(&priv.PublicKey)
default:
panic("internal error")
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -1830,18 +1803,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv ...@@ -1830,18 +1803,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
digest := h.Sum(nil) digest := h.Sum(nil)
var signature []byte var signature []byte
switch priv := priv.(type) { signature, err = priv.Sign(rand, digest, hashFunc)
case *rsa.PrivateKey:
signature, err = rsa.SignPKCS1v15(rand, priv, hashFunc, digest)
case *ecdsa.PrivateKey:
var r, s *big.Int
if r, s, err = ecdsa.Sign(rand, priv, digest); err == nil {
signature, err = asn1.Marshal(ecdsaSignature{r, s})
}
default:
panic("internal error")
}
if err != nil { if err != nil {
return return
} }
......
...@@ -6,6 +6,7 @@ package x509 ...@@ -6,6 +6,7 @@ package x509
import ( import (
"bytes" "bytes"
"crypto"
"crypto/dsa" "crypto/dsa"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic" "crypto/elliptic"
...@@ -304,10 +305,11 @@ func TestCreateSelfSignedCertificate(t *testing.T) { ...@@ -304,10 +305,11 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
} }
tests := []struct { tests := []struct {
name string name string
pub, priv interface{} pub interface{}
checkSig bool priv crypto.Signer
sigAlgo SignatureAlgorithm checkSig bool
sigAlgo SignatureAlgorithm
}{ }{
{"RSA/RSA", &rsaPriv.PublicKey, rsaPriv, true, SHA1WithRSA}, {"RSA/RSA", &rsaPriv.PublicKey, rsaPriv, true, SHA1WithRSA},
{"RSA/ECDSA", &rsaPriv.PublicKey, ecdsaPriv, false, ECDSAWithSHA384}, {"RSA/ECDSA", &rsaPriv.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
...@@ -779,7 +781,7 @@ func TestCreateCertificateRequest(t *testing.T) { ...@@ -779,7 +781,7 @@ func TestCreateCertificateRequest(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
priv interface{} priv crypto.Signer
sigAlgo SignatureAlgorithm sigAlgo SignatureAlgorithm
}{ }{
{"RSA", rsaPriv, SHA1WithRSA}, {"RSA", rsaPriv, SHA1WithRSA},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment