Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Copyright 2012 The Go Authors. All rights reserved. | 1 // Copyright 2012 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package ssh | 5 package ssh |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | |
8 "crypto/dsa" | 9 "crypto/dsa" |
9 "crypto/rsa" | 10 "crypto/rsa" |
11 "encoding/base64" | |
10 "math/big" | 12 "math/big" |
13 "strings" | |
14 ) | |
15 | |
16 // Keytypes supported by OpenSSH 1.5.9 | |
agl1
2012/11/30 22:36:45
1.5.9? Maybe 5.9?
| |
17 const ( | |
18 keyAlgoRSA = "ssh-rsa" | |
19 keyAlgoDSA = "ssh-dss" | |
20 keyAlgoECDSA256 = "ecdsa-sha2-nistp256" | |
21 keyAlgoECDSA384 = "ecdsa-sha2-nistp384" | |
22 keyAlgoECDSA521 = "ecdsa-sha2-nistp521" | |
11 ) | 23 ) |
12 | 24 |
13 // parsePubKey parses a public key according to RFC 4253, section 6.6. | 25 // parsePubKey parses a public key according to RFC 4253, section 6.6. |
14 func parsePubKey(in []byte) (out interface{}, rest []byte, ok bool) { | 26 func parsePubKey(in []byte) (out interface{}, rest []byte, ok bool) { |
15 algo, in, ok := parseString(in) | 27 algo, in, ok := parseString(in) |
16 if !ok { | 28 if !ok { |
17 return | 29 return |
18 } | 30 } |
19 | 31 |
20 switch string(algo) { | 32 switch string(algo) { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
111 length += intLength(key.Y) | 123 length += intLength(key.Y) |
112 | 124 |
113 ret := make([]byte, length) | 125 ret := make([]byte, length) |
114 r := marshalInt(ret, key.P) | 126 r := marshalInt(ret, key.P) |
115 r = marshalInt(r, key.Q) | 127 r = marshalInt(r, key.Q) |
116 r = marshalInt(r, key.G) | 128 r = marshalInt(r, key.G) |
117 marshalInt(r, key.Y) | 129 marshalInt(r, key.Y) |
118 | 130 |
119 return ret | 131 return ret |
120 } | 132 } |
133 | |
134 // ParseAuthorizedKeys parses a public key from an authorized_keys | |
135 // file used in OpenSSH according to the sshd(8) manual page. | |
136 func ParseAuthorizedKey(in []byte) (out interface{}, comment string, options []s tring, rest []byte, ok bool) { | |
137 for { | |
138 end := bytes.IndexByte(in, '\n') | |
139 if end != -1 { | |
140 rest = in[end+1:] | |
141 in = in[:end] | |
142 } else { | |
143 rest = nil | |
144 } | |
145 | |
146 end = bytes.IndexByte(in, '\r') | |
147 if end != -1 { | |
148 in = in[:end] | |
149 } | |
150 | |
151 in = bytes.TrimSpace(in) | |
152 if len(in) != 0 && !bytes.HasPrefix(in, []byte("#")) { | |
agl1
2012/11/30 22:36:45
replace
!bytes.HasPrefix(in, []byte("#"))
with
| |
153 break | |
154 } | |
155 in = rest | |
156 } | |
157 | |
158 // fields: options, keytype, base64key, comment | |
159 // options & comment are optional | |
160 fields := strings.Fields(string(in)) | |
161 if len(fields) < 2 { | |
162 return nil, "", nil, rest, false | |
163 } | |
164 var b64key string | |
165 | |
166 switch fields[0] { | |
167 case keyAlgoRSA, keyAlgoDSA: | |
168 options = nil | |
169 b64key = fields[1] | |
170 comment = fields[2] | |
171 case keyAlgoECDSA256, keyAlgoECDSA384, keyAlgoECDSA521: | |
172 panic("unexpected key type") | |
agl1
2012/11/30 22:36:45
I think a panic is too much.
Ideally we would con
| |
173 default: | |
174 options = strings.Split(string(fields[0]), ",") | |
agl1
2012/11/30 22:36:45
What if the options contain a space in a quoted va
| |
175 b64key = fields[2] | |
176 comment = fields[3] | |
177 } | |
178 key, err := base64.StdEncoding.DecodeString(b64key) | |
179 if err != nil { | |
180 return nil, "", nil, rest, false | |
181 } | |
182 out, _, ok = parsePubKey(key) | |
183 | |
184 return | |
185 } | |
186 | |
187 // ParsePublicKey parses an ssh public key formatted for use in | |
188 // on the wire protocol of SSH. | |
189 func ParsePublicKey(in []byte) (out interface{}, rest []byte, ok bool) { | |
190 return parsePubKey(in) | |
191 } | |
192 | |
193 // MarshalAuthorizedKey returns a byte stream suitable for inclusion | |
194 // in an OpenSSH authorized_keys file following the format specified | |
195 // in the sshd(8) manual page. | |
196 func MarshalAuthorizedKey(key interface{}) []byte { | |
197 b := &bytes.Buffer{} | |
198 switch keyType := key.(type) { | |
199 case *rsa.PublicKey: | |
200 b.WriteString(hostAlgoRSA) | |
201 case *dsa.PublicKey: | |
202 b.WriteString(hostAlgoDSA) | |
203 case *OpenSSHCertV01: | |
204 switch keyType.Key.(type) { | |
205 case *rsa.PublicKey: | |
206 b.WriteString(hostAlgoRSACertV01) | |
207 case *dsa.PublicKey: | |
208 b.WriteString(hostAlgoDSACertV01) | |
209 default: | |
210 panic("unexpected key type") | |
211 } | |
212 default: | |
213 panic("unexpected key type") | |
214 } | |
215 | |
216 b.WriteByte(' ') | |
217 e := base64.NewEncoder(base64.StdEncoding, b) | |
218 e.Write(serializePublickey(key)) | |
219 e.Close() | |
220 b.WriteByte('\n') | |
221 return b.Bytes() | |
222 } | |
223 | |
224 // MarshalPublicKey serializes a *rsa.PublicKey, *dsa.PublicKey or | |
225 // *OpenSSHCertV01 for use on the wire protocol of SSH. It can be | |
226 // used for comparison with the pubkey argument of ServerConfig's | |
227 // PublickeyCallback as well as generating an authorized_keys or | |
228 // host_keys file. | |
229 func MarshalPublicKey(key interface{}) []byte { | |
230 return serializePublickey(key) | |
231 } | |
OLD | NEW |