introduce crypto.Signer interface and hide RSA implementation

This commit is contained in:
Lucas Clemente
2016-04-17 00:21:54 +02:00
parent aa894a6df7
commit ac0eed61f2
6 changed files with 36 additions and 28 deletions

View File

@@ -14,14 +14,14 @@ import (
"github.com/lucas-clemente/quic-go/utils"
)
// KeyData stores a key and a certificate for the server proof
type KeyData struct {
// rsaSigner stores a key and a certificate for the server proof
type rsaSigner struct {
key *rsa.PrivateKey
cert *x509.Certificate
}
// LoadKeyData loads the key and cert from files
func LoadKeyData(certFileName string, keyFileName string) (*KeyData, error) {
// NewRSASigner loads the key and cert from files
func NewRSASigner(certFileName string, keyFileName string) (Signer, error) {
keyDER, err := ioutil.ReadFile(keyFileName)
if err != nil {
return nil, err
@@ -39,11 +39,11 @@ func LoadKeyData(certFileName string, keyFileName string) (*KeyData, error) {
return nil, err
}
return &KeyData{key: key, cert: cert}, nil
return &rsaSigner{key: key, cert: cert}, nil
}
// SignServerProof signs CHLO and server config for use in the server proof
func (kd *KeyData) SignServerProof(chlo []byte, serverConfigData []byte) ([]byte, error) {
func (kd *rsaSigner) SignServerProof(chlo []byte, serverConfigData []byte) ([]byte, error) {
hash := sha256.New()
if len(chlo) > 0 {
// Version >= 31
@@ -59,7 +59,7 @@ func (kd *KeyData) SignServerProof(chlo []byte, serverConfigData []byte) ([]byte
}
// GetCertCompressed gets the certificate in the format described by the QUIC crypto doc
func (kd *KeyData) GetCertCompressed() []byte {
func (kd *rsaSigner) GetCertCompressed() []byte {
b := &bytes.Buffer{}
b.WriteByte(1) // Entry type compressed
b.WriteByte(0) // Entry type end_of_list
@@ -81,6 +81,6 @@ func (kd *KeyData) GetCertCompressed() []byte {
}
// GetCertUncompressed gets the certificate in DER
func (kd *KeyData) GetCertUncompressed() []byte {
func (kd *rsaSigner) GetCertUncompressed() []byte {
return kd.cert.Raw
}

View File

@@ -22,7 +22,7 @@ var _ = Describe("ProofRsa", func() {
z.Write([]byte{0x04, 0x00, 0x00, 0x00})
z.Write(cert)
z.Close()
kd := &KeyData{cert: &x509.Certificate{Raw: cert}}
kd := &rsaSigner{cert: &x509.Certificate{Raw: cert}}
Expect(kd.GetCertCompressed()).To(Equal(append([]byte{
0x01, 0x00,
0x08, 0x00, 0x00, 0x00,
@@ -31,14 +31,14 @@ var _ = Describe("ProofRsa", func() {
It("gives valid signatures", func() {
path := os.Getenv("GOPATH") + "/src/github.com/lucas-clemente/quic-go/example/"
keyData, err := LoadKeyData(path+"cert.der", path+"key.der")
kd, err := NewRSASigner(path+"cert.der", path+"key.der")
Expect(err).ToNot(HaveOccurred())
signature, err := keyData.SignServerProof([]byte{'C', 'H', 'L', 'O'}, []byte{'S', 'C', 'F', 'G'})
signature, err := kd.SignServerProof([]byte{'C', 'H', 'L', 'O'}, []byte{'S', 'C', 'F', 'G'})
Expect(err).ToNot(HaveOccurred())
// Generated with:
// ruby -e 'require "digest"; p Digest::SHA256.digest("QUIC CHLO and server config signature\x00" + "\x20\x00\x00\x00" + Digest::SHA256.digest("CHLO") + "SCFG")'
data := []byte("W\xA6\xFC\xDE\xC7\xD2>c\xE6\xB5\xF6\tq\x9E|<~1\xA33\x01\xCA=\x19\xBD\xC1\xE4\xB0\xBA\x9B\x16%")
err = rsa.VerifyPSS(keyData.cert.PublicKey.(*rsa.PublicKey), crypto.SHA256, data, signature, &rsa.PSSOptions{SaltLength: 32})
err = rsa.VerifyPSS(kd.(*rsaSigner).cert.PublicKey.(*rsa.PublicKey), crypto.SHA256, data, signature, &rsa.PSSOptions{SaltLength: 32})
Expect(err).ToNot(HaveOccurred())
})
})

8
crypto/signer.go Normal file
View File

@@ -0,0 +1,8 @@
package crypto
// A Signer holds a certificate and a private key
type Signer interface {
SignServerProof(chlo []byte, serverConfigData []byte) ([]byte, error)
GetCertCompressed() []byte
GetCertUncompressed() []byte
}

View File

@@ -93,12 +93,12 @@ func (h *CryptoSetup) HandleCryptoMessage(data []byte) ([]byte, error) {
nonce.Write(cryptoData[TagNONC])
nonce.Write(h.nonce)
h.secureAEAD, err = crypto.DeriveKeysChacha20(false, sharedSecret, nonce.Bytes(), h.connID, data, h.scfg.Get(), h.scfg.kd.GetCertUncompressed())
h.secureAEAD, err = crypto.DeriveKeysChacha20(false, sharedSecret, nonce.Bytes(), h.connID, data, h.scfg.Get(), h.scfg.signer.GetCertUncompressed())
if err != nil {
return nil, err
}
// TODO: Use new curve
h.forwardSecureAEAD, err = crypto.DeriveKeysChacha20(true, sharedSecret, nonce.Bytes(), h.connID, data, h.scfg.Get(), h.scfg.kd.GetCertUncompressed())
h.forwardSecureAEAD, err = crypto.DeriveKeysChacha20(true, sharedSecret, nonce.Bytes(), h.connID, data, h.scfg.Get(), h.scfg.signer.GetCertUncompressed())
if err != nil {
return nil, err
}

View File

@@ -9,22 +9,22 @@ import (
// ServerConfig is a server config
type ServerConfig struct {
kex crypto.KeyExchange
kd *crypto.KeyData
ID []byte
kex crypto.KeyExchange
signer crypto.Signer
ID []byte
}
// NewServerConfig creates a new server config
func NewServerConfig(kex crypto.KeyExchange, kd *crypto.KeyData) *ServerConfig {
func NewServerConfig(kex crypto.KeyExchange, signer crypto.Signer) *ServerConfig {
id := make([]byte, 16)
_, err := rand.Reader.Read(id)
if err != nil {
panic(err)
}
return &ServerConfig{
kex: kex,
kd: kd,
ID: id,
kex: kex,
signer: signer,
ID: id,
}
}
@@ -45,10 +45,10 @@ func (s *ServerConfig) Get() []byte {
// Sign the server config and CHLO with the server's keyData
func (s *ServerConfig) Sign(chlo []byte) ([]byte, error) {
return s.kd.SignServerProof(chlo, s.Get())
return s.signer.SignServerProof(chlo, s.Get())
}
// GetCertCompressed returns the certificate data
func (s *ServerConfig) GetCertCompressed() []byte {
return s.kd.GetCertCompressed()
return s.signer.GetCertCompressed()
}

View File

@@ -13,8 +13,8 @@ import (
// A Server of QUIC
type Server struct {
keyData *crypto.KeyData
scfg *handshake.ServerConfig
signer crypto.Signer
scfg *handshake.ServerConfig
sessions map[protocol.ConnectionID]*Session
@@ -24,15 +24,15 @@ type Server struct {
// NewServer makes a new server
func NewServer(certPath, keyPath string, cb StreamCallback) (*Server, error) {
path := os.Getenv("GOPATH") + "/src/github.com/lucas-clemente/quic-go/example/"
keyData, err := crypto.LoadKeyData(path+"cert.der", path+"key.der")
signer, err := crypto.NewRSASigner(path+"cert.der", path+"key.der")
if err != nil {
return nil, err
}
scfg := handshake.NewServerConfig(crypto.NewCurve25519KEX(), keyData)
scfg := handshake.NewServerConfig(crypto.NewCurve25519KEX(), signer)
return &Server{
keyData: keyData,
signer: signer,
scfg: scfg,
streamCallback: cb,
sessions: map[protocol.ConnectionID]*Session{},