Commit 596e2a37 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

go.crypto/ssh: introduce Signer method, an abstraction of

private keys.

R=agl, jpsugar, jonathan.mark.pittman
CC=golang-dev
https://codereview.appspot.com/13338044

Committer: Adam Langley <agl@golang.org>
parent d6dd1dc1
......@@ -68,10 +68,6 @@ func (c *OpenSSHCertV01) PublicKeyAlgo() string {
return algo
}
func (c *OpenSSHCertV01) RawKey() interface{} {
return c.Key.RawKey()
}
func (c *OpenSSHCertV01) PrivateKeyAlgo() string {
return c.Key.PrivateKeyAlgo()
}
......
......@@ -6,12 +6,7 @@ package ssh
import (
"bytes"
"crypto"
"crypto/dsa"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"io"
"io/ioutil"
"math/big"
......@@ -62,32 +57,23 @@ rrxx26itVhJmcvoUhOjwuzSlP2bE5VHAvkGB352YBg==
// keychain implements the ClientKeyring interface
type keychain struct {
keys []interface{}
keys []Signer
}
func (k *keychain) Key(i int) (PublicKey, error) {
if i < 0 || i >= len(k.keys) {
return nil, nil
}
switch key := k.keys[i].(type) {
case *rsa.PrivateKey:
return NewRSAPublicKey(&key.PublicKey), nil
case *dsa.PrivateKey:
return NewDSAPublicKey(&key.PublicKey), nil
}
panic("unknown key type")
return k.keys[i].PublicKey(), nil
}
func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
hashFunc := crypto.SHA1
h := hashFunc.New()
h.Write(data)
digest := h.Sum(nil)
switch key := k.keys[i].(type) {
case *rsa.PrivateKey:
return rsa.SignPKCS1v15(rand, key, hashFunc, digest)
}
return nil, errors.New("ssh: unknown key type")
return k.keys[i].Sign(rand, data)
}
func (k *keychain) add(key Signer) {
k.keys = append(k.keys, key)
}
func (k *keychain) loadPEM(file string) error {
......@@ -95,15 +81,11 @@ func (k *keychain) loadPEM(file string) error {
if err != nil {
return err
}
block, _ := pem.Decode(buf)
if block == nil {
return errors.New("ssh: no key found")
}
r, err := x509.ParsePKCS1PrivateKey(block.Bytes)
key, err := ParsePrivateKey(buf)
if err != nil {
return err
}
k.keys = append(k.keys, r)
k.add(key)
return nil
}
......@@ -126,8 +108,8 @@ func (cr *keyboardInteractive) Challenge(user string, instruction string, questi
// reused internally by tests
var (
rsakey *rsa.PrivateKey
dsakey *dsa.PrivateKey
rsaKey Signer
dsaKey Signer
clientKeychain = new(keychain)
clientPassword = password("tiger")
serverConfig = &ServerConfig{
......@@ -135,8 +117,7 @@ var (
return user == "testuser" && pass == string(clientPassword)
},
PublicKeyCallback: func(conn *ServerConn, user, algo string, pubkey []byte) bool {
rsaKey := &clientKeychain.keys[0].(*rsa.PrivateKey).PublicKey
key := NewRSAPublicKey(rsaKey)
key, _ := clientKeychain.Key(0)
expected := MarshalPublicKey(key)
algoname := key.PublicKeyAlgo()
return user == "testuser" && algo == algoname && bytes.Equal(pubkey, expected)
......@@ -157,21 +138,26 @@ var (
)
func init() {
if err := serverConfig.SetRSAPrivateKey([]byte(testServerPrivateKey)); err != nil {
var err error
rsaKey, err = ParsePrivateKey([]byte(testServerPrivateKey))
if err != nil {
panic("unable to set private key: " + err.Error())
}
rawDSAKey := new(dsa.PrivateKey)
block, _ := pem.Decode([]byte(testClientPrivateKey))
rsakey, _ = x509.ParsePKCS1PrivateKey(block.Bytes)
clientKeychain.keys = append(clientKeychain.keys, rsakey)
dsakey = new(dsa.PrivateKey)
// taken from crypto/dsa/dsa_test.go
dsakey.P, _ = new(big.Int).SetString("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF", 16)
dsakey.Q, _ = new(big.Int).SetString("E1D3391245933D68A0714ED34BBCB7A1F422B9C1", 16)
dsakey.G, _ = new(big.Int).SetString("634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA", 16)
dsakey.Y, _ = new(big.Int).SetString("32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2", 16)
dsakey.X, _ = new(big.Int).SetString("5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A", 16)
rawDSAKey.P, _ = new(big.Int).SetString("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF", 16)
rawDSAKey.Q, _ = new(big.Int).SetString("E1D3391245933D68A0714ED34BBCB7A1F422B9C1", 16)
rawDSAKey.G, _ = new(big.Int).SetString("634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA", 16)
rawDSAKey.Y, _ = new(big.Int).SetString("32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2", 16)
rawDSAKey.X, _ = new(big.Int).SetString("5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A", 16)
dsaKey, err = NewSignerFromKey(rawDSAKey)
if err != nil {
panic("NewSignerFromKey: " + err.Error())
}
clientKeychain.add(rsaKey)
serverConfig.AddHostKey(rsaKey)
}
// newMockAuthServer creates a new Server bound to
......@@ -287,7 +273,8 @@ func TestClientAuthWrongKeyboardInteractive(t *testing.T) {
// the mock server will only authenticate ssh-rsa keys
func TestClientAuthInvalidPublicKey(t *testing.T) {
kc := new(keychain)
kc.keys = append(kc.keys, dsakey)
kc.add(dsaKey)
config := &ClientConfig{
User: "testuser",
Auth: []ClientAuth{
......@@ -305,7 +292,8 @@ func TestClientAuthInvalidPublicKey(t *testing.T) {
// the client should authenticate with the second key
func TestClientAuthRSAandDSA(t *testing.T) {
kc := new(keychain)
kc.keys = append(kc.keys, dsakey, rsakey)
kc.add(dsaKey)
kc.add(rsaKey)
config := &ClientConfig{
User: "testuser",
Auth: []ClientAuth{
......@@ -321,7 +309,7 @@ func TestClientAuthRSAandDSA(t *testing.T) {
func TestClientHMAC(t *testing.T) {
kc := new(keychain)
kc.keys = append(kc.keys, rsakey)
kc.add(rsaKey)
for _, mac := range DefaultMACOrder {
config := &ClientConfig{
User: "testuser",
......@@ -343,7 +331,6 @@ func TestClientHMAC(t *testing.T) {
// issue 4285.
func TestClientUnsupportedCipher(t *testing.T) {
kc := new(keychain)
kc.keys = append(kc.keys, rsakey)
config := &ClientConfig{
User: "testuser",
Auth: []ClientAuth{
......@@ -362,7 +349,6 @@ func TestClientUnsupportedCipher(t *testing.T) {
func TestClientUnsupportedKex(t *testing.T) {
kc := new(keychain)
kc.keys = append(kc.keys, rsakey)
config := &ClientConfig{
User: "testuser",
Auth: []ClientAuth{
......
......@@ -6,7 +6,6 @@ package ssh
import (
"crypto"
"crypto/elliptic"
"errors"
"fmt"
"math/big"
......@@ -223,19 +222,6 @@ func (c *CryptoConfig) macs() []string {
return c.MACs
}
// ecHash returns the hash to match the given elliptic curve, see RFC
// 5656, section 6.2.1
func ecHash(curve elliptic.Curve) crypto.Hash {
bitSize := curve.Params().BitSize
switch {
case bitSize <= 256:
return crypto.SHA256
case bitSize <= 384:
return crypto.SHA384
}
return crypto.SHA512
}
// serialize a signed slice according to RFC 4254 6.6. The name should
// be a key type name, rather than a cert type name.
func serializeSignature(name string, sig []byte) []byte {
......
......@@ -23,14 +23,18 @@ func ExampleListen() {
},
}
pemBytes, err := ioutil.ReadFile("id_rsa")
privateBytes, err := ioutil.ReadFile("id_rsa")
if err != nil {
panic("Failed to load private key")
}
if err = config.SetRSAPrivateKey(pemBytes); err != nil {
private, err := ParsePrivateKey(privateBytes)
if err != nil {
panic("Failed to parse private key")
}
config.AddHostKey(private)
// Once a ServerConfig has been configured, connections can be
// accepted.
listener, err := Listen("tcp", "0.0.0.0:2022", config)
......
......@@ -11,7 +11,12 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"io"
"math/big"
)
......@@ -209,12 +214,17 @@ type PublicKey interface {
// Verify that sig is a signature on the given data using this
// key. This function will hash the data appropriately first.
Verify(data []byte, sigBlob []byte) bool
// RawKey returns the underlying object, eg. *rsa.PublicKey.
RawKey() interface{}
}
// TODO(hanwen): define PrivateKey too.
// A Signer is can create signatures that verify against a public key.
type Signer interface {
// PublicKey returns an associated PublicKey instance.
PublicKey() PublicKey
// Sign returns raw signature for the given data. This method
// will apply the hash specified for the keytype to the data.
Sign(rand io.Reader, data []byte) ([]byte, error)
}
type rsaPublicKey rsa.PublicKey
......@@ -223,11 +233,7 @@ func (r *rsaPublicKey) PrivateKeyAlgo() string {
}
func (r *rsaPublicKey) PublicKeyAlgo() string {
return "ssh-rsa"
}
func (r *rsaPublicKey) RawKey() interface{} {
return (*rsa.PublicKey)(r)
return r.PrivateKeyAlgo()
}
// parseRSA parses an RSA key according to RFC 4253, section 6.6.
......@@ -250,7 +256,7 @@ func parseRSA(in []byte) (out PublicKey, rest []byte, ok bool) {
}
ok = true
return NewRSAPublicKey(key), in, ok
return (*rsaPublicKey)(key), in, ok
}
func (r *rsaPublicKey) Marshal() []byte {
......@@ -273,8 +279,19 @@ func (r *rsaPublicKey) Verify(data []byte, sig []byte) bool {
return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig) == nil
}
func NewRSAPublicKey(k *rsa.PublicKey) PublicKey {
return (*rsaPublicKey)(k)
type rsaPrivateKey struct {
*rsa.PrivateKey
}
func (r *rsaPrivateKey) PublicKey() PublicKey {
return (*rsaPublicKey)(&r.PrivateKey.PublicKey)
}
func (r *rsaPrivateKey) Sign(rand io.Reader, data []byte) ([]byte, error) {
h := crypto.SHA1.New()
h.Write(data)
digest := h.Sum(nil)
return rsa.SignPKCS1v15(rand, r.PrivateKey, crypto.SHA1, digest)
}
type dsaPublicKey dsa.PublicKey
......@@ -282,11 +299,9 @@ type dsaPublicKey dsa.PublicKey
func (r *dsaPublicKey) PrivateKeyAlgo() string {
return "ssh-dss"
}
func (r *dsaPublicKey) PublicKeyAlgo() string {
return "ssh-dss"
}
func (r *dsaPublicKey) RawKey() interface{} {
return (*dsa.PublicKey)(r)
return r.PrivateKeyAlgo()
}
// parseDSA parses an DSA key according to RFC 4253, section 6.6.
......@@ -310,7 +325,7 @@ func parseDSA(in []byte) (out PublicKey, rest []byte, ok bool) {
}
ok = true
return NewDSAPublicKey(key), in, ok
return (*dsaPublicKey)(key), in, ok
}
func (r *dsaPublicKey) Marshal() []byte {
......@@ -347,21 +362,33 @@ func (k *dsaPublicKey) Verify(data []byte, sigBlob []byte) bool {
return dsa.Verify((*dsa.PublicKey)(k), digest, r, s)
}
func NewDSAPublicKey(k *dsa.PublicKey) PublicKey {
return (*dsaPublicKey)(k)
type dsaPrivateKey struct {
*dsa.PrivateKey
}
type ecdsaPublicKey ecdsa.PublicKey
func NewECDSAPublicKey(k *ecdsa.PublicKey) PublicKey {
return (*ecdsaPublicKey)(k)
func (k *dsaPrivateKey) PublicKey() PublicKey {
return (*dsaPublicKey)(&k.PrivateKey.PublicKey)
}
func (r *ecdsaPublicKey) RawKey() interface{} {
return (*ecdsa.PublicKey)(r)
func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) ([]byte, error) {
h := crypto.SHA1.New()
h.Write(data)
digest := h.Sum(nil)
r, s, err := dsa.Sign(rand, k.PrivateKey, digest)
if err != nil {
return nil, err
}
sig := make([]byte, 40)
copy(sig[:20], r.Bytes())
copy(sig[20:], s.Bytes())
return sig, nil
}
type ecdsaPublicKey ecdsa.PublicKey
func (key *ecdsaPublicKey) PrivateKeyAlgo() string {
return "ecdh-sha2-" + key.nistID()
return "ecdsa-sha2-" + key.nistID()
}
func (key *ecdsaPublicKey) nistID() string {
......@@ -376,29 +403,25 @@ func (key *ecdsaPublicKey) nistID() string {
panic("ssh: unsupported ecdsa key size")
}
// RFC 5656, section 6.2.1 (for ECDSA).
func (key *ecdsaPublicKey) hash() crypto.Hash {
switch key.Params().BitSize {
case 256:
func supportedEllipticCurve(curve elliptic.Curve) bool {
return (curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521())
}
// ecHash returns the hash to match the given elliptic curve, see RFC
// 5656, section 6.2.1
func ecHash(curve elliptic.Curve) crypto.Hash {
bitSize := curve.Params().BitSize
switch {
case bitSize <= 256:
return crypto.SHA256
case 384:
case bitSize <= 384:
return crypto.SHA384
case 521:
return crypto.SHA512
}
panic("ssh: unsupported ecdsa key size")
return crypto.SHA512
}
func (key *ecdsaPublicKey) PublicKeyAlgo() string {
switch key.Params().BitSize {
case 256:
return KeyAlgoECDSA256
case 384:
return KeyAlgoECDSA384
case 521:
return KeyAlgoECDSA521
}
panic("ssh: unsupported ecdsa key size")
return key.PrivateKeyAlgo()
}
// parseECDSA parses an ECDSA key according to RFC 5656, section 3.1.
......@@ -432,7 +455,7 @@ func parseECDSA(in []byte) (out PublicKey, rest []byte, ok bool) {
ok = false
return
}
return NewECDSAPublicKey(key), in, ok
return (*ecdsaPublicKey)(key), in, ok
}
func (key *ecdsaPublicKey) Marshal() []byte {
......@@ -450,7 +473,7 @@ func (key *ecdsaPublicKey) Marshal() []byte {
}
func (key *ecdsaPublicKey) Verify(data []byte, sigBlob []byte) bool {
h := key.hash().New()
h := ecHash(key.Curve).New()
h.Write(data)
digest := h.Sum(nil)
......@@ -468,3 +491,100 @@ func (key *ecdsaPublicKey) Verify(data []byte, sigBlob []byte) bool {
}
return ecdsa.Verify((*ecdsa.PublicKey)(key), digest, r, s)
}
type ecdsaPrivateKey struct {
*ecdsa.PrivateKey
}
func (k *ecdsaPrivateKey) PublicKey() PublicKey {
return (*ecdsaPublicKey)(&k.PrivateKey.PublicKey)
}
func (k *ecdsaPrivateKey) Sign(rand io.Reader, data []byte) ([]byte, error) {
h := ecHash(k.PrivateKey.PublicKey.Curve).New()
h.Write(data)
digest := h.Sum(nil)
r, s, err := ecdsa.Sign(rand, k.PrivateKey, digest)
if err != nil {
return nil, err
}
sig := make([]byte, intLength(r)+intLength(s))
rest := marshalInt(sig, r)
marshalInt(rest, s)
return sig, nil
}
// NewPrivateKey takes a pointer to rsa, dsa or ecdsa PrivateKey
// returns a corresponding Signer instance. EC keys should use P256,
// P384 or P521.
func NewSignerFromKey(k interface{}) (Signer, error) {
var sshKey Signer
switch t := k.(type) {
case *rsa.PrivateKey:
sshKey = &rsaPrivateKey{t}
case *dsa.PrivateKey:
sshKey = &dsaPrivateKey{t}
case *ecdsa.PrivateKey:
if !supportedEllipticCurve(t.Curve) {
return nil, errors.New("ssh: only P256, P384 and P521 EC keys are supported.")
}
sshKey = &ecdsaPrivateKey{t}
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", k)
}
return sshKey, nil
}
// NewPublicKey takes a pointer to rsa, dsa or ecdsa PublicKey
// and returns a corresponding ssh PublicKey instance. EC keys should use P256, P384 or P521.
func NewPublicKey(k interface{}) (PublicKey, error) {
var sshKey PublicKey
switch t := k.(type) {
case *rsa.PublicKey:
sshKey = (*rsaPublicKey)(t)
case *ecdsa.PublicKey:
if !supportedEllipticCurve(t.Curve) {
return nil, errors.New("ssh: only P256, P384 and P521 EC keys are supported.")
}
sshKey = (*ecdsaPublicKey)(t)
case *dsa.PublicKey:
sshKey = (*dsaPublicKey)(t)
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", k)
}
return sshKey, nil
}
// ParsePublicKey parses a PEM encoded private key. Currently, only
// PKCS#1, RSA and ECDSA private keys are supported.
func ParsePrivateKey(pemBytes []byte) (Signer, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
return nil, errors.New("ssh: no key found")
}
var rawkey interface{}
switch block.Type {
case "RSA PRIVATE KEY":
rsa, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
rawkey = rsa
case "EC PRIVATE KEY":
ec, err := x509.ParseECPrivateKey(block.Bytes)
if err != nil {
return nil, err
}
rawkey = ec
// TODO(hanwen): find doc for format and implement PEM parsing
// for DSA keys.
default:
return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
}
return NewSignerFromKey(rawkey)
}
package ssh
import (
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"reflect"
"strings"
"testing"
)
func TestRSAMarshal(t *testing.T) {
k0 := &rsakey.PublicKey
k1 := NewRSAPublicKey(k0)
k2, rest, ok := ParsePublicKey(MarshalPublicKey(k1))
if !ok {
t.Errorf("could not parse back Blob output")
var ecdsaKey Signer
func rawKey(pub PublicKey) interface{} {
switch k := pub.(type) {
case *rsaPublicKey:
return (*rsa.PublicKey)(k)
case *dsaPublicKey:
return (*dsa.PublicKey)(k)
case *ecdsaPublicKey:
return (*ecdsa.PublicKey)(k)
}
panic("unknown key type")
}
func TestKeyMarshalParse(t *testing.T) {
keys := []Signer{rsaKey, dsaKey, ecdsaKey}
for _, priv := range keys {
pub := priv.PublicKey()
roundtrip, rest, ok := ParsePublicKey(MarshalPublicKey(pub))
if !ok {
t.Errorf("ParsePublicKey(%T) failed", pub)
}
if len(rest) > 0 {
t.Errorf("ParsePublicKey(%T): trailing junk", pub)
}
k1 := rawKey(pub)
k2 := rawKey(roundtrip)
if !reflect.DeepEqual(k1, k2) {
t.Errorf("got %#v in roundtrip, want %#v", k2, k1)
}
}
if len(rest) > 0 {
t.Errorf("trailing junk in RSA Blob() output")
}
func TestUnsupportedCurves(t *testing.T) {
raw, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
if err != nil {
t.Fatalf("GenerateKey: %v", err)
}
if _, err = NewSignerFromKey(raw); err == nil || !strings.Contains(err.Error(), "only P256") {
t.Fatalf("NewPrivateKey should not succeed with P224, got: %v", err)
}
if _, err = NewPublicKey(&raw.PublicKey); err == nil || !strings.Contains(err.Error(), "only P256") {
t.Fatalf("NewPublicKey should not succeed with P224, got: %v", err)
}
if !reflect.DeepEqual(k0, k2.RawKey().(*rsa.PublicKey)) {
t.Errorf("got %#v in roundtrip, want %#v", k2.RawKey(), k0)
}
func TestNewPublicKey(t *testing.T) {
keys := []Signer{rsaKey, dsaKey, ecdsaKey}
for _, k := range keys {
raw := rawKey(k.PublicKey())
pub, err := NewPublicKey(raw)
if err != nil {
t.Errorf("NewPublicKey(%#v): %v", raw, err)
}
if !reflect.DeepEqual(k.PublicKey(), pub) {
t.Errorf("NewPublicKey(%#v) = %#v, want %#v", raw, pub, k.PublicKey())
}
}
}
func TestRSAKeyVerify(t *testing.T) {
pub := NewRSAPublicKey(&rsakey.PublicKey)
func TestKeySignVerify(t *testing.T) {
keys := []Signer{rsaKey, dsaKey, ecdsaKey}
for _, priv := range keys {
pub := priv.PublicKey()
data := []byte("sign me")
h := crypto.SHA1.New()
h.Write(data)
digest := h.Sum(nil)
data := []byte("sign me")
sig, err := priv.Sign(rand.Reader, data)
if err != nil {
t.Fatalf("Sign(%T): %v", priv, err)
}
if !pub.Verify(data, sig) {
t.Errorf("publicKey.Verify(%T) failed", priv)
}
}
}
sig, err := rsa.SignPKCS1v15(rand.Reader, rsakey, crypto.SHA1, digest)
func TestParseRSAPrivateKey(t *testing.T) {
key, err := ParsePrivateKey([]byte(testServerPrivateKey))
if err != nil {
t.Fatalf("SignPKCS1v15: %v", err)
t.Fatalf("ParsePrivateKey: %v", err)
}
rsa, ok := key.(*rsaPrivateKey)
if !ok {
t.Fatalf("got %T, want *rsa.PrivateKey", rsa)
}
if !pub.Verify(data, sig) {
t.Errorf("publicKey.Verify failed")
if err := rsa.Validate(); err != nil {
t.Errorf("Validate: %v", err)
}
}
func TestDSAMarshal(t *testing.T) {
k0 := &dsakey.PublicKey
k1 := NewDSAPublicKey(k0)
k2, rest, ok := ParsePublicKey(MarshalPublicKey(k1))
if !ok {
t.Errorf("could not parse back Blob output")
func TestParseECPrivateKey(t *testing.T) {
// Taken from the data in test/ .
pem := []byte(`-----BEGIN EC PRIVATE KEY-----
MHcCAQEEINGWx0zo6fhJ/0EAfrPzVFyFC9s18lBt3cRoEDhS3ARooAoGCCqGSM49
AwEHoUQDQgAEi9Hdw6KvZcWxfg2IDhA7UkpDtzzt6ZqJXSsFdLd+Kx4S3Sx4cVO+
6/ZOXRnPmNAlLUqjShUsUBBngG0u2fqEqA==
-----END EC PRIVATE KEY-----`)
key, err := ParsePrivateKey(pem)
if err != nil {
t.Fatalf("ParsePrivateKey: %v", err)
}
if len(rest) > 0 {
t.Errorf("trailing junk in DSA Blob() output")
ecKey, ok := key.(*ecdsaPrivateKey)
if !ok {
t.Fatalf("got %T, want *ecdsaPrivateKey", ecKey)
}
if !reflect.DeepEqual(k0, k2.RawKey().(*dsa.PublicKey)) {
t.Errorf("got %#v in roundtrip, want %#v", k2.RawKey(), k0)
if !validateECPublicKey(ecKey.Curve, ecKey.X, ecKey.Y) {
t.Fatalf("public key does not validate.")
}
}
// TODO(hanwen): test for ECDSA marshal.
func init() {
raw, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
ecdsaKey, _ = NewSignerFromKey(raw)
}
......@@ -10,10 +10,7 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/binary"
"encoding/pem"
"errors"
"io"
"math/big"
......@@ -24,11 +21,7 @@ import (
)
type ServerConfig struct {
rsa *rsa.PrivateKey
// rsaSerialized is the serialized form of the public key that
// corresponds to the private key held in the rsa field.
rsaSerialized []byte
hostKeys []Signer
// Rand provides the source of entropy for key exchange. If Rand is
// nil, the cryptographic random reader in package crypto/rand will
......@@ -69,21 +62,29 @@ func (c *ServerConfig) rand() io.Reader {
return c.Rand
}
// AddHostKey adds a private key as a host key. If an existing host
// key exists with the same algorithm, it is overwritten.
func (s *ServerConfig) AddHostKey(key Signer) {
for i, k := range s.hostKeys {
if k.PublicKey().PublicKeyAlgo() == key.PublicKey().PublicKeyAlgo() {
s.hostKeys[i] = key
return