crypto: add 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 interfaces for representing them and
alters crypto/tls so that client certificates can use
opaque keys.

LGTM=bradfitz
R=bradfitz
CC=golang-codereviews, jdeprez
https://golang.org/cl/114680043
This commit is contained in:
Adam Langley 2014-08-29 12:36:30 -07:00
parent 16b2f42015
commit b88cd69926
2 changed files with 22 additions and 15 deletions

View File

@ -487,7 +487,12 @@ func (c *Config) BuildNameToCertificate() {
// A Certificate is a chain of one or more certificates, leaf first.
type Certificate struct {
Certificate [][]byte
PrivateKey crypto.PrivateKey // supported types: *rsa.PrivateKey, *ecdsa.PrivateKey
// PrivateKey contains the private key corresponding to the public key
// in Leaf. For a server, this must be a *rsa.PrivateKey or
// *ecdsa.PrivateKey. For a client doing client authentication, this
// can be any type that implements crypto.Signer (which includes RSA
// and ECDSA private keys).
PrivateKey crypto.PrivateKey
// OCSPStaple contains an optional OCSP response which will be served
// to clients that request it.
OCSPStaple []byte

View File

@ -6,11 +6,11 @@ package tls
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/rsa"
"crypto/subtle"
"crypto/x509"
"encoding/asn1"
"errors"
"fmt"
"io"
@ -345,8 +345,8 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
// We need to search our list of client certs for one
// where SignatureAlgorithm is RSA and the Issuer is in
// certReq.certificateAuthorities
// where SignatureAlgorithm is acceptable to the server and the
// Issuer is in certReq.certificateAuthorities
findCert:
for i, chain := range c.config.Certificates {
if !rsaAvail && !ecdsaAvail {
@ -373,7 +373,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
if len(certReq.certificateAuthorities) == 0 {
// they gave us an empty list, so just take the
// first RSA cert from c.config.Certificates
// first cert from c.config.Certificates
chainToSend = &chain
break findCert
}
@ -428,22 +428,24 @@ func (hs *clientHandshakeState) doFullHandshake() error {
hasSignatureAndHash: c.vers >= VersionTLS12,
}
switch key := c.config.Certificates[0].PrivateKey.(type) {
case *ecdsa.PrivateKey:
digest, _, hashId := hs.finishedHash.hashForClientCertificate(signatureECDSA)
r, s, err := ecdsa.Sign(c.config.rand(), key, digest)
if err == nil {
signed, err = asn1.Marshal(ecdsaSignature{r, s})
}
key, ok := chainToSend.PrivateKey.(crypto.Signer)
if !ok {
c.sendAlert(alertInternalError)
return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
}
switch key.Public().(type) {
case *ecdsa.PublicKey:
digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureECDSA)
signed, err = key.Sign(c.config.rand(), digest, hashFunc)
certVerify.signatureAndHash.signature = signatureECDSA
certVerify.signatureAndHash.hash = hashId
case *rsa.PrivateKey:
case *rsa.PublicKey:
digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureRSA)
signed, err = rsa.SignPKCS1v15(c.config.rand(), key, hashFunc, digest)
signed, err = key.Sign(c.config.rand(), digest, hashFunc)
certVerify.signatureAndHash.signature = signatureRSA
certVerify.signatureAndHash.hash = hashId
default:
err = errors.New("unknown private key type")
err = fmt.Errorf("tls: unknown client certificate key type: %T", key)
}
if err != nil {
c.sendAlert(alertInternalError)