aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/golang.org/x/crypto/ssh/certs.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/ssh/certs.go')
-rw-r--r--vendor/golang.org/x/crypto/ssh/certs.go503
1 files changed, 503 insertions, 0 deletions
diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go
new file mode 100644
index 0000000..6331c94
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/certs.go
@@ -0,0 +1,503 @@
1// 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
7import (
8 "bytes"
9 "errors"
10 "fmt"
11 "io"
12 "net"
13 "sort"
14 "time"
15)
16
17// These constants from [PROTOCOL.certkeys] represent the algorithm names
18// for certificate types supported by this package.
19const (
20 CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
21 CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
22 CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
23 CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
24 CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
25 CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com"
26)
27
28// Certificate types distinguish between host and user
29// certificates. The values can be set in the CertType field of
30// Certificate.
31const (
32 UserCert = 1
33 HostCert = 2
34)
35
36// Signature represents a cryptographic signature.
37type Signature struct {
38 Format string
39 Blob []byte
40}
41
42// CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that
43// a certificate does not expire.
44const CertTimeInfinity = 1<<64 - 1
45
46// An Certificate represents an OpenSSH certificate as defined in
47// [PROTOCOL.certkeys]?rev=1.8.
48type Certificate struct {
49 Nonce []byte
50 Key PublicKey
51 Serial uint64
52 CertType uint32
53 KeyId string
54 ValidPrincipals []string
55 ValidAfter uint64
56 ValidBefore uint64
57 Permissions
58 Reserved []byte
59 SignatureKey PublicKey
60 Signature *Signature
61}
62
63// genericCertData holds the key-independent part of the certificate data.
64// Overall, certificates contain an nonce, public key fields and
65// key-independent fields.
66type genericCertData struct {
67 Serial uint64
68 CertType uint32
69 KeyId string
70 ValidPrincipals []byte
71 ValidAfter uint64
72 ValidBefore uint64
73 CriticalOptions []byte
74 Extensions []byte
75 Reserved []byte
76 SignatureKey []byte
77 Signature []byte
78}
79
80func marshalStringList(namelist []string) []byte {
81 var to []byte
82 for _, name := range namelist {
83 s := struct{ N string }{name}
84 to = append(to, Marshal(&s)...)
85 }
86 return to
87}
88
89type optionsTuple struct {
90 Key string
91 Value []byte
92}
93
94type optionsTupleValue struct {
95 Value string
96}
97
98// serialize a map of critical options or extensions
99// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
100// we need two length prefixes for a non-empty string value
101func marshalTuples(tups map[string]string) []byte {
102 keys := make([]string, 0, len(tups))
103 for key := range tups {
104 keys = append(keys, key)
105 }
106 sort.Strings(keys)
107
108 var ret []byte
109 for _, key := range keys {
110 s := optionsTuple{Key: key}
111 if value := tups[key]; len(value) > 0 {
112 s.Value = Marshal(&optionsTupleValue{value})
113 }
114 ret = append(ret, Marshal(&s)...)
115 }
116 return ret
117}
118
119// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
120// we need two length prefixes for a non-empty option value
121func parseTuples(in []byte) (map[string]string, error) {
122 tups := map[string]string{}
123 var lastKey string
124 var haveLastKey bool
125
126 for len(in) > 0 {
127 var key, val, extra []byte
128 var ok bool
129
130 if key, in, ok = parseString(in); !ok {
131 return nil, errShortRead
132 }
133 keyStr := string(key)
134 // according to [PROTOCOL.certkeys], the names must be in
135 // lexical order.
136 if haveLastKey && keyStr <= lastKey {
137 return nil, fmt.Errorf("ssh: certificate options are not in lexical order")
138 }
139 lastKey, haveLastKey = keyStr, true
140 // the next field is a data field, which if non-empty has a string embedded
141 if val, in, ok = parseString(in); !ok {
142 return nil, errShortRead
143 }
144 if len(val) > 0 {
145 val, extra, ok = parseString(val)
146 if !ok {
147 return nil, errShortRead
148 }
149 if len(extra) > 0 {
150 return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value")
151 }
152 tups[keyStr] = string(val)
153 } else {
154 tups[keyStr] = ""
155 }
156 }
157 return tups, nil
158}
159
160func parseCert(in []byte, privAlgo string) (*Certificate, error) {
161 nonce, rest, ok := parseString(in)
162 if !ok {
163 return nil, errShortRead
164 }
165
166 key, rest, err := parsePubKey(rest, privAlgo)
167 if err != nil {
168 return nil, err
169 }
170
171 var g genericCertData
172 if err := Unmarshal(rest, &g); err != nil {
173 return nil, err
174 }
175
176 c := &Certificate{
177 Nonce: nonce,
178 Key: key,
179 Serial: g.Serial,
180 CertType: g.CertType,
181 KeyId: g.KeyId,
182 ValidAfter: g.ValidAfter,
183 ValidBefore: g.ValidBefore,
184 }
185
186 for principals := g.ValidPrincipals; len(principals) > 0; {
187 principal, rest, ok := parseString(principals)
188 if !ok {
189 return nil, errShortRead
190 }
191 c.ValidPrincipals = append(c.ValidPrincipals, string(principal))
192 principals = rest
193 }
194
195 c.CriticalOptions, err = parseTuples(g.CriticalOptions)
196 if err != nil {
197 return nil, err
198 }
199 c.Extensions, err = parseTuples(g.Extensions)
200 if err != nil {
201 return nil, err
202 }
203 c.Reserved = g.Reserved
204 k, err := ParsePublicKey(g.SignatureKey)
205 if err != nil {
206 return nil, err
207 }
208
209 c.SignatureKey = k
210 c.Signature, rest, ok = parseSignatureBody(g.Signature)
211 if !ok || len(rest) > 0 {
212 return nil, errors.New("ssh: signature parse error")
213 }
214
215 return c, nil
216}
217
218type openSSHCertSigner struct {
219 pub *Certificate
220 signer Signer
221}
222
223// NewCertSigner returns a Signer that signs with the given Certificate, whose
224// private key is held by signer. It returns an error if the public key in cert
225// doesn't match the key used by signer.
226func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
227 if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {
228 return nil, errors.New("ssh: signer and cert have different public key")
229 }
230
231 return &openSSHCertSigner{cert, signer}, nil
232}
233
234func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
235 return s.signer.Sign(rand, data)
236}
237
238func (s *openSSHCertSigner) PublicKey() PublicKey {
239 return s.pub
240}
241
242const sourceAddressCriticalOption = "source-address"
243
244// CertChecker does the work of verifying a certificate. Its methods
245// can be plugged into ClientConfig.HostKeyCallback and
246// ServerConfig.PublicKeyCallback. For the CertChecker to work,
247// minimally, the IsAuthority callback should be set.
248type CertChecker struct {
249 // SupportedCriticalOptions lists the CriticalOptions that the
250 // server application layer understands. These are only used
251 // for user certificates.
252 SupportedCriticalOptions []string
253
254 // IsAuthority should return true if the key is recognized as
255 // an authority. This allows for certificates to be signed by other
256 // certificates.
257 IsAuthority func(auth PublicKey) bool
258
259 // Clock is used for verifying time stamps. If nil, time.Now
260 // is used.
261 Clock func() time.Time
262
263 // UserKeyFallback is called when CertChecker.Authenticate encounters a
264 // public key that is not a certificate. It must implement validation
265 // of user keys or else, if nil, all such keys are rejected.
266 UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
267
268 // HostKeyFallback is called when CertChecker.CheckHostKey encounters a
269 // public key that is not a certificate. It must implement host key
270 // validation or else, if nil, all such keys are rejected.
271 HostKeyFallback func(addr string, remote net.Addr, key PublicKey) error
272
273 // IsRevoked is called for each certificate so that revocation checking
274 // can be implemented. It should return true if the given certificate
275 // is revoked and false otherwise. If nil, no certificates are
276 // considered to have been revoked.
277 IsRevoked func(cert *Certificate) bool
278}
279
280// CheckHostKey checks a host key certificate. This method can be
281// plugged into ClientConfig.HostKeyCallback.
282func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error {
283 cert, ok := key.(*Certificate)
284 if !ok {
285 if c.HostKeyFallback != nil {
286 return c.HostKeyFallback(addr, remote, key)
287 }
288 return errors.New("ssh: non-certificate host key")
289 }
290 if cert.CertType != HostCert {
291 return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)
292 }
293
294 return c.CheckCert(addr, cert)
295}
296
297// Authenticate checks a user certificate. Authenticate can be used as
298// a value for ServerConfig.PublicKeyCallback.
299func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) {
300 cert, ok := pubKey.(*Certificate)
301 if !ok {
302 if c.UserKeyFallback != nil {
303 return c.UserKeyFallback(conn, pubKey)
304 }
305 return nil, errors.New("ssh: normal key pairs not accepted")
306 }
307
308 if cert.CertType != UserCert {
309 return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)
310 }
311
312 if err := c.CheckCert(conn.User(), cert); err != nil {
313 return nil, err
314 }
315
316 return &cert.Permissions, nil
317}
318
319// CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and
320// the signature of the certificate.
321func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
322 if c.IsRevoked != nil && c.IsRevoked(cert) {
323 return fmt.Errorf("ssh: certicate serial %d revoked", cert.Serial)
324 }
325
326 for opt, _ := range cert.CriticalOptions {
327 // sourceAddressCriticalOption will be enforced by
328 // serverAuthenticate
329 if opt == sourceAddressCriticalOption {
330 continue
331 }
332
333 found := false
334 for _, supp := range c.SupportedCriticalOptions {
335 if supp == opt {
336 found = true
337 break
338 }
339 }
340 if !found {
341 return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt)
342 }
343 }
344
345 if len(cert.ValidPrincipals) > 0 {
346 // By default, certs are valid for all users/hosts.
347 found := false
348 for _, p := range cert.ValidPrincipals {
349 if p == principal {
350 found = true
351 break
352 }
353 }
354 if !found {
355 return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals)
356 }
357 }
358
359 if !c.IsAuthority(cert.SignatureKey) {
360 return fmt.Errorf("ssh: certificate signed by unrecognized authority")
361 }
362
363 clock := c.Clock
364 if clock == nil {
365 clock = time.Now
366 }
367
368 unixNow := clock().Unix()
369 if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
370 return fmt.Errorf("ssh: cert is not yet valid")
371 }
372 if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {
373 return fmt.Errorf("ssh: cert has expired")
374 }
375 if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
376 return fmt.Errorf("ssh: certificate signature does not verify")
377 }
378
379 return nil
380}
381
382// SignCert sets c.SignatureKey to the authority's public key and stores a
383// Signature, by authority, in the certificate.
384func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
385 c.Nonce = make([]byte, 32)
386 if _, err := io.ReadFull(rand, c.Nonce); err != nil {
387 return err
388 }
389 c.SignatureKey = authority.PublicKey()
390
391 sig, err := authority.Sign(rand, c.bytesForSigning())
392 if err != nil {
393 return err
394 }
395 c.Signature = sig
396 return nil
397}
398
399var certAlgoNames = map[string]string{
400 KeyAlgoRSA: CertAlgoRSAv01,
401 KeyAlgoDSA: CertAlgoDSAv01,
402 KeyAlgoECDSA256: CertAlgoECDSA256v01,
403 KeyAlgoECDSA384: CertAlgoECDSA384v01,
404 KeyAlgoECDSA521: CertAlgoECDSA521v01,
405 KeyAlgoED25519: CertAlgoED25519v01,
406}
407
408// certToPrivAlgo returns the underlying algorithm for a certificate algorithm.
409// Panics if a non-certificate algorithm is passed.
410func certToPrivAlgo(algo string) string {
411 for privAlgo, pubAlgo := range certAlgoNames {
412 if pubAlgo == algo {
413 return privAlgo
414 }
415 }
416 panic("unknown cert algorithm")
417}
418
419func (cert *Certificate) bytesForSigning() []byte {
420 c2 := *cert
421 c2.Signature = nil
422 out := c2.Marshal()
423 // Drop trailing signature length.
424 return out[:len(out)-4]
425}
426
427// Marshal serializes c into OpenSSH's wire format. It is part of the
428// PublicKey interface.
429func (c *Certificate) Marshal() []byte {
430 generic := genericCertData{
431 Serial: c.Serial,
432 CertType: c.CertType,
433 KeyId: c.KeyId,
434 ValidPrincipals: marshalStringList(c.ValidPrincipals),
435 ValidAfter: uint64(c.ValidAfter),
436 ValidBefore: uint64(c.ValidBefore),
437 CriticalOptions: marshalTuples(c.CriticalOptions),
438 Extensions: marshalTuples(c.Extensions),
439 Reserved: c.Reserved,
440 SignatureKey: c.SignatureKey.Marshal(),
441 }
442 if c.Signature != nil {
443 generic.Signature = Marshal(c.Signature)
444 }
445 genericBytes := Marshal(&generic)
446 keyBytes := c.Key.Marshal()
447 _, keyBytes, _ = parseString(keyBytes)
448 prefix := Marshal(&struct {
449 Name string
450 Nonce []byte
451 Key []byte `ssh:"rest"`
452 }{c.Type(), c.Nonce, keyBytes})
453
454 result := make([]byte, 0, len(prefix)+len(genericBytes))
455 result = append(result, prefix...)
456 result = append(result, genericBytes...)
457 return result
458}
459
460// Type returns the key name. It is part of the PublicKey interface.
461func (c *Certificate) Type() string {
462 algo, ok := certAlgoNames[c.Key.Type()]
463 if !ok {
464 panic("unknown cert key type " + c.Key.Type())
465 }
466 return algo
467}
468
469// Verify verifies a signature against the certificate's public
470// key. It is part of the PublicKey interface.
471func (c *Certificate) Verify(data []byte, sig *Signature) error {
472 return c.Key.Verify(data, sig)
473}
474
475func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) {
476 format, in, ok := parseString(in)
477 if !ok {
478 return
479 }
480
481 out = &Signature{
482 Format: string(format),
483 }
484
485 if out.Blob, in, ok = parseString(in); !ok {
486 return
487 }
488
489 return out, in, ok
490}
491
492func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) {
493 sigBytes, rest, ok := parseString(in)
494 if !ok {
495 return
496 }
497
498 out, trailing, ok := parseSignatureBody(sigBytes)
499 if !ok || len(trailing) > 0 {
500 return nil, nil, false
501 }
502 return
503}