Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef5341b706 | ||
|
|
b999374650 | ||
|
|
c247dead11 | ||
|
|
1fda73153f | ||
|
|
1b4c3d2e8c | ||
|
|
b903b535d3 | ||
|
|
459a9db11b | ||
|
|
74e709ad8a | ||
|
|
b3790b8d91 | ||
|
|
1dc4269656 | ||
|
|
97bf787255 | ||
|
|
952517d181 | ||
|
|
c6fce02826 | ||
|
|
0ae49b8145 | ||
|
|
3bf9d2afd4 | ||
|
|
9bab96736c | ||
|
|
4f9f0ca9fc | ||
|
|
eac7cf0d78 | ||
|
|
18228cd6f1 | ||
|
|
73f6362471 | ||
|
|
ebc8e46315 | ||
|
|
e944286e33 | ||
|
|
78a1fd7893 | ||
|
|
ac58737d25 | ||
|
|
9dbbcf002b | ||
|
|
9f6bf8449a |
+36
-54
@@ -31,12 +31,11 @@ import (
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -471,7 +470,7 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat
|
||||
// while waiting for a final authorization status.
|
||||
d := retryAfter(res.Header.Get("Retry-After"))
|
||||
if d == 0 {
|
||||
// Given that the fastest challenges TLS-SNI and HTTP-01
|
||||
// Given that the fastest challenges TLS-ALPN and HTTP-01
|
||||
// require a CA to make at least 1 network round trip
|
||||
// and most likely persist a challenge state,
|
||||
// this default delay seems reasonable.
|
||||
@@ -572,50 +571,28 @@ func (c *Client) HTTP01ChallengePath(token string) string {
|
||||
}
|
||||
|
||||
// TLSSNI01ChallengeCert creates a certificate for TLS-SNI-01 challenge response.
|
||||
// Always returns an error.
|
||||
//
|
||||
// Deprecated: This challenge type is unused in both draft-02 and RFC versions of the ACME spec.
|
||||
func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
|
||||
ka, err := keyAuth(c.Key.Public(), token)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, "", err
|
||||
}
|
||||
b := sha256.Sum256([]byte(ka))
|
||||
h := hex.EncodeToString(b[:])
|
||||
name = fmt.Sprintf("%s.%s.acme.invalid", h[:32], h[32:])
|
||||
cert, err = tlsChallengeCert([]string{name}, opt)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, "", err
|
||||
}
|
||||
return cert, name, nil
|
||||
// Deprecated: This challenge type was only present in pre-standardized ACME
|
||||
// protocol drafts and is insecure for use in shared hosting environments.
|
||||
func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (tls.Certificate, string, error) {
|
||||
return tls.Certificate{}, "", errPreRFC
|
||||
}
|
||||
|
||||
// TLSSNI02ChallengeCert creates a certificate for TLS-SNI-02 challenge response.
|
||||
// Always returns an error.
|
||||
//
|
||||
// Deprecated: This challenge type is unused in both draft-02 and RFC versions of the ACME spec.
|
||||
func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
|
||||
b := sha256.Sum256([]byte(token))
|
||||
h := hex.EncodeToString(b[:])
|
||||
sanA := fmt.Sprintf("%s.%s.token.acme.invalid", h[:32], h[32:])
|
||||
|
||||
ka, err := keyAuth(c.Key.Public(), token)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, "", err
|
||||
}
|
||||
b = sha256.Sum256([]byte(ka))
|
||||
h = hex.EncodeToString(b[:])
|
||||
sanB := fmt.Sprintf("%s.%s.ka.acme.invalid", h[:32], h[32:])
|
||||
|
||||
cert, err = tlsChallengeCert([]string{sanA, sanB}, opt)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, "", err
|
||||
}
|
||||
return cert, sanA, nil
|
||||
// Deprecated: This challenge type was only present in pre-standardized ACME
|
||||
// protocol drafts and is insecure for use in shared hosting environments.
|
||||
func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (tls.Certificate, string, error) {
|
||||
return tls.Certificate{}, "", errPreRFC
|
||||
}
|
||||
|
||||
// TLSALPN01ChallengeCert creates a certificate for TLS-ALPN-01 challenge response.
|
||||
// Servers can present the certificate to validate the challenge and prove control
|
||||
// over a domain name. For more details on TLS-ALPN-01 see
|
||||
// https://tools.ietf.org/html/draft-shoemaker-acme-tls-alpn-00#section-3
|
||||
// over an identifier (either a DNS name or the textual form of an IPv4 or IPv6
|
||||
// address). For more details on TLS-ALPN-01 see
|
||||
// https://www.rfc-editor.org/rfc/rfc8737 and https://www.rfc-editor.org/rfc/rfc8738
|
||||
//
|
||||
// The token argument is a Challenge.Token value.
|
||||
// If a WithKey option is provided, its private part signs the returned cert,
|
||||
@@ -623,9 +600,13 @@ func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tl
|
||||
// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
|
||||
//
|
||||
// The returned certificate is valid for the next 24 hours and must be presented only when
|
||||
// the server name in the TLS ClientHello matches the domain, and the special acme-tls/1 ALPN protocol
|
||||
// the server name in the TLS ClientHello matches the identifier, and the special acme-tls/1 ALPN protocol
|
||||
// has been specified.
|
||||
func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption) (cert tls.Certificate, err error) {
|
||||
//
|
||||
// Validation requests for IP address identifiers will use the reverse DNS form in the server name
|
||||
// in the TLS ClientHello since the SNI extension is not supported for IP addresses.
|
||||
// See RFC 8738 Section 6 for more information.
|
||||
func (c *Client) TLSALPN01ChallengeCert(token, identifier string, opt ...CertOption) (cert tls.Certificate, err error) {
|
||||
ka, err := keyAuth(c.Key.Public(), token)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, err
|
||||
@@ -655,7 +636,7 @@ func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption)
|
||||
}
|
||||
tmpl.ExtraExtensions = append(tmpl.ExtraExtensions, acmeExtension)
|
||||
newOpt = append(newOpt, WithTemplate(tmpl))
|
||||
return tlsChallengeCert([]string{domain}, newOpt)
|
||||
return tlsChallengeCert(identifier, newOpt)
|
||||
}
|
||||
|
||||
// popNonce returns a nonce value previously stored with c.addNonce
|
||||
@@ -773,11 +754,15 @@ func defaultTLSChallengeCertTemplate() *x509.Certificate {
|
||||
}
|
||||
}
|
||||
|
||||
// tlsChallengeCert creates a temporary certificate for TLS-SNI challenges
|
||||
// with the given SANs and auto-generated public/private key pair.
|
||||
// The Subject Common Name is set to the first SAN to aid debugging.
|
||||
// tlsChallengeCert creates a temporary certificate for TLS-ALPN challenges
|
||||
// for the given identifier, using an auto-generated public/private key pair.
|
||||
//
|
||||
// If the provided identifier is a domain name, it will be used as a DNS type SAN and for the
|
||||
// subject common name. If the provided identifier is an IP address it will be used as an IP type
|
||||
// SAN.
|
||||
//
|
||||
// To create a cert with a custom key pair, specify WithKey option.
|
||||
func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
|
||||
func tlsChallengeCert(identifier string, opt []CertOption) (tls.Certificate, error) {
|
||||
var key crypto.Signer
|
||||
tmpl := defaultTLSChallengeCertTemplate()
|
||||
for _, o := range opt {
|
||||
@@ -801,9 +786,12 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
}
|
||||
tmpl.DNSNames = san
|
||||
if len(san) > 0 {
|
||||
tmpl.Subject.CommonName = san[0]
|
||||
|
||||
if ip := net.ParseIP(identifier); ip != nil {
|
||||
tmpl.IPAddresses = []net.IP{ip}
|
||||
} else {
|
||||
tmpl.DNSNames = []string{identifier}
|
||||
tmpl.Subject.CommonName = identifier
|
||||
}
|
||||
|
||||
der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key)
|
||||
@@ -816,11 +804,5 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// encodePEM returns b encoded as PEM with block of type typ.
|
||||
func encodePEM(typ string, b []byte) []byte {
|
||||
pb := &pem.Block{Type: typ, Bytes: b}
|
||||
return pem.EncodeToMemory(pb)
|
||||
}
|
||||
|
||||
// timeNow is time.Now, except in tests which can mess with it.
|
||||
var timeNow = time.Now
|
||||
|
||||
+34
-110
@@ -9,7 +9,6 @@ import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
@@ -22,8 +21,6 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -692,71 +689,6 @@ func TestLinkHeader(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSSNI01ChallengeCert(t *testing.T) {
|
||||
const (
|
||||
token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
|
||||
// echo -n <token.testKeyECThumbprint> | shasum -a 256
|
||||
san = "dbbd5eefe7b4d06eb9d1d9f5acb4c7cd.a27d320e4b30332f0b6cb441734ad7b0.acme.invalid"
|
||||
)
|
||||
|
||||
tlscert, name, err := newTestClient().TLSSNI01ChallengeCert(token)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n := len(tlscert.Certificate); n != 1 {
|
||||
t.Fatalf("len(tlscert.Certificate) = %d; want 1", n)
|
||||
}
|
||||
cert, err := x509.ParseCertificate(tlscert.Certificate[0])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(cert.DNSNames) != 1 || cert.DNSNames[0] != san {
|
||||
t.Fatalf("cert.DNSNames = %v; want %q", cert.DNSNames, san)
|
||||
}
|
||||
if cert.DNSNames[0] != name {
|
||||
t.Errorf("cert.DNSNames[0] != name: %q vs %q", cert.DNSNames[0], name)
|
||||
}
|
||||
if cn := cert.Subject.CommonName; cn != san {
|
||||
t.Errorf("cert.Subject.CommonName = %q; want %q", cn, san)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSSNI02ChallengeCert(t *testing.T) {
|
||||
const (
|
||||
token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
|
||||
// echo -n evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA | shasum -a 256
|
||||
sanA = "7ea0aaa69214e71e02cebb18bb867736.09b730209baabf60e43d4999979ff139.token.acme.invalid"
|
||||
// echo -n <token.testKeyECThumbprint> | shasum -a 256
|
||||
sanB = "dbbd5eefe7b4d06eb9d1d9f5acb4c7cd.a27d320e4b30332f0b6cb441734ad7b0.ka.acme.invalid"
|
||||
)
|
||||
|
||||
tlscert, name, err := newTestClient().TLSSNI02ChallengeCert(token)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n := len(tlscert.Certificate); n != 1 {
|
||||
t.Fatalf("len(tlscert.Certificate) = %d; want 1", n)
|
||||
}
|
||||
cert, err := x509.ParseCertificate(tlscert.Certificate[0])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
names := []string{sanA, sanB}
|
||||
if !reflect.DeepEqual(cert.DNSNames, names) {
|
||||
t.Fatalf("cert.DNSNames = %v;\nwant %v", cert.DNSNames, names)
|
||||
}
|
||||
sort.Strings(cert.DNSNames)
|
||||
i := sort.SearchStrings(cert.DNSNames, name)
|
||||
if i >= len(cert.DNSNames) || cert.DNSNames[i] != name {
|
||||
t.Errorf("%v doesn't have %q", cert.DNSNames, name)
|
||||
}
|
||||
if cn := cert.Subject.CommonName; cn != sanA {
|
||||
t.Errorf("CommonName = %q; want %q", cn, sanA)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSALPN01ChallengeCert(t *testing.T) {
|
||||
const (
|
||||
token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
|
||||
@@ -813,6 +745,7 @@ func TestTLSChallengeCertOpt(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
domain := "example.com"
|
||||
tmpl := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(2),
|
||||
Subject: pkix.Name{Organization: []string{"Test"}},
|
||||
@@ -821,52 +754,43 @@ func TestTLSChallengeCertOpt(t *testing.T) {
|
||||
opts := []CertOption{WithKey(key), WithTemplate(tmpl)}
|
||||
|
||||
client := newTestClient()
|
||||
cert1, _, err := client.TLSSNI01ChallengeCert("token", opts...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cert2, _, err := client.TLSSNI02ChallengeCert("token", opts...)
|
||||
cert, err := client.TLSALPN01ChallengeCert("token", domain, opts...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i, tlscert := range []tls.Certificate{cert1, cert2} {
|
||||
// verify generated cert private key
|
||||
tlskey, ok := tlscert.PrivateKey.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
t.Errorf("%d: tlscert.PrivateKey is %T; want *rsa.PrivateKey", i, tlscert.PrivateKey)
|
||||
continue
|
||||
}
|
||||
if tlskey.D.Cmp(key.D) != 0 {
|
||||
t.Errorf("%d: tlskey.D = %v; want %v", i, tlskey.D, key.D)
|
||||
}
|
||||
// verify generated cert public key
|
||||
x509Cert, err := x509.ParseCertificate(tlscert.Certificate[0])
|
||||
if err != nil {
|
||||
t.Errorf("%d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
tlspub, ok := x509Cert.PublicKey.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
t.Errorf("%d: x509Cert.PublicKey is %T; want *rsa.PublicKey", i, x509Cert.PublicKey)
|
||||
continue
|
||||
}
|
||||
if tlspub.N.Cmp(key.N) != 0 {
|
||||
t.Errorf("%d: tlspub.N = %v; want %v", i, tlspub.N, key.N)
|
||||
}
|
||||
// verify template option
|
||||
sn := big.NewInt(2)
|
||||
if x509Cert.SerialNumber.Cmp(sn) != 0 {
|
||||
t.Errorf("%d: SerialNumber = %v; want %v", i, x509Cert.SerialNumber, sn)
|
||||
}
|
||||
org := []string{"Test"}
|
||||
if !reflect.DeepEqual(x509Cert.Subject.Organization, org) {
|
||||
t.Errorf("%d: Subject.Organization = %+v; want %+v", i, x509Cert.Subject.Organization, org)
|
||||
}
|
||||
for _, v := range x509Cert.DNSNames {
|
||||
if !strings.HasSuffix(v, ".acme.invalid") {
|
||||
t.Errorf("%d: invalid DNSNames element: %q", i, v)
|
||||
}
|
||||
// verify generated cert private key
|
||||
tlskey, ok := cert.PrivateKey.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
t.Fatalf("tlscert.PrivateKey is %T; want *rsa.PrivateKey", cert.PrivateKey)
|
||||
}
|
||||
if tlskey.D.Cmp(key.D) != 0 {
|
||||
t.Errorf("tlskey.D = %v; want %v", tlskey.D, key.D)
|
||||
}
|
||||
// verify generated cert public key
|
||||
x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tlspub, ok := x509Cert.PublicKey.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
t.Fatalf("x509Cert.PublicKey is %T; want *rsa.PublicKey", x509Cert.PublicKey)
|
||||
}
|
||||
if tlspub.N.Cmp(key.N) != 0 {
|
||||
t.Errorf("tlspub.N = %v; want %v", tlspub.N, key.N)
|
||||
}
|
||||
// verify template option
|
||||
sn := big.NewInt(2)
|
||||
if x509Cert.SerialNumber.Cmp(sn) != 0 {
|
||||
t.Errorf("SerialNumber = %v; want %v", x509Cert.SerialNumber, sn)
|
||||
}
|
||||
org := []string{"Test"}
|
||||
if !reflect.DeepEqual(x509Cert.Subject.Organization, org) {
|
||||
t.Errorf("Subject.Organization = %+v; want %+v", x509Cert.Subject.Organization, org)
|
||||
}
|
||||
for _, v := range x509Cert.DNSNames {
|
||||
if v != domain {
|
||||
t.Errorf("invalid DNSNames element: %q", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -782,15 +782,3 @@ func decodePayload(v interface{}, r io.Reader) error {
|
||||
func challengeToken(domain, challType string, authzID int) string {
|
||||
return fmt.Sprintf("token-%s-%s-%d", domain, challType, authzID)
|
||||
}
|
||||
|
||||
func unique(a []string) []string {
|
||||
seen := make(map[string]bool)
|
||||
var res []string
|
||||
for _, s := range a {
|
||||
if s != "" && !seen[s] {
|
||||
seen[s] = true
|
||||
res = append(res, s)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -0,0 +1,804 @@
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package acme_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/acme"
|
||||
)
|
||||
|
||||
const (
|
||||
// pebbleModVersion is the module version used for Pebble and Pebble's
|
||||
// challenge test server. It is ignored if `-pebble-local-dir` is provided.
|
||||
pebbleModVersion = "v2.7.0"
|
||||
// startingPort is the first port number used for binding interface
|
||||
// addresses. Each call to takeNextPort() will increment a port number
|
||||
// starting at this value.
|
||||
startingPort = 5555
|
||||
)
|
||||
|
||||
var (
|
||||
pebbleLocalDir = flag.String(
|
||||
"pebble-local-dir",
|
||||
"",
|
||||
"Local Pebble to use, instead of fetching from source",
|
||||
)
|
||||
nextPort atomic.Uint32
|
||||
)
|
||||
|
||||
func init() {
|
||||
nextPort.Store(startingPort)
|
||||
}
|
||||
|
||||
func TestWithPebble(t *testing.T) {
|
||||
// We want to use process groups w/ syscall.Kill, and the acme package
|
||||
// is very platform-agnostic, so skip on non-Linux.
|
||||
if runtime.GOOS != "linux" {
|
||||
t.Skip("skipping pebble tests on non-linux OS")
|
||||
}
|
||||
|
||||
if testing.Short() {
|
||||
t.Skip("skipping pebble tests in short mode")
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
challSrv func(*environment) (challengeServer, string)
|
||||
}{
|
||||
{
|
||||
name: "TLSALPN01-Issuance",
|
||||
challSrv: func(env *environment) (challengeServer, string) {
|
||||
bindAddr := fmt.Sprintf(":%d", env.config.TLSPort)
|
||||
return newChallTLSServer(bindAddr), bindAddr
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "HTTP01-Issuance",
|
||||
challSrv: func(env *environment) (challengeServer, string) {
|
||||
bindAddr := fmt.Sprintf(":%d", env.config.HTTPPort)
|
||||
return newChallHTTPServer(bindAddr), bindAddr
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
env := startPebbleEnvironment(t, nil)
|
||||
challSrv, challSrvAddr := tt.challSrv(&env)
|
||||
challSrv.Run()
|
||||
|
||||
t.Cleanup(func() {
|
||||
challSrv.Shutdown()
|
||||
})
|
||||
|
||||
waitForServer(t, challSrvAddr)
|
||||
testIssuance(t, &env, challSrv)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// challengeServer abstracts over the details of running a challenge response
|
||||
// server for some supported acme.Challenge type. Responses are provisioned
|
||||
// during the test issuance process to be presented to the ACME server's
|
||||
// validation authority.
|
||||
type challengeServer interface {
|
||||
Run()
|
||||
Shutdown() error
|
||||
Supported(chal *acme.Challenge) bool
|
||||
Provision(client *acme.Client, ident acme.AuthzID, chal *acme.Challenge) error
|
||||
}
|
||||
|
||||
// challTLSServer is a simple challenge response server that listens for TLS
|
||||
// connections on a specific port and if they are TLS-ALPN-01 challenge
|
||||
// requests, completes the handshake using the configured challenge response
|
||||
// certificate for the SNI value provided.
|
||||
type challTLSServer struct {
|
||||
*http.Server
|
||||
// mu protects challCerts.
|
||||
mu sync.RWMutex
|
||||
// challCerts is a map from SNI domain name to challenge response certificate.
|
||||
challCerts map[string]*tls.Certificate
|
||||
}
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/rfc8737#section-4
|
||||
const acmeTLSAlpnProtocol = "acme-tls/1"
|
||||
|
||||
func newChallTLSServer(address string) *challTLSServer {
|
||||
challServer := &challTLSServer{Server: &http.Server{
|
||||
Addr: address,
|
||||
ReadTimeout: 5 * time.Second,
|
||||
WriteTimeout: 5 * time.Second,
|
||||
}, challCerts: make(map[string]*tls.Certificate)}
|
||||
|
||||
// Configure the server to support the TLS-ALPN-01 challenge protocol
|
||||
// and to use a callback for selecting the handshake certificate.
|
||||
challServer.Server.TLSConfig = &tls.Config{
|
||||
NextProtos: []string{acmeTLSAlpnProtocol},
|
||||
GetCertificate: challServer.getCertificate,
|
||||
}
|
||||
|
||||
return challServer
|
||||
}
|
||||
|
||||
func (c *challTLSServer) Shutdown() error {
|
||||
log.Printf("challTLSServer: shutting down")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10)
|
||||
defer cancel()
|
||||
return c.Server.Shutdown(ctx)
|
||||
}
|
||||
|
||||
func (c *challTLSServer) Run() {
|
||||
go func() {
|
||||
// Note: certFile and keyFile are empty because our config uses a
|
||||
// GetCertificate callback.
|
||||
if err := c.Server.ListenAndServeTLS("", ""); err != nil {
|
||||
if !errors.Is(err, http.ErrServerClosed) {
|
||||
log.Printf("challTLSServer error: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (c *challTLSServer) Supported(chal *acme.Challenge) bool {
|
||||
return chal.Type == "tls-alpn-01"
|
||||
}
|
||||
|
||||
func (c *challTLSServer) Provision(client *acme.Client, ident acme.AuthzID, chal *acme.Challenge) error {
|
||||
respCert, err := client.TLSALPN01ChallengeCert(chal.Token, ident.Value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("challTLSServer: failed to generate challlenge response cert for %s: %w",
|
||||
ident.Value, err)
|
||||
}
|
||||
|
||||
log.Printf("challTLSServer: setting challenge response certificate for %s", ident.Value)
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.challCerts[ident.Value] = &respCert
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *challTLSServer) getCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
// Verify the request looks like a TLS-ALPN-01 challenge request.
|
||||
if len(clientHello.SupportedProtos) != 1 || clientHello.SupportedProtos[0] != acmeTLSAlpnProtocol {
|
||||
return nil, fmt.Errorf(
|
||||
"challTLSServer: non-TLS-ALPN-01 challenge request received with SupportedProtos: %s",
|
||||
clientHello.SupportedProtos)
|
||||
}
|
||||
|
||||
serverName := clientHello.ServerName
|
||||
|
||||
// TLS-ALPN-01 challenge requests for IP addresses are encoded in the SNI
|
||||
// using the reverse-DNS notation. See RFC 8738 Section 6:
|
||||
// https://www.rfc-editor.org/rfc/rfc8738.html#section-6
|
||||
if strings.HasSuffix(serverName, ".in-addr.arpa") {
|
||||
serverName = strings.TrimSuffix(serverName, ".in-addr.arpa")
|
||||
parts := strings.Split(serverName, ".")
|
||||
for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
|
||||
parts[i], parts[j] = parts[j], parts[i]
|
||||
}
|
||||
serverName = strings.Join(parts, ".")
|
||||
}
|
||||
|
||||
log.Printf("challTLSServer: selecting certificate for request from %s for %s",
|
||||
clientHello.Conn.RemoteAddr(), serverName)
|
||||
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
cert := c.challCerts[serverName]
|
||||
if cert == nil {
|
||||
return nil, fmt.Errorf("challTLSServer: no challenge response certificate configured for %s", serverName)
|
||||
}
|
||||
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// challHTTPServer is a simple challenge response server that listens for HTTP
|
||||
// connections on a specific port and if they are HTTP-01 challenge requests,
|
||||
// serves the challenge response key authorization.
|
||||
type challHTTPServer struct {
|
||||
*http.Server
|
||||
// mu protects challMap
|
||||
mu sync.RWMutex
|
||||
// challMap is a mapping from request path to response body.
|
||||
challMap map[string]string
|
||||
}
|
||||
|
||||
func newChallHTTPServer(address string) *challHTTPServer {
|
||||
challServer := &challHTTPServer{
|
||||
Server: &http.Server{
|
||||
Addr: address,
|
||||
ReadTimeout: 5 * time.Second,
|
||||
WriteTimeout: 5 * time.Second,
|
||||
},
|
||||
challMap: make(map[string]string),
|
||||
}
|
||||
|
||||
challServer.Server.Handler = challServer
|
||||
|
||||
return challServer
|
||||
}
|
||||
|
||||
func (c *challHTTPServer) Supported(chal *acme.Challenge) bool {
|
||||
return chal.Type == "http-01"
|
||||
}
|
||||
|
||||
func (c *challHTTPServer) Provision(client *acme.Client, ident acme.AuthzID, chall *acme.Challenge) error {
|
||||
path := client.HTTP01ChallengePath(chall.Token)
|
||||
body, err := client.HTTP01ChallengeResponse(chall.Token)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate HTTP-01 challenge response for %v challenge %s token %s: %w",
|
||||
ident, chall.URI, chall.Token, err)
|
||||
}
|
||||
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
log.Printf("challHTTPServer: setting challenge response for %s", path)
|
||||
c.challMap[path] = body
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *challHTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("challHTTPServer: handling %s to %s from %s", r.Method, r.URL.Path, r.RemoteAddr)
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
response, exists := c.challMap[r.URL.Path]
|
||||
|
||||
if !exists {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.Write([]byte(response))
|
||||
}
|
||||
|
||||
func (c *challHTTPServer) Shutdown() error {
|
||||
log.Printf("challHTTPServer: shutting down")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
return c.Server.Shutdown(ctx)
|
||||
}
|
||||
|
||||
func (c *challHTTPServer) Run() {
|
||||
go func() {
|
||||
if err := c.Server.ListenAndServe(); err != nil {
|
||||
if !errors.Is(err, http.ErrServerClosed) {
|
||||
log.Printf("challHTTPServer error: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func testIssuance(t *testing.T, env *environment, challSrv challengeServer) {
|
||||
t.Helper()
|
||||
|
||||
// Bound the total issuance process by a timeout of 60 seconds.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Create a new ACME account.
|
||||
client := env.client
|
||||
acct, err := client.Register(ctx, &acme.Account{}, acme.AcceptTOS)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to register account: %v", err)
|
||||
}
|
||||
if acct.Status != acme.StatusValid {
|
||||
t.Fatalf("expected new account status to be valid, got %v", acct.Status)
|
||||
}
|
||||
log.Printf("registered account: %s", acct.URI)
|
||||
|
||||
// Create a new order for some example identifiers
|
||||
identifiers := []acme.AuthzID{
|
||||
{
|
||||
Type: "dns",
|
||||
Value: "example.com",
|
||||
},
|
||||
{
|
||||
Type: "dns",
|
||||
Value: "www.example.com",
|
||||
},
|
||||
{
|
||||
Type: "ip",
|
||||
Value: "127.0.0.1",
|
||||
},
|
||||
}
|
||||
order, err := client.AuthorizeOrder(ctx, identifiers)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create order for %v: %v", identifiers, err)
|
||||
}
|
||||
if order.Status != acme.StatusPending {
|
||||
t.Fatalf("expected new order status to be pending, got %v", order.Status)
|
||||
}
|
||||
orderURL := order.URI
|
||||
log.Printf("created order: %v", orderURL)
|
||||
|
||||
// For each pending authz provision a supported challenge type's response
|
||||
// with the test challenge server, and tell the ACME server to verify it.
|
||||
for _, authzURL := range order.AuthzURLs {
|
||||
authz, err := client.GetAuthorization(ctx, authzURL)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get order %s authorization %s: %v",
|
||||
orderURL, authzURL, err)
|
||||
}
|
||||
|
||||
if authz.Status != acme.StatusPending {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, challenge := range authz.Challenges {
|
||||
if challenge.Status != acme.StatusPending || !challSrv.Supported(challenge) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := challSrv.Provision(client, authz.Identifier, challenge); err != nil {
|
||||
t.Fatalf("failed to provision challenge %s: %v", challenge.URI, err)
|
||||
}
|
||||
|
||||
_, err = client.Accept(ctx, challenge)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to accept order %s challenge %s: %v",
|
||||
orderURL, challenge.URI, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the order to become ready for finalization.
|
||||
order, err = client.WaitOrder(ctx, order.URI)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to wait for order %s: %s", orderURL, err)
|
||||
}
|
||||
if order.Status != acme.StatusReady {
|
||||
t.Fatalf("expected order %s status to be ready, got %v",
|
||||
orderURL, order.Status)
|
||||
}
|
||||
|
||||
// Generate a certificate keypair and a CSR for the order identifiers.
|
||||
certKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to generate certificate key: %v", err)
|
||||
}
|
||||
var dnsNames []string
|
||||
var ipAddresses []net.IP
|
||||
for _, ident := range identifiers {
|
||||
switch ident.Type {
|
||||
case "dns":
|
||||
dnsNames = append(dnsNames, ident.Value)
|
||||
case "ip":
|
||||
ipAddresses = append(ipAddresses, net.ParseIP(ident.Value))
|
||||
default:
|
||||
t.Fatalf("unsupported identifier type: %s", ident.Type)
|
||||
}
|
||||
}
|
||||
csrDer, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{
|
||||
DNSNames: dnsNames,
|
||||
IPAddresses: ipAddresses,
|
||||
}, certKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create CSR: %v", err)
|
||||
}
|
||||
|
||||
// Finalize the order by creating a certificate with our CSR.
|
||||
chain, _, err := client.CreateOrderCert(ctx, order.FinalizeURL, csrDer, true)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to finalize order %s with finalize URL %s: %v",
|
||||
orderURL, order.FinalizeURL, err)
|
||||
}
|
||||
|
||||
// Split the chain into the leaf and any intermediates.
|
||||
leaf := chain[0]
|
||||
intermediatesDER := chain[1:]
|
||||
leafCert, err := x509.ParseCertificate(leaf)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse order %s leaf certificate: %v", orderURL, err)
|
||||
}
|
||||
intermediates := x509.NewCertPool()
|
||||
for i, intermediateDER := range intermediatesDER {
|
||||
intermediate, err := x509.ParseCertificate(intermediateDER)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse intermediate %d: %v", i, err)
|
||||
}
|
||||
intermediates.AddCert(intermediate)
|
||||
}
|
||||
|
||||
// Verify there is a valid path from the leaf certificate to Pebble's
|
||||
// issuing root using the provided intermediate certificates.
|
||||
roots, err := env.RootCert()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get Pebble issuer root certs: %v", err)
|
||||
}
|
||||
paths, err := leafCert.Verify(x509.VerifyOptions{
|
||||
Intermediates: intermediates,
|
||||
Roots: roots,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to verify order %s leaf certificate: %v", orderURL, err)
|
||||
}
|
||||
log.Printf("verified %d path(s) from issued leaf certificate to Pebble root CA", len(paths))
|
||||
|
||||
// Also verify that the leaf cert is valid for each of the DNS names
|
||||
// and IP addresses from our order's identifiers.
|
||||
for _, name := range dnsNames {
|
||||
if err := leafCert.VerifyHostname(name); err != nil {
|
||||
t.Fatalf("failed to verify order %s leaf certificate for order DNS name %s: %v",
|
||||
orderURL, name, err)
|
||||
}
|
||||
}
|
||||
for _, ip := range ipAddresses {
|
||||
if err := leafCert.VerifyHostname(ip.String()); err != nil {
|
||||
t.Fatalf("failed to verify order %s leaf certificate for order IP address %s: %v",
|
||||
orderURL, ip, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type environment struct {
|
||||
config *environmentConfig
|
||||
client *acme.Client
|
||||
}
|
||||
|
||||
// RootCert returns the Pebble CA's primary issuing hierarchy root certificate.
|
||||
// This is generated randomly at each startup and can be used to verify
|
||||
// certificate chains issued by Pebble's ACME interface. Note that this
|
||||
// is separate from the static root certificate used by the Pebble ACME
|
||||
// HTTPS interface.
|
||||
func (e *environment) RootCert() (*x509.CertPool, error) {
|
||||
// NOTE: in the future we may want to consider the alternative chains
|
||||
// returned as Link alternative headers.
|
||||
rootURL := fmt.Sprintf("https://%s/roots/0", e.config.pebbleConfig.ManagementListenAddress)
|
||||
resp, err := e.client.HTTPClient.Get(rootURL)
|
||||
if err != nil || resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("failed to GET Pebble root CA from %s: %v", rootURL, err)
|
||||
}
|
||||
|
||||
roots := x509.NewCertPool()
|
||||
rootPEM, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse Pebble root CA PEM: %v", err)
|
||||
}
|
||||
rootDERBlock, _ := pem.Decode(rootPEM)
|
||||
rootCA, err := x509.ParseCertificate(rootDERBlock.Bytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse Pebble root CA DER: %v", err)
|
||||
}
|
||||
roots.AddCert(rootCA)
|
||||
|
||||
return roots, nil
|
||||
}
|
||||
|
||||
// environmentConfig describes the Pebble configuration, and configuration
|
||||
// shared between pebble and pebble-challtestsrv.
|
||||
type environmentConfig struct {
|
||||
pebbleConfig
|
||||
dnsPort uint32
|
||||
}
|
||||
|
||||
// defaultConfig returns an environmentConfig populated with default values.
|
||||
// The provided pebbleDir is used to specify certificate/private key paths
|
||||
// for the HTTPS ACME interface.
|
||||
func defaultConfig(pebbleDir string) environmentConfig {
|
||||
return environmentConfig{
|
||||
pebbleConfig: pebbleConfig{
|
||||
ListenAddress: fmt.Sprintf("127.0.0.1:%d", takeNextPort()),
|
||||
ManagementListenAddress: fmt.Sprintf("127.0.0.1:%d", takeNextPort()),
|
||||
HTTPPort: takeNextPort(),
|
||||
TLSPort: takeNextPort(),
|
||||
Certificate: fmt.Sprintf("%s/test/certs/localhost/cert.pem", pebbleDir),
|
||||
PrivateKey: fmt.Sprintf("%s/test/certs/localhost/key.pem", pebbleDir),
|
||||
OCSPResponderURL: "",
|
||||
ExternalAccountBindingRequired: false,
|
||||
ExternalAccountMACKeys: make(map[string]string),
|
||||
DomainBlocklist: []string{"blocked-domain.example"},
|
||||
Profiles: map[string]struct {
|
||||
Description string
|
||||
ValidityPeriod uint64
|
||||
}{
|
||||
"default": {
|
||||
Description: "default profile",
|
||||
ValidityPeriod: 3600,
|
||||
},
|
||||
},
|
||||
RetryAfter: struct {
|
||||
Authz int
|
||||
Order int
|
||||
}{
|
||||
3,
|
||||
5,
|
||||
},
|
||||
},
|
||||
dnsPort: takeNextPort(),
|
||||
}
|
||||
}
|
||||
|
||||
// pebbleConfig matches the JSON structure of the Pebble configuration file.
|
||||
type pebbleConfig struct {
|
||||
ListenAddress string
|
||||
ManagementListenAddress string
|
||||
HTTPPort uint32
|
||||
TLSPort uint32
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
OCSPResponderURL string
|
||||
ExternalAccountBindingRequired bool
|
||||
ExternalAccountMACKeys map[string]string
|
||||
DomainBlocklist []string
|
||||
Profiles map[string]struct {
|
||||
Description string
|
||||
ValidityPeriod uint64
|
||||
}
|
||||
RetryAfter struct {
|
||||
Authz int
|
||||
Order int
|
||||
}
|
||||
}
|
||||
|
||||
func takeNextPort() uint32 {
|
||||
return nextPort.Add(1) - 1
|
||||
}
|
||||
|
||||
// startPebbleEnvironment is a test helper that spawns Pebble and Pebble
|
||||
// challenge test server processes based on the provided environmentConfig. The
|
||||
// processes will be torn down when the test ends.
|
||||
func startPebbleEnvironment(t *testing.T, config *environmentConfig) environment {
|
||||
t.Helper()
|
||||
|
||||
var pebbleDir string
|
||||
if *pebbleLocalDir != "" {
|
||||
pebbleDir = *pebbleLocalDir
|
||||
} else {
|
||||
pebbleDir = fetchModule(t, "github.com/letsencrypt/pebble/v2", pebbleModVersion)
|
||||
}
|
||||
|
||||
binDir := prepareBinaries(t, pebbleDir)
|
||||
|
||||
if config == nil {
|
||||
cfg := defaultConfig(pebbleDir)
|
||||
config = &cfg
|
||||
}
|
||||
|
||||
marshalConfig := struct {
|
||||
Pebble pebbleConfig
|
||||
}{
|
||||
Pebble: config.pebbleConfig,
|
||||
}
|
||||
|
||||
configData, err := json.Marshal(marshalConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal config: %v", err)
|
||||
}
|
||||
|
||||
configFile, err := os.CreateTemp("", "pebble-config-*.json")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp config file: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { os.Remove(configFile.Name()) })
|
||||
|
||||
if _, err := configFile.Write(configData); err != nil {
|
||||
t.Fatalf("failed to write config file: %v", err)
|
||||
}
|
||||
configFile.Close()
|
||||
|
||||
log.Printf("pebble dir: %s", pebbleDir)
|
||||
log.Printf("config file: %s", configFile.Name())
|
||||
|
||||
// Spawn the Pebble CA server. It answers ACME requests and performs
|
||||
// outbound validations. We configure it to use a mock DNS server that
|
||||
// always answers 127.0.0.1 for all A queries so that validation
|
||||
// requests for any domain name will resolve to our local challenge
|
||||
// server instances.
|
||||
spawnServerProcess(t, binDir, "pebble", "-config", configFile.Name(),
|
||||
"-dnsserver", fmt.Sprintf("127.0.0.1:%d", config.dnsPort),
|
||||
"-strict")
|
||||
|
||||
// Spawn the Pebble challenge test server. We'll use it to mock DNS
|
||||
// responses but disable all the other interfaces. We want to stand
|
||||
// up our own challenge response servers for TLS-ALPN-01,
|
||||
// etc.
|
||||
// Note: we specify -defaultIPv6 "" so that no AAAA records are served.
|
||||
// The LUCI CI runners have issues with IPv6 connectivity on localhost.
|
||||
spawnServerProcess(t, binDir, "pebble-challtestsrv",
|
||||
"-dns01", fmt.Sprintf(":%d", config.dnsPort),
|
||||
"-defaultIPv6", "",
|
||||
"-management", fmt.Sprintf(":%d", takeNextPort()),
|
||||
"-doh", "",
|
||||
"-http01", "",
|
||||
"-tlsalpn01", "",
|
||||
"-https01", "")
|
||||
|
||||
waitForServer(t, config.pebbleConfig.ListenAddress)
|
||||
waitForServer(t, fmt.Sprintf("127.0.0.1:%d", config.dnsPort))
|
||||
|
||||
log.Printf("pebble environment ready")
|
||||
|
||||
// Construct a cert pool that contains the CA certificate used by the ACME
|
||||
// interface's certificate chain. This is separate from the issuing
|
||||
// hierarchy and is used for the ACME client to interact with the ACME
|
||||
// interface without cert verification error.
|
||||
caCertPath := filepath.Join(pebbleDir, "test/certs/pebble.minica.pem")
|
||||
caCert, err := os.ReadFile(caCertPath)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read CA certificate %s: %v", caCertPath, err)
|
||||
}
|
||||
caCertPool := x509.NewCertPool()
|
||||
if !caCertPool.AppendCertsFromPEM(caCert) {
|
||||
t.Fatalf("failed to parse CA certificate %s", caCertPath)
|
||||
}
|
||||
httpClient := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
RootCAs: caCertPool,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Create an ACME account keypair/client and verify it can discover
|
||||
// the Pebble server's ACME directory without error.
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to generate account key: %v", err)
|
||||
}
|
||||
client := &acme.Client{
|
||||
Key: key,
|
||||
HTTPClient: httpClient,
|
||||
DirectoryURL: fmt.Sprintf("https://%s/dir", config.ListenAddress),
|
||||
}
|
||||
_, err = client.Discover(context.TODO())
|
||||
if err != nil {
|
||||
t.Fatalf("failed to discover ACME directory: %v", err)
|
||||
}
|
||||
|
||||
return environment{
|
||||
config: config,
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
func waitForServer(t *testing.T, addr string) {
|
||||
t.Helper()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
if conn, err := net.Dial("tcp", addr); err == nil {
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Duration(i*100) * time.Millisecond)
|
||||
}
|
||||
t.Fatalf("failed to connect to %q after 20 tries", addr)
|
||||
}
|
||||
|
||||
// fetchModule fetches the module at the given version and returns the directory
|
||||
// containing its source tree. It skips the test if fetching modules is not
|
||||
// possible in this environment.
|
||||
//
|
||||
// Copied from the stdlib cryptotest.FetchModule and adapted to not rely on the
|
||||
// stdlib internal testenv package.
|
||||
func fetchModule(t *testing.T, module, version string) string {
|
||||
// If the default GOMODCACHE doesn't exist, use a temporary directory
|
||||
// instead. (For example, run.bash sets GOPATH=/nonexist-gopath.)
|
||||
out, err := exec.Command("go", "env", "GOMODCACHE").Output()
|
||||
if err != nil {
|
||||
t.Errorf("go env GOMODCACHE: %v\n%s", err, out)
|
||||
if ee, ok := err.(*exec.ExitError); ok {
|
||||
t.Logf("%s", ee.Stderr)
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
modcacheOk := false
|
||||
if gomodcache := string(bytes.TrimSpace(out)); gomodcache != "" {
|
||||
if _, err := os.Stat(gomodcache); err == nil {
|
||||
modcacheOk = true
|
||||
}
|
||||
}
|
||||
if !modcacheOk {
|
||||
t.Setenv("GOMODCACHE", t.TempDir())
|
||||
// Allow t.TempDir() to clean up subdirectories.
|
||||
t.Setenv("GOFLAGS", os.Getenv("GOFLAGS")+" -modcacherw")
|
||||
}
|
||||
|
||||
t.Logf("fetching %s@%s\n", module, version)
|
||||
|
||||
output, err := exec.Command("go", "mod", "download", "-json", module+"@"+version).CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to download %s@%s: %s\n%s\n", module, version, err, output)
|
||||
}
|
||||
var j struct {
|
||||
Dir string
|
||||
}
|
||||
if err := json.Unmarshal(output, &j); err != nil {
|
||||
t.Fatalf("failed to parse 'go mod download': %s\n%s\n", err, output)
|
||||
}
|
||||
|
||||
return j.Dir
|
||||
}
|
||||
|
||||
func prepareBinaries(t *testing.T, pebbleDir string) string {
|
||||
t.Helper()
|
||||
|
||||
// We don't want to build in the module cache dir, which might not be
|
||||
// writable or to pollute the user's clone with binaries if pebbleLocalDir
|
||||
//is used.
|
||||
binDir := t.TempDir()
|
||||
|
||||
build := func(cmd string) {
|
||||
log.Printf("building %s", cmd)
|
||||
buildCmd := exec.Command(
|
||||
"go",
|
||||
"build", "-o", filepath.Join(binDir, cmd), "-mod", "mod", "./cmd/"+cmd)
|
||||
buildCmd.Dir = pebbleDir
|
||||
output, err := buildCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to build %s: %s\n%s\n", cmd, err, output)
|
||||
}
|
||||
}
|
||||
|
||||
build("pebble")
|
||||
build("pebble-challtestsrv")
|
||||
|
||||
return binDir
|
||||
}
|
||||
|
||||
func spawnServerProcess(t *testing.T, dir string, cmd string, args ...string) {
|
||||
t.Helper()
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
|
||||
cmdInstance := exec.Command("./"+cmd, args...)
|
||||
cmdInstance.Dir = dir
|
||||
cmdInstance.Stdout = &stdout
|
||||
cmdInstance.Stderr = &stderr
|
||||
|
||||
if err := cmdInstance.Start(); err != nil {
|
||||
t.Fatalf("failed to start %s: %v", cmd, err)
|
||||
}
|
||||
|
||||
t.Cleanup(func() {
|
||||
cmdInstance.Process.Kill()
|
||||
cmdInstance.Wait()
|
||||
|
||||
if t.Failed() || testing.Verbose() {
|
||||
t.Logf("=== %s output ===", cmd)
|
||||
if stdout.Len() > 0 {
|
||||
t.Logf("stdout:\n%s", strings.TrimSpace(stdout.String()))
|
||||
}
|
||||
if stderr.Len() > 0 {
|
||||
t.Logf("stderr:\n%s", strings.TrimSpace(stderr.String()))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
+1
-1
@@ -619,7 +619,7 @@ func (*certOptKey) privateCertOpt() {}
|
||||
//
|
||||
// In TLS ChallengeCert methods, the template is also used as parent,
|
||||
// resulting in a self-signed certificate.
|
||||
// The DNSNames field of t is always overwritten for tls-sni challenge certs.
|
||||
// The DNSNames or IPAddresses fields of t are always overwritten for tls-alpn challenge certs.
|
||||
func WithTemplate(t *x509.Certificate) CertOption {
|
||||
return (*certOptTemplate)(t)
|
||||
}
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ func (ih InvalidHashPrefixError) Error() string {
|
||||
type InvalidCostError int
|
||||
|
||||
func (ic InvalidCostError) Error() string {
|
||||
return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), MinCost, MaxCost)
|
||||
return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed inclusive range %d..%d", int(ic), MinCost, MaxCost)
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
|
||||
// XOF defines the interface to hash functions that
|
||||
// support arbitrary-length output.
|
||||
//
|
||||
// New callers should prefer the standard library [hash.XOF].
|
||||
type XOF interface {
|
||||
// Write absorbs more data into the hash's state. It panics if called
|
||||
// after Read.
|
||||
@@ -47,6 +49,8 @@ const maxOutputLength = (1 << 32) * 64
|
||||
//
|
||||
// A non-nil key turns the hash into a MAC. The key must between
|
||||
// zero and 32 bytes long.
|
||||
//
|
||||
// The result can be safely interface-upgraded to [hash.XOF].
|
||||
func NewXOF(size uint32, key []byte) (XOF, error) {
|
||||
if len(key) > Size {
|
||||
return nil, errKeySize
|
||||
@@ -93,6 +97,10 @@ func (x *xof) Clone() XOF {
|
||||
return &clone
|
||||
}
|
||||
|
||||
func (x *xof) BlockSize() int {
|
||||
return x.d.BlockSize()
|
||||
}
|
||||
|
||||
func (x *xof) Reset() {
|
||||
x.cfg[0] = byte(Size)
|
||||
binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.25
|
||||
|
||||
package blake2b
|
||||
|
||||
import "hash"
|
||||
|
||||
var _ hash.XOF = (*xof)(nil)
|
||||
@@ -3,9 +3,9 @@ module golang.org/x/crypto
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
golang.org/x/net v0.21.0 // tagx:ignore
|
||||
golang.org/x/sys v0.33.0
|
||||
golang.org/x/term v0.32.0
|
||||
golang.org/x/net v0.42.0 // tagx:ignore
|
||||
golang.org/x/sys v0.35.0
|
||||
golang.org/x/term v0.34.0
|
||||
)
|
||||
|
||||
require golang.org/x/text v0.25.0 // indirect
|
||||
require golang.org/x/text v0.28.0 // indirect
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
|
||||
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
|
||||
+11
-11
@@ -555,7 +555,7 @@ func (c *client) insertKey(s interface{}, comment string, constraints []byte) er
|
||||
})
|
||||
case *dsa.PrivateKey:
|
||||
req = ssh.Marshal(dsaKeyMsg{
|
||||
Type: ssh.KeyAlgoDSA,
|
||||
Type: ssh.InsecureKeyAlgoDSA,
|
||||
P: k.P,
|
||||
Q: k.Q,
|
||||
G: k.G,
|
||||
@@ -803,16 +803,16 @@ var _ ssh.AlgorithmSigner = &agentKeyringSigner{}
|
||||
//
|
||||
// This map must be kept in sync with the one in certs.go.
|
||||
var certKeyAlgoNames = map[string]string{
|
||||
ssh.CertAlgoRSAv01: ssh.KeyAlgoRSA,
|
||||
ssh.CertAlgoRSASHA256v01: ssh.KeyAlgoRSASHA256,
|
||||
ssh.CertAlgoRSASHA512v01: ssh.KeyAlgoRSASHA512,
|
||||
ssh.CertAlgoDSAv01: ssh.KeyAlgoDSA,
|
||||
ssh.CertAlgoECDSA256v01: ssh.KeyAlgoECDSA256,
|
||||
ssh.CertAlgoECDSA384v01: ssh.KeyAlgoECDSA384,
|
||||
ssh.CertAlgoECDSA521v01: ssh.KeyAlgoECDSA521,
|
||||
ssh.CertAlgoSKECDSA256v01: ssh.KeyAlgoSKECDSA256,
|
||||
ssh.CertAlgoED25519v01: ssh.KeyAlgoED25519,
|
||||
ssh.CertAlgoSKED25519v01: ssh.KeyAlgoSKED25519,
|
||||
ssh.CertAlgoRSAv01: ssh.KeyAlgoRSA,
|
||||
ssh.CertAlgoRSASHA256v01: ssh.KeyAlgoRSASHA256,
|
||||
ssh.CertAlgoRSASHA512v01: ssh.KeyAlgoRSASHA512,
|
||||
ssh.InsecureCertAlgoDSAv01: ssh.InsecureKeyAlgoDSA,
|
||||
ssh.CertAlgoECDSA256v01: ssh.KeyAlgoECDSA256,
|
||||
ssh.CertAlgoECDSA384v01: ssh.KeyAlgoECDSA384,
|
||||
ssh.CertAlgoECDSA521v01: ssh.KeyAlgoECDSA521,
|
||||
ssh.CertAlgoSKECDSA256v01: ssh.KeyAlgoSKECDSA256,
|
||||
ssh.CertAlgoED25519v01: ssh.KeyAlgoED25519,
|
||||
ssh.CertAlgoSKED25519v01: ssh.KeyAlgoSKED25519,
|
||||
}
|
||||
|
||||
// underlyingAlgo returns the signature algorithm associated with algo (which is
|
||||
|
||||
+2
-2
@@ -506,7 +506,7 @@ func (s *server) insertIdentity(req []byte) error {
|
||||
switch record.Type {
|
||||
case ssh.KeyAlgoRSA:
|
||||
addedKey, err = parseRSAKey(req)
|
||||
case ssh.KeyAlgoDSA:
|
||||
case ssh.InsecureKeyAlgoDSA:
|
||||
addedKey, err = parseDSAKey(req)
|
||||
case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521:
|
||||
addedKey, err = parseECDSAKey(req)
|
||||
@@ -514,7 +514,7 @@ func (s *server) insertIdentity(req []byte) error {
|
||||
addedKey, err = parseEd25519Key(req)
|
||||
case ssh.CertAlgoRSAv01:
|
||||
addedKey, err = parseRSACert(req)
|
||||
case ssh.CertAlgoDSAv01:
|
||||
case ssh.InsecureCertAlgoDSAv01:
|
||||
addedKey, err = parseDSACert(req)
|
||||
case ssh.CertAlgoECDSA256v01, ssh.CertAlgoECDSA384v01, ssh.CertAlgoECDSA521v01:
|
||||
addedKey, err = parseECDSACert(req)
|
||||
|
||||
+40
-27
@@ -20,14 +20,19 @@ import (
|
||||
// returned by MultiAlgorithmSigner and don't appear in the Signature.Format
|
||||
// field.
|
||||
const (
|
||||
CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
|
||||
CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
|
||||
CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
|
||||
CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
|
||||
CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
|
||||
CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
|
||||
CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com"
|
||||
CertAlgoSKED25519v01 = "sk-ssh-ed25519-cert-v01@openssh.com"
|
||||
CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
|
||||
// Deprecated: DSA is only supported at insecure key sizes, and was removed
|
||||
// from major implementations.
|
||||
CertAlgoDSAv01 = InsecureCertAlgoDSAv01
|
||||
// Deprecated: DSA is only supported at insecure key sizes, and was removed
|
||||
// from major implementations.
|
||||
InsecureCertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
|
||||
CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
|
||||
CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
|
||||
CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
|
||||
CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
|
||||
CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com"
|
||||
CertAlgoSKED25519v01 = "sk-ssh-ed25519-cert-v01@openssh.com"
|
||||
|
||||
// CertAlgoRSASHA256v01 and CertAlgoRSASHA512v01 can't appear as a
|
||||
// Certificate.Type (or PublicKey.Type), but only in
|
||||
@@ -228,7 +233,11 @@ func parseCert(in []byte, privAlgo string) (*Certificate, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The Type() function is intended to return only certificate key types, but
|
||||
// we use certKeyAlgoNames anyway for safety, to match [Certificate.Type].
|
||||
if _, ok := certKeyAlgoNames[k.Type()]; ok {
|
||||
return nil, fmt.Errorf("ssh: the signature key type %q is invalid for certificates", k.Type())
|
||||
}
|
||||
c.SignatureKey = k
|
||||
c.Signature, rest, ok = parseSignatureBody(g.Signature)
|
||||
if !ok || len(rest) > 0 {
|
||||
@@ -296,16 +305,13 @@ type CertChecker struct {
|
||||
SupportedCriticalOptions []string
|
||||
|
||||
// IsUserAuthority should return true if the key is recognized as an
|
||||
// authority for the given user certificate. This allows for
|
||||
// certificates to be signed by other certificates. This must be set
|
||||
// if this CertChecker will be checking user certificates.
|
||||
// authority for user certificate. This must be set if this CertChecker
|
||||
// will be checking user certificates.
|
||||
IsUserAuthority func(auth PublicKey) bool
|
||||
|
||||
// IsHostAuthority should report whether the key is recognized as
|
||||
// an authority for this host. This allows for certificates to be
|
||||
// signed by other keys, and for those other keys to only be valid
|
||||
// signers for particular hostnames. This must be set if this
|
||||
// CertChecker will be checking host certificates.
|
||||
// an authority for this host. This must be set if this CertChecker
|
||||
// will be checking host certificates.
|
||||
IsHostAuthority func(auth PublicKey, address string) bool
|
||||
|
||||
// Clock is used for verifying time stamps. If nil, time.Now
|
||||
@@ -442,12 +448,19 @@ func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
|
||||
// SignCert signs the certificate with an authority, setting the Nonce,
|
||||
// SignatureKey, and Signature fields. If the authority implements the
|
||||
// MultiAlgorithmSigner interface the first algorithm in the list is used. This
|
||||
// is useful if you want to sign with a specific algorithm.
|
||||
// is useful if you want to sign with a specific algorithm. As specified in
|
||||
// [SSH-CERTS], Section 2.1.1, authority can't be a [Certificate].
|
||||
func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
|
||||
c.Nonce = make([]byte, 32)
|
||||
if _, err := io.ReadFull(rand, c.Nonce); err != nil {
|
||||
return err
|
||||
}
|
||||
// The Type() function is intended to return only certificate key types, but
|
||||
// we use certKeyAlgoNames anyway for safety, to match [Certificate.Type].
|
||||
if _, ok := certKeyAlgoNames[authority.PublicKey().Type()]; ok {
|
||||
return fmt.Errorf("ssh: certificates cannot be used as authority (public key type %q)",
|
||||
authority.PublicKey().Type())
|
||||
}
|
||||
c.SignatureKey = authority.PublicKey()
|
||||
|
||||
if v, ok := authority.(MultiAlgorithmSigner); ok {
|
||||
@@ -485,16 +498,16 @@ func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
|
||||
//
|
||||
// This map must be kept in sync with the one in agent/client.go.
|
||||
var certKeyAlgoNames = map[string]string{
|
||||
CertAlgoRSAv01: KeyAlgoRSA,
|
||||
CertAlgoRSASHA256v01: KeyAlgoRSASHA256,
|
||||
CertAlgoRSASHA512v01: KeyAlgoRSASHA512,
|
||||
CertAlgoDSAv01: KeyAlgoDSA,
|
||||
CertAlgoECDSA256v01: KeyAlgoECDSA256,
|
||||
CertAlgoECDSA384v01: KeyAlgoECDSA384,
|
||||
CertAlgoECDSA521v01: KeyAlgoECDSA521,
|
||||
CertAlgoSKECDSA256v01: KeyAlgoSKECDSA256,
|
||||
CertAlgoED25519v01: KeyAlgoED25519,
|
||||
CertAlgoSKED25519v01: KeyAlgoSKED25519,
|
||||
CertAlgoRSAv01: KeyAlgoRSA,
|
||||
CertAlgoRSASHA256v01: KeyAlgoRSASHA256,
|
||||
CertAlgoRSASHA512v01: KeyAlgoRSASHA512,
|
||||
InsecureCertAlgoDSAv01: InsecureKeyAlgoDSA,
|
||||
CertAlgoECDSA256v01: KeyAlgoECDSA256,
|
||||
CertAlgoECDSA384v01: KeyAlgoECDSA384,
|
||||
CertAlgoECDSA521v01: KeyAlgoECDSA521,
|
||||
CertAlgoSKECDSA256v01: KeyAlgoSKECDSA256,
|
||||
CertAlgoED25519v01: KeyAlgoED25519,
|
||||
CertAlgoSKED25519v01: KeyAlgoSKED25519,
|
||||
}
|
||||
|
||||
// underlyingAlgo returns the signature algorithm associated with algo (which is
|
||||
|
||||
+30
-1
@@ -297,7 +297,7 @@ func TestCertTypes(t *testing.T) {
|
||||
{"legacyRSASigner", &legacyRSASigner{testSigners["rsa"]}, KeyAlgoRSA},
|
||||
{"multiAlgoRSASignerSHA256", multiAlgoSignerSHA256, KeyAlgoRSASHA256},
|
||||
{"multiAlgoRSASignerSHA512", multiAlgoSignerSHA512, KeyAlgoRSASHA512},
|
||||
{CertAlgoDSAv01, testSigners["dsa"], ""},
|
||||
{InsecureCertAlgoDSAv01, testSigners["dsa"], ""},
|
||||
}
|
||||
|
||||
k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
@@ -404,3 +404,32 @@ func TestCertSignWithMultiAlgorithmSigner(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertSignWithCertificate(t *testing.T) {
|
||||
cert := &Certificate{
|
||||
Key: testPublicKeys["rsa"],
|
||||
ValidBefore: CertTimeInfinity,
|
||||
CertType: UserCert,
|
||||
}
|
||||
if err := cert.SignCert(rand.Reader, testSigners["ecdsa"]); err != nil {
|
||||
t.Fatalf("SignCert: %v", err)
|
||||
}
|
||||
signer, err := NewSignerWithAlgorithms(testSigners["rsa"].(AlgorithmSigner), []string{KeyAlgoRSASHA256})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
certSigner, err := NewCertSigner(cert, signer)
|
||||
if err != nil {
|
||||
t.Fatalf("NewCertSigner: %v", err)
|
||||
}
|
||||
|
||||
cert1 := &Certificate{
|
||||
Key: testPublicKeys["ecdsa"],
|
||||
ValidBefore: CertTimeInfinity,
|
||||
CertType: UserCert,
|
||||
}
|
||||
|
||||
if err := cert1.SignCert(rand.Reader, certSigner); err == nil {
|
||||
t.Fatal("successfully signed a certificate using another certificate, it is expected to fail")
|
||||
}
|
||||
}
|
||||
|
||||
+19
-21
@@ -58,11 +58,11 @@ func newRC4(key, iv []byte) (cipher.Stream, error) {
|
||||
type cipherMode struct {
|
||||
keySize int
|
||||
ivSize int
|
||||
create func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error)
|
||||
create func(key, iv []byte, macKey []byte, algs DirectionAlgorithms) (packetCipher, error)
|
||||
}
|
||||
|
||||
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) {
|
||||
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
|
||||
@@ -98,36 +98,36 @@ func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher.Stream,
|
||||
var cipherModes = map[string]*cipherMode{
|
||||
// Ciphers from RFC 4344, which introduced many CTR-based ciphers. Algorithms
|
||||
// are defined in the order specified in the RFC.
|
||||
"aes128-ctr": {16, aes.BlockSize, streamCipherMode(0, newAESCTR)},
|
||||
"aes192-ctr": {24, aes.BlockSize, streamCipherMode(0, newAESCTR)},
|
||||
"aes256-ctr": {32, aes.BlockSize, streamCipherMode(0, newAESCTR)},
|
||||
CipherAES128CTR: {16, aes.BlockSize, streamCipherMode(0, newAESCTR)},
|
||||
CipherAES192CTR: {24, aes.BlockSize, streamCipherMode(0, newAESCTR)},
|
||||
CipherAES256CTR: {32, aes.BlockSize, streamCipherMode(0, newAESCTR)},
|
||||
|
||||
// Ciphers from RFC 4345, which introduces security-improved arcfour ciphers.
|
||||
// They are defined in the order specified in the RFC.
|
||||
"arcfour128": {16, 0, streamCipherMode(1536, newRC4)},
|
||||
"arcfour256": {32, 0, streamCipherMode(1536, newRC4)},
|
||||
InsecureCipherRC4128: {16, 0, streamCipherMode(1536, newRC4)},
|
||||
InsecureCipherRC4256: {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."
|
||||
// RFC 4345 introduces improved versions of Arcfour.
|
||||
"arcfour": {16, 0, streamCipherMode(0, newRC4)},
|
||||
InsecureCipherRC4: {16, 0, streamCipherMode(0, newRC4)},
|
||||
|
||||
// AEAD ciphers
|
||||
gcm128CipherID: {16, 12, newGCMCipher},
|
||||
gcm256CipherID: {32, 12, newGCMCipher},
|
||||
chacha20Poly1305ID: {64, 0, newChaCha20Cipher},
|
||||
CipherAES128GCM: {16, 12, newGCMCipher},
|
||||
CipherAES256GCM: {32, 12, newGCMCipher},
|
||||
CipherChaCha20Poly1305: {64, 0, newChaCha20Cipher},
|
||||
|
||||
// CBC mode is insecure and so is not included in the default config.
|
||||
// (See https://www.ieee-security.org/TC/SP2013/papers/4977a526.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, newAESCBCCipher},
|
||||
InsecureCipherAES128CBC: {16, aes.BlockSize, newAESCBCCipher},
|
||||
|
||||
// 3des-cbc is insecure and is not included in the default
|
||||
// config.
|
||||
tripledescbcID: {24, des.BlockSize, newTripleDESCBCCipher},
|
||||
InsecureCipherTripleDESCBC: {24, des.BlockSize, newTripleDESCBCCipher},
|
||||
}
|
||||
|
||||
// prefixLen is the length of the packet prefix that contains the packet length
|
||||
@@ -307,7 +307,7 @@ type gcmCipher struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) {
|
||||
func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs DirectionAlgorithms) (packetCipher, error) {
|
||||
c, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -429,7 +429,7 @@ type cbcCipher struct {
|
||||
oracleCamouflage uint32
|
||||
}
|
||||
|
||||
func newCBCCipher(c cipher.Block, key, iv, 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),
|
||||
@@ -443,7 +443,7 @@ func newCBCCipher(c cipher.Block, key, iv, macKey []byte, algs directionAlgorith
|
||||
return cbc, nil
|
||||
}
|
||||
|
||||
func newAESCBCCipher(key, iv, 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
|
||||
@@ -457,7 +457,7 @@ func newAESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCi
|
||||
return cbc, nil
|
||||
}
|
||||
|
||||
func newTripleDESCBCCipher(key, iv, 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
|
||||
@@ -635,8 +635,6 @@ func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader
|
||||
return nil
|
||||
}
|
||||
|
||||
const chacha20Poly1305ID = "chacha20-poly1305@openssh.com"
|
||||
|
||||
// chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com
|
||||
// AEAD, which is described here:
|
||||
//
|
||||
@@ -650,7 +648,7 @@ type chacha20Poly1305Cipher struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) {
|
||||
func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs DirectionAlgorithms) (packetCipher, error) {
|
||||
if len(key) != 64 {
|
||||
panic(len(key))
|
||||
}
|
||||
|
||||
+14
-14
@@ -22,7 +22,7 @@ func TestDefaultCiphersExist(t *testing.T) {
|
||||
t.Errorf("supported cipher %q is unknown", cipherAlgo)
|
||||
}
|
||||
}
|
||||
for _, cipherAlgo := range preferredCiphers {
|
||||
for _, cipherAlgo := range defaultCiphers {
|
||||
if _, ok := cipherModes[cipherAlgo]; !ok {
|
||||
t.Errorf("preferred cipher %q is unknown", cipherAlgo)
|
||||
}
|
||||
@@ -30,8 +30,8 @@ func TestDefaultCiphersExist(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPacketCiphers(t *testing.T) {
|
||||
defaultMac := "hmac-sha2-256"
|
||||
defaultCipher := "aes128-ctr"
|
||||
defaultMac := HMACSHA256
|
||||
defaultCipher := CipherAES128CTR
|
||||
for cipher := range cipherModes {
|
||||
t.Run("cipher="+cipher,
|
||||
func(t *testing.T) { testPacketCipher(t, cipher, defaultMac) })
|
||||
@@ -44,10 +44,10 @@ func TestPacketCiphers(t *testing.T) {
|
||||
|
||||
func testPacketCipher(t *testing.T, cipher, mac string) {
|
||||
kr := &kexResult{Hash: crypto.SHA1}
|
||||
algs := directionAlgorithms{
|
||||
algs := DirectionAlgorithms{
|
||||
Cipher: cipher,
|
||||
MAC: mac,
|
||||
Compression: "none",
|
||||
compression: compressionNone,
|
||||
}
|
||||
client, err := newPacketCipher(clientKeys, algs, kr)
|
||||
if err != nil {
|
||||
@@ -77,10 +77,10 @@ func testPacketCipher(t *testing.T, cipher, mac string) {
|
||||
|
||||
func TestCBCOracleCounterMeasure(t *testing.T) {
|
||||
kr := &kexResult{Hash: crypto.SHA1}
|
||||
algs := directionAlgorithms{
|
||||
Cipher: aes128cbcID,
|
||||
MAC: "hmac-sha1",
|
||||
Compression: "none",
|
||||
algs := DirectionAlgorithms{
|
||||
Cipher: InsecureCipherAES128CBC,
|
||||
MAC: HMACSHA1,
|
||||
compression: compressionNone,
|
||||
}
|
||||
client, err := newPacketCipher(clientKeys, algs, kr)
|
||||
if err != nil {
|
||||
@@ -141,7 +141,7 @@ func TestCVE202143565(t *testing.T) {
|
||||
constructPacket func(packetCipher) io.Reader
|
||||
}{
|
||||
{
|
||||
cipher: gcm128CipherID,
|
||||
cipher: CipherAES128GCM,
|
||||
constructPacket: func(client packetCipher) io.Reader {
|
||||
internalCipher := client.(*gcmCipher)
|
||||
b := &bytes.Buffer{}
|
||||
@@ -159,7 +159,7 @@ func TestCVE202143565(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
cipher: chacha20Poly1305ID,
|
||||
cipher: CipherChaCha20Poly1305,
|
||||
constructPacket: func(client packetCipher) io.Reader {
|
||||
internalCipher := client.(*chacha20Poly1305Cipher)
|
||||
b := &bytes.Buffer{}
|
||||
@@ -201,13 +201,13 @@ func TestCVE202143565(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
mac := "hmac-sha2-256"
|
||||
mac := HMACSHA256
|
||||
|
||||
kr := &kexResult{Hash: crypto.SHA1}
|
||||
algs := directionAlgorithms{
|
||||
algs := DirectionAlgorithms{
|
||||
Cipher: tc.cipher,
|
||||
MAC: mac,
|
||||
Compression: "none",
|
||||
compression: compressionNone,
|
||||
}
|
||||
client, err := newPacketCipher(clientKeys, algs, kr)
|
||||
if err != nil {
|
||||
|
||||
@@ -110,6 +110,7 @@ func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) e
|
||||
}
|
||||
|
||||
c.sessionID = c.transport.getSessionID()
|
||||
c.algorithms = c.transport.getAlgorithms()
|
||||
return c.clientAuthenticate(config)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -289,7 +289,7 @@ func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (MultiA
|
||||
}
|
||||
}
|
||||
|
||||
algo, err := findCommon("public key signature algorithm", keyAlgos, serverAlgos)
|
||||
algo, err := findCommon("public key signature algorithm", keyAlgos, serverAlgos, true)
|
||||
if err != nil {
|
||||
// If there is no overlap, return the fallback algorithm to support
|
||||
// servers that fail to list all supported algorithms.
|
||||
|
||||
@@ -324,6 +324,9 @@ func TestMethodInvalidAlgorithm(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestClientHMAC(t *testing.T) {
|
||||
supportedAlgos := SupportedAlgorithms()
|
||||
insecureAlgos := InsecureAlgorithms()
|
||||
supportedMACs := append(supportedAlgos.MACs, insecureAlgos.MACs...)
|
||||
for _, mac := range supportedMACs {
|
||||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
@@ -349,7 +352,7 @@ func TestClientUnsupportedCipher(t *testing.T) {
|
||||
PublicKeys(),
|
||||
},
|
||||
Config: Config{
|
||||
Ciphers: []string{"aes128-cbc"}, // not currently supported
|
||||
Ciphers: []string{"unsupported-cipher"}, // not currently supported
|
||||
},
|
||||
}
|
||||
if err := tryAuth(t, config); err == nil {
|
||||
|
||||
+5
-5
@@ -292,7 +292,7 @@ func TestUnsupportedAlgorithm(t *testing.T) {
|
||||
{
|
||||
"unsupported and supported KEXs",
|
||||
Config{
|
||||
KeyExchanges: []string{"unsupported", kexAlgoCurve25519SHA256},
|
||||
KeyExchanges: []string{"unsupported", KeyExchangeCurve25519},
|
||||
},
|
||||
"",
|
||||
},
|
||||
@@ -306,7 +306,7 @@ func TestUnsupportedAlgorithm(t *testing.T) {
|
||||
{
|
||||
"unsupported and supported ciphers",
|
||||
Config{
|
||||
Ciphers: []string{"unsupported", chacha20Poly1305ID},
|
||||
Ciphers: []string{"unsupported", CipherChaCha20Poly1305},
|
||||
},
|
||||
"",
|
||||
},
|
||||
@@ -315,16 +315,16 @@ func TestUnsupportedAlgorithm(t *testing.T) {
|
||||
Config{
|
||||
MACs: []string{"unsupported"},
|
||||
// MAC is used for non AAED ciphers.
|
||||
Ciphers: []string{"aes256-ctr"},
|
||||
Ciphers: []string{CipherAES256CTR},
|
||||
},
|
||||
"no common algorithm",
|
||||
},
|
||||
{
|
||||
"unsupported and supported MACs",
|
||||
Config{
|
||||
MACs: []string{"unsupported", "hmac-sha2-256-etm@openssh.com"},
|
||||
MACs: []string{"unsupported", HMACSHA256ETM},
|
||||
// MAC is used for non AAED ciphers.
|
||||
Ciphers: []string{"aes256-ctr"},
|
||||
Ciphers: []string{CipherAES256CTR},
|
||||
},
|
||||
"",
|
||||
},
|
||||
|
||||
+307
-107
@@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
_ "crypto/sha1"
|
||||
@@ -24,69 +25,258 @@ const (
|
||||
serviceSSH = "ssh-connection"
|
||||
)
|
||||
|
||||
// supportedCiphers lists ciphers we support but might not recommend.
|
||||
var supportedCiphers = []string{
|
||||
"aes128-ctr", "aes192-ctr", "aes256-ctr",
|
||||
"aes128-gcm@openssh.com", gcm256CipherID,
|
||||
chacha20Poly1305ID,
|
||||
"arcfour256", "arcfour128", "arcfour",
|
||||
aes128cbcID,
|
||||
tripledescbcID,
|
||||
// The ciphers currently or previously implemented by this library, to use in
|
||||
// [Config.Ciphers]. For a list, see the [Algorithms.Ciphers] returned by
|
||||
// [SupportedAlgorithms] or [InsecureAlgorithms].
|
||||
const (
|
||||
CipherAES128GCM = "aes128-gcm@openssh.com"
|
||||
CipherAES256GCM = "aes256-gcm@openssh.com"
|
||||
CipherChaCha20Poly1305 = "chacha20-poly1305@openssh.com"
|
||||
CipherAES128CTR = "aes128-ctr"
|
||||
CipherAES192CTR = "aes192-ctr"
|
||||
CipherAES256CTR = "aes256-ctr"
|
||||
InsecureCipherAES128CBC = "aes128-cbc"
|
||||
InsecureCipherTripleDESCBC = "3des-cbc"
|
||||
InsecureCipherRC4 = "arcfour"
|
||||
InsecureCipherRC4128 = "arcfour128"
|
||||
InsecureCipherRC4256 = "arcfour256"
|
||||
)
|
||||
|
||||
// The key exchanges currently or previously implemented by this library, to use
|
||||
// in [Config.KeyExchanges]. For a list, see the
|
||||
// [Algorithms.KeyExchanges] returned by [SupportedAlgorithms] or
|
||||
// [InsecureAlgorithms].
|
||||
const (
|
||||
InsecureKeyExchangeDH1SHA1 = "diffie-hellman-group1-sha1"
|
||||
InsecureKeyExchangeDH14SHA1 = "diffie-hellman-group14-sha1"
|
||||
KeyExchangeDH14SHA256 = "diffie-hellman-group14-sha256"
|
||||
KeyExchangeDH16SHA512 = "diffie-hellman-group16-sha512"
|
||||
KeyExchangeECDHP256 = "ecdh-sha2-nistp256"
|
||||
KeyExchangeECDHP384 = "ecdh-sha2-nistp384"
|
||||
KeyExchangeECDHP521 = "ecdh-sha2-nistp521"
|
||||
KeyExchangeCurve25519 = "curve25519-sha256"
|
||||
InsecureKeyExchangeDHGEXSHA1 = "diffie-hellman-group-exchange-sha1"
|
||||
KeyExchangeDHGEXSHA256 = "diffie-hellman-group-exchange-sha256"
|
||||
// KeyExchangeMLKEM768X25519 is supported from Go 1.24.
|
||||
KeyExchangeMLKEM768X25519 = "mlkem768x25519-sha256"
|
||||
|
||||
// An alias for KeyExchangeCurve25519SHA256. This kex ID will be added if
|
||||
// KeyExchangeCurve25519SHA256 is requested for backward compatibility with
|
||||
// OpenSSH versions up to 7.2.
|
||||
keyExchangeCurve25519LibSSH = "curve25519-sha256@libssh.org"
|
||||
)
|
||||
|
||||
// The message authentication code (MAC) currently or previously implemented by
|
||||
// this library, to use in [Config.MACs]. For a list, see the
|
||||
// [Algorithms.MACs] returned by [SupportedAlgorithms] or
|
||||
// [InsecureAlgorithms].
|
||||
const (
|
||||
HMACSHA256ETM = "hmac-sha2-256-etm@openssh.com"
|
||||
HMACSHA512ETM = "hmac-sha2-512-etm@openssh.com"
|
||||
HMACSHA256 = "hmac-sha2-256"
|
||||
HMACSHA512 = "hmac-sha2-512"
|
||||
HMACSHA1 = "hmac-sha1"
|
||||
InsecureHMACSHA196 = "hmac-sha1-96"
|
||||
)
|
||||
|
||||
var (
|
||||
// supportedKexAlgos specifies key-exchange algorithms implemented by this
|
||||
// package in preference order, excluding those with security issues.
|
||||
supportedKexAlgos = []string{
|
||||
KeyExchangeCurve25519,
|
||||
KeyExchangeECDHP256,
|
||||
KeyExchangeECDHP384,
|
||||
KeyExchangeECDHP521,
|
||||
KeyExchangeDH14SHA256,
|
||||
KeyExchangeDH16SHA512,
|
||||
KeyExchangeDHGEXSHA256,
|
||||
}
|
||||
// defaultKexAlgos specifies the default preference for key-exchange
|
||||
// algorithms in preference order.
|
||||
defaultKexAlgos = []string{
|
||||
KeyExchangeCurve25519,
|
||||
KeyExchangeECDHP256,
|
||||
KeyExchangeECDHP384,
|
||||
KeyExchangeECDHP521,
|
||||
KeyExchangeDH14SHA256,
|
||||
InsecureKeyExchangeDH14SHA1,
|
||||
}
|
||||
// insecureKexAlgos specifies key-exchange algorithms implemented by this
|
||||
// package and which have security issues.
|
||||
insecureKexAlgos = []string{
|
||||
InsecureKeyExchangeDH14SHA1,
|
||||
InsecureKeyExchangeDH1SHA1,
|
||||
InsecureKeyExchangeDHGEXSHA1,
|
||||
}
|
||||
// supportedCiphers specifies cipher algorithms implemented by this package
|
||||
// in preference order, excluding those with security issues.
|
||||
supportedCiphers = []string{
|
||||
CipherAES128GCM,
|
||||
CipherAES256GCM,
|
||||
CipherChaCha20Poly1305,
|
||||
CipherAES128CTR,
|
||||
CipherAES192CTR,
|
||||
CipherAES256CTR,
|
||||
}
|
||||
// defaultCiphers specifies the default preference for ciphers algorithms
|
||||
// in preference order.
|
||||
defaultCiphers = supportedCiphers
|
||||
// insecureCiphers specifies cipher algorithms implemented by this
|
||||
// package and which have security issues.
|
||||
insecureCiphers = []string{
|
||||
InsecureCipherAES128CBC,
|
||||
InsecureCipherTripleDESCBC,
|
||||
InsecureCipherRC4256,
|
||||
InsecureCipherRC4128,
|
||||
InsecureCipherRC4,
|
||||
}
|
||||
// supportedMACs specifies MAC algorithms implemented by this package in
|
||||
// preference order, excluding those with security issues.
|
||||
supportedMACs = []string{
|
||||
HMACSHA256ETM,
|
||||
HMACSHA512ETM,
|
||||
HMACSHA256,
|
||||
HMACSHA512,
|
||||
HMACSHA1,
|
||||
}
|
||||
// defaultMACs specifies the default preference for MAC algorithms in
|
||||
// preference order.
|
||||
defaultMACs = []string{
|
||||
HMACSHA256ETM,
|
||||
HMACSHA512ETM,
|
||||
HMACSHA256,
|
||||
HMACSHA512,
|
||||
HMACSHA1,
|
||||
InsecureHMACSHA196,
|
||||
}
|
||||
// insecureMACs specifies MAC algorithms implemented by this
|
||||
// package and which have security issues.
|
||||
insecureMACs = []string{
|
||||
InsecureHMACSHA196,
|
||||
}
|
||||
// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e.
|
||||
// methods of authenticating servers) implemented by this package in
|
||||
// preference order, excluding those with security issues.
|
||||
supportedHostKeyAlgos = []string{
|
||||
CertAlgoRSASHA256v01,
|
||||
CertAlgoRSASHA512v01,
|
||||
CertAlgoECDSA256v01,
|
||||
CertAlgoECDSA384v01,
|
||||
CertAlgoECDSA521v01,
|
||||
CertAlgoED25519v01,
|
||||
KeyAlgoRSASHA256,
|
||||
KeyAlgoRSASHA512,
|
||||
KeyAlgoECDSA256,
|
||||
KeyAlgoECDSA384,
|
||||
KeyAlgoECDSA521,
|
||||
KeyAlgoED25519,
|
||||
}
|
||||
// defaultHostKeyAlgos specifies the default preference for host-key
|
||||
// algorithms in preference order.
|
||||
defaultHostKeyAlgos = []string{
|
||||
CertAlgoRSASHA256v01,
|
||||
CertAlgoRSASHA512v01,
|
||||
CertAlgoRSAv01,
|
||||
InsecureCertAlgoDSAv01,
|
||||
CertAlgoECDSA256v01,
|
||||
CertAlgoECDSA384v01,
|
||||
CertAlgoECDSA521v01,
|
||||
CertAlgoED25519v01,
|
||||
KeyAlgoECDSA256,
|
||||
KeyAlgoECDSA384,
|
||||
KeyAlgoECDSA521,
|
||||
KeyAlgoRSASHA256,
|
||||
KeyAlgoRSASHA512,
|
||||
KeyAlgoRSA,
|
||||
InsecureKeyAlgoDSA,
|
||||
KeyAlgoED25519,
|
||||
}
|
||||
// insecureHostKeyAlgos specifies host-key algorithms implemented by this
|
||||
// package and which have security issues.
|
||||
insecureHostKeyAlgos = []string{
|
||||
KeyAlgoRSA,
|
||||
InsecureKeyAlgoDSA,
|
||||
CertAlgoRSAv01,
|
||||
InsecureCertAlgoDSAv01,
|
||||
}
|
||||
// supportedPubKeyAuthAlgos specifies the supported client public key
|
||||
// authentication algorithms. Note that this doesn't include certificate
|
||||
// types since those use the underlying algorithm. Order is irrelevant.
|
||||
supportedPubKeyAuthAlgos = []string{
|
||||
KeyAlgoED25519,
|
||||
KeyAlgoSKED25519,
|
||||
KeyAlgoSKECDSA256,
|
||||
KeyAlgoECDSA256,
|
||||
KeyAlgoECDSA384,
|
||||
KeyAlgoECDSA521,
|
||||
KeyAlgoRSASHA256,
|
||||
KeyAlgoRSASHA512,
|
||||
}
|
||||
|
||||
// defaultPubKeyAuthAlgos specifies the preferred client public key
|
||||
// authentication algorithms. This list is sent to the client if it supports
|
||||
// the server-sig-algs extension. Order is irrelevant.
|
||||
defaultPubKeyAuthAlgos = []string{
|
||||
KeyAlgoED25519,
|
||||
KeyAlgoSKED25519,
|
||||
KeyAlgoSKECDSA256,
|
||||
KeyAlgoECDSA256,
|
||||
KeyAlgoECDSA384,
|
||||
KeyAlgoECDSA521,
|
||||
KeyAlgoRSASHA256,
|
||||
KeyAlgoRSASHA512,
|
||||
KeyAlgoRSA,
|
||||
InsecureKeyAlgoDSA,
|
||||
}
|
||||
// insecurePubKeyAuthAlgos specifies client public key authentication
|
||||
// algorithms implemented by this package and which have security issues.
|
||||
insecurePubKeyAuthAlgos = []string{
|
||||
KeyAlgoRSA,
|
||||
InsecureKeyAlgoDSA,
|
||||
}
|
||||
)
|
||||
|
||||
// NegotiatedAlgorithms defines algorithms negotiated between client and server.
|
||||
type NegotiatedAlgorithms struct {
|
||||
KeyExchange string
|
||||
HostKey string
|
||||
Read DirectionAlgorithms
|
||||
Write DirectionAlgorithms
|
||||
}
|
||||
|
||||
// preferredCiphers specifies the default preference for ciphers.
|
||||
var preferredCiphers = []string{
|
||||
"aes128-gcm@openssh.com", gcm256CipherID,
|
||||
chacha20Poly1305ID,
|
||||
"aes128-ctr", "aes192-ctr", "aes256-ctr",
|
||||
// Algorithms defines a set of algorithms that can be configured in the client
|
||||
// or server config for negotiation during a handshake.
|
||||
type Algorithms struct {
|
||||
KeyExchanges []string
|
||||
Ciphers []string
|
||||
MACs []string
|
||||
HostKeys []string
|
||||
PublicKeyAuths []string
|
||||
}
|
||||
|
||||
// supportedKexAlgos specifies the supported key-exchange algorithms in
|
||||
// preference order.
|
||||
var supportedKexAlgos = []string{
|
||||
kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH,
|
||||
// P384 and P521 are not constant-time yet, but since we don't
|
||||
// reuse ephemeral keys, using them for ECDH should be OK.
|
||||
kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
|
||||
kexAlgoDH14SHA256, kexAlgoDH16SHA512, kexAlgoDH14SHA1,
|
||||
kexAlgoDH1SHA1,
|
||||
// SupportedAlgorithms returns algorithms currently implemented by this package,
|
||||
// excluding those with security issues, which are returned by
|
||||
// InsecureAlgorithms. The algorithms listed here are in preference order.
|
||||
func SupportedAlgorithms() Algorithms {
|
||||
return Algorithms{
|
||||
Ciphers: slices.Clone(supportedCiphers),
|
||||
MACs: slices.Clone(supportedMACs),
|
||||
KeyExchanges: slices.Clone(supportedKexAlgos),
|
||||
HostKeys: slices.Clone(supportedHostKeyAlgos),
|
||||
PublicKeyAuths: slices.Clone(supportedPubKeyAuthAlgos),
|
||||
}
|
||||
}
|
||||
|
||||
// serverForbiddenKexAlgos contains key exchange algorithms, that are forbidden
|
||||
// for the server half.
|
||||
var serverForbiddenKexAlgos = map[string]struct{}{
|
||||
kexAlgoDHGEXSHA1: {}, // server half implementation is only minimal to satisfy the automated tests
|
||||
kexAlgoDHGEXSHA256: {}, // server half implementation is only minimal to satisfy the automated tests
|
||||
}
|
||||
|
||||
// preferredKexAlgos specifies the default preference for key-exchange
|
||||
// algorithms in preference order. The diffie-hellman-group16-sha512 algorithm
|
||||
// is disabled by default because it is a bit slower than the others.
|
||||
var preferredKexAlgos = []string{
|
||||
kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH,
|
||||
kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
|
||||
kexAlgoDH14SHA256, kexAlgoDH14SHA1,
|
||||
}
|
||||
|
||||
// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods
|
||||
// of authenticating servers) in preference order.
|
||||
var supportedHostKeyAlgos = []string{
|
||||
CertAlgoRSASHA256v01, CertAlgoRSASHA512v01,
|
||||
CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01,
|
||||
CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01,
|
||||
|
||||
KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
|
||||
KeyAlgoRSASHA256, KeyAlgoRSASHA512,
|
||||
KeyAlgoRSA, KeyAlgoDSA,
|
||||
|
||||
KeyAlgoED25519,
|
||||
}
|
||||
|
||||
// supportedMACs specifies a default set of MAC algorithms in preference order.
|
||||
// This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed
|
||||
// because they have reached the end of their useful life.
|
||||
var supportedMACs = []string{
|
||||
"hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", "hmac-sha1-96",
|
||||
// InsecureAlgorithms returns algorithms currently implemented by this package
|
||||
// and which have security issues.
|
||||
func InsecureAlgorithms() Algorithms {
|
||||
return Algorithms{
|
||||
KeyExchanges: slices.Clone(insecureKexAlgos),
|
||||
Ciphers: slices.Clone(insecureCiphers),
|
||||
MACs: slices.Clone(insecureMACs),
|
||||
HostKeys: slices.Clone(insecureHostKeyAlgos),
|
||||
PublicKeyAuths: slices.Clone(insecurePubKeyAuthAlgos),
|
||||
}
|
||||
}
|
||||
|
||||
var supportedCompressions = []string{compressionNone}
|
||||
@@ -94,13 +284,13 @@ var supportedCompressions = []string{compressionNone}
|
||||
// hashFuncs keeps the mapping of supported signature algorithms to their
|
||||
// respective hashes needed for signing and verification.
|
||||
var hashFuncs = map[string]crypto.Hash{
|
||||
KeyAlgoRSA: crypto.SHA1,
|
||||
KeyAlgoRSASHA256: crypto.SHA256,
|
||||
KeyAlgoRSASHA512: crypto.SHA512,
|
||||
KeyAlgoDSA: crypto.SHA1,
|
||||
KeyAlgoECDSA256: crypto.SHA256,
|
||||
KeyAlgoECDSA384: crypto.SHA384,
|
||||
KeyAlgoECDSA521: crypto.SHA512,
|
||||
KeyAlgoRSA: crypto.SHA1,
|
||||
KeyAlgoRSASHA256: crypto.SHA256,
|
||||
KeyAlgoRSASHA512: crypto.SHA512,
|
||||
InsecureKeyAlgoDSA: crypto.SHA1,
|
||||
KeyAlgoECDSA256: crypto.SHA256,
|
||||
KeyAlgoECDSA384: crypto.SHA384,
|
||||
KeyAlgoECDSA521: crypto.SHA512,
|
||||
// KeyAlgoED25519 doesn't pre-hash.
|
||||
KeyAlgoSKECDSA256: crypto.SHA256,
|
||||
KeyAlgoSKED25519: crypto.SHA256,
|
||||
@@ -135,18 +325,6 @@ func isRSACert(algo string) bool {
|
||||
return isRSA(algo)
|
||||
}
|
||||
|
||||
// supportedPubKeyAuthAlgos specifies the supported client public key
|
||||
// authentication algorithms. Note that this doesn't include certificate types
|
||||
// since those use the underlying algorithm. This list is sent to the client if
|
||||
// it supports the server-sig-algs extension. Order is irrelevant.
|
||||
var supportedPubKeyAuthAlgos = []string{
|
||||
KeyAlgoED25519,
|
||||
KeyAlgoSKED25519, KeyAlgoSKECDSA256,
|
||||
KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
|
||||
KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA,
|
||||
KeyAlgoDSA,
|
||||
}
|
||||
|
||||
// unexpectedMessageError results when the SSH message that we received didn't
|
||||
// match what we wanted.
|
||||
func unexpectedMessageError(expected, got uint8) error {
|
||||
@@ -158,7 +336,7 @@ func parseError(tag uint8) error {
|
||||
return fmt.Errorf("ssh: parse error in message type %d", tag)
|
||||
}
|
||||
|
||||
func findCommon(what string, client []string, server []string) (common string, err error) {
|
||||
func findCommon(what string, client []string, server []string, isClient bool) (string, error) {
|
||||
for _, c := range client {
|
||||
for _, s := range server {
|
||||
if c == s {
|
||||
@@ -166,23 +344,49 @@ func findCommon(what string, client []string, server []string) (common string, e
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server)
|
||||
err := &AlgorithmNegotiationError{
|
||||
What: what,
|
||||
}
|
||||
if isClient {
|
||||
err.SupportedAlgorithms = client
|
||||
err.RequestedAlgorithms = server
|
||||
} else {
|
||||
err.SupportedAlgorithms = server
|
||||
err.RequestedAlgorithms = client
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
// directionAlgorithms records algorithm choices in one direction (either read or write)
|
||||
type directionAlgorithms struct {
|
||||
// AlgorithmNegotiationError defines the error returned if the client and the
|
||||
// server cannot agree on an algorithm for key exchange, host key, cipher, MAC.
|
||||
type AlgorithmNegotiationError struct {
|
||||
What string
|
||||
// RequestedAlgorithms lists the algorithms supported by the peer.
|
||||
RequestedAlgorithms []string
|
||||
// SupportedAlgorithms lists the algorithms supported on our side.
|
||||
SupportedAlgorithms []string
|
||||
}
|
||||
|
||||
func (a *AlgorithmNegotiationError) Error() string {
|
||||
return fmt.Sprintf("ssh: no common algorithm for %s; we offered: %v, peer offered: %v",
|
||||
a.What, a.SupportedAlgorithms, a.RequestedAlgorithms)
|
||||
}
|
||||
|
||||
// DirectionAlgorithms defines the algorithms negotiated in one direction
|
||||
// (either read or write).
|
||||
type DirectionAlgorithms struct {
|
||||
Cipher string
|
||||
MAC string
|
||||
Compression string
|
||||
compression string
|
||||
}
|
||||
|
||||
// rekeyBytes returns a rekeying intervals in bytes.
|
||||
func (a *directionAlgorithms) rekeyBytes() int64 {
|
||||
func (a *DirectionAlgorithms) rekeyBytes() int64 {
|
||||
// According to RFC 4344 block ciphers should rekey after
|
||||
// 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is
|
||||
// 128.
|
||||
switch a.Cipher {
|
||||
case "aes128-ctr", "aes192-ctr", "aes256-ctr", gcm128CipherID, gcm256CipherID, aes128cbcID:
|
||||
case CipherAES128CTR, CipherAES192CTR, CipherAES256CTR, CipherAES128GCM, CipherAES256GCM, InsecureCipherAES128CBC:
|
||||
return 16 * (1 << 32)
|
||||
|
||||
}
|
||||
@@ -192,66 +396,59 @@ func (a *directionAlgorithms) rekeyBytes() int64 {
|
||||
}
|
||||
|
||||
var aeadCiphers = map[string]bool{
|
||||
gcm128CipherID: true,
|
||||
gcm256CipherID: true,
|
||||
chacha20Poly1305ID: true,
|
||||
CipherAES128GCM: true,
|
||||
CipherAES256GCM: true,
|
||||
CipherChaCha20Poly1305: true,
|
||||
}
|
||||
|
||||
type algorithms struct {
|
||||
kex string
|
||||
hostKey string
|
||||
w directionAlgorithms
|
||||
r directionAlgorithms
|
||||
}
|
||||
func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *NegotiatedAlgorithms, err error) {
|
||||
result := &NegotiatedAlgorithms{}
|
||||
|
||||
func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) {
|
||||
result := &algorithms{}
|
||||
|
||||
result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos)
|
||||
result.KeyExchange, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos, isClient)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result.hostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos)
|
||||
result.HostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos, isClient)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
stoc, ctos := &result.w, &result.r
|
||||
stoc, ctos := &result.Write, &result.Read
|
||||
if isClient {
|
||||
ctos, stoc = stoc, ctos
|
||||
}
|
||||
|
||||
ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
|
||||
ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer, isClient)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
|
||||
stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient, isClient)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !aeadCiphers[ctos.Cipher] {
|
||||
ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
|
||||
ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer, isClient)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !aeadCiphers[stoc.Cipher] {
|
||||
stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
|
||||
stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient, isClient)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctos.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
|
||||
ctos.compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer, isClient)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
stoc.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
|
||||
stoc.compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient, isClient)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -297,7 +494,7 @@ func (c *Config) SetDefaults() {
|
||||
c.Rand = rand.Reader
|
||||
}
|
||||
if c.Ciphers == nil {
|
||||
c.Ciphers = preferredCiphers
|
||||
c.Ciphers = defaultCiphers
|
||||
}
|
||||
var ciphers []string
|
||||
for _, c := range c.Ciphers {
|
||||
@@ -309,19 +506,22 @@ func (c *Config) SetDefaults() {
|
||||
c.Ciphers = ciphers
|
||||
|
||||
if c.KeyExchanges == nil {
|
||||
c.KeyExchanges = preferredKexAlgos
|
||||
c.KeyExchanges = defaultKexAlgos
|
||||
}
|
||||
var kexs []string
|
||||
for _, k := range c.KeyExchanges {
|
||||
if kexAlgoMap[k] != nil {
|
||||
// Ignore the KEX if we have no kexAlgoMap definition.
|
||||
kexs = append(kexs, k)
|
||||
if k == KeyExchangeCurve25519 && !contains(c.KeyExchanges, keyExchangeCurve25519LibSSH) {
|
||||
kexs = append(kexs, keyExchangeCurve25519LibSSH)
|
||||
}
|
||||
}
|
||||
}
|
||||
c.KeyExchanges = kexs
|
||||
|
||||
if c.MACs == nil {
|
||||
c.MACs = supportedMACs
|
||||
c.MACs = defaultMACs
|
||||
}
|
||||
var macs []string
|
||||
for _, m := range c.MACs {
|
||||
|
||||
+17
-17
@@ -51,33 +51,33 @@ func TestFindAgreedAlgorithms(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
initDirAlgs := func(a *directionAlgorithms) {
|
||||
initDirAlgs := func(a *DirectionAlgorithms) {
|
||||
if a.Cipher == "" {
|
||||
a.Cipher = "cipher1"
|
||||
}
|
||||
if a.MAC == "" {
|
||||
a.MAC = "mac1"
|
||||
}
|
||||
if a.Compression == "" {
|
||||
a.Compression = "compression1"
|
||||
if a.compression == "" {
|
||||
a.compression = "compression1"
|
||||
}
|
||||
}
|
||||
|
||||
initAlgs := func(a *algorithms) {
|
||||
if a.kex == "" {
|
||||
a.kex = "kex1"
|
||||
initAlgs := func(a *NegotiatedAlgorithms) {
|
||||
if a.KeyExchange == "" {
|
||||
a.KeyExchange = "kex1"
|
||||
}
|
||||
if a.hostKey == "" {
|
||||
a.hostKey = "hostkey1"
|
||||
if a.HostKey == "" {
|
||||
a.HostKey = "hostkey1"
|
||||
}
|
||||
initDirAlgs(&a.r)
|
||||
initDirAlgs(&a.w)
|
||||
initDirAlgs(&a.Read)
|
||||
initDirAlgs(&a.Write)
|
||||
}
|
||||
|
||||
type testcase struct {
|
||||
name string
|
||||
clientIn, serverIn kexInitMsg
|
||||
wantClient, wantServer algorithms
|
||||
wantClient, wantServer NegotiatedAlgorithms
|
||||
wantErr bool
|
||||
}
|
||||
|
||||
@@ -120,19 +120,19 @@ func TestFindAgreedAlgorithms(t *testing.T) {
|
||||
CiphersClientServer: []string{"cipher2", "cipher1"},
|
||||
CiphersServerClient: []string{"cipher3", "cipher2"},
|
||||
},
|
||||
wantClient: algorithms{
|
||||
r: directionAlgorithms{
|
||||
wantClient: NegotiatedAlgorithms{
|
||||
Read: DirectionAlgorithms{
|
||||
Cipher: "cipher3",
|
||||
},
|
||||
w: directionAlgorithms{
|
||||
Write: DirectionAlgorithms{
|
||||
Cipher: "cipher2",
|
||||
},
|
||||
},
|
||||
wantServer: algorithms{
|
||||
w: directionAlgorithms{
|
||||
wantServer: NegotiatedAlgorithms{
|
||||
Write: DirectionAlgorithms{
|
||||
Cipher: "cipher3",
|
||||
},
|
||||
r: directionAlgorithms{
|
||||
Read: DirectionAlgorithms{
|
||||
Cipher: "cipher2",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -74,6 +74,13 @@ type Conn interface {
|
||||
// Disconnect
|
||||
}
|
||||
|
||||
// AlgorithmsConnMetadata is a ConnMetadata that can return the algorithms
|
||||
// negotiated between client and server.
|
||||
type AlgorithmsConnMetadata interface {
|
||||
ConnMetadata
|
||||
Algorithms() NegotiatedAlgorithms
|
||||
}
|
||||
|
||||
// DiscardRequests consumes and rejects all requests from the
|
||||
// passed-in channel.
|
||||
func DiscardRequests(in <-chan *Request) {
|
||||
@@ -106,6 +113,7 @@ type sshConn struct {
|
||||
sessionID []byte
|
||||
clientVersion []byte
|
||||
serverVersion []byte
|
||||
algorithms NegotiatedAlgorithms
|
||||
}
|
||||
|
||||
func dup(src []byte) []byte {
|
||||
@@ -141,3 +149,7 @@ func (c *sshConn) ClientVersion() []byte {
|
||||
func (c *sshConn) ServerVersion() []byte {
|
||||
return dup(c.serverVersion)
|
||||
}
|
||||
|
||||
func (c *sshConn) Algorithms() NegotiatedAlgorithms {
|
||||
return c.algorithms
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ References:
|
||||
[PROTOCOL]: https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL?rev=HEAD
|
||||
[PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
|
||||
[SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1
|
||||
[SSH-CERTS]: https://datatracker.ietf.org/doc/html/draft-miller-ssh-cert-01
|
||||
|
||||
This package does not fall under the stability promise of the Go language itself,
|
||||
so its API may be changed when pressing needs arise.
|
||||
|
||||
@@ -154,6 +154,75 @@ func ExampleNewServerConn() {
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleServerConfig() {
|
||||
// Minimal ServerConfig with SHA-1 algoritms disabled and supporting only
|
||||
// public key authentication.
|
||||
|
||||
// The algorithms returned by ssh.SupportedAlgorithms() are different from
|
||||
// the default ones and do not include algorithms that are considered
|
||||
// insecure, such as those using SHA-1, returned by
|
||||
// ssh.InsecureAlgorithms().
|
||||
algorithms := ssh.SupportedAlgorithms()
|
||||
|
||||
// Public key authentication is done by comparing
|
||||
// the public key of a received connection
|
||||
// with the entries in the authorized_keys file.
|
||||
authorizedKeysBytes, err := os.ReadFile("authorized_keys")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load authorized_keys, err: %v", err)
|
||||
}
|
||||
|
||||
authorizedKeysMap := map[string]bool{}
|
||||
for len(authorizedKeysBytes) > 0 {
|
||||
pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
authorizedKeysMap[string(pubKey.Marshal())] = true
|
||||
authorizedKeysBytes = rest
|
||||
}
|
||||
|
||||
config := &ssh.ServerConfig{
|
||||
Config: ssh.Config{
|
||||
KeyExchanges: algorithms.KeyExchanges,
|
||||
Ciphers: algorithms.Ciphers,
|
||||
MACs: algorithms.MACs,
|
||||
},
|
||||
// The configured PublicKeyAuthAlgorithms do not contain SHA-1 based
|
||||
// signature formats, so if the client attempts to use them the
|
||||
// authentication will fail before calling the defined callback.
|
||||
PublicKeyAuthAlgorithms: algorithms.PublicKeyAuths,
|
||||
PublicKeyCallback: func(c ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
|
||||
if authorizedKeysMap[string(pubKey.Marshal())] {
|
||||
return &ssh.Permissions{
|
||||
// Record the public key used for authentication.
|
||||
Extensions: map[string]string{
|
||||
"pubkey-fp": ssh.FingerprintSHA256(pubKey),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown public key for %q", c.User())
|
||||
},
|
||||
}
|
||||
|
||||
privateBytes, err := os.ReadFile("id_rsa")
|
||||
if err != nil {
|
||||
log.Fatal("Failed to load private key: ", err)
|
||||
}
|
||||
|
||||
private, err := ssh.ParsePrivateKey(privateBytes)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to parse private key: ", err)
|
||||
}
|
||||
// Restrict host key algorithms to disable ssh-rsa.
|
||||
signer, err := ssh.NewSignerWithAlgorithms(private.(ssh.AlgorithmSigner), []string{ssh.KeyAlgoRSASHA256, ssh.KeyAlgoRSASHA512})
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create private key with restricted algorithms: ", err)
|
||||
}
|
||||
config.AddHostKey(signer)
|
||||
}
|
||||
|
||||
func ExampleServerConfig_AddHostKey() {
|
||||
// Minimal ServerConfig supporting only password authentication.
|
||||
config := &ssh.ServerConfig{
|
||||
@@ -262,6 +331,47 @@ func ExampleDial() {
|
||||
fmt.Println(b.String())
|
||||
}
|
||||
|
||||
func ExampleClientConfig() {
|
||||
var hostKey ssh.PublicKey
|
||||
key, err := os.ReadFile("/home/user/.ssh/id_rsa")
|
||||
if err != nil {
|
||||
log.Fatalf("unable to read private key: %v", err)
|
||||
}
|
||||
|
||||
// Create the Signer for this private key.
|
||||
signer, err := ssh.ParsePrivateKey(key)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to parse private key: %v", err)
|
||||
}
|
||||
|
||||
// Minimal ClientConfig with SHA-1 algoritms disabled.
|
||||
// The algorithms returned by ssh.SupportedAlgorithms() are different from
|
||||
// the default ones and do not include algorithms that are considered
|
||||
// insecure, such as those using SHA-1, returned by
|
||||
// ssh.InsecureAlgorithms().
|
||||
algorithms := ssh.SupportedAlgorithms()
|
||||
config := &ssh.ClientConfig{
|
||||
Config: ssh.Config{
|
||||
KeyExchanges: algorithms.KeyExchanges,
|
||||
Ciphers: algorithms.Ciphers,
|
||||
MACs: algorithms.MACs,
|
||||
},
|
||||
User: "username",
|
||||
Auth: []ssh.AuthMethod{
|
||||
ssh.PublicKeys(signer),
|
||||
},
|
||||
HostKeyCallback: ssh.FixedHostKey(hostKey),
|
||||
// We should check that hostKey algorithm is inlcuded in
|
||||
// algorithms.HostKeys.
|
||||
HostKeyAlgorithms: algorithms.HostKeys,
|
||||
}
|
||||
client, err := ssh.Dial("tcp", "yourserver.com:22", config)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to dial: ", err)
|
||||
}
|
||||
defer client.Close()
|
||||
}
|
||||
|
||||
func ExamplePublicKeys() {
|
||||
var hostKey ssh.PublicKey
|
||||
// A public key may be used to authenticate against the remote
|
||||
|
||||
+14
-10
@@ -38,7 +38,7 @@ type keyingTransport interface {
|
||||
// prepareKeyChange sets up a key change. The key change for a
|
||||
// direction will be effected if a msgNewKeys message is sent
|
||||
// or received.
|
||||
prepareKeyChange(*algorithms, *kexResult) error
|
||||
prepareKeyChange(*NegotiatedAlgorithms, *kexResult) error
|
||||
|
||||
// setStrictMode sets the strict KEX mode, notably triggering
|
||||
// sequence number resets on sending or receiving msgNewKeys.
|
||||
@@ -115,7 +115,7 @@ type handshakeTransport struct {
|
||||
bannerCallback BannerCallback
|
||||
|
||||
// Algorithms agreed in the last key exchange.
|
||||
algorithms *algorithms
|
||||
algorithms *NegotiatedAlgorithms
|
||||
|
||||
// Counters exclusively owned by readLoop.
|
||||
readPacketsLeft uint32
|
||||
@@ -164,7 +164,7 @@ func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byt
|
||||
if config.HostKeyAlgorithms != nil {
|
||||
t.hostKeyAlgorithms = config.HostKeyAlgorithms
|
||||
} else {
|
||||
t.hostKeyAlgorithms = supportedHostKeyAlgos
|
||||
t.hostKeyAlgorithms = defaultHostKeyAlgos
|
||||
}
|
||||
go t.readLoop()
|
||||
go t.kexLoop()
|
||||
@@ -184,6 +184,10 @@ func (t *handshakeTransport) getSessionID() []byte {
|
||||
return t.sessionID
|
||||
}
|
||||
|
||||
func (t *handshakeTransport) getAlgorithms() NegotiatedAlgorithms {
|
||||
return *t.algorithms
|
||||
}
|
||||
|
||||
// waitSession waits for the session to be established. This should be
|
||||
// the first thing to call after instantiating handshakeTransport.
|
||||
func (t *handshakeTransport) waitSession() error {
|
||||
@@ -290,7 +294,7 @@ func (t *handshakeTransport) resetWriteThresholds() {
|
||||
if t.config.RekeyThreshold > 0 {
|
||||
t.writeBytesLeft = int64(t.config.RekeyThreshold)
|
||||
} else if t.algorithms != nil {
|
||||
t.writeBytesLeft = t.algorithms.w.rekeyBytes()
|
||||
t.writeBytesLeft = t.algorithms.Write.rekeyBytes()
|
||||
} else {
|
||||
t.writeBytesLeft = 1 << 30
|
||||
}
|
||||
@@ -407,7 +411,7 @@ func (t *handshakeTransport) resetReadThresholds() {
|
||||
if t.config.RekeyThreshold > 0 {
|
||||
t.readBytesLeft = int64(t.config.RekeyThreshold)
|
||||
} else if t.algorithms != nil {
|
||||
t.readBytesLeft = t.algorithms.r.rekeyBytes()
|
||||
t.readBytesLeft = t.algorithms.Read.rekeyBytes()
|
||||
} else {
|
||||
t.readBytesLeft = 1 << 30
|
||||
}
|
||||
@@ -700,9 +704,9 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
|
||||
}
|
||||
}
|
||||
|
||||
kex, ok := kexAlgoMap[t.algorithms.kex]
|
||||
kex, ok := kexAlgoMap[t.algorithms.KeyExchange]
|
||||
if !ok {
|
||||
return fmt.Errorf("ssh: unexpected key exchange algorithm %v", t.algorithms.kex)
|
||||
return fmt.Errorf("ssh: unexpected key exchange algorithm %v", t.algorithms.KeyExchange)
|
||||
}
|
||||
|
||||
var result *kexResult
|
||||
@@ -809,12 +813,12 @@ func pickHostKey(hostKeys []Signer, algo string) AlgorithmSigner {
|
||||
}
|
||||
|
||||
func (t *handshakeTransport) server(kex kexAlgorithm, magics *handshakeMagics) (*kexResult, error) {
|
||||
hostKey := pickHostKey(t.hostKeys, t.algorithms.hostKey)
|
||||
hostKey := pickHostKey(t.hostKeys, t.algorithms.HostKey)
|
||||
if hostKey == nil {
|
||||
return nil, errors.New("ssh: internal error: negotiated unsupported signature type")
|
||||
}
|
||||
|
||||
r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey, t.algorithms.hostKey)
|
||||
r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey, t.algorithms.HostKey)
|
||||
return r, err
|
||||
}
|
||||
|
||||
@@ -829,7 +833,7 @@ func (t *handshakeTransport) client(kex kexAlgorithm, magics *handshakeMagics) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := verifyHostKeySignature(hostKey, t.algorithms.hostKey, result); err != nil {
|
||||
if err := verifyHostKeySignature(hostKey, t.algorithms.HostKey, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
+129
-4
@@ -367,7 +367,7 @@ type errorKeyingTransport struct {
|
||||
readLeft, writeLeft int
|
||||
}
|
||||
|
||||
func (n *errorKeyingTransport) prepareKeyChange(*algorithms, *kexResult) error {
|
||||
func (n *errorKeyingTransport) prepareKeyChange(*NegotiatedAlgorithms, *kexResult) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -545,7 +545,7 @@ type mockKeyingTransport struct {
|
||||
kexInitSent chan struct{}
|
||||
}
|
||||
|
||||
func (n *mockKeyingTransport) prepareKeyChange(*algorithms, *kexResult) error {
|
||||
func (n *mockKeyingTransport) prepareKeyChange(*NegotiatedAlgorithms, *kexResult) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -762,7 +762,7 @@ func TestHandshakePendingPacketsError(t *testing.T) {
|
||||
func TestHandshakeRekeyDefault(t *testing.T) {
|
||||
clientConf := &ClientConfig{
|
||||
Config: Config{
|
||||
Ciphers: []string{"aes128-ctr"},
|
||||
Ciphers: []string{CipherAES128CTR},
|
||||
},
|
||||
HostKeyCallback: InsecureIgnoreHostKey(),
|
||||
}
|
||||
@@ -788,7 +788,7 @@ func TestHandshakeRekeyDefault(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHandshakeAEADCipherNoMAC(t *testing.T) {
|
||||
for _, cipher := range []string{chacha20Poly1305ID, gcm128CipherID} {
|
||||
for _, cipher := range []string{CipherChaCha20Poly1305, CipherAES128GCM} {
|
||||
checker := &syncChecker{
|
||||
called: make(chan int, 1),
|
||||
}
|
||||
@@ -1239,3 +1239,128 @@ func TestStrictKEXMixed(t *testing.T) {
|
||||
t.Fatalf("client.waitSession: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNegotiatedAlgorithms(t *testing.T) {
|
||||
c1, c2, err := netPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("netPipe: %v", err)
|
||||
}
|
||||
defer c1.Close()
|
||||
defer c2.Close()
|
||||
|
||||
var serverAlgorithms NegotiatedAlgorithms
|
||||
|
||||
serverConf := &ServerConfig{
|
||||
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
|
||||
if algorithmConn, ok := conn.(AlgorithmsConnMetadata); ok {
|
||||
serverAlgorithms = algorithmConn.Algorithms()
|
||||
return &Permissions{}, nil
|
||||
}
|
||||
return nil, errors.New("server conn does not implement AlgorithmsConnMetadata")
|
||||
},
|
||||
}
|
||||
serverConf.AddHostKey(testSigners["rsa"])
|
||||
go NewServerConn(c1, serverConf)
|
||||
|
||||
clientConf := &ClientConfig{
|
||||
User: "test",
|
||||
Auth: []AuthMethod{Password("testpw")},
|
||||
HostKeyCallback: FixedHostKey(testSigners["rsa"].PublicKey()),
|
||||
}
|
||||
|
||||
if conn, _, _, err := NewClientConn(c2, "", clientConf); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if algorithmConn, ok := conn.(AlgorithmsConnMetadata); ok {
|
||||
clientAlgorithms := algorithmConn.Algorithms()
|
||||
if clientAlgorithms.HostKey == "" {
|
||||
t.Fatal("negotiated client host key is empty")
|
||||
}
|
||||
if clientAlgorithms.KeyExchange == "" {
|
||||
t.Fatal("negotiated client KEX is empty")
|
||||
}
|
||||
if clientAlgorithms.Read.Cipher == "" {
|
||||
t.Fatal("negotiated client read cipher is empty")
|
||||
}
|
||||
if clientAlgorithms.Write.Cipher == "" {
|
||||
t.Fatal("negotiated client write cipher is empty")
|
||||
}
|
||||
if !reflect.DeepEqual(clientAlgorithms, serverAlgorithms) {
|
||||
t.Fatalf("negotiated client algorithms: %+v differs from negotiated server algorithms: %+v",
|
||||
clientAlgorithms, serverAlgorithms)
|
||||
}
|
||||
} else {
|
||||
t.Fatal("client conn does not implement AlgorithmsConnMetadata")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlgorithmNegotiationError(t *testing.T) {
|
||||
c1, c2, err := netPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("netPipe: %v", err)
|
||||
}
|
||||
defer c1.Close()
|
||||
defer c2.Close()
|
||||
|
||||
serverConf := &ServerConfig{
|
||||
Config: Config{
|
||||
Ciphers: []string{CipherAES128CTR, CipherAES256CTR},
|
||||
},
|
||||
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
|
||||
return &Permissions{}, nil
|
||||
},
|
||||
}
|
||||
serverConf.AddHostKey(testSigners["rsa"])
|
||||
|
||||
srvErrCh := make(chan error, 1)
|
||||
go func() {
|
||||
_, _, _, err := NewServerConn(c1, serverConf)
|
||||
srvErrCh <- err
|
||||
}()
|
||||
|
||||
clientConf := &ClientConfig{
|
||||
Config: Config{
|
||||
Ciphers: []string{CipherAES128GCM, CipherAES256GCM},
|
||||
},
|
||||
User: "test",
|
||||
Auth: []AuthMethod{Password("testpw")},
|
||||
HostKeyCallback: FixedHostKey(testSigners["rsa"].PublicKey()),
|
||||
}
|
||||
|
||||
_, _, _, err = NewClientConn(c2, "", clientConf)
|
||||
if err == nil {
|
||||
t.Fatal("client connection succeded expected algorithm negotiation error")
|
||||
}
|
||||
var negotiationError *AlgorithmNegotiationError
|
||||
if !errors.As(err, &negotiationError) {
|
||||
t.Fatalf("expected algorithm negotiation error, got %v", err)
|
||||
}
|
||||
expectedErrorString := fmt.Sprintf("ssh: handshake failed: ssh: no common algorithm for client to server cipher; we offered: %v, peer offered: %v",
|
||||
clientConf.Ciphers, serverConf.Ciphers)
|
||||
if err.Error() != expectedErrorString {
|
||||
t.Fatalf("expected error string %q, got %q", expectedErrorString, err.Error())
|
||||
}
|
||||
if !reflect.DeepEqual(negotiationError.RequestedAlgorithms, serverConf.Ciphers) {
|
||||
t.Fatalf("expected requested algorithms %v, got %v", serverConf.Ciphers, negotiationError.RequestedAlgorithms)
|
||||
}
|
||||
if !reflect.DeepEqual(negotiationError.SupportedAlgorithms, clientConf.Ciphers) {
|
||||
t.Fatalf("expected supported algorithms %v, got %v", clientConf.Ciphers, negotiationError.SupportedAlgorithms)
|
||||
}
|
||||
err = <-srvErrCh
|
||||
negotiationError = nil
|
||||
if !errors.As(err, &negotiationError) {
|
||||
t.Fatalf("expected algorithm negotiation error, got %v", err)
|
||||
}
|
||||
expectedErrorString = fmt.Sprintf("ssh: no common algorithm for client to server cipher; we offered: %v, peer offered: %v",
|
||||
serverConf.Ciphers, clientConf.Ciphers)
|
||||
if err.Error() != expectedErrorString {
|
||||
t.Fatalf("expected error string %q, got %q", expectedErrorString, err.Error())
|
||||
}
|
||||
if !reflect.DeepEqual(negotiationError.RequestedAlgorithms, clientConf.Ciphers) {
|
||||
t.Fatalf("expected requested algorithms %v, got %v", clientConf.Ciphers, negotiationError.RequestedAlgorithms)
|
||||
}
|
||||
if !reflect.DeepEqual(negotiationError.SupportedAlgorithms, serverConf.Ciphers) {
|
||||
t.Fatalf("expected supported algorithms %v, got %v", serverConf.Ciphers, negotiationError.SupportedAlgorithms)
|
||||
}
|
||||
}
|
||||
|
||||
+57
-50
@@ -20,21 +20,18 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
|
||||
kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
|
||||
kexAlgoDH14SHA256 = "diffie-hellman-group14-sha256"
|
||||
kexAlgoDH16SHA512 = "diffie-hellman-group16-sha512"
|
||||
kexAlgoECDH256 = "ecdh-sha2-nistp256"
|
||||
kexAlgoECDH384 = "ecdh-sha2-nistp384"
|
||||
kexAlgoECDH521 = "ecdh-sha2-nistp521"
|
||||
kexAlgoCurve25519SHA256LibSSH = "curve25519-sha256@libssh.org"
|
||||
kexAlgoCurve25519SHA256 = "curve25519-sha256"
|
||||
|
||||
// For the following kex only the client half contains a production
|
||||
// ready implementation. The server half only consists of a minimal
|
||||
// implementation to satisfy the automated tests.
|
||||
kexAlgoDHGEXSHA1 = "diffie-hellman-group-exchange-sha1"
|
||||
kexAlgoDHGEXSHA256 = "diffie-hellman-group-exchange-sha256"
|
||||
// This is the group called diffie-hellman-group1-sha1 in RFC 4253 and
|
||||
// Oakley Group 2 in RFC 2409.
|
||||
oakleyGroup2 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
|
||||
// This is the group called diffie-hellman-group14-sha1 in RFC 4253 and
|
||||
// Oakley Group 14 in RFC 3526.
|
||||
oakleyGroup14 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF"
|
||||
// This is the group called diffie-hellman-group15-sha512 in RFC 8268 and
|
||||
// Oakley Group 15 in RFC 3526.
|
||||
oakleyGroup15 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"
|
||||
// This is the group called diffie-hellman-group16-sha512 in RFC 8268 and
|
||||
// Oakley Group 16 in RFC 3526.
|
||||
oakleyGroup16 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF"
|
||||
)
|
||||
|
||||
// kexResult captures the outcome of a key exchange.
|
||||
@@ -402,53 +399,46 @@ func ecHash(curve elliptic.Curve) crypto.Hash {
|
||||
var kexAlgoMap = map[string]kexAlgorithm{}
|
||||
|
||||
func init() {
|
||||
// This is the group called diffie-hellman-group1-sha1 in
|
||||
// RFC 4253 and Oakley Group 2 in RFC 2409.
|
||||
p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
|
||||
kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{
|
||||
p, _ := new(big.Int).SetString(oakleyGroup2, 16)
|
||||
kexAlgoMap[InsecureKeyExchangeDH1SHA1] = &dhGroup{
|
||||
g: new(big.Int).SetInt64(2),
|
||||
p: p,
|
||||
pMinus1: new(big.Int).Sub(p, bigOne),
|
||||
hashFunc: crypto.SHA1,
|
||||
}
|
||||
|
||||
// This are the groups called diffie-hellman-group14-sha1 and
|
||||
// diffie-hellman-group14-sha256 in RFC 4253 and RFC 8268,
|
||||
// and Oakley Group 14 in RFC 3526.
|
||||
p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
|
||||
p, _ = new(big.Int).SetString(oakleyGroup14, 16)
|
||||
group14 := &dhGroup{
|
||||
g: new(big.Int).SetInt64(2),
|
||||
p: p,
|
||||
pMinus1: new(big.Int).Sub(p, bigOne),
|
||||
}
|
||||
|
||||
kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
|
||||
kexAlgoMap[InsecureKeyExchangeDH14SHA1] = &dhGroup{
|
||||
g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
|
||||
hashFunc: crypto.SHA1,
|
||||
}
|
||||
kexAlgoMap[kexAlgoDH14SHA256] = &dhGroup{
|
||||
kexAlgoMap[KeyExchangeDH14SHA256] = &dhGroup{
|
||||
g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
|
||||
hashFunc: crypto.SHA256,
|
||||
}
|
||||
|
||||
// This is the group called diffie-hellman-group16-sha512 in RFC
|
||||
// 8268 and Oakley Group 16 in RFC 3526.
|
||||
p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF", 16)
|
||||
p, _ = new(big.Int).SetString(oakleyGroup16, 16)
|
||||
|
||||
kexAlgoMap[kexAlgoDH16SHA512] = &dhGroup{
|
||||
kexAlgoMap[KeyExchangeDH16SHA512] = &dhGroup{
|
||||
g: new(big.Int).SetInt64(2),
|
||||
p: p,
|
||||
pMinus1: new(big.Int).Sub(p, bigOne),
|
||||
hashFunc: crypto.SHA512,
|
||||
}
|
||||
|
||||
kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
|
||||
kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
|
||||
kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
|
||||
kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{}
|
||||
kexAlgoMap[kexAlgoCurve25519SHA256LibSSH] = &curve25519sha256{}
|
||||
kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
|
||||
kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
|
||||
kexAlgoMap[KeyExchangeECDHP521] = &ecdh{elliptic.P521()}
|
||||
kexAlgoMap[KeyExchangeECDHP384] = &ecdh{elliptic.P384()}
|
||||
kexAlgoMap[KeyExchangeECDHP256] = &ecdh{elliptic.P256()}
|
||||
kexAlgoMap[KeyExchangeCurve25519] = &curve25519sha256{}
|
||||
kexAlgoMap[keyExchangeCurve25519LibSSH] = &curve25519sha256{}
|
||||
kexAlgoMap[InsecureKeyExchangeDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
|
||||
kexAlgoMap[KeyExchangeDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
|
||||
}
|
||||
|
||||
// curve25519sha256 implements the curve25519-sha256 (formerly known as
|
||||
@@ -601,9 +591,9 @@ const (
|
||||
func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
|
||||
// Send GexRequest
|
||||
kexDHGexRequest := kexDHGexRequestMsg{
|
||||
MinBits: dhGroupExchangeMinimumBits,
|
||||
PreferedBits: dhGroupExchangePreferredBits,
|
||||
MaxBits: dhGroupExchangeMaximumBits,
|
||||
MinBits: dhGroupExchangeMinimumBits,
|
||||
PreferredBits: dhGroupExchangePreferredBits,
|
||||
MaxBits: dhGroupExchangeMaximumBits,
|
||||
}
|
||||
if err := c.writePacket(Marshal(&kexDHGexRequest)); err != nil {
|
||||
return nil, err
|
||||
@@ -690,9 +680,7 @@ func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshak
|
||||
}
|
||||
|
||||
// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256.
|
||||
//
|
||||
// This is a minimal implementation to satisfy the automated tests.
|
||||
func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
|
||||
func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
|
||||
// Receive GexRequest
|
||||
packet, err := c.readPacket()
|
||||
if err != nil {
|
||||
@@ -702,13 +690,32 @@ func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshake
|
||||
if err = Unmarshal(packet, &kexDHGexRequest); err != nil {
|
||||
return
|
||||
}
|
||||
// We check that the request received is valid and that the MaxBits
|
||||
// requested are at least equal to our supported minimum. This is the same
|
||||
// check done in OpenSSH:
|
||||
// https://github.com/openssh/openssh-portable/blob/80a2f64b/kexgexs.c#L94
|
||||
//
|
||||
// Furthermore, we also check that the required MinBits are less than or
|
||||
// equal to 4096 because we can use up to Oakley Group 16.
|
||||
if kexDHGexRequest.MaxBits < kexDHGexRequest.MinBits || kexDHGexRequest.PreferredBits < kexDHGexRequest.MinBits ||
|
||||
kexDHGexRequest.MaxBits < kexDHGexRequest.PreferredBits || kexDHGexRequest.MaxBits < dhGroupExchangeMinimumBits ||
|
||||
kexDHGexRequest.MinBits > 4096 {
|
||||
return nil, fmt.Errorf("ssh: DH GEX request out of range, min: %d, max: %d, preferred: %d", kexDHGexRequest.MinBits,
|
||||
kexDHGexRequest.MaxBits, kexDHGexRequest.PreferredBits)
|
||||
}
|
||||
|
||||
var p *big.Int
|
||||
// We hardcode sending Oakley Group 14 (2048 bits), Oakley Group 15 (3072
|
||||
// bits) or Oakley Group 16 (4096 bits), based on the requested max size.
|
||||
if kexDHGexRequest.MaxBits < 3072 {
|
||||
p, _ = new(big.Int).SetString(oakleyGroup14, 16)
|
||||
} else if kexDHGexRequest.MaxBits < 4096 {
|
||||
p, _ = new(big.Int).SetString(oakleyGroup15, 16)
|
||||
} else {
|
||||
p, _ = new(big.Int).SetString(oakleyGroup16, 16)
|
||||
}
|
||||
|
||||
// Send GexGroup
|
||||
// This is the group called diffie-hellman-group14-sha1 in RFC
|
||||
// 4253 and Oakley Group 14 in RFC 3526.
|
||||
p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
|
||||
g := big.NewInt(2)
|
||||
|
||||
msg := &kexDHGexGroupMsg{
|
||||
P: p,
|
||||
G: g,
|
||||
@@ -746,9 +753,9 @@ func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshake
|
||||
h := gex.hashFunc.New()
|
||||
magics.write(h)
|
||||
writeString(h, hostKeyBytes)
|
||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
|
||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
|
||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
|
||||
binary.Write(h, binary.BigEndian, kexDHGexRequest.MinBits)
|
||||
binary.Write(h, binary.BigEndian, kexDHGexRequest.PreferredBits)
|
||||
binary.Write(h, binary.BigEndian, kexDHGexRequest.MaxBits)
|
||||
writeInt(h, p)
|
||||
writeInt(h, g)
|
||||
writeInt(h, kexDHGexInit.X)
|
||||
|
||||
+16
-11
@@ -36,14 +36,19 @@ import (
|
||||
// ClientConfig.HostKeyAlgorithms, Signature.Format, or as AlgorithmSigner
|
||||
// arguments.
|
||||
const (
|
||||
KeyAlgoRSA = "ssh-rsa"
|
||||
KeyAlgoDSA = "ssh-dss"
|
||||
KeyAlgoECDSA256 = "ecdsa-sha2-nistp256"
|
||||
KeyAlgoSKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com"
|
||||
KeyAlgoECDSA384 = "ecdsa-sha2-nistp384"
|
||||
KeyAlgoECDSA521 = "ecdsa-sha2-nistp521"
|
||||
KeyAlgoED25519 = "ssh-ed25519"
|
||||
KeyAlgoSKED25519 = "sk-ssh-ed25519@openssh.com"
|
||||
KeyAlgoRSA = "ssh-rsa"
|
||||
// Deprecated: DSA is only supported at insecure key sizes, and was removed
|
||||
// from major implementations.
|
||||
KeyAlgoDSA = InsecureKeyAlgoDSA
|
||||
// Deprecated: DSA is only supported at insecure key sizes, and was removed
|
||||
// from major implementations.
|
||||
InsecureKeyAlgoDSA = "ssh-dss"
|
||||
KeyAlgoECDSA256 = "ecdsa-sha2-nistp256"
|
||||
KeyAlgoSKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com"
|
||||
KeyAlgoECDSA384 = "ecdsa-sha2-nistp384"
|
||||
KeyAlgoECDSA521 = "ecdsa-sha2-nistp521"
|
||||
KeyAlgoED25519 = "ssh-ed25519"
|
||||
KeyAlgoSKED25519 = "sk-ssh-ed25519@openssh.com"
|
||||
|
||||
// KeyAlgoRSASHA256 and KeyAlgoRSASHA512 are only public key algorithms, not
|
||||
// public key formats, so they can't appear as a PublicKey.Type. The
|
||||
@@ -67,7 +72,7 @@ func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err err
|
||||
switch algo {
|
||||
case KeyAlgoRSA:
|
||||
return parseRSA(in)
|
||||
case KeyAlgoDSA:
|
||||
case InsecureKeyAlgoDSA:
|
||||
return parseDSA(in)
|
||||
case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
|
||||
return parseECDSA(in)
|
||||
@@ -77,7 +82,7 @@ func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err err
|
||||
return parseED25519(in)
|
||||
case KeyAlgoSKED25519:
|
||||
return parseSKEd25519(in)
|
||||
case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
|
||||
case CertAlgoRSAv01, InsecureCertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
|
||||
cert, err := parseCert(in, certKeyAlgoNames[algo])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -268,7 +273,7 @@ func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []str
|
||||
return nil, "", nil, nil, errors.New("ssh: no key found")
|
||||
}
|
||||
|
||||
// ParsePublicKey parses an SSH public key formatted for use in
|
||||
// ParsePublicKey parses an SSH public key or certificate formatted for use in
|
||||
// the SSH wire protocol according to RFC 4253, section 6.6.
|
||||
func ParsePublicKey(in []byte) (out PublicKey, err error) {
|
||||
algo, in, ok := parseString(in)
|
||||
|
||||
@@ -810,3 +810,30 @@ func TestCryptoPublicKey(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCertWithCertSignatureKey(t *testing.T) {
|
||||
certBytes := []byte(`-----BEGIN SSH CERTIFICATE-----
|
||||
AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIPSp27hvNSB0
|
||||
IotJnVhjC4zxNgNS8BHlUCxD0VJi4D/eAAAAIIJMi1e5qfx+IFuKD/p/Ssqcb3os
|
||||
CpOw/4wBs1pQ53zwAAAAAAAAAAEAAAACAAAAAAAAABMAAAAPZm9vLmV4YW1wbGUu
|
||||
Y29tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0AAAAgc3NoLWVkMjU1
|
||||
MTktY2VydC12MDFAb3BlbnNzaC5jb20AAAAg+sNYhCO35mQT1UBMpmMk8ey+culd
|
||||
IU8vBlPEl4B07swAAAAggiv+RLnboS4znGCVl/n1jDg2uD0h15tW4s/04eS2mLQA
|
||||
AAAAAAAAAQAAAAIAAAAAAAAAEwAAAA9mb28uZXhhbXBsZS5jb20AAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACCV2wETgLKL
|
||||
Kt0bRl3YUnd/ZYSlq0xJMbn4Jj3cdPWykQAAAFMAAAALc3NoLWVkMjU1MTkAAABA
|
||||
WOdbRGEzyRAhiIK227CLUQD5caXYMV8FvSIB7toEE2M/8HnWdG9H3Rsg/v3unruQ
|
||||
JrQldnuPJNe7KOP2+zvUDgAAAFMAAAALc3NoLWVkMjU1MTkAAABAm3bIPp85ZpIe
|
||||
D+izJcUqlcAOri7HO8bULFNHT6LVegvB06xQ5TLwMlrxWUF4cafl1tSe8JQck4a6
|
||||
cLYUOHfQDw==
|
||||
-----END SSH CERTIFICATE-----
|
||||
`)
|
||||
block, _ := pem.Decode(certBytes)
|
||||
if block == nil {
|
||||
t.Fatal("invalid test certificate")
|
||||
}
|
||||
|
||||
if _, err := ParsePublicKey(block.Bytes); err == nil {
|
||||
t.Fatal("parsing an SSH certificate using another certificate as signature key succeeded; expected failure")
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -47,22 +47,22 @@ func (t truncatingMAC) Size() int {
|
||||
func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
|
||||
|
||||
var macModes = map[string]*macMode{
|
||||
"hmac-sha2-512-etm@openssh.com": {64, true, func(key []byte) hash.Hash {
|
||||
HMACSHA512ETM: {64, true, func(key []byte) hash.Hash {
|
||||
return hmac.New(sha512.New, key)
|
||||
}},
|
||||
"hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash {
|
||||
HMACSHA256ETM: {32, true, func(key []byte) hash.Hash {
|
||||
return hmac.New(sha256.New, key)
|
||||
}},
|
||||
"hmac-sha2-512": {64, false, func(key []byte) hash.Hash {
|
||||
HMACSHA512: {64, false, func(key []byte) hash.Hash {
|
||||
return hmac.New(sha512.New, key)
|
||||
}},
|
||||
"hmac-sha2-256": {32, false, func(key []byte) hash.Hash {
|
||||
HMACSHA256: {32, false, func(key []byte) hash.Hash {
|
||||
return hmac.New(sha256.New, key)
|
||||
}},
|
||||
"hmac-sha1": {20, false, func(key []byte) hash.Hash {
|
||||
HMACSHA1: {20, false, func(key []byte) hash.Hash {
|
||||
return hmac.New(sha1.New, key)
|
||||
}},
|
||||
"hmac-sha1-96": {20, false, func(key []byte) hash.Hash {
|
||||
InsecureHMACSHA196: {20, false, func(key []byte) hash.Hash {
|
||||
return truncatingMAC{12, hmac.New(sha1.New, key)}
|
||||
}},
|
||||
}
|
||||
|
||||
+3
-3
@@ -122,9 +122,9 @@ type kexDHGexReplyMsg struct {
|
||||
const msgKexDHGexRequest = 34
|
||||
|
||||
type kexDHGexRequestMsg struct {
|
||||
MinBits uint32 `sshtype:"34"`
|
||||
PreferedBits uint32
|
||||
MaxBits uint32
|
||||
MinBits uint32 `sshtype:"34"`
|
||||
PreferredBits uint32
|
||||
MaxBits uint32
|
||||
}
|
||||
|
||||
// See RFC 4253, section 10.
|
||||
|
||||
+3
-7
@@ -19,19 +19,15 @@ import (
|
||||
"golang.org/x/crypto/curve25519"
|
||||
)
|
||||
|
||||
const (
|
||||
kexAlgoMLKEM768xCurve25519SHA256 = "mlkem768x25519-sha256"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// After Go 1.24rc1 mlkem swapped the order of return values of Encapsulate.
|
||||
// See #70950.
|
||||
if runtime.Version() == "go1.24rc1" {
|
||||
return
|
||||
}
|
||||
supportedKexAlgos = slices.Insert(supportedKexAlgos, 0, kexAlgoMLKEM768xCurve25519SHA256)
|
||||
preferredKexAlgos = slices.Insert(preferredKexAlgos, 0, kexAlgoMLKEM768xCurve25519SHA256)
|
||||
kexAlgoMap[kexAlgoMLKEM768xCurve25519SHA256] = &mlkem768WithCurve25519sha256{}
|
||||
supportedKexAlgos = slices.Insert(supportedKexAlgos, 0, KeyExchangeMLKEM768X25519)
|
||||
defaultKexAlgos = slices.Insert(defaultKexAlgos, 0, KeyExchangeMLKEM768X25519)
|
||||
kexAlgoMap[KeyExchangeMLKEM768X25519] = &mlkem768WithCurve25519sha256{}
|
||||
}
|
||||
|
||||
// mlkem768WithCurve25519sha256 implements the hybrid ML-KEM768 with
|
||||
|
||||
+3
-9
@@ -243,22 +243,15 @@ func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewCha
|
||||
fullConf.MaxAuthTries = 6
|
||||
}
|
||||
if len(fullConf.PublicKeyAuthAlgorithms) == 0 {
|
||||
fullConf.PublicKeyAuthAlgorithms = supportedPubKeyAuthAlgos
|
||||
fullConf.PublicKeyAuthAlgorithms = defaultPubKeyAuthAlgos
|
||||
} else {
|
||||
for _, algo := range fullConf.PublicKeyAuthAlgorithms {
|
||||
if !contains(supportedPubKeyAuthAlgos, algo) {
|
||||
if !contains(SupportedAlgorithms().PublicKeyAuths, algo) && !contains(InsecureAlgorithms().PublicKeyAuths, algo) {
|
||||
c.Close()
|
||||
return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if the config contains any unsupported key exchanges
|
||||
for _, kex := range fullConf.KeyExchanges {
|
||||
if _, ok := serverForbiddenKexAlgos[kex]; ok {
|
||||
c.Close()
|
||||
return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex)
|
||||
}
|
||||
}
|
||||
|
||||
s := &connection{
|
||||
sshConn: sshConn{conn: c},
|
||||
@@ -315,6 +308,7 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error)
|
||||
|
||||
// We just did the key change, so the session ID is established.
|
||||
s.sessionID = s.transport.getSessionID()
|
||||
s.algorithms = s.transport.getAlgorithms()
|
||||
|
||||
var packet []byte
|
||||
if packet, err = s.transport.readPacket(); err != nil {
|
||||
|
||||
+1
-1
@@ -212,7 +212,7 @@ func TestNewServerConnValidationErrors(t *testing.T) {
|
||||
|
||||
serverConf = &ServerConfig{
|
||||
Config: Config{
|
||||
KeyExchanges: []string{kexAlgoDHGEXSHA256},
|
||||
KeyExchanges: []string{KeyExchangeDHGEXSHA256},
|
||||
},
|
||||
}
|
||||
c = &markerConn{}
|
||||
|
||||
@@ -236,7 +236,7 @@ func recordingsClientConfig() *ssh.ClientConfig {
|
||||
config := clientConfig()
|
||||
config.SetDefaults()
|
||||
// Remove ML-KEM since it only works with Go 1.24.
|
||||
if config.KeyExchanges[0] == "mlkem768x25519-sha256" {
|
||||
if config.KeyExchanges[0] == ssh.KeyExchangeMLKEM768X25519 {
|
||||
config.KeyExchanges = config.KeyExchanges[1:]
|
||||
}
|
||||
config.Auth = []ssh.AuthMethod{
|
||||
@@ -352,7 +352,7 @@ func TestHostKeyCheck(t *testing.T) {
|
||||
|
||||
// change the keys.
|
||||
hostDB.keys[ssh.KeyAlgoRSA][25]++
|
||||
hostDB.keys[ssh.KeyAlgoDSA][25]++
|
||||
hostDB.keys[ssh.InsecureKeyAlgoDSA][25]++
|
||||
hostDB.keys[ssh.KeyAlgoECDSA256][25]++
|
||||
|
||||
test := clientTest{
|
||||
|
||||
@@ -219,7 +219,7 @@ func recordingsServerConfig() *ssh.ServerConfig {
|
||||
config.SetDefaults()
|
||||
// Remove ML-KEM since it only works with Go 1.24.
|
||||
config.SetDefaults()
|
||||
if config.KeyExchanges[0] == "mlkem768x25519-sha256" {
|
||||
if config.KeyExchanges[0] == ssh.KeyExchangeMLKEM768X25519 {
|
||||
config.KeyExchanges = config.KeyExchanges[1:]
|
||||
}
|
||||
config.AddHostKey(testSigners["rsa"])
|
||||
|
||||
@@ -128,7 +128,7 @@ func clientConfig() *ssh.ClientConfig {
|
||||
HostKeyCallback: hostKeyDB().Check,
|
||||
HostKeyAlgorithms: []string{ // by default, don't allow certs as this affects the hostKeyDB checker
|
||||
ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521,
|
||||
ssh.KeyAlgoRSA, ssh.KeyAlgoDSA,
|
||||
ssh.KeyAlgoRSA, ssh.InsecureKeyAlgoDSA,
|
||||
ssh.KeyAlgoED25519,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -224,8 +224,8 @@ func testOneCipher(t *testing.T, cipher string, cipherOrder []string) {
|
||||
}
|
||||
|
||||
var deprecatedCiphers = []string{
|
||||
"aes128-cbc", "3des-cbc",
|
||||
"arcfour128", "arcfour256",
|
||||
ssh.InsecureCipherAES128CBC, ssh.InsecureCipherTripleDESCBC,
|
||||
ssh.InsecureCipherRC4128, ssh.InsecureCipherRC4256,
|
||||
}
|
||||
|
||||
func TestCiphers(t *testing.T) {
|
||||
|
||||
+74
-11
@@ -34,23 +34,29 @@ func sshClient(t *testing.T) string {
|
||||
return sshCLI
|
||||
}
|
||||
|
||||
// setupSSHCLIKeys writes the provided key files to a temporary directory and
|
||||
// returns the path to the private key.
|
||||
func setupSSHCLIKeys(t *testing.T, keyFiles map[string][]byte, privKeyName string) string {
|
||||
tmpDir := t.TempDir()
|
||||
for fn, content := range keyFiles {
|
||||
if err := os.WriteFile(filepath.Join(tmpDir, fn), content, 0600); err != nil {
|
||||
t.Fatalf("WriteFile(%q): %v", fn, err)
|
||||
}
|
||||
}
|
||||
return filepath.Join(tmpDir, privKeyName)
|
||||
}
|
||||
|
||||
func TestSSHCLIAuth(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skipf("always fails on Windows, see #64403")
|
||||
}
|
||||
sshCLI := sshClient(t)
|
||||
dir := t.TempDir()
|
||||
keyPrivPath := filepath.Join(dir, "rsa")
|
||||
|
||||
for fn, content := range map[string][]byte{
|
||||
keyPrivPath: testdata.PEMBytes["rsa"],
|
||||
keyPrivPath + ".pub": ssh.MarshalAuthorizedKey(testPublicKeys["rsa"]),
|
||||
filepath.Join(dir, "rsa-cert.pub"): testdata.SSHCertificates["rsa-user-testcertificate"],
|
||||
} {
|
||||
if err := os.WriteFile(fn, content, 0600); err != nil {
|
||||
t.Fatalf("WriteFile(%q): %v", fn, err)
|
||||
}
|
||||
keyFiles := map[string][]byte{
|
||||
"rsa": testdata.PEMBytes["rsa"],
|
||||
"rsa.pub": ssh.MarshalAuthorizedKey(testPublicKeys["rsa"]),
|
||||
"rsa-cert.pub": testdata.SSHCertificates["rsa-user-testcertificate"],
|
||||
}
|
||||
keyPrivPath := setupSSHCLIKeys(t, keyFiles, "rsa")
|
||||
|
||||
certChecker := ssh.CertChecker{
|
||||
IsUserAuthority: func(k ssh.PublicKey) bool {
|
||||
@@ -98,3 +104,60 @@ func TestSSHCLIAuth(t *testing.T) {
|
||||
t.Fatalf("user certificate authentication failed, error: %v, command output %q", err, string(out))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSSHCLIKeyExchanges(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skipf("always fails on Windows, see #64403")
|
||||
}
|
||||
sshCLI := sshClient(t)
|
||||
keyFiles := map[string][]byte{
|
||||
"rsa": testdata.PEMBytes["rsa"],
|
||||
"rsa.pub": ssh.MarshalAuthorizedKey(testPublicKeys["rsa"]),
|
||||
}
|
||||
keyPrivPath := setupSSHCLIKeys(t, keyFiles, "rsa")
|
||||
|
||||
keyExchanges := append(ssh.SupportedAlgorithms().KeyExchanges, ssh.InsecureAlgorithms().KeyExchanges...)
|
||||
for _, kex := range keyExchanges {
|
||||
t.Run(kex, func(t *testing.T) {
|
||||
cmd := testenv.Command(t, sshCLI, "-Q", "kex")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("%s failed to check if the KEX is supported, error: %v, command output %q", kex, err, string(out))
|
||||
}
|
||||
if !bytes.Contains(out, []byte(kex)) {
|
||||
t.Skipf("KEX %q is not supported in the installed ssh CLI", kex)
|
||||
}
|
||||
config := &ssh.ServerConfig{
|
||||
Config: ssh.Config{
|
||||
KeyExchanges: []string{kex},
|
||||
},
|
||||
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
|
||||
if conn.User() == "testpubkey" && bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("pubkey for %q not acceptable", conn.User())
|
||||
},
|
||||
}
|
||||
config.AddHostKey(testSigners["rsa"])
|
||||
|
||||
server, err := newTestServer(config)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to start test server: %v", err)
|
||||
}
|
||||
defer server.Close()
|
||||
|
||||
port, err := server.port()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get server port: %v", err)
|
||||
}
|
||||
|
||||
cmd = testenv.Command(t, sshCLI, "-vvv", "-i", keyPrivPath, "-o", "StrictHostKeyChecking=no",
|
||||
"-o", fmt.Sprintf("KexAlgorithms=%s", kex), "-p", port, "testpubkey@127.0.0.1", "true")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("%s failed, error: %v, command output %q", kex, err, string(out))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+254
-255
@@ -2,58 +2,59 @@
|
||||
00000000 53 53 48 2d 32 2e 30 2d 47 6f 0d 0a |SSH-2.0-Go..|
|
||||
>>> Flow 2 (server to client)
|
||||
00000000 53 53 48 2d 32 2e 30 2d 4f 70 65 6e 53 53 48 5f |SSH-2.0-OpenSSH_|
|
||||
00000010 39 2e 39 0d 0a |9.9..|
|
||||
00000010 31 30 2e 30 0d 0a |10.0..|
|
||||
>>> Flow 3 (client to server)
|
||||
00000000 00 00 02 9c 11 14 7f 9c 2b a4 e8 8f 82 7d 61 60 |........+....}a`|
|
||||
00000010 45 50 76 05 85 3e 00 00 00 39 63 75 72 76 65 32 |EPv..>...9curve2|
|
||||
00000020 35 35 31 39 2d 73 68 61 32 35 36 2c 65 78 74 2d |5519-sha256,ext-|
|
||||
00000030 69 6e 66 6f 2d 63 2c 6b 65 78 2d 73 74 72 69 63 |info-c,kex-stric|
|
||||
00000040 74 2d 63 2d 76 30 30 40 6f 70 65 6e 73 73 68 2e |t-c-v00@openssh.|
|
||||
00000050 63 6f 6d 00 00 00 57 65 63 64 73 61 2d 73 68 61 |com...Wecdsa-sha|
|
||||
00000060 32 2d 6e 69 73 74 70 32 35 36 2c 65 63 64 73 61 |2-nistp256,ecdsa|
|
||||
00000070 2d 73 68 61 32 2d 6e 69 73 74 70 33 38 34 2c 65 |-sha2-nistp384,e|
|
||||
00000080 63 64 73 61 2d 73 68 61 32 2d 6e 69 73 74 70 35 |cdsa-sha2-nistp5|
|
||||
00000090 32 31 2c 73 73 68 2d 72 73 61 2c 73 73 68 2d 64 |21,ssh-rsa,ssh-d|
|
||||
000000a0 73 73 2c 73 73 68 2d 65 64 32 35 35 31 39 00 00 |ss,ssh-ed25519..|
|
||||
000000b0 00 6c 61 65 73 31 32 38 2d 67 63 6d 40 6f 70 65 |.laes128-gcm@ope|
|
||||
000000c0 6e 73 73 68 2e 63 6f 6d 2c 61 65 73 32 35 36 2d |nssh.com,aes256-|
|
||||
000000d0 67 63 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c |gcm@openssh.com,|
|
||||
000000e0 63 68 61 63 68 61 32 30 2d 70 6f 6c 79 31 33 30 |chacha20-poly130|
|
||||
000000f0 35 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 61 65 |5@openssh.com,ae|
|
||||
00000100 73 31 32 38 2d 63 74 72 2c 61 65 73 31 39 32 2d |s128-ctr,aes192-|
|
||||
00000110 63 74 72 2c 61 65 73 32 35 36 2d 63 74 72 00 00 |ctr,aes256-ctr..|
|
||||
00000120 00 6c 61 65 73 31 32 38 2d 67 63 6d 40 6f 70 65 |.laes128-gcm@ope|
|
||||
00000130 6e 73 73 68 2e 63 6f 6d 2c 61 65 73 32 35 36 2d |nssh.com,aes256-|
|
||||
00000140 67 63 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c |gcm@openssh.com,|
|
||||
00000150 63 68 61 63 68 61 32 30 2d 70 6f 6c 79 31 33 30 |chacha20-poly130|
|
||||
00000160 35 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 61 65 |5@openssh.com,ae|
|
||||
00000170 73 31 32 38 2d 63 74 72 2c 61 65 73 31 39 32 2d |s128-ctr,aes192-|
|
||||
00000180 63 74 72 2c 61 65 73 32 35 36 2d 63 74 72 00 00 |ctr,aes256-ctr..|
|
||||
00000190 00 6e 68 6d 61 63 2d 73 68 61 32 2d 32 35 36 2d |.nhmac-sha2-256-|
|
||||
000001a0 65 74 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c |etm@openssh.com,|
|
||||
000001b0 68 6d 61 63 2d 73 68 61 32 2d 35 31 32 2d 65 74 |hmac-sha2-512-et|
|
||||
000001c0 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 6d |m@openssh.com,hm|
|
||||
000001d0 61 63 2d 73 68 61 32 2d 32 35 36 2c 68 6d 61 63 |ac-sha2-256,hmac|
|
||||
000001e0 2d 73 68 61 32 2d 35 31 32 2c 68 6d 61 63 2d 73 |-sha2-512,hmac-s|
|
||||
000001f0 68 61 31 2c 68 6d 61 63 2d 73 68 61 31 2d 39 36 |ha1,hmac-sha1-96|
|
||||
00000200 00 00 00 6e 68 6d 61 63 2d 73 68 61 32 2d 32 35 |...nhmac-sha2-25|
|
||||
00000210 36 2d 65 74 6d 40 6f 70 65 6e 73 73 68 2e 63 6f |6-etm@openssh.co|
|
||||
00000220 6d 2c 68 6d 61 63 2d 73 68 61 32 2d 35 31 32 2d |m,hmac-sha2-512-|
|
||||
00000230 65 74 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c |etm@openssh.com,|
|
||||
00000240 68 6d 61 63 2d 73 68 61 32 2d 32 35 36 2c 68 6d |hmac-sha2-256,hm|
|
||||
00000250 61 63 2d 73 68 61 32 2d 35 31 32 2c 68 6d 61 63 |ac-sha2-512,hmac|
|
||||
00000260 2d 73 68 61 31 2c 68 6d 61 63 2d 73 68 61 31 2d |-sha1,hmac-sha1-|
|
||||
00000270 39 36 00 00 00 04 6e 6f 6e 65 00 00 00 04 6e 6f |96....none....no|
|
||||
00000280 6e 65 00 00 00 00 00 00 00 00 00 00 00 00 00 d7 |ne..............|
|
||||
00000290 3b 80 93 f6 ef bc 88 eb 1a 6e ac fa 66 ef 26 3c |;........n..f.&<|
|
||||
00000000 00 00 02 ac 04 14 7f 9c 2b a4 e8 8f 82 7d 61 60 |........+....}a`|
|
||||
00000010 45 50 76 05 85 3e 00 00 00 56 63 75 72 76 65 32 |EPv..>...Vcurve2|
|
||||
00000020 35 35 31 39 2d 73 68 61 32 35 36 2c 63 75 72 76 |5519-sha256,curv|
|
||||
00000030 65 32 35 35 31 39 2d 73 68 61 32 35 36 40 6c 69 |e25519-sha256@li|
|
||||
00000040 62 73 73 68 2e 6f 72 67 2c 65 78 74 2d 69 6e 66 |bssh.org,ext-inf|
|
||||
00000050 6f 2d 63 2c 6b 65 78 2d 73 74 72 69 63 74 2d 63 |o-c,kex-strict-c|
|
||||
00000060 2d 76 30 30 40 6f 70 65 6e 73 73 68 2e 63 6f 6d |-v00@openssh.com|
|
||||
00000070 00 00 00 57 65 63 64 73 61 2d 73 68 61 32 2d 6e |...Wecdsa-sha2-n|
|
||||
00000080 69 73 74 70 32 35 36 2c 65 63 64 73 61 2d 73 68 |istp256,ecdsa-sh|
|
||||
00000090 61 32 2d 6e 69 73 74 70 33 38 34 2c 65 63 64 73 |a2-nistp384,ecds|
|
||||
000000a0 61 2d 73 68 61 32 2d 6e 69 73 74 70 35 32 31 2c |a-sha2-nistp521,|
|
||||
000000b0 73 73 68 2d 72 73 61 2c 73 73 68 2d 64 73 73 2c |ssh-rsa,ssh-dss,|
|
||||
000000c0 73 73 68 2d 65 64 32 35 35 31 39 00 00 00 6c 61 |ssh-ed25519...la|
|
||||
000000d0 65 73 31 32 38 2d 67 63 6d 40 6f 70 65 6e 73 73 |es128-gcm@openss|
|
||||
000000e0 68 2e 63 6f 6d 2c 61 65 73 32 35 36 2d 67 63 6d |h.com,aes256-gcm|
|
||||
000000f0 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 63 68 61 |@openssh.com,cha|
|
||||
00000100 63 68 61 32 30 2d 70 6f 6c 79 31 33 30 35 40 6f |cha20-poly1305@o|
|
||||
00000110 70 65 6e 73 73 68 2e 63 6f 6d 2c 61 65 73 31 32 |penssh.com,aes12|
|
||||
00000120 38 2d 63 74 72 2c 61 65 73 31 39 32 2d 63 74 72 |8-ctr,aes192-ctr|
|
||||
00000130 2c 61 65 73 32 35 36 2d 63 74 72 00 00 00 6c 61 |,aes256-ctr...la|
|
||||
00000140 65 73 31 32 38 2d 67 63 6d 40 6f 70 65 6e 73 73 |es128-gcm@openss|
|
||||
00000150 68 2e 63 6f 6d 2c 61 65 73 32 35 36 2d 67 63 6d |h.com,aes256-gcm|
|
||||
00000160 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 63 68 61 |@openssh.com,cha|
|
||||
00000170 63 68 61 32 30 2d 70 6f 6c 79 31 33 30 35 40 6f |cha20-poly1305@o|
|
||||
00000180 70 65 6e 73 73 68 2e 63 6f 6d 2c 61 65 73 31 32 |penssh.com,aes12|
|
||||
00000190 38 2d 63 74 72 2c 61 65 73 31 39 32 2d 63 74 72 |8-ctr,aes192-ctr|
|
||||
000001a0 2c 61 65 73 32 35 36 2d 63 74 72 00 00 00 6e 68 |,aes256-ctr...nh|
|
||||
000001b0 6d 61 63 2d 73 68 61 32 2d 32 35 36 2d 65 74 6d |mac-sha2-256-etm|
|
||||
000001c0 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 6d 61 |@openssh.com,hma|
|
||||
000001d0 63 2d 73 68 61 32 2d 35 31 32 2d 65 74 6d 40 6f |c-sha2-512-etm@o|
|
||||
000001e0 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 6d 61 63 2d |penssh.com,hmac-|
|
||||
000001f0 73 68 61 32 2d 32 35 36 2c 68 6d 61 63 2d 73 68 |sha2-256,hmac-sh|
|
||||
00000200 61 32 2d 35 31 32 2c 68 6d 61 63 2d 73 68 61 31 |a2-512,hmac-sha1|
|
||||
00000210 2c 68 6d 61 63 2d 73 68 61 31 2d 39 36 00 00 00 |,hmac-sha1-96...|
|
||||
00000220 6e 68 6d 61 63 2d 73 68 61 32 2d 32 35 36 2d 65 |nhmac-sha2-256-e|
|
||||
00000230 74 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 |tm@openssh.com,h|
|
||||
00000240 6d 61 63 2d 73 68 61 32 2d 35 31 32 2d 65 74 6d |mac-sha2-512-etm|
|
||||
00000250 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 6d 61 |@openssh.com,hma|
|
||||
00000260 63 2d 73 68 61 32 2d 32 35 36 2c 68 6d 61 63 2d |c-sha2-256,hmac-|
|
||||
00000270 73 68 61 32 2d 35 31 32 2c 68 6d 61 63 2d 73 68 |sha2-512,hmac-sh|
|
||||
00000280 61 31 2c 68 6d 61 63 2d 73 68 61 31 2d 39 36 00 |a1,hmac-sha1-96.|
|
||||
00000290 00 00 04 6e 6f 6e 65 00 00 00 04 6e 6f 6e 65 00 |...none....none.|
|
||||
000002a0 00 00 00 00 00 00 00 00 00 00 00 00 d7 3b 80 93 |.............;..|
|
||||
>>> Flow 4 (server to client)
|
||||
00000000 00 00 04 9c 0a 14 86 1d 13 33 bb 65 c5 7e 3d 8b |.........3.e.~=.|
|
||||
00000010 4f 63 27 f5 d1 59 00 00 01 7a 73 6e 74 72 75 70 |Oc'..Y...zsntrup|
|
||||
00000020 37 36 31 78 32 35 35 31 39 2d 73 68 61 35 31 32 |761x25519-sha512|
|
||||
00000030 2c 73 6e 74 72 75 70 37 36 31 78 32 35 35 31 39 |,sntrup761x25519|
|
||||
00000040 2d 73 68 61 35 31 32 40 6f 70 65 6e 73 73 68 2e |-sha512@openssh.|
|
||||
00000050 63 6f 6d 2c 6d 6c 6b 65 6d 37 36 38 78 32 35 35 |com,mlkem768x255|
|
||||
00000060 31 39 2d 73 68 61 32 35 36 2c 63 75 72 76 65 32 |19-sha256,curve2|
|
||||
00000000 00 00 04 7c 08 14 d7 da a8 cd 40 76 e6 8a 12 b5 |...|......@v....|
|
||||
00000010 5f ff a4 a5 57 4b 00 00 01 5c 6d 6c 6b 65 6d 37 |_...WK...\mlkem7|
|
||||
00000020 36 38 78 32 35 35 31 39 2d 73 68 61 32 35 36 2c |68x25519-sha256,|
|
||||
00000030 73 6e 74 72 75 70 37 36 31 78 32 35 35 31 39 2d |sntrup761x25519-|
|
||||
00000040 73 68 61 35 31 32 2c 73 6e 74 72 75 70 37 36 31 |sha512,sntrup761|
|
||||
00000050 78 32 35 35 31 39 2d 73 68 61 35 31 32 40 6f 70 |x25519-sha512@op|
|
||||
00000060 65 6e 73 73 68 2e 63 6f 6d 2c 63 75 72 76 65 32 |enssh.com,curve2|
|
||||
00000070 35 35 31 39 2d 73 68 61 32 35 36 2c 63 75 72 76 |5519-sha256,curv|
|
||||
00000080 65 32 35 35 31 39 2d 73 68 61 32 35 36 40 6c 69 |e25519-sha256@li|
|
||||
00000090 62 73 73 68 2e 6f 72 67 2c 65 63 64 68 2d 73 68 |bssh.org,ecdh-sh|
|
||||
@@ -61,229 +62,227 @@
|
||||
000000b0 2d 73 68 61 32 2d 6e 69 73 74 70 33 38 34 2c 65 |-sha2-nistp384,e|
|
||||
000000c0 63 64 68 2d 73 68 61 32 2d 6e 69 73 74 70 35 32 |cdh-sha2-nistp52|
|
||||
000000d0 31 2c 64 69 66 66 69 65 2d 68 65 6c 6c 6d 61 6e |1,diffie-hellman|
|
||||
000000e0 2d 67 72 6f 75 70 2d 65 78 63 68 61 6e 67 65 2d |-group-exchange-|
|
||||
000000f0 73 68 61 32 35 36 2c 64 69 66 66 69 65 2d 68 65 |sha256,diffie-he|
|
||||
00000100 6c 6c 6d 61 6e 2d 67 72 6f 75 70 31 36 2d 73 68 |llman-group16-sh|
|
||||
00000110 61 35 31 32 2c 64 69 66 66 69 65 2d 68 65 6c 6c |a512,diffie-hell|
|
||||
00000120 6d 61 6e 2d 67 72 6f 75 70 31 38 2d 73 68 61 35 |man-group18-sha5|
|
||||
00000130 31 32 2c 64 69 66 66 69 65 2d 68 65 6c 6c 6d 61 |12,diffie-hellma|
|
||||
00000140 6e 2d 67 72 6f 75 70 31 34 2d 73 68 61 32 35 36 |n-group14-sha256|
|
||||
00000150 2c 64 69 66 66 69 65 2d 68 65 6c 6c 6d 61 6e 2d |,diffie-hellman-|
|
||||
00000160 67 72 6f 75 70 31 34 2d 73 68 61 31 2c 65 78 74 |group14-sha1,ext|
|
||||
00000170 2d 69 6e 66 6f 2d 73 2c 6b 65 78 2d 73 74 72 69 |-info-s,kex-stri|
|
||||
00000180 63 74 2d 73 2d 76 30 30 40 6f 70 65 6e 73 73 68 |ct-s-v00@openssh|
|
||||
00000190 2e 63 6f 6d 00 00 00 2d 72 73 61 2d 73 68 61 32 |.com...-rsa-sha2|
|
||||
000001a0 2d 35 31 32 2c 72 73 61 2d 73 68 61 32 2d 32 35 |-512,rsa-sha2-25|
|
||||
000001b0 36 2c 65 63 64 73 61 2d 73 68 61 32 2d 6e 69 73 |6,ecdsa-sha2-nis|
|
||||
000001c0 74 70 32 35 36 00 00 00 6c 63 68 61 63 68 61 32 |tp256...lchacha2|
|
||||
000001d0 30 2d 70 6f 6c 79 31 33 30 35 40 6f 70 65 6e 73 |0-poly1305@opens|
|
||||
000001e0 73 68 2e 63 6f 6d 2c 61 65 73 31 32 38 2d 63 74 |sh.com,aes128-ct|
|
||||
000001f0 72 2c 61 65 73 31 39 32 2d 63 74 72 2c 61 65 73 |r,aes192-ctr,aes|
|
||||
00000200 32 35 36 2d 63 74 72 2c 61 65 73 31 32 38 2d 67 |256-ctr,aes128-g|
|
||||
00000210 63 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 61 |cm@openssh.com,a|
|
||||
00000220 65 73 32 35 36 2d 67 63 6d 40 6f 70 65 6e 73 73 |es256-gcm@openss|
|
||||
00000230 68 2e 63 6f 6d 00 00 00 6c 63 68 61 63 68 61 32 |h.com...lchacha2|
|
||||
00000240 30 2d 70 6f 6c 79 31 33 30 35 40 6f 70 65 6e 73 |0-poly1305@opens|
|
||||
00000250 73 68 2e 63 6f 6d 2c 61 65 73 31 32 38 2d 63 74 |sh.com,aes128-ct|
|
||||
00000260 72 2c 61 65 73 31 39 32 2d 63 74 72 2c 61 65 73 |r,aes192-ctr,aes|
|
||||
00000270 32 35 36 2d 63 74 72 2c 61 65 73 31 32 38 2d 67 |256-ctr,aes128-g|
|
||||
00000280 63 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 61 |cm@openssh.com,a|
|
||||
00000290 65 73 32 35 36 2d 67 63 6d 40 6f 70 65 6e 73 73 |es256-gcm@openss|
|
||||
000002a0 68 2e 63 6f 6d 00 00 00 d5 75 6d 61 63 2d 36 34 |h.com....umac-64|
|
||||
000002b0 2d 65 74 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d |-etm@openssh.com|
|
||||
000002c0 2c 75 6d 61 63 2d 31 32 38 2d 65 74 6d 40 6f 70 |,umac-128-etm@op|
|
||||
000000e0 2d 67 72 6f 75 70 31 34 2d 73 68 61 31 2c 64 69 |-group14-sha1,di|
|
||||
000000f0 66 66 69 65 2d 68 65 6c 6c 6d 61 6e 2d 67 72 6f |ffie-hellman-gro|
|
||||
00000100 75 70 31 34 2d 73 68 61 32 35 36 2c 64 69 66 66 |up14-sha256,diff|
|
||||
00000110 69 65 2d 68 65 6c 6c 6d 61 6e 2d 67 72 6f 75 70 |ie-hellman-group|
|
||||
00000120 31 36 2d 73 68 61 35 31 32 2c 64 69 66 66 69 65 |16-sha512,diffie|
|
||||
00000130 2d 68 65 6c 6c 6d 61 6e 2d 67 72 6f 75 70 2d 65 |-hellman-group-e|
|
||||
00000140 78 63 68 61 6e 67 65 2d 73 68 61 32 35 36 2c 65 |xchange-sha256,e|
|
||||
00000150 78 74 2d 69 6e 66 6f 2d 73 2c 6b 65 78 2d 73 74 |xt-info-s,kex-st|
|
||||
00000160 72 69 63 74 2d 73 2d 76 30 30 40 6f 70 65 6e 73 |rict-s-v00@opens|
|
||||
00000170 73 68 2e 63 6f 6d 00 00 00 2d 72 73 61 2d 73 68 |sh.com...-rsa-sh|
|
||||
00000180 61 32 2d 35 31 32 2c 72 73 61 2d 73 68 61 32 2d |a2-512,rsa-sha2-|
|
||||
00000190 32 35 36 2c 65 63 64 73 61 2d 73 68 61 32 2d 6e |256,ecdsa-sha2-n|
|
||||
000001a0 69 73 74 70 32 35 36 00 00 00 6c 63 68 61 63 68 |istp256...lchach|
|
||||
000001b0 61 32 30 2d 70 6f 6c 79 31 33 30 35 40 6f 70 65 |a20-poly1305@ope|
|
||||
000001c0 6e 73 73 68 2e 63 6f 6d 2c 61 65 73 31 32 38 2d |nssh.com,aes128-|
|
||||
000001d0 67 63 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c |gcm@openssh.com,|
|
||||
000001e0 61 65 73 32 35 36 2d 67 63 6d 40 6f 70 65 6e 73 |aes256-gcm@opens|
|
||||
000001f0 73 68 2e 63 6f 6d 2c 61 65 73 31 32 38 2d 63 74 |sh.com,aes128-ct|
|
||||
00000200 72 2c 61 65 73 31 39 32 2d 63 74 72 2c 61 65 73 |r,aes192-ctr,aes|
|
||||
00000210 32 35 36 2d 63 74 72 00 00 00 6c 63 68 61 63 68 |256-ctr...lchach|
|
||||
00000220 61 32 30 2d 70 6f 6c 79 31 33 30 35 40 6f 70 65 |a20-poly1305@ope|
|
||||
00000230 6e 73 73 68 2e 63 6f 6d 2c 61 65 73 31 32 38 2d |nssh.com,aes128-|
|
||||
00000240 67 63 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c |gcm@openssh.com,|
|
||||
00000250 61 65 73 32 35 36 2d 67 63 6d 40 6f 70 65 6e 73 |aes256-gcm@opens|
|
||||
00000260 73 68 2e 63 6f 6d 2c 61 65 73 31 32 38 2d 63 74 |sh.com,aes128-ct|
|
||||
00000270 72 2c 61 65 73 31 39 32 2d 63 74 72 2c 61 65 73 |r,aes192-ctr,aes|
|
||||
00000280 32 35 36 2d 63 74 72 00 00 00 d5 75 6d 61 63 2d |256-ctr....umac-|
|
||||
00000290 36 34 2d 65 74 6d 40 6f 70 65 6e 73 73 68 2e 63 |64-etm@openssh.c|
|
||||
000002a0 6f 6d 2c 75 6d 61 63 2d 31 32 38 2d 65 74 6d 40 |om,umac-128-etm@|
|
||||
000002b0 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 6d 61 63 |openssh.com,hmac|
|
||||
000002c0 2d 73 68 61 32 2d 32 35 36 2d 65 74 6d 40 6f 70 |-sha2-256-etm@op|
|
||||
000002d0 65 6e 73 73 68 2e 63 6f 6d 2c 68 6d 61 63 2d 73 |enssh.com,hmac-s|
|
||||
000002e0 68 61 32 2d 32 35 36 2d 65 74 6d 40 6f 70 65 6e |ha2-256-etm@open|
|
||||
000002e0 68 61 32 2d 35 31 32 2d 65 74 6d 40 6f 70 65 6e |ha2-512-etm@open|
|
||||
000002f0 73 73 68 2e 63 6f 6d 2c 68 6d 61 63 2d 73 68 61 |ssh.com,hmac-sha|
|
||||
00000300 32 2d 35 31 32 2d 65 74 6d 40 6f 70 65 6e 73 73 |2-512-etm@openss|
|
||||
00000310 68 2e 63 6f 6d 2c 68 6d 61 63 2d 73 68 61 31 2d |h.com,hmac-sha1-|
|
||||
00000320 65 74 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c |etm@openssh.com,|
|
||||
00000330 75 6d 61 63 2d 36 34 40 6f 70 65 6e 73 73 68 2e |umac-64@openssh.|
|
||||
00000340 63 6f 6d 2c 75 6d 61 63 2d 31 32 38 40 6f 70 65 |com,umac-128@ope|
|
||||
00000350 6e 73 73 68 2e 63 6f 6d 2c 68 6d 61 63 2d 73 68 |nssh.com,hmac-sh|
|
||||
00000360 61 32 2d 32 35 36 2c 68 6d 61 63 2d 73 68 61 32 |a2-256,hmac-sha2|
|
||||
00000370 2d 35 31 32 2c 68 6d 61 63 2d 73 68 61 31 00 00 |-512,hmac-sha1..|
|
||||
00000380 00 d5 75 6d 61 63 2d 36 34 2d 65 74 6d 40 6f 70 |..umac-64-etm@op|
|
||||
00000390 65 6e 73 73 68 2e 63 6f 6d 2c 75 6d 61 63 2d 31 |enssh.com,umac-1|
|
||||
000003a0 32 38 2d 65 74 6d 40 6f 70 65 6e 73 73 68 2e 63 |28-etm@openssh.c|
|
||||
000003b0 6f 6d 2c 68 6d 61 63 2d 73 68 61 32 2d 32 35 36 |om,hmac-sha2-256|
|
||||
00000300 31 2d 65 74 6d 40 6f 70 65 6e 73 73 68 2e 63 6f |1-etm@openssh.co|
|
||||
00000310 6d 2c 75 6d 61 63 2d 36 34 40 6f 70 65 6e 73 73 |m,umac-64@openss|
|
||||
00000320 68 2e 63 6f 6d 2c 75 6d 61 63 2d 31 32 38 40 6f |h.com,umac-128@o|
|
||||
00000330 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 6d 61 63 2d |penssh.com,hmac-|
|
||||
00000340 73 68 61 32 2d 32 35 36 2c 68 6d 61 63 2d 73 68 |sha2-256,hmac-sh|
|
||||
00000350 61 32 2d 35 31 32 2c 68 6d 61 63 2d 73 68 61 31 |a2-512,hmac-sha1|
|
||||
00000360 00 00 00 d5 75 6d 61 63 2d 36 34 2d 65 74 6d 40 |....umac-64-etm@|
|
||||
00000370 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 75 6d 61 63 |openssh.com,umac|
|
||||
00000380 2d 31 32 38 2d 65 74 6d 40 6f 70 65 6e 73 73 68 |-128-etm@openssh|
|
||||
00000390 2e 63 6f 6d 2c 68 6d 61 63 2d 73 68 61 32 2d 32 |.com,hmac-sha2-2|
|
||||
000003a0 35 36 2d 65 74 6d 40 6f 70 65 6e 73 73 68 2e 63 |56-etm@openssh.c|
|
||||
000003b0 6f 6d 2c 68 6d 61 63 2d 73 68 61 32 2d 35 31 32 |om,hmac-sha2-512|
|
||||
000003c0 2d 65 74 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d |-etm@openssh.com|
|
||||
000003d0 2c 68 6d 61 63 2d 73 68 61 32 2d 35 31 32 2d 65 |,hmac-sha2-512-e|
|
||||
000003e0 74 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 |tm@openssh.com,h|
|
||||
000003f0 6d 61 63 2d 73 68 61 31 2d 65 74 6d 40 6f 70 65 |mac-sha1-etm@ope|
|
||||
00000400 6e 73 73 68 2e 63 6f 6d 2c 75 6d 61 63 2d 36 34 |nssh.com,umac-64|
|
||||
00000410 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 75 6d 61 |@openssh.com,uma|
|
||||
00000420 63 2d 31 32 38 40 6f 70 65 6e 73 73 68 2e 63 6f |c-128@openssh.co|
|
||||
00000430 6d 2c 68 6d 61 63 2d 73 68 61 32 2d 32 35 36 2c |m,hmac-sha2-256,|
|
||||
00000440 68 6d 61 63 2d 73 68 61 32 2d 35 31 32 2c 68 6d |hmac-sha2-512,hm|
|
||||
00000450 61 63 2d 73 68 61 31 00 00 00 15 6e 6f 6e 65 2c |ac-sha1....none,|
|
||||
00000460 7a 6c 69 62 40 6f 70 65 6e 73 73 68 2e 63 6f 6d |zlib@openssh.com|
|
||||
00000470 00 00 00 15 6e 6f 6e 65 2c 7a 6c 69 62 40 6f 70 |....none,zlib@op|
|
||||
00000480 65 6e 73 73 68 2e 63 6f 6d 00 00 00 00 00 00 00 |enssh.com.......|
|
||||
00000490 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
000003d0 2c 68 6d 61 63 2d 73 68 61 31 2d 65 74 6d 40 6f |,hmac-sha1-etm@o|
|
||||
000003e0 70 65 6e 73 73 68 2e 63 6f 6d 2c 75 6d 61 63 2d |penssh.com,umac-|
|
||||
000003f0 36 34 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 75 |64@openssh.com,u|
|
||||
00000400 6d 61 63 2d 31 32 38 40 6f 70 65 6e 73 73 68 2e |mac-128@openssh.|
|
||||
00000410 63 6f 6d 2c 68 6d 61 63 2d 73 68 61 32 2d 32 35 |com,hmac-sha2-25|
|
||||
00000420 36 2c 68 6d 61 63 2d 73 68 61 32 2d 35 31 32 2c |6,hmac-sha2-512,|
|
||||
00000430 68 6d 61 63 2d 73 68 61 31 00 00 00 15 6e 6f 6e |hmac-sha1....non|
|
||||
00000440 65 2c 7a 6c 69 62 40 6f 70 65 6e 73 73 68 2e 63 |e,zlib@openssh.c|
|
||||
00000450 6f 6d 00 00 00 15 6e 6f 6e 65 2c 7a 6c 69 62 40 |om....none,zlib@|
|
||||
00000460 6f 70 65 6e 73 73 68 2e 63 6f 6d 00 00 00 00 00 |openssh.com.....|
|
||||
00000470 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
>>> Flow 5 (client to server)
|
||||
00000000 00 00 00 2c 06 1e 00 00 00 20 aa 80 4b 53 a8 4b |...,..... ..KS.K|
|
||||
00000010 4c 0f fa ac a3 b8 5f 64 7d 36 42 e7 1d 56 45 7e |L....._d}6B..VE~|
|
||||
00000020 2b ac e0 f9 e7 60 f5 d7 55 37 b8 cc 87 3c 23 dc |+....`..U7...<#.|
|
||||
00000000 00 00 00 2c 06 1e 00 00 00 20 13 87 32 34 3e 68 |...,..... ..24>h|
|
||||
00000010 e6 9b 9a cb 23 22 06 11 e8 24 71 e5 d7 96 79 83 |....#"...$q...y.|
|
||||
00000020 48 59 1a 95 f2 b0 86 1c 76 54 58 e8 a3 63 9c a8 |HY......vTX..c..|
|
||||
>>> Flow 6 (server to client)
|
||||
00000000 00 00 01 04 0b 1f 00 00 00 68 00 00 00 13 65 63 |.........h....ec|
|
||||
00000000 00 00 01 04 0a 1f 00 00 00 68 00 00 00 13 65 63 |.........h....ec|
|
||||
00000010 64 73 61 2d 73 68 61 32 2d 6e 69 73 74 70 32 35 |dsa-sha2-nistp25|
|
||||
00000020 36 00 00 00 08 6e 69 73 74 70 32 35 36 00 00 00 |6....nistp256...|
|
||||
00000030 41 04 8b d1 dd c3 a2 af 65 c5 b1 7e 0d 88 0e 10 |A.......e..~....|
|
||||
00000040 3b 52 4a 43 b7 3c ed e9 9a 89 5d 2b 05 74 b7 7e |;RJC.<....]+.t.~|
|
||||
00000050 2b 1e 12 dd 2c 78 71 53 be eb f6 4e 5d 19 cf 98 |+...,xqS...N]...|
|
||||
00000060 d0 25 2d 4a a3 4a 15 2c 50 10 67 80 6d 2e d9 fa |.%-J.J.,P.g.m...|
|
||||
00000070 84 a8 00 00 00 20 e8 01 e7 b0 7b 47 62 2e ac 12 |..... ....{Gb...|
|
||||
00000080 80 ba 70 5b a4 65 6a 25 50 1c 59 6c f3 12 ed 64 |..p[.ej%P.Yl...d|
|
||||
00000090 2c f3 7a 3b 0e 53 00 00 00 63 00 00 00 13 65 63 |,.z;.S...c....ec|
|
||||
00000070 84 a8 00 00 00 20 85 12 a8 ca dd 22 7d 74 89 87 |..... ....."}t..|
|
||||
00000080 df 36 23 6e fb 59 c0 75 4b 38 1e 49 d6 fa 5e 8c |.6#n.Y.uK8.I..^.|
|
||||
00000090 cd 6c eb fd 26 34 00 00 00 64 00 00 00 13 65 63 |.l..&4...d....ec|
|
||||
000000a0 64 73 61 2d 73 68 61 32 2d 6e 69 73 74 70 32 35 |dsa-sha2-nistp25|
|
||||
000000b0 36 00 00 00 48 00 00 00 1f 1f dd 4b cc 7e f3 af |6...H......K.~..|
|
||||
000000c0 63 93 77 64 79 a8 77 02 96 98 cb 96 59 a6 a6 a2 |c.wdy.w.....Y...|
|
||||
000000d0 9b 23 08 d0 f5 2e 13 04 00 00 00 21 00 e9 d8 dc |.#.........!....|
|
||||
000000e0 27 de b1 e8 bc ee 5e ca 9e 62 20 09 d3 08 43 f6 |'.....^..b ...C.|
|
||||
000000f0 d0 7d a1 6a f7 6d 64 64 81 ea 63 82 f8 00 00 00 |.}.j.mdd..c.....|
|
||||
000000b0 36 00 00 00 49 00 00 00 21 00 f4 8e 10 b5 77 04 |6...I...!.....w.|
|
||||
000000c0 3e 1b 59 06 4f ef 48 08 2b 15 07 4a 69 0f 30 a2 |>.Y.O.H.+..Ji.0.|
|
||||
000000d0 a4 37 7b 5e f9 de 15 0a ca 1a 00 00 00 20 6a 97 |.7{^......... j.|
|
||||
000000e0 a3 23 e3 7c 92 67 28 0d 02 9e 36 e0 ae b1 f3 37 |.#.|.g(...6....7|
|
||||
000000f0 19 34 12 cd bf db 84 31 8e 97 72 a5 e1 3f 00 00 |.4.....1..r..?..|
|
||||
00000100 00 00 00 00 00 00 00 00 00 00 00 0c 0a 15 00 00 |................|
|
||||
00000110 00 00 00 00 00 00 00 00 00 00 01 40 62 ac b9 7c |...........@b..||
|
||||
00000120 06 dc 0b 16 24 e2 56 cd b2 3a f9 51 ab e8 62 3e |....$.V..:.Q..b>|
|
||||
00000130 72 a8 fa 95 2d af 2d d0 54 e1 de 08 a3 97 11 08 |r...-.-.T.......|
|
||||
00000140 52 6b d5 dd 7e 81 be a5 f9 71 83 9e 68 f8 7e d1 |Rk..~....q..h.~.|
|
||||
00000150 e8 22 8b b3 ff b2 2e 67 16 af d8 df 74 3f bf d6 |.".....g....t?..|
|
||||
00000160 aa 46 3d 49 90 3d fa 12 6a 6f 75 98 1b b8 67 22 |.F=I.=..jou...g"|
|
||||
00000170 d0 06 31 61 eb 29 aa 21 fb 7d e4 7e c7 ff b4 e5 |..1a.).!.}.~....|
|
||||
00000180 a1 0f da 75 74 6f c0 45 31 3f e1 7a 29 d0 ff 25 |...uto.E1?.z)..%|
|
||||
00000190 64 8c 49 5c c5 bf 9c 44 36 67 e1 86 5c e9 13 23 |d.I\...D6g..\..#|
|
||||
000001a0 b8 d5 85 5d 33 4b 19 a5 fa bc 50 86 08 32 08 48 |...]3K....P..2.H|
|
||||
000001b0 5e 0e 2e 68 9a ff 96 6a 00 51 d9 16 87 a6 88 c1 |^..h...j.Q......|
|
||||
000001c0 dd b5 9c 18 3b fc 66 6a ff a7 60 f6 4a 29 f8 5d |....;.fj..`.J).]|
|
||||
000001d0 fd 8d 5e 6a f0 1a 70 21 d6 4e c0 92 e3 95 96 b8 |..^j..p!.N......|
|
||||
000001e0 fa 50 90 58 c5 59 6a 20 12 3d ce d4 49 0e da 2e |.P.X.Yj .=..I...|
|
||||
000001f0 1d 2c b9 28 d1 71 52 49 43 25 90 24 b2 16 a9 58 |.,.(.qRIC%.$...X|
|
||||
00000200 0f f3 07 94 92 83 8e 1a 3f 2a 92 a3 42 80 0e 3c |........?*..B..<|
|
||||
00000210 42 7a 7c 65 3a f0 86 cf 40 49 9b f7 e6 a5 3d 36 |Bz|e:...@I....=6|
|
||||
00000220 f6 ae db 6e 6c 39 cc 5e 47 f4 eb d2 c6 61 5e 61 |...nl9.^G....a^a|
|
||||
00000230 e0 58 6c 16 13 c4 74 db e1 be 29 fc 84 be 42 22 |.Xl...t...)...B"|
|
||||
00000240 14 72 ab 29 f1 ea 10 2c 34 1c 5e d2 a4 19 0d cb |.r.)...,4.^.....|
|
||||
00000250 23 e0 d3 db 4d 5d 50 c7 a0 82 11 ed 1d 49 d3 4e |#...M]P......I.N|
|
||||
00000260 32 be db 14 c1 fc 4b dc 97 3a 38 9b |2.....K..:8.|
|
||||
00000110 00 00 00 00 00 00 00 00 00 00 01 40 03 fb e9 4c |...........@...L|
|
||||
00000120 15 76 5c bf 4b d7 6a 8b 2a 83 6f df bd 5e f6 45 |.v\.K.j.*.o..^.E|
|
||||
00000130 b2 2b bc bf 38 9f f0 30 13 e1 03 67 d3 4f e6 6f |.+..8..0...g.O.o|
|
||||
00000140 88 97 39 8e a6 2d df 6f a7 d2 90 df c2 9a 87 93 |..9..-.o........|
|
||||
00000150 ad 91 12 2e 92 c1 c4 bb 93 b7 7d 6e fd 7c c2 10 |..........}n.|..|
|
||||
00000160 fe fa b6 22 7e a5 a7 64 c4 25 ce cc bb 5d a5 f0 |..."~..d.%...]..|
|
||||
00000170 ad 41 c7 8c a1 59 c3 a9 23 f0 69 38 4a 64 2a a1 |.A...Y..#.i8Jd*.|
|
||||
00000180 62 8d bc 69 1c c1 01 ce ac a9 30 58 a1 d0 68 92 |b..i......0X..h.|
|
||||
00000190 35 e8 7b 3a bf 1b 68 82 f6 90 8e dd 01 e6 92 4b |5.{:..h........K|
|
||||
000001a0 bc ce 50 a8 96 2a 7d a5 4d 61 13 98 67 83 11 70 |..P..*}.Ma..g..p|
|
||||
000001b0 ef f2 af 94 a6 0c 34 78 05 a8 39 d3 44 f6 c4 13 |......4x..9.D...|
|
||||
000001c0 76 59 77 38 72 83 c4 92 a7 4c 7f 5e 25 08 9b a0 |vYw8r....L.^%...|
|
||||
000001d0 6f eb 02 4d 4d c6 0a 07 09 2d c6 80 d3 05 8b c2 |o..MM....-......|
|
||||
000001e0 e7 de 37 16 5a db 1c 02 2e 35 fb 3a 93 ce 79 4e |..7.Z....5.:..yN|
|
||||
000001f0 0c 25 05 c9 b7 be b7 47 31 8c 18 d8 37 ba 66 34 |.%.....G1...7.f4|
|
||||
00000200 bb 03 15 0d 0d cc da ad 2d 2c 36 0f 88 3f 5a 70 |........-,6..?Zp|
|
||||
00000210 21 5f f1 cc 8a 21 e7 5a af c7 7c a0 e3 51 04 4a |!_...!.Z..|..Q.J|
|
||||
00000220 d3 cb bb a4 60 2f d1 28 7b 6f 52 10 e8 76 fa c2 |....`/.({oR..v..|
|
||||
00000230 86 9b 08 3f b2 72 e5 f0 0a 7c e0 19 ce 6f d2 74 |...?.r...|...o.t|
|
||||
00000240 3e 12 8f 7d 1e 21 73 25 57 b8 c9 96 ad 35 f3 b6 |>..}.!s%W....5..|
|
||||
00000250 5f b0 ae 82 90 4b 05 10 de 11 46 ea ad d7 3b 08 |_....K....F...;.|
|
||||
00000260 a6 0d b5 24 f6 e3 ae 3b 67 3c a0 44 |...$...;g<.D|
|
||||
>>> Flow 7 (client to server)
|
||||
00000000 00 00 00 0c 0a 15 62 b8 d2 60 16 9a fa 2f 75 ab |......b..`.../u.|
|
||||
00000010 00 00 00 20 d9 dc 27 14 2c 6d 93 10 bd 87 c5 06 |... ..'.,m......|
|
||||
00000020 90 80 21 40 13 e5 86 f4 39 f1 5b b5 75 ed 31 19 |..!@....9.[.u.1.|
|
||||
00000030 87 05 83 a7 5f 28 81 02 d0 6e b4 f0 bd 89 0a e5 |...._(...n......|
|
||||
00000040 fa 1e ac 07 |....|
|
||||
00000000 00 00 00 0c 0a 15 a1 e3 f9 ae 57 e2 35 b8 cc 87 |..........W.5...|
|
||||
00000010 00 00 00 20 ba d9 4a 00 05 48 df ec d8 c5 bf f8 |... ..J..H......|
|
||||
00000020 7d ed c8 ac a8 5f 1c 46 a0 21 c3 26 7e c6 51 2d |}...._.F.!.&~.Q-|
|
||||
00000030 b8 e8 12 50 38 3a 08 8c a8 0e 98 e7 8c 27 4f 4d |...P8:.......'OM|
|
||||
00000040 76 42 94 1f |vB..|
|
||||
>>> Flow 8 (server to client)
|
||||
00000000 00 00 00 20 03 52 b6 aa 7d 30 65 ad 08 b8 dd d1 |... .R..}0e.....|
|
||||
00000010 7f f0 3e b5 69 43 fa 0f 06 2a 18 5d 9d 4e b0 13 |..>.iC...*.].N..|
|
||||
00000020 d8 4a 06 ca e1 d7 99 f9 59 14 d0 ef 0b a1 1a 47 |.J......Y......G|
|
||||
00000030 8f c5 4b e5 |..K.|
|
||||
00000000 00 00 00 20 53 c2 11 dc 60 cb f1 e0 55 eb f8 50 |... S...`...U..P|
|
||||
00000010 38 11 aa 98 fc 4c 2a d1 36 0f 57 c2 c9 55 cb 04 |8....L*.6.W..U..|
|
||||
00000020 dc 2f 79 36 28 5d fa 67 08 01 0a 1b fc a5 57 cd |./y6(].g......W.|
|
||||
00000030 7f 67 ea 81 |.g..|
|
||||
>>> Flow 9 (client to server)
|
||||
00000000 00 00 00 30 34 a3 2c 36 49 de 9d 6c 4b 74 c4 0d |...04.,6I..lKt..|
|
||||
00000010 2d 25 98 e4 6b 48 58 c5 e0 e6 04 90 31 11 59 4f |-%..kHX.....1.YO|
|
||||
00000020 f0 33 8d e8 1a 9b e9 b5 02 fb 26 32 0e 5a 09 7b |.3........&2.Z.{|
|
||||
00000030 5f 2a 80 dd 72 17 cd ed cb 54 ca 3b 50 44 ed 1f |_*..r....T.;PD..|
|
||||
00000040 d4 4b b4 9b |.K..|
|
||||
00000000 00 00 00 30 c5 dd dd 05 d4 df 9e 48 d6 58 76 a1 |...0.......H.Xv.|
|
||||
00000010 8a 7e 04 c6 51 26 44 1a cb 85 8b 9a 51 44 bd 57 |.~..Q&D.....QD.W|
|
||||
00000020 bc 4f 2e a0 0a b9 e0 ee 00 b6 57 d3 2f 52 71 8e |.O........W./Rq.|
|
||||
00000030 b6 4e f6 f7 34 7c 9f fe c7 c7 ec ca 08 6f d9 b0 |.N..4|.......o..|
|
||||
00000040 e3 85 81 49 |...I|
|
||||
>>> Flow 10 (server to client)
|
||||
00000000 00 00 00 20 7e c0 e9 9e 89 d7 16 2d 48 c0 e0 bf |... ~......-H...|
|
||||
00000010 dd c3 89 1e 08 3e ee ab 73 77 77 2e 5a 62 14 02 |.....>..sww.Zb..|
|
||||
00000020 6a 7f c2 e9 19 c0 df 69 43 60 82 d6 ea ff da f0 |j......iC`......|
|
||||
00000030 fa 40 2b b6 00 00 00 40 3a 06 de c5 ac 63 46 77 |.@+....@:....cFw|
|
||||
00000040 a8 8e a1 d0 be 35 cb 27 34 d1 63 a1 0c b2 c3 30 |.....5.'4.c....0|
|
||||
00000050 c6 d8 bd 92 7a f7 48 4b 95 a5 5f 6e 4e ca 6f 60 |....z.HK.._nN.o`|
|
||||
00000060 32 11 4d d0 15 2e 31 22 03 1a 89 fa 91 e0 ea 10 |2.M...1"........|
|
||||
00000070 7b e4 4e d8 a8 a7 a4 35 3c b0 76 39 6e e9 ef c9 |{.N....5<.v9n...|
|
||||
00000080 69 02 c8 01 51 bc fb ad |i...Q...|
|
||||
00000000 00 00 00 20 4e d8 10 08 39 ab 47 f6 49 42 4e bd |... N...9.G.IBN.|
|
||||
00000010 2f 69 f7 bc 48 26 1b 5f ee ee 08 25 2e b8 8d 1f |/i..H&._...%....|
|
||||
00000020 a0 e0 fa 11 28 26 9c af f0 6b 7e e0 f0 00 8f 92 |....(&...k~.....|
|
||||
00000030 08 96 73 64 00 00 00 40 60 bb 40 d2 c4 8f 5e 09 |..sd...@`.@...^.|
|
||||
00000040 e6 d9 13 04 fc 4e 21 81 51 dc ad 06 48 51 fc 35 |.....N!.Q...HQ.5|
|
||||
00000050 b2 cd bb ba df 66 c4 20 b1 c0 b0 7e 7b c0 a7 41 |.....f. ...~{..A|
|
||||
00000060 6f 16 7a fe 01 fe 3a be 45 4a b9 94 d1 46 a1 82 |o.z...:.EJ...F..|
|
||||
00000070 09 24 97 57 17 83 9e e6 1b 4e 04 83 a0 73 55 08 |.$.W.....N...sU.|
|
||||
00000080 2f e6 de 6b 43 77 84 31 |/..kCw.1|
|
||||
>>> Flow 11 (client to server)
|
||||
00000000 00 00 01 60 3a fe b0 e3 19 9e ef b8 4b 47 ac 18 |...`:.......KG..|
|
||||
00000010 52 0f 93 e5 04 69 58 d5 51 b9 82 ab 56 41 5c 73 |R....iX.Q...VA\s|
|
||||
00000020 e2 e7 d1 98 41 f2 73 30 13 b5 7d ca 0e 0d 78 7b |....A.s0..}...x{|
|
||||
00000030 01 83 ab e7 ce 1d 3b 8c 14 ed c5 0d 39 cf 82 f3 |......;.....9...|
|
||||
00000040 f6 eb 9e 17 c4 36 61 78 5b 50 66 2d 8c 37 cf fb |.....6ax[Pf-.7..|
|
||||
00000050 42 44 45 fc 94 a8 e2 d2 9e 5e 5f 12 85 f2 4a 46 |BDE......^_...JF|
|
||||
00000060 50 fc 5c 04 80 2e 17 ce 7e f2 a6 ee 94 7c e7 99 |P.\.....~....|..|
|
||||
00000070 6c a3 b3 5d 08 23 f6 10 6f 79 8b a0 56 20 d3 ed |l..].#..oy..V ..|
|
||||
00000080 e0 44 07 fb dc d3 b6 64 5b c2 d4 66 77 3e 39 a2 |.D.....d[..fw>9.|
|
||||
00000090 57 4b 44 95 96 33 4b 51 51 40 3f f0 9a db 95 96 |WKD..3KQQ@?.....|
|
||||
000000a0 41 3c f2 d6 7c d3 bb 6b a5 b1 b3 67 0b 94 38 e1 |A<..|..k...g..8.|
|
||||
000000b0 4d e5 68 68 f4 e0 93 57 d7 01 7b 4d 9c 8c 18 32 |M.hh...W..{M...2|
|
||||
000000c0 44 3a 93 7b 38 3b 19 0f 63 98 04 15 22 1e ce 09 |D:.{8;..c..."...|
|
||||
000000d0 db f5 80 2e 42 bb 22 59 9d 04 05 7e 67 32 c8 52 |....B."Y...~g2.R|
|
||||
000000e0 9f 2d d0 02 e9 ad d0 7f 1d b3 f8 64 f2 4b ff 03 |.-.........d.K..|
|
||||
000000f0 56 6b 28 b5 bb 2e 3c eb 47 5b 95 96 26 64 8a 8e |Vk(...<.G[..&d..|
|
||||
00000100 96 e6 fe bd ee 71 e7 53 6b 27 a6 b7 38 ba 8c 5b |.....q.Sk'..8..[|
|
||||
00000110 14 14 08 ec 59 e7 a5 42 b4 0e 0e 39 09 c1 25 bc |....Y..B...9..%.|
|
||||
00000120 6f 9b 94 85 14 ae 76 6c 94 f2 58 d5 ad 73 01 fc |o.....vl..X..s..|
|
||||
00000130 f1 6c 0d e7 13 f1 9b 86 54 33 b3 d2 c0 78 3e 9b |.l......T3...x>.|
|
||||
00000140 fb aa e2 ce c8 1f 3e f5 19 2e 22 78 fb 02 4d ab |......>..."x..M.|
|
||||
00000150 49 52 3e 17 6c 22 a7 4a 19 aa 68 a1 12 d6 24 4e |IR>.l".J..h...$N|
|
||||
00000160 e7 0d 39 cc a5 1a 90 f6 26 15 75 9f 80 88 74 11 |..9.....&.u...t.|
|
||||
00000170 9f d8 2b 2e |..+.|
|
||||
00000000 00 00 01 60 f2 7d b2 4f d9 db ec 78 6b a2 c2 77 |...`.}.O...xk..w|
|
||||
00000010 6a a1 f8 d0 3c 5c e0 3b d3 99 33 ac 54 4b f7 e2 |j...<\.;..3.TK..|
|
||||
00000020 3d 1f 6e 51 6f 4c c2 7e d5 3a 79 1e 9f 51 70 75 |=.nQoL.~.:y..Qpu|
|
||||
00000030 67 35 8c f8 5d 62 35 9a ff fe b2 46 6f 72 47 0b |g5..]b5....ForG.|
|
||||
00000040 5b 78 30 5b ce 54 5c ab 46 a4 a5 12 8b ef 32 2e |[x0[.T\.F.....2.|
|
||||
00000050 1e a9 4a 25 07 9e a3 87 42 f9 69 ae c6 9d 83 68 |..J%....B.i....h|
|
||||
00000060 e8 dd 19 a3 ef 4e 97 c9 ef 19 be a7 08 77 28 7d |.....N.......w(}|
|
||||
00000070 ee aa b4 a4 3a e5 c1 4e 78 ee b2 b7 50 6d f2 eb |....:..Nx...Pm..|
|
||||
00000080 2b df 38 22 a3 c9 be f7 ea 36 2f 7d f7 25 fd f4 |+.8".....6/}.%..|
|
||||
00000090 9f 54 ec cf d5 82 5c 4b e5 e0 3f 74 da 9d d0 32 |.T....\K..?t...2|
|
||||
000000a0 06 f6 a1 13 15 f4 11 24 e9 74 4c 9b 5e e2 c8 5b |.......$.tL.^..[|
|
||||
000000b0 32 6b 89 87 d4 d4 ee e3 0c 81 16 d4 54 b7 97 ef |2k..........T...|
|
||||
000000c0 c6 a4 d7 16 2d 87 be 2c 19 b8 48 9d d6 82 3c 82 |....-..,..H...<.|
|
||||
000000d0 88 de bc 18 5b 64 ab aa d7 ac 8b 64 6a ad a8 4d |....[d.....dj..M|
|
||||
000000e0 5a 20 a3 6e ee 7b 7f bf dc 6d 69 6a b0 8b ee 26 |Z .n.{...mij...&|
|
||||
000000f0 0b 34 f0 22 a6 81 0f d3 b5 15 e8 86 1b 71 1a 60 |.4.".........q.`|
|
||||
00000100 16 dc 2f 6b ca 63 6c 52 b3 33 42 46 c0 ea 63 50 |../k.clR.3BF..cP|
|
||||
00000110 bb 23 29 69 79 0c 23 3f fb da 29 dd 94 44 f1 7e |.#)iy.#?..)..D.~|
|
||||
00000120 58 1c 12 0f df a7 80 3c 69 8a 44 f7 4d 2e 7b db |X......<i.D.M.{.|
|
||||
00000130 c2 5a 01 c0 0c 57 8e ff 4f 98 74 71 c3 3b 61 fc |.Z...W..O.tq.;a.|
|
||||
00000140 1b e6 fb 4c 75 33 ff 6b 0e 83 52 40 4a 7f 35 2f |...Lu3.k..R@J.5/|
|
||||
00000150 82 38 40 22 22 bc 51 6e 21 ce f9 bb 02 bf 26 a5 |.8@"".Qn!.....&.|
|
||||
00000160 63 9b 91 c3 37 46 6d f6 fe 19 27 5f 91 68 a7 29 |c...7Fm...'_.h.)|
|
||||
00000170 b7 00 27 37 |..'7|
|
||||
>>> Flow 12 (server to client)
|
||||
00000000 00 00 01 40 07 30 22 23 53 70 62 fd 53 15 21 49 |...@.0"#Spb.S.!I|
|
||||
00000010 b7 ff 50 fc c0 4e 4d 8f ef 4b 09 8a 9f e0 0e de |..P..NM..K......|
|
||||
00000020 de 3d 06 cf e2 8c f1 cc 92 c4 84 78 6f 1e 4a cd |.=.........xo.J.|
|
||||
00000030 8b 8a 61 a9 ff 6e 3c c2 3c d0 0e 70 5d 6e 4e 40 |..a..n<.<..p]nN@|
|
||||
00000040 c0 8a 4f 3b e4 25 05 15 21 63 09 fd f7 fd ee d9 |..O;.%..!c......|
|
||||
00000050 92 10 e1 e6 6a 27 ae ff fe 1e 66 7a 00 e7 27 95 |....j'....fz..'.|
|
||||
00000060 d2 fe 32 5f f8 79 89 ea 25 19 62 44 04 aa 84 8c |..2_.y..%.bD....|
|
||||
00000070 2b 46 b4 73 e3 4f 9b d9 bd 39 7d 13 91 5c 55 44 |+F.s.O...9}..\UD|
|
||||
00000080 70 67 8e 50 5b 12 23 b4 39 82 cd 15 ac 77 91 bf |pg.P[.#.9....w..|
|
||||
00000090 4d ea d7 4c e2 ef 7b 0a f6 4e 77 aa 47 49 fd a2 |M..L..{..Nw.GI..|
|
||||
000000a0 bd ae 0e 06 d8 23 df f2 c7 62 8a c0 13 24 3e 30 |.....#...b...$>0|
|
||||
000000b0 5d ba 3e e1 3f 5d 80 34 54 ab e0 00 7c 61 5b 17 |].>.?].4T...|a[.|
|
||||
000000c0 23 c6 7e c6 d2 d1 01 0a 32 a5 d5 85 3e ec dd a8 |#.~.....2...>...|
|
||||
000000d0 13 dc 52 e8 c4 85 56 04 3d 98 2d 72 6a f2 bb 52 |..R...V.=.-rj..R|
|
||||
000000e0 ae f0 86 ff 99 9e a9 b9 23 4c 27 65 41 5b 27 37 |........#L'eA['7|
|
||||
000000f0 93 ee ac 33 f8 c9 23 e9 3e 5a 4d d3 58 51 e8 e4 |...3..#.>ZM.XQ..|
|
||||
00000100 7e 3f 45 d3 d0 02 ab 5b 9d 12 5d 16 34 7b 01 dd |~?E....[..].4{..|
|
||||
00000110 fb 77 cf 24 55 f5 0d 00 56 9c 94 4c 96 af eb 68 |.w.$U...V..L...h|
|
||||
00000120 af 80 d8 20 8a 7f 26 6b ec 47 64 0c 9d 05 9c 8f |... ..&k.Gd.....|
|
||||
00000130 93 3a 2c 89 81 ae 37 6f f5 53 43 19 cf 7d c7 95 |.:,...7o.SC..}..|
|
||||
00000140 6d f1 25 ff c1 8f 26 5b 4f b1 a0 99 cf 29 b7 cc |m.%...&[O....)..|
|
||||
00000150 72 b2 49 83 |r.I.|
|
||||
00000000 00 00 01 40 ed 8c ad 60 63 f2 de d8 77 4e ea e5 |...@...`c...wN..|
|
||||
00000010 7f 0e e7 65 d5 07 51 66 b5 f6 60 1f ba f0 00 59 |...e..Qf..`....Y|
|
||||
00000020 ed b3 87 97 9f 52 71 a1 60 9b 3b ef 16 5c 69 2b |.....Rq.`.;..\i+|
|
||||
00000030 73 1b 35 01 61 52 d6 36 50 5b 61 04 da e3 eb 2f |s.5.aR.6P[a..../|
|
||||
00000040 b1 5f e4 b2 20 fa f9 52 76 ff 90 66 fe 69 98 26 |._.. ..Rv..f.i.&|
|
||||
00000050 c2 72 9f 93 aa e3 bb 9a b4 28 62 e3 ea 7f 94 c6 |.r.......(b.....|
|
||||
00000060 92 e3 2a 81 99 6c 08 f1 df 99 dc d1 a0 cd d0 e6 |..*..l..........|
|
||||
00000070 31 21 7b d4 c0 e7 85 66 2c 3f 0e 9e 8f 8b 49 11 |1!{....f,?....I.|
|
||||
00000080 64 6b 61 c4 39 15 d2 c0 83 76 f5 cf f5 5d 0c dc |dka.9....v...]..|
|
||||
00000090 03 37 22 a7 fa f5 3c 8b b2 a4 2f 1b c3 57 7f 9a |.7"...<.../..W..|
|
||||
000000a0 4b eb 80 dc e2 17 fd 8f 55 90 b9 03 2d 7f 1e e8 |K.......U...-...|
|
||||
000000b0 5a 2b 08 57 76 a1 c7 7b 46 97 68 6e af b4 42 8a |Z+.Wv..{F.hn..B.|
|
||||
000000c0 ea 13 b1 d7 7a 88 c1 f1 9d 45 ec 41 aa ed ef a0 |....z....E.A....|
|
||||
000000d0 40 3b b8 74 e4 80 88 a9 6a bf d4 a8 9c 27 3d 21 |@;.t....j....'=!|
|
||||
000000e0 65 8f 28 8a e5 4e 33 a7 fd 9b 78 08 07 ee d0 cf |e.(..N3...x.....|
|
||||
000000f0 51 f9 b7 5c e3 6c cb 07 5a 74 55 f6 0f ef 42 2b |Q..\.l..ZtU...B+|
|
||||
00000100 da 28 ac 34 e7 70 64 9b 4d 35 dd a0 d6 94 4f 48 |.(.4.pd.M5....OH|
|
||||
00000110 d0 91 d5 6b 36 64 9e ce 88 c7 07 9b b7 c4 2e e3 |...k6d..........|
|
||||
00000120 3b a9 0e 2e b2 63 f6 f6 0c 38 48 71 a0 a4 de 1b |;....c...8Hq....|
|
||||
00000130 42 61 82 1e d8 1f d0 6b 83 71 ff e8 d5 c6 bc 7b |Ba.....k.q.....{|
|
||||
00000140 ee 53 5b 87 b5 38 cf 07 5d 73 6e 59 cb d5 d7 d6 |.S[..8..]snY....|
|
||||
00000150 bc 76 4e e8 |.vN.|
|
||||
>>> Flow 13 (client to server)
|
||||
00000000 00 00 02 80 28 72 8e 75 6f ff ec ad 60 fe ff b9 |....(r.uo...`...|
|
||||
00000010 e9 92 32 54 9f 41 16 05 7d ea 7d 65 36 d9 90 d1 |..2T.A..}.}e6...|
|
||||
00000020 e1 0b 5d 7c c9 86 08 de 9b fb 7d 45 6f 08 3f b0 |..]|......}Eo.?.|
|
||||
00000030 74 54 75 53 0f d2 03 fa d8 d4 d7 98 db e3 ed 2c |tTuS...........,|
|
||||
00000040 76 21 10 53 84 ed 08 53 98 50 5b 93 38 cd 82 35 |v!.S...S.P[.8..5|
|
||||
00000050 f3 f6 06 cb fd 67 06 4f 4c a9 86 1a bd 27 40 77 |.....g.OL....'@w|
|
||||
00000060 87 04 da b8 d5 3a bc c6 18 4b 41 54 d4 bc fc 49 |.....:...KAT...I|
|
||||
00000070 26 e0 4b e1 e9 3b 1a 05 c9 22 94 8e 52 40 30 1d |&.K..;..."..R@0.|
|
||||
00000080 bb 53 c6 96 2a 38 24 3b e1 23 4d 9f 53 27 b1 3b |.S..*8$;.#M.S'.;|
|
||||
00000090 39 49 89 a8 d3 02 59 90 fa ee 6f e1 63 d1 6a 86 |9I....Y...o.c.j.|
|
||||
000000a0 c0 c0 f0 78 2f 5c d7 19 42 59 9d 72 03 96 f8 cd |...x/\..BY.r....|
|
||||
000000b0 d1 4f 0a 7f c2 e7 cb 87 6e 9a 68 45 05 03 b5 66 |.O......n.hE...f|
|
||||
000000c0 4f d1 de 9b 97 b4 79 d3 ad b9 b9 ab 49 9a fb 38 |O.....y.....I..8|
|
||||
000000d0 1e cc bb ce 8a 14 f5 0c 4b b5 6e ce 87 18 d0 bd |........K.n.....|
|
||||
000000e0 4f 57 28 bf a5 06 1a d2 85 92 61 45 d8 38 c4 5b |OW(.......aE.8.[|
|
||||
000000f0 6e 0e 65 64 4e e9 dc f6 a4 2c 1c 31 c5 d9 28 fd |n.edN....,.1..(.|
|
||||
00000100 71 19 c3 2b f0 23 6f f7 c8 2a 6e 4d 1d 5c 93 94 |q..+.#o..*nM.\..|
|
||||
00000110 ff 9b 5f 33 7f 6c 18 e2 de f4 08 ea 99 ac 83 39 |.._3.l.........9|
|
||||
00000120 25 6c 16 eb 7f da 70 f8 9e 89 76 5f 4c b1 86 6f |%l....p...v_L..o|
|
||||
00000130 0e 0e cb 62 af dc 35 e4 20 83 7e e3 37 ca 67 2e |...b..5. .~.7.g.|
|
||||
00000140 9c e3 97 e3 d0 09 fd 6a 1c 70 e0 ca c8 a4 1e 9d |.......j.p......|
|
||||
00000150 67 10 07 ef ec 98 c9 7e c2 b2 7f f6 ba 30 34 e0 |g......~.....04.|
|
||||
00000160 a7 1c da 9b cf f5 5b 11 5a 43 97 47 ad e6 d7 da |......[.ZC.G....|
|
||||
00000170 28 4a 17 92 58 1a ae a7 c2 29 2c 29 5c c4 fd 41 |(J..X....),)\..A|
|
||||
00000180 43 99 27 dc a9 5a 06 fd d8 50 36 95 73 42 8a e6 |C.'..Z...P6.sB..|
|
||||
00000190 a9 9b 66 a6 d4 b6 56 4b 3e b7 a5 cb f4 82 e6 93 |..f...VK>.......|
|
||||
000001a0 40 e6 f2 0c ed d5 d0 bf be 30 5a 3c c2 18 9f 8d |@........0Z<....|
|
||||
000001b0 35 f8 d8 26 60 a4 84 d8 3b 22 96 ad 58 6e 62 15 |5..&`...;"..Xnb.|
|
||||
000001c0 aa 23 66 4b d7 78 63 7a 95 02 41 45 9d 70 47 ef |.#fK.xcz..AE.pG.|
|
||||
000001d0 54 0e 60 61 9a 18 f9 6e 1e e4 35 55 ef cf d2 33 |T.`a...n..5U...3|
|
||||
000001e0 92 0f 28 a2 74 81 c1 62 4e 14 a3 6a 4b b1 d7 32 |..(.t..bN..jK..2|
|
||||
000001f0 95 3a e8 4b 00 61 19 3a 57 a0 a0 a6 a2 85 3d d9 |.:.K.a.:W.....=.|
|
||||
00000200 47 5f 79 26 c6 21 c3 94 27 c2 9e 57 57 2f 43 1a |G_y&.!..'..WW/C.|
|
||||
00000210 5e ea da 9b c3 69 29 90 d4 17 63 41 4b 24 cc ed |^....i)...cAK$..|
|
||||
00000220 37 3c d2 d3 4a 87 29 25 4a 83 03 0f 48 9e 86 80 |7<..J.)%J...H...|
|
||||
00000230 54 e1 01 df 83 8c 83 49 c1 18 ff a8 22 12 73 da |T......I....".s.|
|
||||
00000240 e9 d7 d1 76 04 74 f3 eb 6e f8 15 07 92 21 67 28 |...v.t..n....!g(|
|
||||
00000250 b9 9f 07 71 e5 83 78 1f 27 6e 92 82 48 7b 70 ce |...q..x.'n..H{p.|
|
||||
00000260 46 d9 e3 6a e2 9c 77 cf 45 e3 5f e5 ab 44 ca 51 |F..j..w.E._..D.Q|
|
||||
00000270 ea 40 81 4a 85 89 0d 7c ab 4d 09 81 2e d7 7d 3e |.@.J...|.M....}>|
|
||||
00000280 fc 43 ca ad 9f 4f fc f4 52 cb 4e 40 97 9f e4 3d |.C...O..R.N@...=|
|
||||
00000290 ef 02 58 d5 |..X.|
|
||||
00000000 00 00 02 80 62 66 4c ce e6 ed b9 56 ed 11 4a 46 |....bfL....V..JF|
|
||||
00000010 93 45 c7 16 71 c0 e2 c4 fc bf 06 58 fb 20 3d ca |.E..q......X. =.|
|
||||
00000020 2f 85 8f 6f da 51 9a 0d 90 3e 0b e0 af d5 00 5d |/..o.Q...>.....]|
|
||||
00000030 f2 17 db fb 3c e9 4a 93 df a7 f2 a9 e1 d0 65 33 |....<.J.......e3|
|
||||
00000040 18 f2 45 09 28 4e eb d2 58 22 b7 9e a9 df b4 48 |..E.(N..X".....H|
|
||||
00000050 8e 60 e0 b3 b6 78 e9 e5 1c 37 26 1a a1 82 4b e8 |.`...x...7&...K.|
|
||||
00000060 c3 9d 06 69 f5 13 59 18 2a 78 f6 2c 36 f0 96 0a |...i..Y.*x.,6...|
|
||||
00000070 99 c5 f0 90 de 38 c4 58 b7 0d 42 0f e1 5d 11 2f |.....8.X..B..]./|
|
||||
00000080 1f 56 da d6 d9 94 86 68 df bb 4b df ce ea 31 86 |.V.....h..K...1.|
|
||||
00000090 32 cc 7f 50 75 ac 03 f3 48 c1 7b 58 7f db f8 3b |2..Pu...H.{X...;|
|
||||
000000a0 5e 02 79 9d 59 38 9d 7f 7c ee 24 8b a1 22 92 a0 |^.y.Y8..|.$.."..|
|
||||
000000b0 a1 52 2a 09 3a a1 b8 fb 3e be 40 63 7d af cf 21 |.R*.:...>.@c}..!|
|
||||
000000c0 c8 a0 b6 86 94 af d8 bc 21 3b 83 77 55 c4 0a d0 |........!;.wU...|
|
||||
000000d0 8e ea 4b 19 04 e7 88 2d 6f ff 9f 79 32 8a 7a 7d |..K....-o..y2.z}|
|
||||
000000e0 20 09 9b 52 05 d7 a2 95 53 0d 7b 57 b0 92 be 0e | ..R....S.{W....|
|
||||
000000f0 52 c2 0e c2 71 a4 d2 67 f5 80 e9 89 7b 6c d1 ea |R...q..g....{l..|
|
||||
00000100 7c 83 f1 af 13 3e b6 69 62 e7 10 ed 75 c8 f8 cf ||....>.ib...u...|
|
||||
00000110 60 07 d8 9a 46 e6 4f b4 22 f2 f7 ca ba ed 36 f9 |`...F.O.".....6.|
|
||||
00000120 f3 ac a9 e0 f3 e5 37 b0 b0 7d 23 ed b9 7f 1f b3 |......7..}#.....|
|
||||
00000130 57 38 7c c3 34 b0 78 a5 e8 29 a9 cb 35 17 68 4d |W8|.4.x..)..5.hM|
|
||||
00000140 dd 8f 35 9c f1 b5 e6 e6 29 00 3b 1c ac 5d d0 cd |..5.....).;..]..|
|
||||
00000150 1f a0 a8 a1 25 b0 97 53 ed 9a 72 a8 f0 61 0b 66 |....%..S..r..a.f|
|
||||
00000160 2c 67 c9 e1 dd 86 6a 14 54 00 7b 90 7e 3c d2 5c |,g....j.T.{.~<.\|
|
||||
00000170 d8 d3 a2 a0 cd c9 b2 82 8f 48 a0 22 49 63 54 6d |.........H."IcTm|
|
||||
00000180 9f 04 f9 47 27 db 4f 3d 41 82 4a 1a be 4a b7 2f |...G'.O=A.J..J./|
|
||||
00000190 81 c5 ad 12 cc 1e 45 f8 bb 42 93 ea 4b 24 97 44 |......E..B..K$.D|
|
||||
000001a0 6b c4 4c 4d f4 61 08 0c a3 37 20 48 d3 be 47 71 |k.LM.a...7 H..Gq|
|
||||
000001b0 1b b2 8a a1 eb 9f b9 17 61 07 64 15 29 6e fc 93 |........a.d.)n..|
|
||||
000001c0 7d 21 fd 7d f2 09 6b 9c 5f 05 79 2b dc e0 c6 d4 |}!.}..k._.y+....|
|
||||
000001d0 03 d4 9e 23 f2 3e 4b 23 11 5e 58 ec a8 5e 96 63 |...#.>K#.^X..^.c|
|
||||
000001e0 6d 51 22 d5 3e e3 de ee 1a c5 d5 85 c3 c5 c4 05 |mQ".>...........|
|
||||
000001f0 38 4c bd 54 b4 1e 6a 64 5a 9a 3e 48 82 ec e7 fe |8L.T..jdZ.>H....|
|
||||
00000200 6a 67 a5 30 c0 fc fd c6 7e d4 d0 68 a7 30 40 e0 |jg.0....~..h.0@.|
|
||||
00000210 87 c1 5d 75 0b a0 4f 90 f7 46 51 18 8b 02 36 c5 |..]u..O..FQ...6.|
|
||||
00000220 fb b5 54 bd 32 75 dc 63 84 6f 61 a5 36 fe a6 23 |..T.2u.c.oa.6..#|
|
||||
00000230 f8 a5 b9 cc af 00 e4 83 c0 11 50 ad 81 2b e2 bd |..........P..+..|
|
||||
00000240 20 08 85 11 40 5e 66 25 d8 ac 06 a3 a2 10 dc 52 | ...@^f%.......R|
|
||||
00000250 7a d5 13 61 82 b5 48 83 02 32 7b 20 96 78 40 14 |z..a..H..2{ .x@.|
|
||||
00000260 38 10 9f 88 25 d3 60 3c 7e e4 11 da a9 6e 1e 58 |8...%.`<~....n.X|
|
||||
00000270 13 de d8 d4 74 78 b2 5f 8c ce 9c ce 33 5c 1a 6e |....tx._....3\.n|
|
||||
00000280 76 56 49 a4 54 0c ab 20 b9 c6 20 d4 fa b8 6f 41 |vVI.T.. .. ...oA|
|
||||
00000290 81 1a 7e f4 |..~.|
|
||||
>>> Flow 14 (server to client)
|
||||
00000000 00 00 00 10 bc 56 ff 49 8f 1b c2 79 5b 65 67 84 |.....V.I...y[eg.|
|
||||
00000010 fb 19 0c 51 ef 4f 2c e8 58 01 84 90 5c 31 78 d4 |...Q.O,.X...\1x.|
|
||||
00000020 ab 3e cb 21 |.>.!|
|
||||
00000000 00 00 00 10 6e 70 e8 37 1b 64 e5 98 df 83 52 b2 |....np.7.d....R.|
|
||||
00000010 40 ca 82 24 96 8c 21 c4 df d2 ec a8 d8 c7 b1 48 |@..$..!........H|
|
||||
00000020 c2 48 90 90 |.H..|
|
||||
|
||||
+258
-257
@@ -2,54 +2,55 @@
|
||||
00000000 53 53 48 2d 32 2e 30 2d 47 6f 0d 0a |SSH-2.0-Go..|
|
||||
>>> Flow 2 (client to server)
|
||||
00000000 53 53 48 2d 32 2e 30 2d 4f 70 65 6e 53 53 48 5f |SSH-2.0-OpenSSH_|
|
||||
00000010 39 2e 39 0d 0a |9.9..|
|
||||
00000010 31 30 2e 30 0d 0a |10.0..|
|
||||
>>> Flow 3 (server to client)
|
||||
00000000 00 00 02 5c 12 14 7f 9c 2b a4 e8 8f 82 7d 61 60 |...\....+....}a`|
|
||||
00000010 45 50 76 05 85 3e 00 00 00 2e 63 75 72 76 65 32 |EPv..>....curve2|
|
||||
00000020 35 35 31 39 2d 73 68 61 32 35 36 2c 6b 65 78 2d |5519-sha256,kex-|
|
||||
00000030 73 74 72 69 63 74 2d 73 2d 76 30 30 40 6f 70 65 |strict-s-v00@ope|
|
||||
00000040 6e 73 73 68 2e 63 6f 6d 00 00 00 21 72 73 61 2d |nssh.com...!rsa-|
|
||||
00000050 73 68 61 32 2d 32 35 36 2c 72 73 61 2d 73 68 61 |sha2-256,rsa-sha|
|
||||
00000060 32 2d 35 31 32 2c 73 73 68 2d 72 73 61 00 00 00 |2-512,ssh-rsa...|
|
||||
00000070 6c 61 65 73 31 32 38 2d 67 63 6d 40 6f 70 65 6e |laes128-gcm@open|
|
||||
00000080 73 73 68 2e 63 6f 6d 2c 61 65 73 32 35 36 2d 67 |ssh.com,aes256-g|
|
||||
00000090 63 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 63 |cm@openssh.com,c|
|
||||
000000a0 68 61 63 68 61 32 30 2d 70 6f 6c 79 31 33 30 35 |hacha20-poly1305|
|
||||
000000b0 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 61 65 73 |@openssh.com,aes|
|
||||
000000c0 31 32 38 2d 63 74 72 2c 61 65 73 31 39 32 2d 63 |128-ctr,aes192-c|
|
||||
000000d0 74 72 2c 61 65 73 32 35 36 2d 63 74 72 00 00 00 |tr,aes256-ctr...|
|
||||
000000e0 6c 61 65 73 31 32 38 2d 67 63 6d 40 6f 70 65 6e |laes128-gcm@open|
|
||||
000000f0 73 73 68 2e 63 6f 6d 2c 61 65 73 32 35 36 2d 67 |ssh.com,aes256-g|
|
||||
00000100 63 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 63 |cm@openssh.com,c|
|
||||
00000110 68 61 63 68 61 32 30 2d 70 6f 6c 79 31 33 30 35 |hacha20-poly1305|
|
||||
00000120 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 61 65 73 |@openssh.com,aes|
|
||||
00000130 31 32 38 2d 63 74 72 2c 61 65 73 31 39 32 2d 63 |128-ctr,aes192-c|
|
||||
00000140 74 72 2c 61 65 73 32 35 36 2d 63 74 72 00 00 00 |tr,aes256-ctr...|
|
||||
00000150 6e 68 6d 61 63 2d 73 68 61 32 2d 32 35 36 2d 65 |nhmac-sha2-256-e|
|
||||
00000160 74 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 |tm@openssh.com,h|
|
||||
00000170 6d 61 63 2d 73 68 61 32 2d 35 31 32 2d 65 74 6d |mac-sha2-512-etm|
|
||||
00000180 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 6d 61 |@openssh.com,hma|
|
||||
00000190 63 2d 73 68 61 32 2d 32 35 36 2c 68 6d 61 63 2d |c-sha2-256,hmac-|
|
||||
000001a0 73 68 61 32 2d 35 31 32 2c 68 6d 61 63 2d 73 68 |sha2-512,hmac-sh|
|
||||
000001b0 61 31 2c 68 6d 61 63 2d 73 68 61 31 2d 39 36 00 |a1,hmac-sha1-96.|
|
||||
000001c0 00 00 6e 68 6d 61 63 2d 73 68 61 32 2d 32 35 36 |..nhmac-sha2-256|
|
||||
000001d0 2d 65 74 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d |-etm@openssh.com|
|
||||
000001e0 2c 68 6d 61 63 2d 73 68 61 32 2d 35 31 32 2d 65 |,hmac-sha2-512-e|
|
||||
000001f0 74 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 |tm@openssh.com,h|
|
||||
00000200 6d 61 63 2d 73 68 61 32 2d 32 35 36 2c 68 6d 61 |mac-sha2-256,hma|
|
||||
00000210 63 2d 73 68 61 32 2d 35 31 32 2c 68 6d 61 63 2d |c-sha2-512,hmac-|
|
||||
00000220 73 68 61 31 2c 68 6d 61 63 2d 73 68 61 31 2d 39 |sha1,hmac-sha1-9|
|
||||
00000230 36 00 00 00 04 6e 6f 6e 65 00 00 00 04 6e 6f 6e |6....none....non|
|
||||
00000240 65 00 00 00 00 00 00 00 00 00 00 00 00 00 d7 3b |e..............;|
|
||||
00000250 80 93 f6 ef bc 88 eb 1a 6e ac fa 66 ef 26 3c b1 |........n..f.&<.|
|
||||
00000000 00 00 02 6c 05 14 7f 9c 2b a4 e8 8f 82 7d 61 60 |...l....+....}a`|
|
||||
00000010 45 50 76 05 85 3e 00 00 00 4b 63 75 72 76 65 32 |EPv..>...Kcurve2|
|
||||
00000020 35 35 31 39 2d 73 68 61 32 35 36 2c 63 75 72 76 |5519-sha256,curv|
|
||||
00000030 65 32 35 35 31 39 2d 73 68 61 32 35 36 40 6c 69 |e25519-sha256@li|
|
||||
00000040 62 73 73 68 2e 6f 72 67 2c 6b 65 78 2d 73 74 72 |bssh.org,kex-str|
|
||||
00000050 69 63 74 2d 73 2d 76 30 30 40 6f 70 65 6e 73 73 |ict-s-v00@openss|
|
||||
00000060 68 2e 63 6f 6d 00 00 00 21 72 73 61 2d 73 68 61 |h.com...!rsa-sha|
|
||||
00000070 32 2d 32 35 36 2c 72 73 61 2d 73 68 61 32 2d 35 |2-256,rsa-sha2-5|
|
||||
00000080 31 32 2c 73 73 68 2d 72 73 61 00 00 00 6c 61 65 |12,ssh-rsa...lae|
|
||||
00000090 73 31 32 38 2d 67 63 6d 40 6f 70 65 6e 73 73 68 |s128-gcm@openssh|
|
||||
000000a0 2e 63 6f 6d 2c 61 65 73 32 35 36 2d 67 63 6d 40 |.com,aes256-gcm@|
|
||||
000000b0 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 63 68 61 63 |openssh.com,chac|
|
||||
000000c0 68 61 32 30 2d 70 6f 6c 79 31 33 30 35 40 6f 70 |ha20-poly1305@op|
|
||||
000000d0 65 6e 73 73 68 2e 63 6f 6d 2c 61 65 73 31 32 38 |enssh.com,aes128|
|
||||
000000e0 2d 63 74 72 2c 61 65 73 31 39 32 2d 63 74 72 2c |-ctr,aes192-ctr,|
|
||||
000000f0 61 65 73 32 35 36 2d 63 74 72 00 00 00 6c 61 65 |aes256-ctr...lae|
|
||||
00000100 73 31 32 38 2d 67 63 6d 40 6f 70 65 6e 73 73 68 |s128-gcm@openssh|
|
||||
00000110 2e 63 6f 6d 2c 61 65 73 32 35 36 2d 67 63 6d 40 |.com,aes256-gcm@|
|
||||
00000120 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 63 68 61 63 |openssh.com,chac|
|
||||
00000130 68 61 32 30 2d 70 6f 6c 79 31 33 30 35 40 6f 70 |ha20-poly1305@op|
|
||||
00000140 65 6e 73 73 68 2e 63 6f 6d 2c 61 65 73 31 32 38 |enssh.com,aes128|
|
||||
00000150 2d 63 74 72 2c 61 65 73 31 39 32 2d 63 74 72 2c |-ctr,aes192-ctr,|
|
||||
00000160 61 65 73 32 35 36 2d 63 74 72 00 00 00 6e 68 6d |aes256-ctr...nhm|
|
||||
00000170 61 63 2d 73 68 61 32 2d 32 35 36 2d 65 74 6d 40 |ac-sha2-256-etm@|
|
||||
00000180 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 6d 61 63 |openssh.com,hmac|
|
||||
00000190 2d 73 68 61 32 2d 35 31 32 2d 65 74 6d 40 6f 70 |-sha2-512-etm@op|
|
||||
000001a0 65 6e 73 73 68 2e 63 6f 6d 2c 68 6d 61 63 2d 73 |enssh.com,hmac-s|
|
||||
000001b0 68 61 32 2d 32 35 36 2c 68 6d 61 63 2d 73 68 61 |ha2-256,hmac-sha|
|
||||
000001c0 32 2d 35 31 32 2c 68 6d 61 63 2d 73 68 61 31 2c |2-512,hmac-sha1,|
|
||||
000001d0 68 6d 61 63 2d 73 68 61 31 2d 39 36 00 00 00 6e |hmac-sha1-96...n|
|
||||
000001e0 68 6d 61 63 2d 73 68 61 32 2d 32 35 36 2d 65 74 |hmac-sha2-256-et|
|
||||
000001f0 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 6d |m@openssh.com,hm|
|
||||
00000200 61 63 2d 73 68 61 32 2d 35 31 32 2d 65 74 6d 40 |ac-sha2-512-etm@|
|
||||
00000210 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 6d 61 63 |openssh.com,hmac|
|
||||
00000220 2d 73 68 61 32 2d 32 35 36 2c 68 6d 61 63 2d 73 |-sha2-256,hmac-s|
|
||||
00000230 68 61 32 2d 35 31 32 2c 68 6d 61 63 2d 73 68 61 |ha2-512,hmac-sha|
|
||||
00000240 31 2c 68 6d 61 63 2d 73 68 61 31 2d 39 36 00 00 |1,hmac-sha1-96..|
|
||||
00000250 00 04 6e 6f 6e 65 00 00 00 04 6e 6f 6e 65 00 00 |..none....none..|
|
||||
00000260 00 00 00 00 00 00 00 00 00 00 00 d7 3b 80 93 f6 |............;...|
|
||||
>>> Flow 4 (client to server)
|
||||
00000000 00 00 06 3c 08 14 34 e2 44 2d 08 8d 33 01 02 63 |...<..4.D-..3..c|
|
||||
00000010 68 be 4c 40 4d e6 00 00 01 7a 73 6e 74 72 75 70 |h.L@M....zsntrup|
|
||||
00000020 37 36 31 78 32 35 35 31 39 2d 73 68 61 35 31 32 |761x25519-sha512|
|
||||
00000030 2c 73 6e 74 72 75 70 37 36 31 78 32 35 35 31 39 |,sntrup761x25519|
|
||||
00000040 2d 73 68 61 35 31 32 40 6f 70 65 6e 73 73 68 2e |-sha512@openssh.|
|
||||
00000050 63 6f 6d 2c 6d 6c 6b 65 6d 37 36 38 78 32 35 35 |com,mlkem768x255|
|
||||
00000060 31 39 2d 73 68 61 32 35 36 2c 63 75 72 76 65 32 |19-sha256,curve2|
|
||||
00000000 00 00 06 3c 08 14 c5 d5 30 62 29 26 f3 01 f2 08 |...<....0b)&....|
|
||||
00000010 8a 6e d9 d5 8e 80 00 00 01 7a 6d 6c 6b 65 6d 37 |.n.......zmlkem7|
|
||||
00000020 36 38 78 32 35 35 31 39 2d 73 68 61 32 35 36 2c |68x25519-sha256,|
|
||||
00000030 73 6e 74 72 75 70 37 36 31 78 32 35 35 31 39 2d |sntrup761x25519-|
|
||||
00000040 73 68 61 35 31 32 2c 73 6e 74 72 75 70 37 36 31 |sha512,sntrup761|
|
||||
00000050 78 32 35 35 31 39 2d 73 68 61 35 31 32 40 6f 70 |x25519-sha512@op|
|
||||
00000060 65 6e 73 73 68 2e 63 6f 6d 2c 63 75 72 76 65 32 |enssh.com,curve2|
|
||||
00000070 35 35 31 39 2d 73 68 61 32 35 36 2c 63 75 72 76 |5519-sha256,curv|
|
||||
00000080 65 32 35 35 31 39 2d 73 68 61 32 35 36 40 6c 69 |e25519-sha256@li|
|
||||
00000090 62 73 73 68 2e 6f 72 67 2c 65 63 64 68 2d 73 68 |bssh.org,ecdh-sh|
|
||||
@@ -68,50 +69,50 @@
|
||||
00000160 67 72 6f 75 70 31 34 2d 73 68 61 31 2c 65 78 74 |group14-sha1,ext|
|
||||
00000170 2d 69 6e 66 6f 2d 63 2c 6b 65 78 2d 73 74 72 69 |-info-c,kex-stri|
|
||||
00000180 63 74 2d 63 2d 76 30 30 40 6f 70 65 6e 73 73 68 |ct-c-v00@openssh|
|
||||
00000190 2e 63 6f 6d 00 00 01 cf 72 73 61 2d 73 68 61 32 |.com....rsa-sha2|
|
||||
000001a0 2d 35 31 32 2d 63 65 72 74 2d 76 30 31 40 6f 70 |-512-cert-v01@op|
|
||||
000001b0 65 6e 73 73 68 2e 63 6f 6d 2c 72 73 61 2d 73 68 |enssh.com,rsa-sh|
|
||||
000001c0 61 32 2d 32 35 36 2d 63 65 72 74 2d 76 30 31 40 |a2-256-cert-v01@|
|
||||
000001d0 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 72 73 61 2d |openssh.com,rsa-|
|
||||
000001e0 73 68 61 32 2d 35 31 32 2c 72 73 61 2d 73 68 61 |sha2-512,rsa-sha|
|
||||
000001f0 32 2d 32 35 36 2c 73 73 68 2d 65 64 32 35 35 31 |2-256,ssh-ed2551|
|
||||
00000200 39 2d 63 65 72 74 2d 76 30 31 40 6f 70 65 6e 73 |9-cert-v01@opens|
|
||||
00000210 73 68 2e 63 6f 6d 2c 65 63 64 73 61 2d 73 68 61 |sh.com,ecdsa-sha|
|
||||
00000220 32 2d 6e 69 73 74 70 32 35 36 2d 63 65 72 74 2d |2-nistp256-cert-|
|
||||
00000230 76 30 31 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c |v01@openssh.com,|
|
||||
00000240 65 63 64 73 61 2d 73 68 61 32 2d 6e 69 73 74 70 |ecdsa-sha2-nistp|
|
||||
00000250 33 38 34 2d 63 65 72 74 2d 76 30 31 40 6f 70 65 |384-cert-v01@ope|
|
||||
00000260 6e 73 73 68 2e 63 6f 6d 2c 65 63 64 73 61 2d 73 |nssh.com,ecdsa-s|
|
||||
00000270 68 61 32 2d 6e 69 73 74 70 35 32 31 2d 63 65 72 |ha2-nistp521-cer|
|
||||
00000280 74 2d 76 30 31 40 6f 70 65 6e 73 73 68 2e 63 6f |t-v01@openssh.co|
|
||||
00000290 6d 2c 73 6b 2d 73 73 68 2d 65 64 32 35 35 31 39 |m,sk-ssh-ed25519|
|
||||
000002a0 2d 63 65 72 74 2d 76 30 31 40 6f 70 65 6e 73 73 |-cert-v01@openss|
|
||||
000002b0 68 2e 63 6f 6d 2c 73 6b 2d 65 63 64 73 61 2d 73 |h.com,sk-ecdsa-s|
|
||||
000002c0 68 61 32 2d 6e 69 73 74 70 32 35 36 2d 63 65 72 |ha2-nistp256-cer|
|
||||
000002d0 74 2d 76 30 31 40 6f 70 65 6e 73 73 68 2e 63 6f |t-v01@openssh.co|
|
||||
000002e0 6d 2c 73 73 68 2d 65 64 32 35 35 31 39 2c 65 63 |m,ssh-ed25519,ec|
|
||||
000002f0 64 73 61 2d 73 68 61 32 2d 6e 69 73 74 70 32 35 |dsa-sha2-nistp25|
|
||||
00000300 36 2c 65 63 64 73 61 2d 73 68 61 32 2d 6e 69 73 |6,ecdsa-sha2-nis|
|
||||
00000310 74 70 33 38 34 2c 65 63 64 73 61 2d 73 68 61 32 |tp384,ecdsa-sha2|
|
||||
00000320 2d 6e 69 73 74 70 35 32 31 2c 73 6b 2d 73 73 68 |-nistp521,sk-ssh|
|
||||
00000330 2d 65 64 32 35 35 31 39 40 6f 70 65 6e 73 73 68 |-ed25519@openssh|
|
||||
00000340 2e 63 6f 6d 2c 73 6b 2d 65 63 64 73 61 2d 73 68 |.com,sk-ecdsa-sh|
|
||||
00000350 61 32 2d 6e 69 73 74 70 32 35 36 40 6f 70 65 6e |a2-nistp256@open|
|
||||
00000360 73 73 68 2e 63 6f 6d 00 00 00 6c 63 68 61 63 68 |ssh.com...lchach|
|
||||
00000190 2e 63 6f 6d 00 00 01 cf 73 73 68 2d 65 64 32 35 |.com....ssh-ed25|
|
||||
000001a0 35 31 39 2d 63 65 72 74 2d 76 30 31 40 6f 70 65 |519-cert-v01@ope|
|
||||
000001b0 6e 73 73 68 2e 63 6f 6d 2c 65 63 64 73 61 2d 73 |nssh.com,ecdsa-s|
|
||||
000001c0 68 61 32 2d 6e 69 73 74 70 32 35 36 2d 63 65 72 |ha2-nistp256-cer|
|
||||
000001d0 74 2d 76 30 31 40 6f 70 65 6e 73 73 68 2e 63 6f |t-v01@openssh.co|
|
||||
000001e0 6d 2c 65 63 64 73 61 2d 73 68 61 32 2d 6e 69 73 |m,ecdsa-sha2-nis|
|
||||
000001f0 74 70 33 38 34 2d 63 65 72 74 2d 76 30 31 40 6f |tp384-cert-v01@o|
|
||||
00000200 70 65 6e 73 73 68 2e 63 6f 6d 2c 65 63 64 73 61 |penssh.com,ecdsa|
|
||||
00000210 2d 73 68 61 32 2d 6e 69 73 74 70 35 32 31 2d 63 |-sha2-nistp521-c|
|
||||
00000220 65 72 74 2d 76 30 31 40 6f 70 65 6e 73 73 68 2e |ert-v01@openssh.|
|
||||
00000230 63 6f 6d 2c 73 6b 2d 73 73 68 2d 65 64 32 35 35 |com,sk-ssh-ed255|
|
||||
00000240 31 39 2d 63 65 72 74 2d 76 30 31 40 6f 70 65 6e |19-cert-v01@open|
|
||||
00000250 73 73 68 2e 63 6f 6d 2c 73 6b 2d 65 63 64 73 61 |ssh.com,sk-ecdsa|
|
||||
00000260 2d 73 68 61 32 2d 6e 69 73 74 70 32 35 36 2d 63 |-sha2-nistp256-c|
|
||||
00000270 65 72 74 2d 76 30 31 40 6f 70 65 6e 73 73 68 2e |ert-v01@openssh.|
|
||||
00000280 63 6f 6d 2c 72 73 61 2d 73 68 61 32 2d 35 31 32 |com,rsa-sha2-512|
|
||||
00000290 2d 63 65 72 74 2d 76 30 31 40 6f 70 65 6e 73 73 |-cert-v01@openss|
|
||||
000002a0 68 2e 63 6f 6d 2c 72 73 61 2d 73 68 61 32 2d 32 |h.com,rsa-sha2-2|
|
||||
000002b0 35 36 2d 63 65 72 74 2d 76 30 31 40 6f 70 65 6e |56-cert-v01@open|
|
||||
000002c0 73 73 68 2e 63 6f 6d 2c 73 73 68 2d 65 64 32 35 |ssh.com,ssh-ed25|
|
||||
000002d0 35 31 39 2c 65 63 64 73 61 2d 73 68 61 32 2d 6e |519,ecdsa-sha2-n|
|
||||
000002e0 69 73 74 70 32 35 36 2c 65 63 64 73 61 2d 73 68 |istp256,ecdsa-sh|
|
||||
000002f0 61 32 2d 6e 69 73 74 70 33 38 34 2c 65 63 64 73 |a2-nistp384,ecds|
|
||||
00000300 61 2d 73 68 61 32 2d 6e 69 73 74 70 35 32 31 2c |a-sha2-nistp521,|
|
||||
00000310 73 6b 2d 73 73 68 2d 65 64 32 35 35 31 39 40 6f |sk-ssh-ed25519@o|
|
||||
00000320 70 65 6e 73 73 68 2e 63 6f 6d 2c 73 6b 2d 65 63 |penssh.com,sk-ec|
|
||||
00000330 64 73 61 2d 73 68 61 32 2d 6e 69 73 74 70 32 35 |dsa-sha2-nistp25|
|
||||
00000340 36 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 72 73 |6@openssh.com,rs|
|
||||
00000350 61 2d 73 68 61 32 2d 35 31 32 2c 72 73 61 2d 73 |a-sha2-512,rsa-s|
|
||||
00000360 68 61 32 2d 32 35 36 00 00 00 6c 63 68 61 63 68 |ha2-256...lchach|
|
||||
00000370 61 32 30 2d 70 6f 6c 79 31 33 30 35 40 6f 70 65 |a20-poly1305@ope|
|
||||
00000380 6e 73 73 68 2e 63 6f 6d 2c 61 65 73 31 32 38 2d |nssh.com,aes128-|
|
||||
00000390 63 74 72 2c 61 65 73 31 39 32 2d 63 74 72 2c 61 |ctr,aes192-ctr,a|
|
||||
000003a0 65 73 32 35 36 2d 63 74 72 2c 61 65 73 31 32 38 |es256-ctr,aes128|
|
||||
000003b0 2d 67 63 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d |-gcm@openssh.com|
|
||||
000003c0 2c 61 65 73 32 35 36 2d 67 63 6d 40 6f 70 65 6e |,aes256-gcm@open|
|
||||
000003d0 73 73 68 2e 63 6f 6d 00 00 00 6c 63 68 61 63 68 |ssh.com...lchach|
|
||||
00000390 67 63 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c |gcm@openssh.com,|
|
||||
000003a0 61 65 73 32 35 36 2d 67 63 6d 40 6f 70 65 6e 73 |aes256-gcm@opens|
|
||||
000003b0 73 68 2e 63 6f 6d 2c 61 65 73 31 32 38 2d 63 74 |sh.com,aes128-ct|
|
||||
000003c0 72 2c 61 65 73 31 39 32 2d 63 74 72 2c 61 65 73 |r,aes192-ctr,aes|
|
||||
000003d0 32 35 36 2d 63 74 72 00 00 00 6c 63 68 61 63 68 |256-ctr...lchach|
|
||||
000003e0 61 32 30 2d 70 6f 6c 79 31 33 30 35 40 6f 70 65 |a20-poly1305@ope|
|
||||
000003f0 6e 73 73 68 2e 63 6f 6d 2c 61 65 73 31 32 38 2d |nssh.com,aes128-|
|
||||
00000400 63 74 72 2c 61 65 73 31 39 32 2d 63 74 72 2c 61 |ctr,aes192-ctr,a|
|
||||
00000410 65 73 32 35 36 2d 63 74 72 2c 61 65 73 31 32 38 |es256-ctr,aes128|
|
||||
00000420 2d 67 63 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d |-gcm@openssh.com|
|
||||
00000430 2c 61 65 73 32 35 36 2d 67 63 6d 40 6f 70 65 6e |,aes256-gcm@open|
|
||||
00000440 73 73 68 2e 63 6f 6d 00 00 00 d5 75 6d 61 63 2d |ssh.com....umac-|
|
||||
00000400 67 63 6d 40 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c |gcm@openssh.com,|
|
||||
00000410 61 65 73 32 35 36 2d 67 63 6d 40 6f 70 65 6e 73 |aes256-gcm@opens|
|
||||
00000420 73 68 2e 63 6f 6d 2c 61 65 73 31 32 38 2d 63 74 |sh.com,aes128-ct|
|
||||
00000430 72 2c 61 65 73 31 39 32 2d 63 74 72 2c 61 65 73 |r,aes192-ctr,aes|
|
||||
00000440 32 35 36 2d 63 74 72 00 00 00 d5 75 6d 61 63 2d |256-ctr....umac-|
|
||||
00000450 36 34 2d 65 74 6d 40 6f 70 65 6e 73 73 68 2e 63 |64-etm@openssh.c|
|
||||
00000460 6f 6d 2c 75 6d 61 63 2d 31 32 38 2d 65 74 6d 40 |om,umac-128-etm@|
|
||||
00000470 6f 70 65 6e 73 73 68 2e 63 6f 6d 2c 68 6d 61 63 |openssh.com,hmac|
|
||||
@@ -143,9 +144,9 @@
|
||||
00000610 6f 6d 00 00 00 15 6e 6f 6e 65 2c 7a 6c 69 62 40 |om....none,zlib@|
|
||||
00000620 6f 70 65 6e 73 73 68 2e 63 6f 6d 00 00 00 00 00 |openssh.com.....|
|
||||
00000630 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
00000640 00 00 00 2c 06 1e 00 00 00 20 f9 b4 36 4f 33 07 |...,..... ..6O3.|
|
||||
00000650 53 32 b2 ba a5 a4 e1 aa 34 8b ff d7 44 18 42 7c |S2......4...D.B||
|
||||
00000660 70 05 cf 55 41 9f aa 46 44 3e 00 00 00 00 00 00 |p..UA..FD>......|
|
||||
00000640 00 00 00 2c 06 1e 00 00 00 20 07 c6 6a cc 26 c1 |...,..... ..j.&.|
|
||||
00000650 98 86 8f 53 1c 84 6b 74 ca a1 20 cc 6e 95 46 85 |...S..kt.. .n.F.|
|
||||
00000660 4a 31 4a e7 06 31 df f7 8b 49 00 00 00 00 00 00 |J1J..1...I......|
|
||||
>>> Flow 5 (server to client)
|
||||
00000000 00 00 02 6c 13 1f 00 00 01 17 00 00 00 07 73 73 |...l..........ss|
|
||||
00000010 68 2d 72 73 61 00 00 00 03 01 00 01 00 00 01 01 |h-rsa...........|
|
||||
@@ -165,185 +166,185 @@
|
||||
000000f0 e0 27 88 e0 a2 05 8a a1 35 56 b9 9f 70 c8 0f f1 |.'......5V..p...|
|
||||
00000100 fb 62 d1 2d 1b e0 9b 66 bd eb d8 a0 f7 7e ff 00 |.b.-...f.....~..|
|
||||
00000110 7d 22 d1 6a be 17 3a 9f 2b b1 17 43 df 58 7f 92 |}".j..:.+..C.X..|
|
||||
00000120 bf 00 00 00 20 ba d1 83 03 7f f7 60 46 13 f5 6f |.... ......`F..o|
|
||||
00000130 4a 2c ee b3 5c 07 13 87 44 f6 a5 ed 9a 96 1a 29 |J,..\...D......)|
|
||||
00000140 f5 1e 71 79 71 00 00 01 14 00 00 00 0c 72 73 61 |..qyq........rsa|
|
||||
00000150 2d 73 68 61 32 2d 35 31 32 00 00 01 00 5a 61 32 |-sha2-512....Za2|
|
||||
00000160 73 4c 41 20 e8 8b f9 ab f8 8b da 4a 7f d2 76 7f |sLA .......J..v.|
|
||||
00000170 83 b5 4a 20 7b 0a 45 2c 60 dd f6 27 63 c4 8a d1 |..J {.E,`..'c...|
|
||||
00000180 d2 0f 93 c7 e4 16 1a dc c9 c5 25 a1 04 cc e9 0e |..........%.....|
|
||||
00000190 0c f0 a7 1b a5 e7 ed ac 5f 78 f2 73 d2 4a fe d1 |........_x.s.J..|
|
||||
000001a0 5f b2 e2 fe fa 51 30 2a 99 57 7d c8 3f 5f 83 73 |_....Q0*.W}.?_.s|
|
||||
000001b0 fa 31 da e6 86 cf e0 0f 77 97 3d 9f 48 08 32 b6 |.1......w.=.H.2.|
|
||||
000001c0 12 68 d9 74 cb b7 6f 21 ff cd d9 53 de b3 3a b2 |.h.t..o!...S..:.|
|
||||
000001d0 f8 8a b1 fe 47 ea 93 7e c2 01 8f 09 b0 f1 d2 ca |....G..~........|
|
||||
000001e0 de b8 c3 89 4a 97 84 7a 07 38 06 ca 41 ac b1 cb |....J..z.8..A...|
|
||||
000001f0 b5 70 8a c9 d9 58 11 04 95 17 40 97 4b 46 03 54 |.p...X....@.KF.T|
|
||||
00000200 6f 9e 38 e0 be 5c bc d9 16 c0 11 70 79 3a c2 9f |o.8..\.....py:..|
|
||||
00000210 ea e7 47 f3 c7 38 84 26 e8 ed b4 e1 a3 3b d2 64 |..G..8.&.....;.d|
|
||||
00000220 22 b4 60 9d d4 cb e7 f0 b7 f5 0f c7 44 c3 10 2d |".`.........D..-|
|
||||
00000230 32 ec e2 e6 a3 00 4b ed f6 5f 82 fe 2e 19 ed c3 |2.....K.._......|
|
||||
00000240 e2 92 09 0e cb a9 6f ba 1c 98 8a 6e d0 de ad 4a |......o....n...J|
|
||||
00000250 17 a1 cf 69 a8 6d 6e bb 52 37 2a a6 2a cc 87 3c |...i.mn.R7*.*..<|
|
||||
00000260 23 dc 62 b8 d2 60 16 9a fa 2f 75 ab 91 6a 58 d9 |#.b..`.../u..jX.|
|
||||
00000270 00 00 00 0c 0a 15 74 91 88 35 d2 5e 6a 43 50 85 |......t..5.^jCP.|
|
||||
00000280 f7 ed ca f3 01 aa f4 da b9 50 da 63 fa 6c 03 10 |.........P.c.l..|
|
||||
00000290 47 76 f7 f6 36 a7 10 42 d3 38 45 66 2f df bc a9 |Gv..6..B.8Ef/...|
|
||||
000002a0 0c f6 4d f7 38 f8 bf de 81 55 1b 6f 80 cf f5 70 |..M.8....U.o...p|
|
||||
000002b0 d1 4d 2d bf 26 7a a4 f2 fd ec 48 92 1a 9a 1d 02 |.M-.&z....H.....|
|
||||
000002c0 80 30 74 21 a9 47 b1 ae 84 95 c5 ce e0 fa 42 2c |.0t!.G........B,|
|
||||
000002d0 a0 48 27 f0 fa 18 a7 75 ce 13 3f b0 8f fb ad 9c |.H'....u..?.....|
|
||||
000002e0 c6 54 01 40 3c d2 64 5b 67 04 d0 d0 fc 4e 08 74 |.T.@<.d[g....N.t|
|
||||
000002f0 3a 4e 3f 91 e1 05 26 9a b7 f6 88 b0 a7 d1 be 41 |:N?...&........A|
|
||||
00000300 ea 32 d3 2b 50 bb 82 30 ca 96 e1 c3 c0 5d 6e be |.2.+P..0.....]n.|
|
||||
00000310 be 11 57 e8 39 d6 52 d2 ee 1b 15 ba d0 5d d2 75 |..W.9.R......].u|
|
||||
00000320 6d 30 fa 1c 8b c5 37 9c 9f a4 da f3 c9 b2 d4 68 |m0....7........h|
|
||||
00000330 66 b6 6d 27 ff 5d 22 ad fa 49 99 a1 99 28 c2 bd |f.m'.]"..I...(..|
|
||||
00000340 7c a6 11 d2 77 38 ae ab 67 ed 98 88 b4 d9 63 c5 ||...w8..g.....c.|
|
||||
00000350 59 c1 63 4d 03 b4 76 9c c6 60 09 46 25 d4 0a 4a |Y.cM..v..`.F%..J|
|
||||
00000360 a8 54 fe a5 55 43 45 a2 b5 4d db 58 38 ab 2b 3f |.T..UCE..M.X8.+?|
|
||||
00000370 c5 e2 2d 47 c9 91 7b 11 43 fb ab c2 47 e7 21 a5 |..-G..{.C...G.!.|
|
||||
00000380 1c 0f 16 a2 |....|
|
||||
00000120 bf 00 00 00 20 13 cf b6 0f c2 c9 08 d9 7b f6 60 |.... ........{.`|
|
||||
00000130 d4 53 7f 4b b1 29 37 59 98 3c dd ab b1 51 12 94 |.S.K.)7Y.<...Q..|
|
||||
00000140 92 eb 56 4c 6f 00 00 01 14 00 00 00 0c 72 73 61 |..VLo........rsa|
|
||||
00000150 2d 73 68 61 32 2d 35 31 32 00 00 01 00 64 a3 e2 |-sha2-512....d..|
|
||||
00000160 1b 13 ca 48 cf 1b ce 82 1f 24 15 74 dd 53 c4 20 |...H.....$.t.S. |
|
||||
00000170 f3 bb f5 48 45 2c 11 db 63 e2 b2 f6 30 c8 72 b1 |...HE,..c...0.r.|
|
||||
00000180 42 8a f3 67 3b 1d 9f dc 60 f8 57 d8 9e bf 24 7b |B..g;...`.W...${|
|
||||
00000190 97 96 cc dd 52 e6 1e f7 d6 ab 83 98 a2 5f 05 fd |....R........_..|
|
||||
000001a0 15 ae b3 b8 a8 7e d0 b8 3e 49 0a 03 89 69 14 d7 |.....~..>I...i..|
|
||||
000001b0 58 9f d2 a5 48 3d 65 25 91 e2 13 1b fa 09 e5 f9 |X...H=e%........|
|
||||
000001c0 c2 6d 2e 6e b7 21 55 90 cd c9 97 29 94 03 c4 d2 |.m.n.!U....)....|
|
||||
000001d0 b5 0a 36 54 ad 7e de d5 33 e3 04 1e bb 63 c3 ed |..6T.~..3....c..|
|
||||
000001e0 ce b1 b6 36 f9 8a 75 53 c3 6e 55 4c 78 99 66 55 |...6..uS.nULx.fU|
|
||||
000001f0 0e eb 1f 41 f6 d9 ca a6 67 3b c9 2a a2 81 26 d6 |...A....g;.*..&.|
|
||||
00000200 7c 7b fb bb 06 b4 64 1a 44 72 e6 01 3b 51 e4 76 ||{....d.Dr..;Q.v|
|
||||
00000210 39 66 8e cb a1 5a c8 5c df 94 27 e2 9c 1a fd 97 |9f...Z.\..'.....|
|
||||
00000220 ef fb c5 c8 15 c1 76 f9 70 ad 33 64 e4 8e df c0 |......v.p.3d....|
|
||||
00000230 39 b2 12 93 8d d7 59 f3 4e 6e ae bc 4a 9a 7e 8e |9.....Y.Nn..J.~.|
|
||||
00000240 d6 e5 ba 85 b4 32 2f f6 95 dd c2 79 ca f7 77 74 |.....2/....y..wt|
|
||||
00000250 ef 12 a7 4e c9 f8 5e b5 4d f2 b4 0c ef e8 a3 63 |...N..^.M......c|
|
||||
00000260 9c a8 a1 e3 f9 ae 57 e2 35 b8 cc 87 3c 23 dc 62 |......W.5...<#.b|
|
||||
00000270 00 00 00 0c 0a 15 b8 d2 60 16 9a fa 2f 75 ab 91 |........`.../u..|
|
||||
00000280 46 fe cb a3 45 3f 82 e6 fe 2c d4 e1 e3 0c 8b 21 |F...E?...,.....!|
|
||||
00000290 72 62 8b bd 5a de b1 65 d3 68 43 56 c3 65 ef d9 |rb..Z..e.hCV.e..|
|
||||
000002a0 b0 ea 9b 6b 54 1c 04 93 d8 71 5d 4c ff 55 08 84 |...kT....q]L.U..|
|
||||
000002b0 0f ee 03 cb f7 c1 fd 8f e6 75 26 13 98 b6 c9 63 |.........u&....c|
|
||||
000002c0 1f 7d 0b 09 d7 14 9d b3 ab a1 32 6f 88 8f 53 2d |.}........2o..S-|
|
||||
000002d0 fb 0f f8 cf 58 c3 23 78 9f cd a5 81 34 08 24 2f |....X.#x....4.$/|
|
||||
000002e0 9e 5b 41 f0 81 c5 8d 2f 80 2a d8 6b a5 5b 81 c2 |.[A..../.*.k.[..|
|
||||
000002f0 4e 2a 71 c6 69 39 94 ba 8c ef 3f ec 13 ba 73 81 |N*q.i9....?...s.|
|
||||
00000300 9e 23 ca 7c 97 66 4d 06 9c f5 1b d9 30 e4 26 af |.#.|.fM.....0.&.|
|
||||
00000310 e0 bf 67 25 7a b3 57 02 cd 5d 31 a2 5f 80 22 37 |..g%z.W..]1._."7|
|
||||
00000320 79 75 87 f7 50 3b 8f 43 cb ec 14 3c 0b d7 6f 0c |yu..P;.C...<..o.|
|
||||
00000330 3e 95 60 03 f3 fc 36 23 5a 92 63 0d 66 a3 98 61 |>.`...6#Z.c.f..a|
|
||||
00000340 e5 b2 db b4 bb 1f d6 e7 e7 bd 39 92 c9 66 12 eb |..........9..f..|
|
||||
00000350 9b 54 3e ba f1 96 bf 39 c6 cd 7a 27 95 c1 b6 7c |.T>....9..z'...||
|
||||
00000360 9b e3 f1 a6 ea 93 aa a1 db 3a 3f 32 2f 6d 9e 14 |.........:?2/m..|
|
||||
00000370 ee 93 3b 89 85 54 87 c7 12 07 66 e4 42 65 ba 28 |..;..T....f.Be.(|
|
||||
00000380 0b ad 7c d4 |..|.|
|
||||
>>> Flow 6 (client to server)
|
||||
00000000 00 00 00 0c 0a 15 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
00000010 a8 13 62 11 40 33 41 a5 63 99 c5 71 e8 12 5d 6e |..b.@3A.c..q..]n|
|
||||
00000020 f2 a0 ab 7c ca 08 84 b2 c5 92 f7 1a 33 93 2c 97 |...|........3.,.|
|
||||
00000030 97 2a ed 6f cf b3 60 cd 06 0f ce cb |.*.o..`.....|
|
||||
00000010 e8 62 17 70 dc 16 ff ad b2 d7 c5 23 45 62 93 83 |.b.p.......#Eb..|
|
||||
00000020 f8 01 1b 79 df 30 da 0e a9 fd 8b 3c 51 4d b6 cc |...y.0.....<QM..|
|
||||
00000030 05 ce 2e 21 93 08 ae 1e 0e ac 80 80 |...!........|
|
||||
>>> Flow 7 (server to client)
|
||||
00000000 ca 84 08 4b 1d 34 d2 7e d8 ff 49 51 d9 62 3d 46 |...K.4.~..IQ.b=F|
|
||||
00000010 2c b5 29 4e 75 2f a3 e3 ef c5 a4 46 7e fc d3 16 |,.)Nu/.....F~...|
|
||||
00000020 d8 51 39 df bd e8 f6 bd 0f cb 41 2f |.Q9.......A/|
|
||||
00000000 10 45 f8 2f ae bb 2c e7 03 ee d8 7e 5a b0 d8 a4 |.E./..,....~Z...|
|
||||
00000010 91 17 95 56 a1 e3 d3 85 e9 d2 84 84 09 a2 3b d3 |...V..........;.|
|
||||
00000020 d0 95 a3 1c 05 01 9c e5 b0 91 74 09 |..........t.|
|
||||
>>> Flow 8 (client to server)
|
||||
00000000 a5 bd d6 66 38 58 c2 81 c2 5c c8 51 9f dd 92 73 |...f8X...\.Q...s|
|
||||
00000010 bf 4b bf e6 62 11 27 4c f2 0e ca 0e 98 8b 79 1b |.K..b.'L......y.|
|
||||
00000020 e7 61 6c f8 69 d2 9d 9b 24 92 7b 7e d8 c2 e7 9e |.al.i...$.{~....|
|
||||
00000030 d1 98 3f a6 f5 db 7f 49 da 57 f7 2d 83 c4 92 7f |..?....I.W.-....|
|
||||
00000040 6d b2 77 83 |m.w.|
|
||||
00000000 c3 4f 1f 70 2e b7 7c b2 cf 8a 41 71 87 5a fa ff |.O.p..|...Aq.Z..|
|
||||
00000010 f1 80 e4 e2 28 05 b8 ff cf 93 ef 9b d3 c8 fe f4 |....(...........|
|
||||
00000020 19 a7 aa f3 43 82 20 ab a5 f4 84 00 c9 99 33 32 |....C. .......32|
|
||||
00000030 7e b2 0b 20 b9 75 2b d8 79 ec 48 b0 9e 8d c0 b5 |~.. .u+.y.H.....|
|
||||
00000040 ff 06 1c b3 |....|
|
||||
>>> Flow 9 (server to client)
|
||||
00000000 47 50 20 fd 43 ef ef 7a 52 7b 41 0a 1e 15 37 bd |GP .C..zR{A...7.|
|
||||
00000010 b9 22 2b 3e a8 51 89 fe f2 49 6e d0 93 58 98 52 |."+>.Q...In..X.R|
|
||||
00000020 f0 7b 81 01 8d f4 ce 59 21 24 d9 31 |.{.....Y!$.1|
|
||||
00000000 b7 1a 6c 15 3c 76 f9 e2 f1 4e 22 39 9e af 8c b4 |..l.<v...N"9....|
|
||||
00000010 42 a6 39 88 3f c7 d4 50 ae e3 5b 11 57 4d ab e1 |B.9.?..P..[.WM..|
|
||||
00000020 39 77 75 63 43 e3 8b 81 21 8c b2 0a |9wucC...!...|
|
||||
>>> Flow 10 (client to server)
|
||||
00000000 00 fc 64 a5 9b 15 da a4 22 c6 cb 48 5a 57 ce f9 |..d....."..HZW..|
|
||||
00000010 54 e9 47 6b ec d6 b1 4c 3c 39 c8 45 55 0e 27 58 |T.Gk...L<9.EU.'X|
|
||||
00000020 af 26 70 f4 59 d3 1a c8 6f c5 30 b4 79 96 4f f4 |.&p.Y...o.0.y.O.|
|
||||
00000030 d6 d0 55 e4 c5 c2 eb 94 1c ee 68 6f 3a 92 a1 49 |..U.......ho:..I|
|
||||
00000040 ce 55 cc 92 ba 26 5c 79 67 5a ee 14 01 ee df 29 |.U...&\ygZ.....)|
|
||||
00000050 0b 67 5e dc fb 13 ba 1c 36 86 e2 65 93 ff 78 a1 |.g^.....6..e..x.|
|
||||
00000060 56 f0 82 ac 11 c2 49 ed a9 79 1c 68 d9 20 17 3e |V.....I..y.h. .>|
|
||||
00000070 2b 76 d2 38 a4 4c 77 91 27 bc f9 2a 20 53 97 fe |+v.8.Lw.'..* S..|
|
||||
00000080 3f 15 e6 77 cd 34 c6 30 96 f0 71 5f 79 ea d1 7b |?..w.4.0..q_y..{|
|
||||
00000090 53 96 94 65 10 de 72 06 b5 47 98 5a a6 47 d7 c2 |S..e..r..G.Z.G..|
|
||||
000000a0 bf 4e 1b 76 58 3a ac f1 27 dd ef af a4 4b 4b d1 |.N.vX:..'....KK.|
|
||||
000000b0 7d d1 76 b8 57 0e ca 50 c3 88 94 50 96 42 10 be |}.v.W..P...P.B..|
|
||||
000000c0 58 8e a7 e8 12 bd 03 b7 e8 58 45 3e 74 2b b8 59 |X........XE>t+.Y|
|
||||
000000d0 29 e9 0e 0d 20 4f b8 b2 84 9e c7 86 c8 d9 30 ba |)... O........0.|
|
||||
000000e0 ff 47 37 50 49 b4 00 d7 aa 39 54 54 57 b6 c2 b0 |.G7PI....9TTW...|
|
||||
000000f0 f5 be 83 6d 3b 3d 75 cb a2 13 36 8b b1 76 3c c8 |...m;=u...6..v<.|
|
||||
00000100 71 f7 b1 30 ff 73 c1 3b 0c ff 8f df 24 74 26 50 |q..0.s.;....$t&P|
|
||||
00000110 61 8d 81 e7 48 85 2e df 99 1e ad c9 e0 70 09 d9 |a...H........p..|
|
||||
00000120 b7 00 5e 1e 01 07 02 89 2f 83 1f 44 f9 96 2f 64 |..^...../..D../d|
|
||||
00000130 01 7e b7 38 8c df ab 7a fc e3 68 3e b1 7d 95 e7 |.~.8...z..h>.}..|
|
||||
00000140 d8 98 44 49 ed ff dd e9 9a 9d 80 06 67 73 a1 db |..DI........gs..|
|
||||
00000150 c3 0b 85 18 26 bf 35 1b 6b b4 af 08 67 32 c5 bf |....&.5.k...g2..|
|
||||
00000160 43 16 cc 1f fc 35 f4 50 32 1f 4e 89 11 16 cf 85 |C....5.P2.N.....|
|
||||
00000170 7c 19 ef 87 ||...|
|
||||
00000000 46 ee 3c 00 23 17 9c ef 31 90 23 82 d7 4e f0 da |F.<.#...1.#..N..|
|
||||
00000010 ad 91 8f 32 08 a3 db eb 7d 0c 9f f1 00 37 8f 68 |...2....}....7.h|
|
||||
00000020 1a 0d 8d 04 b0 ab e5 15 bc e9 3c 31 ff 4d 63 52 |..........<1.McR|
|
||||
00000030 a6 3b e4 f7 2f ed 6c f8 df cd f8 6c 1b 2e 55 37 |.;../.l....l..U7|
|
||||
00000040 d6 7a 22 20 45 bb cb c3 ba cf fb 45 06 1a 6d 86 |.z" E......E..m.|
|
||||
00000050 66 f6 d3 b6 60 ab 80 e5 c6 1d 12 2b 10 55 2b cc |f...`......+.U+.|
|
||||
00000060 59 54 4b b2 f5 71 bd 02 93 0a ed 4a 2f 54 cb 27 |YTK..q.....J/T.'|
|
||||
00000070 04 e0 b6 6d 2e 9f d1 79 48 e4 75 fb a2 7b 5b 7b |...m...yH.u..{[{|
|
||||
00000080 59 6a d4 a0 f5 f6 7b b9 60 e8 2e c0 b2 2a bf 2e |Yj....{.`....*..|
|
||||
00000090 fe 89 c8 71 fa 24 9f 48 be 94 7e 93 cf 1f c0 e5 |...q.$.H..~.....|
|
||||
000000a0 4c 2d c2 0a f6 95 75 96 a6 54 e5 7a 9b 52 95 4d |L-....u..T.z.R.M|
|
||||
000000b0 8e 30 a9 1b 0f 07 2d 6f 54 30 3c db 79 47 91 08 |.0....-oT0<.yG..|
|
||||
000000c0 8e 6b cd fa b2 d8 cc c4 69 07 69 82 48 d9 05 01 |.k......i.i.H...|
|
||||
000000d0 d8 4d 14 7b 16 6d aa cf 4a da 5e 94 93 5f 81 dd |.M.{.m..J.^.._..|
|
||||
000000e0 d0 8e 10 e4 fe 94 ed 2e 70 42 2f 6c e5 50 2a 2f |........pB/l.P*/|
|
||||
000000f0 b6 6d 1f 48 38 93 44 d9 55 46 b5 2b 18 1f 78 89 |.m.H8.D.UF.+..x.|
|
||||
00000100 32 f1 21 03 cb a8 37 9c e4 dc 7f 34 cd 42 f1 90 |2.!...7....4.B..|
|
||||
00000110 72 14 d3 c3 25 37 5e b8 a1 bd 39 60 f2 e7 da 39 |r...%7^...9`...9|
|
||||
00000120 87 5c 37 99 87 64 05 bd c8 45 22 be 79 7c 1e 47 |.\7..d...E".y|.G|
|
||||
00000130 99 a7 b9 5b ab b0 81 d6 24 3e 85 fe 30 3e b0 3d |...[....$>..0>.=|
|
||||
00000140 4d 92 eb 95 86 0d 72 2c eb 2c 7d 2a a1 f0 9e ed |M.....r,.,}*....|
|
||||
00000150 d1 9c 2f 71 3d c4 e0 92 2c 62 ae 4e 32 cd 20 ae |../q=...,b.N2. .|
|
||||
00000160 e2 6b 91 c2 0f d5 90 6e 80 91 4c eb 40 74 36 1f |.k.....n..L.@t6.|
|
||||
00000170 50 36 4d f7 |P6M.|
|
||||
>>> Flow 11 (server to client)
|
||||
00000000 5f 10 56 52 67 5a d9 3e 33 8d dc 87 a5 e9 65 30 |_.VRgZ.>3.....e0|
|
||||
00000010 b2 38 f2 bb 02 86 ae a4 d3 9d 1a f0 ff a7 f6 88 |.8..............|
|
||||
00000020 1f bd 6f 7f cc 61 67 aa e8 08 39 b1 3d 44 be 39 |..o..ag...9.=D.9|
|
||||
00000030 d7 5c f9 11 41 02 9d 01 fb e5 22 16 3f 70 8c 0c |.\..A.....".?p..|
|
||||
00000040 7e db a5 f5 88 87 fa 13 61 f0 c7 9b 06 90 65 a5 |~.......a.....e.|
|
||||
00000050 b4 55 32 e7 4d fd 87 40 31 c0 56 28 61 91 e6 34 |.U2.M..@1.V(a..4|
|
||||
00000060 dd 46 05 75 ff 8b e4 7c a9 fe 05 06 42 41 01 97 |.F.u...|....BA..|
|
||||
00000070 a2 43 fd c3 7c cc 60 93 41 8f ec f9 43 ae 72 ff |.C..|.`.A...C.r.|
|
||||
00000080 fd a4 d1 13 07 a4 0d cd c5 e8 1e f8 71 83 9b d3 |............q...|
|
||||
00000090 40 75 e5 8b 41 45 f1 3b 10 28 fd fa 7b a0 e4 55 |@u..AE.;.(..{..U|
|
||||
000000a0 a3 8f 1d 17 4a 7a bb 00 5a 05 ae 96 e0 8e fe b2 |....Jz..Z.......|
|
||||
000000b0 4d fc 4d ad 60 1b 6e 3c 29 66 40 16 47 93 8c 50 |M.M.`.n<)f@.G..P|
|
||||
000000c0 98 41 9b 74 1f 3a 8f 61 60 8e cf 64 d1 1b 90 a3 |.A.t.:.a`..d....|
|
||||
000000d0 2f 5e ef 63 32 11 75 91 fd 8a ff 80 d1 c7 89 55 |/^.c2.u........U|
|
||||
000000e0 e1 4b d7 de c0 29 8c 31 6f ef 58 09 1c f4 3c 6b |.K...).1o.X...<k|
|
||||
000000f0 46 f6 65 9b ad 76 31 e6 7d a1 96 29 b5 00 aa c2 |F.e..v1.}..)....|
|
||||
00000100 eb ad cf da e2 ef f9 2a 82 b0 5b e8 39 a6 2d 0e |.......*..[.9.-.|
|
||||
00000110 76 c0 aa 77 d5 5d 9d f5 8a 3f 3a e4 21 e2 88 12 |v..w.]...?:.!...|
|
||||
00000120 9d 16 2f 25 74 c5 5f 4b 5f d1 b3 d1 ad 8b 56 86 |../%t._K_.....V.|
|
||||
00000130 75 64 c7 82 8c e2 66 10 d0 38 21 64 4e af d5 f1 |ud....f..8!dN...|
|
||||
00000140 61 34 e4 77 81 85 6e ed f7 46 9a 43 |a4.w..n..F.C|
|
||||
00000000 d5 4c 72 d9 7a c9 22 77 d6 4c 63 74 37 fa 30 ad |.Lr.z."w.Lct7.0.|
|
||||
00000010 7e 13 45 59 61 84 82 f7 d2 13 3f 44 ac 2d de 41 |~.EYa.....?D.-.A|
|
||||
00000020 db 9c dd 1b fe 06 aa bc 38 30 1d a4 bb ed 7c 9d |........80....|.|
|
||||
00000030 4b 6e 79 78 e4 0a 35 5f 68 e9 4f a5 e9 65 99 f3 |Knyx..5_h.O..e..|
|
||||
00000040 e9 72 59 1d cd 0b ed 44 52 5d f9 dc 76 c9 23 ce |.rY....DR]..v.#.|
|
||||
00000050 9f 27 21 ff 94 0c dd 60 95 89 ce 71 8d 37 c1 ec |.'!....`...q.7..|
|
||||
00000060 12 90 99 b3 62 83 18 3a ea d9 c8 73 67 67 c4 64 |....b..:...sgg.d|
|
||||
00000070 55 f8 3b b9 5b ea 67 5b de 8a e6 00 49 15 9a 64 |U.;.[.g[....I..d|
|
||||
00000080 2f b6 7c ec 76 71 d0 c2 cc e0 3f 44 46 ed 27 85 |/.|.vq....?DF.'.|
|
||||
00000090 f1 71 5e 44 94 d0 c0 b4 da 4b ab e5 28 be 62 44 |.q^D.....K..(.bD|
|
||||
000000a0 3a 36 ef 1d d3 5a a2 ea 9e 5e e0 19 18 5d be 85 |:6...Z...^...]..|
|
||||
000000b0 26 7c 92 b9 14 38 18 27 35 32 bf f9 18 ce d2 ec |&|...8.'52......|
|
||||
000000c0 20 1d ac de ea 78 2a 2b 5a 3d a8 e8 95 43 24 ea | ....x*+Z=...C$.|
|
||||
000000d0 ee eb 24 f1 c1 c3 d0 e4 d9 21 f9 57 17 f9 4d 4c |..$......!.W..ML|
|
||||
000000e0 03 37 ae dd b8 80 f0 52 77 43 80 e0 6e 79 07 7c |.7.....RwC..ny.||
|
||||
000000f0 a9 c6 38 43 a1 89 fd 0d f4 07 84 33 e2 f6 94 61 |..8C.......3...a|
|
||||
00000100 ff 33 66 05 21 0f 6d 88 4b 41 88 12 9a cc b8 a0 |.3f.!.m.KA......|
|
||||
00000110 81 4b 7b ed 61 0d a2 6f 05 91 dd ff f8 56 95 73 |.K{.a..o.....V.s|
|
||||
00000120 6d ec 15 6a ee df cc 7c 65 f0 7d 02 23 06 0f c1 |m..j...|e.}.#...|
|
||||
00000130 90 6c 76 81 15 9a 22 99 09 78 9f 2c b6 9d 67 9f |.lv..."..x.,..g.|
|
||||
00000140 45 85 3c a2 dd af c7 f9 f3 0d 05 d3 |E.<.........|
|
||||
>>> Flow 12 (client to server)
|
||||
00000000 3d 66 0f 09 25 f8 c6 94 96 76 8f bb 42 e1 39 a5 |=f..%....v..B.9.|
|
||||
00000010 a4 68 37 80 00 dc c3 5f d4 e7 da de 1f d0 6c 13 |.h7...._......l.|
|
||||
00000020 3c 8c 55 96 d4 4e 6c 9c 46 02 d9 5b ba 25 a2 42 |<.U..Nl.F..[.%.B|
|
||||
00000030 ed 92 b2 4a 78 e0 90 c5 ab 03 68 30 a3 e8 b6 c2 |...Jx.....h0....|
|
||||
00000040 74 50 9b 60 c6 27 a2 d4 6f fe b6 30 15 7e b7 74 |tP.`.'..o..0.~.t|
|
||||
00000050 89 a1 05 37 4c ae 9e dd 93 32 ad d3 1e fe 47 05 |...7L....2....G.|
|
||||
00000060 cb 07 f0 46 2b 11 96 57 19 c0 ec 4b 19 2c c7 2b |...F+..W...K.,.+|
|
||||
00000070 5a 7a 31 e7 0a 6d 9e 2e bf d2 15 e6 eb 2b f6 9a |Zz1..m.......+..|
|
||||
00000080 80 01 99 69 1d e6 0b 5b 02 b2 22 19 b8 f8 6c b8 |...i...[.."...l.|
|
||||
00000090 f0 95 54 e5 67 1a e9 71 8d 05 7c d7 6f 39 eb 15 |..T.g..q..|.o9..|
|
||||
000000a0 dc be 20 e6 c1 dd fa 22 13 af fb 08 8b 67 2a eb |.. ....".....g*.|
|
||||
000000b0 12 fd 55 c4 c7 e0 8a 7c 28 14 cf 27 58 fd 2d 87 |..U....|(..'X.-.|
|
||||
000000c0 3d 5b 3b 42 94 8c da 72 b4 97 d6 e3 a5 3c 73 05 |=[;B...r.....<s.|
|
||||
000000d0 c9 e9 d3 bb 89 8c 8d 84 db 9d e6 4e 25 a0 a4 eb |...........N%...|
|
||||
000000e0 47 4b c2 09 ed 0e 00 71 3e 27 09 7c 37 f5 e3 1c |GK.....q>'.|7...|
|
||||
000000f0 b3 d7 f3 bc bc bf 48 f3 12 64 89 df 5d a9 4a da |......H..d..].J.|
|
||||
00000100 dd 76 1d 9d a0 0a fb 15 81 b0 78 0d 75 29 43 1f |.v........x.u)C.|
|
||||
00000110 5b 0c 47 dc a0 dc d1 3f e4 2f 90 e8 59 6e 80 47 |[.G....?./..Yn.G|
|
||||
00000120 11 1a 42 db 86 72 ec 84 41 ca 19 8d 48 8f b3 e8 |..B..r..A...H...|
|
||||
00000130 97 3e dc f8 36 1d 44 1b 54 68 fa 61 17 c2 c8 6e |.>..6.D.Th.a...n|
|
||||
00000140 89 7d 25 f7 1e 55 fa 26 f1 0b a5 9d f9 af 66 32 |.}%..U.&......f2|
|
||||
00000150 65 6c 9b 16 f5 41 8c 5c d6 29 44 5e 97 9e 73 35 |el...A.\.)D^..s5|
|
||||
00000160 f3 78 54 1d 7e fe 41 92 a2 85 49 9f 4b 8e f9 87 |.xT.~.A...I.K...|
|
||||
00000170 05 9b 93 6e 62 ce 1c ae ed 14 b4 22 89 df e7 97 |...nb......"....|
|
||||
00000180 fc e9 67 eb bd a9 ae 4a 14 bf cf 37 cb 46 b9 55 |..g....J...7.F.U|
|
||||
00000190 0d 72 f5 be 7f 5b d7 39 15 23 30 00 fb 1d 2c 04 |.r...[.9.#0...,.|
|
||||
000001a0 54 49 14 c5 ac d6 1b 56 20 f9 5f 4c 0a ca 02 1e |TI.....V ._L....|
|
||||
000001b0 82 78 be e5 db a1 cd b5 85 1b 54 18 51 c2 3c 2c |.x........T.Q.<,|
|
||||
000001c0 1c bb 3c 85 1d 93 51 61 a4 2d ec f6 76 62 d7 1e |..<...Qa.-..vb..|
|
||||
000001d0 12 f6 24 e7 93 3b c3 63 9e ca 2d 0d 04 b1 b4 f8 |..$..;.c..-.....|
|
||||
000001e0 41 03 b9 53 43 e3 7c b4 ca 65 35 f7 b8 af 71 91 |A..SC.|..e5...q.|
|
||||
000001f0 2f f2 4c 04 e1 d3 a7 1a 35 78 55 44 d6 2b 7f 52 |/.L.....5xUD.+.R|
|
||||
00000200 c5 60 26 68 30 7a ff e0 d5 77 56 b1 02 84 0a 09 |.`&h0z...wV.....|
|
||||
00000210 5a b3 22 ad 8b f7 be 50 00 21 69 fd 2f c2 c7 0c |Z."....P.!i./...|
|
||||
00000220 8d 15 76 9d 49 c9 48 2a 4d e9 d6 da e7 18 0a 73 |..v.I.H*M......s|
|
||||
00000230 47 1d ab 9b f6 41 22 e9 18 e6 e3 cd a4 b7 51 ee |G....A".......Q.|
|
||||
00000240 d2 68 fb 35 3c cb 1d 86 e7 1b 89 36 5a a6 37 8f |.h.5<......6Z.7.|
|
||||
00000250 60 79 d5 e5 42 82 f8 9f 0a 04 03 27 ac a3 31 d3 |`y..B......'..1.|
|
||||
00000260 dd c9 5e fe 8d 69 cd 06 19 93 69 07 12 e7 fd c8 |..^..i....i.....|
|
||||
00000270 8a d4 65 df 14 36 f0 0b bf f3 8f 1a dc 7c c7 33 |..e..6.......|.3|
|
||||
00000280 11 d3 4b 25 4b 68 d1 8b 38 70 05 22 |..K%Kh..8p."|
|
||||
00000000 30 4c 00 77 a3 9a a9 d7 56 a7 37 b1 b5 ed 6d 26 |0L.w....V.7...m&|
|
||||
00000010 c1 6c e2 cf 5e c8 76 3c f8 84 3f 8b 2b 9d bc 1d |.l..^.v<..?.+...|
|
||||
00000020 3b 7a 6c 44 e2 64 9b f2 b2 04 09 96 47 27 58 4b |;zlD.d......G'XK|
|
||||
00000030 18 7b c4 e7 b5 71 07 29 94 34 9b a3 30 4a 4e de |.{...q.).4..0JN.|
|
||||
00000040 48 83 10 65 25 41 6b 71 2a b8 a1 77 e5 26 9c dd |H..e%Akq*..w.&..|
|
||||
00000050 d2 5b b7 89 a3 54 1f e2 1e f0 78 19 fe a3 92 db |.[...T....x.....|
|
||||
00000060 b6 fe 47 3e dd 7c 3a 3d 76 ec 6e 1b 20 9c 02 b1 |..G>.|:=v.n. ...|
|
||||
00000070 58 85 d0 77 c9 3f 04 68 f3 b5 a1 6c dd 9f 5c 39 |X..w.?.h...l..\9|
|
||||
00000080 8e 3f 06 9e bd c5 a2 e8 5a 85 b7 de 75 d6 82 81 |.?......Z...u...|
|
||||
00000090 f2 6f 35 dd b8 e3 de bd a0 b7 2e d6 12 5b b1 0b |.o5..........[..|
|
||||
000000a0 bb 68 36 ac 1f ad 08 bd f6 0f 27 08 ed 70 5b 5e |.h6.......'..p[^|
|
||||
000000b0 34 45 8b 00 ef 4f b3 52 53 b0 8d c5 9d 1b c0 fb |4E...O.RS.......|
|
||||
000000c0 f3 40 70 bb 07 8b e0 d8 11 de 5f 98 b9 36 18 aa |.@p......._..6..|
|
||||
000000d0 8d 5b 29 45 02 ce 32 04 35 2e f4 21 6a 2d 24 cf |.[)E..2.5..!j-$.|
|
||||
000000e0 29 a0 3e 1e 14 91 17 09 64 77 23 34 23 3f 5b 37 |).>.....dw#4#?[7|
|
||||
000000f0 b3 c7 e7 50 23 8d be 32 3d 98 8e 6c d6 96 8b a9 |...P#..2=..l....|
|
||||
00000100 82 5d 89 e2 56 9a ad 39 04 af 4a 78 20 3e 46 60 |.]..V..9..Jx >F`|
|
||||
00000110 38 e0 b9 3f 8f 5c 2d b6 82 cf ad 20 89 fd c7 c5 |8..?.\-.... ....|
|
||||
00000120 e7 54 9a d8 a0 70 31 18 7c 8c 32 99 73 a4 6c ff |.T...p1.|.2.s.l.|
|
||||
00000130 c0 36 5f 22 1b 01 d3 a6 b0 03 9a 04 0c 0a e3 8d |.6_"............|
|
||||
00000140 b2 23 28 16 6c 2a c6 8d 53 fa 4c 25 db 0b d9 ab |.#(.l*..S.L%....|
|
||||
00000150 d1 e6 e1 d3 38 f7 2b 3d 36 03 e2 65 37 04 14 d5 |....8.+=6..e7...|
|
||||
00000160 66 9f 3b 4f bb e6 8e 64 22 60 f2 ba 8f 15 98 2b |f.;O...d"`.....+|
|
||||
00000170 09 d6 c0 af aa 26 e5 64 14 0e 61 dd 51 9d 0d ba |.....&.d..a.Q...|
|
||||
00000180 50 74 51 2d c6 45 5e 25 a3 94 5a b3 68 ce 73 aa |PtQ-.E^%..Z.h.s.|
|
||||
00000190 e3 11 d1 a4 c2 49 79 1a 1d 24 7c 03 32 ac 91 43 |.....Iy..$|.2..C|
|
||||
000001a0 1f 40 74 2c 95 c3 90 6d 86 ea d2 ef b5 9e 92 6b |.@t,...m.......k|
|
||||
000001b0 1e af 4c b4 a7 4f d8 ea 59 27 cb 8c b4 f5 7e 8e |..L..O..Y'....~.|
|
||||
000001c0 62 7c ae e0 57 20 bc 4b 2c b7 7c 1b 50 a4 3a 14 |b|..W .K,.|.P.:.|
|
||||
000001d0 3b 9b b3 cd 89 52 3b 72 bb 22 7d 74 00 a9 3f d9 |;....R;r."}t..?.|
|
||||
000001e0 7c 70 04 f2 24 db 49 e3 80 95 98 85 50 9d 90 8c ||p..$.I.....P...|
|
||||
000001f0 8c 67 d8 0c 9f 78 32 5b b0 af ab 06 0d 04 1f 19 |.g...x2[........|
|
||||
00000200 d7 b7 62 3a 2b 49 4f 8e 1b 08 3e f1 0e 6f dd 62 |..b:+IO...>..o.b|
|
||||
00000210 57 2b c1 fd e1 dc d2 8c 4e 95 d6 0f ab 00 94 a3 |W+......N.......|
|
||||
00000220 ba 85 08 bf 4c a0 a6 0c 26 dd b0 b2 e5 2c 82 5d |....L...&....,.]|
|
||||
00000230 53 e0 3b 2e 8e 03 98 c2 d7 f2 67 bc 48 56 bf bb |S.;.......g.HV..|
|
||||
00000240 9b 62 11 33 38 a1 bb 8d 36 e0 63 5c b8 11 c7 4d |.b.38...6.c\...M|
|
||||
00000250 00 19 33 73 e8 e2 96 46 e2 ff 44 95 84 05 7f 58 |..3s...F..D....X|
|
||||
00000260 d1 fb 92 86 a5 65 43 c4 f5 90 a0 f4 00 5b fe 73 |.....eC......[.s|
|
||||
00000270 86 ec 69 b1 c7 a8 51 d3 3a 6e 4e fa 9c 2c a7 09 |..i...Q.:nN..,..|
|
||||
00000280 f3 8b 74 39 6d a6 5d d0 43 a2 e6 30 |..t9m.].C..0|
|
||||
>>> Flow 13 (server to client)
|
||||
00000000 d9 20 09 e1 7e 5e 59 b2 ae 81 50 fa 2b e7 82 42 |. ..~^Y...P.+..B|
|
||||
00000010 6b 14 29 2a 1e 44 96 52 30 6a b5 ed |k.)*.D.R0j..|
|
||||
00000000 33 a5 4d 90 84 2c 28 47 86 8c fc 3b 1e 21 e4 54 |3.M..,(G...;.!.T|
|
||||
00000010 a9 2a 37 82 53 41 fe f2 40 ef b3 c3 |.*7.SA..@...|
|
||||
>>> Flow 14 (client to server)
|
||||
00000000 9f 1b 62 56 0a 21 c5 b5 5d 76 ae 1b f9 c1 70 3f |..bV.!..]v....p?|
|
||||
00000010 b6 09 a5 be 89 12 04 b1 9a f8 3f bf 90 a8 e2 c0 |..........?.....|
|
||||
00000020 58 68 0a 8b 17 63 3c 43 2d 33 7d 89 8c 32 90 3f |Xh...c<C-3}..2.?|
|
||||
00000030 21 88 63 86 |!.c.|
|
||||
00000000 9b c2 b4 83 be 85 e9 65 ef 00 3d 7e d4 4c 8f 1a |.......e..=~.L..|
|
||||
00000010 d7 3a 45 d7 30 b2 4c c2 fe 3e 44 bd 25 e7 96 fd |.:E.0.L..>D.%...|
|
||||
00000020 d5 22 6a 21 12 d0 89 b7 8a 97 b3 48 c6 27 04 69 |."j!.......H.'.i|
|
||||
00000030 0d eb 54 0a |..T.|
|
||||
>>> Flow 15 (server to client)
|
||||
00000000 23 d0 5d 42 65 ba 45 89 75 8c 88 76 69 e3 80 b6 |#.]Be.E.u..vi...|
|
||||
00000010 8d 3b d5 b5 84 27 05 03 43 19 67 20 c1 c8 08 d8 |.;...'..C.g ....|
|
||||
00000020 d0 60 b3 e3 c4 1e 32 25 a0 1f 44 6e |.`....2%..Dn|
|
||||
00000000 9c 34 68 72 6f 87 4e 6f 08 a5 1e ac 43 31 d3 74 |.4hro.No....C1.t|
|
||||
00000010 9f 0a 0b e2 c0 3c aa ae 82 35 1f c7 3c 0d 04 c9 |.....<...5..<...|
|
||||
00000020 67 c9 ec fd 39 e5 15 16 fa ee ca 89 |g...9.......|
|
||||
>>> Flow 16 (client to server)
|
||||
00000000 42 00 21 ac 15 92 63 b5 bd e6 7a 1d f7 06 b9 24 |B.!...c...z....$|
|
||||
00000010 cf 18 31 ac a4 49 fd a1 d2 9f 46 06 04 f7 7b 76 |..1..I....F...{v|
|
||||
00000020 9a 8f 07 c0 55 a8 01 e3 bb e6 b9 02 4b c4 86 d3 |....U.......K...|
|
||||
00000030 b1 aa 9f 21 d1 cc 03 ea c7 61 72 df be c7 d2 38 |...!.....ar....8|
|
||||
00000040 93 b4 ad 5f 4b ec e8 8d 85 70 31 14 11 e0 d6 3a |..._K....p1....:|
|
||||
00000050 62 62 bb e7 c6 a5 3c 9e |bb....<.|
|
||||
00000000 14 7e 97 99 c7 2b 99 94 40 0c 0d 0a a3 2c 69 8a |.~...+..@....,i.|
|
||||
00000010 59 bd ab ab 60 dd 35 c9 f7 59 02 fc 08 05 0e a7 |Y...`.5..Y......|
|
||||
00000020 3b de d1 9d 37 29 09 64 1b ed 10 f7 82 7b d6 8c |;...7).d.....{..|
|
||||
00000030 fc 89 54 ca ca 67 86 c0 6a 60 f8 cf b3 c6 08 fa |..T..g..j`......|
|
||||
00000040 3d f6 68 d1 c1 1b 5b ea e5 cf d4 24 8f b4 9b e7 |=.h...[....$....|
|
||||
00000050 b6 95 a9 2e ea 50 38 75 |.....P8u|
|
||||
>>> Flow 17 (server to client)
|
||||
00000000 b1 ec 5a ea 52 a1 03 42 b3 1a b1 42 ea 71 fd 16 |..Z.R..B...B.q..|
|
||||
00000010 06 2c 3d 74 f5 4f 9e 76 2f cd 3e 57 75 97 eb e6 |.,=t.O.v/.>Wu...|
|
||||
00000020 21 ba aa 47 ae 3c 11 92 47 55 90 44 9d 08 01 68 |!..G.<..GU.D...h|
|
||||
00000030 f6 e2 71 7d 2f 0c 64 83 4d 4d 58 96 14 cd 1e 70 |..q}/.d.MMX....p|
|
||||
00000040 3f 7d ad e3 4f f2 65 45 4d 4d 0f 14 c3 99 a8 ca |?}..O.eEMM......|
|
||||
00000050 7a 65 f2 75 59 02 e5 1c 19 13 96 f5 05 57 ac 0b |ze.uY........W..|
|
||||
00000060 d7 39 86 d1 76 55 0a 99 93 5a f0 fc 39 41 19 38 |.9..vU...Z..9A.8|
|
||||
00000070 af 6f 24 90 5e fe e1 e2 47 6c d7 24 |.o$.^...Gl.$|
|
||||
00000000 fa cf 4c 38 01 c5 20 b6 3c cd ec b8 9e ae 50 8f |..L8.. .<.....P.|
|
||||
00000010 bd 5e 77 6a e1 46 ac 25 c8 a3 7c e7 f7 f5 a4 3f |.^wj.F.%..|....?|
|
||||
00000020 1f f8 4a 68 0e cb e6 a8 3f 9e e7 64 61 3f 42 7e |..Jh....?..da?B~|
|
||||
00000030 d0 e0 f1 82 15 ab 65 e9 c4 3f 8e 36 7a 84 0c c3 |......e..?.6z...|
|
||||
00000040 36 90 6d 28 06 89 fa 6a 53 f3 ca 45 8d 52 5c a2 |6.m(...jS..E.R\.|
|
||||
00000050 50 97 0f 7d e1 61 70 d1 ce bd d8 6f 1c 63 39 13 |P..}.ap....o.c9.|
|
||||
00000060 10 66 38 a4 8f 0d 90 ff dc e0 57 f5 79 94 3a c8 |.f8.......W.y.:.|
|
||||
00000070 39 d7 ff 31 8e 62 7f ca 69 8e 37 da |9..1.b..i.7.|
|
||||
>>> Flow 18 (client to server)
|
||||
00000000 98 d1 51 36 8b d9 89 f9 8b 1b bf 5a e6 aa ab 28 |..Q6.......Z...(|
|
||||
00000010 8a 68 c3 a6 7d d9 f1 01 a1 93 fe 62 c1 49 4f 46 |.h..}......b.IOF|
|
||||
00000020 42 52 76 45 59 46 02 a0 19 5d 6e 7f 5c ce ab 85 |BRvEYF...]n.\...|
|
||||
00000030 c5 0d 89 6e f2 c4 aa 99 71 f8 35 5d a9 3c 6a 42 |...n....q.5].<jB|
|
||||
00000040 a0 4e f0 48 0b 9c 72 68 0d b9 a7 97 24 b4 50 7d |.N.H..rh....$.P}|
|
||||
00000050 49 f8 c1 b1 a9 24 a2 b5 99 33 f4 72 74 8c 35 9e |I....$...3.rt.5.|
|
||||
00000000 f8 55 f0 f7 44 40 b9 e2 bb aa e3 09 00 11 f8 19 |.U..D@..........|
|
||||
00000010 d3 06 9e 95 e5 84 d5 d5 3f 6a d0 89 fe 18 86 3d |........?j.....=|
|
||||
00000020 a6 02 6e 7f af 0d 37 e4 c1 3e 3c 64 85 13 ea e3 |..n...7..><d....|
|
||||
00000030 34 5e 5a d7 d2 c6 be d3 85 a1 a7 d6 38 22 17 21 |4^Z.........8".!|
|
||||
00000040 91 70 06 b5 7a 2f 16 fe 0f 39 c5 47 68 12 df 03 |.p..z/...9.Gh...|
|
||||
00000050 8f b6 29 a6 17 7c 2f c6 3a 3f b2 7a 83 7f 17 14 |..)..|/.:?.z....|
|
||||
|
||||
+4
-11
@@ -16,13 +16,6 @@ import (
|
||||
// wire. No message decoding is done, to minimize the impact on timing.
|
||||
const debugTransport = false
|
||||
|
||||
const (
|
||||
gcm128CipherID = "aes128-gcm@openssh.com"
|
||||
gcm256CipherID = "aes256-gcm@openssh.com"
|
||||
aes128cbcID = "aes128-cbc"
|
||||
tripledescbcID = "3des-cbc"
|
||||
)
|
||||
|
||||
// packetConn represents a transport that implements packet based
|
||||
// operations.
|
||||
type packetConn interface {
|
||||
@@ -92,14 +85,14 @@ func (t *transport) setInitialKEXDone() {
|
||||
// prepareKeyChange sets up key material for a keychange. The key changes in
|
||||
// both directions are triggered by reading and writing a msgNewKey packet
|
||||
// respectively.
|
||||
func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) error {
|
||||
ciph, err := newPacketCipher(t.reader.dir, algs.r, kexResult)
|
||||
func (t *transport) prepareKeyChange(algs *NegotiatedAlgorithms, kexResult *kexResult) error {
|
||||
ciph, err := newPacketCipher(t.reader.dir, algs.Read, kexResult)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.reader.pendingKeyChange <- ciph
|
||||
|
||||
ciph, err = newPacketCipher(t.writer.dir, algs.w, kexResult)
|
||||
ciph, err = newPacketCipher(t.writer.dir, algs.Write, kexResult)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -259,7 +252,7 @@ var (
|
||||
// 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) {
|
||||
func newPacketCipher(d direction, algs DirectionAlgorithms, kex *kexResult) (packetCipher, error) {
|
||||
cipherMode := cipherModes[algs.Cipher]
|
||||
|
||||
iv := make([]byte, cipherMode.ivSize)
|
||||
|
||||
Binary file not shown.
+753
-4360
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,32 @@
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package fallback
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBundle(t *testing.T) {
|
||||
for i, unparsed := range unparsedCertificates {
|
||||
cert, err := x509.ParseCertificate(rawCerts[unparsed.certStartOff : unparsed.certStartOff+unparsed.certLength])
|
||||
if err != nil {
|
||||
t.Errorf("ParseCertificate(unparsedCertificates[%v]) unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if unparsed.cn != cert.Subject.String() {
|
||||
t.Errorf("unparsedCertificates[%v].cn = %q; want = %q", i, unparsed.cn, cert.Subject.String())
|
||||
}
|
||||
|
||||
sum := sha256.Sum256(cert.Raw)
|
||||
sumHex := hex.EncodeToString(sum[:])
|
||||
if sumHex != unparsed.sha256Hash {
|
||||
t.Errorf("unparsedCertificates[%v].sha256Hash = %q; want = %q", i, unparsed.sha256Hash, sumHex)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,23 @@
|
||||
// available.
|
||||
package fallback
|
||||
|
||||
import "crypto/x509"
|
||||
import (
|
||||
"crypto/x509"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
//go:embed bundle.der
|
||||
var rawCerts []byte
|
||||
|
||||
func init() {
|
||||
x509.SetFallbackRoots(newFallbackCertPool())
|
||||
}
|
||||
|
||||
func newFallbackCertPool() *x509.CertPool {
|
||||
p := x509.NewCertPool()
|
||||
for _, c := range parsedCertificates {
|
||||
for _, c := range mustParse(unparsedCertificates) {
|
||||
if len(c.constraints) == 0 {
|
||||
p.AddCert(c.cert)
|
||||
} else {
|
||||
@@ -36,5 +48,48 @@ func init() {
|
||||
})
|
||||
}
|
||||
}
|
||||
x509.SetFallbackRoots(p)
|
||||
return p
|
||||
}
|
||||
|
||||
type unparsedCertificate struct {
|
||||
cn string
|
||||
sha256Hash string
|
||||
certStartOff int
|
||||
certLength int
|
||||
|
||||
// possible constraints
|
||||
distrustAfter string
|
||||
}
|
||||
|
||||
type parsedCertificate struct {
|
||||
cert *x509.Certificate
|
||||
constraints []func([]*x509.Certificate) error
|
||||
}
|
||||
|
||||
func mustParse(unparsedCerts []unparsedCertificate) []parsedCertificate {
|
||||
b := make([]parsedCertificate, 0, len(unparsedCerts))
|
||||
for _, unparsed := range unparsedCerts {
|
||||
cert, err := x509.ParseCertificate(rawCerts[unparsed.certStartOff : unparsed.certStartOff+unparsed.certLength])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
parsed := parsedCertificate{cert: cert}
|
||||
// parse possible constraints, this should check all fields of unparsedCertificate.
|
||||
if unparsed.distrustAfter != "" {
|
||||
distrustAfter, err := time.Parse(time.RFC3339, unparsed.distrustAfter)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to parse distrustAfter %q: %s", unparsed.distrustAfter, err))
|
||||
}
|
||||
parsed.constraints = append(parsed.constraints, func(chain []*x509.Certificate) error {
|
||||
for _, c := range chain {
|
||||
if c.NotBefore.After(distrustAfter) {
|
||||
return fmt.Errorf("certificate issued after distrust-after date %q", distrustAfter)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
b = append(b, parsed)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package fallback
|
||||
|
||||
import "testing"
|
||||
|
||||
// BenchmarkInitTime benchmarks the time it takes to parse all certificates
|
||||
// in this bundle, it corresponds to the init time of this package.
|
||||
func BenchmarkInitTime(b *testing.B) {
|
||||
for range b.N {
|
||||
newFallbackCertPool()
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/pem"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/format"
|
||||
@@ -30,67 +29,6 @@ const tmpl = `// Code generated by gen_fallback_bundle.go; DO NOT EDIT.
|
||||
|
||||
package fallback
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type unparsedCertificate struct {
|
||||
cn string
|
||||
sha256Hash string
|
||||
pem string
|
||||
|
||||
// possible constraints
|
||||
distrustAfter string
|
||||
}
|
||||
|
||||
type parsedCertificate struct {
|
||||
cert *x509.Certificate
|
||||
constraints []func([]*x509.Certificate) error
|
||||
}
|
||||
|
||||
func mustParse(unparsedCerts []unparsedCertificate) []parsedCertificate {
|
||||
var b []parsedCertificate
|
||||
for _, unparsed := range unparsedCerts {
|
||||
block, rest := pem.Decode([]byte(unparsed.pem))
|
||||
if block == nil {
|
||||
panic(fmt.Sprintf("unexpected nil PEM block for %q", unparsed.cn))
|
||||
}
|
||||
if len(rest) != 0 {
|
||||
panic(fmt.Sprintf("unexpected trailing data in PEM for %q", unparsed.cn))
|
||||
}
|
||||
if block.Type != "CERTIFICATE" {
|
||||
panic(fmt.Sprintf("unexpected PEM block type for %q: %s", unparsed.cn, block.Type))
|
||||
}
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
parsed := parsedCertificate{cert: cert}
|
||||
// parse possible constraints, this should check all fields of unparsedCertificate.
|
||||
if unparsed.distrustAfter != "" {
|
||||
distrustAfter, err := time.Parse(time.RFC3339, unparsed.distrustAfter)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to parse distrustAfter %q: %s", unparsed.distrustAfter, err))
|
||||
}
|
||||
parsed.constraints = append(parsed.constraints, func(chain []*x509.Certificate) error {
|
||||
for _, c := range chain {
|
||||
if c.NotBefore.After(distrustAfter) {
|
||||
return fmt.Errorf("certificate issued after distrust-after date %q", distrustAfter)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
b = append(b, parsed)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
var parsedCertificates = mustParse(unparsedCertificates)
|
||||
|
||||
var unparsedCertificates = []unparsedCertificate{
|
||||
`
|
||||
|
||||
@@ -98,6 +36,7 @@ var (
|
||||
certDataURL = flag.String("certdata-url", "https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt", "URL to the raw certdata.txt file to parse (certdata-path overrides this, if provided)")
|
||||
certDataPath = flag.String("certdata-path", "", "Path to the NSS certdata.txt file to parse (this overrides certdata-url, if provided)")
|
||||
output = flag.String("output", "fallback/bundle.go", "Path to file to write output to")
|
||||
derOutput = flag.String("deroutput", "fallback/bundle.der", "Path to file to write output to (DER certificate bundle)")
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -153,8 +92,9 @@ func main() {
|
||||
return subjI < subjJ
|
||||
})
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
b.WriteString(tmpl)
|
||||
rawCertsData := new(bytes.Buffer)
|
||||
goSrcOut := new(bytes.Buffer)
|
||||
goSrcOut.WriteString(tmpl)
|
||||
for _, c := range certs {
|
||||
var constraints []string
|
||||
var skip bool
|
||||
@@ -171,19 +111,24 @@ func main() {
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(b, "{\ncn: %q,\nsha256Hash: \"%x\",\npem: `%s`,\n",
|
||||
|
||||
off := rawCertsData.Len()
|
||||
rawCertsData.Write(c.X509.Raw)
|
||||
|
||||
fmt.Fprintf(goSrcOut, "{\ncn: %q,\nsha256Hash: \"%x\",\ncertStartOff: %v,\ncertLength: %v,\n",
|
||||
c.X509.Subject.String(),
|
||||
sha256.Sum256(c.X509.Raw),
|
||||
string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: c.X509.Raw})),
|
||||
off,
|
||||
len(c.X509.Raw),
|
||||
)
|
||||
for _, constraint := range constraints {
|
||||
fmt.Fprintln(b, constraint)
|
||||
fmt.Fprintln(goSrcOut, constraint)
|
||||
}
|
||||
fmt.Fprintln(b, "},")
|
||||
fmt.Fprintln(goSrcOut, "},")
|
||||
}
|
||||
fmt.Fprintln(b, "}")
|
||||
fmt.Fprintln(goSrcOut, "}")
|
||||
|
||||
formatted, err := format.Source(b.Bytes())
|
||||
formatted, err := format.Source(goSrcOut.Bytes())
|
||||
if err != nil {
|
||||
log.Fatalf("failed to format source: %s", err)
|
||||
}
|
||||
@@ -191,4 +136,8 @@ func main() {
|
||||
if err := os.WriteFile(*output, formatted, 0644); err != nil {
|
||||
log.Fatalf("failed to write to %q: %s", *output, err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(*derOutput, rawCertsData.Bytes(), 0644); err != nil {
|
||||
log.Fatalf("failed to write to %q: %s", *output, err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user