Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(176)

Side by Side Diff: ssh/keys.go

Issue 6855107: code review 6855107: ssh: add functions for public keys in wire & auth keys ...
Patch Set: diff -r b2b2ae1f5140 https://code.google.com/p/go.crypto Created 11 years, 3 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | ssh/test/keys_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
11 ) 13 )
12 14
15 // Keytypes supported by OpenSSH 5.9
16 const (
17 keyAlgoRSA = "ssh-rsa"
18 keyAlgoDSA = "ssh-dss"
19 keyAlgoECDSA256 = "ecdsa-sha2-nistp256"
20 keyAlgoECDSA384 = "ecdsa-sha2-nistp384"
21 keyAlgoECDSA521 = "ecdsa-sha2-nistp521"
22 )
23
13 // parsePubKey parses a public key according to RFC 4253, section 6.6. 24 // parsePubKey parses a public key according to RFC 4253, section 6.6.
14 func parsePubKey(in []byte) (out interface{}, rest []byte, ok bool) { 25 func parsePubKey(in []byte) (out interface{}, rest []byte, ok bool) {
15 algo, in, ok := parseString(in) 26 algo, in, ok := parseString(in)
16 if !ok { 27 if !ok {
17 return 28 return
18 } 29 }
19 30
20 switch string(algo) { 31 switch string(algo) {
21 case hostAlgoRSA: 32 case hostAlgoRSA:
22 return parseRSA(in) 33 return parseRSA(in)
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 length += intLength(key.Y) 122 length += intLength(key.Y)
112 123
113 ret := make([]byte, length) 124 ret := make([]byte, length)
114 r := marshalInt(ret, key.P) 125 r := marshalInt(ret, key.P)
115 r = marshalInt(r, key.Q) 126 r = marshalInt(r, key.Q)
116 r = marshalInt(r, key.G) 127 r = marshalInt(r, key.G)
117 marshalInt(r, key.Y) 128 marshalInt(r, key.Y)
118 129
119 return ret 130 return ret
120 } 131 }
132
133 // parseAuthorizedKey parses a public key in OpenSSH authorized_keys format
134 // (see sshd(8) manual page). in contains the line after the options and key
135 // type fields have been removed.
136 func parseAuthorizedKey(in []byte) (out interface{}, comment string, ok bool) {
137 in = bytes.TrimSpace(in)
138
139 i := bytes.IndexAny(in, " \t")
140 if i == -1 {
141 i = len(in)
142 }
143 base64Key := in[:i]
144
145 key := make([]byte, base64.StdEncoding.DecodedLen(len(base64Key)))
146 n, err := base64.StdEncoding.Decode(key, base64Key)
147 if err != nil {
148 return
149 }
150 key = key[:n]
151 out, _, ok = parsePubKey(key)
152 if !ok {
153 return nil, "", false
154 }
155 comment = string(bytes.TrimSpace(in[i:]))
156 return
157 }
158
159 // ParseAuthorizedKeys parses a public key from an authorized_keys
160 // file used in OpenSSH according to the sshd(8) manual page.
161 func ParseAuthorizedKey(in []byte) (out interface{}, comment string, options []s tring, rest []byte, ok bool) {
162 for len(in) > 0 {
163 end := bytes.IndexByte(in, '\n')
164 if end != -1 {
165 rest = in[end+1:]
166 in = in[:end]
167 } else {
168 rest = nil
169 }
170
171 end = bytes.IndexByte(in, '\r')
172 if end != -1 {
173 in = in[:end]
174 }
175
176 in = bytes.TrimSpace(in)
177 if len(in) == 0 || in[0] == '#' {
178 in = rest
179 continue
180 }
181
182 i := bytes.IndexAny(in, " \t")
183 if i == -1 {
184 in = rest
185 continue
186 }
187
188 field := string(in[:i])
189 switch field {
190 case keyAlgoRSA, keyAlgoDSA:
191 out, comment, ok = parseAuthorizedKey(in[i:])
192 if ok {
193 return
194 }
195 case keyAlgoECDSA256, keyAlgoECDSA384, keyAlgoECDSA521:
196 // We don't support these keys.
197 in = rest
198 continue
199 case hostAlgoRSACertV01, hostAlgoDSACertV01,
200 hostAlgoECDSA256CertV01, hostAlgoECDSA384CertV01, hostAl goECDSA521CertV01:
201 // We don't support these certificates.
202 in = rest
203 continue
204 }
205
206 // No key type recognised. Maybe there's an options field at
207 // the beginning.
208 var b byte
209 inQuote := false
210 var candidateOptions []string
211 optionStart := 0
212 for i, b = range in {
213 isEnd := !inQuote && (b == ' ' || b == '\t')
214 if (b == ',' && !inQuote) || isEnd {
215 if i-optionStart > 0 {
216 candidateOptions = append(candidateOptio ns, string(in[optionStart:i]))
217 }
218 optionStart = i + 1
219 }
220 if isEnd {
221 break
222 }
223 if b == '"' && (i == 0 || (i > 0 && in[i-1] != '\\')) {
224 inQuote = !inQuote
225 }
226 }
227 for i < len(in) && (in[i] == ' ' || in[i] == '\t') {
228 i++
229 }
230 if i == len(in) {
231 // Invalid line: unmatched quote
232 in = rest
233 continue
234 }
235
236 in = in[i:]
237 i = bytes.IndexAny(in, " \t")
238 if i == -1 {
239 in = rest
240 continue
241 }
242
243 field = string(in[:i])
244 switch field {
245 case keyAlgoRSA, keyAlgoDSA:
246 out, comment, ok = parseAuthorizedKey(in[i:])
247 if ok {
248 options = candidateOptions
249 return
250 }
251 }
252
253 in = rest
254 continue
255 }
256
257 return
258 }
259
260 // ParsePublicKey parses an ssh public key formatted for use in
261 // on the wire protocol of SSH.
262 func ParsePublicKey(in []byte) (out interface{}, rest []byte, ok bool) {
263 return parsePubKey(in)
264 }
265
266 // MarshalAuthorizedKey returns a byte stream suitable for inclusion
267 // in an OpenSSH authorized_keys file following the format specified
268 // in the sshd(8) manual page.
269 func MarshalAuthorizedKey(key interface{}) []byte {
270 b := &bytes.Buffer{}
271 switch keyType := key.(type) {
272 case *rsa.PublicKey:
273 b.WriteString(hostAlgoRSA)
274 case *dsa.PublicKey:
275 b.WriteString(hostAlgoDSA)
276 case *OpenSSHCertV01:
277 switch keyType.Key.(type) {
278 case *rsa.PublicKey:
279 b.WriteString(hostAlgoRSACertV01)
280 case *dsa.PublicKey:
281 b.WriteString(hostAlgoDSACertV01)
282 default:
283 panic("unexpected key type")
284 }
285 default:
286 panic("unexpected key type")
287 }
288
289 b.WriteByte(' ')
290 e := base64.NewEncoder(base64.StdEncoding, b)
291 e.Write(serializePublickey(key))
292 e.Close()
293 b.WriteByte('\n')
294 return b.Bytes()
295 }
296
297 // MarshalPublicKey serializes a *rsa.PublicKey, *dsa.PublicKey or
298 // *OpenSSHCertV01 for use on the wire protocol of SSH. It can be
299 // used for comparison with the pubkey argument of ServerConfig's
300 // PublickeyCallback as well as generating an authorized_keys or
301 // host_keys file.
302 func MarshalPublicKey(key interface{}) []byte {
303 return serializePublickey(key)
304 }
OLDNEW
« no previous file with comments | « no previous file | ssh/test/keys_test.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b