Skip to content

Commit

Permalink
Adding read and parse functionalities for ed25519 keys
Browse files Browse the repository at this point in the history
  • Loading branch information
piratax007 committed Jun 8, 2022
1 parent 9cea7b5 commit 314811f
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 9 deletions.
11 changes: 11 additions & 0 deletions ssh/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,17 @@ func (s *sshSuite) Test_access_AllKeys_ReturnsAKeyEntryListOfPrivateKeysIfSSHDir
r := rand.Int()
privateKeyFile1 := "private-key"
privateKeyFile2 := fmt.Sprintf("is-a-private-key-%d", r)
privateKeyFile3 := "ed25519-key"
s.createFileWithContent(sshDirectory, privateKeyFile1, correctRSASSHPrivateKey)
s.createFileWithContent(sshDirectory, privateKeyFile2, correctRSASSHPrivateKeyOther)
s.createFileWithContent(sshDirectory, privateKeyFile3, correctEd25519PrivateKey)
s.createEmptyFile(sshDirectory, "empty-file")

a, _ := accessWithTestLogging()
s.ElementsMatch([]api.KeyEntry{
createPrivateKeyRepresentation(path.Join(sshDirectory, privateKeyFile1)),
createPrivateKeyRepresentation(path.Join(sshDirectory, privateKeyFile2)),
createPrivateKeyRepresentation(path.Join(sshDirectory, privateKeyFile3)),
}, a.AllKeys())
}

Expand All @@ -69,14 +72,17 @@ func (s *sshSuite) Test_access_AllKeys_ReturnsAKeyEntryListOfPublicKeysIfSSHDire
r := rand.Int()
publicKeyFile1 := "ssh-rsa.pub"
publicKeyFile2 := fmt.Sprintf("ssh-rsa-%d.pub", r)
publicKeyFile3 := "ed25519.pub"
s.createFileWithContent(sshDirectory, publicKeyFile1, "ssh-rsa BBBB batman@debian")
s.createFileWithContent(sshDirectory, publicKeyFile2, "ssh-rsa AAAA robin@debian")
s.createFileWithContent(sshDirectory, publicKeyFile3, "ssh-ed25519 CCC alfred@debian")
s.createEmptyFile(sshDirectory, "empty-file")

a, _ := accessWithTestLogging()
s.ElementsMatch([]api.KeyEntry{
createPublicKeyRepresentation(path.Join(sshDirectory, publicKeyFile1)),
createPublicKeyRepresentation(path.Join(sshDirectory, publicKeyFile2)),
createPublicKeyRepresentation(path.Join(sshDirectory, publicKeyFile3)),
}, a.AllKeys())
}

Expand All @@ -88,18 +94,23 @@ func (s *sshSuite) Test_access_AllKeys_ReturnsAKeyEntryListOfKeypairsIfSSHDirect
r := rand.Int()
matchingPrivateKeyFile1 := "match-key"
matchingPrivateKeyFile2 := fmt.Sprintf("is-a-match-key-%d", r)
matchingPrivateKeyFile3 := "match-ed25519-key"
s.createFileWithContent(sshDirectory, matchingPrivateKeyFile1, correctRSASSHPrivateKey)
s.createFileWithContent(sshDirectory, matchingPrivateKeyFile2, correctRSASSHPrivateKeyOther)
s.createFileWithContent(sshDirectory, matchingPrivateKeyFile3, correctEd25519PrivateKey)
matchingPublicKeyFile1 := "match-key.pub"
matchingPublicKeyFile2 := fmt.Sprintf("is-a-match-key-%d.pub", r)
matchingPublicKeyFile3 := "match-ed25519-key.pub"
s.createFileWithContent(sshDirectory, matchingPublicKeyFile1, "ssh-rsa BBBB batman@debian")
s.createFileWithContent(sshDirectory, matchingPublicKeyFile2, "ssh-rsa AAAA robin@debian")
s.createFileWithContent(sshDirectory, matchingPublicKeyFile3, "ssh-ed25519 CCCC alfred@debian")
s.createEmptyFile(sshDirectory, "empty-file")

