|
|
|
|
@ -2,24 +2,17 @@ package ssh
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"crypto/rand"
|
|
|
|
|
"errors"
|
|
|
|
|
"strconv"
|
|
|
|
|
"crypto/dsa"
|
|
|
|
|
"crypto/ecdsa"
|
|
|
|
|
"crypto/rsa"
|
|
|
|
|
"fmt"
|
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"github.com/hashicorp/packer/common/uuid"
|
|
|
|
|
"golang.org/x/crypto/ed25519"
|
|
|
|
|
gossh "golang.org/x/crypto/ssh"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// expected contains the data that the key pair should contain.
|
|
|
|
|
type expected struct {
|
|
|
|
|
kind KeyPairType
|
|
|
|
|
bits int
|
|
|
|
|
desc string
|
|
|
|
|
name string
|
|
|
|
|
data []byte
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
pemRsa1024 = `-----BEGIN RSA PRIVATE KEY-----
|
|
|
|
|
MIICWwIBAAKBgQDJEMFPpTBiWNDb3qEIPTSeEnIP8FZdBpG8njOrclcMoQQNhzZ+
|
|
|
|
|
@ -151,401 +144,306 @@ QBAgM=
|
|
|
|
|
`
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func (o expected) matches(kp KeyPair) error {
|
|
|
|
|
if o.kind.String() == "" {
|
|
|
|
|
return errors.New("expected kind's value cannot be empty")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if o.bits <= 0 {
|
|
|
|
|
return errors.New("expected bits' value cannot be less than or equal to 0")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if o.desc == "" {
|
|
|
|
|
return errors.New("expected description's value cannot be empty")
|
|
|
|
|
func TestNewKeyPair_Default(t *testing.T) {
|
|
|
|
|
kp, err := NewKeyPair(CreateKeyPairConfig{})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(o.data) == 0 {
|
|
|
|
|
return errors.New("expected random data value cannot be nothing")
|
|
|
|
|
err = verifyEcdsaKeyPair(kp, expectedData{
|
|
|
|
|
bits: 521,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if kp.Type() != o.kind {
|
|
|
|
|
return errors.New("key pair type should be " + o.kind.String() +
|
|
|
|
|
" - got '" + kp.Type().String() + "'")
|
|
|
|
|
func TestNewKeyPair_ECDSA_Default(t *testing.T) {
|
|
|
|
|
kp, err := NewKeyPair(CreateKeyPairConfig{
|
|
|
|
|
Type: Ecdsa,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if kp.Bits() != o.bits {
|
|
|
|
|
return errors.New("key pair bits should be " + strconv.Itoa(o.bits) +
|
|
|
|
|
" - got " + strconv.Itoa(kp.Bits()))
|
|
|
|
|
err = verifyEcdsaKeyPair(kp, expectedData{
|
|
|
|
|
bits: 521,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(o.name) > 0 && kp.Name() != o.name {
|
|
|
|
|
return errors.New("key pair name should be '" + o.name +
|
|
|
|
|
"' - got '" + kp.Name() + "'")
|
|
|
|
|
}
|
|
|
|
|
func TestNewKeyPair_ECDSA_Positive(t *testing.T) {
|
|
|
|
|
for _, bits := range []int{521, 384, 256} {
|
|
|
|
|
config := CreateKeyPairConfig{
|
|
|
|
|
Type: Ecdsa,
|
|
|
|
|
Bits: bits,
|
|
|
|
|
Name: uuid.TimeOrderedUUID(),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if kp.Description() != o.desc {
|
|
|
|
|
return errors.New("key pair description should be '" +
|
|
|
|
|
o.desc + "' - got '" + kp.Description() + "'")
|
|
|
|
|
}
|
|
|
|
|
kp, err := NewKeyPair(config)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err := o.verifyPublicKeyAuthorizedKeysFormat(kp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
err = verifyEcdsaKeyPair(kp, expectedData{
|
|
|
|
|
bits: bits,
|
|
|
|
|
name: config.Name,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = o.verifyKeyPair(kp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
func TestNewKeyPair_ECDSA_Negative(t *testing.T) {
|
|
|
|
|
for _, bits := range []int{224, 1, 2, 3} {
|
|
|
|
|
_, err := NewKeyPair(CreateKeyPairConfig{
|
|
|
|
|
Type: Ecdsa,
|
|
|
|
|
Bits: bits,
|
|
|
|
|
})
|
|
|
|
|
if err == nil {
|
|
|
|
|
t.Fatalf("expected key pair generation to fail for %d bits", bits)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (o expected) verifyPublicKeyAuthorizedKeysFormat(kp KeyPair) error {
|
|
|
|
|
newLines := []NewLineOption{
|
|
|
|
|
UnixNewLine,
|
|
|
|
|
NoNewLine,
|
|
|
|
|
WindowsNewLine,
|
|
|
|
|
}
|
|
|
|
|
func TestNewKeyPair_RSA_Positive(t *testing.T) {
|
|
|
|
|
for _, bits := range []int{4096, 2048} {
|
|
|
|
|
config := CreateKeyPairConfig{
|
|
|
|
|
Type: Rsa,
|
|
|
|
|
Bits: bits,
|
|
|
|
|
Name: uuid.TimeOrderedUUID(),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, nl := range newLines {
|
|
|
|
|
publicKeyAk := kp.PublicKeyAuthorizedKeysLine(nl)
|
|
|
|
|
kp, err := NewKeyPair(config)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(publicKeyAk) < 2 {
|
|
|
|
|
return errors.New("expected public key in authorized keys format to be at least 2 bytes")
|
|
|
|
|
err = verifyRsaKeyPair(kp, expectedData{
|
|
|
|
|
bits: config.Bits,
|
|
|
|
|
name: config.Name,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch nl {
|
|
|
|
|
case NoNewLine:
|
|
|
|
|
if publicKeyAk[len(publicKeyAk)-1] == '\n' {
|
|
|
|
|
return errors.New("public key in authorized keys format has trailing new line when none was specified")
|
|
|
|
|
}
|
|
|
|
|
case UnixNewLine:
|
|
|
|
|
if publicKeyAk[len(publicKeyAk)-1] != '\n' {
|
|
|
|
|
return errors.New("public key in authorized keys format does not have unix new line when unix was specified")
|
|
|
|
|
}
|
|
|
|
|
if string(publicKeyAk[len(publicKeyAk)-2:]) == WindowsNewLine.String() {
|
|
|
|
|
return errors.New("public key in authorized keys format has windows new line when unix was specified")
|
|
|
|
|
}
|
|
|
|
|
case WindowsNewLine:
|
|
|
|
|
if string(publicKeyAk[len(publicKeyAk)-2:]) != WindowsNewLine.String() {
|
|
|
|
|
return errors.New("public key in authorized keys format does not have windows new line when windows was specified")
|
|
|
|
|
}
|
|
|
|
|
func TestKeyPairFromPrivateKey(t *testing.T) {
|
|
|
|
|
m := map[string]fromPrivateExpectedData{
|
|
|
|
|
pemRsa1024: {
|
|
|
|
|
t: Rsa,
|
|
|
|
|
d: expectedData{
|
|
|
|
|
bits: 1024,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
pemRsa2048: {
|
|
|
|
|
t: Rsa,
|
|
|
|
|
d: expectedData{
|
|
|
|
|
bits: 2048,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
pemOpenSshRsa1024: {
|
|
|
|
|
t: Rsa,
|
|
|
|
|
d: expectedData{
|
|
|
|
|
bits: 1024,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
pemOpenSshRsa2048: {
|
|
|
|
|
t: Rsa,
|
|
|
|
|
d: expectedData{
|
|
|
|
|
bits: 2048,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
pemDsa: {
|
|
|
|
|
t: Dsa,
|
|
|
|
|
d: expectedData{
|
|
|
|
|
bits: 1024,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
pemEcdsa384: {
|
|
|
|
|
t: Ecdsa,
|
|
|
|
|
d: expectedData{
|
|
|
|
|
bits: 384,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
pemEcdsa521: {
|
|
|
|
|
t: Ecdsa,
|
|
|
|
|
d: expectedData{
|
|
|
|
|
bits: 521,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
pemOpenSshEd25519: {
|
|
|
|
|
t: Ed25519,
|
|
|
|
|
d: expectedData{
|
|
|
|
|
bits: 256,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for rawPrivateKey, expected := range m {
|
|
|
|
|
kp, err := KeyPairFromPrivateKey(FromPrivateKeyConfig{
|
|
|
|
|
RawPrivateKeyPemBlock: []byte(rawPrivateKey),
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(o.name) > 0 {
|
|
|
|
|
if len(publicKeyAk) < len(o.name) {
|
|
|
|
|
return errors.New("public key in authorized keys format is shorter than the key pair's name")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
suffix := []byte{' '}
|
|
|
|
|
suffix = append(suffix, o.name...)
|
|
|
|
|
suffix = append(suffix, nl.Bytes()...)
|
|
|
|
|
if !bytes.HasSuffix(publicKeyAk, suffix) {
|
|
|
|
|
return errors.New("public key in authorized keys format with name does not have name in suffix - got '" +
|
|
|
|
|
string(publicKeyAk) + "'")
|
|
|
|
|
}
|
|
|
|
|
switch expected.t {
|
|
|
|
|
case Dsa:
|
|
|
|
|
err = verifyDsaKeyPair(kp, expected)
|
|
|
|
|
case Ecdsa:
|
|
|
|
|
err = verifyEcdsaKeyPair(kp, expected.d)
|
|
|
|
|
case Ed25519:
|
|
|
|
|
err = verifyEd25519KeyPair(kp, expected)
|
|
|
|
|
case Rsa:
|
|
|
|
|
err = verifyRsaKeyPair(kp, expected.d)
|
|
|
|
|
default:
|
|
|
|
|
err = fmt.Errorf("unexected SSH key pair type %s", expected.t.String())
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
type fromPrivateExpectedData struct {
|
|
|
|
|
t KeyPairType
|
|
|
|
|
d expectedData
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (o expected) verifyKeyPair(kp KeyPair) error {
|
|
|
|
|
signer, err := gossh.ParsePrivateKey(kp.PrivateKeyPemBlock())
|
|
|
|
|
type expectedData struct {
|
|
|
|
|
bits int
|
|
|
|
|
name string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func verifyEcdsaKeyPair(kp KeyPair, e expectedData) error {
|
|
|
|
|
privateKey, err := gossh.ParseRawPrivateKey(kp.PrivateKeyPemBlock)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.New("failed to parse private key during verification - " + err.Error())
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
signature, err := signer.Sign(rand.Reader, o.data)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.New("failed to sign test data during verification - " + err.Error())
|
|
|
|
|
pk, ok := privateKey.(*ecdsa.PrivateKey)
|
|
|
|
|
if !ok {
|
|
|
|
|
return fmt.Errorf("private key should be *ecdsa.PrivateKey")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = signer.PublicKey().Verify(o.data, signature)
|
|
|
|
|
if pk.Curve.Params().BitSize != e.bits {
|
|
|
|
|
return fmt.Errorf("bit size should be %d - got %d", e.bits, pk.Curve.Params().BitSize)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
publicKey, err := gossh.NewPublicKey(&pk.PublicKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.New("failed to verify test data - " + err.Error())
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expectedBytes := bytes.TrimSuffix(gossh.MarshalAuthorizedKey(publicKey), []byte("\n"))
|
|
|
|
|
if len(e.name) > 0 {
|
|
|
|
|
expectedBytes = append(expectedBytes, ' ')
|
|
|
|
|
expectedBytes = append(expectedBytes, e.name...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !bytes.Equal(expectedBytes, kp.PublicKeyAuthorizedKeysLine) {
|
|
|
|
|
return fmt.Errorf("authorized keys line should be:\n'%s'\nGot:\n'%s'",
|
|
|
|
|
string(expectedBytes), string(kp.PublicKeyAuthorizedKeysLine))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDefaultKeyPairBuilder_Build_Default(t *testing.T) {
|
|
|
|
|
kp, err := NewKeyPairBuilder().Build()
|
|
|
|
|
func verifyRsaKeyPair(kp KeyPair, e expectedData) error {
|
|
|
|
|
privateKey, err := gossh.ParseRawPrivateKey(kp.PrivateKeyPemBlock)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = expected{
|
|
|
|
|
kind: Ecdsa,
|
|
|
|
|
bits: 521,
|
|
|
|
|
desc: "521 bit ECDSA",
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}.matches(kp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
pk, ok := privateKey.(*rsa.PrivateKey)
|
|
|
|
|
if !ok {
|
|
|
|
|
return fmt.Errorf("private key should be *rsa.PrivateKey")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDefaultKeyPairBuilder_Build_EcdsaDefault(t *testing.T) {
|
|
|
|
|
kp, err := NewKeyPairBuilder().
|
|
|
|
|
SetType(Ecdsa).
|
|
|
|
|
Build()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
if pk.N.BitLen() != e.bits {
|
|
|
|
|
return fmt.Errorf("bit size should be %d - got %d", e.bits, pk.N.BitLen())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = expected{
|
|
|
|
|
kind: Ecdsa,
|
|
|
|
|
bits: 521,
|
|
|
|
|
desc: "521 bit ECDSA",
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}.matches(kp)
|
|
|
|
|
publicKey, err := gossh.NewPublicKey(&pk.PublicKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDefaultKeyPairBuilder_Build_EcdsaSupportedCurves(t *testing.T) {
|
|
|
|
|
supportedBits := []int{
|
|
|
|
|
521,
|
|
|
|
|
384,
|
|
|
|
|
256,
|
|
|
|
|
expectedBytes := bytes.TrimSuffix(gossh.MarshalAuthorizedKey(publicKey), []byte("\n"))
|
|
|
|
|
if len(e.name) > 0 {
|
|
|
|
|
expectedBytes = append(expectedBytes, ' ')
|
|
|
|
|
expectedBytes = append(expectedBytes, e.name...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, bits := range supportedBits {
|
|
|
|
|
kp, err := NewKeyPairBuilder().
|
|
|
|
|
SetType(Ecdsa).
|
|
|
|
|
SetBits(bits).
|
|
|
|
|
Build()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = expected{
|
|
|
|
|
kind: Ecdsa,
|
|
|
|
|
bits: bits,
|
|
|
|
|
desc: strconv.Itoa(bits) + " bit ECDSA",
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}.matches(kp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
}
|
|
|
|
|
if !bytes.Equal(expectedBytes, kp.PublicKeyAuthorizedKeysLine) {
|
|
|
|
|
return fmt.Errorf("authorized keys line should be:\n'%s'\nGot:\n'%s'",
|
|
|
|
|
string(expectedBytes), string(kp.PublicKeyAuthorizedKeysLine))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDefaultKeyPairBuilder_Build_RsaDefault(t *testing.T) {
|
|
|
|
|
kp, err := NewKeyPairBuilder().
|
|
|
|
|
SetType(Rsa).
|
|
|
|
|
Build()
|
|
|
|
|
func verifyDsaKeyPair(kp KeyPair, e fromPrivateExpectedData) error {
|
|
|
|
|
privateKey, err := gossh.ParseRawPrivateKey(kp.PrivateKeyPemBlock)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = expected{
|
|
|
|
|
kind: Rsa,
|
|
|
|
|
bits: 4096,
|
|
|
|
|
desc: "4096 bit RSA",
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}.matches(kp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
pk, ok := privateKey.(*dsa.PrivateKey)
|
|
|
|
|
if !ok {
|
|
|
|
|
return fmt.Errorf("private key should be *rsa.PrivateKey")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDefaultKeyPairBuilder_Build_NamedEcdsa(t *testing.T) {
|
|
|
|
|
name := uuid.TimeOrderedUUID()
|
|
|
|
|
|
|
|
|
|
kp, err := NewKeyPairBuilder().
|
|
|
|
|
SetType(Ecdsa).
|
|
|
|
|
SetName(name).
|
|
|
|
|
Build()
|
|
|
|
|
publicKey, err := gossh.NewPublicKey(&pk.PublicKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = expected{
|
|
|
|
|
kind: Ecdsa,
|
|
|
|
|
bits: 521,
|
|
|
|
|
desc: "521 bit ECDSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
name: name,
|
|
|
|
|
}.matches(kp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
expectedBytes := bytes.TrimSuffix(gossh.MarshalAuthorizedKey(publicKey), []byte("\n"))
|
|
|
|
|
if len(e.d.name) > 0 {
|
|
|
|
|
expectedBytes = append(expectedBytes, ' ')
|
|
|
|
|
expectedBytes = append(expectedBytes, e.d.name...)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDefaultKeyPairBuilder_Build_NamedRsa(t *testing.T) {
|
|
|
|
|
name := uuid.TimeOrderedUUID()
|
|
|
|
|
|
|
|
|
|
kp, err := NewKeyPairBuilder().
|
|
|
|
|
SetType(Rsa).
|
|
|
|
|
SetName(name).
|
|
|
|
|
Build()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
if !bytes.Equal(expectedBytes, kp.PublicKeyAuthorizedKeysLine) {
|
|
|
|
|
return fmt.Errorf("authorized keys line should be:\n'%s'\nGot:\n'%s'",
|
|
|
|
|
string(expectedBytes), string(kp.PublicKeyAuthorizedKeysLine))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = expected{
|
|
|
|
|
kind: Rsa,
|
|
|
|
|
bits: 4096,
|
|
|
|
|
desc: "4096 bit RSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
name: name,
|
|
|
|
|
}.matches(kp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err.Error())
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDefaultKeyPairBuilder_SetPrivateKey(t *testing.T) {
|
|
|
|
|
name := uuid.TimeOrderedUUID()
|
|
|
|
|
pemData := make(map[string]expected)
|
|
|
|
|
pemData[pemRsa1024] = expected{
|
|
|
|
|
bits: 1024,
|
|
|
|
|
kind: Rsa,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "1024 bit RSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}
|
|
|
|
|
pemData[pemRsa2048] = expected{
|
|
|
|
|
bits: 2048,
|
|
|
|
|
kind: Rsa,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "2048 bit RSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}
|
|
|
|
|
pemData[pemOpenSshRsa1024] = expected{
|
|
|
|
|
bits: 1024,
|
|
|
|
|
kind: Rsa,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "1024 bit RSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}
|
|
|
|
|
pemData[pemOpenSshRsa2048] = expected{
|
|
|
|
|
bits: 2048,
|
|
|
|
|
kind: Rsa,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "2048 bit RSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}
|
|
|
|
|
pemData[pemDsa] = expected{
|
|
|
|
|
bits: 1024,
|
|
|
|
|
kind: Dsa,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "1024 bit DSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}
|
|
|
|
|
pemData[pemEcdsa384] = expected{
|
|
|
|
|
bits: 384,
|
|
|
|
|
kind: Ecdsa,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "384 bit ECDSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}
|
|
|
|
|
pemData[pemEcdsa521] = expected{
|
|
|
|
|
bits: 521,
|
|
|
|
|
kind: Ecdsa,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "521 bit ECDSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}
|
|
|
|
|
pemData[pemOpenSshEd25519] = expected{
|
|
|
|
|
bits: 256,
|
|
|
|
|
kind: Ed25519,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "256 bit ED25519 named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
func verifyEd25519KeyPair(kp KeyPair, e fromPrivateExpectedData) error {
|
|
|
|
|
privateKey, err := gossh.ParseRawPrivateKey(kp.PrivateKeyPemBlock)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for s, l := range pemData {
|
|
|
|
|
kp, err := NewKeyPairBuilder().SetPrivateKey([]byte(s)).SetName(name).Build()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
err = l.matches(kp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
pk, ok := privateKey.(*ed25519.PrivateKey)
|
|
|
|
|
if !ok {
|
|
|
|
|
return fmt.Errorf("private key should be *rsa.PrivateKey")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDefaultKeyPairBuilder_SetPrivateKey_Override(t *testing.T) {
|
|
|
|
|
name := uuid.TimeOrderedUUID()
|
|
|
|
|
pemData := make(map[string]expected)
|
|
|
|
|
pemData[pemRsa1024] = expected{
|
|
|
|
|
bits: 1024,
|
|
|
|
|
kind: Rsa,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "1024 bit RSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}
|
|
|
|
|
pemData[pemRsa2048] = expected{
|
|
|
|
|
bits: 2048,
|
|
|
|
|
kind: Rsa,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "2048 bit RSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}
|
|
|
|
|
pemData[pemOpenSshRsa1024] = expected{
|
|
|
|
|
bits: 1024,
|
|
|
|
|
kind: Rsa,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "1024 bit RSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}
|
|
|
|
|
pemData[pemOpenSshRsa2048] = expected{
|
|
|
|
|
bits: 2048,
|
|
|
|
|
kind: Rsa,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "2048 bit RSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}
|
|
|
|
|
pemData[pemDsa] = expected{
|
|
|
|
|
bits: 1024,
|
|
|
|
|
kind: Dsa,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "1024 bit DSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}
|
|
|
|
|
pemData[pemEcdsa384] = expected{
|
|
|
|
|
bits: 384,
|
|
|
|
|
kind: Ecdsa,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "384 bit ECDSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
}
|
|
|
|
|
pemData[pemEcdsa521] = expected{
|
|
|
|
|
bits: 521,
|
|
|
|
|
kind: Ecdsa,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "521 bit ECDSA named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
publicKey, err := gossh.NewPublicKey(pk.Public())
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
pemData[pemOpenSshEd25519] = expected{
|
|
|
|
|
bits: 256,
|
|
|
|
|
kind: Ed25519,
|
|
|
|
|
name: name,
|
|
|
|
|
desc: "256 bit ED25519 named " + name,
|
|
|
|
|
data: []byte(uuid.TimeOrderedUUID()),
|
|
|
|
|
|
|
|
|
|
expectedBytes := bytes.TrimSuffix(gossh.MarshalAuthorizedKey(publicKey), []byte("\n"))
|
|
|
|
|
if len(e.d.name) > 0 {
|
|
|
|
|
expectedBytes = append(expectedBytes, ' ')
|
|
|
|
|
expectedBytes = append(expectedBytes, e.d.name...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
supportedKeyTypes := []KeyPairType{Rsa, Dsa}
|
|
|
|
|
for _, keyType := range supportedKeyTypes {
|
|
|
|
|
for pemString, expectedResult := range pemData {
|
|
|
|
|
kp, err := NewKeyPairBuilder().
|
|
|
|
|
SetPrivateKey([]byte(pemString)).
|
|
|
|
|
SetName(name).
|
|
|
|
|
SetType(keyType).
|
|
|
|
|
Build()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
err = expectedResult.matches(kp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !bytes.Equal(expectedBytes, kp.PublicKeyAuthorizedKeysLine) {
|
|
|
|
|
return fmt.Errorf("authorized keys line should be:\n'%s'\nGot:\n'%s'",
|
|
|
|
|
string(expectedBytes), string(kp.PublicKeyAuthorizedKeysLine))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|