Skip to content

Commit 72e1e35

Browse files
idimov-keeperRicky White
andauthored
Add support for SSH Key with a passphrase (#40)
* Added passphrase handling * Improved field parsing * Refactor error handling. --------- Co-authored-by: Ricky White <[email protected]>
1 parent f896c1c commit 72e1e35

File tree

4 files changed

+38
-10
lines changed

4 files changed

+38
-10
lines changed

cmd/ssh-sign/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func main() {
9191
}
9292
fileMode := fileinfo.Mode()
9393

94-
sig, err := sign.SignCommit(keyPair.PrivateKey, file)
94+
sig, err := sign.SignCommit(keyPair.PrivateKey, keyPair.Passphrase, file)
9595
if err != nil {
9696
fmt.Println(err)
9797
os.Exit(1)

internal/sign/sign.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import (
44
"crypto/rand"
55
"crypto/sha512"
66
"encoding/pem"
7-
"golang.org/x/crypto/ssh"
87
"io"
8+
9+
"golang.org/x/crypto/ssh"
910
)
1011

11-
/*
12-
The code in this module is heavily based on the great work done by the
12+
/*
13+
The code in this module is heavily based on the great work done by the
1314
sigstore/rekor project: https://github.com/sigstore/rekor/
1415
*/
1516

@@ -89,8 +90,14 @@ func NewSignature(signer ssh.AlgorithmSigner, data io.Reader) (*ssh.Signature, e
8990
}
9091

9192
// Sign a commit(data) using the given private key.
92-
func SignCommit(sshPrivateKey string, data io.Reader) ([]byte, error) {
93-
s, err := ssh.ParsePrivateKey([]byte(sshPrivateKey))
93+
func SignCommit(sshPrivateKey string, passphrase string, data io.Reader) ([]byte, error) {
94+
var err error
95+
var s ssh.Signer
96+
if passphrase != "" {
97+
s, err = ssh.ParsePrivateKeyWithPassphrase([]byte(sshPrivateKey), []byte(passphrase))
98+
} else {
99+
s, err = ssh.ParsePrivateKey([]byte(sshPrivateKey))
100+
}
94101
if err != nil {
95102
return nil, err
96103
}

internal/sign/sign_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,11 @@ func TestSignCommit(t *testing.T) {
8787

8888
for _, tt := range tests {
8989
t.Run(tt.name, func(t *testing.T) {
90-
_, err := SignCommit(tt.key, data)
90+
_, err := SignCommit(tt.key, "", data)
9191
if (err != nil) != tt.wantErr {
9292
t.Errorf("TestSignCommit expected: %v, got: %v", tt.wantErr, err)
9393
return
9494
}
9595
})
9696
}
9797
}
98-

internal/vault/vault.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type ConfigOptions struct {
1616
type KeyPair struct {
1717
PrivateKey string
1818
PublicKey string
19+
Passphrase string
1920
}
2021

2122
// Build the config options based on the given options.
@@ -71,8 +72,29 @@ func FetchKeys(uid string) (*KeyPair, error) {
7172
// "keyPair".
7273
keys := records[0].GetFieldsByType("keyPair")[0]["value"].([]interface{})[0]
7374

75+
privateKey, ok := keys.(map[string]interface{})["privateKey"].(string)
76+
if !ok || (privateKey == "") {
77+
return nil, fmt.Errorf("no private key found for UID: %s", uid)
78+
}
79+
80+
publicKey, ok := keys.(map[string]interface{})["publicKey"].(string)
81+
if !ok || (publicKey == ""){
82+
return nil, fmt.Errorf("no public key found for UID: %s", uid)
83+
}
84+
85+
// If a passphrase is set, it is stored in the password field of the
86+
// SSH template. If no passphrase is set, passPhrase is set to an empty
87+
// string.
88+
passPhrase := ""
89+
if passArr, ok := records[0].GetFieldsByType("password")[0]["value"].([]interface{}); ok && len(passArr) > 0 {
90+
if passStr, ok := passArr[0].(string); ok {
91+
passPhrase = passStr
92+
}
93+
}
94+
7495
return &KeyPair{
75-
PrivateKey: keys.(map[string]interface{})["privateKey"].(string),
76-
PublicKey: keys.(map[string]interface{})["publicKey"].(string),
96+
PrivateKey: privateKey,
97+
PublicKey: publicKey,
98+
Passphrase: passPhrase,
7799
}, nil
78100
}

0 commit comments

Comments
 (0)