]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/golang.org/x/crypto/ssh/certs.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / golang.org / x / crypto / ssh / certs.go
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 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.
31 const (
32 UserCert = 1
33 HostCert = 2
34 )
35
36 // Signature represents a cryptographic signature.
37 type 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.
44 const CertTimeInfinity = 1<<64 - 1
45
46 // An Certificate represents an OpenSSH certificate as defined in
47 // [PROTOCOL.certkeys]?rev=1.8.
48 type 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.
66 type 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
80 func 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
89 type optionsTuple struct {
90 Key string
91 Value []byte
92 }
93
94 type 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
101 func 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
121 func 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
160 func 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
218 type 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.
226 func 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
234 func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
235 return s.signer.Sign(rand, data)
236 }
237
238 func (s *openSSHCertSigner) PublicKey() PublicKey {
239 return s.pub
240 }
241
242 const 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.
248 type 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.
282 func (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.
299 func (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.
321 func (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.
384 func (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
399 var 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.
410 func 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
419 func (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.
429 func (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.
461 func (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.
471 func (c *Certificate) Verify(data []byte, sig *Signature) error {
472 return c.Key.Verify(data, sig)
473 }
474
475 func 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
492 func 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 }