~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/golang.org/x/crypto/ssh/certs.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

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