a, _ := accessWithTestLogging()
s.ElementsMatch([]api.KeyEntry{
createKeypairRepresentation(createPrivateKeyRepresentation(path.Join(sshDirectory, matchingPrivateKeyFile1)), createPublicKeyRepresentation(path.Join(sshDirectory, matchingPublicKeyFile1))),
createKeypairRepresentation(createPrivateKeyRepresentation(path.Join(sshDirectory, matchingPrivateKeyFile2)), createPublicKeyRepresentation(path.Join(sshDirectory, matchingPublicKeyFile2))),
createKeypairRepresentation(createPrivateKeyRepresentation(path.Join(sshDirectory, matchingPrivateKeyFile3)), createPublicKeyRepresentation(path.Join(sshDirectory, matchingPublicKeyFile3))),
}, a.AllKeys())
}

Expand Down
18 changes: 18 additions & 0 deletions ssh/ed25519_file_reader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ssh

func (a *access) checkIfFileContainsAPrivateEd25519Key(fileName string) (bool, error) {
return fileContentMatches(fileName, a.isEd25519PrivateKey)
}

func (a *access) filesContainingEd25519PrivateKeys(fileNameList []string) []string {
result := filter(fileNameList, ignoringErrors(a.checkIfFileContainsAPrivateEd25519Key))
return result
}

func checkIfFileContainsAPublicEd25519Key(fileName string) (bool, error) {
return fileContentMatches(fileName, isEd25519PublicKey)
}

func filesContainingEd25519PublicKeys(fileNameList []string) []string {
return filter(fileNameList, ignoringErrors(checkIfFileContainsAPublicEd25519Key))
}
91 changes: 91 additions & 0 deletions ssh/ed25519_file_reader_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package ssh

import "path/filepath"

func (s *sshSuite) Test_filesContainingEd25519PrivateKeys_ReturnsAnEmptyListIfAnEmptyListIsProvided() {
fileNameList := []string{}

a, _ := accessWithTestLogging()
selected := a.filesContainingEd25519PrivateKeys(fileNameList)

s.Empty(selected)
}

func (s *sshSuite) Test_filesContainingEd25519PrivateKeys_ReturnsAnEmptyListIfAListWithANonExistingFileIsProvided() {
fileNameList := []string{"File that doesn't exist"}

a, _ := accessWithTestLogging()
selected := a.filesContainingEd25519PrivateKeys(fileNameList)

s.Empty(selected)
}

func (s *sshSuite) Test_filesContainingEd25519PrivateKeys_ReturnsAnEmptyListIfAListWithAnEmptyFileIsProvided() {
// Given
fileName := "Empty file"
s.createEmptyFile(s.tdir, fileName)
fileNameList := []string{filepath.Join(s.tdir, fileName)}

// When
a, _ := accessWithTestLogging()
selected := a.filesContainingEd25519PrivateKeys(fileNameList)

// Then
s.Empty(selected)
}

func (s *sshSuite) Test_filesContainingEd25519PrivateKeys_ReturnsAnEmptyListIfAListWithAFileThatDoesntContainAnEd25519PrivateKeyIsProvided() {
// Given
fileName := "Empty file"
s.createFileWithContent(s.tdir, fileName, "not a Ed25519 private key")
fileNameList := []string{filepath.Join(s.tdir, fileName)}

// When
a, _ := accessWithTestLogging()
selected := a.filesContainingEd25519PrivateKeys(fileNameList)

// Then
s.Empty(selected)
}

func (s *sshSuite) Test_filesContainingEd25519PrivateKeys_ReturnsAListWithOneFileNameIfAListWithAFileThatContainsAnEd25519PrivateKeyIsProvided() {
// Given
fileName := "File-with-content"
s.createFileWithContent(s.tdir, fileName, correctEd25519PrivateKey)
fileNameList := []string{filepath.Join(s.tdir, fileName)}

// When
a, _ := accessWithTestLogging()
selected := a.filesContainingEd25519PrivateKeys(fileNameList)

// Then
s.Equal(selected, []string{filepath.Join(s.tdir, fileName)})
}

const correctEd25519PrivateKeyOther = `
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACCRcAFuKgCAnlEuMGswxk18tn2JVXH+7OkVSDbBC2WQ2gAAAJCs0I2+rNCN
vgAAAAtzc2gtZWQyNTUxOQAAACCRcAFuKgCAnlEuMGswxk18tn2JVXH+7OkVSDbBC2WQ2g
AAAED9p1K4JP1ykaLj705pfax2AVvTXryKkJxEXkp3eIuLm5FwAW4qAICeUS4wazDGTXy2
fYlVcf7s6RVINsELZZDaAAAACmZhdXN0b0BDQUQBAgM=
-----END OPENSSH PRIVATE KEY-----
`

