blob: 4ef71035f17d36f7483876f599253d2b6c9ca38d [file] [log] [blame]
Jonathan Pittman9b05c272012-02-24 12:52:06 -05001// Copyright 2012 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package ssh
6
Jonathan Pittman9b05c272012-02-24 12:52:06 -05007import (
8 "crypto/dsa"
Jonathan Pittman94c9f922012-12-14 05:52:19 +11009 "crypto/ecdsa"
Jonathan Pittman9b05c272012-02-24 12:52:06 -050010 "crypto/rsa"
11 "time"
12)
13
14// String constants in [PROTOCOL.certkeys] for certificate algorithm names.
15const (
Jonathan Pittman54c65ae2012-12-14 10:11:06 -050016 CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
17 CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
18 CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
19 CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
20 CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
Jonathan Pittman9b05c272012-02-24 12:52:06 -050021)
22
23// Certificate types are used to specify whether a certificate is for identification
24// of a user or a host. Current identities are defined in [PROTOCOL.certkeys].
25const (
26 UserCert = 1
27 HostCert = 2
28)
29
30type signature struct {
31 Format string
32 Blob []byte
33}
34
35type tuple struct {
36 Name string
37 Data string
38}
39
40// An OpenSSHCertV01 represents an OpenSSH certificate as defined in
Jonathan Pittman54c65ae2012-12-14 10:11:06 -050041// [PROTOCOL.certkeys]?rev=1.8.
Jonathan Pittman9b05c272012-02-24 12:52:06 -050042type OpenSSHCertV01 struct {
43 Nonce []byte
Jonathan Pittman94c9f922012-12-14 05:52:19 +110044 Key interface{} // rsa, dsa, or ecdsa *PublicKey
Jonathan Pittman9b05c272012-02-24 12:52:06 -050045 Serial uint64
46 Type uint32
47 KeyId string
48 ValidPrincipals []string
49 ValidAfter, ValidBefore time.Time
50 CriticalOptions []tuple
51 Extensions []tuple
52 Reserved []byte
53 SignatureKey interface{} // rsa, dsa, or ecdsa *PublicKey
54 Signature *signature
55}
56
57func parseOpenSSHCertV01(in []byte, algo string) (out *OpenSSHCertV01, rest []byte, ok bool) {
58 cert := new(OpenSSHCertV01)
59
60 if cert.Nonce, in, ok = parseString(in); !ok {
61 return
62 }
63
64 switch algo {
Jonathan Pittman54c65ae2012-12-14 10:11:06 -050065 case CertAlgoRSAv01:
Jonathan Pittman9b05c272012-02-24 12:52:06 -050066 var rsaPubKey *rsa.PublicKey
67 if rsaPubKey, in, ok = parseRSA(in); !ok {
68 return
69 }
70 cert.Key = rsaPubKey
Jonathan Pittman54c65ae2012-12-14 10:11:06 -050071 case CertAlgoDSAv01:
Jonathan Pittman9b05c272012-02-24 12:52:06 -050072 var dsaPubKey *dsa.PublicKey
73 if dsaPubKey, in, ok = parseDSA(in); !ok {
74 return
75 }
76 cert.Key = dsaPubKey
Jonathan Pittman54c65ae2012-12-14 10:11:06 -050077 case CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01:
Jonathan Pittman94c9f922012-12-14 05:52:19 +110078 var ecdsaPubKey *ecdsa.PublicKey
79 if ecdsaPubKey, in, ok = parseECDSA(in); !ok {
80 return
81 }
82 cert.Key = ecdsaPubKey
Jonathan Pittman9b05c272012-02-24 12:52:06 -050083 default:
Jonathan Pittman8ab83122012-04-26 17:13:49 -040084 ok = false
Jonathan Pittman9b05c272012-02-24 12:52:06 -050085 return
86 }
87
88 if cert.Serial, in, ok = parseUint64(in); !ok {
89 return
90 }
91
92 if cert.Type, in, ok = parseUint32(in); !ok || cert.Type != UserCert && cert.Type != HostCert {
93 return
94 }
95
96 keyId, in, ok := parseString(in)
97 if !ok {
98 return
99 }
100 cert.KeyId = string(keyId)
101
102 if cert.ValidPrincipals, in, ok = parseLengthPrefixedNameList(in); !ok {
103 return
104 }
105
106 va, in, ok := parseUint64(in)
107 if !ok {
108 return
109 }
110 cert.ValidAfter = time.Unix(int64(va), 0)
111
112 vb, in, ok := parseUint64(in)
113 if !ok {
114 return
115 }
116 cert.ValidBefore = time.Unix(int64(vb), 0)
117
118 if cert.CriticalOptions, in, ok = parseTupleList(in); !ok {
119 return
120 }
121
122 if cert.Extensions, in, ok = parseTupleList(in); !ok {
123 return
124 }
125
126 if cert.Reserved, in, ok = parseString(in); !ok {
127 return
128 }
129
130 sigKey, in, ok := parseString(in)
131 if !ok {
132 return
133 }
134 if cert.SignatureKey, _, ok = parsePubKey(sigKey); !ok {
135 return
136 }
137
138 if cert.Signature, in, ok = parseSignature(in); !ok {
139 return
140 }
141
142 ok = true
143 return cert, in, ok
144}
145
146func marshalOpenSSHCertV01(cert *OpenSSHCertV01) []byte {
147 var pubKey []byte
148 switch cert.Key.(type) {
149 case *rsa.PublicKey:
150 k := cert.Key.(*rsa.PublicKey)
151 pubKey = marshalPubRSA(k)
152 case *dsa.PublicKey:
153 k := cert.Key.(*dsa.PublicKey)
154 pubKey = marshalPubDSA(k)
Jonathan Pittman94c9f922012-12-14 05:52:19 +1100155 case *ecdsa.PublicKey:
156 k := cert.Key.(*ecdsa.PublicKey)
157 pubKey = marshalPubECDSA(k)
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500158 default:
159 panic("ssh: unknown public key type in cert")
160 }
161
162 sigKey := serializePublickey(cert.SignatureKey)
163
Adam Langley63f855d2012-04-20 15:17:42 -0400164 length := stringLength(len(cert.Nonce))
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500165 length += len(pubKey)
166 length += 8 // Length of Serial
167 length += 4 // Length of Type
Adam Langley63f855d2012-04-20 15:17:42 -0400168 length += stringLength(len(cert.KeyId))
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500169 length += lengthPrefixedNameListLength(cert.ValidPrincipals)
170 length += 8 // Length of ValidAfter
171 length += 8 // Length of ValidBefore
172 length += tupleListLength(cert.CriticalOptions)
173 length += tupleListLength(cert.Extensions)
Adam Langley63f855d2012-04-20 15:17:42 -0400174 length += stringLength(len(cert.Reserved))
175 length += stringLength(len(sigKey))
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500176 length += signatureLength(cert.Signature)
177
178 ret := make([]byte, length)
179 r := marshalString(ret, cert.Nonce)
180 copy(r, pubKey)
181 r = r[len(pubKey):]
182 r = marshalUint64(r, cert.Serial)
183 r = marshalUint32(r, cert.Type)
184 r = marshalString(r, []byte(cert.KeyId))
185 r = marshalLengthPrefixedNameList(r, cert.ValidPrincipals)
186 r = marshalUint64(r, uint64(cert.ValidAfter.Unix()))
187 r = marshalUint64(r, uint64(cert.ValidBefore.Unix()))
188 r = marshalTupleList(r, cert.CriticalOptions)
189 r = marshalTupleList(r, cert.Extensions)
190 r = marshalString(r, cert.Reserved)
191 r = marshalString(r, sigKey)
192 r = marshalSignature(r, cert.Signature)
193 if len(r) > 0 {
194 panic("internal error")
195 }
196 return ret
197}
198
199func lengthPrefixedNameListLength(namelist []string) int {
200 length := 4 // length prefix for list
201 for _, name := range namelist {
202 length += 4 // length prefix for name
203 length += len(name)
204 }
205 return length
206}
207
208func marshalLengthPrefixedNameList(to []byte, namelist []string) []byte {
209 length := uint32(lengthPrefixedNameListLength(namelist) - 4)
210 to = marshalUint32(to, length)
211 for _, name := range namelist {
212 to = marshalString(to, []byte(name))
213 }
214 return to
215}
216
217func parseLengthPrefixedNameList(in []byte) (out []string, rest []byte, ok bool) {
218 list, rest, ok := parseString(in)
219 if !ok {
220 return
221 }
222
223 for len(list) > 0 {
224 var next []byte
Adam Langley63f855d2012-04-20 15:17:42 -0400225 if next, list, ok = parseString(list); !ok {
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500226 return nil, nil, false
227 }
228 out = append(out, string(next))
229 }
230 ok = true
231 return
232}
233
234func tupleListLength(tupleList []tuple) int {
235 length := 4 // length prefix for list
236 for _, t := range tupleList {
237 length += 4 // length prefix for t.Name
238 length += len(t.Name)
239 length += 4 // length prefix for t.Data
240 length += len(t.Data)
241 }
242 return length
243}
244
245func marshalTupleList(to []byte, tuplelist []tuple) []byte {
246 length := uint32(tupleListLength(tuplelist) - 4)
247 to = marshalUint32(to, length)
248 for _, t := range tuplelist {
249 to = marshalString(to, []byte(t.Name))
250 to = marshalString(to, []byte(t.Data))
251 }
252 return to
253}
254
255func parseTupleList(in []byte) (out []tuple, rest []byte, ok bool) {
256 list, rest, ok := parseString(in)
257 if !ok {
258 return
259 }
260
261 for len(list) > 0 {
262 var name, data []byte
263 var ok bool
264 name, list, ok = parseString(list)
265 if !ok {
266 return nil, nil, false
267 }
268 data, list, ok = parseString(list)
269 if !ok {
270 return nil, nil, false
271 }
272 out = append(out, tuple{string(name), string(data)})
273 }
274 ok = true
275 return
276}
277
278func signatureLength(sig *signature) int {
279 length := 4 // length prefix for signature
Adam Langley63f855d2012-04-20 15:17:42 -0400280 length += stringLength(len(sig.Format))
281 length += stringLength(len(sig.Blob))
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500282 return length
283}
284
285func marshalSignature(to []byte, sig *signature) []byte {
286 length := uint32(signatureLength(sig) - 4)
287 to = marshalUint32(to, length)
288 to = marshalString(to, []byte(sig.Format))
289 to = marshalString(to, sig.Blob)
290 return to
291}
292
293func parseSignature(in []byte) (out *signature, rest []byte, ok bool) {
294 var sigBytes, format []byte
295 sig := new(signature)
296
297 if sigBytes, rest, ok = parseString(in); !ok {
298 return
299 }
300
301 if format, sigBytes, ok = parseString(sigBytes); !ok {
302 return
303 }
304 sig.Format = string(format)
305
306 if sig.Blob, sigBytes, ok = parseString(sigBytes); !ok {
307 return
308 }
309
310 return sig, rest, ok
311}