Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbb6ec16ec | ||
|
|
403f69900e | ||
|
|
055043dfed | ||
|
|
08396bb92b | ||
|
|
9d2ee975ef | ||
|
|
4e5a26183e | ||
|
|
152cdb1503 | ||
|
|
fdfe1f8531 | ||
|
|
b8ffc16e10 | ||
|
|
7e6fbd82c8 | ||
|
|
bda2f3f5cf |
@@ -199,8 +199,8 @@ TEXT ·mixBlocksSSE2(SB), 4, $0-32
|
|||||||
MOVQ out+0(FP), DX
|
MOVQ out+0(FP), DX
|
||||||
MOVQ a+8(FP), AX
|
MOVQ a+8(FP), AX
|
||||||
MOVQ b+16(FP), BX
|
MOVQ b+16(FP), BX
|
||||||
MOVQ a+24(FP), CX
|
MOVQ c+24(FP), CX
|
||||||
MOVQ $128, BP
|
MOVQ $128, DI
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
MOVOU 0(AX), X0
|
MOVOU 0(AX), X0
|
||||||
@@ -213,7 +213,7 @@ loop:
|
|||||||
ADDQ $16, BX
|
ADDQ $16, BX
|
||||||
ADDQ $16, CX
|
ADDQ $16, CX
|
||||||
ADDQ $16, DX
|
ADDQ $16, DX
|
||||||
SUBQ $2, BP
|
SUBQ $2, DI
|
||||||
JA loop
|
JA loop
|
||||||
RET
|
RET
|
||||||
|
|
||||||
@@ -222,8 +222,8 @@ TEXT ·xorBlocksSSE2(SB), 4, $0-32
|
|||||||
MOVQ out+0(FP), DX
|
MOVQ out+0(FP), DX
|
||||||
MOVQ a+8(FP), AX
|
MOVQ a+8(FP), AX
|
||||||
MOVQ b+16(FP), BX
|
MOVQ b+16(FP), BX
|
||||||
MOVQ a+24(FP), CX
|
MOVQ c+24(FP), CX
|
||||||
MOVQ $128, BP
|
MOVQ $128, DI
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
MOVOU 0(AX), X0
|
MOVOU 0(AX), X0
|
||||||
@@ -238,6 +238,6 @@ loop:
|
|||||||
ADDQ $16, BX
|
ADDQ $16, BX
|
||||||
ADDQ $16, CX
|
ADDQ $16, CX
|
||||||
ADDQ $16, DX
|
ADDQ $16, DX
|
||||||
SUBQ $2, BP
|
SUBQ $2, DI
|
||||||
JA loop
|
JA loop
|
||||||
RET
|
RET
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build go1.7 && amd64 && gc && !purego
|
//go:build amd64 && gc && !purego
|
||||||
|
|
||||||
package blake2b
|
package blake2b
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build go1.7 && amd64 && gc && !purego
|
//go:build amd64 && gc && !purego
|
||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
// Copyright 2016 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.7 && amd64 && gc && !purego
|
|
||||||
|
|
||||||
package blake2b
|
|
||||||
|
|
||||||
import "golang.org/x/sys/cpu"
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
useSSE4 = cpu.X86.HasSSE41
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
|
||||||
|
|
||||||
func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
|
|
||||||
if useSSE4 {
|
|
||||||
hashBlocksSSE4(h, c, flag, blocks)
|
|
||||||
} else {
|
|
||||||
hashBlocksGeneric(h, c, flag, blocks)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,8 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build go1.9
|
|
||||||
|
|
||||||
package blake2b
|
package blake2b
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ go 1.18
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
golang.org/x/net v0.10.0 // tagx:ignore
|
golang.org/x/net v0.10.0 // tagx:ignore
|
||||||
golang.org/x/sys v0.15.0
|
golang.org/x/sys v0.16.0
|
||||||
golang.org/x/term v0.15.0
|
golang.org/x/term v0.16.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require golang.org/x/text v0.14.0 // indirect
|
require golang.org/x/text v0.14.0 // indirect
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
|
||||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
// Copyright 2019 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.13
|
|
||||||
|
|
||||||
package poly1305
|
|
||||||
|
|
||||||
// Generic fallbacks for the math/bits intrinsics, copied from
|
|
||||||
// src/math/bits/bits.go. They were added in Go 1.12, but Add64 and Sum64 had
|
|
||||||
// variable time fallbacks until Go 1.13.
|
|
||||||
|
|
||||||
func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) {
|
|
||||||
sum = x + y + carry
|
|
||||||
carryOut = ((x & y) | ((x | y) &^ sum)) >> 63
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) {
|
|
||||||
diff = x - y - borrow
|
|
||||||
borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func bitsMul64(x, y uint64) (hi, lo uint64) {
|
|
||||||
const mask32 = 1<<32 - 1
|
|
||||||
x0 := x & mask32
|
|
||||||
x1 := x >> 32
|
|
||||||
y0 := y & mask32
|
|
||||||
y1 := y >> 32
|
|
||||||
w0 := x0 * y0
|
|
||||||
t := x1*y0 + w0>>32
|
|
||||||
w1 := t & mask32
|
|
||||||
w2 := t >> 32
|
|
||||||
w1 += x0 * y1
|
|
||||||
hi = x1*y1 + w2 + w1>>32
|
|
||||||
lo = x * y
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// Copyright 2019 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.13
|
|
||||||
|
|
||||||
package poly1305
|
|
||||||
|
|
||||||
import "math/bits"
|
|
||||||
|
|
||||||
func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) {
|
|
||||||
return bits.Add64(x, y, carry)
|
|
||||||
}
|
|
||||||
|
|
||||||
func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) {
|
|
||||||
return bits.Sub64(x, y, borrow)
|
|
||||||
}
|
|
||||||
|
|
||||||
func bitsMul64(x, y uint64) (hi, lo uint64) {
|
|
||||||
return bits.Mul64(x, y)
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,10 @@
|
|||||||
|
|
||||||
package poly1305
|
package poly1305
|
||||||
|
|
||||||
import "encoding/binary"
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"math/bits"
|
||||||
|
)
|
||||||
|
|
||||||
// Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag
|
// Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag
|
||||||
// for a 64 bytes message is approximately
|
// for a 64 bytes message is approximately
|
||||||
@@ -114,13 +117,13 @@ type uint128 struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func mul64(a, b uint64) uint128 {
|
func mul64(a, b uint64) uint128 {
|
||||||
hi, lo := bitsMul64(a, b)
|
hi, lo := bits.Mul64(a, b)
|
||||||
return uint128{lo, hi}
|
return uint128{lo, hi}
|
||||||
}
|
}
|
||||||
|
|
||||||
func add128(a, b uint128) uint128 {
|
func add128(a, b uint128) uint128 {
|
||||||
lo, c := bitsAdd64(a.lo, b.lo, 0)
|
lo, c := bits.Add64(a.lo, b.lo, 0)
|
||||||
hi, c := bitsAdd64(a.hi, b.hi, c)
|
hi, c := bits.Add64(a.hi, b.hi, c)
|
||||||
if c != 0 {
|
if c != 0 {
|
||||||
panic("poly1305: unexpected overflow")
|
panic("poly1305: unexpected overflow")
|
||||||
}
|
}
|
||||||
@@ -155,8 +158,8 @@ func updateGeneric(state *macState, msg []byte) {
|
|||||||
// hide leading zeroes. For full chunks, that's 1 << 128, so we can just
|
// hide leading zeroes. For full chunks, that's 1 << 128, so we can just
|
||||||
// add 1 to the most significant (2¹²⁸) limb, h2.
|
// add 1 to the most significant (2¹²⁸) limb, h2.
|
||||||
if len(msg) >= TagSize {
|
if len(msg) >= TagSize {
|
||||||
h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0)
|
h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0)
|
||||||
h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(msg[8:16]), c)
|
h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(msg[8:16]), c)
|
||||||
h2 += c + 1
|
h2 += c + 1
|
||||||
|
|
||||||
msg = msg[TagSize:]
|
msg = msg[TagSize:]
|
||||||
@@ -165,8 +168,8 @@ func updateGeneric(state *macState, msg []byte) {
|
|||||||
copy(buf[:], msg)
|
copy(buf[:], msg)
|
||||||
buf[len(msg)] = 1
|
buf[len(msg)] = 1
|
||||||
|
|
||||||
h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0)
|
h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0)
|
||||||
h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(buf[8:16]), c)
|
h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(buf[8:16]), c)
|
||||||
h2 += c
|
h2 += c
|
||||||
|
|
||||||
msg = nil
|
msg = nil
|
||||||
@@ -219,9 +222,9 @@ func updateGeneric(state *macState, msg []byte) {
|
|||||||
m3 := h2r1
|
m3 := h2r1
|
||||||
|
|
||||||
t0 := m0.lo
|
t0 := m0.lo
|
||||||
t1, c := bitsAdd64(m1.lo, m0.hi, 0)
|
t1, c := bits.Add64(m1.lo, m0.hi, 0)
|
||||||
t2, c := bitsAdd64(m2.lo, m1.hi, c)
|
t2, c := bits.Add64(m2.lo, m1.hi, c)
|
||||||
t3, _ := bitsAdd64(m3.lo, m2.hi, c)
|
t3, _ := bits.Add64(m3.lo, m2.hi, c)
|
||||||
|
|
||||||
// Now we have the result as 4 64-bit limbs, and we need to reduce it
|
// Now we have the result as 4 64-bit limbs, and we need to reduce it
|
||||||
// modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do
|
// modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do
|
||||||
@@ -243,14 +246,14 @@ func updateGeneric(state *macState, msg []byte) {
|
|||||||
|
|
||||||
// To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c.
|
// To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c.
|
||||||
|
|
||||||
h0, c = bitsAdd64(h0, cc.lo, 0)
|
h0, c = bits.Add64(h0, cc.lo, 0)
|
||||||
h1, c = bitsAdd64(h1, cc.hi, c)
|
h1, c = bits.Add64(h1, cc.hi, c)
|
||||||
h2 += c
|
h2 += c
|
||||||
|
|
||||||
cc = shiftRightBy2(cc)
|
cc = shiftRightBy2(cc)
|
||||||
|
|
||||||
h0, c = bitsAdd64(h0, cc.lo, 0)
|
h0, c = bits.Add64(h0, cc.lo, 0)
|
||||||
h1, c = bitsAdd64(h1, cc.hi, c)
|
h1, c = bits.Add64(h1, cc.hi, c)
|
||||||
h2 += c
|
h2 += c
|
||||||
|
|
||||||
// h2 is at most 3 + 1 + 1 = 5, making the whole of h at most
|
// h2 is at most 3 + 1 + 1 = 5, making the whole of h at most
|
||||||
@@ -287,9 +290,9 @@ func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {
|
|||||||
// in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the
|
// in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the
|
||||||
// result if the subtraction underflows, and t otherwise.
|
// result if the subtraction underflows, and t otherwise.
|
||||||
|
|
||||||
hMinusP0, b := bitsSub64(h0, p0, 0)
|
hMinusP0, b := bits.Sub64(h0, p0, 0)
|
||||||
hMinusP1, b := bitsSub64(h1, p1, b)
|
hMinusP1, b := bits.Sub64(h1, p1, b)
|
||||||
_, b = bitsSub64(h2, p2, b)
|
_, b = bits.Sub64(h2, p2, b)
|
||||||
|
|
||||||
// h = h if h < p else h - p
|
// h = h if h < p else h - p
|
||||||
h0 = select64(b, h0, hMinusP0)
|
h0 = select64(b, h0, hMinusP0)
|
||||||
@@ -301,8 +304,8 @@ func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {
|
|||||||
//
|
//
|
||||||
// by just doing a wide addition with the 128 low bits of h and discarding
|
// by just doing a wide addition with the 128 low bits of h and discarding
|
||||||
// the overflow.
|
// the overflow.
|
||||||
h0, c := bitsAdd64(h0, s[0], 0)
|
h0, c := bits.Add64(h0, s[0], 0)
|
||||||
h1, _ = bitsAdd64(h1, s[1], c)
|
h1, _ = bits.Add64(h1, s[1], c)
|
||||||
|
|
||||||
binary.LittleEndian.PutUint64(out[0:8], h0)
|
binary.LittleEndian.PutUint64(out[0:8], h0)
|
||||||
binary.LittleEndian.PutUint64(out[8:16], h1)
|
binary.LittleEndian.PutUint64(out[8:16], h1)
|
||||||
|
|||||||
@@ -319,9 +319,9 @@
|
|||||||
MOVQ rDi, _si(oState); \
|
MOVQ rDi, _si(oState); \
|
||||||
MOVQ rDo, _so(oState) \
|
MOVQ rDo, _so(oState) \
|
||||||
|
|
||||||
// func keccakF1600(state *[25]uint64)
|
// func keccakF1600(a *[25]uint64)
|
||||||
TEXT ·keccakF1600(SB), 0, $200-8
|
TEXT ·keccakF1600(SB), 0, $200-8
|
||||||
MOVQ state+0(FP), rpState
|
MOVQ a+0(FP), rpState
|
||||||
|
|
||||||
// Convert the user state into an internal state
|
// Convert the user state into an internal state
|
||||||
NOTQ _be(rpState)
|
NOTQ _be(rpState)
|
||||||
|
|||||||
+20
-8
@@ -187,9 +187,11 @@ type channel struct {
|
|||||||
pending *buffer
|
pending *buffer
|
||||||
extPending *buffer
|
extPending *buffer
|
||||||
|
|
||||||
// windowMu protects myWindow, the flow-control window.
|
// windowMu protects myWindow, the flow-control window, and myConsumed,
|
||||||
windowMu sync.Mutex
|
// the number of bytes consumed since we last increased myWindow
|
||||||
myWindow uint32
|
windowMu sync.Mutex
|
||||||
|
myWindow uint32
|
||||||
|
myConsumed uint32
|
||||||
|
|
||||||
// writeMu serializes calls to mux.conn.writePacket() and
|
// writeMu serializes calls to mux.conn.writePacket() and
|
||||||
// protects sentClose and packetPool. This mutex must be
|
// protects sentClose and packetPool. This mutex must be
|
||||||
@@ -332,14 +334,24 @@ func (ch *channel) handleData(packet []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *channel) adjustWindow(n uint32) error {
|
func (c *channel) adjustWindow(adj uint32) error {
|
||||||
c.windowMu.Lock()
|
c.windowMu.Lock()
|
||||||
// Since myWindow is managed on our side, and can never exceed
|
// Since myConsumed and myWindow are managed on our side, and can never
|
||||||
// the initial window setting, we don't worry about overflow.
|
// exceed the initial window setting, we don't worry about overflow.
|
||||||
c.myWindow += uint32(n)
|
c.myConsumed += adj
|
||||||
|
var sendAdj uint32
|
||||||
|
if (channelWindowSize-c.myWindow > 3*c.maxIncomingPayload) ||
|
||||||
|
(c.myWindow < channelWindowSize/2) {
|
||||||
|
sendAdj = c.myConsumed
|
||||||
|
c.myConsumed = 0
|
||||||
|
c.myWindow += sendAdj
|
||||||
|
}
|
||||||
c.windowMu.Unlock()
|
c.windowMu.Unlock()
|
||||||
|
if sendAdj == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return c.sendMessage(windowAdjustMsg{
|
return c.sendMessage(windowAdjustMsg{
|
||||||
AdditionalBytes: uint32(n),
|
AdditionalBytes: sendAdj,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -82,7 +82,7 @@ func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan
|
|||||||
|
|
||||||
if err := conn.clientHandshake(addr, &fullConf); err != nil {
|
if err := conn.clientHandshake(addr, &fullConf); err != nil {
|
||||||
c.Close()
|
c.Close()
|
||||||
return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err)
|
return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %w", err)
|
||||||
}
|
}
|
||||||
conn.mux = newMux(conn.transport)
|
conn.mux = newMux(conn.transport)
|
||||||
return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil
|
return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil
|
||||||
|
|||||||
+23
-2
@@ -7,6 +7,9 @@ package ssh
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@@ -207,9 +210,12 @@ func TestBannerCallback(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewClientConn(t *testing.T) {
|
func TestNewClientConn(t *testing.T) {
|
||||||
|
errHostKeyMismatch := errors.New("host key mismatch")
|
||||||
|
|
||||||
for _, tt := range []struct {
|
for _, tt := range []struct {
|
||||||
name string
|
name string
|
||||||
user string
|
user string
|
||||||
|
simulateHostKeyMismatch HostKeyCallback
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "good user field for ConnMetadata",
|
name: "good user field for ConnMetadata",
|
||||||
@@ -219,6 +225,13 @@ func TestNewClientConn(t *testing.T) {
|
|||||||
name: "empty user field for ConnMetadata",
|
name: "empty user field for ConnMetadata",
|
||||||
user: "",
|
user: "",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "host key mismatch",
|
||||||
|
user: "testuser",
|
||||||
|
simulateHostKeyMismatch: func(hostname string, remote net.Addr, key PublicKey) error {
|
||||||
|
return fmt.Errorf("%w: %s", errHostKeyMismatch, bytes.TrimSpace(MarshalAuthorizedKey(key)))
|
||||||
|
},
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
c1, c2, err := netPipe()
|
c1, c2, err := netPipe()
|
||||||
@@ -243,8 +256,16 @@ func TestNewClientConn(t *testing.T) {
|
|||||||
},
|
},
|
||||||
HostKeyCallback: InsecureIgnoreHostKey(),
|
HostKeyCallback: InsecureIgnoreHostKey(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tt.simulateHostKeyMismatch != nil {
|
||||||
|
clientConf.HostKeyCallback = tt.simulateHostKeyMismatch
|
||||||
|
}
|
||||||
|
|
||||||
clientConn, _, _, err := NewClientConn(c2, "", clientConf)
|
clientConn, _, _, err := NewClientConn(c2, "", clientConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if tt.simulateHostKeyMismatch != nil && errors.Is(err, errHostKeyMismatch) {
|
||||||
|
return
|
||||||
|
}
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+52
-4
@@ -35,6 +35,16 @@ type keyingTransport interface {
|
|||||||
// direction will be effected if a msgNewKeys message is sent
|
// direction will be effected if a msgNewKeys message is sent
|
||||||
// or received.
|
// or received.
|
||||||
prepareKeyChange(*algorithms, *kexResult) error
|
prepareKeyChange(*algorithms, *kexResult) error
|
||||||
|
|
||||||
|
// setStrictMode sets the strict KEX mode, notably triggering
|
||||||
|
// sequence number resets on sending or receiving msgNewKeys.
|
||||||
|
// If the sequence number is already > 1 when setStrictMode
|
||||||
|
// is called, an error is returned.
|
||||||
|
setStrictMode() error
|
||||||
|
|
||||||
|
// setInitialKEXDone indicates to the transport that the initial key exchange
|
||||||
|
// was completed
|
||||||
|
setInitialKEXDone()
|
||||||
}
|
}
|
||||||
|
|
||||||
// handshakeTransport implements rekeying on top of a keyingTransport
|
// handshakeTransport implements rekeying on top of a keyingTransport
|
||||||
@@ -100,6 +110,10 @@ type handshakeTransport struct {
|
|||||||
|
|
||||||
// The session ID or nil if first kex did not complete yet.
|
// The session ID or nil if first kex did not complete yet.
|
||||||
sessionID []byte
|
sessionID []byte
|
||||||
|
|
||||||
|
// strictMode indicates if the other side of the handshake indicated
|
||||||
|
// that we should be following the strict KEX protocol restrictions.
|
||||||
|
strictMode bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type pendingKex struct {
|
type pendingKex struct {
|
||||||
@@ -209,7 +223,10 @@ func (t *handshakeTransport) readLoop() {
|
|||||||
close(t.incoming)
|
close(t.incoming)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if p[0] == msgIgnore || p[0] == msgDebug {
|
// If this is the first kex, and strict KEX mode is enabled,
|
||||||
|
// we don't ignore any messages, as they may be used to manipulate
|
||||||
|
// the packet sequence numbers.
|
||||||
|
if !(t.sessionID == nil && t.strictMode) && (p[0] == msgIgnore || p[0] == msgDebug) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
t.incoming <- p
|
t.incoming <- p
|
||||||
@@ -441,6 +458,11 @@ func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) {
|
|||||||
return successPacket, nil
|
return successPacket, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
kexStrictClient = "kex-strict-c-v00@openssh.com"
|
||||||
|
kexStrictServer = "kex-strict-s-v00@openssh.com"
|
||||||
|
)
|
||||||
|
|
||||||
// sendKexInit sends a key change message.
|
// sendKexInit sends a key change message.
|
||||||
func (t *handshakeTransport) sendKexInit() error {
|
func (t *handshakeTransport) sendKexInit() error {
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
@@ -454,7 +476,6 @@ func (t *handshakeTransport) sendKexInit() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
msg := &kexInitMsg{
|
msg := &kexInitMsg{
|
||||||
KexAlgos: t.config.KeyExchanges,
|
|
||||||
CiphersClientServer: t.config.Ciphers,
|
CiphersClientServer: t.config.Ciphers,
|
||||||
CiphersServerClient: t.config.Ciphers,
|
CiphersServerClient: t.config.Ciphers,
|
||||||
MACsClientServer: t.config.MACs,
|
MACsClientServer: t.config.MACs,
|
||||||
@@ -464,6 +485,13 @@ func (t *handshakeTransport) sendKexInit() error {
|
|||||||
}
|
}
|
||||||
io.ReadFull(rand.Reader, msg.Cookie[:])
|
io.ReadFull(rand.Reader, msg.Cookie[:])
|
||||||
|
|
||||||
|
// We mutate the KexAlgos slice, in order to add the kex-strict extension algorithm,
|
||||||
|
// and possibly to add the ext-info extension algorithm. Since the slice may be the
|
||||||
|
// user owned KeyExchanges, we create our own slice in order to avoid using user
|
||||||
|
// owned memory by mistake.
|
||||||
|
msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+2) // room for kex-strict and ext-info
|
||||||
|
msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...)
|
||||||
|
|
||||||
isServer := len(t.hostKeys) > 0
|
isServer := len(t.hostKeys) > 0
|
||||||
if isServer {
|
if isServer {
|
||||||
for _, k := range t.hostKeys {
|
for _, k := range t.hostKeys {
|
||||||
@@ -488,17 +516,24 @@ func (t *handshakeTransport) sendKexInit() error {
|
|||||||
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat)
|
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if t.sessionID == nil {
|
||||||
|
msg.KexAlgos = append(msg.KexAlgos, kexStrictServer)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
msg.ServerHostKeyAlgos = t.hostKeyAlgorithms
|
msg.ServerHostKeyAlgos = t.hostKeyAlgorithms
|
||||||
|
|
||||||
// As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what
|
// As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what
|
||||||
// algorithms the server supports for public key authentication. See RFC
|
// algorithms the server supports for public key authentication. See RFC
|
||||||
// 8308, Section 2.1.
|
// 8308, Section 2.1.
|
||||||
|
//
|
||||||
|
// We also send the strict KEX mode extension algorithm, in order to opt
|
||||||
|
// into the strict KEX mode.
|
||||||
if firstKeyExchange := t.sessionID == nil; firstKeyExchange {
|
if firstKeyExchange := t.sessionID == nil; firstKeyExchange {
|
||||||
msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+1)
|
|
||||||
msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...)
|
|
||||||
msg.KexAlgos = append(msg.KexAlgos, "ext-info-c")
|
msg.KexAlgos = append(msg.KexAlgos, "ext-info-c")
|
||||||
|
msg.KexAlgos = append(msg.KexAlgos, kexStrictClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
packet := Marshal(msg)
|
packet := Marshal(msg)
|
||||||
@@ -604,6 +639,13 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if t.sessionID == nil && ((isClient && contains(serverInit.KexAlgos, kexStrictServer)) || (!isClient && contains(clientInit.KexAlgos, kexStrictClient))) {
|
||||||
|
t.strictMode = true
|
||||||
|
if err := t.conn.setStrictMode(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We don't send FirstKexFollows, but we handle receiving it.
|
// We don't send FirstKexFollows, but we handle receiving it.
|
||||||
//
|
//
|
||||||
// RFC 4253 section 7 defines the kex and the agreement method for
|
// RFC 4253 section 7 defines the kex and the agreement method for
|
||||||
@@ -679,6 +721,12 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
|
|||||||
return unexpectedMessageError(msgNewKeys, packet[0])
|
return unexpectedMessageError(msgNewKeys, packet[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if firstKeyExchange {
|
||||||
|
// Indicates to the transport that the first key exchange is completed
|
||||||
|
// after receiving SSH_MSG_NEWKEYS.
|
||||||
|
t.conn.setInitialKEXDone()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -395,6 +395,10 @@ func (n *errorKeyingTransport) readPacket() ([]byte, error) {
|
|||||||
return n.packetConn.readPacket()
|
return n.packetConn.readPacket()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *errorKeyingTransport) setStrictMode() error { return nil }
|
||||||
|
|
||||||
|
func (n *errorKeyingTransport) setInitialKEXDone() {}
|
||||||
|
|
||||||
func TestHandshakeErrorHandlingRead(t *testing.T) {
|
func TestHandshakeErrorHandlingRead(t *testing.T) {
|
||||||
for i := 0; i < 20; i++ {
|
for i := 0; i < 20; i++ {
|
||||||
testHandshakeErrorHandlingN(t, i, -1, false)
|
testHandshakeErrorHandlingN(t, i, -1, false)
|
||||||
@@ -710,3 +714,308 @@ func TestPickIncompatibleHostKeyAlgo(t *testing.T) {
|
|||||||
t.Fatal("incompatible signer returned")
|
t.Fatal("incompatible signer returned")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStrictKEXResetSeqFirstKEX(t *testing.T) {
|
||||||
|
if runtime.GOOS == "plan9" {
|
||||||
|
t.Skip("see golang.org/issue/7237")
|
||||||
|
}
|
||||||
|
|
||||||
|
checker := &syncChecker{
|
||||||
|
waitCall: make(chan int, 10),
|
||||||
|
called: make(chan int, 10),
|
||||||
|
}
|
||||||
|
|
||||||
|
checker.waitCall <- 1
|
||||||
|
trC, trS, err := handshakePair(&ClientConfig{HostKeyCallback: checker.Check}, "addr", false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("handshakePair: %v", err)
|
||||||
|
}
|
||||||
|
<-checker.called
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
trC.Close()
|
||||||
|
trS.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Throw away the msgExtInfo packet sent during the handshake by the server
|
||||||
|
_, err = trC.readPacket()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("readPacket failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// close the handshake transports before checking the sequence number to
|
||||||
|
// avoid races.
|
||||||
|
trC.Close()
|
||||||
|
trS.Close()
|
||||||
|
|
||||||
|
// check that the sequence number counters. We reset after msgNewKeys, but
|
||||||
|
// then the server immediately writes msgExtInfo, and we close the
|
||||||
|
// transports so we expect read 2, write 0 on the client and read 1, write 1
|
||||||
|
// on the server.
|
||||||
|
if trC.conn.(*transport).reader.seqNum != 2 || trC.conn.(*transport).writer.seqNum != 0 ||
|
||||||
|
trS.conn.(*transport).reader.seqNum != 1 || trS.conn.(*transport).writer.seqNum != 1 {
|
||||||
|
t.Errorf(
|
||||||
|
"unexpected sequence counters:\nclient: reader %d (expected 2), writer %d (expected 0)\nserver: reader %d (expected 1), writer %d (expected 1)",
|
||||||
|
trC.conn.(*transport).reader.seqNum,
|
||||||
|
trC.conn.(*transport).writer.seqNum,
|
||||||
|
trS.conn.(*transport).reader.seqNum,
|
||||||
|
trS.conn.(*transport).writer.seqNum,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStrictKEXResetSeqSuccessiveKEX(t *testing.T) {
|
||||||
|
if runtime.GOOS == "plan9" {
|
||||||
|
t.Skip("see golang.org/issue/7237")
|
||||||
|
}
|
||||||
|
|
||||||
|
checker := &syncChecker{
|
||||||
|
waitCall: make(chan int, 10),
|
||||||
|
called: make(chan int, 10),
|
||||||
|
}
|
||||||
|
|
||||||
|
checker.waitCall <- 1
|
||||||
|
trC, trS, err := handshakePair(&ClientConfig{HostKeyCallback: checker.Check}, "addr", false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("handshakePair: %v", err)
|
||||||
|
}
|
||||||
|
<-checker.called
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
trC.Close()
|
||||||
|
trS.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Throw away the msgExtInfo packet sent during the handshake by the server
|
||||||
|
_, err = trC.readPacket()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("readPacket failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// write and read five packets on either side to bump the sequence numbers
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
if err := trC.writePacket([]byte{msgRequestSuccess}); err != nil {
|
||||||
|
t.Fatalf("writePacket failed: %s", err)
|
||||||
|
}
|
||||||
|
if _, err := trS.readPacket(); err != nil {
|
||||||
|
t.Fatalf("readPacket failed: %s", err)
|
||||||
|
}
|
||||||
|
if err := trS.writePacket([]byte{msgRequestSuccess}); err != nil {
|
||||||
|
t.Fatalf("writePacket failed: %s", err)
|
||||||
|
}
|
||||||
|
if _, err := trC.readPacket(); err != nil {
|
||||||
|
t.Fatalf("readPacket failed: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request a key exchange, which should cause the sequence numbers to reset
|
||||||
|
checker.waitCall <- 1
|
||||||
|
trC.requestKeyExchange()
|
||||||
|
<-checker.called
|
||||||
|
|
||||||
|
// write a packet on the client, and then read it, to verify the key change has actually happened, since
|
||||||
|
// the HostKeyCallback is called _during_ the handshake, so isn't actually indicative of the handshake
|
||||||
|
// finishing.
|
||||||
|
dummyPacket := []byte{99}
|
||||||
|
if err := trS.writePacket(dummyPacket); err != nil {
|
||||||
|
t.Fatalf("writePacket failed: %s", err)
|
||||||
|
}
|
||||||
|
if p, err := trC.readPacket(); err != nil {
|
||||||
|
t.Fatalf("readPacket failed: %s", err)
|
||||||
|
} else if !bytes.Equal(p, dummyPacket) {
|
||||||
|
t.Fatalf("unexpected packet: got %x, want %x", p, dummyPacket)
|
||||||
|
}
|
||||||
|
|
||||||
|
// close the handshake transports before checking the sequence number to
|
||||||
|
// avoid races.
|
||||||
|
trC.Close()
|
||||||
|
trS.Close()
|
||||||
|
|
||||||
|
if trC.conn.(*transport).reader.seqNum != 2 || trC.conn.(*transport).writer.seqNum != 0 ||
|
||||||
|
trS.conn.(*transport).reader.seqNum != 1 || trS.conn.(*transport).writer.seqNum != 1 {
|
||||||
|
t.Errorf(
|
||||||
|
"unexpected sequence counters:\nclient: reader %d (expected 2), writer %d (expected 0)\nserver: reader %d (expected 1), writer %d (expected 1)",
|
||||||
|
trC.conn.(*transport).reader.seqNum,
|
||||||
|
trC.conn.(*transport).writer.seqNum,
|
||||||
|
trS.conn.(*transport).reader.seqNum,
|
||||||
|
trS.conn.(*transport).writer.seqNum,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSeqNumIncrease(t *testing.T) {
|
||||||
|
if runtime.GOOS == "plan9" {
|
||||||
|
t.Skip("see golang.org/issue/7237")
|
||||||
|
}
|
||||||
|
|
||||||
|
checker := &syncChecker{
|
||||||
|
waitCall: make(chan int, 10),
|
||||||
|
called: make(chan int, 10),
|
||||||
|
}
|
||||||
|
|
||||||
|
checker.waitCall <- 1
|
||||||
|
trC, trS, err := handshakePair(&ClientConfig{HostKeyCallback: checker.Check}, "addr", false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("handshakePair: %v", err)
|
||||||
|
}
|
||||||
|
<-checker.called
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
trC.Close()
|
||||||
|
trS.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Throw away the msgExtInfo packet sent during the handshake by the server
|
||||||
|
_, err = trC.readPacket()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("readPacket failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// write and read five packets on either side to bump the sequence numbers
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
if err := trC.writePacket([]byte{msgRequestSuccess}); err != nil {
|
||||||
|
t.Fatalf("writePacket failed: %s", err)
|
||||||
|
}
|
||||||
|
if _, err := trS.readPacket(); err != nil {
|
||||||
|
t.Fatalf("readPacket failed: %s", err)
|
||||||
|
}
|
||||||
|
if err := trS.writePacket([]byte{msgRequestSuccess}); err != nil {
|
||||||
|
t.Fatalf("writePacket failed: %s", err)
|
||||||
|
}
|
||||||
|
if _, err := trC.readPacket(); err != nil {
|
||||||
|
t.Fatalf("readPacket failed: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// close the handshake transports before checking the sequence number to
|
||||||
|
// avoid races.
|
||||||
|
trC.Close()
|
||||||
|
trS.Close()
|
||||||
|
|
||||||
|
if trC.conn.(*transport).reader.seqNum != 7 || trC.conn.(*transport).writer.seqNum != 5 ||
|
||||||
|
trS.conn.(*transport).reader.seqNum != 6 || trS.conn.(*transport).writer.seqNum != 6 {
|
||||||
|
t.Errorf(
|
||||||
|
"unexpected sequence counters:\nclient: reader %d (expected 7), writer %d (expected 5)\nserver: reader %d (expected 6), writer %d (expected 6)",
|
||||||
|
trC.conn.(*transport).reader.seqNum,
|
||||||
|
trC.conn.(*transport).writer.seqNum,
|
||||||
|
trS.conn.(*transport).reader.seqNum,
|
||||||
|
trS.conn.(*transport).writer.seqNum,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStrictKEXUnexpectedMsg(t *testing.T) {
|
||||||
|
if runtime.GOOS == "plan9" {
|
||||||
|
t.Skip("see golang.org/issue/7237")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that unexpected messages during the handshake cause failure
|
||||||
|
_, _, err := handshakePair(&ClientConfig{HostKeyCallback: func(hostname string, remote net.Addr, key PublicKey) error { return nil }}, "addr", true)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("handshake should fail when there are unexpected messages during the handshake")
|
||||||
|
}
|
||||||
|
|
||||||
|
trC, trS, err := handshakePair(&ClientConfig{HostKeyCallback: func(hostname string, remote net.Addr, key PublicKey) error { return nil }}, "addr", false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("handshake failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that ignore/debug pacekts are still ignored outside of the handshake
|
||||||
|
if err := trC.writePacket([]byte{msgIgnore}); err != nil {
|
||||||
|
t.Fatalf("writePacket failed: %s", err)
|
||||||
|
}
|
||||||
|
if err := trC.writePacket([]byte{msgDebug}); err != nil {
|
||||||
|
t.Fatalf("writePacket failed: %s", err)
|
||||||
|
}
|
||||||
|
dummyPacket := []byte{99}
|
||||||
|
if err := trC.writePacket(dummyPacket); err != nil {
|
||||||
|
t.Fatalf("writePacket failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p, err := trS.readPacket(); err != nil {
|
||||||
|
t.Fatalf("readPacket failed: %s", err)
|
||||||
|
} else if !bytes.Equal(p, dummyPacket) {
|
||||||
|
t.Fatalf("unexpected packet: got %x, want %x", p, dummyPacket)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStrictKEXMixed(t *testing.T) {
|
||||||
|
// Test that we still support a mixed connection, where one side sends kex-strict but the other
|
||||||
|
// side doesn't.
|
||||||
|
|
||||||
|
a, b, err := netPipe()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("netPipe failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var trC, trS keyingTransport
|
||||||
|
|
||||||
|
trC = newTransport(a, rand.Reader, true)
|
||||||
|
trS = newTransport(b, rand.Reader, false)
|
||||||
|
trS = addNoiseTransport(trS)
|
||||||
|
|
||||||
|
clientConf := &ClientConfig{HostKeyCallback: func(hostname string, remote net.Addr, key PublicKey) error { return nil }}
|
||||||
|
clientConf.SetDefaults()
|
||||||
|
|
||||||
|
v := []byte("version")
|
||||||
|
client := newClientTransport(trC, v, v, clientConf, "addr", a.RemoteAddr())
|
||||||
|
|
||||||
|
serverConf := &ServerConfig{}
|
||||||
|
serverConf.AddHostKey(testSigners["ecdsa"])
|
||||||
|
serverConf.AddHostKey(testSigners["rsa"])
|
||||||
|
serverConf.SetDefaults()
|
||||||
|
|
||||||
|
transport := newHandshakeTransport(trS, &serverConf.Config, []byte("version"), []byte("version"))
|
||||||
|
transport.hostKeys = serverConf.hostKeys
|
||||||
|
transport.publicKeyAuthAlgorithms = serverConf.PublicKeyAuthAlgorithms
|
||||||
|
|
||||||
|
readOneFailure := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
if _, err := transport.readOnePacket(true); err != nil {
|
||||||
|
readOneFailure <- err
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Basically sendKexInit, but without the kex-strict extension algorithm
|
||||||
|
msg := &kexInitMsg{
|
||||||
|
KexAlgos: transport.config.KeyExchanges,
|
||||||
|
CiphersClientServer: transport.config.Ciphers,
|
||||||
|
CiphersServerClient: transport.config.Ciphers,
|
||||||
|
MACsClientServer: transport.config.MACs,
|
||||||
|
MACsServerClient: transport.config.MACs,
|
||||||
|
CompressionClientServer: supportedCompressions,
|
||||||
|
CompressionServerClient: supportedCompressions,
|
||||||
|
ServerHostKeyAlgos: []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA},
|
||||||
|
}
|
||||||
|
packet := Marshal(msg)
|
||||||
|
// writePacket destroys the contents, so save a copy.
|
||||||
|
packetCopy := make([]byte, len(packet))
|
||||||
|
copy(packetCopy, packet)
|
||||||
|
if err := transport.pushPacket(packetCopy); err != nil {
|
||||||
|
t.Fatalf("pushPacket: %s", err)
|
||||||
|
}
|
||||||
|
transport.sentInitMsg = msg
|
||||||
|
transport.sentInitPacket = packet
|
||||||
|
|
||||||
|
if err := transport.getWriteError(); err != nil {
|
||||||
|
t.Fatalf("getWriteError failed: %s", err)
|
||||||
|
}
|
||||||
|
var request *pendingKex
|
||||||
|
select {
|
||||||
|
case err = <-readOneFailure:
|
||||||
|
t.Fatalf("server readOnePacket failed: %s", err)
|
||||||
|
case request = <-transport.startKex:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// We expect the following calls to fail if the side which does not support
|
||||||
|
// kex-strict sends unexpected/ignored packets during the handshake, even if
|
||||||
|
// the other side does support kex-strict.
|
||||||
|
|
||||||
|
if err := transport.enterKeyExchange(request.otherInit); err != nil {
|
||||||
|
t.Fatalf("enterKeyExchange failed: %s", err)
|
||||||
|
}
|
||||||
|
if err := client.waitSession(); err != nil {
|
||||||
|
t.Fatalf("client.waitSession: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+17
-3
@@ -13,9 +13,10 @@ import (
|
|||||||
// An in-memory packetConn. It is safe to call Close and writePacket
|
// An in-memory packetConn. It is safe to call Close and writePacket
|
||||||
// from different goroutines.
|
// from different goroutines.
|
||||||
type memTransport struct {
|
type memTransport struct {
|
||||||
eof bool
|
eof bool
|
||||||
pending [][]byte
|
pending [][]byte
|
||||||
write *memTransport
|
write *memTransport
|
||||||
|
writeCount uint64
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
*sync.Cond
|
*sync.Cond
|
||||||
}
|
}
|
||||||
@@ -63,9 +64,16 @@ func (t *memTransport) writePacket(p []byte) error {
|
|||||||
copy(c, p)
|
copy(c, p)
|
||||||
t.write.pending = append(t.write.pending, c)
|
t.write.pending = append(t.write.pending, c)
|
||||||
t.write.Cond.Signal()
|
t.write.Cond.Signal()
|
||||||
|
t.writeCount++
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *memTransport) getWriteCount() uint64 {
|
||||||
|
t.write.Lock()
|
||||||
|
defer t.write.Unlock()
|
||||||
|
return t.writeCount
|
||||||
|
}
|
||||||
|
|
||||||
func memPipe() (a, b packetConn) {
|
func memPipe() (a, b packetConn) {
|
||||||
t1 := memTransport{}
|
t1 := memTransport{}
|
||||||
t2 := memTransport{}
|
t2 := memTransport{}
|
||||||
@@ -81,6 +89,9 @@ func TestMemPipe(t *testing.T) {
|
|||||||
if err := a.writePacket([]byte{42}); err != nil {
|
if err := a.writePacket([]byte{42}); err != nil {
|
||||||
t.Fatalf("writePacket: %v", err)
|
t.Fatalf("writePacket: %v", err)
|
||||||
}
|
}
|
||||||
|
if wc := a.(*memTransport).getWriteCount(); wc != 1 {
|
||||||
|
t.Fatalf("got %v, want 1", wc)
|
||||||
|
}
|
||||||
if err := a.Close(); err != nil {
|
if err := a.Close(); err != nil {
|
||||||
t.Fatal("Close: ", err)
|
t.Fatal("Close: ", err)
|
||||||
}
|
}
|
||||||
@@ -95,6 +106,9 @@ func TestMemPipe(t *testing.T) {
|
|||||||
if err != io.EOF {
|
if err != io.EOF {
|
||||||
t.Fatalf("got %v, %v, want EOF", p, err)
|
t.Fatalf("got %v, %v, want EOF", p, err)
|
||||||
}
|
}
|
||||||
|
if wc := b.(*memTransport).getWriteCount(); wc != 0 {
|
||||||
|
t.Fatalf("got %v, want 0", wc)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDoubleClose(t *testing.T) {
|
func TestDoubleClose(t *testing.T) {
|
||||||
|
|||||||
@@ -182,6 +182,40 @@ func TestMuxChannelOverflow(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMuxChannelReadUnblock(t *testing.T) {
|
||||||
|
reader, writer, mux := channelPair(t)
|
||||||
|
defer reader.Close()
|
||||||
|
defer writer.Close()
|
||||||
|
defer mux.Close()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
t.Cleanup(wg.Wait)
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
if _, err := writer.Write(make([]byte, channelWindowSize)); err != nil {
|
||||||
|
t.Errorf("could not fill window: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := writer.Write(make([]byte, 1)); err != nil {
|
||||||
|
t.Errorf("Write: %v", err)
|
||||||
|
}
|
||||||
|
writer.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
writer.remoteWin.waitWriterBlocked()
|
||||||
|
|
||||||
|
buf := make([]byte, 32768)
|
||||||
|
for {
|
||||||
|
_, err := reader.Read(buf)
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Read: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMuxChannelCloseWriteUnblock(t *testing.T) {
|
func TestMuxChannelCloseWriteUnblock(t *testing.T) {
|
||||||
reader, writer, mux := channelPair(t)
|
reader, writer, mux := channelPair(t)
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
@@ -754,6 +788,43 @@ func TestMuxMaxPacketSize(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMuxChannelWindowDeferredUpdates(t *testing.T) {
|
||||||
|
s, c, mux := channelPair(t)
|
||||||
|
cTransport := mux.conn.(*memTransport)
|
||||||
|
defer s.Close()
|
||||||
|
defer c.Close()
|
||||||
|
defer mux.Close()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
t.Cleanup(wg.Wait)
|
||||||
|
|
||||||
|
data := make([]byte, 1024)
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
_, err := s.Write(data)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Write: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
cWritesInit := cTransport.getWriteCount()
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
for i := 0; i < len(data); i++ {
|
||||||
|
n, err := c.Read(buf)
|
||||||
|
if n != len(buf) || err != nil {
|
||||||
|
t.Fatalf("Read: %v, %v", n, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cWrites := cTransport.getWriteCount() - cWritesInit
|
||||||
|
// reading 1 KiB should not cause any window updates to be sent, but allow
|
||||||
|
// for some unexpected writes
|
||||||
|
if cWrites > 30 {
|
||||||
|
t.Fatalf("reading 1 KiB from channel caused %v writes", cWrites)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Don't ship code with debug=true.
|
// Don't ship code with debug=true.
|
||||||
func TestDebug(t *testing.T) {
|
func TestDebug(t *testing.T) {
|
||||||
if debugMux {
|
if debugMux {
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewCha
|
|||||||
} else {
|
} else {
|
||||||
for _, algo := range fullConf.PublicKeyAuthAlgorithms {
|
for _, algo := range fullConf.PublicKeyAuthAlgorithms {
|
||||||
if !contains(supportedPubKeyAuthAlgos, algo) {
|
if !contains(supportedPubKeyAuthAlgos, algo) {
|
||||||
|
c.Close()
|
||||||
return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
|
return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,6 +221,7 @@ func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewCha
|
|||||||
// Check if the config contains any unsupported key exchanges
|
// Check if the config contains any unsupported key exchanges
|
||||||
for _, kex := range fullConf.KeyExchanges {
|
for _, kex := range fullConf.KeyExchanges {
|
||||||
if _, ok := serverForbiddenKexAlgos[kex]; ok {
|
if _, ok := serverForbiddenKexAlgos[kex]; ok {
|
||||||
|
c.Close()
|
||||||
return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex)
|
return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+64
-9
@@ -5,7 +5,11 @@
|
|||||||
package ssh
|
package ssh
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestClientAuthRestrictedPublicKeyAlgos(t *testing.T) {
|
func TestClientAuthRestrictedPublicKeyAlgos(t *testing.T) {
|
||||||
@@ -59,27 +63,78 @@ func TestClientAuthRestrictedPublicKeyAlgos(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewServerConnValidationErrors(t *testing.T) {
|
func TestNewServerConnValidationErrors(t *testing.T) {
|
||||||
c1, c2, err := netPipe()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("netPipe: %v", err)
|
|
||||||
}
|
|
||||||
defer c1.Close()
|
|
||||||
defer c2.Close()
|
|
||||||
|
|
||||||
serverConf := &ServerConfig{
|
serverConf := &ServerConfig{
|
||||||
PublicKeyAuthAlgorithms: []string{CertAlgoRSAv01},
|
PublicKeyAuthAlgorithms: []string{CertAlgoRSAv01},
|
||||||
}
|
}
|
||||||
_, _, _, err = NewServerConn(c1, serverConf)
|
c := &markerConn{}
|
||||||
|
_, _, _, err := NewServerConn(c, serverConf)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("NewServerConn with invalid public key auth algorithms succeeded")
|
t.Fatal("NewServerConn with invalid public key auth algorithms succeeded")
|
||||||
}
|
}
|
||||||
|
if !c.isClosed() {
|
||||||
|
t.Fatal("NewServerConn with invalid public key auth algorithms left connection open")
|
||||||
|
}
|
||||||
|
if c.isUsed() {
|
||||||
|
t.Fatal("NewServerConn with invalid public key auth algorithms used connection")
|
||||||
|
}
|
||||||
|
|
||||||
serverConf = &ServerConfig{
|
serverConf = &ServerConfig{
|
||||||
Config: Config{
|
Config: Config{
|
||||||
KeyExchanges: []string{kexAlgoDHGEXSHA256},
|
KeyExchanges: []string{kexAlgoDHGEXSHA256},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, _, _, err = NewServerConn(c1, serverConf)
|
c = &markerConn{}
|
||||||
|
_, _, _, err = NewServerConn(c, serverConf)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("NewServerConn with unsupported key exchange succeeded")
|
t.Fatal("NewServerConn with unsupported key exchange succeeded")
|
||||||
}
|
}
|
||||||
|
if !c.isClosed() {
|
||||||
|
t.Fatal("NewServerConn with unsupported key exchange left connection open")
|
||||||
|
}
|
||||||
|
if c.isUsed() {
|
||||||
|
t.Fatal("NewServerConn with unsupported key exchange used connection")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type markerConn struct {
|
||||||
|
closed uint32
|
||||||
|
used uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *markerConn) isClosed() bool {
|
||||||
|
return atomic.LoadUint32(&c.closed) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *markerConn) isUsed() bool {
|
||||||
|
return atomic.LoadUint32(&c.used) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *markerConn) Close() error {
|
||||||
|
atomic.StoreUint32(&c.closed, 1)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *markerConn) Read(b []byte) (n int, err error) {
|
||||||
|
atomic.StoreUint32(&c.used, 1)
|
||||||
|
if atomic.LoadUint32(&c.closed) != 0 {
|
||||||
|
return 0, net.ErrClosed
|
||||||
|
} else {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *markerConn) Write(b []byte) (n int, err error) {
|
||||||
|
atomic.StoreUint32(&c.used, 1)
|
||||||
|
if atomic.LoadUint32(&c.closed) != 0 {
|
||||||
|
return 0, net.ErrClosed
|
||||||
|
} else {
|
||||||
|
return 0, io.ErrClosedPipe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*markerConn) LocalAddr() net.Addr { return nil }
|
||||||
|
func (*markerConn) RemoteAddr() net.Addr { return nil }
|
||||||
|
|
||||||
|
func (*markerConn) SetDeadline(t time.Time) error { return nil }
|
||||||
|
func (*markerConn) SetReadDeadline(t time.Time) error { return nil }
|
||||||
|
func (*markerConn) SetWriteDeadline(t time.Time) error { return nil }
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ func TestAgentForward(t *testing.T) {
|
|||||||
|
|
||||||
sess, err := conn.NewSession()
|
sess, err := conn.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
skipIfIssue64959(t, err)
|
||||||
t.Fatalf("NewSession: %v", err)
|
t.Fatalf("NewSession: %v", err)
|
||||||
}
|
}
|
||||||
if err := agent.RequestAgentForwarding(sess); err != nil {
|
if err := agent.RequestAgentForwarding(sess); err != nil {
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ func testDial(t *testing.T, n, listenAddr string, x dialTester) {
|
|||||||
// on the opened connection.
|
// on the opened connection.
|
||||||
cancel()
|
cancel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
skipIfIssue64959(t, err)
|
||||||
t.Fatalf("Dial: %v", err)
|
t.Fatalf("Dial: %v", err)
|
||||||
}
|
}
|
||||||
x.TestClientConn(t, conn)
|
x.TestClientConn(t, conn)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -27,6 +28,9 @@ func testPortForward(t *testing.T, n, listenAddr string) {
|
|||||||
|
|
||||||
sshListener, err := conn.Listen(n, listenAddr)
|
sshListener, err := conn.Listen(n, listenAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if runtime.GOOS == "darwin" && err == io.EOF {
|
||||||
|
t.Skipf("skipping test broken on some versions of macOS; see https://go.dev/issue/64959")
|
||||||
|
}
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,6 +126,9 @@ func testAcceptClose(t *testing.T, n, listenAddr string) {
|
|||||||
|
|
||||||
sshListener, err := conn.Listen(n, listenAddr)
|
sshListener, err := conn.Listen(n, listenAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if runtime.GOOS == "darwin" && err == io.EOF {
|
||||||
|
t.Skipf("skipping test broken on some versions of macOS; see https://go.dev/issue/64959")
|
||||||
|
}
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,6 +170,9 @@ func testPortForwardConnectionClose(t *testing.T, n, listenAddr string) {
|
|||||||
|
|
||||||
sshListener, err := client.Listen(n, listenAddr)
|
sshListener, err := client.Listen(n, listenAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if runtime.GOOS == "darwin" && err == io.EOF {
|
||||||
|
t.Skipf("skipping test broken on some versions of macOS; see https://go.dev/issue/64959")
|
||||||
|
}
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,13 @@ import (
|
|||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func skipIfIssue64959(t *testing.T, err error) {
|
||||||
|
if err != nil && runtime.GOOS == "darwin" && strings.Contains(err.Error(), "ssh: unexpected packet in response to channel open: <nil>") {
|
||||||
|
t.Helper()
|
||||||
|
t.Skipf("skipping test broken on some versions of macOS; see https://go.dev/issue/64959")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRunCommandSuccess(t *testing.T) {
|
func TestRunCommandSuccess(t *testing.T) {
|
||||||
server := newServer(t)
|
server := newServer(t)
|
||||||
conn := server.Dial(clientConfig())
|
conn := server.Dial(clientConfig())
|
||||||
@@ -29,6 +36,7 @@ func TestRunCommandSuccess(t *testing.T) {
|
|||||||
|
|
||||||
session, err := conn.NewSession()
|
session, err := conn.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
skipIfIssue64959(t, err)
|
||||||
t.Fatalf("session failed: %v", err)
|
t.Fatalf("session failed: %v", err)
|
||||||
}
|
}
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
@@ -66,6 +74,7 @@ func TestRunCommandStdin(t *testing.T) {
|
|||||||
|
|
||||||
session, err := conn.NewSession()
|
session, err := conn.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
skipIfIssue64959(t, err)
|
||||||
t.Fatalf("session failed: %v", err)
|
t.Fatalf("session failed: %v", err)
|
||||||
}
|
}
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
@@ -88,6 +97,7 @@ func TestRunCommandStdinError(t *testing.T) {
|
|||||||
|
|
||||||
session, err := conn.NewSession()
|
session, err := conn.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
skipIfIssue64959(t, err)
|
||||||
t.Fatalf("session failed: %v", err)
|
t.Fatalf("session failed: %v", err)
|
||||||
}
|
}
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
@@ -111,6 +121,7 @@ func TestRunCommandFailed(t *testing.T) {
|
|||||||
|
|
||||||
session, err := conn.NewSession()
|
session, err := conn.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
skipIfIssue64959(t, err)
|
||||||
t.Fatalf("session failed: %v", err)
|
t.Fatalf("session failed: %v", err)
|
||||||
}
|
}
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
@@ -127,6 +138,7 @@ func TestRunCommandWeClosed(t *testing.T) {
|
|||||||
|
|
||||||
session, err := conn.NewSession()
|
session, err := conn.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
skipIfIssue64959(t, err)
|
||||||
t.Fatalf("session failed: %v", err)
|
t.Fatalf("session failed: %v", err)
|
||||||
}
|
}
|
||||||
err = session.Shell()
|
err = session.Shell()
|
||||||
@@ -146,6 +158,7 @@ func TestFuncLargeRead(t *testing.T) {
|
|||||||
|
|
||||||
session, err := conn.NewSession()
|
session, err := conn.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
skipIfIssue64959(t, err)
|
||||||
t.Fatalf("unable to create new session: %s", err)
|
t.Fatalf("unable to create new session: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,6 +195,7 @@ func TestKeyChange(t *testing.T) {
|
|||||||
for i := 0; i < 4; i++ {
|
for i := 0; i < 4; i++ {
|
||||||
session, err := conn.NewSession()
|
session, err := conn.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
skipIfIssue64959(t, err)
|
||||||
t.Fatalf("unable to create new session: %s", err)
|
t.Fatalf("unable to create new session: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,6 +237,7 @@ func TestValidTerminalMode(t *testing.T) {
|
|||||||
|
|
||||||
session, err := conn.NewSession()
|
session, err := conn.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
skipIfIssue64959(t, err)
|
||||||
t.Fatalf("session failed: %v", err)
|
t.Fatalf("session failed: %v", err)
|
||||||
}
|
}
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
@@ -287,6 +302,7 @@ func TestWindowChange(t *testing.T) {
|
|||||||
|
|
||||||
session, err := conn.NewSession()
|
session, err := conn.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
skipIfIssue64959(t, err)
|
||||||
t.Fatalf("session failed: %v", err)
|
t.Fatalf("session failed: %v", err)
|
||||||
}
|
}
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
@@ -349,6 +365,7 @@ func testOneCipher(t *testing.T, cipher string, cipherOrder []string) {
|
|||||||
// Exercise receiving data from the server
|
// Exercise receiving data from the server
|
||||||
session, err := conn.NewSession()
|
session, err := conn.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
skipIfIssue64959(t, err)
|
||||||
t.Fatalf("NewSession: %v", err)
|
t.Fatalf("NewSession: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ func (s *server) TryDial(config *ssh.ClientConfig) (*ssh.Client, error) {
|
|||||||
|
|
||||||
// addr is the user specified host:port. While we don't actually dial it,
|
// addr is the user specified host:port. While we don't actually dial it,
|
||||||
// we need to know this for host key matching
|
// we need to know this for host key matching
|
||||||
func (s *server) TryDialWithAddr(config *ssh.ClientConfig, addr string) (*ssh.Client, error) {
|
func (s *server) TryDialWithAddr(config *ssh.ClientConfig, addr string) (client *ssh.Client, err error) {
|
||||||
sshd, err := exec.LookPath("sshd")
|
sshd, err := exec.LookPath("sshd")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.t.Skipf("skipping test: %v", err)
|
s.t.Skipf("skipping test: %v", err)
|
||||||
@@ -188,13 +188,26 @@ func (s *server) TryDialWithAddr(config *ssh.ClientConfig, addr string) (*ssh.Cl
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
s.t.Fatalf("unixConnection: %v", err)
|
s.t.Fatalf("unixConnection: %v", err)
|
||||||
}
|
}
|
||||||
|
defer func() {
|
||||||
|
// Close c2 after we've started the sshd command so that it won't prevent c1
|
||||||
|
// from returning EOF when the sshd command exits.
|
||||||
|
c2.Close()
|
||||||
|
|
||||||
|
// Leave c1 open if we're returning a client that wraps it.
|
||||||
|
// (The client is responsible for closing it.)
|
||||||
|
// Otherwise, close it to free up the socket.
|
||||||
|
if client == nil {
|
||||||
|
c1.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
cmd := testenv.Command(s.t, sshd, "-f", s.configfile, "-i", "-e")
|
|
||||||
f, err := c2.File()
|
f, err := c2.File()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.t.Fatalf("UnixConn.File: %v", err)
|
s.t.Fatalf("UnixConn.File: %v", err)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
|
cmd := testenv.Command(s.t, sshd, "-f", s.configfile, "-i", "-e")
|
||||||
cmd.Stdin = f
|
cmd.Stdin = f
|
||||||
cmd.Stdout = f
|
cmd.Stdout = f
|
||||||
cmd.Stderr = new(bytes.Buffer)
|
cmd.Stderr = new(bytes.Buffer)
|
||||||
@@ -223,7 +236,7 @@ func (s *server) TryDialWithAddr(config *ssh.ClientConfig, addr string) (*ssh.Cl
|
|||||||
// processes are killed too.
|
// processes are killed too.
|
||||||
cmd.Process.Signal(os.Interrupt)
|
cmd.Process.Signal(os.Interrupt)
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
if s.t.Failed() {
|
if s.t.Failed() || testing.Verbose() {
|
||||||
// log any output from sshd process
|
// log any output from sshd process
|
||||||
s.t.Logf("sshd:\n%s", cmd.Stderr)
|
s.t.Logf("sshd:\n%s", cmd.Stderr)
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-5
@@ -49,6 +49,9 @@ type transport struct {
|
|||||||
rand io.Reader
|
rand io.Reader
|
||||||
isClient bool
|
isClient bool
|
||||||
io.Closer
|
io.Closer
|
||||||
|
|
||||||
|
strictMode bool
|
||||||
|
initialKEXDone bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// packetCipher represents a combination of SSH encryption/MAC
|
// packetCipher represents a combination of SSH encryption/MAC
|
||||||
@@ -74,6 +77,18 @@ type connectionState struct {
|
|||||||
pendingKeyChange chan packetCipher
|
pendingKeyChange chan packetCipher
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *transport) setStrictMode() error {
|
||||||
|
if t.reader.seqNum != 1 {
|
||||||
|
return errors.New("ssh: sequence number != 1 when strict KEX mode requested")
|
||||||
|
}
|
||||||
|
t.strictMode = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *transport) setInitialKEXDone() {
|
||||||
|
t.initialKEXDone = true
|
||||||
|
}
|
||||||
|
|
||||||
// prepareKeyChange sets up key material for a keychange. The key changes in
|
// prepareKeyChange sets up key material for a keychange. The key changes in
|
||||||
// both directions are triggered by reading and writing a msgNewKey packet
|
// both directions are triggered by reading and writing a msgNewKey packet
|
||||||
// respectively.
|
// respectively.
|
||||||
@@ -112,11 +127,12 @@ func (t *transport) printPacket(p []byte, write bool) {
|
|||||||
// Read and decrypt next packet.
|
// Read and decrypt next packet.
|
||||||
func (t *transport) readPacket() (p []byte, err error) {
|
func (t *transport) readPacket() (p []byte, err error) {
|
||||||
for {
|
for {
|
||||||
p, err = t.reader.readPacket(t.bufReader)
|
p, err = t.reader.readPacket(t.bufReader, t.strictMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if len(p) == 0 || (p[0] != msgIgnore && p[0] != msgDebug) {
|
// in strict mode we pass through DEBUG and IGNORE packets only during the initial KEX
|
||||||
|
if len(p) == 0 || (t.strictMode && !t.initialKEXDone) || (p[0] != msgIgnore && p[0] != msgDebug) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,7 +143,7 @@ func (t *transport) readPacket() (p []byte, err error) {
|
|||||||
return p, err
|
return p, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) {
|
func (s *connectionState) readPacket(r *bufio.Reader, strictMode bool) ([]byte, error) {
|
||||||
packet, err := s.packetCipher.readCipherPacket(s.seqNum, r)
|
packet, err := s.packetCipher.readCipherPacket(s.seqNum, r)
|
||||||
s.seqNum++
|
s.seqNum++
|
||||||
if err == nil && len(packet) == 0 {
|
if err == nil && len(packet) == 0 {
|
||||||
@@ -140,6 +156,9 @@ func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) {
|
|||||||
select {
|
select {
|
||||||
case cipher := <-s.pendingKeyChange:
|
case cipher := <-s.pendingKeyChange:
|
||||||
s.packetCipher = cipher
|
s.packetCipher = cipher
|
||||||
|
if strictMode {
|
||||||
|
s.seqNum = 0
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("ssh: got bogus newkeys message")
|
return nil, errors.New("ssh: got bogus newkeys message")
|
||||||
}
|
}
|
||||||
@@ -170,10 +189,10 @@ func (t *transport) writePacket(packet []byte) error {
|
|||||||
if debugTransport {
|
if debugTransport {
|
||||||
t.printPacket(packet, true)
|
t.printPacket(packet, true)
|
||||||
}
|
}
|
||||||
return t.writer.writePacket(t.bufWriter, t.rand, packet)
|
return t.writer.writePacket(t.bufWriter, t.rand, packet, t.strictMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error {
|
func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte, strictMode bool) error {
|
||||||
changeKeys := len(packet) > 0 && packet[0] == msgNewKeys
|
changeKeys := len(packet) > 0 && packet[0] == msgNewKeys
|
||||||
|
|
||||||
err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet)
|
err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet)
|
||||||
@@ -188,6 +207,9 @@ func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []
|
|||||||
select {
|
select {
|
||||||
case cipher := <-s.pendingKeyChange:
|
case cipher := <-s.pendingKeyChange:
|
||||||
s.packetCipher = cipher
|
s.packetCipher = cipher
|
||||||
|
if strictMode {
|
||||||
|
s.seqNum = 0
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
panic("ssh: no key material for msgNewKeys")
|
panic("ssh: no key material for msgNewKeys")
|
||||||
}
|
}
|
||||||
|
|||||||
+150
-37
@@ -446,43 +446,6 @@ f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9
|
|||||||
ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK
|
ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK
|
||||||
GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV
|
GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
# CN=Autoridad de Certificacion Firmaprofesional CIF A62634068,C=ES
|
|
||||||
# 04048028bf1f2864d48f9ad4d83294366a828856553f3b14303f90147f5d40ef
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
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
|
|
||||||
jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
# CN=BJCA Global Root CA1,O=BEIJING CERTIFICATE AUTHORITY,C=CN
|
# CN=BJCA Global Root CA1,O=BEIJING CERTIFICATE AUTHORITY,C=CN
|
||||||
# f3896f88fe7c0a882766a7fa6ad2749fb57a7f3e98fb769c1fa7b09c2c44d5ae
|
# f3896f88fe7c0a882766a7fa6ad2749fb57a7f3e98fb769c1fa7b09c2c44d5ae
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
@@ -992,6 +955,104 @@ qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP
|
|||||||
0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf
|
0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf
|
||||||
E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb
|
E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
# CN=CommScope Public Trust ECC Root-01,O=CommScope,C=US
|
||||||
|
# 11437cda7bb45e41365f45b39a38986b0de00def348e0c7bb0873633800bc38b
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMw
|
||||||
|
TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t
|
||||||
|
bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNa
|
||||||
|
Fw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv
|
||||||
|
cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDEw
|
||||||
|
djAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLxeP0C
|
||||||
|
flfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJE
|
||||||
|
hRGnSjot6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
|
||||||
|
VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggq
|
||||||
|
hkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg
|
||||||
|
2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liWpDVfG2XqYZpwI7UNo5uS
|
||||||
|
Um9poIyNStDuiw7LR47QjRE=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
# CN=CommScope Public Trust ECC Root-02,O=CommScope,C=US
|
||||||
|
# 2ffb7f813bbbb3c89ab4e8162d0f16d71509a830cc9d73c262e5140875d1ad4a
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMw
|
||||||
|
TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t
|
||||||
|
bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRa
|
||||||
|
Fw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv
|
||||||
|
cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDIw
|
||||||
|
djAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/MMDAL
|
||||||
|
j2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmU
|
||||||
|
v4RDsNuESgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
|
||||||
|
VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggq
|
||||||
|
hkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/n
|
||||||
|
ich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs73u1Z/GtMMH9ZzkXpc2AV
|
||||||
|
mkzw5l4lIhVtwodZ0LKOag==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
# CN=CommScope Public Trust RSA Root-01,O=CommScope,C=US
|
||||||
|
# 02bdf96e2a45dd9bf18fc7e1dbdf21a0379ba3c9c2610344cfd8d606fec1ed81
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
# CN=CommScope Public Trust RSA Root-02,O=CommScope,C=US
|
||||||
|
# ffe943d793424b4f7c440c1c3d648d5363f34b82dc87aa7a9f118fc5dee101f1
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
-----END CERTIFICATE-----
|
||||||
# CN=D-TRUST BR Root CA 1 2020,O=D-Trust GmbH,C=DE
|
# CN=D-TRUST BR Root CA 1 2020,O=D-Trust GmbH,C=DE
|
||||||
# e59aaa816009c22bff5b25bad37df306f049797c1f81d85ab089e657bd8f0044
|
# e59aaa816009c22bff5b25bad37df306f049797c1f81d85ab089e657bd8f0044
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
@@ -3167,6 +3228,58 @@ t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn
|
|||||||
HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx
|
HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx
|
||||||
SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
|
SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
# CN=TrustAsia Global Root CA G3,O=TrustAsia Technologies\, Inc.,C=CN
|
||||||
|
# e0d3226aeb1163c2e48ff9be3b50b4c6431be7bb1eacc5c36b5d5ec509039a08
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
FGWsJwt0ivKH
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
# CN=TrustAsia Global Root CA G4,O=TrustAsia Technologies\, Inc.,C=CN
|
||||||
|
# be4b56cb5056c0136a526df444508daa36a0b54f42e4ac38f72af470e479654c
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMw
|
||||||
|
WjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs
|
||||||
|
IEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0y
|
||||||
|
MTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJaMFoxCzAJBgNVBAYTAkNOMSUwIwYD
|
||||||
|
VQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtUcnVz
|
||||||
|
dEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATx
|
||||||
|
s8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbw
|
||||||
|
LxYI+hW8m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJij
|
||||||
|
YzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mD
|
||||||
|
pm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/pDHel4NZg6ZvccveMA4GA1UdDwEB/wQE
|
||||||
|
AwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AAbbd+NvBNEU/zy4k6LHiR
|
||||||
|
UKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xkdUfFVZDj
|
||||||
|
/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
# CN=Trustwave Global Certification Authority,O=Trustwave Holdings\, Inc.,L=Chicago,ST=Illinois,C=US
|
# CN=Trustwave Global Certification Authority,O=Trustwave Holdings\, Inc.,L=Chicago,ST=Illinois,C=US
|
||||||
# 97552015f5ddfc3c8788c006944555408894450084f100867086bc1a2bb58dc8
|
# 97552015f5ddfc3c8788c006944555408894450084f100867086bc1a2bb58dc8
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
|
|||||||
Reference in New Issue
Block a user