func (s *sshSuite) Test_filesContainingEd25519PrivateKeys_ReturnsAListWithSeveralFileNamesThatContainsEd25519Key() {
// Given
s.createFileWithContent(s.tdir, "key_file1", correctECDSASSHPrivateKey)
s.createFileWithContent(s.tdir, "key_file2", correctEd25519PrivateKey)
s.createEmptyFile(s.tdir, "key_file3")
s.createFileWithContent(s.tdir, "key_file4", correctEd25519PrivateKeyOther)

fileList := s.withDirectory("key_file1", "key_file2", "key_file3", "key_file4", "key_file5")

// When
a, _ := accessWithTestLogging()
selected := a.filesContainingEd25519PrivateKeys(fileList)

// Then
expected := s.withDirectory("key_file2", "key_file4")
s.Equal(expected, selected)
}
23 changes: 23 additions & 0 deletions ssh/ed25519_key_reader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package ssh

const ed25519Algorithm = "ssh-ed25519"

func (a *access) isEd25519PrivateKey(pk string) bool {
priv, ok := a.parsePrivateKey(pk)
if !ok {
return false
}
return priv.isEd25519()
}

func (k *publicKey) isEd25519() bool {
return k.isAlgorithm(ed25519Algorithm)
}

func isEd25519PublicKey(k string) bool {
pub, ok := parsePublicKey(k)
if !ok {
return false
}
return pub.isEd25519()
}
5 changes: 5 additions & 0 deletions ssh/ed25519_private_key_parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ssh

func (k *privateKey) isEd25519() bool {
return k.isAlgorithm(ed25519Algorithm)
}
21 changes: 21 additions & 0 deletions ssh/ed25519_private_key_parser_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ssh

const correctEd25519PrivateKey = `
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACC7eNn1eQ/DPPtfZUAie2p9I1TAuj91YucOlbHyxV7hygAAAJC+YoKmvmKC
pgAAAAtzc2gtZWQyNTUxOQAAACC7eNn1eQ/DPPtfZUAie2p9I1TAuj91YucOlbHyxV7hyg
AAAEBVI12MKVSate/Pvx/nqIe2B4/J3Y8qURPhFGcUZyEtgbt42fV5D8M8+19lQCJ7an0j
VMC6P3Vi5w6VsfLFXuHKAAAACmZhdXN0b0BDQUQBAgM=
-----END OPENSSH PRIVATE KEY-----
`

func (s *sshSuite) Test_parsePrivateKey_AStringContainingACorrectEd25519KeyShouldBeConsideredAPrivateKey() {
pk := correctEd25519PrivateKey

a, _ := accessWithTestLogging()
priv, ok := a.parsePrivateKey(pk)

s.True(ok)
s.Equal("ssh-ed25519", priv.algorithm)
}
13 changes: 11 additions & 2 deletions ssh/file_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,18 @@ func createPrivateKeyRepresentationsFrom(input []string) []*privateKeyRepresenta
}

func (a *access) privateKeyRepresentationsFrom(input []string) []*privateKeyRepresentation {
return createPrivateKeyRepresentationsFrom(a.filesContainingRSAPrivateKeys(input))
privateKeyFiles := concat(
a.filesContainingRSAPrivateKeys(input),
a.filesContainingEd25519PrivateKeys(input),
)

return createPrivateKeyRepresentationsFrom(privateKeyFiles)
}

func publicKeyRepresentationsFrom(input []string) []*publicKeyRepresentation {
return createPublicKeyRepresentationsFrom(filesContainingRSAPublicKeys(input))
publicKeyFiles := concat(
filesContainingRSAPublicKeys(input),
filesContainingEd25519PublicKeys(input),
)
return createPublicKeyRepresentationsFrom(publicKeyFiles)
}
14 changes: 7 additions & 7 deletions ssh/file_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func (s *sshSuite) Test_selectFilesContainingRSAPublicKeys_ReturnsAListWithSever
s.Equal(expected, selected)
}

