7
7
"errors"
8
8
"fmt"
9
9
"io"
10
+ "io/ioutil"
10
11
"net"
11
12
"sort"
12
13
"strings"
@@ -34,12 +35,17 @@ func (hkcb HostKeyCallback) HostKeyCallback() ssh.HostKeyCallback {
34
35
return ssh .HostKeyCallback (hkcb )
35
36
}
36
37
38
+ type PublicKey struct {
39
+ ssh.PublicKey
40
+ cert bool
41
+ }
42
+
37
43
// HostKeys returns a slice of known host public keys for the supplied host:port
38
44
// found in the known_hosts file(s), or an empty slice if the host is not
39
45
// already known. For hosts that have multiple known_hosts entries (for
40
46
// different key types), the result will be sorted by known_hosts filename and
41
47
// line number.
42
- func (hkcb HostKeyCallback ) HostKeys (hostWithPort string ) (keys []ssh. PublicKey ) {
48
+ func (hkcb HostKeyCallback ) HostKeys (hostWithPort string ) (keys []PublicKey ) {
43
49
var keyErr * xknownhosts.KeyError
44
50
placeholderAddr := & net.TCPAddr {IP : []byte {0 , 0 , 0 , 0 }}
45
51
placeholderPubKey := & fakePublicKey {}
@@ -53,14 +59,47 @@ func (hkcb HostKeyCallback) HostKeys(hostWithPort string) (keys []ssh.PublicKey)
53
59
return (kkeys [i ].Filename == kkeys [j ].Filename && kkeys [i ].Line < kkeys [j ].Line )
54
60
}
55
61
sort .Slice (kkeys , knownKeyLess )
56
- keys = make ([]ssh.PublicKey , len (kkeys ))
57
- for n := range kkeys {
58
- keys [n ] = kkeys [n ].Key
62
+ keys = make ([]PublicKey , len (kkeys ))
63
+ for n , k := range kkeys {
64
+ content , err := ioutil .ReadFile (k .Filename )
65
+ if err != nil {
66
+ continue
67
+ }
68
+ lines := strings .Split (string (content ), "\n " )
69
+ line := lines [k .Line - 1 ]
70
+ isCert := strings .HasPrefix (line , "@cert-authority" )
71
+
72
+ keys [n ] = PublicKey {
73
+ PublicKey : k .Key ,
74
+ cert : isCert ,
75
+ }
59
76
}
60
77
}
61
78
return keys
62
79
}
63
80
81
+ func keyTypeToCertType (keyType string ) string {
82
+ switch keyType {
83
+ case ssh .KeyAlgoRSA :
84
+ return ssh .CertAlgoRSAv01
85
+ case ssh .KeyAlgoDSA :
86
+ return ssh .CertAlgoDSAv01
87
+ case ssh .KeyAlgoECDSA256 :
88
+ return ssh .CertAlgoECDSA256v01
89
+ case ssh .KeyAlgoSKECDSA256 :
90
+ return ssh .CertAlgoSKECDSA256v01
91
+ case ssh .KeyAlgoECDSA384 :
92
+ return ssh .CertAlgoECDSA384v01
93
+ case ssh .KeyAlgoECDSA521 :
94
+ return ssh .CertAlgoECDSA521v01
95
+ case ssh .KeyAlgoED25519 :
96
+ return ssh .CertAlgoED25519v01
97
+ case ssh .KeyAlgoSKED25519 :
98
+ return ssh .CertAlgoSKED25519v01
99
+ }
100
+ return ""
101
+ }
102
+
64
103
// HostKeyAlgorithms returns a slice of host key algorithms for the supplied
65
104
// host:port found in the known_hosts file(s), or an empty slice if the host
66
105
// is not already known. The result may be used in ssh.ClientConfig's
@@ -84,14 +123,27 @@ func (hkcb HostKeyCallback) HostKeyAlgorithms(hostWithPort string) (algos []stri
84
123
}
85
124
for _ , key := range hostKeys {
86
125
typ := key .Type ()
87
- if typ == ssh .KeyAlgoRSA {
88
- // KeyAlgoRSASHA256 and KeyAlgoRSASHA512 are only public key algorithms,
89
- // not public key formats, so they can't appear as a PublicKey.Type.
90
- // The corresponding PublicKey.Type is KeyAlgoRSA. See RFC 8332, Section 2.
91
- addAlgo (ssh .KeyAlgoRSASHA512 )
92
- addAlgo (ssh .KeyAlgoRSASHA256 )
126
+ if key .cert {
127
+ certType := keyTypeToCertType (typ )
128
+ if certType == ssh .CertAlgoRSAv01 {
129
+
130
+ // CertAlgoRSASHA256v01 and CertAlgoRSASHA512v01 can't appear as a
131
+ // Certificate.Type (or PublicKey.Type), but only in
132
+ // ClientConfig.HostKeyAlgorithms.
133
+ addAlgo (ssh .CertAlgoRSASHA256v01 )
134
+ addAlgo (ssh .CertAlgoRSASHA512v01 )
135
+ }
136
+ addAlgo (certType )
137
+ } else {
138
+ if typ == ssh .KeyAlgoRSA {
139
+ // KeyAlgoRSASHA256 and KeyAlgoRSASHA512 are only public key algorithms,
140
+ // not public key formats, so they can't appear as a PublicKey.Type.
141
+ // The corresponding PublicKey.Type is KeyAlgoRSA. See RFC 8332, Section 2.
142
+ addAlgo (ssh .KeyAlgoRSASHA512 )
143
+ addAlgo (ssh .KeyAlgoRSASHA256 )
144
+ }
145
+ addAlgo (typ )
93
146
}
94
- addAlgo (typ )
95
147
}
96
148
return algos
97
149
}
0 commit comments