go.crypto/ssh: Add certificate verification, step up support for authorized keys

R=agl, hanwen, jpsugar, dave
CC=golang-dev
https://golang.org/cl/14540051
This commit is contained in:
Jonathan Pittman
2013-10-22 15:12:41 -04:00
committed by Adam Langley
parent f5f25bdad0
commit 9112f50fcd
4 changed files with 187 additions and 103 deletions
+54 -37
View File
@@ -1,19 +1,66 @@
package ssh
import (
"bytes"
"crypto/dsa"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"encoding/base64"
"reflect"
"strings"
"testing"
"time"
)
var ecdsaKey Signer
var (
ecdsaKey Signer
ecdsa384Key Signer
ecdsa521Key Signer
testCertKey Signer
)
type testSigner struct {
Signer
pub PublicKey
}
func (ts *testSigner) PublicKey() PublicKey {
if ts.pub != nil {
return ts.pub
}
return ts.Signer.PublicKey()
}
func init() {
raw256, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
ecdsaKey, _ = NewSignerFromKey(raw256)
raw384, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
ecdsa384Key, _ = NewSignerFromKey(raw384)
raw521, _ := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
ecdsa521Key, _ = NewSignerFromKey(raw521)
// Create a cert and sign it for use in tests.
testCert := &OpenSSHCertV01{
Nonce: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil
Key: ecdsaKey.PublicKey(),
ValidPrincipals: []string{"gopher1", "gopher2"}, // increases test coverage
ValidAfter: time.Now().Truncate(time.Second),
ValidBefore: time.Now().Truncate(time.Second).Add(time.Hour),
Reserved: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil
SignatureKey: rsaKey.PublicKey(),
}
sigBytes, _ := rsaKey.Sign(rand.Reader, testCert.BytesForSigning())
testCert.Signature = &signature{
Format: testCert.SignatureKey.PublicKeyAlgo(),
Blob: sigBytes,
}
testCertKey = &testSigner{
Signer: ecdsaKey,
pub: testCert,
}
}
func rawKey(pub PublicKey) interface{} {
switch k := pub.(type) {
@@ -23,12 +70,14 @@ func rawKey(pub PublicKey) interface{} {
return (*dsa.PublicKey)(k)
case *ecdsaPublicKey:
return (*ecdsa.PublicKey)(k)
case *OpenSSHCertV01:
return k
}
panic("unknown key type")
}
func TestKeyMarshalParse(t *testing.T) {
keys := []Signer{rsaKey, dsaKey, ecdsaKey}
keys := []Signer{rsaKey, dsaKey, ecdsaKey, ecdsa384Key, ecdsa521Key, testCertKey}
for _, priv := range keys {
pub := priv.PublicKey()
roundtrip, rest, ok := ParsePublicKey(MarshalPublicKey(pub))
@@ -79,7 +128,7 @@ func TestNewPublicKey(t *testing.T) {
}
func TestKeySignVerify(t *testing.T) {
keys := []Signer{rsaKey, dsaKey, ecdsaKey}
keys := []Signer{rsaKey, dsaKey, ecdsaKey, testCertKey}
for _, priv := range keys {
pub := priv.PublicKey()
@@ -164,35 +213,3 @@ func TestParseDSA(t *testing.T) {
t.Error("Verify failed.")
}
}
func TestParseCert(t *testing.T) {
// Cert generated by ssh-keygen 6.0p1 Debian-4.
// % ssh-keygen -s ca-key -I test user-key
b64data := "AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgb1srW/W3ZDjYAO45xLYAwzHBDLsJ4Ux6ICFIkTjb1LEAAAADAQABAAAAYQCkoR51poH0wE8w72cqSB8Sszx+vAhzcMdCO0wqHTj7UNENHWEXGrU0E0UQekD7U+yhkhtoyjbPOVIP7hNa6aRk/ezdh/iUnCIt4Jt1v3Z1h1P+hA4QuYFMHNB+rmjPwAcAAAAAAAAAAAAAAAEAAAAEdGVzdAAAAAAAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAHcAAAAHc3NoLXJzYQAAAAMBAAEAAABhANFS2kaktpSGc+CcmEKPyw9mJC4nZKxHKTgLVZeaGbFZOvJTNzBspQHdy7Q1uKSfktxpgjZnksiu/tFF9ngyY2KFoc+U88ya95IZUycBGCUbBQ8+bhDtw/icdDGQD5WnUwAAAG8AAAAHc3NoLXJzYQAAAGC8Y9Z2LQKhIhxf52773XaWrXdxP0t3GBVo4A10vUWiYoAGepr6rQIoGGXFxT4B9Gp+nEBJjOwKDXPrAevow0T9ca8gZN+0ykbhSrXLE5Ao48rqr3zP4O1/9P7e6gp0gw8="
data, err := base64.StdEncoding.DecodeString(b64data)
if err != nil {
t.Fatal("base64.StdEncoding.DecodeString: ", err)
}
key, rest, ok := ParsePublicKey(data)
if !ok {
t.Fatalf("could not parse certificate")
}
if len(rest) > 0 {
t.Errorf("rest: got %q, want empty", rest)
}
_, ok = key.(*OpenSSHCertV01)
if !ok {
t.Fatalf("got %#v, want *OpenSSHCertV01", key)
}
marshaled := MarshalPublicKey(key)
if !bytes.Equal(data, marshaled) {
t.Errorf("marshaled certificate does not match original: got %q, want %q", marshaled, data)
}
}
func init() {
raw, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
ecdsaKey, _ = NewSignerFromKey(raw)
}