func (s *sshSuite) Test_selectFilesContainingRSAPrivateKeys_ReturnsAnEmptyListIfAnEmptyListIsProvided() {
func (s *sshSuite) Test_filesContainingRSAPrivateKeys_ReturnsAnEmptyListIfAnEmptyListIsProvided() {
fileNameList := []string{}

a, _ := accessWithTestLogging()
Expand All @@ -145,7 +145,7 @@ func (s *sshSuite) Test_selectFilesContainingRSAPrivateKeys_ReturnsAnEmptyListIf
s.Empty(selected)
}

func (s *sshSuite) Test_selectFilesContainingRSAPrivateKeys_ReturnsAnEmptyListIfAListWithANonExistingFileIsProvided() {
func (s *sshSuite) Test_filesContainingRSAPrivateKeys_ReturnsAnEmptyListIfAListWithANonExistingFileIsProvided() {
fileNameList := []string{"File that doesn't exist"}

a, _ := accessWithTestLogging()
Expand All @@ -154,7 +154,7 @@ func (s *sshSuite) Test_selectFilesContainingRSAPrivateKeys_ReturnsAnEmptyListIf
s.Empty(selected)
}

func (s *sshSuite) Test_selectFilesContainingRSAPrivateKeys_ReturnsAnEmptyListIfAListWithAnEmptyFileIsProvided() {
func (s *sshSuite) Test_filesContainingRSAPrivateKeys_ReturnsAnEmptyListIfAListWithAnEmptyFileIsProvided() {
// Given
fileName := "Empty file"
s.createEmptyFile(s.tdir, fileName)
Expand All @@ -168,10 +168,10 @@ func (s *sshSuite) Test_selectFilesContainingRSAPrivateKeys_ReturnsAnEmptyListIf
s.Empty(selected)
}

func (s *sshSuite) Test_selectFilesContainingRSAPrivateKeys_ReturnsAnEmptyListIfAListWithAFileThatDoesntContainAnRSAPublicKeyIsProvided() {
func (s *sshSuite) Test_filesContainingRSAPrivateKeys_ReturnsAnEmptyListIfAListWithAFileThatDoesntContainAnRSAPrivateKeyIsProvided() {
// Given
fileName := "Empty file"
s.createFileWithContent(s.tdir, fileName, "not a RSA public key")
s.createFileWithContent(s.tdir, fileName, "not a RSA private key")
fileNameList := []string{filepath.Join(s.tdir, fileName)}

// When
Expand All @@ -182,7 +182,7 @@ func (s *sshSuite) Test_selectFilesContainingRSAPrivateKeys_ReturnsAnEmptyListIf
s.Empty(selected)
}

func (s *sshSuite) Test_selectFilesContainingRSAPrivateKeys_ReturnsAListWithOneFileNameIfAListWithAFileThatContainsAnRSAPublicKeyIsProvided() {
func (s *sshSuite) Test_filesContainingRSAPrivateKeys_ReturnsAListWithOneFileNameIfAListWithAFileThatContainsAnRSAPrivateKeyIsProvided() {
// Given
fileName := "File-with-content"
s.createFileWithContent(s.tdir, fileName, correctRSASSHPrivateKey)
Expand All @@ -196,7 +196,7 @@ func (s *sshSuite) Test_selectFilesContainingRSAPrivateKeys_ReturnsAListWithOneF
s.Equal(selected, []string{filepath.Join(s.tdir, fileName)})
}

func (s *sshSuite) Test_selectFilesContainingRSAPrivateKeys_ReturnsAListWithSeveralFileNamesThatContainsRSAKey() {
func (s *sshSuite) Test_filesContainingRSAPrivateKeys_ReturnsAListWithSeveralFileNamesThatContainsRSAKey() {
// Given
s.createFileWithContent(s.tdir, "key_file1", correctECDSASSHPrivateKey)
s.createFileWithContent(s.tdir, "key_file2", correctRSASSHPrivateKey)
Expand Down
8 changes: 8 additions & 0 deletions ssh/slices.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,11 @@ func foreach[T any](values []T, f func(T)) {
f(v)
}
}

func concat[T any](s ...[]T) []T {
if len(s) == 0 {
return nil
}

return append(s[0], concat(s[1:]...)...)
}

0 comments on commit 314811f

Please sign in to comment.