summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto')
-rw-r--r--vendor/golang.org/x/crypto/acme/autocert/autocert.go316
-rw-r--r--vendor/golang.org/x/crypto/acme/autocert/autocert_test.go151
-rw-r--r--vendor/golang.org/x/crypto/acme/autocert/example_test.go3
-rw-r--r--vendor/golang.org/x/crypto/argon2/blamka_amd64.go2
-rw-r--r--vendor/golang.org/x/crypto/ssh/cipher.go240
-rw-r--r--vendor/golang.org/x/crypto/ssh/cipher_test.go11
-rw-r--r--vendor/golang.org/x/crypto/ssh/client_test.go92
-rw-r--r--vendor/golang.org/x/crypto/ssh/common.go16
-rw-r--r--vendor/golang.org/x/crypto/ssh/test/session_test.go61
-rw-r--r--vendor/golang.org/x/crypto/ssh/transport.go56
-rw-r--r--vendor/golang.org/x/crypto/ssh/transport_test.go14
11 files changed, 734 insertions, 228 deletions
diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert.go b/vendor/golang.org/x/crypto/acme/autocert/autocert.go
index 94edba986..453e72291 100644
--- a/vendor/golang.org/x/crypto/acme/autocert/autocert.go
+++ b/vendor/golang.org/x/crypto/acme/autocert/autocert.go
@@ -24,7 +24,9 @@ import (
"fmt"
"io"
mathrand "math/rand"
+ "net"
"net/http"
+ "path"
"strconv"
"strings"
"sync"
@@ -80,8 +82,9 @@ func defaultHostPolicy(context.Context, string) error {
}
// Manager is a stateful certificate manager built on top of acme.Client.
-// It obtains and refreshes certificates automatically,
-// as well as providing them to a TLS server via tls.Config.
+// It obtains and refreshes certificates automatically using "tls-sni-01",
+// "tls-sni-02" and "http-01" challenge types, as well as providing them
+// to a TLS server via tls.Config.
//
// You must specify a cache implementation, such as DirCache,
// to reuse obtained certificates across program restarts.
@@ -150,15 +153,26 @@ type Manager struct {
stateMu sync.Mutex
state map[string]*certState // keyed by domain name
- // tokenCert is keyed by token domain name, which matches server name
- // of ClientHello. Keys always have ".acme.invalid" suffix.
- tokenCertMu sync.RWMutex
- tokenCert map[string]*tls.Certificate
-
// renewal tracks the set of domains currently running renewal timers.
// It is keyed by domain name.
renewalMu sync.Mutex
renewal map[string]*domainRenewal
+
+ // tokensMu guards the rest of the fields: tryHTTP01, certTokens and httpTokens.
+ tokensMu sync.RWMutex
+ // tryHTTP01 indicates whether the Manager should try "http-01" challenge type
+ // during the authorization flow.
+ tryHTTP01 bool
+ // httpTokens contains response body values for http-01 challenges
+ // and is keyed by the URL path at which a challenge response is expected
+ // to be provisioned.
+ // The entries are stored for the duration of the authorization flow.
+ httpTokens map[string][]byte
+ // certTokens contains temporary certificates for tls-sni challenges
+ // and is keyed by token domain name, which matches server name of ClientHello.
+ // Keys always have ".acme.invalid" suffix.
+ // The entries are stored for the duration of the authorization flow.
+ certTokens map[string]*tls.Certificate
}
// GetCertificate implements the tls.Config.GetCertificate hook.
@@ -185,14 +199,16 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
return nil, errors.New("acme/autocert: server name contains invalid character")
}
+ // In the worst-case scenario, the timeout needs to account for caching, host policy,
+ // domain ownership verification and certificate issuance.
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
// check whether this is a token cert requested for TLS-SNI challenge
if strings.HasSuffix(name, ".acme.invalid") {
- m.tokenCertMu.RLock()
- defer m.tokenCertMu.RUnlock()
- if cert := m.tokenCert[name]; cert != nil {
+ m.tokensMu.RLock()
+ defer m.tokensMu.RUnlock()
+ if cert := m.certTokens[name]; cert != nil {
return cert, nil
}
if cert, err := m.cacheGet(ctx, name); err == nil {
@@ -224,6 +240,68 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
return cert, nil
}
+// HTTPHandler configures the Manager to provision ACME "http-01" challenge responses.
+// It returns an http.Handler that responds to the challenges and must be
+// running on port 80. If it receives a request that is not an ACME challenge,
+// it delegates the request to the optional fallback handler.
+//
+// If fallback is nil, the returned handler redirects all GET and HEAD requests
+// to the default TLS port 443 with 302 Found status code, preserving the original
+// request path and query. It responds with 400 Bad Request to all other HTTP methods.
+// The fallback is not protected by the optional HostPolicy.
+//
+// Because the fallback handler is run with unencrypted port 80 requests,
+// the fallback should not serve TLS-only requests.
+//
+// If HTTPHandler is never called, the Manager will only use TLS SNI
+// challenges for domain verification.
+func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler {
+ m.tokensMu.Lock()
+ defer m.tokensMu.Unlock()
+ m.tryHTTP01 = true
+
+ if fallback == nil {
+ fallback = http.HandlerFunc(handleHTTPRedirect)
+ }
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if !strings.HasPrefix(r.URL.Path, "/.well-known/acme-challenge/") {
+ fallback.ServeHTTP(w, r)
+ return
+ }
+ // A reasonable context timeout for cache and host policy only,
+ // because we don't wait for a new certificate issuance here.
+ ctx, cancel := context.WithTimeout(r.Context(), time.Minute)
+ defer cancel()
+ if err := m.hostPolicy()(ctx, r.Host); err != nil {
+ http.Error(w, err.Error(), http.StatusForbidden)
+ return
+ }
+ data, err := m.httpToken(ctx, r.URL.Path)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusNotFound)
+ return
+ }
+ w.Write(data)
+ })
+}
+
+func handleHTTPRedirect(w http.ResponseWriter, r *http.Request) {
+ if r.Method != "GET" && r.Method != "HEAD" {
+ http.Error(w, "Use HTTPS", http.StatusBadRequest)
+ return
+ }
+ target := "https://" + stripPort(r.Host) + r.URL.RequestURI()
+ http.Redirect(w, r, target, http.StatusFound)
+}
+
+func stripPort(hostport string) string {
+ host, _, err := net.SplitHostPort(hostport)
+ if err != nil {
+ return hostport
+ }
+ return net.JoinHostPort(host, "443")
+}
+
// cert returns an existing certificate either from m.state or cache.
// If a certificate is found in cache but not in m.state, the latter will be filled
// with the cached value.
@@ -442,13 +520,14 @@ func (m *Manager) certState(domain string) (*certState, error) {
// authorizedCert starts the domain ownership verification process and requests a new cert upon success.
// The key argument is the certificate private key.
func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain string) (der [][]byte, leaf *x509.Certificate, err error) {
- if err := m.verify(ctx, domain); err != nil {
- return nil, nil, err
- }
client, err := m.acmeClient(ctx)
if err != nil {
return nil, nil, err
}
+
+ if err := m.verify(ctx, client, domain); err != nil {
+ return nil, nil, err
+ }
csr, err := certRequest(key, domain)
if err != nil {
return nil, nil, err
@@ -464,98 +543,171 @@ func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain
return der, leaf, nil
}
-// verify starts a new identifier (domain) authorization flow.
-// It prepares a challenge response and then blocks until the authorization
-// is marked as "completed" by the CA (either succeeded or failed).
-//
-// verify returns nil iff the verification was successful.
-func (m *Manager) verify(ctx context.Context, domain string) error {
- client, err := m.acmeClient(ctx)
- if err != nil {
- return err
- }
-
- // start domain authorization and get the challenge
- authz, err := client.Authorize(ctx, domain)
- if err != nil {
- return err
- }
- // maybe don't need to at all
- if authz.Status == acme.StatusValid {
- return nil
- }
+// verify runs the identifier (domain) authorization flow
+// using each applicable ACME challenge type.
+func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error {
+ // The list of challenge types we'll try to fulfill
+ // in this specific order.
+ challengeTypes := []string{"tls-sni-02", "tls-sni-01"}
+ m.tokensMu.RLock()
+ if m.tryHTTP01 {
+ challengeTypes = append(challengeTypes, "http-01")
+ }
+ m.tokensMu.RUnlock()
+
+ var nextTyp int // challengeType index of the next challenge type to try
+ for {
+ // Start domain authorization and get the challenge.
+ authz, err := client.Authorize(ctx, domain)
+ if err != nil {
+ return err
+ }
+ // No point in accepting challenges if the authorization status
+ // is in a final state.
+ switch authz.Status {
+ case acme.StatusValid:
+ return nil // already authorized
+ case acme.StatusInvalid:
+ return fmt.Errorf("acme/autocert: invalid authorization %q", authz.URI)
+ }
- // pick a challenge: prefer tls-sni-02 over tls-sni-01
- // TODO: consider authz.Combinations
- var chal *acme.Challenge
- for _, c := range authz.Challenges {
- if c.Type == "tls-sni-02" {
- chal = c
- break
+ // Pick the next preferred challenge.
+ var chal *acme.Challenge
+ for chal == nil && nextTyp < len(challengeTypes) {
+ chal = pickChallenge(challengeTypes[nextTyp], authz.Challenges)
+ nextTyp++
}
- if c.Type == "tls-sni-01" {
- chal = c
+ if chal == nil {
+ return fmt.Errorf("acme/autocert: unable to authorize %q; tried %q", domain, challengeTypes)
+ }
+ cleanup, err := m.fulfill(ctx, client, chal)
+ if err != nil {
+ continue
+ }
+ defer cleanup()
+ if _, err := client.Accept(ctx, chal); err != nil {
+ continue
+ }
+
+ // A challenge is fulfilled and accepted: wait for the CA to validate.
+ if _, err := client.WaitAuthorization(ctx, authz.URI); err == nil {
+ return nil
}
}
- if chal == nil {
- return errors.New("acme/autocert: no supported challenge type found")
- }
+}
- // create a token cert for the challenge response
- var (
- cert tls.Certificate
- name string
- )
+// fulfill provisions a response to the challenge chal.
+// The cleanup is non-nil only if provisioning succeeded.
+func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge) (cleanup func(), err error) {
switch chal.Type {
case "tls-sni-01":
- cert, name, err = client.TLSSNI01ChallengeCert(chal.Token)
+ cert, name, err := client.TLSSNI01ChallengeCert(chal.Token)
+ if err != nil {
+ return nil, err
+ }
+ m.putCertToken(ctx, name, &cert)
+ return func() { go m.deleteCertToken(name) }, nil
case "tls-sni-02":
- cert, name, err = client.TLSSNI02ChallengeCert(chal.Token)
- default:
- err = fmt.Errorf("acme/autocert: unknown challenge type %q", chal.Type)
- }
- if err != nil {
- return err
+ cert, name, err := client.TLSSNI02ChallengeCert(chal.Token)
+ if err != nil {
+ return nil, err
+ }
+ m.putCertToken(ctx, name, &cert)
+ return func() { go m.deleteCertToken(name) }, nil
+ case "http-01":
+ resp, err := client.HTTP01ChallengeResponse(chal.Token)
+ if err != nil {
+ return nil, err
+ }
+ p := client.HTTP01ChallengePath(chal.Token)
+ m.putHTTPToken(ctx, p, resp)
+ return func() { go m.deleteHTTPToken(p) }, nil
}
- m.putTokenCert(ctx, name, &cert)
- defer func() {
- // verification has ended at this point
- // don't need token cert anymore
- go m.deleteTokenCert(name)
- }()
+ return nil, fmt.Errorf("acme/autocert: unknown challenge type %q", chal.Type)
+}
- // ready to fulfill the challenge
- if _, err := client.Accept(ctx, chal); err != nil {
- return err
+func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge {
+ for _, c := range chal {
+ if c.Type == typ {
+ return c
+ }
}
- // wait for the CA to validate
- _, err = client.WaitAuthorization(ctx, authz.URI)
- return err
+ return nil
}
-// putTokenCert stores the cert under the named key in both m.tokenCert map
+// putCertToken stores the cert under the named key in both m.certTokens map
// and m.Cache.
-func (m *Manager) putTokenCert(ctx context.Context, name string, cert *tls.Certificate) {
- m.tokenCertMu.Lock()
- defer m.tokenCertMu.Unlock()
- if m.tokenCert == nil {
- m.tokenCert = make(map[string]*tls.Certificate)
+func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certificate) {
+ m.tokensMu.Lock()
+ defer m.tokensMu.Unlock()
+ if m.certTokens == nil {
+ m.certTokens = make(map[string]*tls.Certificate)
}
- m.tokenCert[name] = cert
+ m.certTokens[name] = cert
m.cachePut(ctx, name, cert)
}
-// deleteTokenCert removes the token certificate for the specified domain name
-// from both m.tokenCert map and m.Cache.
-func (m *Manager) deleteTokenCert(name string) {
- m.tokenCertMu.Lock()
- defer m.tokenCertMu.Unlock()
- delete(m.tokenCert, name)
+// deleteCertToken removes the token certificate for the specified domain name
+// from both m.certTokens map and m.Cache.
+func (m *Manager) deleteCertToken(name string) {
+ m.tokensMu.Lock()
+ defer m.tokensMu.Unlock()
+ delete(m.certTokens, name)
if m.Cache != nil {
m.Cache.Delete(context.Background(), name)
}
}
+// httpToken retrieves an existing http-01 token value from an in-memory map
+// or the optional cache.
+func (m *Manager) httpToken(ctx context.Context, tokenPath string) ([]byte, error) {
+ m.tokensMu.RLock()
+ defer m.tokensMu.RUnlock()
+ if v, ok := m.httpTokens[tokenPath]; ok {
+ return v, nil
+ }
+ if m.Cache == nil {
+ return nil, fmt.Errorf("acme/autocert: no token at %q", tokenPath)
+ }
+ return m.Cache.Get(ctx, httpTokenCacheKey(tokenPath))
+}
+
+// putHTTPToken stores an http-01 token value using tokenPath as key
+// in both in-memory map and the optional Cache.
+//
+// It ignores any error returned from Cache.Put.
+func (m *Manager) putHTTPToken(ctx context.Context, tokenPath, val string) {
+ m.tokensMu.Lock()
+ defer m.tokensMu.Unlock()
+ if m.httpTokens == nil {
+ m.httpTokens = make(map[string][]byte)
+ }
+ b := []byte(val)
+ m.httpTokens[tokenPath] = b
+ if m.Cache != nil {
+ m.Cache.Put(ctx, httpTokenCacheKey(tokenPath), b)
+ }
+}
+
+// deleteHTTPToken removes an http-01 token value from both in-memory map
+// and the optional Cache, ignoring any error returned from the latter.
+//
+// If m.Cache is non-nil, it blocks until Cache.Delete returns without a timeout.
+func (m *Manager) deleteHTTPToken(tokenPath string) {
+ m.tokensMu.Lock()
+ defer m.tokensMu.Unlock()
+ delete(m.httpTokens, tokenPath)
+ if m.Cache != nil {
+ m.Cache.Delete(context.Background(), httpTokenCacheKey(tokenPath))
+ }
+}
+
+// httpTokenCacheKey returns a key at which an http-01 token value may be stored
+// in the Manager's optional Cache.
+func httpTokenCacheKey(tokenPath string) string {
+ return "http-01-" + path.Base(tokenPath)
+}
+
// renew starts a cert renewal timer loop, one per domain.
//
// The loop is scheduled in two cases:
diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go b/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go
index 43a62011a..2da1912e9 100644
--- a/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go
+++ b/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go
@@ -23,6 +23,7 @@ import (
"net/http"
"net/http/httptest"
"reflect"
+ "strings"
"sync"
"testing"
"time"
@@ -48,6 +49,16 @@ var authzTmpl = template.Must(template.New("authz").Parse(`{
"uri": "{{.}}/challenge/2",
"type": "tls-sni-02",
"token": "token-02"
+ },
+ {
+ "uri": "{{.}}/challenge/dns-01",
+ "type": "dns-01",
+ "token": "token-dns-01"
+ },
+ {
+ "uri": "{{.}}/challenge/http-01",
+ "type": "http-01",
+ "token": "token-http-01"
}
]
}`))
@@ -419,6 +430,146 @@ func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.Cl
}
+func TestVerifyHTTP01(t *testing.T) {
+ var (
+ http01 http.Handler
+
+ authzCount int // num. of created authorizations
+ didAcceptHTTP01 bool
+ )
+
+ verifyHTTPToken := func() {
+ r := httptest.NewRequest("GET", "/.well-known/acme-challenge/token-http-01", nil)
+ w := httptest.NewRecorder()
+ http01.ServeHTTP(w, r)
+ if w.Code != http.StatusOK {
+ t.Errorf("http token: w.Code = %d; want %d", w.Code, http.StatusOK)
+ }
+ if v := string(w.Body.Bytes()); !strings.HasPrefix(v, "token-http-01.") {
+ t.Errorf("http token value = %q; want 'token-http-01.' prefix", v)
+ }
+ }
+
+ // ACME CA server stub, only the needed bits.
+ // TODO: Merge this with startACMEServerStub, making it a configurable CA for testing.
+ var ca *httptest.Server
+ ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Replay-Nonce", "nonce")
+ if r.Method == "HEAD" {
+ // a nonce request
+ return
+ }
+
+ switch r.URL.Path {
+ // Discovery.
+ case "/":
+ if err := discoTmpl.Execute(w, ca.URL); err != nil {
+ t.Errorf("discoTmpl: %v", err)
+ }
+ // Client key registration.
+ case "/new-reg":
+ w.Write([]byte("{}"))
+ // New domain authorization.
+ case "/new-authz":
+ authzCount++
+ w.Header().Set("Location", fmt.Sprintf("%s/authz/%d", ca.URL, authzCount))
+ w.WriteHeader(http.StatusCreated)
+ if err := authzTmpl.Execute(w, ca.URL); err != nil {
+ t.Errorf("authzTmpl: %v", err)
+ }
+ // Accept tls-sni-02.
+ case "/challenge/2":
+ w.Write([]byte("{}"))
+ // Reject tls-sni-01.
+ case "/challenge/1":
+ http.Error(w, "won't accept tls-sni-01", http.StatusBadRequest)
+ // Should not accept dns-01.
+ case "/challenge/dns-01":
+ t.Errorf("dns-01 challenge was accepted")
+ http.Error(w, "won't accept dns-01", http.StatusBadRequest)
+ // Accept http-01.
+ case "/challenge/http-01":
+ didAcceptHTTP01 = true
+ verifyHTTPToken()
+ w.Write([]byte("{}"))
+ // Authorization statuses.
+ // Make tls-sni-xxx invalid.
+ case "/authz/1", "/authz/2":
+ w.Write([]byte(`{"status": "invalid"}`))
+ case "/authz/3", "/authz/4":
+ w.Write([]byte(`{"status": "valid"}`))
+ default:
+ http.NotFound(w, r)
+ t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
+ }
+ }))
+ defer ca.Close()
+
+ key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ m := &Manager{
+ Client: &acme.Client{
+ Key: key,
+ DirectoryURL: ca.URL,
+ },
+ }
+ http01 = m.HTTPHandler(nil)
+ if err := m.verify(context.Background(), m.Client, "example.org"); err != nil {
+ t.Errorf("m.verify: %v", err)
+ }
+ // Only tls-sni-01, tls-sni-02 and http-01 must be accepted
+ // The dns-01 challenge is unsupported.
+ if authzCount != 3 {
+ t.Errorf("authzCount = %d; want 3", authzCount)
+ }
+ if !didAcceptHTTP01 {
+ t.Error("did not accept http-01 challenge")
+ }
+}
+
+func TestHTTPHandlerDefaultFallback(t *testing.T) {
+ tt := []struct {
+ method, url string
+ wantCode int
+ wantLocation string
+ }{
+ {"GET", "http://example.org", 302, "https://example.org/"},
+ {"GET", "http://example.org/foo", 302, "https://example.org/foo"},
+ {"GET", "http://example.org/foo/bar/", 302, "https://example.org/foo/bar/"},
+ {"GET", "http://example.org/?a=b", 302, "https://example.org/?a=b"},
+ {"GET", "http://example.org/foo?a=b", 302, "https://example.org/foo?a=b"},
+ {"GET", "http://example.org:80/foo?a=b", 302, "https://example.org:443/foo?a=b"},
+ {"GET", "http://example.org:80/foo%20bar", 302, "https://example.org:443/foo%20bar"},
+ {"GET", "http://[2602:d1:xxxx::c60a]:1234", 302, "https://[2602:d1:xxxx::c60a]:443/"},
+ {"GET", "http://[2602:d1:xxxx::c60a]", 302, "https://[2602:d1:xxxx::c60a]/"},
+ {"GET", "http://[2602:d1:xxxx::c60a]/foo?a=b", 302, "https://[2602:d1:xxxx::c60a]/foo?a=b"},
+ {"HEAD", "http://example.org", 302, "https://example.org/"},
+ {"HEAD", "http://example.org/foo", 302, "https://example.org/foo"},
+ {"HEAD", "http://example.org/foo/bar/", 302, "https://example.org/foo/bar/"},
+ {"HEAD", "http://example.org/?a=b", 302, "https://example.org/?a=b"},
+ {"HEAD", "http://example.org/foo?a=b", 302, "https://example.org/foo?a=b"},
+ {"POST", "http://example.org", 400, ""},
+ {"PUT", "http://example.org", 400, ""},
+ {"GET", "http://example.org/.well-known/acme-challenge/x", 404, ""},
+ }
+ var m Manager
+ h := m.HTTPHandler(nil)
+ for i, test := range tt {
+ r := httptest.NewRequest(test.method, test.url, nil)
+ w := httptest.NewRecorder()
+ h.ServeHTTP(w, r)
+ if w.Code != test.wantCode {
+ t.Errorf("%d: w.Code = %d; want %d", i, w.Code, test.wantCode)
+ t.Errorf("%d: body: %s", i, w.Body.Bytes())
+ }
+ if v := w.Header().Get("Location"); v != test.wantLocation {
+ t.Errorf("%d: Location = %q; want %q", i, v, test.wantLocation)
+ }
+ }
+}
+
func TestAccountKeyCache(t *testing.T) {
m := Manager{Cache: newMemCache()}
ctx := context.Background()
diff --git a/vendor/golang.org/x/crypto/acme/autocert/example_test.go b/vendor/golang.org/x/crypto/acme/autocert/example_test.go
index 71d61eb1c..552a62549 100644
--- a/vendor/golang.org/x/crypto/acme/autocert/example_test.go
+++ b/vendor/golang.org/x/crypto/acme/autocert/example_test.go
@@ -22,11 +22,12 @@ func ExampleNewListener() {
}
func ExampleManager() {
- m := autocert.Manager{
+ m := &autocert.Manager{
Cache: autocert.DirCache("secret-dir"),
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("example.org"),
}
+ go http.ListenAndServe(":http", m.HTTPHandler(nil))
s := &http.Server{
Addr: ":https",
TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
diff --git a/vendor/golang.org/x/crypto/argon2/blamka_amd64.go b/vendor/golang.org/x/crypto/argon2/blamka_amd64.go
index 583ac4be2..bb2b0d8b4 100644
--- a/vendor/golang.org/x/crypto/argon2/blamka_amd64.go
+++ b/vendor/golang.org/x/crypto/argon2/blamka_amd64.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build amd64,!gccgo,!appengine
+
package argon2
func init() {
diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go
index e67c5e0aa..30a49fdf2 100644
--- a/vendor/golang.org/x/crypto/ssh/cipher.go
+++ b/vendor/golang.org/x/crypto/ssh/cipher.go
@@ -16,6 +16,9 @@ import (
"hash"
"io"
"io/ioutil"
+
+ "golang.org/x/crypto/internal/chacha20"
+ "golang.org/x/crypto/poly1305"
)
const (
@@ -53,78 +56,78 @@ func newRC4(key, iv []byte) (cipher.Stream, error) {
return rc4.NewCipher(key)
}
-type streamCipherMode struct {
- keySize int
- ivSize int
- skip int
- createFunc func(key, iv []byte) (cipher.Stream, error)
+type cipherMode struct {
+ keySize int
+ ivSize int
+ create func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error)
}
-func (c *streamCipherMode) createStream(key, iv []byte) (cipher.Stream, error) {
- if len(key) < c.keySize {
- panic("ssh: key length too small for cipher")
- }
- if len(iv) < c.ivSize {
- panic("ssh: iv too small for cipher")
- }
-
- stream, err := c.createFunc(key[:c.keySize], iv[:c.ivSize])
- if err != nil {
- return nil, err
- }
+func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher.Stream, error)) func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
+ return func(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
+ stream, err := createFunc(key, iv)
+ if err != nil {
+ return nil, err
+ }
- var streamDump []byte
- if c.skip > 0 {
- streamDump = make([]byte, 512)
- }
+ var streamDump []byte
+ if skip > 0 {
+ streamDump = make([]byte, 512)
+ }
- for remainingToDump := c.skip; remainingToDump > 0; {
- dumpThisTime := remainingToDump
- if dumpThisTime > len(streamDump) {
- dumpThisTime = len(streamDump)
+ for remainingToDump := skip; remainingToDump > 0; {
+ dumpThisTime := remainingToDump
+ if dumpThisTime > len(streamDump) {
+ dumpThisTime = len(streamDump)
+ }
+ stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime])
+ remainingToDump -= dumpThisTime
}
- stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime])
- remainingToDump -= dumpThisTime
- }
- return stream, nil
+ mac := macModes[algs.MAC].new(macKey)
+ return &streamPacketCipher{
+ mac: mac,
+ etm: macModes[algs.MAC].etm,
+ macResult: make([]byte, mac.Size()),
+ cipher: stream,
+ }, nil
+ }
}
// cipherModes documents properties of supported ciphers. Ciphers not included
// are not supported and will not be negotiated, even if explicitly requested in
// ClientConfig.Crypto.Ciphers.
-var cipherModes = map[string]*streamCipherMode{
+var cipherModes = map[string]*cipherMode{
// Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms
// are defined in the order specified in the RFC.
- "aes128-ctr": {16, aes.BlockSize, 0, newAESCTR},
- "aes192-ctr": {24, aes.BlockSize, 0, newAESCTR},
- "aes256-ctr": {32, aes.BlockSize, 0, newAESCTR},
+ "aes128-ctr": {16, aes.BlockSize, streamCipherMode(0, newAESCTR)},
+ "aes192-ctr": {24, aes.BlockSize, streamCipherMode(0, newAESCTR)},
+ "aes256-ctr": {32, aes.BlockSize, streamCipherMode(0, newAESCTR)},
// Ciphers from RFC4345, which introduces security-improved arcfour ciphers.
// They are defined in the order specified in the RFC.
- "arcfour128": {16, 0, 1536, newRC4},
- "arcfour256": {32, 0, 1536, newRC4},
+ "arcfour128": {16, 0, streamCipherMode(1536, newRC4)},
+ "arcfour256": {32, 0, streamCipherMode(1536, newRC4)},
// Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol.
// Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and
// RC4) has problems with weak keys, and should be used with caution."
// RFC4345 introduces improved versions of Arcfour.
- "arcfour": {16, 0, 0, newRC4},
+ "arcfour": {16, 0, streamCipherMode(0, newRC4)},
- // AES-GCM is not a stream cipher, so it is constructed with a
- // special case. If we add any more non-stream ciphers, we
- // should invest a cleaner way to do this.
- gcmCipherID: {16, 12, 0, nil},
+ // AEAD ciphers
+ gcmCipherID: {16, 12, newGCMCipher},
+ chacha20Poly1305ID: {64, 0, newChaCha20Cipher},
// CBC mode is insecure and so is not included in the default config.
// (See http://www.isg.rhul.ac.uk/~kp/SandPfinal.pdf). If absolutely
// needed, it's possible to specify a custom Config to enable it.
// You should expect that an active attacker can recover plaintext if
// you do.
- aes128cbcID: {16, aes.BlockSize, 0, nil},
+ aes128cbcID: {16, aes.BlockSize, newAESCBCCipher},
- // 3des-cbc is insecure and is disabled by default.
- tripledescbcID: {24, des.BlockSize, 0, nil},
+ // 3des-cbc is insecure and is not included in the default
+ // config.
+ tripledescbcID: {24, des.BlockSize, newTripleDESCBCCipher},
}
// prefixLen is the length of the packet prefix that contains the packet length
@@ -304,7 +307,7 @@ type gcmCipher struct {
buf []byte
}
-func newGCMCipher(iv, key []byte) (packetCipher, error) {
+func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) {
c, err := aes.NewCipher(key)
if err != nil {
return nil, err
@@ -422,7 +425,7 @@ type cbcCipher struct {
oracleCamouflage uint32
}
-func newCBCCipher(c cipher.Block, iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
+func newCBCCipher(c cipher.Block, key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
cbc := &cbcCipher{
mac: macModes[algs.MAC].new(macKey),
decrypter: cipher.NewCBCDecrypter(c, iv),
@@ -436,13 +439,13 @@ func newCBCCipher(c cipher.Block, iv, key, macKey []byte, algs directionAlgorith
return cbc, nil
}
-func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
+func newAESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
c, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
- cbc, err := newCBCCipher(c, iv, key, macKey, algs)
+ cbc, err := newCBCCipher(c, key, iv, macKey, algs)
if err != nil {
return nil, err
}
@@ -450,13 +453,13 @@ func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCi
return cbc, nil
}
-func newTripleDESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
+func newTripleDESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
c, err := des.NewTripleDESCipher(key)
if err != nil {
return nil, err
}
- cbc, err := newCBCCipher(c, iv, key, macKey, algs)
+ cbc, err := newCBCCipher(c, key, iv, macKey, algs)
if err != nil {
return nil, err
}
@@ -627,3 +630,142 @@ func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, pack
return nil
}
+
+const chacha20Poly1305ID = "chacha20-poly1305@openssh.com"
+
+// chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com
+// AEAD, which is described here:
+//
+// https://tools.ietf.org/html/draft-josefsson-ssh-chacha20-poly1305-openssh-00
+//
+// the methods here also implement padding, which RFC4253 Section 6
+// also requires of stream ciphers.
+type chacha20Poly1305Cipher struct {
+ lengthKey [32]byte
+ contentKey [32]byte
+ buf []byte
+}
+
+func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) {
+ if len(key) != 64 {
+ panic(len(key))
+ }
+
+ c := &chacha20Poly1305Cipher{
+ buf: make([]byte, 256),
+ }
+
+ copy(c.contentKey[:], key[:32])
+ copy(c.lengthKey[:], key[32:])
+ return c, nil
+}
+
+// The Poly1305 key is obtained by encrypting 32 0-bytes.
+var chacha20PolyKeyInput [32]byte
+
+func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
+ var counter [16]byte
+ binary.BigEndian.PutUint64(counter[8:], uint64(seqNum))
+
+ var polyKey [32]byte
+ chacha20.XORKeyStream(polyKey[:], chacha20PolyKeyInput[:], &counter, &c.contentKey)
+
+ encryptedLength := c.buf[:4]
+ if _, err := io.ReadFull(r, encryptedLength); err != nil {
+ return nil, err
+ }
+
+ var lenBytes [4]byte
+ chacha20.XORKeyStream(lenBytes[:], encryptedLength, &counter, &c.lengthKey)
+
+ length := binary.BigEndian.Uint32(lenBytes[:])
+ if length > maxPacket {
+ return nil, errors.New("ssh: invalid packet length, packet too large")
+ }
+
+ contentEnd := 4 + length
+ packetEnd := contentEnd + poly1305.TagSize
+ if uint32(cap(c.buf)) < packetEnd {
+ c.buf = make([]byte, packetEnd)
+ copy(c.buf[:], encryptedLength)
+ } else {
+ c.buf = c.buf[:packetEnd]
+ }
+
+ if _, err := io.ReadFull(r, c.buf[4:packetEnd]); err != nil {
+ return nil, err
+ }
+
+ var mac [poly1305.TagSize]byte
+ copy(mac[:], c.buf[contentEnd:packetEnd])
+ if !poly1305.Verify(&mac, c.buf[:contentEnd], &polyKey) {
+ return nil, errors.New("ssh: MAC failure")
+ }
+
+ counter[0] = 1
+
+ plain := c.buf[4:contentEnd]
+ chacha20.XORKeyStream(plain, plain, &counter, &c.contentKey)
+
+ padding := plain[0]
+ if padding < 4 {
+ // padding is a byte, so it automatically satisfies
+ // the maximum size, which is 255.
+ return nil, fmt.Errorf("ssh: illegal padding %d", padding)
+ }
+
+ if int(padding)+1 >= len(plain) {
+ return nil, fmt.Errorf("ssh: padding %d too large", padding)
+ }
+
+ plain = plain[1 : len(plain)-int(padding)]
+
+ return plain, nil
+}
+
+func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error {
+ var counter [16]byte
+ binary.BigEndian.PutUint64(counter[8:], uint64(seqNum))
+
+ var polyKey [32]byte
+ chacha20.XORKeyStream(polyKey[:], chacha20PolyKeyInput[:], &counter, &c.contentKey)
+
+ // There is no blocksize, so fall back to multiple of 8 byte
+ // padding, as described in RFC 4253, Sec 6.
+ const packetSizeMultiple = 8
+
+ padding := packetSizeMultiple - (1+len(payload))%packetSizeMultiple
+ if padding < 4 {
+ padding += packetSizeMultiple
+ }
+
+ // size (4 bytes), padding (1), payload, padding, tag.
+ totalLength := 4 + 1 + len(payload) + padding + poly1305.TagSize
+ if cap(c.buf) < totalLength {
+ c.buf = make([]byte, totalLength)
+ } else {
+ c.buf = c.buf[:totalLength]
+ }
+
+ binary.BigEndian.PutUint32(c.buf, uint32(1+len(payload)+padding))
+ chacha20.XORKeyStream(c.buf, c.buf[:4], &counter, &c.lengthKey)
+ c.buf[4] = byte(padding)
+ copy(c.buf[5:], payload)
+ packetEnd := 5 + len(payload) + padding
+ if _, err := io.ReadFull(rand, c.buf[5+len(payload):packetEnd]); err != nil {
+ return err
+ }
+
+ counter[0] = 1
+ chacha20.XORKeyStream(c.buf[4:], c.buf[4:packetEnd], &counter, &c.contentKey)
+
+ var mac [poly1305.TagSize]byte
+ poly1305.Sum(&mac, c.buf[:packetEnd], &polyKey)
+
+ copy(c.buf[packetEnd:], mac[:])
+
+ if _, err := w.Write(c.buf); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/cipher_test.go b/vendor/golang.org/x/crypto/ssh/cipher_test.go
index 6a35d8708..a52d6e486 100644
--- a/vendor/golang.org/x/crypto/ssh/cipher_test.go
+++ b/vendor/golang.org/x/crypto/ssh/cipher_test.go
@@ -7,7 +7,6 @@ package ssh
import (
"bytes"
"crypto"
- "crypto/aes"
"crypto/rand"
"testing"
)
@@ -15,7 +14,12 @@ import (
func TestDefaultCiphersExist(t *testing.T) {
for _, cipherAlgo := range supportedCiphers {
if _, ok := cipherModes[cipherAlgo]; !ok {
- t.Errorf("default cipher %q is unknown", cipherAlgo)
+ t.Errorf("supported cipher %q is unknown", cipherAlgo)
+ }
+ }
+ for _, cipherAlgo := range preferredCiphers {
+ if _, ok := cipherModes[cipherAlgo]; !ok {
+ t.Errorf("preferred cipher %q is unknown", cipherAlgo)
}
}
}
@@ -67,9 +71,6 @@ func testPacketCipher(t *testing.T, cipher, mac string) {
}
func TestCBCOracleCounterMeasure(t *testing.T) {
- cipherModes[aes128cbcID] = &streamCipherMode{16, aes.BlockSize, 0, nil}
- defer delete(cipherModes, aes128cbcID)
-
kr := &kexResult{Hash: crypto.SHA1}
algs := directionAlgorithms{
Cipher: aes128cbcID,
diff --git a/vendor/golang.org/x/crypto/ssh/client_test.go b/vendor/golang.org/x/crypto/ssh/client_test.go
index ef95069ef..81f9599e1 100644
--- a/vendor/golang.org/x/crypto/ssh/client_test.go
+++ b/vendor/golang.org/x/crypto/ssh/client_test.go
@@ -5,41 +5,77 @@
package ssh
import (
- "net"
"strings"
"testing"
)
-func testClientVersion(t *testing.T, config *ClientConfig, expected string) {
- clientConn, serverConn := net.Pipe()
- defer clientConn.Close()
- receivedVersion := make(chan string, 1)
- config.HostKeyCallback = InsecureIgnoreHostKey()
- go func() {
- version, err := readVersion(serverConn)
- if err != nil {
- receivedVersion <- ""
- } else {
- receivedVersion <- string(version)
- }
- serverConn.Close()
- }()
- NewClientConn(clientConn, "", config)
- actual := <-receivedVersion
- if actual != expected {
- t.Fatalf("got %s; want %s", actual, expected)
+func TestClientVersion(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ version string
+ multiLine string
+ wantErr bool
+ }{
+ {
+ name: "default version",
+ version: packageVersion,
+ },
+ {
+ name: "custom version",
+ version: "SSH-2.0-CustomClientVersionString",
+ },
+ {
+ name: "good multi line version",
+ version: packageVersion,
+ multiLine: strings.Repeat("ignored\r\n", 20),
+ },
+ {
+ name: "bad multi line version",
+ version: packageVersion,
+ multiLine: "bad multi line version",
+ wantErr: true,
+ },
+ {
+ name: "long multi line version",
+ version: packageVersion,
+ multiLine: strings.Repeat("long multi line version\r\n", 50)[:256],
+ wantErr: true,
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ c1, c2, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+ defer c1.Close()
+ defer c2.Close()
+ go func() {
+ if tt.multiLine != "" {
+ c1.Write([]byte(tt.multiLine))
+ }
+ NewClientConn(c1, "", &ClientConfig{
+ ClientVersion: tt.version,
+ HostKeyCallback: InsecureIgnoreHostKey(),
+ })
+ c1.Close()
+ }()
+ conf := &ServerConfig{NoClientAuth: true}
+ conf.AddHostKey(testSigners["rsa"])
+ conn, _, _, err := NewServerConn(c2, conf)
+ if err == nil == tt.wantErr {
+ t.Fatalf("got err %v; wantErr %t", err, tt.wantErr)
+ }
+ if tt.wantErr {
+ // Don't verify the version on an expected error.
+ return
+ }
+ if got := string(conn.ClientVersion()); got != tt.version {
+ t.Fatalf("got %q; want %q", got, tt.version)
+ }
+ })
}
}
-func TestCustomClientVersion(t *testing.T) {
- version := "Test-Client-Version-0.0"
- testClientVersion(t, &ClientConfig{ClientVersion: version}, version)
-}
-
-func TestDefaultClientVersion(t *testing.T) {
- testClientVersion(t, &ClientConfig{}, packageVersion)
-}
-
func TestHostKeyCheck(t *testing.T) {
for _, tt := range []struct {
name string
diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go
index 135b4edd7..04f3620b3 100644
--- a/vendor/golang.org/x/crypto/ssh/common.go
+++ b/vendor/golang.org/x/crypto/ssh/common.go
@@ -24,11 +24,21 @@ const (
serviceSSH = "ssh-connection"
)
-// supportedCiphers specifies the supported ciphers in preference order.
+// supportedCiphers lists ciphers we support but might not recommend.
var supportedCiphers = []string{
"aes128-ctr", "aes192-ctr", "aes256-ctr",
"aes128-gcm@openssh.com",
- "arcfour256", "arcfour128",
+ chacha20Poly1305ID,
+ "arcfour256", "arcfour128", "arcfour",
+ aes128cbcID,
+ tripledescbcID,
+}
+
+// preferredCiphers specifies the default preference for ciphers.
+var preferredCiphers = []string{
+ "aes128-gcm@openssh.com",
+ chacha20Poly1305ID,
+ "aes128-ctr", "aes192-ctr", "aes256-ctr",
}
// supportedKexAlgos specifies the supported key-exchange algorithms in
@@ -211,7 +221,7 @@ func (c *Config) SetDefaults() {
c.Rand = rand.Reader
}
if c.Ciphers == nil {
- c.Ciphers = supportedCiphers
+ c.Ciphers = preferredCiphers
}
var ciphers []string
for _, c := range c.Ciphers {
diff --git a/vendor/golang.org/x/crypto/ssh/test/session_test.go b/vendor/golang.org/x/crypto/ssh/test/session_test.go
index 9e702effa..4eb7afde8 100644
--- a/vendor/golang.org/x/crypto/ssh/test/session_test.go
+++ b/vendor/golang.org/x/crypto/ssh/test/session_test.go
@@ -11,6 +11,7 @@ package test
import (
"bytes"
"errors"
+ "fmt"
"io"
"strings"
"testing"
@@ -324,31 +325,59 @@ func TestWindowChange(t *testing.T) {
}
}
+func testOneCipher(t *testing.T, cipher string, cipherOrder []string) {
+ server := newServer(t)
+ defer server.Shutdown()
+ conf := clientConfig()
+ conf.Ciphers = []string{cipher}
+ // Don't fail if sshd doesn't have the cipher.
+ conf.Ciphers = append(conf.Ciphers, cipherOrder...)
+ conn, err := server.TryDial(conf)
+ if err != nil {
+ t.Fatalf("TryDial: %v", err)
+ }
+ defer conn.Close()
+
+ numBytes := 4096
+
+ // Exercise sending data to the server
+ if _, _, err := conn.Conn.SendRequest("drop-me", false, make([]byte, numBytes)); err != nil {
+ t.Fatalf("SendRequest: %v", err)
+ }
+
+ // Exercise receiving data from the server
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("NewSession: %v", err)
+ }
+
+ out, err := session.Output(fmt.Sprintf("dd if=/dev/zero of=/dev/stdout bs=%d count=1", numBytes))
+ if err != nil {
+ t.Fatalf("Output: %v", err)
+ }
+
+ if len(out) != numBytes {
+ t.Fatalf("got %d bytes, want %d bytes", len(out), numBytes)
+ }
+}
+
+var deprecatedCiphers = []string{
+ "aes128-cbc", "3des-cbc",
+ "arcfour128", "arcfour256",
+}
+
func TestCiphers(t *testing.T) {
var config ssh.Config
config.SetDefaults()
- cipherOrder := config.Ciphers
- // These ciphers will not be tested when commented out in cipher.go it will
- // fallback to the next available as per line 292.
- cipherOrder = append(cipherOrder, "aes128-cbc", "3des-cbc")
+ cipherOrder := append(config.Ciphers, deprecatedCiphers...)
for _, ciph := range cipherOrder {
t.Run(ciph, func(t *testing.T) {
- server := newServer(t)
- defer server.Shutdown()
- conf := clientConfig()
- conf.Ciphers = []string{ciph}
- // Don't fail if sshd doesn't have the cipher.
- conf.Ciphers = append(conf.Ciphers, cipherOrder...)
- conn, err := server.TryDial(conf)
- if err == nil {
- conn.Close()
- } else {
- t.Fatalf("failed for cipher %q", ciph)
- }
+ testOneCipher(t, ciph, cipherOrder)
})
}
}
+
func TestMACs(t *testing.T) {
var config ssh.Config
config.SetDefaults()
diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go
index 01150eb89..f6fae1db4 100644
--- a/vendor/golang.org/x/crypto/ssh/transport.go
+++ b/vendor/golang.org/x/crypto/ssh/transport.go
@@ -6,6 +6,7 @@ package ssh
import (
"bufio"
+ "bytes"
"errors"
"io"
"log"
@@ -232,52 +233,22 @@ var (
clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}}
)
-// generateKeys generates key material for IV, MAC and encryption.
-func generateKeys(d direction, algs directionAlgorithms, kex *kexResult) (iv, key, macKey []byte) {
+// setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as
+// described in RFC 4253, section 6.4. direction should either be serverKeys
+// (to setup server->client keys) or clientKeys (for client->server keys).
+func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) {
cipherMode := cipherModes[algs.Cipher]
macMode := macModes[algs.MAC]
- iv = make([]byte, cipherMode.ivSize)
- key = make([]byte, cipherMode.keySize)
- macKey = make([]byte, macMode.keySize)
+ iv := make([]byte, cipherMode.ivSize)
+ key := make([]byte, cipherMode.keySize)
+ macKey := make([]byte, macMode.keySize)
generateKeyMaterial(iv, d.ivTag, kex)
generateKeyMaterial(key, d.keyTag, kex)
generateKeyMaterial(macKey, d.macKeyTag, kex)
- return
-}
-
-// setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as
-// described in RFC 4253, section 6.4. direction should either be serverKeys
-// (to setup server->client keys) or clientKeys (for client->server keys).
-func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) {
- iv, key, macKey := generateKeys(d, algs, kex)
-
- if algs.Cipher == gcmCipherID {
- return newGCMCipher(iv, key)
- }
-
- if algs.Cipher == aes128cbcID {
- return newAESCBCCipher(iv, key, macKey, algs)
- }
- if algs.Cipher == tripledescbcID {
- return newTripleDESCBCCipher(iv, key, macKey, algs)
- }
-
- c := &streamPacketCipher{
- mac: macModes[algs.MAC].new(macKey),
- etm: macModes[algs.MAC].etm,
- }
- c.macResult = make([]byte, c.mac.Size())
-
- var err error
- c.cipher, err = cipherModes[algs.Cipher].createStream(key, iv)
- if err != nil {
- return nil, err
- }
-
- return c, nil
+ return cipherModes[algs.Cipher].create(key, iv, macKey, algs)
}
// generateKeyMaterial fills out with key material generated from tag, K, H
@@ -342,7 +313,7 @@ func readVersion(r io.Reader) ([]byte, error) {
var ok bool
var buf [1]byte
- for len(versionString) < maxVersionStringBytes {
+ for length := 0; length < maxVersionStringBytes; length++ {
_, err := io.ReadFull(r, buf[:])
if err != nil {
return nil, err
@@ -350,6 +321,13 @@ func readVersion(r io.Reader) ([]byte, error) {
// The RFC says that the version should be terminated with \r\n
// but several SSH servers actually only send a \n.
if buf[0] == '\n' {
+ if !bytes.HasPrefix(versionString, []byte("SSH-")) {
+ // RFC 4253 says we need to ignore all version string lines
+ // except the one containing the SSH version (provided that
+ // all the lines do not exceed 255 bytes in total).
+ versionString = versionString[:0]
+ continue
+ }
ok = true
break
}
diff --git a/vendor/golang.org/x/crypto/ssh/transport_test.go b/vendor/golang.org/x/crypto/ssh/transport_test.go
index 92d83abf9..8445e1e56 100644
--- a/vendor/golang.org/x/crypto/ssh/transport_test.go
+++ b/vendor/golang.org/x/crypto/ssh/transport_test.go
@@ -13,11 +13,13 @@ import (
)
func TestReadVersion(t *testing.T) {
- longversion := strings.Repeat("SSH-2.0-bla", 50)[:253]
+ longVersion := strings.Repeat("SSH-2.0-bla", 50)[:253]
+ multiLineVersion := strings.Repeat("ignored\r\n", 20) + "SSH-2.0-bla\r\n"
cases := map[string]string{
"SSH-2.0-bla\r\n": "SSH-2.0-bla",
"SSH-2.0-bla\n": "SSH-2.0-bla",
- longversion + "\r\n": longversion,
+ multiLineVersion: "SSH-2.0-bla",
+ longVersion + "\r\n": longVersion,
}
for in, want := range cases {
@@ -33,9 +35,11 @@ func TestReadVersion(t *testing.T) {
}
func TestReadVersionError(t *testing.T) {
- longversion := strings.Repeat("SSH-2.0-bla", 50)[:253]
+ longVersion := strings.Repeat("SSH-2.0-bla", 50)[:253]
+ multiLineVersion := strings.Repeat("ignored\r\n", 50) + "SSH-2.0-bla\r\n"
cases := []string{
- longversion + "too-long\r\n",
+ longVersion + "too-long\r\n",
+ multiLineVersion,
}
for _, in := range cases {
if _, err := readVersion(bytes.NewBufferString(in)); err == nil {
@@ -60,7 +64,7 @@ func TestExchangeVersionsBasic(t *testing.T) {
func TestExchangeVersions(t *testing.T) {
cases := []string{
"not\x000allowed",
- "not allowed\n",
+ "not allowed\x01\r\n",
}
for _, c := range cases {
buf := bytes.NewBufferString("SSH-2.0-bla\r\n")