]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/x509: implement crypto.Signer
authorPaul van Brouwershaven <paul@vanbrouwershaven.com>
Mon, 5 Jan 2015 10:07:05 +0000 (10:07 +0000)
committerAdam Langley <agl@golang.org>
Wed, 21 Jan 2015 20:13:48 +0000 (20:13 +0000)
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: Id7857fb9a3b4c957c7050b519552ef1c8e55461e
Reviewed-on: https://go-review.googlesource.com/3126
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
src/crypto/x509/x509.go

index 8bad08e5aefea5835a1bfc159ba59c439daec15c..be61fd5607f67aaa76d3551ad90df7372c89eddc 100644 (file)
@@ -12,7 +12,7 @@ import (
        "crypto/ecdsa"
        "crypto/elliptic"
        "crypto/rsa"
-       "crypto/sha1"
+       "crypto/sha1"
        _ "crypto/sha256"
        _ "crypto/sha512"
        "crypto/x509/pkix"
@@ -1389,14 +1389,14 @@ func subjectBytes(cert *Certificate) ([]byte, error) {
        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
 // 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
 
-       switch priv := priv.(type) {
-       case *rsa.PrivateKey:
+       switch pub := pub.(type) {
+       case *rsa.PublicKey:
                pubType = RSA
                hashFunc = crypto.SHA256
                sigAlgo.Algorithm = oidSignatureSHA256WithRSA
@@ -1404,10 +1404,10 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo
                        Tag: 5,
                }
 
-       case *ecdsa.PrivateKey:
+       case *ecdsa.PublicKey:
                pubType = ECDSA
 
-               switch priv.Curve {
+               switch pub.Curve {
                case elliptic.P224(), elliptic.P256():
                        hashFunc = crypto.SHA256
                        sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
@@ -1422,7 +1422,7 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo
                }
 
        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 {
@@ -1469,21 +1469,22 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo
 //
 // The returned slice is the certificate in DER encoding.
 //
-// The only supported key types are RSA and ECDSA (*rsa.PublicKey or
-// *ecdsa.PublicKey for pub, *rsa.PrivateKey or *ecdsa.PrivateKey for priv).
-func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interface{}, priv interface{}) (cert []byte, err error) {
-       hashFunc, signatureAlgorithm, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm)
-       if err != nil {
-               return nil, err
+// All keys types that are implemented via crypto.Signer are supported (This
+// includes *rsa.PublicKey and *ecdsa.PublicKey.)
+func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) {
+       key, ok := priv.(crypto.Signer)
+       if !ok {
+               return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
        }
 
-       publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub)
+       hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
        if err != nil {
                return nil, err
        }
 
+       publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub)
        if err != nil {
-               return
+               return nil, err
        }
 
        if len(parent.SubjectKeyId) > 0 {
@@ -1529,30 +1530,17 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf
        digest := h.Sum(nil)
 
        var signature []byte
-
-       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")
-       }
-
+       signature, err = key.Sign(rand, digest, hashFunc)
        if err != nil {
                return
        }
 
-       cert, err = asn1.Marshal(certificate{
+       return asn1.Marshal(certificate{
                nil,
                c,
                signatureAlgorithm,
                asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
        })
-       return
 }
 
 // pemCRLPrefix is the magic string that indicates that we have a PEM encoded
@@ -1588,18 +1576,20 @@ func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) {
 
 // CreateCRL returns a DER encoded CRL, signed by this Certificate, that
 // contains the given list of revoked certificates.
-//
-// The only supported key type is RSA (*rsa.PrivateKey for priv).
 func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
-       rsaPriv, ok := priv.(*rsa.PrivateKey)
+       key, ok := priv.(crypto.Signer)
        if !ok {
-               return nil, errors.New("x509: non-RSA private keys not supported")
+               return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
+       }
+
+       hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0)
+       if err != nil {
+               return nil, err
        }
+
        tbsCertList := pkix.TBSCertificateList{
-               Version: 1,
-               Signature: pkix.AlgorithmIdentifier{
-                       Algorithm: oidSignatureSHA1WithRSA,
-               },
+               Version:             1,
+               Signature:           signatureAlgorithm,
                Issuer:              c.Subject.ToRDNSequence(),
                ThisUpdate:          now.UTC(),
                NextUpdate:          expiry.UTC(),
@@ -1622,21 +1612,20 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [
                return
        }
 
-       h := sha1.New()
+       h := hashFunc.New()
        h.Write(tbsCertListContents)
        digest := h.Sum(nil)
 
-       signature, err := rsa.SignPKCS1v15(rand, rsaPriv, crypto.SHA1, digest)
+       var signature []byte
+       signature, err = key.Sign(rand, digest, hashFunc)
        if err != nil {
                return
        }
 
        return asn1.Marshal(pkix.CertificateList{
-               TBSCertList: tbsCertList,
-               SignatureAlgorithm: pkix.AlgorithmIdentifier{
-                       Algorithm: oidSignatureSHA1WithRSA,
-               },
-               SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+               TBSCertList:        tbsCertList,
+               SignatureAlgorithm: signatureAlgorithm,
+               SignatureValue:     asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
        })
 }
 
@@ -1710,26 +1699,24 @@ var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
 //
 // The returned slice is the certificate request in DER encoding.
 //
-// The only supported key types are RSA (*rsa.PrivateKey) and ECDSA
-// (*ecdsa.PrivateKey).
+// All keys types that are implemented via crypto.Signer are supported (This
+// includes *rsa.PublicKey and *ecdsa.PublicKey.)
 func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) {
-       hashFunc, sigAlgo, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm)
+       key, ok := priv.(crypto.Signer)
+       if !ok {
+               return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
+       }
+
+       var hashFunc crypto.Hash
+       var sigAlgo pkix.AlgorithmIdentifier
+       hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
        if err != nil {
                return nil, err
        }
 
        var publicKeyBytes []byte
        var publicKeyAlgorithm pkix.AlgorithmIdentifier
-
-       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")
-       }
-
+       publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(key.Public())
        if err != nil {
                return nil, err
        }
@@ -1841,18 +1828,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
        digest := h.Sum(nil)
 
        var signature []byte
-       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")
-       }
-
+       signature, err = key.Sign(rand, digest, hashFunc)
        if err != nil {
                return
        }