mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-10-31 08:03:43 +08:00 
			
		
		
		
	
							
								
								
									
										8
									
								
								vendor/golang.org/x/crypto/curve25519/const_amd64.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vendor/golang.org/x/crypto/curve25519/const_amd64.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // This code was translated into a form compatible with 6a from the public | ||||
| // domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html | ||||
|  | ||||
| #define REDMASK51     0x0007FFFFFFFFFFFF | ||||
							
								
								
									
										20
									
								
								vendor/golang.org/x/crypto/curve25519/const_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/golang.org/x/crypto/curve25519/const_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // This code was translated into a form compatible with 6a from the public | ||||
| // domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html | ||||
|  | ||||
| // +build amd64,!gccgo,!appengine | ||||
|  | ||||
| // These constants cannot be encoded in non-MOVQ immediates. | ||||
| // We access them directly from memory instead. | ||||
|  | ||||
| DATA ·_121666_213(SB)/8, $996687872 | ||||
| GLOBL ·_121666_213(SB), 8, $8 | ||||
|  | ||||
| DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA | ||||
| GLOBL ·_2P0(SB), 8, $8 | ||||
|  | ||||
| DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE | ||||
| GLOBL ·_2P1234(SB), 8, $8 | ||||
							
								
								
									
										65
									
								
								vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // +build amd64,!gccgo,!appengine | ||||
|  | ||||
| // func cswap(inout *[4][5]uint64, v uint64) | ||||
| TEXT ·cswap(SB),7,$0 | ||||
| 	MOVQ inout+0(FP),DI | ||||
| 	MOVQ v+8(FP),SI | ||||
|  | ||||
| 	SUBQ $1, SI | ||||
| 	NOTQ SI | ||||
| 	MOVQ SI, X15 | ||||
| 	PSHUFD $0x44, X15, X15 | ||||
|  | ||||
| 	MOVOU 0(DI), X0 | ||||
| 	MOVOU 16(DI), X2 | ||||
| 	MOVOU 32(DI), X4 | ||||
| 	MOVOU 48(DI), X6 | ||||
| 	MOVOU 64(DI), X8 | ||||
| 	MOVOU 80(DI), X1 | ||||
| 	MOVOU 96(DI), X3 | ||||
| 	MOVOU 112(DI), X5 | ||||
| 	MOVOU 128(DI), X7 | ||||
| 	MOVOU 144(DI), X9 | ||||
|  | ||||
| 	MOVO X1, X10 | ||||
| 	MOVO X3, X11 | ||||
| 	MOVO X5, X12 | ||||
| 	MOVO X7, X13 | ||||
| 	MOVO X9, X14 | ||||
|  | ||||
| 	PXOR X0, X10 | ||||
| 	PXOR X2, X11 | ||||
| 	PXOR X4, X12 | ||||
| 	PXOR X6, X13 | ||||
| 	PXOR X8, X14 | ||||
| 	PAND X15, X10 | ||||
| 	PAND X15, X11 | ||||
| 	PAND X15, X12 | ||||
| 	PAND X15, X13 | ||||
| 	PAND X15, X14 | ||||
| 	PXOR X10, X0 | ||||
| 	PXOR X10, X1 | ||||
| 	PXOR X11, X2 | ||||
| 	PXOR X11, X3 | ||||
| 	PXOR X12, X4 | ||||
| 	PXOR X12, X5 | ||||
| 	PXOR X13, X6 | ||||
| 	PXOR X13, X7 | ||||
| 	PXOR X14, X8 | ||||
| 	PXOR X14, X9 | ||||
|  | ||||
| 	MOVOU X0, 0(DI) | ||||
| 	MOVOU X2, 16(DI) | ||||
| 	MOVOU X4, 32(DI) | ||||
| 	MOVOU X6, 48(DI) | ||||
| 	MOVOU X8, 64(DI) | ||||
| 	MOVOU X1, 80(DI) | ||||
| 	MOVOU X3, 96(DI) | ||||
| 	MOVOU X5, 112(DI) | ||||
| 	MOVOU X7, 128(DI) | ||||
| 	MOVOU X9, 144(DI) | ||||
| 	RET | ||||
							
								
								
									
										834
									
								
								vendor/golang.org/x/crypto/curve25519/curve25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										834
									
								
								vendor/golang.org/x/crypto/curve25519/curve25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,834 @@ | ||||
| // Copyright 2013 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. | ||||
|  | ||||
| // We have an implementation in amd64 assembly so this code is only run on | ||||
| // non-amd64 platforms. The amd64 assembly does not support gccgo. | ||||
| // +build !amd64 gccgo appengine | ||||
|  | ||||
| package curve25519 | ||||
|  | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| ) | ||||
|  | ||||
| // This code is a port of the public domain, "ref10" implementation of | ||||
| // curve25519 from SUPERCOP 20130419 by D. J. Bernstein. | ||||
|  | ||||
| // fieldElement represents an element of the field GF(2^255 - 19). An element | ||||
| // t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 | ||||
| // t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on | ||||
| // context. | ||||
| type fieldElement [10]int32 | ||||
|  | ||||
| func feZero(fe *fieldElement) { | ||||
| 	for i := range fe { | ||||
| 		fe[i] = 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func feOne(fe *fieldElement) { | ||||
| 	feZero(fe) | ||||
| 	fe[0] = 1 | ||||
| } | ||||
|  | ||||
| func feAdd(dst, a, b *fieldElement) { | ||||
| 	for i := range dst { | ||||
| 		dst[i] = a[i] + b[i] | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func feSub(dst, a, b *fieldElement) { | ||||
| 	for i := range dst { | ||||
| 		dst[i] = a[i] - b[i] | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func feCopy(dst, src *fieldElement) { | ||||
| 	for i := range dst { | ||||
| 		dst[i] = src[i] | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0. | ||||
| // | ||||
| // Preconditions: b in {0,1}. | ||||
| func feCSwap(f, g *fieldElement, b int32) { | ||||
| 	b = -b | ||||
| 	for i := range f { | ||||
| 		t := b & (f[i] ^ g[i]) | ||||
| 		f[i] ^= t | ||||
| 		g[i] ^= t | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // load3 reads a 24-bit, little-endian value from in. | ||||
| func load3(in []byte) int64 { | ||||
| 	var r int64 | ||||
| 	r = int64(in[0]) | ||||
| 	r |= int64(in[1]) << 8 | ||||
| 	r |= int64(in[2]) << 16 | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // load4 reads a 32-bit, little-endian value from in. | ||||
| func load4(in []byte) int64 { | ||||
| 	return int64(binary.LittleEndian.Uint32(in)) | ||||
| } | ||||
|  | ||||
| func feFromBytes(dst *fieldElement, src *[32]byte) { | ||||
| 	h0 := load4(src[:]) | ||||
| 	h1 := load3(src[4:]) << 6 | ||||
| 	h2 := load3(src[7:]) << 5 | ||||
| 	h3 := load3(src[10:]) << 3 | ||||
| 	h4 := load3(src[13:]) << 2 | ||||
| 	h5 := load4(src[16:]) | ||||
| 	h6 := load3(src[20:]) << 7 | ||||
| 	h7 := load3(src[23:]) << 5 | ||||
| 	h8 := load3(src[26:]) << 4 | ||||
| 	h9 := load3(src[29:]) << 2 | ||||
|  | ||||
| 	var carry [10]int64 | ||||
| 	carry[9] = (h9 + 1<<24) >> 25 | ||||
| 	h0 += carry[9] * 19 | ||||
| 	h9 -= carry[9] << 25 | ||||
| 	carry[1] = (h1 + 1<<24) >> 25 | ||||
| 	h2 += carry[1] | ||||
| 	h1 -= carry[1] << 25 | ||||
| 	carry[3] = (h3 + 1<<24) >> 25 | ||||
| 	h4 += carry[3] | ||||
| 	h3 -= carry[3] << 25 | ||||
| 	carry[5] = (h5 + 1<<24) >> 25 | ||||
| 	h6 += carry[5] | ||||
| 	h5 -= carry[5] << 25 | ||||
| 	carry[7] = (h7 + 1<<24) >> 25 | ||||
| 	h8 += carry[7] | ||||
| 	h7 -= carry[7] << 25 | ||||
|  | ||||
| 	carry[0] = (h0 + 1<<25) >> 26 | ||||
| 	h1 += carry[0] | ||||
| 	h0 -= carry[0] << 26 | ||||
| 	carry[2] = (h2 + 1<<25) >> 26 | ||||
| 	h3 += carry[2] | ||||
| 	h2 -= carry[2] << 26 | ||||
| 	carry[4] = (h4 + 1<<25) >> 26 | ||||
| 	h5 += carry[4] | ||||
| 	h4 -= carry[4] << 26 | ||||
| 	carry[6] = (h6 + 1<<25) >> 26 | ||||
| 	h7 += carry[6] | ||||
| 	h6 -= carry[6] << 26 | ||||
| 	carry[8] = (h8 + 1<<25) >> 26 | ||||
| 	h9 += carry[8] | ||||
| 	h8 -= carry[8] << 26 | ||||
|  | ||||
| 	dst[0] = int32(h0) | ||||
| 	dst[1] = int32(h1) | ||||
| 	dst[2] = int32(h2) | ||||
| 	dst[3] = int32(h3) | ||||
| 	dst[4] = int32(h4) | ||||
| 	dst[5] = int32(h5) | ||||
| 	dst[6] = int32(h6) | ||||
| 	dst[7] = int32(h7) | ||||
| 	dst[8] = int32(h8) | ||||
| 	dst[9] = int32(h9) | ||||
| } | ||||
|  | ||||
| // feToBytes marshals h to s. | ||||
| // Preconditions: | ||||
| //   |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. | ||||
| // | ||||
| // Write p=2^255-19; q=floor(h/p). | ||||
| // Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). | ||||
| // | ||||
| // Proof: | ||||
| //   Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. | ||||
| //   Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4. | ||||
| // | ||||
| //   Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). | ||||
| //   Then 0<y<1. | ||||
| // | ||||
| //   Write r=h-pq. | ||||
| //   Have 0<=r<=p-1=2^255-20. | ||||
| //   Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1. | ||||
| // | ||||
| //   Write x=r+19(2^-255)r+y. | ||||
| //   Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q. | ||||
| // | ||||
| //   Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1)) | ||||
| //   so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q. | ||||
| func feToBytes(s *[32]byte, h *fieldElement) { | ||||
| 	var carry [10]int32 | ||||
|  | ||||
| 	q := (19*h[9] + (1 << 24)) >> 25 | ||||
| 	q = (h[0] + q) >> 26 | ||||
| 	q = (h[1] + q) >> 25 | ||||
| 	q = (h[2] + q) >> 26 | ||||
| 	q = (h[3] + q) >> 25 | ||||
| 	q = (h[4] + q) >> 26 | ||||
| 	q = (h[5] + q) >> 25 | ||||
| 	q = (h[6] + q) >> 26 | ||||
| 	q = (h[7] + q) >> 25 | ||||
| 	q = (h[8] + q) >> 26 | ||||
| 	q = (h[9] + q) >> 25 | ||||
|  | ||||
| 	// Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. | ||||
| 	h[0] += 19 * q | ||||
| 	// Goal: Output h-2^255 q, which is between 0 and 2^255-20. | ||||
|  | ||||
| 	carry[0] = h[0] >> 26 | ||||
| 	h[1] += carry[0] | ||||
| 	h[0] -= carry[0] << 26 | ||||
| 	carry[1] = h[1] >> 25 | ||||
| 	h[2] += carry[1] | ||||
| 	h[1] -= carry[1] << 25 | ||||
| 	carry[2] = h[2] >> 26 | ||||
| 	h[3] += carry[2] | ||||
| 	h[2] -= carry[2] << 26 | ||||
| 	carry[3] = h[3] >> 25 | ||||
| 	h[4] += carry[3] | ||||
| 	h[3] -= carry[3] << 25 | ||||
| 	carry[4] = h[4] >> 26 | ||||
| 	h[5] += carry[4] | ||||
| 	h[4] -= carry[4] << 26 | ||||
| 	carry[5] = h[5] >> 25 | ||||
| 	h[6] += carry[5] | ||||
| 	h[5] -= carry[5] << 25 | ||||
| 	carry[6] = h[6] >> 26 | ||||
| 	h[7] += carry[6] | ||||
| 	h[6] -= carry[6] << 26 | ||||
| 	carry[7] = h[7] >> 25 | ||||
| 	h[8] += carry[7] | ||||
| 	h[7] -= carry[7] << 25 | ||||
| 	carry[8] = h[8] >> 26 | ||||
| 	h[9] += carry[8] | ||||
| 	h[8] -= carry[8] << 26 | ||||
| 	carry[9] = h[9] >> 25 | ||||
| 	h[9] -= carry[9] << 25 | ||||
| 	// h10 = carry9 | ||||
|  | ||||
| 	// Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. | ||||
| 	// Have h[0]+...+2^230 h[9] between 0 and 2^255-1; | ||||
| 	// evidently 2^255 h10-2^255 q = 0. | ||||
| 	// Goal: Output h[0]+...+2^230 h[9]. | ||||
|  | ||||
| 	s[0] = byte(h[0] >> 0) | ||||
| 	s[1] = byte(h[0] >> 8) | ||||
| 	s[2] = byte(h[0] >> 16) | ||||
| 	s[3] = byte((h[0] >> 24) | (h[1] << 2)) | ||||
| 	s[4] = byte(h[1] >> 6) | ||||
| 	s[5] = byte(h[1] >> 14) | ||||
| 	s[6] = byte((h[1] >> 22) | (h[2] << 3)) | ||||
| 	s[7] = byte(h[2] >> 5) | ||||
| 	s[8] = byte(h[2] >> 13) | ||||
| 	s[9] = byte((h[2] >> 21) | (h[3] << 5)) | ||||
| 	s[10] = byte(h[3] >> 3) | ||||
| 	s[11] = byte(h[3] >> 11) | ||||
| 	s[12] = byte((h[3] >> 19) | (h[4] << 6)) | ||||
| 	s[13] = byte(h[4] >> 2) | ||||
| 	s[14] = byte(h[4] >> 10) | ||||
| 	s[15] = byte(h[4] >> 18) | ||||
| 	s[16] = byte(h[5] >> 0) | ||||
| 	s[17] = byte(h[5] >> 8) | ||||
| 	s[18] = byte(h[5] >> 16) | ||||
| 	s[19] = byte((h[5] >> 24) | (h[6] << 1)) | ||||
| 	s[20] = byte(h[6] >> 7) | ||||
| 	s[21] = byte(h[6] >> 15) | ||||
| 	s[22] = byte((h[6] >> 23) | (h[7] << 3)) | ||||
| 	s[23] = byte(h[7] >> 5) | ||||
| 	s[24] = byte(h[7] >> 13) | ||||
| 	s[25] = byte((h[7] >> 21) | (h[8] << 4)) | ||||
| 	s[26] = byte(h[8] >> 4) | ||||
| 	s[27] = byte(h[8] >> 12) | ||||
| 	s[28] = byte((h[8] >> 20) | (h[9] << 6)) | ||||
| 	s[29] = byte(h[9] >> 2) | ||||
| 	s[30] = byte(h[9] >> 10) | ||||
| 	s[31] = byte(h[9] >> 18) | ||||
| } | ||||
|  | ||||
| // feMul calculates h = f * g | ||||
| // Can overlap h with f or g. | ||||
| // | ||||
| // Preconditions: | ||||
| //    |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. | ||||
| //    |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. | ||||
| // | ||||
| // Postconditions: | ||||
| //    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. | ||||
| // | ||||
| // Notes on implementation strategy: | ||||
| // | ||||
| // Using schoolbook multiplication. | ||||
| // Karatsuba would save a little in some cost models. | ||||
| // | ||||
| // Most multiplications by 2 and 19 are 32-bit precomputations; | ||||
| // cheaper than 64-bit postcomputations. | ||||
| // | ||||
| // There is one remaining multiplication by 19 in the carry chain; | ||||
| // one *19 precomputation can be merged into this, | ||||
| // but the resulting data flow is considerably less clean. | ||||
| // | ||||
| // There are 12 carries below. | ||||
| // 10 of them are 2-way parallelizable and vectorizable. | ||||
| // Can get away with 11 carries, but then data flow is much deeper. | ||||
| // | ||||
| // With tighter constraints on inputs can squeeze carries into int32. | ||||
| func feMul(h, f, g *fieldElement) { | ||||
| 	f0 := f[0] | ||||
| 	f1 := f[1] | ||||
| 	f2 := f[2] | ||||
| 	f3 := f[3] | ||||
| 	f4 := f[4] | ||||
| 	f5 := f[5] | ||||
| 	f6 := f[6] | ||||
| 	f7 := f[7] | ||||
| 	f8 := f[8] | ||||
| 	f9 := f[9] | ||||
| 	g0 := g[0] | ||||
| 	g1 := g[1] | ||||
| 	g2 := g[2] | ||||
| 	g3 := g[3] | ||||
| 	g4 := g[4] | ||||
| 	g5 := g[5] | ||||
| 	g6 := g[6] | ||||
| 	g7 := g[7] | ||||
| 	g8 := g[8] | ||||
| 	g9 := g[9] | ||||
| 	g1_19 := 19 * g1 // 1.4*2^29 | ||||
| 	g2_19 := 19 * g2 // 1.4*2^30; still ok | ||||
| 	g3_19 := 19 * g3 | ||||
| 	g4_19 := 19 * g4 | ||||
| 	g5_19 := 19 * g5 | ||||
| 	g6_19 := 19 * g6 | ||||
| 	g7_19 := 19 * g7 | ||||
| 	g8_19 := 19 * g8 | ||||
| 	g9_19 := 19 * g9 | ||||
| 	f1_2 := 2 * f1 | ||||
| 	f3_2 := 2 * f3 | ||||
| 	f5_2 := 2 * f5 | ||||
| 	f7_2 := 2 * f7 | ||||
| 	f9_2 := 2 * f9 | ||||
| 	f0g0 := int64(f0) * int64(g0) | ||||
| 	f0g1 := int64(f0) * int64(g1) | ||||
| 	f0g2 := int64(f0) * int64(g2) | ||||
| 	f0g3 := int64(f0) * int64(g3) | ||||
| 	f0g4 := int64(f0) * int64(g4) | ||||
| 	f0g5 := int64(f0) * int64(g5) | ||||
| 	f0g6 := int64(f0) * int64(g6) | ||||
| 	f0g7 := int64(f0) * int64(g7) | ||||
| 	f0g8 := int64(f0) * int64(g8) | ||||
| 	f0g9 := int64(f0) * int64(g9) | ||||
| 	f1g0 := int64(f1) * int64(g0) | ||||
| 	f1g1_2 := int64(f1_2) * int64(g1) | ||||
| 	f1g2 := int64(f1) * int64(g2) | ||||
| 	f1g3_2 := int64(f1_2) * int64(g3) | ||||
| 	f1g4 := int64(f1) * int64(g4) | ||||
| 	f1g5_2 := int64(f1_2) * int64(g5) | ||||
| 	f1g6 := int64(f1) * int64(g6) | ||||
| 	f1g7_2 := int64(f1_2) * int64(g7) | ||||
| 	f1g8 := int64(f1) * int64(g8) | ||||
| 	f1g9_38 := int64(f1_2) * int64(g9_19) | ||||
| 	f2g0 := int64(f2) * int64(g0) | ||||
| 	f2g1 := int64(f2) * int64(g1) | ||||
| 	f2g2 := int64(f2) * int64(g2) | ||||
| 	f2g3 := int64(f2) * int64(g3) | ||||
| 	f2g4 := int64(f2) * int64(g4) | ||||
| 	f2g5 := int64(f2) * int64(g5) | ||||
| 	f2g6 := int64(f2) * int64(g6) | ||||
| 	f2g7 := int64(f2) * int64(g7) | ||||
| 	f2g8_19 := int64(f2) * int64(g8_19) | ||||
| 	f2g9_19 := int64(f2) * int64(g9_19) | ||||
| 	f3g0 := int64(f3) * int64(g0) | ||||
| 	f3g1_2 := int64(f3_2) * int64(g1) | ||||
| 	f3g2 := int64(f3) * int64(g2) | ||||
| 	f3g3_2 := int64(f3_2) * int64(g3) | ||||
| 	f3g4 := int64(f3) * int64(g4) | ||||
| 	f3g5_2 := int64(f3_2) * int64(g5) | ||||
| 	f3g6 := int64(f3) * int64(g6) | ||||
| 	f3g7_38 := int64(f3_2) * int64(g7_19) | ||||
| 	f3g8_19 := int64(f3) * int64(g8_19) | ||||
| 	f3g9_38 := int64(f3_2) * int64(g9_19) | ||||
| 	f4g0 := int64(f4) * int64(g0) | ||||
| 	f4g1 := int64(f4) * int64(g1) | ||||
| 	f4g2 := int64(f4) * int64(g2) | ||||
| 	f4g3 := int64(f4) * int64(g3) | ||||
| 	f4g4 := int64(f4) * int64(g4) | ||||
| 	f4g5 := int64(f4) * int64(g5) | ||||
| 	f4g6_19 := int64(f4) * int64(g6_19) | ||||
| 	f4g7_19 := int64(f4) * int64(g7_19) | ||||
| 	f4g8_19 := int64(f4) * int64(g8_19) | ||||
| 	f4g9_19 := int64(f4) * int64(g9_19) | ||||
| 	f5g0 := int64(f5) * int64(g0) | ||||
| 	f5g1_2 := int64(f5_2) * int64(g1) | ||||
| 	f5g2 := int64(f5) * int64(g2) | ||||
| 	f5g3_2 := int64(f5_2) * int64(g3) | ||||
| 	f5g4 := int64(f5) * int64(g4) | ||||
| 	f5g5_38 := int64(f5_2) * int64(g5_19) | ||||
| 	f5g6_19 := int64(f5) * int64(g6_19) | ||||
| 	f5g7_38 := int64(f5_2) * int64(g7_19) | ||||
| 	f5g8_19 := int64(f5) * int64(g8_19) | ||||
| 	f5g9_38 := int64(f5_2) * int64(g9_19) | ||||
| 	f6g0 := int64(f6) * int64(g0) | ||||
| 	f6g1 := int64(f6) * int64(g1) | ||||
| 	f6g2 := int64(f6) * int64(g2) | ||||
| 	f6g3 := int64(f6) * int64(g3) | ||||
| 	f6g4_19 := int64(f6) * int64(g4_19) | ||||
| 	f6g5_19 := int64(f6) * int64(g5_19) | ||||
| 	f6g6_19 := int64(f6) * int64(g6_19) | ||||
| 	f6g7_19 := int64(f6) * int64(g7_19) | ||||
| 	f6g8_19 := int64(f6) * int64(g8_19) | ||||
| 	f6g9_19 := int64(f6) * int64(g9_19) | ||||
| 	f7g0 := int64(f7) * int64(g0) | ||||
| 	f7g1_2 := int64(f7_2) * int64(g1) | ||||
| 	f7g2 := int64(f7) * int64(g2) | ||||
| 	f7g3_38 := int64(f7_2) * int64(g3_19) | ||||
| 	f7g4_19 := int64(f7) * int64(g4_19) | ||||
| 	f7g5_38 := int64(f7_2) * int64(g5_19) | ||||
| 	f7g6_19 := int64(f7) * int64(g6_19) | ||||
| 	f7g7_38 := int64(f7_2) * int64(g7_19) | ||||
| 	f7g8_19 := int64(f7) * int64(g8_19) | ||||
| 	f7g9_38 := int64(f7_2) * int64(g9_19) | ||||
| 	f8g0 := int64(f8) * int64(g0) | ||||
| 	f8g1 := int64(f8) * int64(g1) | ||||
| 	f8g2_19 := int64(f8) * int64(g2_19) | ||||
| 	f8g3_19 := int64(f8) * int64(g3_19) | ||||
| 	f8g4_19 := int64(f8) * int64(g4_19) | ||||
| 	f8g5_19 := int64(f8) * int64(g5_19) | ||||
| 	f8g6_19 := int64(f8) * int64(g6_19) | ||||
| 	f8g7_19 := int64(f8) * int64(g7_19) | ||||
| 	f8g8_19 := int64(f8) * int64(g8_19) | ||||
| 	f8g9_19 := int64(f8) * int64(g9_19) | ||||
| 	f9g0 := int64(f9) * int64(g0) | ||||
| 	f9g1_38 := int64(f9_2) * int64(g1_19) | ||||
| 	f9g2_19 := int64(f9) * int64(g2_19) | ||||
| 	f9g3_38 := int64(f9_2) * int64(g3_19) | ||||
| 	f9g4_19 := int64(f9) * int64(g4_19) | ||||
| 	f9g5_38 := int64(f9_2) * int64(g5_19) | ||||
| 	f9g6_19 := int64(f9) * int64(g6_19) | ||||
| 	f9g7_38 := int64(f9_2) * int64(g7_19) | ||||
| 	f9g8_19 := int64(f9) * int64(g8_19) | ||||
| 	f9g9_38 := int64(f9_2) * int64(g9_19) | ||||
| 	h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38 | ||||
| 	h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19 | ||||
| 	h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38 | ||||
| 	h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19 | ||||
| 	h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38 | ||||
| 	h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19 | ||||
| 	h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38 | ||||
| 	h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19 | ||||
| 	h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38 | ||||
| 	h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0 | ||||
| 	var carry [10]int64 | ||||
|  | ||||
| 	// |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38)) | ||||
| 	//   i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8 | ||||
| 	// |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19)) | ||||
| 	//   i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9 | ||||
|  | ||||
| 	carry[0] = (h0 + (1 << 25)) >> 26 | ||||
| 	h1 += carry[0] | ||||
| 	h0 -= carry[0] << 26 | ||||
| 	carry[4] = (h4 + (1 << 25)) >> 26 | ||||
| 	h5 += carry[4] | ||||
| 	h4 -= carry[4] << 26 | ||||
| 	// |h0| <= 2^25 | ||||
| 	// |h4| <= 2^25 | ||||
| 	// |h1| <= 1.51*2^58 | ||||
| 	// |h5| <= 1.51*2^58 | ||||
|  | ||||
| 	carry[1] = (h1 + (1 << 24)) >> 25 | ||||
| 	h2 += carry[1] | ||||
| 	h1 -= carry[1] << 25 | ||||
| 	carry[5] = (h5 + (1 << 24)) >> 25 | ||||
| 	h6 += carry[5] | ||||
| 	h5 -= carry[5] << 25 | ||||
| 	// |h1| <= 2^24; from now on fits into int32 | ||||
| 	// |h5| <= 2^24; from now on fits into int32 | ||||
| 	// |h2| <= 1.21*2^59 | ||||
| 	// |h6| <= 1.21*2^59 | ||||
|  | ||||
| 	carry[2] = (h2 + (1 << 25)) >> 26 | ||||
| 	h3 += carry[2] | ||||
| 	h2 -= carry[2] << 26 | ||||
| 	carry[6] = (h6 + (1 << 25)) >> 26 | ||||
| 	h7 += carry[6] | ||||
| 	h6 -= carry[6] << 26 | ||||
| 	// |h2| <= 2^25; from now on fits into int32 unchanged | ||||
| 	// |h6| <= 2^25; from now on fits into int32 unchanged | ||||
| 	// |h3| <= 1.51*2^58 | ||||
| 	// |h7| <= 1.51*2^58 | ||||
|  | ||||
| 	carry[3] = (h3 + (1 << 24)) >> 25 | ||||
| 	h4 += carry[3] | ||||
| 	h3 -= carry[3] << 25 | ||||
| 	carry[7] = (h7 + (1 << 24)) >> 25 | ||||
| 	h8 += carry[7] | ||||
| 	h7 -= carry[7] << 25 | ||||
| 	// |h3| <= 2^24; from now on fits into int32 unchanged | ||||
| 	// |h7| <= 2^24; from now on fits into int32 unchanged | ||||
| 	// |h4| <= 1.52*2^33 | ||||
| 	// |h8| <= 1.52*2^33 | ||||
|  | ||||
| 	carry[4] = (h4 + (1 << 25)) >> 26 | ||||
| 	h5 += carry[4] | ||||
| 	h4 -= carry[4] << 26 | ||||
| 	carry[8] = (h8 + (1 << 25)) >> 26 | ||||
| 	h9 += carry[8] | ||||
| 	h8 -= carry[8] << 26 | ||||
| 	// |h4| <= 2^25; from now on fits into int32 unchanged | ||||
| 	// |h8| <= 2^25; from now on fits into int32 unchanged | ||||
| 	// |h5| <= 1.01*2^24 | ||||
| 	// |h9| <= 1.51*2^58 | ||||
|  | ||||
| 	carry[9] = (h9 + (1 << 24)) >> 25 | ||||
| 	h0 += carry[9] * 19 | ||||
| 	h9 -= carry[9] << 25 | ||||
| 	// |h9| <= 2^24; from now on fits into int32 unchanged | ||||
| 	// |h0| <= 1.8*2^37 | ||||
|  | ||||
| 	carry[0] = (h0 + (1 << 25)) >> 26 | ||||
| 	h1 += carry[0] | ||||
| 	h0 -= carry[0] << 26 | ||||
| 	// |h0| <= 2^25; from now on fits into int32 unchanged | ||||
| 	// |h1| <= 1.01*2^24 | ||||
|  | ||||
| 	h[0] = int32(h0) | ||||
| 	h[1] = int32(h1) | ||||
| 	h[2] = int32(h2) | ||||
| 	h[3] = int32(h3) | ||||
| 	h[4] = int32(h4) | ||||
| 	h[5] = int32(h5) | ||||
| 	h[6] = int32(h6) | ||||
| 	h[7] = int32(h7) | ||||
| 	h[8] = int32(h8) | ||||
| 	h[9] = int32(h9) | ||||
| } | ||||
|  | ||||
| // feSquare calculates h = f*f. Can overlap h with f. | ||||
| // | ||||
| // Preconditions: | ||||
| //    |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. | ||||
| // | ||||
| // Postconditions: | ||||
| //    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. | ||||
| func feSquare(h, f *fieldElement) { | ||||
| 	f0 := f[0] | ||||
| 	f1 := f[1] | ||||
| 	f2 := f[2] | ||||
| 	f3 := f[3] | ||||
| 	f4 := f[4] | ||||
| 	f5 := f[5] | ||||
| 	f6 := f[6] | ||||
| 	f7 := f[7] | ||||
| 	f8 := f[8] | ||||
| 	f9 := f[9] | ||||
| 	f0_2 := 2 * f0 | ||||
| 	f1_2 := 2 * f1 | ||||
| 	f2_2 := 2 * f2 | ||||
| 	f3_2 := 2 * f3 | ||||
| 	f4_2 := 2 * f4 | ||||
| 	f5_2 := 2 * f5 | ||||
| 	f6_2 := 2 * f6 | ||||
| 	f7_2 := 2 * f7 | ||||
| 	f5_38 := 38 * f5 // 1.31*2^30 | ||||
| 	f6_19 := 19 * f6 // 1.31*2^30 | ||||
| 	f7_38 := 38 * f7 // 1.31*2^30 | ||||
| 	f8_19 := 19 * f8 // 1.31*2^30 | ||||
| 	f9_38 := 38 * f9 // 1.31*2^30 | ||||
| 	f0f0 := int64(f0) * int64(f0) | ||||
| 	f0f1_2 := int64(f0_2) * int64(f1) | ||||
| 	f0f2_2 := int64(f0_2) * int64(f2) | ||||
| 	f0f3_2 := int64(f0_2) * int64(f3) | ||||
| 	f0f4_2 := int64(f0_2) * int64(f4) | ||||
| 	f0f5_2 := int64(f0_2) * int64(f5) | ||||
| 	f0f6_2 := int64(f0_2) * int64(f6) | ||||
| 	f0f7_2 := int64(f0_2) * int64(f7) | ||||
| 	f0f8_2 := int64(f0_2) * int64(f8) | ||||
| 	f0f9_2 := int64(f0_2) * int64(f9) | ||||
| 	f1f1_2 := int64(f1_2) * int64(f1) | ||||
| 	f1f2_2 := int64(f1_2) * int64(f2) | ||||
| 	f1f3_4 := int64(f1_2) * int64(f3_2) | ||||
| 	f1f4_2 := int64(f1_2) * int64(f4) | ||||
| 	f1f5_4 := int64(f1_2) * int64(f5_2) | ||||
| 	f1f6_2 := int64(f1_2) * int64(f6) | ||||
| 	f1f7_4 := int64(f1_2) * int64(f7_2) | ||||
| 	f1f8_2 := int64(f1_2) * int64(f8) | ||||
| 	f1f9_76 := int64(f1_2) * int64(f9_38) | ||||
| 	f2f2 := int64(f2) * int64(f2) | ||||
| 	f2f3_2 := int64(f2_2) * int64(f3) | ||||
| 	f2f4_2 := int64(f2_2) * int64(f4) | ||||
| 	f2f5_2 := int64(f2_2) * int64(f5) | ||||
| 	f2f6_2 := int64(f2_2) * int64(f6) | ||||
| 	f2f7_2 := int64(f2_2) * int64(f7) | ||||
| 	f2f8_38 := int64(f2_2) * int64(f8_19) | ||||
| 	f2f9_38 := int64(f2) * int64(f9_38) | ||||
| 	f3f3_2 := int64(f3_2) * int64(f3) | ||||
| 	f3f4_2 := int64(f3_2) * int64(f4) | ||||
| 	f3f5_4 := int64(f3_2) * int64(f5_2) | ||||
| 	f3f6_2 := int64(f3_2) * int64(f6) | ||||
| 	f3f7_76 := int64(f3_2) * int64(f7_38) | ||||
| 	f3f8_38 := int64(f3_2) * int64(f8_19) | ||||
| 	f3f9_76 := int64(f3_2) * int64(f9_38) | ||||
| 	f4f4 := int64(f4) * int64(f4) | ||||
| 	f4f5_2 := int64(f4_2) * int64(f5) | ||||
| 	f4f6_38 := int64(f4_2) * int64(f6_19) | ||||
| 	f4f7_38 := int64(f4) * int64(f7_38) | ||||
| 	f4f8_38 := int64(f4_2) * int64(f8_19) | ||||
| 	f4f9_38 := int64(f4) * int64(f9_38) | ||||
| 	f5f5_38 := int64(f5) * int64(f5_38) | ||||
| 	f5f6_38 := int64(f5_2) * int64(f6_19) | ||||
| 	f5f7_76 := int64(f5_2) * int64(f7_38) | ||||
| 	f5f8_38 := int64(f5_2) * int64(f8_19) | ||||
| 	f5f9_76 := int64(f5_2) * int64(f9_38) | ||||
| 	f6f6_19 := int64(f6) * int64(f6_19) | ||||
| 	f6f7_38 := int64(f6) * int64(f7_38) | ||||
| 	f6f8_38 := int64(f6_2) * int64(f8_19) | ||||
| 	f6f9_38 := int64(f6) * int64(f9_38) | ||||
| 	f7f7_38 := int64(f7) * int64(f7_38) | ||||
| 	f7f8_38 := int64(f7_2) * int64(f8_19) | ||||
| 	f7f9_76 := int64(f7_2) * int64(f9_38) | ||||
| 	f8f8_19 := int64(f8) * int64(f8_19) | ||||
| 	f8f9_38 := int64(f8) * int64(f9_38) | ||||
| 	f9f9_38 := int64(f9) * int64(f9_38) | ||||
| 	h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38 | ||||
| 	h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38 | ||||
| 	h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19 | ||||
| 	h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38 | ||||
| 	h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38 | ||||
| 	h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38 | ||||
| 	h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19 | ||||
| 	h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38 | ||||
| 	h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38 | ||||
| 	h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2 | ||||
| 	var carry [10]int64 | ||||
|  | ||||
| 	carry[0] = (h0 + (1 << 25)) >> 26 | ||||
| 	h1 += carry[0] | ||||
| 	h0 -= carry[0] << 26 | ||||
| 	carry[4] = (h4 + (1 << 25)) >> 26 | ||||
| 	h5 += carry[4] | ||||
| 	h4 -= carry[4] << 26 | ||||
|  | ||||
| 	carry[1] = (h1 + (1 << 24)) >> 25 | ||||
| 	h2 += carry[1] | ||||
| 	h1 -= carry[1] << 25 | ||||
| 	carry[5] = (h5 + (1 << 24)) >> 25 | ||||
| 	h6 += carry[5] | ||||
| 	h5 -= carry[5] << 25 | ||||
|  | ||||
| 	carry[2] = (h2 + (1 << 25)) >> 26 | ||||
| 	h3 += carry[2] | ||||
| 	h2 -= carry[2] << 26 | ||||
| 	carry[6] = (h6 + (1 << 25)) >> 26 | ||||
| 	h7 += carry[6] | ||||
| 	h6 -= carry[6] << 26 | ||||
|  | ||||
| 	carry[3] = (h3 + (1 << 24)) >> 25 | ||||
| 	h4 += carry[3] | ||||
| 	h3 -= carry[3] << 25 | ||||
| 	carry[7] = (h7 + (1 << 24)) >> 25 | ||||
| 	h8 += carry[7] | ||||
| 	h7 -= carry[7] << 25 | ||||
|  | ||||
| 	carry[4] = (h4 + (1 << 25)) >> 26 | ||||
| 	h5 += carry[4] | ||||
| 	h4 -= carry[4] << 26 | ||||
| 	carry[8] = (h8 + (1 << 25)) >> 26 | ||||
| 	h9 += carry[8] | ||||
| 	h8 -= carry[8] << 26 | ||||
|  | ||||
| 	carry[9] = (h9 + (1 << 24)) >> 25 | ||||
| 	h0 += carry[9] * 19 | ||||
| 	h9 -= carry[9] << 25 | ||||
|  | ||||
| 	carry[0] = (h0 + (1 << 25)) >> 26 | ||||
| 	h1 += carry[0] | ||||
| 	h0 -= carry[0] << 26 | ||||
|  | ||||
| 	h[0] = int32(h0) | ||||
| 	h[1] = int32(h1) | ||||
| 	h[2] = int32(h2) | ||||
| 	h[3] = int32(h3) | ||||
| 	h[4] = int32(h4) | ||||
| 	h[5] = int32(h5) | ||||
| 	h[6] = int32(h6) | ||||
| 	h[7] = int32(h7) | ||||
| 	h[8] = int32(h8) | ||||
| 	h[9] = int32(h9) | ||||
| } | ||||
|  | ||||
| // feMul121666 calculates h = f * 121666. Can overlap h with f. | ||||
| // | ||||
| // Preconditions: | ||||
| //    |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. | ||||
| // | ||||
| // Postconditions: | ||||
| //    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. | ||||
| func feMul121666(h, f *fieldElement) { | ||||
| 	h0 := int64(f[0]) * 121666 | ||||
| 	h1 := int64(f[1]) * 121666 | ||||
| 	h2 := int64(f[2]) * 121666 | ||||
| 	h3 := int64(f[3]) * 121666 | ||||
| 	h4 := int64(f[4]) * 121666 | ||||
| 	h5 := int64(f[5]) * 121666 | ||||
| 	h6 := int64(f[6]) * 121666 | ||||
| 	h7 := int64(f[7]) * 121666 | ||||
| 	h8 := int64(f[8]) * 121666 | ||||
| 	h9 := int64(f[9]) * 121666 | ||||
| 	var carry [10]int64 | ||||
|  | ||||
| 	carry[9] = (h9 + (1 << 24)) >> 25 | ||||
| 	h0 += carry[9] * 19 | ||||
| 	h9 -= carry[9] << 25 | ||||
| 	carry[1] = (h1 + (1 << 24)) >> 25 | ||||
| 	h2 += carry[1] | ||||
| 	h1 -= carry[1] << 25 | ||||
| 	carry[3] = (h3 + (1 << 24)) >> 25 | ||||
| 	h4 += carry[3] | ||||
| 	h3 -= carry[3] << 25 | ||||
| 	carry[5] = (h5 + (1 << 24)) >> 25 | ||||
| 	h6 += carry[5] | ||||
| 	h5 -= carry[5] << 25 | ||||
| 	carry[7] = (h7 + (1 << 24)) >> 25 | ||||
| 	h8 += carry[7] | ||||
| 	h7 -= carry[7] << 25 | ||||
|  | ||||
| 	carry[0] = (h0 + (1 << 25)) >> 26 | ||||
| 	h1 += carry[0] | ||||
| 	h0 -= carry[0] << 26 | ||||
| 	carry[2] = (h2 + (1 << 25)) >> 26 | ||||
| 	h3 += carry[2] | ||||
| 	h2 -= carry[2] << 26 | ||||
| 	carry[4] = (h4 + (1 << 25)) >> 26 | ||||
| 	h5 += carry[4] | ||||
| 	h4 -= carry[4] << 26 | ||||
| 	carry[6] = (h6 + (1 << 25)) >> 26 | ||||
| 	h7 += carry[6] | ||||
| 	h6 -= carry[6] << 26 | ||||
| 	carry[8] = (h8 + (1 << 25)) >> 26 | ||||
| 	h9 += carry[8] | ||||
| 	h8 -= carry[8] << 26 | ||||
|  | ||||
| 	h[0] = int32(h0) | ||||
| 	h[1] = int32(h1) | ||||
| 	h[2] = int32(h2) | ||||
| 	h[3] = int32(h3) | ||||
| 	h[4] = int32(h4) | ||||
| 	h[5] = int32(h5) | ||||
| 	h[6] = int32(h6) | ||||
| 	h[7] = int32(h7) | ||||
| 	h[8] = int32(h8) | ||||
| 	h[9] = int32(h9) | ||||
| } | ||||
|  | ||||
| // feInvert sets out = z^-1. | ||||
| func feInvert(out, z *fieldElement) { | ||||
| 	var t0, t1, t2, t3 fieldElement | ||||
| 	var i int | ||||
|  | ||||
| 	feSquare(&t0, z) | ||||
| 	for i = 1; i < 1; i++ { | ||||
| 		feSquare(&t0, &t0) | ||||
| 	} | ||||
| 	feSquare(&t1, &t0) | ||||
| 	for i = 1; i < 2; i++ { | ||||
| 		feSquare(&t1, &t1) | ||||
| 	} | ||||
| 	feMul(&t1, z, &t1) | ||||
| 	feMul(&t0, &t0, &t1) | ||||
| 	feSquare(&t2, &t0) | ||||
| 	for i = 1; i < 1; i++ { | ||||
| 		feSquare(&t2, &t2) | ||||
| 	} | ||||
| 	feMul(&t1, &t1, &t2) | ||||
| 	feSquare(&t2, &t1) | ||||
| 	for i = 1; i < 5; i++ { | ||||
| 		feSquare(&t2, &t2) | ||||
| 	} | ||||
| 	feMul(&t1, &t2, &t1) | ||||
| 	feSquare(&t2, &t1) | ||||
| 	for i = 1; i < 10; i++ { | ||||
| 		feSquare(&t2, &t2) | ||||
| 	} | ||||
| 	feMul(&t2, &t2, &t1) | ||||
| 	feSquare(&t3, &t2) | ||||
| 	for i = 1; i < 20; i++ { | ||||
| 		feSquare(&t3, &t3) | ||||
| 	} | ||||
| 	feMul(&t2, &t3, &t2) | ||||
| 	feSquare(&t2, &t2) | ||||
| 	for i = 1; i < 10; i++ { | ||||
| 		feSquare(&t2, &t2) | ||||
| 	} | ||||
| 	feMul(&t1, &t2, &t1) | ||||
| 	feSquare(&t2, &t1) | ||||
| 	for i = 1; i < 50; i++ { | ||||
| 		feSquare(&t2, &t2) | ||||
| 	} | ||||
| 	feMul(&t2, &t2, &t1) | ||||
| 	feSquare(&t3, &t2) | ||||
| 	for i = 1; i < 100; i++ { | ||||
| 		feSquare(&t3, &t3) | ||||
| 	} | ||||
| 	feMul(&t2, &t3, &t2) | ||||
| 	feSquare(&t2, &t2) | ||||
| 	for i = 1; i < 50; i++ { | ||||
| 		feSquare(&t2, &t2) | ||||
| 	} | ||||
| 	feMul(&t1, &t2, &t1) | ||||
| 	feSquare(&t1, &t1) | ||||
| 	for i = 1; i < 5; i++ { | ||||
| 		feSquare(&t1, &t1) | ||||
| 	} | ||||
| 	feMul(out, &t1, &t0) | ||||
| } | ||||
|  | ||||
| func scalarMult(out, in, base *[32]byte) { | ||||
| 	var e [32]byte | ||||
|  | ||||
| 	copy(e[:], in[:]) | ||||
| 	e[0] &= 248 | ||||
| 	e[31] &= 127 | ||||
| 	e[31] |= 64 | ||||
|  | ||||
| 	var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement | ||||
| 	feFromBytes(&x1, base) | ||||
| 	feOne(&x2) | ||||
| 	feCopy(&x3, &x1) | ||||
| 	feOne(&z3) | ||||
|  | ||||
| 	swap := int32(0) | ||||
| 	for pos := 254; pos >= 0; pos-- { | ||||
| 		b := e[pos/8] >> uint(pos&7) | ||||
| 		b &= 1 | ||||
| 		swap ^= int32(b) | ||||
| 		feCSwap(&x2, &x3, swap) | ||||
| 		feCSwap(&z2, &z3, swap) | ||||
| 		swap = int32(b) | ||||
|  | ||||
| 		feSub(&tmp0, &x3, &z3) | ||||
| 		feSub(&tmp1, &x2, &z2) | ||||
| 		feAdd(&x2, &x2, &z2) | ||||
| 		feAdd(&z2, &x3, &z3) | ||||
| 		feMul(&z3, &tmp0, &x2) | ||||
| 		feMul(&z2, &z2, &tmp1) | ||||
| 		feSquare(&tmp0, &tmp1) | ||||
| 		feSquare(&tmp1, &x2) | ||||
| 		feAdd(&x3, &z3, &z2) | ||||
| 		feSub(&z2, &z3, &z2) | ||||
| 		feMul(&x2, &tmp1, &tmp0) | ||||
| 		feSub(&tmp1, &tmp1, &tmp0) | ||||
| 		feSquare(&z2, &z2) | ||||
| 		feMul121666(&z3, &tmp1) | ||||
| 		feSquare(&x3, &x3) | ||||
| 		feAdd(&tmp0, &tmp0, &z3) | ||||
| 		feMul(&z3, &x1, &z2) | ||||
| 		feMul(&z2, &tmp1, &tmp0) | ||||
| 	} | ||||
|  | ||||
| 	feCSwap(&x2, &x3, swap) | ||||
| 	feCSwap(&z2, &z3, swap) | ||||
|  | ||||
| 	feInvert(&z2, &z2) | ||||
| 	feMul(&x2, &x2, &z2) | ||||
| 	feToBytes(out, &x2) | ||||
| } | ||||
							
								
								
									
										23
									
								
								vendor/golang.org/x/crypto/curve25519/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/golang.org/x/crypto/curve25519/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| // Copyright 2012 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 curve25519 provides an implementation of scalar multiplication on | ||||
| // the elliptic curve known as curve25519. See https://cr.yp.to/ecdh.html | ||||
| package curve25519 // import "golang.org/x/crypto/curve25519" | ||||
|  | ||||
| // basePoint is the x coordinate of the generator of the curve. | ||||
| var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} | ||||
|  | ||||
| // ScalarMult sets dst to the product in*base where dst and base are the x | ||||
| // coordinates of group points and all values are in little-endian form. | ||||
| func ScalarMult(dst, in, base *[32]byte) { | ||||
| 	scalarMult(dst, in, base) | ||||
| } | ||||
|  | ||||
| // ScalarBaseMult sets dst to the product in*base where dst and base are the x | ||||
| // coordinates of group points, base is the standard generator and all values | ||||
| // are in little-endian form. | ||||
| func ScalarBaseMult(dst, in *[32]byte) { | ||||
| 	ScalarMult(dst, in, &basePoint) | ||||
| } | ||||
							
								
								
									
										73
									
								
								vendor/golang.org/x/crypto/curve25519/freeze_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								vendor/golang.org/x/crypto/curve25519/freeze_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // This code was translated into a form compatible with 6a from the public | ||||
| // domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html | ||||
|  | ||||
| // +build amd64,!gccgo,!appengine | ||||
|  | ||||
| #include "const_amd64.h" | ||||
|  | ||||
| // func freeze(inout *[5]uint64) | ||||
| TEXT ·freeze(SB),7,$0-8 | ||||
| 	MOVQ inout+0(FP), DI | ||||
|  | ||||
| 	MOVQ 0(DI),SI | ||||
| 	MOVQ 8(DI),DX | ||||
| 	MOVQ 16(DI),CX | ||||
| 	MOVQ 24(DI),R8 | ||||
| 	MOVQ 32(DI),R9 | ||||
| 	MOVQ $REDMASK51,AX | ||||
| 	MOVQ AX,R10 | ||||
| 	SUBQ $18,R10 | ||||
| 	MOVQ $3,R11 | ||||
| REDUCELOOP: | ||||
| 	MOVQ SI,R12 | ||||
| 	SHRQ $51,R12 | ||||
| 	ANDQ AX,SI | ||||
| 	ADDQ R12,DX | ||||
| 	MOVQ DX,R12 | ||||
| 	SHRQ $51,R12 | ||||
| 	ANDQ AX,DX | ||||
| 	ADDQ R12,CX | ||||
| 	MOVQ CX,R12 | ||||
| 	SHRQ $51,R12 | ||||
| 	ANDQ AX,CX | ||||
| 	ADDQ R12,R8 | ||||
| 	MOVQ R8,R12 | ||||
| 	SHRQ $51,R12 | ||||
| 	ANDQ AX,R8 | ||||
| 	ADDQ R12,R9 | ||||
| 	MOVQ R9,R12 | ||||
| 	SHRQ $51,R12 | ||||
| 	ANDQ AX,R9 | ||||
| 	IMUL3Q $19,R12,R12 | ||||
| 	ADDQ R12,SI | ||||
| 	SUBQ $1,R11 | ||||
| 	JA REDUCELOOP | ||||
| 	MOVQ $1,R12 | ||||
| 	CMPQ R10,SI | ||||
| 	CMOVQLT R11,R12 | ||||
| 	CMPQ AX,DX | ||||
| 	CMOVQNE R11,R12 | ||||
| 	CMPQ AX,CX | ||||
| 	CMOVQNE R11,R12 | ||||
| 	CMPQ AX,R8 | ||||
| 	CMOVQNE R11,R12 | ||||
| 	CMPQ AX,R9 | ||||
| 	CMOVQNE R11,R12 | ||||
| 	NEGQ R12 | ||||
| 	ANDQ R12,AX | ||||
| 	ANDQ R12,R10 | ||||
| 	SUBQ R10,SI | ||||
| 	SUBQ AX,DX | ||||
| 	SUBQ AX,CX | ||||
| 	SUBQ AX,R8 | ||||
| 	SUBQ AX,R9 | ||||
| 	MOVQ SI,0(DI) | ||||
| 	MOVQ DX,8(DI) | ||||
| 	MOVQ CX,16(DI) | ||||
| 	MOVQ R8,24(DI) | ||||
| 	MOVQ R9,32(DI) | ||||
| 	RET | ||||
							
								
								
									
										1377
									
								
								vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1377
									
								
								vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										240
									
								
								vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,240 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // +build amd64,!gccgo,!appengine | ||||
|  | ||||
| package curve25519 | ||||
|  | ||||
| // These functions are implemented in the .s files. The names of the functions | ||||
| // in the rest of the file are also taken from the SUPERCOP sources to help | ||||
| // people following along. | ||||
|  | ||||
| //go:noescape | ||||
|  | ||||
| func cswap(inout *[5]uint64, v uint64) | ||||
|  | ||||
| //go:noescape | ||||
|  | ||||
| func ladderstep(inout *[5][5]uint64) | ||||
|  | ||||
| //go:noescape | ||||
|  | ||||
| func freeze(inout *[5]uint64) | ||||
|  | ||||
| //go:noescape | ||||
|  | ||||
| func mul(dest, a, b *[5]uint64) | ||||
|  | ||||
| //go:noescape | ||||
|  | ||||
| func square(out, in *[5]uint64) | ||||
|  | ||||
| // mladder uses a Montgomery ladder to calculate (xr/zr) *= s. | ||||
| func mladder(xr, zr *[5]uint64, s *[32]byte) { | ||||
| 	var work [5][5]uint64 | ||||
|  | ||||
| 	work[0] = *xr | ||||
| 	setint(&work[1], 1) | ||||
| 	setint(&work[2], 0) | ||||
| 	work[3] = *xr | ||||
| 	setint(&work[4], 1) | ||||
|  | ||||
| 	j := uint(6) | ||||
| 	var prevbit byte | ||||
|  | ||||
| 	for i := 31; i >= 0; i-- { | ||||
| 		for j < 8 { | ||||
| 			bit := ((*s)[i] >> j) & 1 | ||||
| 			swap := bit ^ prevbit | ||||
| 			prevbit = bit | ||||
| 			cswap(&work[1], uint64(swap)) | ||||
| 			ladderstep(&work) | ||||
| 			j-- | ||||
| 		} | ||||
| 		j = 7 | ||||
| 	} | ||||
|  | ||||
| 	*xr = work[1] | ||||
| 	*zr = work[2] | ||||
| } | ||||
|  | ||||
| func scalarMult(out, in, base *[32]byte) { | ||||
| 	var e [32]byte | ||||
| 	copy(e[:], (*in)[:]) | ||||
| 	e[0] &= 248 | ||||
| 	e[31] &= 127 | ||||
| 	e[31] |= 64 | ||||
|  | ||||
| 	var t, z [5]uint64 | ||||
| 	unpack(&t, base) | ||||
| 	mladder(&t, &z, &e) | ||||
| 	invert(&z, &z) | ||||
| 	mul(&t, &t, &z) | ||||
| 	pack(out, &t) | ||||
| } | ||||
|  | ||||
| func setint(r *[5]uint64, v uint64) { | ||||
| 	r[0] = v | ||||
| 	r[1] = 0 | ||||
| 	r[2] = 0 | ||||
| 	r[3] = 0 | ||||
| 	r[4] = 0 | ||||
| } | ||||
|  | ||||
| // unpack sets r = x where r consists of 5, 51-bit limbs in little-endian | ||||
| // order. | ||||
| func unpack(r *[5]uint64, x *[32]byte) { | ||||
| 	r[0] = uint64(x[0]) | | ||||
| 		uint64(x[1])<<8 | | ||||
| 		uint64(x[2])<<16 | | ||||
| 		uint64(x[3])<<24 | | ||||
| 		uint64(x[4])<<32 | | ||||
| 		uint64(x[5])<<40 | | ||||
| 		uint64(x[6]&7)<<48 | ||||
|  | ||||
| 	r[1] = uint64(x[6])>>3 | | ||||
| 		uint64(x[7])<<5 | | ||||
| 		uint64(x[8])<<13 | | ||||
| 		uint64(x[9])<<21 | | ||||
| 		uint64(x[10])<<29 | | ||||
| 		uint64(x[11])<<37 | | ||||
| 		uint64(x[12]&63)<<45 | ||||
|  | ||||
| 	r[2] = uint64(x[12])>>6 | | ||||
| 		uint64(x[13])<<2 | | ||||
| 		uint64(x[14])<<10 | | ||||
| 		uint64(x[15])<<18 | | ||||
| 		uint64(x[16])<<26 | | ||||
| 		uint64(x[17])<<34 | | ||||
| 		uint64(x[18])<<42 | | ||||
| 		uint64(x[19]&1)<<50 | ||||
|  | ||||
| 	r[3] = uint64(x[19])>>1 | | ||||
| 		uint64(x[20])<<7 | | ||||
| 		uint64(x[21])<<15 | | ||||
| 		uint64(x[22])<<23 | | ||||
| 		uint64(x[23])<<31 | | ||||
| 		uint64(x[24])<<39 | | ||||
| 		uint64(x[25]&15)<<47 | ||||
|  | ||||
| 	r[4] = uint64(x[25])>>4 | | ||||
| 		uint64(x[26])<<4 | | ||||
| 		uint64(x[27])<<12 | | ||||
| 		uint64(x[28])<<20 | | ||||
| 		uint64(x[29])<<28 | | ||||
| 		uint64(x[30])<<36 | | ||||
| 		uint64(x[31]&127)<<44 | ||||
| } | ||||
|  | ||||
| // pack sets out = x where out is the usual, little-endian form of the 5, | ||||
| // 51-bit limbs in x. | ||||
| func pack(out *[32]byte, x *[5]uint64) { | ||||
| 	t := *x | ||||
| 	freeze(&t) | ||||
|  | ||||
| 	out[0] = byte(t[0]) | ||||
| 	out[1] = byte(t[0] >> 8) | ||||
| 	out[2] = byte(t[0] >> 16) | ||||
| 	out[3] = byte(t[0] >> 24) | ||||
| 	out[4] = byte(t[0] >> 32) | ||||
| 	out[5] = byte(t[0] >> 40) | ||||
| 	out[6] = byte(t[0] >> 48) | ||||
|  | ||||
| 	out[6] ^= byte(t[1]<<3) & 0xf8 | ||||
| 	out[7] = byte(t[1] >> 5) | ||||
| 	out[8] = byte(t[1] >> 13) | ||||
| 	out[9] = byte(t[1] >> 21) | ||||
| 	out[10] = byte(t[1] >> 29) | ||||
| 	out[11] = byte(t[1] >> 37) | ||||
| 	out[12] = byte(t[1] >> 45) | ||||
|  | ||||
| 	out[12] ^= byte(t[2]<<6) & 0xc0 | ||||
| 	out[13] = byte(t[2] >> 2) | ||||
| 	out[14] = byte(t[2] >> 10) | ||||
| 	out[15] = byte(t[2] >> 18) | ||||
| 	out[16] = byte(t[2] >> 26) | ||||
| 	out[17] = byte(t[2] >> 34) | ||||
| 	out[18] = byte(t[2] >> 42) | ||||
| 	out[19] = byte(t[2] >> 50) | ||||
|  | ||||
| 	out[19] ^= byte(t[3]<<1) & 0xfe | ||||
| 	out[20] = byte(t[3] >> 7) | ||||
| 	out[21] = byte(t[3] >> 15) | ||||
| 	out[22] = byte(t[3] >> 23) | ||||
| 	out[23] = byte(t[3] >> 31) | ||||
| 	out[24] = byte(t[3] >> 39) | ||||
| 	out[25] = byte(t[3] >> 47) | ||||
|  | ||||
| 	out[25] ^= byte(t[4]<<4) & 0xf0 | ||||
| 	out[26] = byte(t[4] >> 4) | ||||
| 	out[27] = byte(t[4] >> 12) | ||||
| 	out[28] = byte(t[4] >> 20) | ||||
| 	out[29] = byte(t[4] >> 28) | ||||
| 	out[30] = byte(t[4] >> 36) | ||||
| 	out[31] = byte(t[4] >> 44) | ||||
| } | ||||
|  | ||||
| // invert calculates r = x^-1 mod p using Fermat's little theorem. | ||||
| func invert(r *[5]uint64, x *[5]uint64) { | ||||
| 	var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64 | ||||
|  | ||||
| 	square(&z2, x)        /* 2 */ | ||||
| 	square(&t, &z2)       /* 4 */ | ||||
| 	square(&t, &t)        /* 8 */ | ||||
| 	mul(&z9, &t, x)       /* 9 */ | ||||
| 	mul(&z11, &z9, &z2)   /* 11 */ | ||||
| 	square(&t, &z11)      /* 22 */ | ||||
| 	mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */ | ||||
|  | ||||
| 	square(&t, &z2_5_0)      /* 2^6 - 2^1 */ | ||||
| 	for i := 1; i < 5; i++ { /* 2^20 - 2^10 */ | ||||
| 		square(&t, &t) | ||||
| 	} | ||||
| 	mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */ | ||||
|  | ||||
| 	square(&t, &z2_10_0)      /* 2^11 - 2^1 */ | ||||
| 	for i := 1; i < 10; i++ { /* 2^20 - 2^10 */ | ||||
| 		square(&t, &t) | ||||
| 	} | ||||
| 	mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */ | ||||
|  | ||||
| 	square(&t, &z2_20_0)      /* 2^21 - 2^1 */ | ||||
| 	for i := 1; i < 20; i++ { /* 2^40 - 2^20 */ | ||||
| 		square(&t, &t) | ||||
| 	} | ||||
| 	mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */ | ||||
|  | ||||
| 	square(&t, &t)            /* 2^41 - 2^1 */ | ||||
| 	for i := 1; i < 10; i++ { /* 2^50 - 2^10 */ | ||||
| 		square(&t, &t) | ||||
| 	} | ||||
| 	mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */ | ||||
|  | ||||
| 	square(&t, &z2_50_0)      /* 2^51 - 2^1 */ | ||||
| 	for i := 1; i < 50; i++ { /* 2^100 - 2^50 */ | ||||
| 		square(&t, &t) | ||||
| 	} | ||||
| 	mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */ | ||||
|  | ||||
| 	square(&t, &z2_100_0)      /* 2^101 - 2^1 */ | ||||
| 	for i := 1; i < 100; i++ { /* 2^200 - 2^100 */ | ||||
| 		square(&t, &t) | ||||
| 	} | ||||
| 	mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */ | ||||
|  | ||||
| 	square(&t, &t)            /* 2^201 - 2^1 */ | ||||
| 	for i := 1; i < 50; i++ { /* 2^250 - 2^50 */ | ||||
| 		square(&t, &t) | ||||
| 	} | ||||
| 	mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */ | ||||
|  | ||||
| 	square(&t, &t) /* 2^251 - 2^1 */ | ||||
| 	square(&t, &t) /* 2^252 - 2^2 */ | ||||
| 	square(&t, &t) /* 2^253 - 2^3 */ | ||||
|  | ||||
| 	square(&t, &t) /* 2^254 - 2^4 */ | ||||
|  | ||||
| 	square(&t, &t)   /* 2^255 - 2^5 */ | ||||
| 	mul(r, &t, &z11) /* 2^255 - 21 */ | ||||
| } | ||||
							
								
								
									
										169
									
								
								vendor/golang.org/x/crypto/curve25519/mul_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								vendor/golang.org/x/crypto/curve25519/mul_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // This code was translated into a form compatible with 6a from the public | ||||
| // domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html | ||||
|  | ||||
| // +build amd64,!gccgo,!appengine | ||||
|  | ||||
| #include "const_amd64.h" | ||||
|  | ||||
| // func mul(dest, a, b *[5]uint64) | ||||
| TEXT ·mul(SB),0,$16-24 | ||||
| 	MOVQ dest+0(FP), DI | ||||
| 	MOVQ a+8(FP), SI | ||||
| 	MOVQ b+16(FP), DX | ||||
|  | ||||
| 	MOVQ DX,CX | ||||
| 	MOVQ 24(SI),DX | ||||
| 	IMUL3Q $19,DX,AX | ||||
| 	MOVQ AX,0(SP) | ||||
| 	MULQ 16(CX) | ||||
| 	MOVQ AX,R8 | ||||
| 	MOVQ DX,R9 | ||||
| 	MOVQ 32(SI),DX | ||||
| 	IMUL3Q $19,DX,AX | ||||
| 	MOVQ AX,8(SP) | ||||
| 	MULQ 8(CX) | ||||
| 	ADDQ AX,R8 | ||||
| 	ADCQ DX,R9 | ||||
| 	MOVQ 0(SI),AX | ||||
| 	MULQ 0(CX) | ||||
| 	ADDQ AX,R8 | ||||
| 	ADCQ DX,R9 | ||||
| 	MOVQ 0(SI),AX | ||||
| 	MULQ 8(CX) | ||||
| 	MOVQ AX,R10 | ||||
| 	MOVQ DX,R11 | ||||
| 	MOVQ 0(SI),AX | ||||
| 	MULQ 16(CX) | ||||
| 	MOVQ AX,R12 | ||||
| 	MOVQ DX,R13 | ||||
| 	MOVQ 0(SI),AX | ||||
| 	MULQ 24(CX) | ||||
| 	MOVQ AX,R14 | ||||
| 	MOVQ DX,R15 | ||||
| 	MOVQ 0(SI),AX | ||||
| 	MULQ 32(CX) | ||||
| 	MOVQ AX,BX | ||||
| 	MOVQ DX,BP | ||||
| 	MOVQ 8(SI),AX | ||||
| 	MULQ 0(CX) | ||||
| 	ADDQ AX,R10 | ||||
| 	ADCQ DX,R11 | ||||
| 	MOVQ 8(SI),AX | ||||
| 	MULQ 8(CX) | ||||
| 	ADDQ AX,R12 | ||||
| 	ADCQ DX,R13 | ||||
| 	MOVQ 8(SI),AX | ||||
| 	MULQ 16(CX) | ||||
| 	ADDQ AX,R14 | ||||
| 	ADCQ DX,R15 | ||||
| 	MOVQ 8(SI),AX | ||||
| 	MULQ 24(CX) | ||||
| 	ADDQ AX,BX | ||||
| 	ADCQ DX,BP | ||||
| 	MOVQ 8(SI),DX | ||||
| 	IMUL3Q $19,DX,AX | ||||
| 	MULQ 32(CX) | ||||
| 	ADDQ AX,R8 | ||||
| 	ADCQ DX,R9 | ||||
| 	MOVQ 16(SI),AX | ||||
| 	MULQ 0(CX) | ||||
| 	ADDQ AX,R12 | ||||
| 	ADCQ DX,R13 | ||||
| 	MOVQ 16(SI),AX | ||||
| 	MULQ 8(CX) | ||||
| 	ADDQ AX,R14 | ||||
| 	ADCQ DX,R15 | ||||
| 	MOVQ 16(SI),AX | ||||
| 	MULQ 16(CX) | ||||
| 	ADDQ AX,BX | ||||
| 	ADCQ DX,BP | ||||
| 	MOVQ 16(SI),DX | ||||
| 	IMUL3Q $19,DX,AX | ||||
| 	MULQ 24(CX) | ||||
| 	ADDQ AX,R8 | ||||
| 	ADCQ DX,R9 | ||||
| 	MOVQ 16(SI),DX | ||||
| 	IMUL3Q $19,DX,AX | ||||
| 	MULQ 32(CX) | ||||
| 	ADDQ AX,R10 | ||||
| 	ADCQ DX,R11 | ||||
| 	MOVQ 24(SI),AX | ||||
| 	MULQ 0(CX) | ||||
| 	ADDQ AX,R14 | ||||
| 	ADCQ DX,R15 | ||||
| 	MOVQ 24(SI),AX | ||||
| 	MULQ 8(CX) | ||||
| 	ADDQ AX,BX | ||||
| 	ADCQ DX,BP | ||||
| 	MOVQ 0(SP),AX | ||||
| 	MULQ 24(CX) | ||||
| 	ADDQ AX,R10 | ||||
| 	ADCQ DX,R11 | ||||
| 	MOVQ 0(SP),AX | ||||
| 	MULQ 32(CX) | ||||
| 	ADDQ AX,R12 | ||||
| 	ADCQ DX,R13 | ||||
| 	MOVQ 32(SI),AX | ||||
| 	MULQ 0(CX) | ||||
| 	ADDQ AX,BX | ||||
| 	ADCQ DX,BP | ||||
| 	MOVQ 8(SP),AX | ||||
| 	MULQ 16(CX) | ||||
| 	ADDQ AX,R10 | ||||
| 	ADCQ DX,R11 | ||||
| 	MOVQ 8(SP),AX | ||||
| 	MULQ 24(CX) | ||||
| 	ADDQ AX,R12 | ||||
| 	ADCQ DX,R13 | ||||
| 	MOVQ 8(SP),AX | ||||
| 	MULQ 32(CX) | ||||
| 	ADDQ AX,R14 | ||||
| 	ADCQ DX,R15 | ||||
| 	MOVQ $REDMASK51,SI | ||||
| 	SHLQ $13,R9:R8 | ||||
| 	ANDQ SI,R8 | ||||
| 	SHLQ $13,R11:R10 | ||||
| 	ANDQ SI,R10 | ||||
| 	ADDQ R9,R10 | ||||
| 	SHLQ $13,R13:R12 | ||||
| 	ANDQ SI,R12 | ||||
| 	ADDQ R11,R12 | ||||
| 	SHLQ $13,R15:R14 | ||||
| 	ANDQ SI,R14 | ||||
| 	ADDQ R13,R14 | ||||
| 	SHLQ $13,BP:BX | ||||
| 	ANDQ SI,BX | ||||
| 	ADDQ R15,BX | ||||
| 	IMUL3Q $19,BP,DX | ||||
| 	ADDQ DX,R8 | ||||
| 	MOVQ R8,DX | ||||
| 	SHRQ $51,DX | ||||
| 	ADDQ R10,DX | ||||
| 	MOVQ DX,CX | ||||
| 	SHRQ $51,DX | ||||
| 	ANDQ SI,R8 | ||||
| 	ADDQ R12,DX | ||||
| 	MOVQ DX,R9 | ||||
| 	SHRQ $51,DX | ||||
| 	ANDQ SI,CX | ||||
| 	ADDQ R14,DX | ||||
| 	MOVQ DX,AX | ||||
| 	SHRQ $51,DX | ||||
| 	ANDQ SI,R9 | ||||
| 	ADDQ BX,DX | ||||
| 	MOVQ DX,R10 | ||||
| 	SHRQ $51,DX | ||||
| 	ANDQ SI,AX | ||||
| 	IMUL3Q $19,DX,DX | ||||
| 	ADDQ DX,R8 | ||||
| 	ANDQ SI,R10 | ||||
| 	MOVQ R8,0(DI) | ||||
| 	MOVQ CX,8(DI) | ||||
| 	MOVQ R9,16(DI) | ||||
| 	MOVQ AX,24(DI) | ||||
| 	MOVQ R10,32(DI) | ||||
| 	RET | ||||
							
								
								
									
										132
									
								
								vendor/golang.org/x/crypto/curve25519/square_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								vendor/golang.org/x/crypto/curve25519/square_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,132 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // This code was translated into a form compatible with 6a from the public | ||||
| // domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html | ||||
|  | ||||
| // +build amd64,!gccgo,!appengine | ||||
|  | ||||
| #include "const_amd64.h" | ||||
|  | ||||
| // func square(out, in *[5]uint64) | ||||
| TEXT ·square(SB),7,$0-16 | ||||
| 	MOVQ out+0(FP), DI | ||||
| 	MOVQ in+8(FP), SI | ||||
|  | ||||
| 	MOVQ 0(SI),AX | ||||
| 	MULQ 0(SI) | ||||
| 	MOVQ AX,CX | ||||
| 	MOVQ DX,R8 | ||||
| 	MOVQ 0(SI),AX | ||||
| 	SHLQ $1,AX | ||||
| 	MULQ 8(SI) | ||||
| 	MOVQ AX,R9 | ||||
| 	MOVQ DX,R10 | ||||
| 	MOVQ 0(SI),AX | ||||
| 	SHLQ $1,AX | ||||
| 	MULQ 16(SI) | ||||
| 	MOVQ AX,R11 | ||||
| 	MOVQ DX,R12 | ||||
| 	MOVQ 0(SI),AX | ||||
| 	SHLQ $1,AX | ||||
| 	MULQ 24(SI) | ||||
| 	MOVQ AX,R13 | ||||
| 	MOVQ DX,R14 | ||||
| 	MOVQ 0(SI),AX | ||||
| 	SHLQ $1,AX | ||||
| 	MULQ 32(SI) | ||||
| 	MOVQ AX,R15 | ||||
| 	MOVQ DX,BX | ||||
| 	MOVQ 8(SI),AX | ||||
| 	MULQ 8(SI) | ||||
| 	ADDQ AX,R11 | ||||
| 	ADCQ DX,R12 | ||||
| 	MOVQ 8(SI),AX | ||||
| 	SHLQ $1,AX | ||||
| 	MULQ 16(SI) | ||||
| 	ADDQ AX,R13 | ||||
| 	ADCQ DX,R14 | ||||
| 	MOVQ 8(SI),AX | ||||
| 	SHLQ $1,AX | ||||
| 	MULQ 24(SI) | ||||
| 	ADDQ AX,R15 | ||||
| 	ADCQ DX,BX | ||||
| 	MOVQ 8(SI),DX | ||||
| 	IMUL3Q $38,DX,AX | ||||
| 	MULQ 32(SI) | ||||
| 	ADDQ AX,CX | ||||
| 	ADCQ DX,R8 | ||||
| 	MOVQ 16(SI),AX | ||||
| 	MULQ 16(SI) | ||||
| 	ADDQ AX,R15 | ||||
| 	ADCQ DX,BX | ||||
| 	MOVQ 16(SI),DX | ||||
| 	IMUL3Q $38,DX,AX | ||||
| 	MULQ 24(SI) | ||||
| 	ADDQ AX,CX | ||||
| 	ADCQ DX,R8 | ||||
| 	MOVQ 16(SI),DX | ||||
| 	IMUL3Q $38,DX,AX | ||||
| 	MULQ 32(SI) | ||||
| 	ADDQ AX,R9 | ||||
| 	ADCQ DX,R10 | ||||
| 	MOVQ 24(SI),DX | ||||
| 	IMUL3Q $19,DX,AX | ||||
| 	MULQ 24(SI) | ||||
| 	ADDQ AX,R9 | ||||
| 	ADCQ DX,R10 | ||||
| 	MOVQ 24(SI),DX | ||||
| 	IMUL3Q $38,DX,AX | ||||
| 	MULQ 32(SI) | ||||
| 	ADDQ AX,R11 | ||||
| 	ADCQ DX,R12 | ||||
| 	MOVQ 32(SI),DX | ||||
| 	IMUL3Q $19,DX,AX | ||||
| 	MULQ 32(SI) | ||||
| 	ADDQ AX,R13 | ||||
| 	ADCQ DX,R14 | ||||
| 	MOVQ $REDMASK51,SI | ||||
| 	SHLQ $13,R8:CX | ||||
| 	ANDQ SI,CX | ||||
| 	SHLQ $13,R10:R9 | ||||
| 	ANDQ SI,R9 | ||||
| 	ADDQ R8,R9 | ||||
| 	SHLQ $13,R12:R11 | ||||
| 	ANDQ SI,R11 | ||||
| 	ADDQ R10,R11 | ||||
| 	SHLQ $13,R14:R13 | ||||
| 	ANDQ SI,R13 | ||||
| 	ADDQ R12,R13 | ||||
| 	SHLQ $13,BX:R15 | ||||
| 	ANDQ SI,R15 | ||||
| 	ADDQ R14,R15 | ||||
| 	IMUL3Q $19,BX,DX | ||||
| 	ADDQ DX,CX | ||||
| 	MOVQ CX,DX | ||||
| 	SHRQ $51,DX | ||||
| 	ADDQ R9,DX | ||||
| 	ANDQ SI,CX | ||||
| 	MOVQ DX,R8 | ||||
| 	SHRQ $51,DX | ||||
| 	ADDQ R11,DX | ||||
| 	ANDQ SI,R8 | ||||
| 	MOVQ DX,R9 | ||||
| 	SHRQ $51,DX | ||||
| 	ADDQ R13,DX | ||||
| 	ANDQ SI,R9 | ||||
| 	MOVQ DX,AX | ||||
| 	SHRQ $51,DX | ||||
| 	ADDQ R15,DX | ||||
| 	ANDQ SI,AX | ||||
| 	MOVQ DX,R10 | ||||
| 	SHRQ $51,DX | ||||
| 	IMUL3Q $19,DX,DX | ||||
| 	ADDQ DX,CX | ||||
| 	ANDQ SI,R10 | ||||
| 	MOVQ CX,0(DI) | ||||
| 	MOVQ R8,8(DI) | ||||
| 	MOVQ R9,16(DI) | ||||
| 	MOVQ AX,24(DI) | ||||
| 	MOVQ R10,32(DI) | ||||
| 	RET | ||||
							
								
								
									
										217
									
								
								vendor/golang.org/x/crypto/ed25519/ed25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								vendor/golang.org/x/crypto/ed25519/ed25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,217 @@ | ||||
| // 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. | ||||
|  | ||||
| // Package ed25519 implements the Ed25519 signature algorithm. See | ||||
| // https://ed25519.cr.yp.to/. | ||||
| // | ||||
| // These functions are also compatible with the “Ed25519” function defined in | ||||
| // RFC 8032. However, unlike RFC 8032's formulation, this package's private key | ||||
| // representation includes a public key suffix to make multiple signing | ||||
| // operations with the same key more efficient. This package refers to the RFC | ||||
| // 8032 private key as the “seed”. | ||||
| package ed25519 | ||||
|  | ||||
| // This code is a port of the public domain, “ref10” implementation of ed25519 | ||||
| // from SUPERCOP. | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto" | ||||
| 	cryptorand "crypto/rand" | ||||
| 	"crypto/sha512" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"golang.org/x/crypto/ed25519/internal/edwards25519" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// PublicKeySize is the size, in bytes, of public keys as used in this package. | ||||
| 	PublicKeySize = 32 | ||||
| 	// PrivateKeySize is the size, in bytes, of private keys as used in this package. | ||||
| 	PrivateKeySize = 64 | ||||
| 	// SignatureSize is the size, in bytes, of signatures generated and verified by this package. | ||||
| 	SignatureSize = 64 | ||||
| 	// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032. | ||||
| 	SeedSize = 32 | ||||
| ) | ||||
|  | ||||
| // PublicKey is the type of Ed25519 public keys. | ||||
| type PublicKey []byte | ||||
|  | ||||
| // PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. | ||||
| type PrivateKey []byte | ||||
|  | ||||
| // Public returns the PublicKey corresponding to priv. | ||||
| func (priv PrivateKey) Public() crypto.PublicKey { | ||||
| 	publicKey := make([]byte, PublicKeySize) | ||||
| 	copy(publicKey, priv[32:]) | ||||
| 	return PublicKey(publicKey) | ||||
| } | ||||
|  | ||||
| // Seed returns the private key seed corresponding to priv. It is provided for | ||||
| // interoperability with RFC 8032. RFC 8032's private keys correspond to seeds | ||||
| // in this package. | ||||
| func (priv PrivateKey) Seed() []byte { | ||||
| 	seed := make([]byte, SeedSize) | ||||
| 	copy(seed, priv[:32]) | ||||
| 	return seed | ||||
| } | ||||
|  | ||||
| // Sign signs the given message with priv. | ||||
| // Ed25519 performs two passes over messages to be signed and therefore cannot | ||||
| // handle pre-hashed messages. Thus opts.HashFunc() must return zero to | ||||
| // indicate the message hasn't been hashed. This can be achieved by passing | ||||
| // crypto.Hash(0) as the value for opts. | ||||
| func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) { | ||||
| 	if opts.HashFunc() != crypto.Hash(0) { | ||||
| 		return nil, errors.New("ed25519: cannot sign hashed message") | ||||
| 	} | ||||
|  | ||||
| 	return Sign(priv, message), nil | ||||
| } | ||||
|  | ||||
| // GenerateKey generates a public/private key pair using entropy from rand. | ||||
| // If rand is nil, crypto/rand.Reader will be used. | ||||
| func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { | ||||
| 	if rand == nil { | ||||
| 		rand = cryptorand.Reader | ||||
| 	} | ||||
|  | ||||
| 	seed := make([]byte, SeedSize) | ||||
| 	if _, err := io.ReadFull(rand, seed); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	privateKey := NewKeyFromSeed(seed) | ||||
| 	publicKey := make([]byte, PublicKeySize) | ||||
| 	copy(publicKey, privateKey[32:]) | ||||
|  | ||||
| 	return publicKey, privateKey, nil | ||||
| } | ||||
|  | ||||
| // NewKeyFromSeed calculates a private key from a seed. It will panic if | ||||
| // len(seed) is not SeedSize. This function is provided for interoperability | ||||
| // with RFC 8032. RFC 8032's private keys correspond to seeds in this | ||||
| // package. | ||||
| func NewKeyFromSeed(seed []byte) PrivateKey { | ||||
| 	if l := len(seed); l != SeedSize { | ||||
| 		panic("ed25519: bad seed length: " + strconv.Itoa(l)) | ||||
| 	} | ||||
|  | ||||
| 	digest := sha512.Sum512(seed) | ||||
| 	digest[0] &= 248 | ||||
| 	digest[31] &= 127 | ||||
| 	digest[31] |= 64 | ||||
|  | ||||
| 	var A edwards25519.ExtendedGroupElement | ||||
| 	var hBytes [32]byte | ||||
| 	copy(hBytes[:], digest[:]) | ||||
| 	edwards25519.GeScalarMultBase(&A, &hBytes) | ||||
| 	var publicKeyBytes [32]byte | ||||
| 	A.ToBytes(&publicKeyBytes) | ||||
|  | ||||
| 	privateKey := make([]byte, PrivateKeySize) | ||||
| 	copy(privateKey, seed) | ||||
| 	copy(privateKey[32:], publicKeyBytes[:]) | ||||
|  | ||||
| 	return privateKey | ||||
| } | ||||
|  | ||||
| // Sign signs the message with privateKey and returns a signature. It will | ||||
| // panic if len(privateKey) is not PrivateKeySize. | ||||
| func Sign(privateKey PrivateKey, message []byte) []byte { | ||||
| 	if l := len(privateKey); l != PrivateKeySize { | ||||
| 		panic("ed25519: bad private key length: " + strconv.Itoa(l)) | ||||
| 	} | ||||
|  | ||||
| 	h := sha512.New() | ||||
| 	h.Write(privateKey[:32]) | ||||
|  | ||||
| 	var digest1, messageDigest, hramDigest [64]byte | ||||
| 	var expandedSecretKey [32]byte | ||||
| 	h.Sum(digest1[:0]) | ||||
| 	copy(expandedSecretKey[:], digest1[:]) | ||||
| 	expandedSecretKey[0] &= 248 | ||||
| 	expandedSecretKey[31] &= 63 | ||||
| 	expandedSecretKey[31] |= 64 | ||||
|  | ||||
| 	h.Reset() | ||||
| 	h.Write(digest1[32:]) | ||||
| 	h.Write(message) | ||||
| 	h.Sum(messageDigest[:0]) | ||||
|  | ||||
| 	var messageDigestReduced [32]byte | ||||
| 	edwards25519.ScReduce(&messageDigestReduced, &messageDigest) | ||||
| 	var R edwards25519.ExtendedGroupElement | ||||
| 	edwards25519.GeScalarMultBase(&R, &messageDigestReduced) | ||||
|  | ||||
| 	var encodedR [32]byte | ||||
| 	R.ToBytes(&encodedR) | ||||
|  | ||||
| 	h.Reset() | ||||
| 	h.Write(encodedR[:]) | ||||
| 	h.Write(privateKey[32:]) | ||||
| 	h.Write(message) | ||||
| 	h.Sum(hramDigest[:0]) | ||||
| 	var hramDigestReduced [32]byte | ||||
| 	edwards25519.ScReduce(&hramDigestReduced, &hramDigest) | ||||
|  | ||||
| 	var s [32]byte | ||||
| 	edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced) | ||||
|  | ||||
| 	signature := make([]byte, SignatureSize) | ||||
| 	copy(signature[:], encodedR[:]) | ||||
| 	copy(signature[32:], s[:]) | ||||
|  | ||||
| 	return signature | ||||
| } | ||||
|  | ||||
| // Verify reports whether sig is a valid signature of message by publicKey. It | ||||
| // will panic if len(publicKey) is not PublicKeySize. | ||||
| func Verify(publicKey PublicKey, message, sig []byte) bool { | ||||
| 	if l := len(publicKey); l != PublicKeySize { | ||||
| 		panic("ed25519: bad public key length: " + strconv.Itoa(l)) | ||||
| 	} | ||||
|  | ||||
| 	if len(sig) != SignatureSize || sig[63]&224 != 0 { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	var A edwards25519.ExtendedGroupElement | ||||
| 	var publicKeyBytes [32]byte | ||||
| 	copy(publicKeyBytes[:], publicKey) | ||||
| 	if !A.FromBytes(&publicKeyBytes) { | ||||
| 		return false | ||||
| 	} | ||||
| 	edwards25519.FeNeg(&A.X, &A.X) | ||||
| 	edwards25519.FeNeg(&A.T, &A.T) | ||||
|  | ||||
| 	h := sha512.New() | ||||
| 	h.Write(sig[:32]) | ||||
| 	h.Write(publicKey[:]) | ||||
| 	h.Write(message) | ||||
| 	var digest [64]byte | ||||
| 	h.Sum(digest[:0]) | ||||
|  | ||||
| 	var hReduced [32]byte | ||||
| 	edwards25519.ScReduce(&hReduced, &digest) | ||||
|  | ||||
| 	var R edwards25519.ProjectiveGroupElement | ||||
| 	var s [32]byte | ||||
| 	copy(s[:], sig[32:]) | ||||
|  | ||||
| 	// https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in | ||||
| 	// the range [0, order) in order to prevent signature malleability. | ||||
| 	if !edwards25519.ScMinimal(&s) { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s) | ||||
|  | ||||
| 	var checkR [32]byte | ||||
| 	R.ToBytes(&checkR) | ||||
| 	return bytes.Equal(sig[:32], checkR[:]) | ||||
| } | ||||
							
								
								
									
										1422
									
								
								vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1422
									
								
								vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1793
									
								
								vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1793
									
								
								vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										264
									
								
								vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,264 @@ | ||||
| // 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. | ||||
|  | ||||
| // Package ChaCha20 implements the core ChaCha20 function as specified | ||||
| // in https://tools.ietf.org/html/rfc7539#section-2.3. | ||||
| package chacha20 | ||||
|  | ||||
| import ( | ||||
| 	"crypto/cipher" | ||||
| 	"encoding/binary" | ||||
|  | ||||
| 	"golang.org/x/crypto/internal/subtle" | ||||
| ) | ||||
|  | ||||
| // assert that *Cipher implements cipher.Stream | ||||
| var _ cipher.Stream = (*Cipher)(nil) | ||||
|  | ||||
| // Cipher is a stateful instance of ChaCha20 using a particular key | ||||
| // and nonce. A *Cipher implements the cipher.Stream interface. | ||||
| type Cipher struct { | ||||
| 	key     [8]uint32 | ||||
| 	counter uint32 // incremented after each block | ||||
| 	nonce   [3]uint32 | ||||
| 	buf     [bufSize]byte // buffer for unused keystream bytes | ||||
| 	len     int           // number of unused keystream bytes at end of buf | ||||
| } | ||||
|  | ||||
| // New creates a new ChaCha20 stream cipher with the given key and nonce. | ||||
| // The initial counter value is set to 0. | ||||
| func New(key [8]uint32, nonce [3]uint32) *Cipher { | ||||
| 	return &Cipher{key: key, nonce: nonce} | ||||
| } | ||||
|  | ||||
| // ChaCha20 constants spelling "expand 32-byte k" | ||||
| const ( | ||||
| 	j0 uint32 = 0x61707865 | ||||
| 	j1 uint32 = 0x3320646e | ||||
| 	j2 uint32 = 0x79622d32 | ||||
| 	j3 uint32 = 0x6b206574 | ||||
| ) | ||||
|  | ||||
| func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) { | ||||
| 	a += b | ||||
| 	d ^= a | ||||
| 	d = (d << 16) | (d >> 16) | ||||
| 	c += d | ||||
| 	b ^= c | ||||
| 	b = (b << 12) | (b >> 20) | ||||
| 	a += b | ||||
| 	d ^= a | ||||
| 	d = (d << 8) | (d >> 24) | ||||
| 	c += d | ||||
| 	b ^= c | ||||
| 	b = (b << 7) | (b >> 25) | ||||
| 	return a, b, c, d | ||||
| } | ||||
|  | ||||
| // XORKeyStream XORs each byte in the given slice with a byte from the | ||||
| // cipher's key stream. Dst and src must overlap entirely or not at all. | ||||
| // | ||||
| // If len(dst) < len(src), XORKeyStream will panic. It is acceptable | ||||
| // to pass a dst bigger than src, and in that case, XORKeyStream will | ||||
| // only update dst[:len(src)] and will not touch the rest of dst. | ||||
| // | ||||
| // Multiple calls to XORKeyStream behave as if the concatenation of | ||||
| // the src buffers was passed in a single run. That is, Cipher | ||||
| // maintains state and does not reset at each XORKeyStream call. | ||||
| func (s *Cipher) XORKeyStream(dst, src []byte) { | ||||
| 	if len(dst) < len(src) { | ||||
| 		panic("chacha20: output smaller than input") | ||||
| 	} | ||||
| 	if subtle.InexactOverlap(dst[:len(src)], src) { | ||||
| 		panic("chacha20: invalid buffer overlap") | ||||
| 	} | ||||
|  | ||||
| 	// xor src with buffered keystream first | ||||
| 	if s.len != 0 { | ||||
| 		buf := s.buf[len(s.buf)-s.len:] | ||||
| 		if len(src) < len(buf) { | ||||
| 			buf = buf[:len(src)] | ||||
| 		} | ||||
| 		td, ts := dst[:len(buf)], src[:len(buf)] // BCE hint | ||||
| 		for i, b := range buf { | ||||
| 			td[i] = ts[i] ^ b | ||||
| 		} | ||||
| 		s.len -= len(buf) | ||||
| 		if s.len != 0 { | ||||
| 			return | ||||
| 		} | ||||
| 		s.buf = [len(s.buf)]byte{} // zero the empty buffer | ||||
| 		src = src[len(buf):] | ||||
| 		dst = dst[len(buf):] | ||||
| 	} | ||||
|  | ||||
| 	if len(src) == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	if haveAsm { | ||||
| 		if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 { | ||||
| 			panic("chacha20: counter overflow") | ||||
| 		} | ||||
| 		s.xorKeyStreamAsm(dst, src) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// set up a 64-byte buffer to pad out the final block if needed | ||||
| 	// (hoisted out of the main loop to avoid spills) | ||||
| 	rem := len(src) % 64  // length of final block | ||||
| 	fin := len(src) - rem // index of final block | ||||
| 	if rem > 0 { | ||||
| 		copy(s.buf[len(s.buf)-64:], src[fin:]) | ||||
| 	} | ||||
|  | ||||
| 	// pre-calculate most of the first round | ||||
| 	s1, s5, s9, s13 := quarterRound(j1, s.key[1], s.key[5], s.nonce[0]) | ||||
| 	s2, s6, s10, s14 := quarterRound(j2, s.key[2], s.key[6], s.nonce[1]) | ||||
| 	s3, s7, s11, s15 := quarterRound(j3, s.key[3], s.key[7], s.nonce[2]) | ||||
|  | ||||
| 	n := len(src) | ||||
| 	src, dst = src[:n:n], dst[:n:n] // BCE hint | ||||
| 	for i := 0; i < n; i += 64 { | ||||
| 		// calculate the remainder of the first round | ||||
| 		s0, s4, s8, s12 := quarterRound(j0, s.key[0], s.key[4], s.counter) | ||||
|  | ||||
| 		// execute the second round | ||||
| 		x0, x5, x10, x15 := quarterRound(s0, s5, s10, s15) | ||||
| 		x1, x6, x11, x12 := quarterRound(s1, s6, s11, s12) | ||||
| 		x2, x7, x8, x13 := quarterRound(s2, s7, s8, s13) | ||||
| 		x3, x4, x9, x14 := quarterRound(s3, s4, s9, s14) | ||||
|  | ||||
| 		// execute the remaining 18 rounds | ||||
| 		for i := 0; i < 9; i++ { | ||||
| 			x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12) | ||||
| 			x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13) | ||||
| 			x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14) | ||||
| 			x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15) | ||||
|  | ||||
| 			x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15) | ||||
| 			x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12) | ||||
| 			x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13) | ||||
| 			x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) | ||||
| 		} | ||||
|  | ||||
| 		x0 += j0 | ||||
| 		x1 += j1 | ||||
| 		x2 += j2 | ||||
| 		x3 += j3 | ||||
|  | ||||
| 		x4 += s.key[0] | ||||
| 		x5 += s.key[1] | ||||
| 		x6 += s.key[2] | ||||
| 		x7 += s.key[3] | ||||
| 		x8 += s.key[4] | ||||
| 		x9 += s.key[5] | ||||
| 		x10 += s.key[6] | ||||
| 		x11 += s.key[7] | ||||
|  | ||||
| 		x12 += s.counter | ||||
| 		x13 += s.nonce[0] | ||||
| 		x14 += s.nonce[1] | ||||
| 		x15 += s.nonce[2] | ||||
|  | ||||
| 		// increment the counter | ||||
| 		s.counter += 1 | ||||
| 		if s.counter == 0 { | ||||
| 			panic("chacha20: counter overflow") | ||||
| 		} | ||||
|  | ||||
| 		// pad to 64 bytes if needed | ||||
| 		in, out := src[i:], dst[i:] | ||||
| 		if i == fin { | ||||
| 			// src[fin:] has already been copied into s.buf before | ||||
| 			// the main loop | ||||
| 			in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:] | ||||
| 		} | ||||
| 		in, out = in[:64], out[:64] // BCE hint | ||||
|  | ||||
| 		// XOR the key stream with the source and write out the result | ||||
| 		xor(out[0:], in[0:], x0) | ||||
| 		xor(out[4:], in[4:], x1) | ||||
| 		xor(out[8:], in[8:], x2) | ||||
| 		xor(out[12:], in[12:], x3) | ||||
| 		xor(out[16:], in[16:], x4) | ||||
| 		xor(out[20:], in[20:], x5) | ||||
| 		xor(out[24:], in[24:], x6) | ||||
| 		xor(out[28:], in[28:], x7) | ||||
| 		xor(out[32:], in[32:], x8) | ||||
| 		xor(out[36:], in[36:], x9) | ||||
| 		xor(out[40:], in[40:], x10) | ||||
| 		xor(out[44:], in[44:], x11) | ||||
| 		xor(out[48:], in[48:], x12) | ||||
| 		xor(out[52:], in[52:], x13) | ||||
| 		xor(out[56:], in[56:], x14) | ||||
| 		xor(out[60:], in[60:], x15) | ||||
| 	} | ||||
| 	// copy any trailing bytes out of the buffer and into dst | ||||
| 	if rem != 0 { | ||||
| 		s.len = 64 - rem | ||||
| 		copy(dst[fin:], s.buf[len(s.buf)-64:]) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Advance discards bytes in the key stream until the next 64 byte block | ||||
| // boundary is reached and updates the counter accordingly. If the key | ||||
| // stream is already at a block boundary no bytes will be discarded and | ||||
| // the counter will be unchanged. | ||||
| func (s *Cipher) Advance() { | ||||
| 	s.len -= s.len % 64 | ||||
| 	if s.len == 0 { | ||||
| 		s.buf = [len(s.buf)]byte{} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // XORKeyStream crypts bytes from in to out using the given key and counters. | ||||
| // In and out must overlap entirely or not at all. Counter contains the raw | ||||
| // ChaCha20 counter bytes (i.e. block counter followed by nonce). | ||||
| func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) { | ||||
| 	s := Cipher{ | ||||
| 		key: [8]uint32{ | ||||
| 			binary.LittleEndian.Uint32(key[0:4]), | ||||
| 			binary.LittleEndian.Uint32(key[4:8]), | ||||
| 			binary.LittleEndian.Uint32(key[8:12]), | ||||
| 			binary.LittleEndian.Uint32(key[12:16]), | ||||
| 			binary.LittleEndian.Uint32(key[16:20]), | ||||
| 			binary.LittleEndian.Uint32(key[20:24]), | ||||
| 			binary.LittleEndian.Uint32(key[24:28]), | ||||
| 			binary.LittleEndian.Uint32(key[28:32]), | ||||
| 		}, | ||||
| 		nonce: [3]uint32{ | ||||
| 			binary.LittleEndian.Uint32(counter[4:8]), | ||||
| 			binary.LittleEndian.Uint32(counter[8:12]), | ||||
| 			binary.LittleEndian.Uint32(counter[12:16]), | ||||
| 		}, | ||||
| 		counter: binary.LittleEndian.Uint32(counter[0:4]), | ||||
| 	} | ||||
| 	s.XORKeyStream(out, in) | ||||
| } | ||||
|  | ||||
| // HChaCha20 uses the ChaCha20 core to generate a derived key from a key and a | ||||
| // nonce. It should only be used as part of the XChaCha20 construction. | ||||
| func HChaCha20(key *[8]uint32, nonce *[4]uint32) [8]uint32 { | ||||
| 	x0, x1, x2, x3 := j0, j1, j2, j3 | ||||
| 	x4, x5, x6, x7 := key[0], key[1], key[2], key[3] | ||||
| 	x8, x9, x10, x11 := key[4], key[5], key[6], key[7] | ||||
| 	x12, x13, x14, x15 := nonce[0], nonce[1], nonce[2], nonce[3] | ||||
|  | ||||
| 	for i := 0; i < 10; i++ { | ||||
| 		x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12) | ||||
| 		x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13) | ||||
| 		x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14) | ||||
| 		x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15) | ||||
|  | ||||
| 		x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15) | ||||
| 		x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12) | ||||
| 		x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13) | ||||
| 		x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) | ||||
| 	} | ||||
|  | ||||
| 	var out [8]uint32 | ||||
| 	out[0], out[1], out[2], out[3] = x0, x1, x2, x3 | ||||
| 	out[4], out[5], out[6], out[7] = x12, x13, x14, x15 | ||||
| 	return out | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| // Copyright 2018 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. | ||||
|  | ||||
| // +build !s390x gccgo appengine | ||||
|  | ||||
| package chacha20 | ||||
|  | ||||
| const ( | ||||
| 	bufSize = 64 | ||||
| 	haveAsm = false | ||||
| ) | ||||
|  | ||||
| func (*Cipher) xorKeyStreamAsm(dst, src []byte) { | ||||
| 	panic("not implemented") | ||||
| } | ||||
							
								
								
									
										30
									
								
								vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| // Copyright 2018 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. | ||||
|  | ||||
| // +build s390x,!gccgo,!appengine | ||||
|  | ||||
| package chacha20 | ||||
|  | ||||
| var haveAsm = hasVectorFacility() | ||||
|  | ||||
| const bufSize = 256 | ||||
|  | ||||
| // hasVectorFacility reports whether the machine supports the vector | ||||
| // facility (vx). | ||||
| // Implementation in asm_s390x.s. | ||||
| func hasVectorFacility() bool | ||||
|  | ||||
| // xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only | ||||
| // be called when the vector facility is available. | ||||
| // Implementation in asm_s390x.s. | ||||
| //go:noescape | ||||
| func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int) | ||||
|  | ||||
| func (c *Cipher) xorKeyStreamAsm(dst, src []byte) { | ||||
| 	xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter, &c.buf, &c.len) | ||||
| } | ||||
|  | ||||
| // EXRL targets, DO NOT CALL! | ||||
| func mvcSrcToBuf() | ||||
| func mvcBufToDst() | ||||
							
								
								
									
										283
									
								
								vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,283 @@ | ||||
| // Copyright 2018 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. | ||||
|  | ||||
| // +build s390x,!gccgo,!appengine | ||||
|  | ||||
| #include "go_asm.h" | ||||
| #include "textflag.h" | ||||
|  | ||||
| // This is an implementation of the ChaCha20 encryption algorithm as | ||||
| // specified in RFC 7539. It uses vector instructions to compute | ||||
| // 4 keystream blocks in parallel (256 bytes) which are then XORed | ||||
| // with the bytes in the input slice. | ||||
|  | ||||
| GLOBL ·constants<>(SB), RODATA|NOPTR, $32 | ||||
| // BSWAP: swap bytes in each 4-byte element | ||||
| DATA ·constants<>+0x00(SB)/4, $0x03020100 | ||||
| DATA ·constants<>+0x04(SB)/4, $0x07060504 | ||||
| DATA ·constants<>+0x08(SB)/4, $0x0b0a0908 | ||||
| DATA ·constants<>+0x0c(SB)/4, $0x0f0e0d0c | ||||
| // J0: [j0, j1, j2, j3] | ||||
| DATA ·constants<>+0x10(SB)/4, $0x61707865 | ||||
| DATA ·constants<>+0x14(SB)/4, $0x3320646e | ||||
| DATA ·constants<>+0x18(SB)/4, $0x79622d32 | ||||
| DATA ·constants<>+0x1c(SB)/4, $0x6b206574 | ||||
|  | ||||
| // EXRL targets: | ||||
| TEXT ·mvcSrcToBuf(SB), NOFRAME|NOSPLIT, $0 | ||||
| 	MVC $1, (R1), (R8) | ||||
| 	RET | ||||
|  | ||||
| TEXT ·mvcBufToDst(SB), NOFRAME|NOSPLIT, $0 | ||||
| 	MVC $1, (R8), (R9) | ||||
| 	RET | ||||
|  | ||||
| #define BSWAP V5 | ||||
| #define J0    V6 | ||||
| #define KEY0  V7 | ||||
| #define KEY1  V8 | ||||
| #define NONCE V9 | ||||
| #define CTR   V10 | ||||
| #define M0    V11 | ||||
| #define M1    V12 | ||||
| #define M2    V13 | ||||
| #define M3    V14 | ||||
| #define INC   V15 | ||||
| #define X0    V16 | ||||
| #define X1    V17 | ||||
| #define X2    V18 | ||||
| #define X3    V19 | ||||
| #define X4    V20 | ||||
| #define X5    V21 | ||||
| #define X6    V22 | ||||
| #define X7    V23 | ||||
| #define X8    V24 | ||||
| #define X9    V25 | ||||
| #define X10   V26 | ||||
| #define X11   V27 | ||||
| #define X12   V28 | ||||
| #define X13   V29 | ||||
| #define X14   V30 | ||||
| #define X15   V31 | ||||
|  | ||||
| #define NUM_ROUNDS 20 | ||||
|  | ||||
| #define ROUND4(a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3, d0, d1, d2, d3) \ | ||||
| 	VAF    a1, a0, a0  \ | ||||
| 	VAF    b1, b0, b0  \ | ||||
| 	VAF    c1, c0, c0  \ | ||||
| 	VAF    d1, d0, d0  \ | ||||
| 	VX     a0, a2, a2  \ | ||||
| 	VX     b0, b2, b2  \ | ||||
| 	VX     c0, c2, c2  \ | ||||
| 	VX     d0, d2, d2  \ | ||||
| 	VERLLF $16, a2, a2 \ | ||||
| 	VERLLF $16, b2, b2 \ | ||||
| 	VERLLF $16, c2, c2 \ | ||||
| 	VERLLF $16, d2, d2 \ | ||||
| 	VAF    a2, a3, a3  \ | ||||
| 	VAF    b2, b3, b3  \ | ||||
| 	VAF    c2, c3, c3  \ | ||||
| 	VAF    d2, d3, d3  \ | ||||
| 	VX     a3, a1, a1  \ | ||||
| 	VX     b3, b1, b1  \ | ||||
| 	VX     c3, c1, c1  \ | ||||
| 	VX     d3, d1, d1  \ | ||||
| 	VERLLF $12, a1, a1 \ | ||||
| 	VERLLF $12, b1, b1 \ | ||||
| 	VERLLF $12, c1, c1 \ | ||||
| 	VERLLF $12, d1, d1 \ | ||||
| 	VAF    a1, a0, a0  \ | ||||
| 	VAF    b1, b0, b0  \ | ||||
| 	VAF    c1, c0, c0  \ | ||||
| 	VAF    d1, d0, d0  \ | ||||
| 	VX     a0, a2, a2  \ | ||||
| 	VX     b0, b2, b2  \ | ||||
| 	VX     c0, c2, c2  \ | ||||
| 	VX     d0, d2, d2  \ | ||||
| 	VERLLF $8, a2, a2  \ | ||||
| 	VERLLF $8, b2, b2  \ | ||||
| 	VERLLF $8, c2, c2  \ | ||||
| 	VERLLF $8, d2, d2  \ | ||||
| 	VAF    a2, a3, a3  \ | ||||
| 	VAF    b2, b3, b3  \ | ||||
| 	VAF    c2, c3, c3  \ | ||||
| 	VAF    d2, d3, d3  \ | ||||
| 	VX     a3, a1, a1  \ | ||||
| 	VX     b3, b1, b1  \ | ||||
| 	VX     c3, c1, c1  \ | ||||
| 	VX     d3, d1, d1  \ | ||||
| 	VERLLF $7, a1, a1  \ | ||||
| 	VERLLF $7, b1, b1  \ | ||||
| 	VERLLF $7, c1, c1  \ | ||||
| 	VERLLF $7, d1, d1 | ||||
|  | ||||
| #define PERMUTE(mask, v0, v1, v2, v3) \ | ||||
| 	VPERM v0, v0, mask, v0 \ | ||||
| 	VPERM v1, v1, mask, v1 \ | ||||
| 	VPERM v2, v2, mask, v2 \ | ||||
| 	VPERM v3, v3, mask, v3 | ||||
|  | ||||
| #define ADDV(x, v0, v1, v2, v3) \ | ||||
| 	VAF x, v0, v0 \ | ||||
| 	VAF x, v1, v1 \ | ||||
| 	VAF x, v2, v2 \ | ||||
| 	VAF x, v3, v3 | ||||
|  | ||||
| #define XORV(off, dst, src, v0, v1, v2, v3) \ | ||||
| 	VLM  off(src), M0, M3          \ | ||||
| 	PERMUTE(BSWAP, v0, v1, v2, v3) \ | ||||
| 	VX   v0, M0, M0                \ | ||||
| 	VX   v1, M1, M1                \ | ||||
| 	VX   v2, M2, M2                \ | ||||
| 	VX   v3, M3, M3                \ | ||||
| 	VSTM M0, M3, off(dst) | ||||
|  | ||||
| #define SHUFFLE(a, b, c, d, t, u, v, w) \ | ||||
| 	VMRHF a, c, t \ // t = {a[0], c[0], a[1], c[1]} | ||||
| 	VMRHF b, d, u \ // u = {b[0], d[0], b[1], d[1]} | ||||
| 	VMRLF a, c, v \ // v = {a[2], c[2], a[3], c[3]} | ||||
| 	VMRLF b, d, w \ // w = {b[2], d[2], b[3], d[3]} | ||||
| 	VMRHF t, u, a \ // a = {a[0], b[0], c[0], d[0]} | ||||
| 	VMRLF t, u, b \ // b = {a[1], b[1], c[1], d[1]} | ||||
| 	VMRHF v, w, c \ // c = {a[2], b[2], c[2], d[2]} | ||||
| 	VMRLF v, w, d // d = {a[3], b[3], c[3], d[3]} | ||||
|  | ||||
| // func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int) | ||||
| TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0 | ||||
| 	MOVD $·constants<>(SB), R1 | ||||
| 	MOVD dst+0(FP), R2         // R2=&dst[0] | ||||
| 	LMG  src+24(FP), R3, R4    // R3=&src[0] R4=len(src) | ||||
| 	MOVD key+48(FP), R5        // R5=key | ||||
| 	MOVD nonce+56(FP), R6      // R6=nonce | ||||
| 	MOVD counter+64(FP), R7    // R7=counter | ||||
| 	MOVD buf+72(FP), R8        // R8=buf | ||||
| 	MOVD len+80(FP), R9        // R9=len | ||||
|  | ||||
| 	// load BSWAP and J0 | ||||
| 	VLM (R1), BSWAP, J0 | ||||
|  | ||||
| 	// set up tail buffer | ||||
| 	ADD     $-1, R4, R12 | ||||
| 	MOVBZ   R12, R12 | ||||
| 	CMPUBEQ R12, $255, aligned | ||||
| 	MOVD    R4, R1 | ||||
| 	AND     $~255, R1 | ||||
| 	MOVD    $(R3)(R1*1), R1 | ||||
| 	EXRL    $·mvcSrcToBuf(SB), R12 | ||||
| 	MOVD    $255, R0 | ||||
| 	SUB     R12, R0 | ||||
| 	MOVD    R0, (R9)               // update len | ||||
|  | ||||
| aligned: | ||||
| 	// setup | ||||
| 	MOVD  $95, R0 | ||||
| 	VLM   (R5), KEY0, KEY1 | ||||
| 	VLL   R0, (R6), NONCE | ||||
| 	VZERO M0 | ||||
| 	VLEIB $7, $32, M0 | ||||
| 	VSRLB M0, NONCE, NONCE | ||||
|  | ||||
| 	// initialize counter values | ||||
| 	VLREPF (R7), CTR | ||||
| 	VZERO  INC | ||||
| 	VLEIF  $1, $1, INC | ||||
| 	VLEIF  $2, $2, INC | ||||
| 	VLEIF  $3, $3, INC | ||||
| 	VAF    INC, CTR, CTR | ||||
| 	VREPIF $4, INC | ||||
|  | ||||
| chacha: | ||||
| 	VREPF $0, J0, X0 | ||||
| 	VREPF $1, J0, X1 | ||||
| 	VREPF $2, J0, X2 | ||||
| 	VREPF $3, J0, X3 | ||||
| 	VREPF $0, KEY0, X4 | ||||
| 	VREPF $1, KEY0, X5 | ||||
| 	VREPF $2, KEY0, X6 | ||||
| 	VREPF $3, KEY0, X7 | ||||
| 	VREPF $0, KEY1, X8 | ||||
| 	VREPF $1, KEY1, X9 | ||||
| 	VREPF $2, KEY1, X10 | ||||
| 	VREPF $3, KEY1, X11 | ||||
| 	VLR   CTR, X12 | ||||
| 	VREPF $1, NONCE, X13 | ||||
| 	VREPF $2, NONCE, X14 | ||||
| 	VREPF $3, NONCE, X15 | ||||
|  | ||||
| 	MOVD $(NUM_ROUNDS/2), R1 | ||||
|  | ||||
| loop: | ||||
| 	ROUND4(X0, X4, X12,  X8, X1, X5, X13,  X9, X2, X6, X14, X10, X3, X7, X15, X11) | ||||
| 	ROUND4(X0, X5, X15, X10, X1, X6, X12, X11, X2, X7, X13, X8,  X3, X4, X14, X9) | ||||
|  | ||||
| 	ADD $-1, R1 | ||||
| 	BNE loop | ||||
|  | ||||
| 	// decrement length | ||||
| 	ADD $-256, R4 | ||||
| 	BLT tail | ||||
|  | ||||
| continue: | ||||
| 	// rearrange vectors | ||||
| 	SHUFFLE(X0, X1, X2, X3, M0, M1, M2, M3) | ||||
| 	ADDV(J0, X0, X1, X2, X3) | ||||
| 	SHUFFLE(X4, X5, X6, X7, M0, M1, M2, M3) | ||||
| 	ADDV(KEY0, X4, X5, X6, X7) | ||||
| 	SHUFFLE(X8, X9, X10, X11, M0, M1, M2, M3) | ||||
| 	ADDV(KEY1, X8, X9, X10, X11) | ||||
| 	VAF CTR, X12, X12 | ||||
| 	SHUFFLE(X12, X13, X14, X15, M0, M1, M2, M3) | ||||
| 	ADDV(NONCE, X12, X13, X14, X15) | ||||
|  | ||||
| 	// increment counters | ||||
| 	VAF INC, CTR, CTR | ||||
|  | ||||
| 	// xor keystream with plaintext | ||||
| 	XORV(0*64, R2, R3, X0, X4,  X8, X12) | ||||
| 	XORV(1*64, R2, R3, X1, X5,  X9, X13) | ||||
| 	XORV(2*64, R2, R3, X2, X6, X10, X14) | ||||
| 	XORV(3*64, R2, R3, X3, X7, X11, X15) | ||||
|  | ||||
| 	// increment pointers | ||||
| 	MOVD $256(R2), R2 | ||||
| 	MOVD $256(R3), R3 | ||||
|  | ||||
| 	CMPBNE  R4, $0, chacha | ||||
| 	CMPUBEQ R12, $255, return | ||||
| 	EXRL    $·mvcBufToDst(SB), R12 // len was updated during setup | ||||
|  | ||||
| return: | ||||
| 	VSTEF $0, CTR, (R7) | ||||
| 	RET | ||||
|  | ||||
| tail: | ||||
| 	MOVD R2, R9 | ||||
| 	MOVD R8, R2 | ||||
| 	MOVD R8, R3 | ||||
| 	MOVD $0, R4 | ||||
| 	JMP  continue | ||||
|  | ||||
| // func hasVectorFacility() bool | ||||
| TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1 | ||||
| 	MOVD  $x-24(SP), R1 | ||||
| 	XC    $24, 0(R1), 0(R1) // clear the storage | ||||
| 	MOVD  $2, R0            // R0 is the number of double words stored -1 | ||||
| 	WORD  $0xB2B01000       // STFLE 0(R1) | ||||
| 	XOR   R0, R0            // reset the value of R0 | ||||
| 	MOVBZ z-8(SP), R1 | ||||
| 	AND   $0x40, R1 | ||||
| 	BEQ   novector | ||||
|  | ||||
| vectorinstalled: | ||||
| 	// check if the vector instruction has been enabled | ||||
| 	VLEIB  $0, $0xF, V16 | ||||
| 	VLGVB  $0, V16, R1 | ||||
| 	CMPBNE R1, $0xF, novector | ||||
| 	MOVB   $1, ret+0(FP)      // have vx | ||||
| 	RET | ||||
|  | ||||
| novector: | ||||
| 	MOVB $0, ret+0(FP) // no vx | ||||
| 	RET | ||||
							
								
								
									
										43
									
								
								vendor/golang.org/x/crypto/internal/chacha20/xor.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/golang.org/x/crypto/internal/chacha20/xor.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| // Copyright 2018 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found src the LICENSE file. | ||||
|  | ||||
| package chacha20 | ||||
|  | ||||
| import ( | ||||
| 	"runtime" | ||||
| ) | ||||
|  | ||||
| // Platforms that have fast unaligned 32-bit little endian accesses. | ||||
| const unaligned = runtime.GOARCH == "386" || | ||||
| 	runtime.GOARCH == "amd64" || | ||||
| 	runtime.GOARCH == "arm64" || | ||||
| 	runtime.GOARCH == "ppc64le" || | ||||
| 	runtime.GOARCH == "s390x" | ||||
|  | ||||
| // xor reads a little endian uint32 from src, XORs it with u and | ||||
| // places the result in little endian byte order in dst. | ||||
| func xor(dst, src []byte, u uint32) { | ||||
| 	_, _ = src[3], dst[3] // eliminate bounds checks | ||||
| 	if unaligned { | ||||
| 		// The compiler should optimize this code into | ||||
| 		// 32-bit unaligned little endian loads and stores. | ||||
| 		// TODO: delete once the compiler does a reliably | ||||
| 		// good job with the generic code below. | ||||
| 		// See issue #25111 for more details. | ||||
| 		v := uint32(src[0]) | ||||
| 		v |= uint32(src[1]) << 8 | ||||
| 		v |= uint32(src[2]) << 16 | ||||
| 		v |= uint32(src[3]) << 24 | ||||
| 		v ^= u | ||||
| 		dst[0] = byte(v) | ||||
| 		dst[1] = byte(v >> 8) | ||||
| 		dst[2] = byte(v >> 16) | ||||
| 		dst[3] = byte(v >> 24) | ||||
| 	} else { | ||||
| 		dst[0] = src[0] ^ byte(u) | ||||
| 		dst[1] = src[1] ^ byte(u>>8) | ||||
| 		dst[2] = src[2] ^ byte(u>>16) | ||||
| 		dst[3] = src[3] ^ byte(u>>24) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										32
									
								
								vendor/golang.org/x/crypto/internal/subtle/aliasing.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								vendor/golang.org/x/crypto/internal/subtle/aliasing.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| // Copyright 2018 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. | ||||
|  | ||||
| // +build !appengine | ||||
|  | ||||
| // Package subtle implements functions that are often useful in cryptographic | ||||
| // code but require careful thought to use correctly. | ||||
| package subtle // import "golang.org/x/crypto/internal/subtle" | ||||
|  | ||||
| import "unsafe" | ||||
|  | ||||
| // AnyOverlap reports whether x and y share memory at any (not necessarily | ||||
| // corresponding) index. The memory beyond the slice length is ignored. | ||||
| func AnyOverlap(x, y []byte) bool { | ||||
| 	return len(x) > 0 && len(y) > 0 && | ||||
| 		uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) && | ||||
| 		uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1])) | ||||
| } | ||||
|  | ||||
| // InexactOverlap reports whether x and y share memory at any non-corresponding | ||||
| // index. The memory beyond the slice length is ignored. Note that x and y can | ||||
| // have different lengths and still not have any inexact overlap. | ||||
| // | ||||
| // InexactOverlap can be used to implement the requirements of the crypto/cipher | ||||
| // AEAD, Block, BlockMode and Stream interfaces. | ||||
| func InexactOverlap(x, y []byte) bool { | ||||
| 	if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { | ||||
| 		return false | ||||
| 	} | ||||
| 	return AnyOverlap(x, y) | ||||
| } | ||||
							
								
								
									
										35
									
								
								vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| // Copyright 2018 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. | ||||
|  | ||||
| // +build appengine | ||||
|  | ||||
| // Package subtle implements functions that are often useful in cryptographic | ||||
| // code but require careful thought to use correctly. | ||||
| package subtle // import "golang.org/x/crypto/internal/subtle" | ||||
|  | ||||
| // This is the Google App Engine standard variant based on reflect | ||||
| // because the unsafe package and cgo are disallowed. | ||||
|  | ||||
| import "reflect" | ||||
|  | ||||
| // AnyOverlap reports whether x and y share memory at any (not necessarily | ||||
| // corresponding) index. The memory beyond the slice length is ignored. | ||||
| func AnyOverlap(x, y []byte) bool { | ||||
| 	return len(x) > 0 && len(y) > 0 && | ||||
| 		reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() && | ||||
| 		reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer() | ||||
| } | ||||
|  | ||||
| // InexactOverlap reports whether x and y share memory at any non-corresponding | ||||
| // index. The memory beyond the slice length is ignored. Note that x and y can | ||||
| // have different lengths and still not have any inexact overlap. | ||||
| // | ||||
| // InexactOverlap can be used to implement the requirements of the crypto/cipher | ||||
| // AEAD, Block, BlockMode and Stream interfaces. | ||||
| func InexactOverlap(x, y []byte) bool { | ||||
| 	if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { | ||||
| 		return false | ||||
| 	} | ||||
| 	return AnyOverlap(x, y) | ||||
| } | ||||
							
								
								
									
										33
									
								
								vendor/golang.org/x/crypto/poly1305/poly1305.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								vendor/golang.org/x/crypto/poly1305/poly1305.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| // Copyright 2012 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 poly1305 implements Poly1305 one-time message authentication code as | ||||
| specified in https://cr.yp.to/mac/poly1305-20050329.pdf. | ||||
|  | ||||
| Poly1305 is a fast, one-time authentication function. It is infeasible for an | ||||
| attacker to generate an authenticator for a message without the key. However, a | ||||
| key must only be used for a single message. Authenticating two different | ||||
| messages with the same key allows an attacker to forge authenticators for other | ||||
| messages with the same key. | ||||
|  | ||||
| Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was | ||||
| used with a fixed key in order to generate one-time keys from an nonce. | ||||
| However, in this package AES isn't used and the one-time key is specified | ||||
| directly. | ||||
| */ | ||||
| package poly1305 // import "golang.org/x/crypto/poly1305" | ||||
|  | ||||
| import "crypto/subtle" | ||||
|  | ||||
| // TagSize is the size, in bytes, of a poly1305 authenticator. | ||||
| const TagSize = 16 | ||||
|  | ||||
| // Verify returns true if mac is a valid authenticator for m with the given | ||||
| // key. | ||||
| func Verify(mac *[16]byte, m []byte, key *[32]byte) bool { | ||||
| 	var tmp [16]byte | ||||
| 	Sum(&tmp, m, key) | ||||
| 	return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1 | ||||
| } | ||||
							
								
								
									
										22
									
								
								vendor/golang.org/x/crypto/poly1305/sum_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/golang.org/x/crypto/poly1305/sum_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // +build amd64,!gccgo,!appengine | ||||
|  | ||||
| package poly1305 | ||||
|  | ||||
| // This function is implemented in sum_amd64.s | ||||
| //go:noescape | ||||
| func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]byte) | ||||
|  | ||||
| // Sum generates an authenticator for m using a one-time key and puts the | ||||
| // 16-byte result into out. Authenticating two different messages with the same | ||||
| // key allows an attacker to forge messages at will. | ||||
| func Sum(out *[16]byte, m []byte, key *[32]byte) { | ||||
| 	var mPtr *byte | ||||
| 	if len(m) > 0 { | ||||
| 		mPtr = &m[0] | ||||
| 	} | ||||
| 	poly1305(out, mPtr, uint64(len(m)), key) | ||||
| } | ||||
							
								
								
									
										125
									
								
								vendor/golang.org/x/crypto/poly1305/sum_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								vendor/golang.org/x/crypto/poly1305/sum_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // +build amd64,!gccgo,!appengine | ||||
|  | ||||
| #include "textflag.h" | ||||
|  | ||||
| #define POLY1305_ADD(msg, h0, h1, h2) \ | ||||
| 	ADDQ 0(msg), h0;  \ | ||||
| 	ADCQ 8(msg), h1;  \ | ||||
| 	ADCQ $1, h2;      \ | ||||
| 	LEAQ 16(msg), msg | ||||
|  | ||||
| #define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3) \ | ||||
| 	MOVQ  r0, AX;                  \ | ||||
| 	MULQ  h0;                      \ | ||||
| 	MOVQ  AX, t0;                  \ | ||||
| 	MOVQ  DX, t1;                  \ | ||||
| 	MOVQ  r0, AX;                  \ | ||||
| 	MULQ  h1;                      \ | ||||
| 	ADDQ  AX, t1;                  \ | ||||
| 	ADCQ  $0, DX;                  \ | ||||
| 	MOVQ  r0, t2;                  \ | ||||
| 	IMULQ h2, t2;                  \ | ||||
| 	ADDQ  DX, t2;                  \ | ||||
| 	                               \ | ||||
| 	MOVQ  r1, AX;                  \ | ||||
| 	MULQ  h0;                      \ | ||||
| 	ADDQ  AX, t1;                  \ | ||||
| 	ADCQ  $0, DX;                  \ | ||||
| 	MOVQ  DX, h0;                  \ | ||||
| 	MOVQ  r1, t3;                  \ | ||||
| 	IMULQ h2, t3;                  \ | ||||
| 	MOVQ  r1, AX;                  \ | ||||
| 	MULQ  h1;                      \ | ||||
| 	ADDQ  AX, t2;                  \ | ||||
| 	ADCQ  DX, t3;                  \ | ||||
| 	ADDQ  h0, t2;                  \ | ||||
| 	ADCQ  $0, t3;                  \ | ||||
| 	                               \ | ||||
| 	MOVQ  t0, h0;                  \ | ||||
| 	MOVQ  t1, h1;                  \ | ||||
| 	MOVQ  t2, h2;                  \ | ||||
| 	ANDQ  $3, h2;                  \ | ||||
| 	MOVQ  t2, t0;                  \ | ||||
| 	ANDQ  $0xFFFFFFFFFFFFFFFC, t0; \ | ||||
| 	ADDQ  t0, h0;                  \ | ||||
| 	ADCQ  t3, h1;                  \ | ||||
| 	ADCQ  $0, h2;                  \ | ||||
| 	SHRQ  $2, t3, t2;              \ | ||||
| 	SHRQ  $2, t3;                  \ | ||||
| 	ADDQ  t2, h0;                  \ | ||||
| 	ADCQ  t3, h1;                  \ | ||||
| 	ADCQ  $0, h2 | ||||
|  | ||||
| DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF | ||||
| DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC | ||||
| GLOBL ·poly1305Mask<>(SB), RODATA, $16 | ||||
|  | ||||
| // func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]key) | ||||
| TEXT ·poly1305(SB), $0-32 | ||||
| 	MOVQ out+0(FP), DI | ||||
| 	MOVQ m+8(FP), SI | ||||
| 	MOVQ mlen+16(FP), R15 | ||||
| 	MOVQ key+24(FP), AX | ||||
|  | ||||
| 	MOVQ 0(AX), R11 | ||||
| 	MOVQ 8(AX), R12 | ||||
| 	ANDQ ·poly1305Mask<>(SB), R11   // r0 | ||||
| 	ANDQ ·poly1305Mask<>+8(SB), R12 // r1 | ||||
| 	XORQ R8, R8                    // h0 | ||||
| 	XORQ R9, R9                    // h1 | ||||
| 	XORQ R10, R10                  // h2 | ||||
|  | ||||
| 	CMPQ R15, $16 | ||||
| 	JB   bytes_between_0_and_15 | ||||
|  | ||||
| loop: | ||||
| 	POLY1305_ADD(SI, R8, R9, R10) | ||||
|  | ||||
| multiply: | ||||
| 	POLY1305_MUL(R8, R9, R10, R11, R12, BX, CX, R13, R14) | ||||
| 	SUBQ $16, R15 | ||||
| 	CMPQ R15, $16 | ||||
| 	JAE  loop | ||||
|  | ||||
| bytes_between_0_and_15: | ||||
| 	TESTQ R15, R15 | ||||
| 	JZ    done | ||||
| 	MOVQ  $1, BX | ||||
| 	XORQ  CX, CX | ||||
| 	XORQ  R13, R13 | ||||
| 	ADDQ  R15, SI | ||||
|  | ||||
| flush_buffer: | ||||
| 	SHLQ $8, BX, CX | ||||
| 	SHLQ $8, BX | ||||
| 	MOVB -1(SI), R13 | ||||
| 	XORQ R13, BX | ||||
| 	DECQ SI | ||||
| 	DECQ R15 | ||||
| 	JNZ  flush_buffer | ||||
|  | ||||
| 	ADDQ BX, R8 | ||||
| 	ADCQ CX, R9 | ||||
| 	ADCQ $0, R10 | ||||
| 	MOVQ $16, R15 | ||||
| 	JMP  multiply | ||||
|  | ||||
| done: | ||||
| 	MOVQ    R8, AX | ||||
| 	MOVQ    R9, BX | ||||
| 	SUBQ    $0xFFFFFFFFFFFFFFFB, AX | ||||
| 	SBBQ    $0xFFFFFFFFFFFFFFFF, BX | ||||
| 	SBBQ    $3, R10 | ||||
| 	CMOVQCS R8, AX | ||||
| 	CMOVQCS R9, BX | ||||
| 	MOVQ    key+24(FP), R8 | ||||
| 	ADDQ    16(R8), AX | ||||
| 	ADCQ    24(R8), BX | ||||
|  | ||||
| 	MOVQ AX, 0(DI) | ||||
| 	MOVQ BX, 8(DI) | ||||
| 	RET | ||||
							
								
								
									
										22
									
								
								vendor/golang.org/x/crypto/poly1305/sum_arm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/golang.org/x/crypto/poly1305/sum_arm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| // Copyright 2015 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. | ||||
|  | ||||
| // +build arm,!gccgo,!appengine,!nacl | ||||
|  | ||||
| package poly1305 | ||||
|  | ||||
| // This function is implemented in sum_arm.s | ||||
| //go:noescape | ||||
| func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]byte) | ||||
|  | ||||
| // Sum generates an authenticator for m using a one-time key and puts the | ||||
| // 16-byte result into out. Authenticating two different messages with the same | ||||
| // key allows an attacker to forge messages at will. | ||||
| func Sum(out *[16]byte, m []byte, key *[32]byte) { | ||||
| 	var mPtr *byte | ||||
| 	if len(m) > 0 { | ||||
| 		mPtr = &m[0] | ||||
| 	} | ||||
| 	poly1305_auth_armv6(out, mPtr, uint32(len(m)), key) | ||||
| } | ||||
							
								
								
									
										427
									
								
								vendor/golang.org/x/crypto/poly1305/sum_arm.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										427
									
								
								vendor/golang.org/x/crypto/poly1305/sum_arm.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,427 @@ | ||||
| // Copyright 2015 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. | ||||
|  | ||||
| // +build arm,!gccgo,!appengine,!nacl | ||||
|  | ||||
| #include "textflag.h" | ||||
|  | ||||
| // This code was translated into a form compatible with 5a from the public | ||||
| // domain source by Andrew Moon: github.com/floodyberry/poly1305-opt/blob/master/app/extensions/poly1305. | ||||
|  | ||||
| DATA ·poly1305_init_constants_armv6<>+0x00(SB)/4, $0x3ffffff | ||||
| DATA ·poly1305_init_constants_armv6<>+0x04(SB)/4, $0x3ffff03 | ||||
| DATA ·poly1305_init_constants_armv6<>+0x08(SB)/4, $0x3ffc0ff | ||||
| DATA ·poly1305_init_constants_armv6<>+0x0c(SB)/4, $0x3f03fff | ||||
| DATA ·poly1305_init_constants_armv6<>+0x10(SB)/4, $0x00fffff | ||||
| GLOBL ·poly1305_init_constants_armv6<>(SB), 8, $20 | ||||
|  | ||||
| // Warning: the linker may use R11 to synthesize certain instructions. Please | ||||
| // take care and verify that no synthetic instructions use it. | ||||
|  | ||||
| TEXT poly1305_init_ext_armv6<>(SB), NOSPLIT, $0 | ||||
| 	// Needs 16 bytes of stack and 64 bytes of space pointed to by R0.  (It | ||||
| 	// might look like it's only 60 bytes of space but the final four bytes | ||||
| 	// will be written by another function.) We need to skip over four | ||||
| 	// bytes of stack because that's saving the value of 'g'. | ||||
| 	ADD       $4, R13, R8 | ||||
| 	MOVM.IB   [R4-R7], (R8) | ||||
| 	MOVM.IA.W (R1), [R2-R5] | ||||
| 	MOVW      $·poly1305_init_constants_armv6<>(SB), R7 | ||||
| 	MOVW      R2, R8 | ||||
| 	MOVW      R2>>26, R9 | ||||
| 	MOVW      R3>>20, g | ||||
| 	MOVW      R4>>14, R11 | ||||
| 	MOVW      R5>>8, R12 | ||||
| 	ORR       R3<<6, R9, R9 | ||||
| 	ORR       R4<<12, g, g | ||||
| 	ORR       R5<<18, R11, R11 | ||||
| 	MOVM.IA   (R7), [R2-R6] | ||||
| 	AND       R8, R2, R2 | ||||
| 	AND       R9, R3, R3 | ||||
| 	AND       g, R4, R4 | ||||
| 	AND       R11, R5, R5 | ||||
| 	AND       R12, R6, R6 | ||||
| 	MOVM.IA.W [R2-R6], (R0) | ||||
| 	EOR       R2, R2, R2 | ||||
| 	EOR       R3, R3, R3 | ||||
| 	EOR       R4, R4, R4 | ||||
| 	EOR       R5, R5, R5 | ||||
| 	EOR       R6, R6, R6 | ||||
| 	MOVM.IA.W [R2-R6], (R0) | ||||
| 	MOVM.IA.W (R1), [R2-R5] | ||||
| 	MOVM.IA   [R2-R6], (R0) | ||||
| 	ADD       $20, R13, R0 | ||||
| 	MOVM.DA   (R0), [R4-R7] | ||||
| 	RET | ||||
|  | ||||
| #define MOVW_UNALIGNED(Rsrc, Rdst, Rtmp, offset) \ | ||||
| 	MOVBU (offset+0)(Rsrc), Rtmp; \ | ||||
| 	MOVBU Rtmp, (offset+0)(Rdst); \ | ||||
| 	MOVBU (offset+1)(Rsrc), Rtmp; \ | ||||
| 	MOVBU Rtmp, (offset+1)(Rdst); \ | ||||
| 	MOVBU (offset+2)(Rsrc), Rtmp; \ | ||||
| 	MOVBU Rtmp, (offset+2)(Rdst); \ | ||||
| 	MOVBU (offset+3)(Rsrc), Rtmp; \ | ||||
| 	MOVBU Rtmp, (offset+3)(Rdst) | ||||
|  | ||||
| TEXT poly1305_blocks_armv6<>(SB), NOSPLIT, $0 | ||||
| 	// Needs 24 bytes of stack for saved registers and then 88 bytes of | ||||
| 	// scratch space after that. We assume that 24 bytes at (R13) have | ||||
| 	// already been used: four bytes for the link register saved in the | ||||
| 	// prelude of poly1305_auth_armv6, four bytes for saving the value of g | ||||
| 	// in that function and 16 bytes of scratch space used around | ||||
| 	// poly1305_finish_ext_armv6_skip1. | ||||
| 	ADD     $24, R13, R12 | ||||
| 	MOVM.IB [R4-R8, R14], (R12) | ||||
| 	MOVW    R0, 88(R13) | ||||
| 	MOVW    R1, 92(R13) | ||||
| 	MOVW    R2, 96(R13) | ||||
| 	MOVW    R1, R14 | ||||
| 	MOVW    R2, R12 | ||||
| 	MOVW    56(R0), R8 | ||||
| 	WORD    $0xe1180008                // TST R8, R8 not working see issue 5921 | ||||
| 	EOR     R6, R6, R6 | ||||
| 	MOVW.EQ $(1<<24), R6 | ||||
| 	MOVW    R6, 84(R13) | ||||
| 	ADD     $116, R13, g | ||||
| 	MOVM.IA (R0), [R0-R9] | ||||
| 	MOVM.IA [R0-R4], (g) | ||||
| 	CMP     $16, R12 | ||||
| 	BLO     poly1305_blocks_armv6_done | ||||
|  | ||||
| poly1305_blocks_armv6_mainloop: | ||||
| 	WORD    $0xe31e0003                            // TST R14, #3 not working see issue 5921 | ||||
| 	BEQ     poly1305_blocks_armv6_mainloop_aligned | ||||
| 	ADD     $100, R13, g | ||||
| 	MOVW_UNALIGNED(R14, g, R0, 0) | ||||
| 	MOVW_UNALIGNED(R14, g, R0, 4) | ||||
| 	MOVW_UNALIGNED(R14, g, R0, 8) | ||||
| 	MOVW_UNALIGNED(R14, g, R0, 12) | ||||
| 	MOVM.IA (g), [R0-R3] | ||||
| 	ADD     $16, R14 | ||||
| 	B       poly1305_blocks_armv6_mainloop_loaded | ||||
|  | ||||
| poly1305_blocks_armv6_mainloop_aligned: | ||||
| 	MOVM.IA.W (R14), [R0-R3] | ||||
|  | ||||
| poly1305_blocks_armv6_mainloop_loaded: | ||||
| 	MOVW    R0>>26, g | ||||
| 	MOVW    R1>>20, R11 | ||||
| 	MOVW    R2>>14, R12 | ||||
| 	MOVW    R14, 92(R13) | ||||
| 	MOVW    R3>>8, R4 | ||||
| 	ORR     R1<<6, g, g | ||||
| 	ORR     R2<<12, R11, R11 | ||||
| 	ORR     R3<<18, R12, R12 | ||||
| 	BIC     $0xfc000000, R0, R0 | ||||
| 	BIC     $0xfc000000, g, g | ||||
| 	MOVW    84(R13), R3 | ||||
| 	BIC     $0xfc000000, R11, R11 | ||||
| 	BIC     $0xfc000000, R12, R12 | ||||
| 	ADD     R0, R5, R5 | ||||
| 	ADD     g, R6, R6 | ||||
| 	ORR     R3, R4, R4 | ||||
| 	ADD     R11, R7, R7 | ||||
| 	ADD     $116, R13, R14 | ||||
| 	ADD     R12, R8, R8 | ||||
| 	ADD     R4, R9, R9 | ||||
| 	MOVM.IA (R14), [R0-R4] | ||||
| 	MULLU   R4, R5, (R11, g) | ||||
| 	MULLU   R3, R5, (R14, R12) | ||||
| 	MULALU  R3, R6, (R11, g) | ||||
| 	MULALU  R2, R6, (R14, R12) | ||||
| 	MULALU  R2, R7, (R11, g) | ||||
| 	MULALU  R1, R7, (R14, R12) | ||||
| 	ADD     R4<<2, R4, R4 | ||||
| 	ADD     R3<<2, R3, R3 | ||||
| 	MULALU  R1, R8, (R11, g) | ||||
| 	MULALU  R0, R8, (R14, R12) | ||||
| 	MULALU  R0, R9, (R11, g) | ||||
| 	MULALU  R4, R9, (R14, R12) | ||||
| 	MOVW    g, 76(R13) | ||||
| 	MOVW    R11, 80(R13) | ||||
| 	MOVW    R12, 68(R13) | ||||
| 	MOVW    R14, 72(R13) | ||||
| 	MULLU   R2, R5, (R11, g) | ||||
| 	MULLU   R1, R5, (R14, R12) | ||||
| 	MULALU  R1, R6, (R11, g) | ||||
| 	MULALU  R0, R6, (R14, R12) | ||||
| 	MULALU  R0, R7, (R11, g) | ||||
| 	MULALU  R4, R7, (R14, R12) | ||||
| 	ADD     R2<<2, R2, R2 | ||||
| 	ADD     R1<<2, R1, R1 | ||||
| 	MULALU  R4, R8, (R11, g) | ||||
| 	MULALU  R3, R8, (R14, R12) | ||||
| 	MULALU  R3, R9, (R11, g) | ||||
| 	MULALU  R2, R9, (R14, R12) | ||||
| 	MOVW    g, 60(R13) | ||||
| 	MOVW    R11, 64(R13) | ||||
| 	MOVW    R12, 52(R13) | ||||
| 	MOVW    R14, 56(R13) | ||||
| 	MULLU   R0, R5, (R11, g) | ||||
| 	MULALU  R4, R6, (R11, g) | ||||
| 	MULALU  R3, R7, (R11, g) | ||||
| 	MULALU  R2, R8, (R11, g) | ||||
| 	MULALU  R1, R9, (R11, g) | ||||
| 	ADD     $52, R13, R0 | ||||
| 	MOVM.IA (R0), [R0-R7] | ||||
| 	MOVW    g>>26, R12 | ||||
| 	MOVW    R4>>26, R14 | ||||
| 	ORR     R11<<6, R12, R12 | ||||
| 	ORR     R5<<6, R14, R14 | ||||
| 	BIC     $0xfc000000, g, g | ||||
| 	BIC     $0xfc000000, R4, R4 | ||||
| 	ADD.S   R12, R0, R0 | ||||
| 	ADC     $0, R1, R1 | ||||
| 	ADD.S   R14, R6, R6 | ||||
| 	ADC     $0, R7, R7 | ||||
| 	MOVW    R0>>26, R12 | ||||
| 	MOVW    R6>>26, R14 | ||||
| 	ORR     R1<<6, R12, R12 | ||||
| 	ORR     R7<<6, R14, R14 | ||||
| 	BIC     $0xfc000000, R0, R0 | ||||
| 	BIC     $0xfc000000, R6, R6 | ||||
| 	ADD     R14<<2, R14, R14 | ||||
| 	ADD.S   R12, R2, R2 | ||||
| 	ADC     $0, R3, R3 | ||||
| 	ADD     R14, g, g | ||||
| 	MOVW    R2>>26, R12 | ||||
| 	MOVW    g>>26, R14 | ||||
| 	ORR     R3<<6, R12, R12 | ||||
| 	BIC     $0xfc000000, g, R5 | ||||
| 	BIC     $0xfc000000, R2, R7 | ||||
| 	ADD     R12, R4, R4 | ||||
| 	ADD     R14, R0, R0 | ||||
| 	MOVW    R4>>26, R12 | ||||
| 	BIC     $0xfc000000, R4, R8 | ||||
| 	ADD     R12, R6, R9 | ||||
| 	MOVW    96(R13), R12 | ||||
| 	MOVW    92(R13), R14 | ||||
| 	MOVW    R0, R6 | ||||
| 	CMP     $32, R12 | ||||
| 	SUB     $16, R12, R12 | ||||
| 	MOVW    R12, 96(R13) | ||||
| 	BHS     poly1305_blocks_armv6_mainloop | ||||
|  | ||||
| poly1305_blocks_armv6_done: | ||||
| 	MOVW    88(R13), R12 | ||||
| 	MOVW    R5, 20(R12) | ||||
| 	MOVW    R6, 24(R12) | ||||
| 	MOVW    R7, 28(R12) | ||||
| 	MOVW    R8, 32(R12) | ||||
| 	MOVW    R9, 36(R12) | ||||
| 	ADD     $48, R13, R0 | ||||
| 	MOVM.DA (R0), [R4-R8, R14] | ||||
| 	RET | ||||
|  | ||||
| #define MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp) \ | ||||
| 	MOVBU.P 1(Rsrc), Rtmp; \ | ||||
| 	MOVBU.P Rtmp, 1(Rdst); \ | ||||
| 	MOVBU.P 1(Rsrc), Rtmp; \ | ||||
| 	MOVBU.P Rtmp, 1(Rdst) | ||||
|  | ||||
| #define MOVWP_UNALIGNED(Rsrc, Rdst, Rtmp) \ | ||||
| 	MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp); \ | ||||
| 	MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp) | ||||
|  | ||||
| // func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]key) | ||||
| TEXT ·poly1305_auth_armv6(SB), $196-16 | ||||
| 	// The value 196, just above, is the sum of 64 (the size of the context | ||||
| 	// structure) and 132 (the amount of stack needed). | ||||
| 	// | ||||
| 	// At this point, the stack pointer (R13) has been moved down. It | ||||
| 	// points to the saved link register and there's 196 bytes of free | ||||
| 	// space above it. | ||||
| 	// | ||||
| 	// The stack for this function looks like: | ||||
| 	// | ||||
| 	// +--------------------- | ||||
| 	// | | ||||
| 	// | 64 bytes of context structure | ||||
| 	// | | ||||
| 	// +--------------------- | ||||
| 	// | | ||||
| 	// | 112 bytes for poly1305_blocks_armv6 | ||||
| 	// | | ||||
| 	// +--------------------- | ||||
| 	// | 16 bytes of final block, constructed at | ||||
| 	// | poly1305_finish_ext_armv6_skip8 | ||||
| 	// +--------------------- | ||||
| 	// | four bytes of saved 'g' | ||||
| 	// +--------------------- | ||||
| 	// | lr, saved by prelude    <- R13 points here | ||||
| 	// +--------------------- | ||||
| 	MOVW g, 4(R13) | ||||
|  | ||||
| 	MOVW out+0(FP), R4 | ||||
| 	MOVW m+4(FP), R5 | ||||
| 	MOVW mlen+8(FP), R6 | ||||
| 	MOVW key+12(FP), R7 | ||||
|  | ||||
| 	ADD  $136, R13, R0 // 136 = 4 + 4 + 16 + 112 | ||||
| 	MOVW R7, R1 | ||||
|  | ||||
| 	// poly1305_init_ext_armv6 will write to the stack from R13+4, but | ||||
| 	// that's ok because none of the other values have been written yet. | ||||
| 	BL    poly1305_init_ext_armv6<>(SB) | ||||
| 	BIC.S $15, R6, R2 | ||||
| 	BEQ   poly1305_auth_armv6_noblocks | ||||
| 	ADD   $136, R13, R0 | ||||
| 	MOVW  R5, R1 | ||||
| 	ADD   R2, R5, R5 | ||||
| 	SUB   R2, R6, R6 | ||||
| 	BL    poly1305_blocks_armv6<>(SB) | ||||
|  | ||||
| poly1305_auth_armv6_noblocks: | ||||
| 	ADD  $136, R13, R0 | ||||
| 	MOVW R5, R1 | ||||
| 	MOVW R6, R2 | ||||
| 	MOVW R4, R3 | ||||
|  | ||||
| 	MOVW  R0, R5 | ||||
| 	MOVW  R1, R6 | ||||
| 	MOVW  R2, R7 | ||||
| 	MOVW  R3, R8 | ||||
| 	AND.S R2, R2, R2 | ||||
| 	BEQ   poly1305_finish_ext_armv6_noremaining | ||||
| 	EOR   R0, R0 | ||||
| 	ADD   $8, R13, R9                           // 8 = offset to 16 byte scratch space | ||||
| 	MOVW  R0, (R9) | ||||
| 	MOVW  R0, 4(R9) | ||||
| 	MOVW  R0, 8(R9) | ||||
| 	MOVW  R0, 12(R9) | ||||
| 	WORD  $0xe3110003                           // TST R1, #3 not working see issue 5921 | ||||
| 	BEQ   poly1305_finish_ext_armv6_aligned | ||||
| 	WORD  $0xe3120008                           // TST R2, #8 not working see issue 5921 | ||||
| 	BEQ   poly1305_finish_ext_armv6_skip8 | ||||
| 	MOVWP_UNALIGNED(R1, R9, g) | ||||
| 	MOVWP_UNALIGNED(R1, R9, g) | ||||
|  | ||||
| poly1305_finish_ext_armv6_skip8: | ||||
| 	WORD $0xe3120004                     // TST $4, R2 not working see issue 5921 | ||||
| 	BEQ  poly1305_finish_ext_armv6_skip4 | ||||
| 	MOVWP_UNALIGNED(R1, R9, g) | ||||
|  | ||||
| poly1305_finish_ext_armv6_skip4: | ||||
| 	WORD $0xe3120002                     // TST $2, R2 not working see issue 5921 | ||||
| 	BEQ  poly1305_finish_ext_armv6_skip2 | ||||
| 	MOVHUP_UNALIGNED(R1, R9, g) | ||||
| 	B    poly1305_finish_ext_armv6_skip2 | ||||
|  | ||||
| poly1305_finish_ext_armv6_aligned: | ||||
| 	WORD      $0xe3120008                             // TST R2, #8 not working see issue 5921 | ||||
| 	BEQ       poly1305_finish_ext_armv6_skip8_aligned | ||||
| 	MOVM.IA.W (R1), [g-R11] | ||||
| 	MOVM.IA.W [g-R11], (R9) | ||||
|  | ||||
| poly1305_finish_ext_armv6_skip8_aligned: | ||||
| 	WORD   $0xe3120004                             // TST $4, R2 not working see issue 5921 | ||||
| 	BEQ    poly1305_finish_ext_armv6_skip4_aligned | ||||
| 	MOVW.P 4(R1), g | ||||
| 	MOVW.P g, 4(R9) | ||||
|  | ||||
| poly1305_finish_ext_armv6_skip4_aligned: | ||||
| 	WORD    $0xe3120002                     // TST $2, R2 not working see issue 5921 | ||||
| 	BEQ     poly1305_finish_ext_armv6_skip2 | ||||
| 	MOVHU.P 2(R1), g | ||||
| 	MOVH.P  g, 2(R9) | ||||
|  | ||||
| poly1305_finish_ext_armv6_skip2: | ||||
| 	WORD    $0xe3120001                     // TST $1, R2 not working see issue 5921 | ||||
| 	BEQ     poly1305_finish_ext_armv6_skip1 | ||||
| 	MOVBU.P 1(R1), g | ||||
| 	MOVBU.P g, 1(R9) | ||||
|  | ||||
| poly1305_finish_ext_armv6_skip1: | ||||
| 	MOVW  $1, R11 | ||||
| 	MOVBU R11, 0(R9) | ||||
| 	MOVW  R11, 56(R5) | ||||
| 	MOVW  R5, R0 | ||||
| 	ADD   $8, R13, R1 | ||||
| 	MOVW  $16, R2 | ||||
| 	BL    poly1305_blocks_armv6<>(SB) | ||||
|  | ||||
| poly1305_finish_ext_armv6_noremaining: | ||||
| 	MOVW      20(R5), R0 | ||||
| 	MOVW      24(R5), R1 | ||||
| 	MOVW      28(R5), R2 | ||||
| 	MOVW      32(R5), R3 | ||||
| 	MOVW      36(R5), R4 | ||||
| 	MOVW      R4>>26, R12 | ||||
| 	BIC       $0xfc000000, R4, R4 | ||||
| 	ADD       R12<<2, R12, R12 | ||||
| 	ADD       R12, R0, R0 | ||||
| 	MOVW      R0>>26, R12 | ||||
| 	BIC       $0xfc000000, R0, R0 | ||||
| 	ADD       R12, R1, R1 | ||||
| 	MOVW      R1>>26, R12 | ||||
| 	BIC       $0xfc000000, R1, R1 | ||||
| 	ADD       R12, R2, R2 | ||||
| 	MOVW      R2>>26, R12 | ||||
| 	BIC       $0xfc000000, R2, R2 | ||||
| 	ADD       R12, R3, R3 | ||||
| 	MOVW      R3>>26, R12 | ||||
| 	BIC       $0xfc000000, R3, R3 | ||||
| 	ADD       R12, R4, R4 | ||||
| 	ADD       $5, R0, R6 | ||||
| 	MOVW      R6>>26, R12 | ||||
| 	BIC       $0xfc000000, R6, R6 | ||||
| 	ADD       R12, R1, R7 | ||||
| 	MOVW      R7>>26, R12 | ||||
| 	BIC       $0xfc000000, R7, R7 | ||||
| 	ADD       R12, R2, g | ||||
| 	MOVW      g>>26, R12 | ||||
| 	BIC       $0xfc000000, g, g | ||||
| 	ADD       R12, R3, R11 | ||||
| 	MOVW      $-(1<<26), R12 | ||||
| 	ADD       R11>>26, R12, R12 | ||||
| 	BIC       $0xfc000000, R11, R11 | ||||
| 	ADD       R12, R4, R9 | ||||
| 	MOVW      R9>>31, R12 | ||||
| 	SUB       $1, R12 | ||||
| 	AND       R12, R6, R6 | ||||
| 	AND       R12, R7, R7 | ||||
| 	AND       R12, g, g | ||||
| 	AND       R12, R11, R11 | ||||
| 	AND       R12, R9, R9 | ||||
| 	MVN       R12, R12 | ||||
| 	AND       R12, R0, R0 | ||||
| 	AND       R12, R1, R1 | ||||
| 	AND       R12, R2, R2 | ||||
| 	AND       R12, R3, R3 | ||||
| 	AND       R12, R4, R4 | ||||
| 	ORR       R6, R0, R0 | ||||
| 	ORR       R7, R1, R1 | ||||
| 	ORR       g, R2, R2 | ||||
| 	ORR       R11, R3, R3 | ||||
| 	ORR       R9, R4, R4 | ||||
| 	ORR       R1<<26, R0, R0 | ||||
| 	MOVW      R1>>6, R1 | ||||
| 	ORR       R2<<20, R1, R1 | ||||
| 	MOVW      R2>>12, R2 | ||||
| 	ORR       R3<<14, R2, R2 | ||||
| 	MOVW      R3>>18, R3 | ||||
| 	ORR       R4<<8, R3, R3 | ||||
| 	MOVW      40(R5), R6 | ||||
| 	MOVW      44(R5), R7 | ||||
| 	MOVW      48(R5), g | ||||
| 	MOVW      52(R5), R11 | ||||
| 	ADD.S     R6, R0, R0 | ||||
| 	ADC.S     R7, R1, R1 | ||||
| 	ADC.S     g, R2, R2 | ||||
| 	ADC.S     R11, R3, R3 | ||||
| 	MOVM.IA   [R0-R3], (R8) | ||||
| 	MOVW      R5, R12 | ||||
| 	EOR       R0, R0, R0 | ||||
| 	EOR       R1, R1, R1 | ||||
| 	EOR       R2, R2, R2 | ||||
| 	EOR       R3, R3, R3 | ||||
| 	EOR       R4, R4, R4 | ||||
| 	EOR       R5, R5, R5 | ||||
| 	EOR       R6, R6, R6 | ||||
| 	EOR       R7, R7, R7 | ||||
| 	MOVM.IA.W [R0-R7], (R12) | ||||
| 	MOVM.IA   [R0-R7], (R12) | ||||
| 	MOVW      4(R13), g | ||||
| 	RET | ||||
							
								
								
									
										14
									
								
								vendor/golang.org/x/crypto/poly1305/sum_noasm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								vendor/golang.org/x/crypto/poly1305/sum_noasm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| // Copyright 2018 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. | ||||
|  | ||||
| // +build s390x,!go1.11 !arm,!amd64,!s390x gccgo appengine nacl | ||||
|  | ||||
| package poly1305 | ||||
|  | ||||
| // Sum generates an authenticator for msg using a one-time key and puts the | ||||
| // 16-byte result into out. Authenticating two different messages with the same | ||||
| // key allows an attacker to forge messages at will. | ||||
| func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) { | ||||
| 	sumGeneric(out, msg, key) | ||||
| } | ||||
							
								
								
									
										139
									
								
								vendor/golang.org/x/crypto/poly1305/sum_ref.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								vendor/golang.org/x/crypto/poly1305/sum_ref.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | ||||
| // Copyright 2012 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 poly1305 | ||||
|  | ||||
| import "encoding/binary" | ||||
|  | ||||
| // sumGeneric generates an authenticator for msg using a one-time key and | ||||
| // puts the 16-byte result into out. This is the generic implementation of | ||||
| // Sum and should be called if no assembly implementation is available. | ||||
| func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { | ||||
| 	var ( | ||||
| 		h0, h1, h2, h3, h4 uint32 // the hash accumulators | ||||
| 		r0, r1, r2, r3, r4 uint64 // the r part of the key | ||||
| 	) | ||||
|  | ||||
| 	r0 = uint64(binary.LittleEndian.Uint32(key[0:]) & 0x3ffffff) | ||||
| 	r1 = uint64((binary.LittleEndian.Uint32(key[3:]) >> 2) & 0x3ffff03) | ||||
| 	r2 = uint64((binary.LittleEndian.Uint32(key[6:]) >> 4) & 0x3ffc0ff) | ||||
| 	r3 = uint64((binary.LittleEndian.Uint32(key[9:]) >> 6) & 0x3f03fff) | ||||
| 	r4 = uint64((binary.LittleEndian.Uint32(key[12:]) >> 8) & 0x00fffff) | ||||
|  | ||||
| 	R1, R2, R3, R4 := r1*5, r2*5, r3*5, r4*5 | ||||
|  | ||||
| 	for len(msg) >= TagSize { | ||||
| 		// h += msg | ||||
| 		h0 += binary.LittleEndian.Uint32(msg[0:]) & 0x3ffffff | ||||
| 		h1 += (binary.LittleEndian.Uint32(msg[3:]) >> 2) & 0x3ffffff | ||||
| 		h2 += (binary.LittleEndian.Uint32(msg[6:]) >> 4) & 0x3ffffff | ||||
| 		h3 += (binary.LittleEndian.Uint32(msg[9:]) >> 6) & 0x3ffffff | ||||
| 		h4 += (binary.LittleEndian.Uint32(msg[12:]) >> 8) | (1 << 24) | ||||
|  | ||||
| 		// h *= r | ||||
| 		d0 := (uint64(h0) * r0) + (uint64(h1) * R4) + (uint64(h2) * R3) + (uint64(h3) * R2) + (uint64(h4) * R1) | ||||
| 		d1 := (d0 >> 26) + (uint64(h0) * r1) + (uint64(h1) * r0) + (uint64(h2) * R4) + (uint64(h3) * R3) + (uint64(h4) * R2) | ||||
| 		d2 := (d1 >> 26) + (uint64(h0) * r2) + (uint64(h1) * r1) + (uint64(h2) * r0) + (uint64(h3) * R4) + (uint64(h4) * R3) | ||||
| 		d3 := (d2 >> 26) + (uint64(h0) * r3) + (uint64(h1) * r2) + (uint64(h2) * r1) + (uint64(h3) * r0) + (uint64(h4) * R4) | ||||
| 		d4 := (d3 >> 26) + (uint64(h0) * r4) + (uint64(h1) * r3) + (uint64(h2) * r2) + (uint64(h3) * r1) + (uint64(h4) * r0) | ||||
|  | ||||
| 		// h %= p | ||||
| 		h0 = uint32(d0) & 0x3ffffff | ||||
| 		h1 = uint32(d1) & 0x3ffffff | ||||
| 		h2 = uint32(d2) & 0x3ffffff | ||||
| 		h3 = uint32(d3) & 0x3ffffff | ||||
| 		h4 = uint32(d4) & 0x3ffffff | ||||
|  | ||||
| 		h0 += uint32(d4>>26) * 5 | ||||
| 		h1 += h0 >> 26 | ||||
| 		h0 = h0 & 0x3ffffff | ||||
|  | ||||
| 		msg = msg[TagSize:] | ||||
| 	} | ||||
|  | ||||
| 	if len(msg) > 0 { | ||||
| 		var block [TagSize]byte | ||||
| 		off := copy(block[:], msg) | ||||
| 		block[off] = 0x01 | ||||
|  | ||||
| 		// h += msg | ||||
| 		h0 += binary.LittleEndian.Uint32(block[0:]) & 0x3ffffff | ||||
| 		h1 += (binary.LittleEndian.Uint32(block[3:]) >> 2) & 0x3ffffff | ||||
| 		h2 += (binary.LittleEndian.Uint32(block[6:]) >> 4) & 0x3ffffff | ||||
| 		h3 += (binary.LittleEndian.Uint32(block[9:]) >> 6) & 0x3ffffff | ||||
| 		h4 += (binary.LittleEndian.Uint32(block[12:]) >> 8) | ||||
|  | ||||
| 		// h *= r | ||||
| 		d0 := (uint64(h0) * r0) + (uint64(h1) * R4) + (uint64(h2) * R3) + (uint64(h3) * R2) + (uint64(h4) * R1) | ||||
| 		d1 := (d0 >> 26) + (uint64(h0) * r1) + (uint64(h1) * r0) + (uint64(h2) * R4) + (uint64(h3) * R3) + (uint64(h4) * R2) | ||||
| 		d2 := (d1 >> 26) + (uint64(h0) * r2) + (uint64(h1) * r1) + (uint64(h2) * r0) + (uint64(h3) * R4) + (uint64(h4) * R3) | ||||
| 		d3 := (d2 >> 26) + (uint64(h0) * r3) + (uint64(h1) * r2) + (uint64(h2) * r1) + (uint64(h3) * r0) + (uint64(h4) * R4) | ||||
| 		d4 := (d3 >> 26) + (uint64(h0) * r4) + (uint64(h1) * r3) + (uint64(h2) * r2) + (uint64(h3) * r1) + (uint64(h4) * r0) | ||||
|  | ||||
| 		// h %= p | ||||
| 		h0 = uint32(d0) & 0x3ffffff | ||||
| 		h1 = uint32(d1) & 0x3ffffff | ||||
| 		h2 = uint32(d2) & 0x3ffffff | ||||
| 		h3 = uint32(d3) & 0x3ffffff | ||||
| 		h4 = uint32(d4) & 0x3ffffff | ||||
|  | ||||
| 		h0 += uint32(d4>>26) * 5 | ||||
| 		h1 += h0 >> 26 | ||||
| 		h0 = h0 & 0x3ffffff | ||||
| 	} | ||||
|  | ||||
| 	// h %= p reduction | ||||
| 	h2 += h1 >> 26 | ||||
| 	h1 &= 0x3ffffff | ||||
| 	h3 += h2 >> 26 | ||||
| 	h2 &= 0x3ffffff | ||||
| 	h4 += h3 >> 26 | ||||
| 	h3 &= 0x3ffffff | ||||
| 	h0 += 5 * (h4 >> 26) | ||||
| 	h4 &= 0x3ffffff | ||||
| 	h1 += h0 >> 26 | ||||
| 	h0 &= 0x3ffffff | ||||
|  | ||||
| 	// h - p | ||||
| 	t0 := h0 + 5 | ||||
| 	t1 := h1 + (t0 >> 26) | ||||
| 	t2 := h2 + (t1 >> 26) | ||||
| 	t3 := h3 + (t2 >> 26) | ||||
| 	t4 := h4 + (t3 >> 26) - (1 << 26) | ||||
| 	t0 &= 0x3ffffff | ||||
| 	t1 &= 0x3ffffff | ||||
| 	t2 &= 0x3ffffff | ||||
| 	t3 &= 0x3ffffff | ||||
|  | ||||
| 	// select h if h < p else h - p | ||||
| 	t_mask := (t4 >> 31) - 1 | ||||
| 	h_mask := ^t_mask | ||||
| 	h0 = (h0 & h_mask) | (t0 & t_mask) | ||||
| 	h1 = (h1 & h_mask) | (t1 & t_mask) | ||||
| 	h2 = (h2 & h_mask) | (t2 & t_mask) | ||||
| 	h3 = (h3 & h_mask) | (t3 & t_mask) | ||||
| 	h4 = (h4 & h_mask) | (t4 & t_mask) | ||||
|  | ||||
| 	// h %= 2^128 | ||||
| 	h0 |= h1 << 26 | ||||
| 	h1 = ((h1 >> 6) | (h2 << 20)) | ||||
| 	h2 = ((h2 >> 12) | (h3 << 14)) | ||||
| 	h3 = ((h3 >> 18) | (h4 << 8)) | ||||
|  | ||||
| 	// s: the s part of the key | ||||
| 	// tag = (h + s) % (2^128) | ||||
| 	t := uint64(h0) + uint64(binary.LittleEndian.Uint32(key[16:])) | ||||
| 	h0 = uint32(t) | ||||
| 	t = uint64(h1) + uint64(binary.LittleEndian.Uint32(key[20:])) + (t >> 32) | ||||
| 	h1 = uint32(t) | ||||
| 	t = uint64(h2) + uint64(binary.LittleEndian.Uint32(key[24:])) + (t >> 32) | ||||
| 	h2 = uint32(t) | ||||
| 	t = uint64(h3) + uint64(binary.LittleEndian.Uint32(key[28:])) + (t >> 32) | ||||
| 	h3 = uint32(t) | ||||
|  | ||||
| 	binary.LittleEndian.PutUint32(out[0:], h0) | ||||
| 	binary.LittleEndian.PutUint32(out[4:], h1) | ||||
| 	binary.LittleEndian.PutUint32(out[8:], h2) | ||||
| 	binary.LittleEndian.PutUint32(out[12:], h3) | ||||
| } | ||||
							
								
								
									
										49
									
								
								vendor/golang.org/x/crypto/poly1305/sum_s390x.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								vendor/golang.org/x/crypto/poly1305/sum_s390x.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| // Copyright 2018 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. | ||||
|  | ||||
| // +build s390x,go1.11,!gccgo,!appengine | ||||
|  | ||||
| package poly1305 | ||||
|  | ||||
| // hasVectorFacility reports whether the machine supports | ||||
| // the vector facility (vx). | ||||
| func hasVectorFacility() bool | ||||
|  | ||||
| // hasVMSLFacility reports whether the machine supports | ||||
| // Vector Multiply Sum Logical (VMSL). | ||||
| func hasVMSLFacility() bool | ||||
|  | ||||
| var hasVX = hasVectorFacility() | ||||
| var hasVMSL = hasVMSLFacility() | ||||
|  | ||||
| // poly1305vx is an assembly implementation of Poly1305 that uses vector | ||||
| // instructions. It must only be called if the vector facility (vx) is | ||||
| // available. | ||||
| //go:noescape | ||||
| func poly1305vx(out *[16]byte, m *byte, mlen uint64, key *[32]byte) | ||||
|  | ||||
| // poly1305vmsl is an assembly implementation of Poly1305 that uses vector | ||||
| // instructions, including VMSL. It must only be called if the vector facility (vx) is | ||||
| // available and if VMSL is supported. | ||||
| //go:noescape | ||||
| func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]byte) | ||||
|  | ||||
| // Sum generates an authenticator for m using a one-time key and puts the | ||||
| // 16-byte result into out. Authenticating two different messages with the same | ||||
| // key allows an attacker to forge messages at will. | ||||
| func Sum(out *[16]byte, m []byte, key *[32]byte) { | ||||
| 	if hasVX { | ||||
| 		var mPtr *byte | ||||
| 		if len(m) > 0 { | ||||
| 			mPtr = &m[0] | ||||
| 		} | ||||
| 		if hasVMSL && len(m) > 256 { | ||||
| 			poly1305vmsl(out, mPtr, uint64(len(m)), key) | ||||
| 		} else { | ||||
| 			poly1305vx(out, mPtr, uint64(len(m)), key) | ||||
| 		} | ||||
| 	} else { | ||||
| 		sumGeneric(out, m, key) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										400
									
								
								vendor/golang.org/x/crypto/poly1305/sum_s390x.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										400
									
								
								vendor/golang.org/x/crypto/poly1305/sum_s390x.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,400 @@ | ||||
| // Copyright 2018 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. | ||||
|  | ||||
| // +build s390x,go1.11,!gccgo,!appengine | ||||
|  | ||||
| #include "textflag.h" | ||||
|  | ||||
| // Implementation of Poly1305 using the vector facility (vx). | ||||
|  | ||||
| // constants | ||||
| #define MOD26 V0 | ||||
| #define EX0   V1 | ||||
| #define EX1   V2 | ||||
| #define EX2   V3 | ||||
|  | ||||
| // temporaries | ||||
| #define T_0 V4 | ||||
| #define T_1 V5 | ||||
| #define T_2 V6 | ||||
| #define T_3 V7 | ||||
| #define T_4 V8 | ||||
|  | ||||
| // key (r) | ||||
| #define R_0  V9 | ||||
| #define R_1  V10 | ||||
| #define R_2  V11 | ||||
| #define R_3  V12 | ||||
| #define R_4  V13 | ||||
| #define R5_1 V14 | ||||
| #define R5_2 V15 | ||||
| #define R5_3 V16 | ||||
| #define R5_4 V17 | ||||
| #define RSAVE_0 R5 | ||||
| #define RSAVE_1 R6 | ||||
| #define RSAVE_2 R7 | ||||
| #define RSAVE_3 R8 | ||||
| #define RSAVE_4 R9 | ||||
| #define R5SAVE_1 V28 | ||||
| #define R5SAVE_2 V29 | ||||
| #define R5SAVE_3 V30 | ||||
| #define R5SAVE_4 V31 | ||||
|  | ||||
| // message block | ||||
| #define F_0 V18 | ||||
| #define F_1 V19 | ||||
| #define F_2 V20 | ||||
| #define F_3 V21 | ||||
| #define F_4 V22 | ||||
|  | ||||
| // accumulator | ||||
| #define H_0 V23 | ||||
| #define H_1 V24 | ||||
| #define H_2 V25 | ||||
| #define H_3 V26 | ||||
| #define H_4 V27 | ||||
|  | ||||
| GLOBL ·keyMask<>(SB), RODATA, $16 | ||||
| DATA ·keyMask<>+0(SB)/8, $0xffffff0ffcffff0f | ||||
| DATA ·keyMask<>+8(SB)/8, $0xfcffff0ffcffff0f | ||||
|  | ||||
| GLOBL ·bswapMask<>(SB), RODATA, $16 | ||||
| DATA ·bswapMask<>+0(SB)/8, $0x0f0e0d0c0b0a0908 | ||||
| DATA ·bswapMask<>+8(SB)/8, $0x0706050403020100 | ||||
|  | ||||
| GLOBL ·constants<>(SB), RODATA, $64 | ||||
| // MOD26 | ||||
| DATA ·constants<>+0(SB)/8, $0x3ffffff | ||||
| DATA ·constants<>+8(SB)/8, $0x3ffffff | ||||
| // EX0 | ||||
| DATA ·constants<>+16(SB)/8, $0x0006050403020100 | ||||
| DATA ·constants<>+24(SB)/8, $0x1016151413121110 | ||||
| // EX1 | ||||
| DATA ·constants<>+32(SB)/8, $0x060c0b0a09080706 | ||||
| DATA ·constants<>+40(SB)/8, $0x161c1b1a19181716 | ||||
| // EX2 | ||||
| DATA ·constants<>+48(SB)/8, $0x0d0d0d0d0d0f0e0d | ||||
| DATA ·constants<>+56(SB)/8, $0x1d1d1d1d1d1f1e1d | ||||
|  | ||||
| // h = (f*g) % (2**130-5) [partial reduction] | ||||
| #define MULTIPLY(f0, f1, f2, f3, f4, g0, g1, g2, g3, g4, g51, g52, g53, g54, h0, h1, h2, h3, h4) \ | ||||
| 	VMLOF  f0, g0, h0        \ | ||||
| 	VMLOF  f0, g1, h1        \ | ||||
| 	VMLOF  f0, g2, h2        \ | ||||
| 	VMLOF  f0, g3, h3        \ | ||||
| 	VMLOF  f0, g4, h4        \ | ||||
| 	VMLOF  f1, g54, T_0      \ | ||||
| 	VMLOF  f1, g0, T_1       \ | ||||
| 	VMLOF  f1, g1, T_2       \ | ||||
| 	VMLOF  f1, g2, T_3       \ | ||||
| 	VMLOF  f1, g3, T_4       \ | ||||
| 	VMALOF f2, g53, h0, h0   \ | ||||
| 	VMALOF f2, g54, h1, h1   \ | ||||
| 	VMALOF f2, g0, h2, h2    \ | ||||
| 	VMALOF f2, g1, h3, h3    \ | ||||
| 	VMALOF f2, g2, h4, h4    \ | ||||
| 	VMALOF f3, g52, T_0, T_0 \ | ||||
| 	VMALOF f3, g53, T_1, T_1 \ | ||||
| 	VMALOF f3, g54, T_2, T_2 \ | ||||
| 	VMALOF f3, g0, T_3, T_3  \ | ||||
| 	VMALOF f3, g1, T_4, T_4  \ | ||||
| 	VMALOF f4, g51, h0, h0   \ | ||||
| 	VMALOF f4, g52, h1, h1   \ | ||||
| 	VMALOF f4, g53, h2, h2   \ | ||||
| 	VMALOF f4, g54, h3, h3   \ | ||||
| 	VMALOF f4, g0, h4, h4    \ | ||||
| 	VAG    T_0, h0, h0       \ | ||||
| 	VAG    T_1, h1, h1       \ | ||||
| 	VAG    T_2, h2, h2       \ | ||||
| 	VAG    T_3, h3, h3       \ | ||||
| 	VAG    T_4, h4, h4 | ||||
|  | ||||
| // carry h0->h1 h3->h4, h1->h2 h4->h0, h0->h1 h2->h3, h3->h4 | ||||
| #define REDUCE(h0, h1, h2, h3, h4) \ | ||||
| 	VESRLG $26, h0, T_0  \ | ||||
| 	VESRLG $26, h3, T_1  \ | ||||
| 	VN     MOD26, h0, h0 \ | ||||
| 	VN     MOD26, h3, h3 \ | ||||
| 	VAG    T_0, h1, h1   \ | ||||
| 	VAG    T_1, h4, h4   \ | ||||
| 	VESRLG $26, h1, T_2  \ | ||||
| 	VESRLG $26, h4, T_3  \ | ||||
| 	VN     MOD26, h1, h1 \ | ||||
| 	VN     MOD26, h4, h4 \ | ||||
| 	VESLG  $2, T_3, T_4  \ | ||||
| 	VAG    T_3, T_4, T_4 \ | ||||
| 	VAG    T_2, h2, h2   \ | ||||
| 	VAG    T_4, h0, h0   \ | ||||
| 	VESRLG $26, h2, T_0  \ | ||||
| 	VESRLG $26, h0, T_1  \ | ||||
| 	VN     MOD26, h2, h2 \ | ||||
| 	VN     MOD26, h0, h0 \ | ||||
| 	VAG    T_0, h3, h3   \ | ||||
| 	VAG    T_1, h1, h1   \ | ||||
| 	VESRLG $26, h3, T_2  \ | ||||
| 	VN     MOD26, h3, h3 \ | ||||
| 	VAG    T_2, h4, h4 | ||||
|  | ||||
| // expand in0 into d[0] and in1 into d[1] | ||||
| #define EXPAND(in0, in1, d0, d1, d2, d3, d4) \ | ||||
| 	VGBM   $0x0707, d1       \ // d1=tmp | ||||
| 	VPERM  in0, in1, EX2, d4 \ | ||||
| 	VPERM  in0, in1, EX0, d0 \ | ||||
| 	VPERM  in0, in1, EX1, d2 \ | ||||
| 	VN     d1, d4, d4        \ | ||||
| 	VESRLG $26, d0, d1       \ | ||||
| 	VESRLG $30, d2, d3       \ | ||||
| 	VESRLG $4, d2, d2        \ | ||||
| 	VN     MOD26, d0, d0     \ | ||||
| 	VN     MOD26, d1, d1     \ | ||||
| 	VN     MOD26, d2, d2     \ | ||||
| 	VN     MOD26, d3, d3 | ||||
|  | ||||
| // pack h4:h0 into h1:h0 (no carry) | ||||
| #define PACK(h0, h1, h2, h3, h4) \ | ||||
| 	VESLG $26, h1, h1  \ | ||||
| 	VESLG $26, h3, h3  \ | ||||
| 	VO    h0, h1, h0   \ | ||||
| 	VO    h2, h3, h2   \ | ||||
| 	VESLG $4, h2, h2   \ | ||||
| 	VLEIB $7, $48, h1  \ | ||||
| 	VSLB  h1, h2, h2   \ | ||||
| 	VO    h0, h2, h0   \ | ||||
| 	VLEIB $7, $104, h1 \ | ||||
| 	VSLB  h1, h4, h3   \ | ||||
| 	VO    h3, h0, h0   \ | ||||
| 	VLEIB $7, $24, h1  \ | ||||
| 	VSRLB h1, h4, h1 | ||||
|  | ||||
| // if h > 2**130-5 then h -= 2**130-5 | ||||
| #define MOD(h0, h1, t0, t1, t2) \ | ||||
| 	VZERO t0          \ | ||||
| 	VLEIG $1, $5, t0  \ | ||||
| 	VACCQ h0, t0, t1  \ | ||||
| 	VAQ   h0, t0, t0  \ | ||||
| 	VONE  t2          \ | ||||
| 	VLEIG $1, $-4, t2 \ | ||||
| 	VAQ   t2, t1, t1  \ | ||||
| 	VACCQ h1, t1, t1  \ | ||||
| 	VONE  t2          \ | ||||
| 	VAQ   t2, t1, t1  \ | ||||
| 	VN    h0, t1, t2  \ | ||||
| 	VNC   t0, t1, t1  \ | ||||
| 	VO    t1, t2, h0 | ||||
|  | ||||
| // func poly1305vx(out *[16]byte, m *byte, mlen uint64, key *[32]key) | ||||
| TEXT ·poly1305vx(SB), $0-32 | ||||
| 	// This code processes up to 2 blocks (32 bytes) per iteration | ||||
| 	// using the algorithm described in: | ||||
| 	// NEON crypto, Daniel J. Bernstein & Peter Schwabe | ||||
| 	// https://cryptojedi.org/papers/neoncrypto-20120320.pdf | ||||
| 	LMG out+0(FP), R1, R4 // R1=out, R2=m, R3=mlen, R4=key | ||||
|  | ||||
| 	// load MOD26, EX0, EX1 and EX2 | ||||
| 	MOVD $·constants<>(SB), R5 | ||||
| 	VLM  (R5), MOD26, EX2 | ||||
|  | ||||
| 	// setup r | ||||
| 	VL   (R4), T_0 | ||||
| 	MOVD $·keyMask<>(SB), R6 | ||||
| 	VL   (R6), T_1 | ||||
| 	VN   T_0, T_1, T_0 | ||||
| 	EXPAND(T_0, T_0, R_0, R_1, R_2, R_3, R_4) | ||||
|  | ||||
| 	// setup r*5 | ||||
| 	VLEIG $0, $5, T_0 | ||||
| 	VLEIG $1, $5, T_0 | ||||
|  | ||||
| 	// store r (for final block) | ||||
| 	VMLOF T_0, R_1, R5SAVE_1 | ||||
| 	VMLOF T_0, R_2, R5SAVE_2 | ||||
| 	VMLOF T_0, R_3, R5SAVE_3 | ||||
| 	VMLOF T_0, R_4, R5SAVE_4 | ||||
| 	VLGVG $0, R_0, RSAVE_0 | ||||
| 	VLGVG $0, R_1, RSAVE_1 | ||||
| 	VLGVG $0, R_2, RSAVE_2 | ||||
| 	VLGVG $0, R_3, RSAVE_3 | ||||
| 	VLGVG $0, R_4, RSAVE_4 | ||||
|  | ||||
| 	// skip r**2 calculation | ||||
| 	CMPBLE R3, $16, skip | ||||
|  | ||||
| 	// calculate r**2 | ||||
| 	MULTIPLY(R_0, R_1, R_2, R_3, R_4, R_0, R_1, R_2, R_3, R_4, R5SAVE_1, R5SAVE_2, R5SAVE_3, R5SAVE_4, H_0, H_1, H_2, H_3, H_4) | ||||
| 	REDUCE(H_0, H_1, H_2, H_3, H_4) | ||||
| 	VLEIG $0, $5, T_0 | ||||
| 	VLEIG $1, $5, T_0 | ||||
| 	VMLOF T_0, H_1, R5_1 | ||||
| 	VMLOF T_0, H_2, R5_2 | ||||
| 	VMLOF T_0, H_3, R5_3 | ||||
| 	VMLOF T_0, H_4, R5_4 | ||||
| 	VLR   H_0, R_0 | ||||
| 	VLR   H_1, R_1 | ||||
| 	VLR   H_2, R_2 | ||||
| 	VLR   H_3, R_3 | ||||
| 	VLR   H_4, R_4 | ||||
|  | ||||
| 	// initialize h | ||||
| 	VZERO H_0 | ||||
| 	VZERO H_1 | ||||
| 	VZERO H_2 | ||||
| 	VZERO H_3 | ||||
| 	VZERO H_4 | ||||
|  | ||||
| loop: | ||||
| 	CMPBLE R3, $32, b2 | ||||
| 	VLM    (R2), T_0, T_1 | ||||
| 	SUB    $32, R3 | ||||
| 	MOVD   $32(R2), R2 | ||||
| 	EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4) | ||||
| 	VLEIB  $4, $1, F_4 | ||||
| 	VLEIB  $12, $1, F_4 | ||||
|  | ||||
| multiply: | ||||
| 	VAG    H_0, F_0, F_0 | ||||
| 	VAG    H_1, F_1, F_1 | ||||
| 	VAG    H_2, F_2, F_2 | ||||
| 	VAG    H_3, F_3, F_3 | ||||
| 	VAG    H_4, F_4, F_4 | ||||
| 	MULTIPLY(F_0, F_1, F_2, F_3, F_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, H_0, H_1, H_2, H_3, H_4) | ||||
| 	REDUCE(H_0, H_1, H_2, H_3, H_4) | ||||
| 	CMPBNE R3, $0, loop | ||||
|  | ||||
| finish: | ||||
| 	// sum vectors | ||||
| 	VZERO  T_0 | ||||
| 	VSUMQG H_0, T_0, H_0 | ||||
| 	VSUMQG H_1, T_0, H_1 | ||||
| 	VSUMQG H_2, T_0, H_2 | ||||
| 	VSUMQG H_3, T_0, H_3 | ||||
| 	VSUMQG H_4, T_0, H_4 | ||||
|  | ||||
| 	// h may be >= 2*(2**130-5) so we need to reduce it again | ||||
| 	REDUCE(H_0, H_1, H_2, H_3, H_4) | ||||
|  | ||||
| 	// carry h1->h4 | ||||
| 	VESRLG $26, H_1, T_1 | ||||
| 	VN     MOD26, H_1, H_1 | ||||
| 	VAQ    T_1, H_2, H_2 | ||||
| 	VESRLG $26, H_2, T_2 | ||||
| 	VN     MOD26, H_2, H_2 | ||||
| 	VAQ    T_2, H_3, H_3 | ||||
| 	VESRLG $26, H_3, T_3 | ||||
| 	VN     MOD26, H_3, H_3 | ||||
| 	VAQ    T_3, H_4, H_4 | ||||
|  | ||||
| 	// h is now < 2*(2**130-5) | ||||
| 	// pack h into h1 (hi) and h0 (lo) | ||||
| 	PACK(H_0, H_1, H_2, H_3, H_4) | ||||
|  | ||||
| 	// if h > 2**130-5 then h -= 2**130-5 | ||||
| 	MOD(H_0, H_1, T_0, T_1, T_2) | ||||
|  | ||||
| 	// h += s | ||||
| 	MOVD  $·bswapMask<>(SB), R5 | ||||
| 	VL    (R5), T_1 | ||||
| 	VL    16(R4), T_0 | ||||
| 	VPERM T_0, T_0, T_1, T_0    // reverse bytes (to big) | ||||
| 	VAQ   T_0, H_0, H_0 | ||||
| 	VPERM H_0, H_0, T_1, H_0    // reverse bytes (to little) | ||||
| 	VST   H_0, (R1) | ||||
|  | ||||
| 	RET | ||||
|  | ||||
| b2: | ||||
| 	CMPBLE R3, $16, b1 | ||||
|  | ||||
| 	// 2 blocks remaining | ||||
| 	SUB    $17, R3 | ||||
| 	VL     (R2), T_0 | ||||
| 	VLL    R3, 16(R2), T_1 | ||||
| 	ADD    $1, R3 | ||||
| 	MOVBZ  $1, R0 | ||||
| 	CMPBEQ R3, $16, 2(PC) | ||||
| 	VLVGB  R3, R0, T_1 | ||||
| 	EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4) | ||||
| 	CMPBNE R3, $16, 2(PC) | ||||
| 	VLEIB  $12, $1, F_4 | ||||
| 	VLEIB  $4, $1, F_4 | ||||
|  | ||||
| 	// setup [r²,r] | ||||
| 	VLVGG $1, RSAVE_0, R_0 | ||||
| 	VLVGG $1, RSAVE_1, R_1 | ||||
| 	VLVGG $1, RSAVE_2, R_2 | ||||
| 	VLVGG $1, RSAVE_3, R_3 | ||||
| 	VLVGG $1, RSAVE_4, R_4 | ||||
| 	VPDI  $0, R5_1, R5SAVE_1, R5_1 | ||||
| 	VPDI  $0, R5_2, R5SAVE_2, R5_2 | ||||
| 	VPDI  $0, R5_3, R5SAVE_3, R5_3 | ||||
| 	VPDI  $0, R5_4, R5SAVE_4, R5_4 | ||||
|  | ||||
| 	MOVD $0, R3 | ||||
| 	BR   multiply | ||||
|  | ||||
| skip: | ||||
| 	VZERO H_0 | ||||
| 	VZERO H_1 | ||||
| 	VZERO H_2 | ||||
| 	VZERO H_3 | ||||
| 	VZERO H_4 | ||||
|  | ||||
| 	CMPBEQ R3, $0, finish | ||||
|  | ||||
| b1: | ||||
| 	// 1 block remaining | ||||
| 	SUB    $1, R3 | ||||
| 	VLL    R3, (R2), T_0 | ||||
| 	ADD    $1, R3 | ||||
| 	MOVBZ  $1, R0 | ||||
| 	CMPBEQ R3, $16, 2(PC) | ||||
| 	VLVGB  R3, R0, T_0 | ||||
| 	VZERO  T_1 | ||||
| 	EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4) | ||||
| 	CMPBNE R3, $16, 2(PC) | ||||
| 	VLEIB  $4, $1, F_4 | ||||
| 	VLEIG  $1, $1, R_0 | ||||
| 	VZERO  R_1 | ||||
| 	VZERO  R_2 | ||||
| 	VZERO  R_3 | ||||
| 	VZERO  R_4 | ||||
| 	VZERO  R5_1 | ||||
| 	VZERO  R5_2 | ||||
| 	VZERO  R5_3 | ||||
| 	VZERO  R5_4 | ||||
|  | ||||
| 	// setup [r, 1] | ||||
| 	VLVGG $0, RSAVE_0, R_0 | ||||
| 	VLVGG $0, RSAVE_1, R_1 | ||||
| 	VLVGG $0, RSAVE_2, R_2 | ||||
| 	VLVGG $0, RSAVE_3, R_3 | ||||
| 	VLVGG $0, RSAVE_4, R_4 | ||||
| 	VPDI  $0, R5SAVE_1, R5_1, R5_1 | ||||
| 	VPDI  $0, R5SAVE_2, R5_2, R5_2 | ||||
| 	VPDI  $0, R5SAVE_3, R5_3, R5_3 | ||||
| 	VPDI  $0, R5SAVE_4, R5_4, R5_4 | ||||
|  | ||||
| 	MOVD $0, R3 | ||||
| 	BR   multiply | ||||
|  | ||||
| TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1 | ||||
| 	MOVD  $x-24(SP), R1 | ||||
| 	XC    $24, 0(R1), 0(R1) // clear the storage | ||||
| 	MOVD  $2, R0            // R0 is the number of double words stored -1 | ||||
| 	WORD  $0xB2B01000       // STFLE 0(R1) | ||||
| 	XOR   R0, R0            // reset the value of R0 | ||||
| 	MOVBZ z-8(SP), R1 | ||||
| 	AND   $0x40, R1 | ||||
| 	BEQ   novector | ||||
|  | ||||
| vectorinstalled: | ||||
| 	// check if the vector instruction has been enabled | ||||
| 	VLEIB  $0, $0xF, V16 | ||||
| 	VLGVB  $0, V16, R1 | ||||
| 	CMPBNE R1, $0xF, novector | ||||
| 	MOVB   $1, ret+0(FP)      // have vx | ||||
| 	RET | ||||
|  | ||||
| novector: | ||||
| 	MOVB $0, ret+0(FP) // no vx | ||||
| 	RET | ||||
							
								
								
									
										931
									
								
								vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										931
									
								
								vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,931 @@ | ||||
| // Copyright 2018 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. | ||||
|  | ||||
| // +build s390x,go1.11,!gccgo,!appengine | ||||
|  | ||||
| #include "textflag.h" | ||||
|  | ||||
| // Implementation of Poly1305 using the vector facility (vx) and the VMSL instruction. | ||||
|  | ||||
| // constants | ||||
| #define EX0   V1 | ||||
| #define EX1   V2 | ||||
| #define EX2   V3 | ||||
|  | ||||
| // temporaries | ||||
| #define T_0 V4 | ||||
| #define T_1 V5 | ||||
| #define T_2 V6 | ||||
| #define T_3 V7 | ||||
| #define T_4 V8 | ||||
| #define T_5 V9 | ||||
| #define T_6 V10 | ||||
| #define T_7 V11 | ||||
| #define T_8 V12 | ||||
| #define T_9 V13 | ||||
| #define T_10 V14 | ||||
|  | ||||
| // r**2 & r**4 | ||||
| #define R_0  V15 | ||||
| #define R_1  V16 | ||||
| #define R_2  V17 | ||||
| #define R5_1 V18 | ||||
| #define R5_2 V19 | ||||
| // key (r) | ||||
| #define RSAVE_0 R7 | ||||
| #define RSAVE_1 R8 | ||||
| #define RSAVE_2 R9 | ||||
| #define R5SAVE_1 R10 | ||||
| #define R5SAVE_2 R11 | ||||
|  | ||||
| // message block | ||||
| #define M0 V20 | ||||
| #define M1 V21 | ||||
| #define M2 V22 | ||||
| #define M3 V23 | ||||
| #define M4 V24 | ||||
| #define M5 V25 | ||||
|  | ||||
| // accumulator | ||||
| #define H0_0 V26 | ||||
| #define H1_0 V27 | ||||
| #define H2_0 V28 | ||||
| #define H0_1 V29 | ||||
| #define H1_1 V30 | ||||
| #define H2_1 V31 | ||||
|  | ||||
| GLOBL ·keyMask<>(SB), RODATA, $16 | ||||
| DATA ·keyMask<>+0(SB)/8, $0xffffff0ffcffff0f | ||||
| DATA ·keyMask<>+8(SB)/8, $0xfcffff0ffcffff0f | ||||
|  | ||||
| GLOBL ·bswapMask<>(SB), RODATA, $16 | ||||
| DATA ·bswapMask<>+0(SB)/8, $0x0f0e0d0c0b0a0908 | ||||
| DATA ·bswapMask<>+8(SB)/8, $0x0706050403020100 | ||||
|  | ||||
| GLOBL ·constants<>(SB), RODATA, $48 | ||||
| // EX0 | ||||
| DATA ·constants<>+0(SB)/8, $0x18191a1b1c1d1e1f | ||||
| DATA ·constants<>+8(SB)/8, $0x0000050403020100 | ||||
| // EX1 | ||||
| DATA ·constants<>+16(SB)/8, $0x18191a1b1c1d1e1f | ||||
| DATA ·constants<>+24(SB)/8, $0x00000a0908070605 | ||||
| // EX2 | ||||
| DATA ·constants<>+32(SB)/8, $0x18191a1b1c1d1e1f | ||||
| DATA ·constants<>+40(SB)/8, $0x0000000f0e0d0c0b | ||||
|  | ||||
| GLOBL ·c<>(SB), RODATA, $48 | ||||
| // EX0 | ||||
| DATA ·c<>+0(SB)/8, $0x0000050403020100 | ||||
| DATA ·c<>+8(SB)/8, $0x0000151413121110 | ||||
| // EX1 | ||||
| DATA ·c<>+16(SB)/8, $0x00000a0908070605 | ||||
| DATA ·c<>+24(SB)/8, $0x00001a1918171615 | ||||
| // EX2 | ||||
| DATA ·c<>+32(SB)/8, $0x0000000f0e0d0c0b | ||||
| DATA ·c<>+40(SB)/8, $0x0000001f1e1d1c1b | ||||
|  | ||||
| GLOBL ·reduce<>(SB), RODATA, $32 | ||||
| // 44 bit | ||||
| DATA ·reduce<>+0(SB)/8, $0x0 | ||||
| DATA ·reduce<>+8(SB)/8, $0xfffffffffff | ||||
| // 42 bit | ||||
| DATA ·reduce<>+16(SB)/8, $0x0 | ||||
| DATA ·reduce<>+24(SB)/8, $0x3ffffffffff | ||||
|  | ||||
| // h = (f*g) % (2**130-5) [partial reduction] | ||||
| // uses T_0...T_9 temporary registers | ||||
| // input: m02_0, m02_1, m02_2, m13_0, m13_1, m13_2, r_0, r_1, r_2, r5_1, r5_2, m4_0, m4_1, m4_2, m5_0, m5_1, m5_2 | ||||
| // temp: t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 | ||||
| // output: m02_0, m02_1, m02_2, m13_0, m13_1, m13_2 | ||||
| #define MULTIPLY(m02_0, m02_1, m02_2, m13_0, m13_1, m13_2, r_0, r_1, r_2, r5_1, r5_2, m4_0, m4_1, m4_2, m5_0, m5_1, m5_2, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9) \ | ||||
| 	\ // Eliminate the dependency for the last 2 VMSLs | ||||
| 	VMSLG m02_0, r_2, m4_2, m4_2                       \ | ||||
| 	VMSLG m13_0, r_2, m5_2, m5_2                       \ // 8 VMSLs pipelined | ||||
| 	VMSLG m02_0, r_0, m4_0, m4_0                       \ | ||||
| 	VMSLG m02_1, r5_2, V0, T_0                         \ | ||||
| 	VMSLG m02_0, r_1, m4_1, m4_1                       \ | ||||
| 	VMSLG m02_1, r_0, V0, T_1                          \ | ||||
| 	VMSLG m02_1, r_1, V0, T_2                          \ | ||||
| 	VMSLG m02_2, r5_1, V0, T_3                         \ | ||||
| 	VMSLG m02_2, r5_2, V0, T_4                         \ | ||||
| 	VMSLG m13_0, r_0, m5_0, m5_0                       \ | ||||
| 	VMSLG m13_1, r5_2, V0, T_5                         \ | ||||
| 	VMSLG m13_0, r_1, m5_1, m5_1                       \ | ||||
| 	VMSLG m13_1, r_0, V0, T_6                          \ | ||||
| 	VMSLG m13_1, r_1, V0, T_7                          \ | ||||
| 	VMSLG m13_2, r5_1, V0, T_8                         \ | ||||
| 	VMSLG m13_2, r5_2, V0, T_9                         \ | ||||
| 	VMSLG m02_2, r_0, m4_2, m4_2                       \ | ||||
| 	VMSLG m13_2, r_0, m5_2, m5_2                       \ | ||||
| 	VAQ   m4_0, T_0, m02_0                             \ | ||||
| 	VAQ   m4_1, T_1, m02_1                             \ | ||||
| 	VAQ   m5_0, T_5, m13_0                             \ | ||||
| 	VAQ   m5_1, T_6, m13_1                             \ | ||||
| 	VAQ   m02_0, T_3, m02_0                            \ | ||||
| 	VAQ   m02_1, T_4, m02_1                            \ | ||||
| 	VAQ   m13_0, T_8, m13_0                            \ | ||||
| 	VAQ   m13_1, T_9, m13_1                            \ | ||||
| 	VAQ   m4_2, T_2, m02_2                             \ | ||||
| 	VAQ   m5_2, T_7, m13_2                             \ | ||||
|  | ||||
| // SQUARE uses three limbs of r and r_2*5 to output square of r | ||||
| // uses T_1, T_5 and T_7 temporary registers | ||||
| // input: r_0, r_1, r_2, r5_2 | ||||
| // temp: TEMP0, TEMP1, TEMP2 | ||||
| // output: p0, p1, p2 | ||||
| #define SQUARE(r_0, r_1, r_2, r5_2, p0, p1, p2, TEMP0, TEMP1, TEMP2) \ | ||||
| 	VMSLG r_0, r_0, p0, p0     \ | ||||
| 	VMSLG r_1, r5_2, V0, TEMP0 \ | ||||
| 	VMSLG r_2, r5_2, p1, p1    \ | ||||
| 	VMSLG r_0, r_1, V0, TEMP1  \ | ||||
| 	VMSLG r_1, r_1, p2, p2     \ | ||||
| 	VMSLG r_0, r_2, V0, TEMP2  \ | ||||
| 	VAQ   TEMP0, p0, p0        \ | ||||
| 	VAQ   TEMP1, p1, p1        \ | ||||
| 	VAQ   TEMP2, p2, p2        \ | ||||
| 	VAQ   TEMP0, p0, p0        \ | ||||
| 	VAQ   TEMP1, p1, p1        \ | ||||
| 	VAQ   TEMP2, p2, p2        \ | ||||
|  | ||||
| // carry h0->h1->h2->h0 || h3->h4->h5->h3 | ||||
| // uses T_2, T_4, T_5, T_7, T_8, T_9 | ||||
| //       t6,  t7,  t8,  t9, t10, t11 | ||||
| // input: h0, h1, h2, h3, h4, h5 | ||||
| // temp: t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11 | ||||
| // output: h0, h1, h2, h3, h4, h5 | ||||
| #define REDUCE(h0, h1, h2, h3, h4, h5, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) \ | ||||
| 	VLM    (R12), t6, t7  \ // 44 and 42 bit clear mask | ||||
| 	VLEIB  $7, $0x28, t10 \ // 5 byte shift mask | ||||
| 	VREPIB $4, t8         \ // 4 bit shift mask | ||||
| 	VREPIB $2, t11        \ // 2 bit shift mask | ||||
| 	VSRLB  t10, h0, t0    \ // h0 byte shift | ||||
| 	VSRLB  t10, h1, t1    \ // h1 byte shift | ||||
| 	VSRLB  t10, h2, t2    \ // h2 byte shift | ||||
| 	VSRLB  t10, h3, t3    \ // h3 byte shift | ||||
| 	VSRLB  t10, h4, t4    \ // h4 byte shift | ||||
| 	VSRLB  t10, h5, t5    \ // h5 byte shift | ||||
| 	VSRL   t8, t0, t0     \ // h0 bit shift | ||||
| 	VSRL   t8, t1, t1     \ // h2 bit shift | ||||
| 	VSRL   t11, t2, t2    \ // h2 bit shift | ||||
| 	VSRL   t8, t3, t3     \ // h3 bit shift | ||||
| 	VSRL   t8, t4, t4     \ // h4 bit shift | ||||
| 	VESLG  $2, t2, t9     \ // h2 carry x5 | ||||
| 	VSRL   t11, t5, t5    \ // h5 bit shift | ||||
| 	VN     t6, h0, h0     \ // h0 clear carry | ||||
| 	VAQ    t2, t9, t2     \ // h2 carry x5 | ||||
| 	VESLG  $2, t5, t9     \ // h5 carry x5 | ||||
| 	VN     t6, h1, h1     \ // h1 clear carry | ||||
| 	VN     t7, h2, h2     \ // h2 clear carry | ||||
| 	VAQ    t5, t9, t5     \ // h5 carry x5 | ||||
| 	VN     t6, h3, h3     \ // h3 clear carry | ||||
| 	VN     t6, h4, h4     \ // h4 clear carry | ||||
| 	VN     t7, h5, h5     \ // h5 clear carry | ||||
| 	VAQ    t0, h1, h1     \ // h0->h1 | ||||
| 	VAQ    t3, h4, h4     \ // h3->h4 | ||||
| 	VAQ    t1, h2, h2     \ // h1->h2 | ||||
| 	VAQ    t4, h5, h5     \ // h4->h5 | ||||
| 	VAQ    t2, h0, h0     \ // h2->h0 | ||||
| 	VAQ    t5, h3, h3     \ // h5->h3 | ||||
| 	VREPG  $1, t6, t6     \ // 44 and 42 bit masks across both halves | ||||
| 	VREPG  $1, t7, t7     \ | ||||
| 	VSLDB  $8, h0, h0, h0 \ // set up [h0/1/2, h3/4/5] | ||||
| 	VSLDB  $8, h1, h1, h1 \ | ||||
| 	VSLDB  $8, h2, h2, h2 \ | ||||
| 	VO     h0, h3, h3     \ | ||||
| 	VO     h1, h4, h4     \ | ||||
| 	VO     h2, h5, h5     \ | ||||
| 	VESRLG $44, h3, t0    \ // 44 bit shift right | ||||
| 	VESRLG $44, h4, t1    \ | ||||
| 	VESRLG $42, h5, t2    \ | ||||
| 	VN     t6, h3, h3     \ // clear carry bits | ||||
| 	VN     t6, h4, h4     \ | ||||
| 	VN     t7, h5, h5     \ | ||||
| 	VESLG  $2, t2, t9     \ // multiply carry by 5 | ||||
| 	VAQ    t9, t2, t2     \ | ||||
| 	VAQ    t0, h4, h4     \ | ||||
| 	VAQ    t1, h5, h5     \ | ||||
| 	VAQ    t2, h3, h3     \ | ||||
|  | ||||
| // carry h0->h1->h2->h0 | ||||
| // input: h0, h1, h2 | ||||
| // temp: t0, t1, t2, t3, t4, t5, t6, t7, t8 | ||||
| // output: h0, h1, h2 | ||||
| #define REDUCE2(h0, h1, h2, t0, t1, t2, t3, t4, t5, t6, t7, t8) \ | ||||
| 	VLEIB  $7, $0x28, t3 \ // 5 byte shift mask | ||||
| 	VREPIB $4, t4        \ // 4 bit shift mask | ||||
| 	VREPIB $2, t7        \ // 2 bit shift mask | ||||
| 	VGBM   $0x003F, t5   \ // mask to clear carry bits | ||||
| 	VSRLB  t3, h0, t0    \ | ||||
| 	VSRLB  t3, h1, t1    \ | ||||
| 	VSRLB  t3, h2, t2    \ | ||||
| 	VESRLG $4, t5, t5    \ // 44 bit clear mask | ||||
| 	VSRL   t4, t0, t0    \ | ||||
| 	VSRL   t4, t1, t1    \ | ||||
| 	VSRL   t7, t2, t2    \ | ||||
| 	VESRLG $2, t5, t6    \ // 42 bit clear mask | ||||
| 	VESLG  $2, t2, t8    \ | ||||
| 	VAQ    t8, t2, t2    \ | ||||
| 	VN     t5, h0, h0    \ | ||||
| 	VN     t5, h1, h1    \ | ||||
| 	VN     t6, h2, h2    \ | ||||
| 	VAQ    t0, h1, h1    \ | ||||
| 	VAQ    t1, h2, h2    \ | ||||
| 	VAQ    t2, h0, h0    \ | ||||
| 	VSRLB  t3, h0, t0    \ | ||||
| 	VSRLB  t3, h1, t1    \ | ||||
| 	VSRLB  t3, h2, t2    \ | ||||
| 	VSRL   t4, t0, t0    \ | ||||
| 	VSRL   t4, t1, t1    \ | ||||
| 	VSRL   t7, t2, t2    \ | ||||
| 	VN     t5, h0, h0    \ | ||||
| 	VN     t5, h1, h1    \ | ||||
| 	VESLG  $2, t2, t8    \ | ||||
| 	VN     t6, h2, h2    \ | ||||
| 	VAQ    t0, h1, h1    \ | ||||
| 	VAQ    t8, t2, t2    \ | ||||
| 	VAQ    t1, h2, h2    \ | ||||
| 	VAQ    t2, h0, h0    \ | ||||
|  | ||||
| // expands two message blocks into the lower halfs of the d registers | ||||
| // moves the contents of the d registers into upper halfs | ||||
| // input: in1, in2, d0, d1, d2, d3, d4, d5 | ||||
| // temp: TEMP0, TEMP1, TEMP2, TEMP3 | ||||
| // output: d0, d1, d2, d3, d4, d5 | ||||
| #define EXPACC(in1, in2, d0, d1, d2, d3, d4, d5, TEMP0, TEMP1, TEMP2, TEMP3) \ | ||||
| 	VGBM   $0xff3f, TEMP0      \ | ||||
| 	VGBM   $0xff1f, TEMP1      \ | ||||
| 	VESLG  $4, d1, TEMP2       \ | ||||
| 	VESLG  $4, d4, TEMP3       \ | ||||
| 	VESRLG $4, TEMP0, TEMP0    \ | ||||
| 	VPERM  in1, d0, EX0, d0    \ | ||||
| 	VPERM  in2, d3, EX0, d3    \ | ||||
| 	VPERM  in1, d2, EX2, d2    \ | ||||
| 	VPERM  in2, d5, EX2, d5    \ | ||||
| 	VPERM  in1, TEMP2, EX1, d1 \ | ||||
| 	VPERM  in2, TEMP3, EX1, d4 \ | ||||
| 	VN     TEMP0, d0, d0       \ | ||||
| 	VN     TEMP0, d3, d3       \ | ||||
| 	VESRLG $4, d1, d1          \ | ||||
| 	VESRLG $4, d4, d4          \ | ||||
| 	VN     TEMP1, d2, d2       \ | ||||
| 	VN     TEMP1, d5, d5       \ | ||||
| 	VN     TEMP0, d1, d1       \ | ||||
| 	VN     TEMP0, d4, d4       \ | ||||
|  | ||||
| // expands one message block into the lower halfs of the d registers | ||||
| // moves the contents of the d registers into upper halfs | ||||
| // input: in, d0, d1, d2 | ||||
| // temp: TEMP0, TEMP1, TEMP2 | ||||
| // output: d0, d1, d2 | ||||
| #define EXPACC2(in, d0, d1, d2, TEMP0, TEMP1, TEMP2) \ | ||||
| 	VGBM   $0xff3f, TEMP0     \ | ||||
| 	VESLG  $4, d1, TEMP2      \ | ||||
| 	VGBM   $0xff1f, TEMP1     \ | ||||
| 	VPERM  in, d0, EX0, d0    \ | ||||
| 	VESRLG $4, TEMP0, TEMP0   \ | ||||
| 	VPERM  in, d2, EX2, d2    \ | ||||
| 	VPERM  in, TEMP2, EX1, d1 \ | ||||
| 	VN     TEMP0, d0, d0      \ | ||||
| 	VN     TEMP1, d2, d2      \ | ||||
| 	VESRLG $4, d1, d1         \ | ||||
| 	VN     TEMP0, d1, d1      \ | ||||
|  | ||||
| // pack h2:h0 into h1:h0 (no carry) | ||||
| // input: h0, h1, h2 | ||||
| // output: h0, h1, h2 | ||||
| #define PACK(h0, h1, h2) \ | ||||
| 	VMRLG  h1, h2, h2  \ // copy h1 to upper half h2 | ||||
| 	VESLG  $44, h1, h1 \ // shift limb 1 44 bits, leaving 20 | ||||
| 	VO     h0, h1, h0  \ // combine h0 with 20 bits from limb 1 | ||||
| 	VESRLG $20, h2, h1 \ // put top 24 bits of limb 1 into h1 | ||||
| 	VLEIG  $1, $0, h1  \ // clear h2 stuff from lower half of h1 | ||||
| 	VO     h0, h1, h0  \ // h0 now has 88 bits (limb 0 and 1) | ||||
| 	VLEIG  $0, $0, h2  \ // clear upper half of h2 | ||||
| 	VESRLG $40, h2, h1 \ // h1 now has upper two bits of result | ||||
| 	VLEIB  $7, $88, h1 \ // for byte shift (11 bytes) | ||||
| 	VSLB   h1, h2, h2  \ // shift h2 11 bytes to the left | ||||
| 	VO     h0, h2, h0  \ // combine h0 with 20 bits from limb 1 | ||||
| 	VLEIG  $0, $0, h1  \ // clear upper half of h1 | ||||
|  | ||||
| // if h > 2**130-5 then h -= 2**130-5 | ||||
| // input: h0, h1 | ||||
| // temp: t0, t1, t2 | ||||
| // output: h0 | ||||
| #define MOD(h0, h1, t0, t1, t2) \ | ||||
| 	VZERO t0          \ | ||||
| 	VLEIG $1, $5, t0  \ | ||||
| 	VACCQ h0, t0, t1  \ | ||||
| 	VAQ   h0, t0, t0  \ | ||||
| 	VONE  t2          \ | ||||
| 	VLEIG $1, $-4, t2 \ | ||||
| 	VAQ   t2, t1, t1  \ | ||||
| 	VACCQ h1, t1, t1  \ | ||||
| 	VONE  t2          \ | ||||
| 	VAQ   t2, t1, t1  \ | ||||
| 	VN    h0, t1, t2  \ | ||||
| 	VNC   t0, t1, t1  \ | ||||
| 	VO    t1, t2, h0  \ | ||||
|  | ||||
| // func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]key) | ||||
| TEXT ·poly1305vmsl(SB), $0-32 | ||||
| 	// This code processes 6 + up to 4 blocks (32 bytes) per iteration | ||||
| 	// using the algorithm described in: | ||||
| 	// NEON crypto, Daniel J. Bernstein & Peter Schwabe | ||||
| 	// https://cryptojedi.org/papers/neoncrypto-20120320.pdf | ||||
| 	// And as moddified for VMSL as described in | ||||
| 	// Accelerating Poly1305 Cryptographic Message Authentication on the z14 | ||||
| 	// O'Farrell et al, CASCON 2017, p48-55 | ||||
| 	// https://ibm.ent.box.com/s/jf9gedj0e9d2vjctfyh186shaztavnht | ||||
|  | ||||
| 	LMG   out+0(FP), R1, R4 // R1=out, R2=m, R3=mlen, R4=key | ||||
| 	VZERO V0                // c | ||||
|  | ||||
| 	// load EX0, EX1 and EX2 | ||||
| 	MOVD $·constants<>(SB), R5 | ||||
| 	VLM  (R5), EX0, EX2        // c | ||||
|  | ||||
| 	// setup r | ||||
| 	VL    (R4), T_0 | ||||
| 	MOVD  $·keyMask<>(SB), R6 | ||||
| 	VL    (R6), T_1 | ||||
| 	VN    T_0, T_1, T_0 | ||||
| 	VZERO T_2                 // limbs for r | ||||
| 	VZERO T_3 | ||||
| 	VZERO T_4 | ||||
| 	EXPACC2(T_0, T_2, T_3, T_4, T_1, T_5, T_7) | ||||
|  | ||||
| 	// T_2, T_3, T_4: [0, r] | ||||
|  | ||||
| 	// setup r*20 | ||||
| 	VLEIG $0, $0, T_0 | ||||
| 	VLEIG $1, $20, T_0       // T_0: [0, 20] | ||||
| 	VZERO T_5 | ||||
| 	VZERO T_6 | ||||
| 	VMSLG T_0, T_3, T_5, T_5 | ||||
| 	VMSLG T_0, T_4, T_6, T_6 | ||||
|  | ||||
| 	// store r for final block in GR | ||||
| 	VLGVG $1, T_2, RSAVE_0  // c | ||||
| 	VLGVG $1, T_3, RSAVE_1  // c | ||||
| 	VLGVG $1, T_4, RSAVE_2  // c | ||||
| 	VLGVG $1, T_5, R5SAVE_1 // c | ||||
| 	VLGVG $1, T_6, R5SAVE_2 // c | ||||
|  | ||||
| 	// initialize h | ||||
| 	VZERO H0_0 | ||||
| 	VZERO H1_0 | ||||
| 	VZERO H2_0 | ||||
| 	VZERO H0_1 | ||||
| 	VZERO H1_1 | ||||
| 	VZERO H2_1 | ||||
|  | ||||
| 	// initialize pointer for reduce constants | ||||
| 	MOVD $·reduce<>(SB), R12 | ||||
|  | ||||
| 	// calculate r**2 and 20*(r**2) | ||||
| 	VZERO R_0 | ||||
| 	VZERO R_1 | ||||
| 	VZERO R_2 | ||||
| 	SQUARE(T_2, T_3, T_4, T_6, R_0, R_1, R_2, T_1, T_5, T_7) | ||||
| 	REDUCE2(R_0, R_1, R_2, M0, M1, M2, M3, M4, R5_1, R5_2, M5, T_1) | ||||
| 	VZERO R5_1 | ||||
| 	VZERO R5_2 | ||||
| 	VMSLG T_0, R_1, R5_1, R5_1 | ||||
| 	VMSLG T_0, R_2, R5_2, R5_2 | ||||
|  | ||||
| 	// skip r**4 calculation if 3 blocks or less | ||||
| 	CMPBLE R3, $48, b4 | ||||
|  | ||||
| 	// calculate r**4 and 20*(r**4) | ||||
| 	VZERO T_8 | ||||
| 	VZERO T_9 | ||||
| 	VZERO T_10 | ||||
| 	SQUARE(R_0, R_1, R_2, R5_2, T_8, T_9, T_10, T_1, T_5, T_7) | ||||
| 	REDUCE2(T_8, T_9, T_10, M0, M1, M2, M3, M4, T_2, T_3, M5, T_1) | ||||
| 	VZERO T_2 | ||||
| 	VZERO T_3 | ||||
| 	VMSLG T_0, T_9, T_2, T_2 | ||||
| 	VMSLG T_0, T_10, T_3, T_3 | ||||
|  | ||||
| 	// put r**2 to the right and r**4 to the left of R_0, R_1, R_2 | ||||
| 	VSLDB $8, T_8, T_8, T_8 | ||||
| 	VSLDB $8, T_9, T_9, T_9 | ||||
| 	VSLDB $8, T_10, T_10, T_10 | ||||
| 	VSLDB $8, T_2, T_2, T_2 | ||||
| 	VSLDB $8, T_3, T_3, T_3 | ||||
|  | ||||
| 	VO T_8, R_0, R_0 | ||||
| 	VO T_9, R_1, R_1 | ||||
| 	VO T_10, R_2, R_2 | ||||
| 	VO T_2, R5_1, R5_1 | ||||
| 	VO T_3, R5_2, R5_2 | ||||
|  | ||||
| 	CMPBLE R3, $80, load // less than or equal to 5 blocks in message | ||||
|  | ||||
| 	// 6(or 5+1) blocks | ||||
| 	SUB    $81, R3 | ||||
| 	VLM    (R2), M0, M4 | ||||
| 	VLL    R3, 80(R2), M5 | ||||
| 	ADD    $1, R3 | ||||
| 	MOVBZ  $1, R0 | ||||
| 	CMPBGE R3, $16, 2(PC) | ||||
| 	VLVGB  R3, R0, M5 | ||||
| 	MOVD   $96(R2), R2 | ||||
| 	EXPACC(M0, M1, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3) | ||||
| 	EXPACC(M2, M3, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3) | ||||
| 	VLEIB  $2, $1, H2_0 | ||||
| 	VLEIB  $2, $1, H2_1 | ||||
| 	VLEIB  $10, $1, H2_0 | ||||
| 	VLEIB  $10, $1, H2_1 | ||||
|  | ||||
| 	VZERO  M0 | ||||
| 	VZERO  M1 | ||||
| 	VZERO  M2 | ||||
| 	VZERO  M3 | ||||
| 	VZERO  T_4 | ||||
| 	VZERO  T_10 | ||||
| 	EXPACC(M4, M5, M0, M1, M2, M3, T_4, T_10, T_0, T_1, T_2, T_3) | ||||
| 	VLR    T_4, M4 | ||||
| 	VLEIB  $10, $1, M2 | ||||
| 	CMPBLT R3, $16, 2(PC) | ||||
| 	VLEIB  $10, $1, T_10 | ||||
| 	MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) | ||||
| 	REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M2, M3, M4, T_4, T_5, T_2, T_7, T_8, T_9) | ||||
| 	VMRHG  V0, H0_1, H0_0 | ||||
| 	VMRHG  V0, H1_1, H1_0 | ||||
| 	VMRHG  V0, H2_1, H2_0 | ||||
| 	VMRLG  V0, H0_1, H0_1 | ||||
| 	VMRLG  V0, H1_1, H1_1 | ||||
| 	VMRLG  V0, H2_1, H2_1 | ||||
|  | ||||
| 	SUB    $16, R3 | ||||
| 	CMPBLE R3, $0, square | ||||
|  | ||||
| load: | ||||
| 	// load EX0, EX1 and EX2 | ||||
| 	MOVD $·c<>(SB), R5 | ||||
| 	VLM  (R5), EX0, EX2 | ||||
|  | ||||
| loop: | ||||
| 	CMPBLE R3, $64, add // b4	// last 4 or less blocks left | ||||
|  | ||||
| 	// next 4 full blocks | ||||
| 	VLM  (R2), M2, M5 | ||||
| 	SUB  $64, R3 | ||||
| 	MOVD $64(R2), R2 | ||||
| 	REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, T_0, T_1, T_3, T_4, T_5, T_2, T_7, T_8, T_9) | ||||
|  | ||||
| 	// expacc in-lined to create [m2, m3] limbs | ||||
| 	VGBM   $0x3f3f, T_0     // 44 bit clear mask | ||||
| 	VGBM   $0x1f1f, T_1     // 40 bit clear mask | ||||
| 	VPERM  M2, M3, EX0, T_3 | ||||
| 	VESRLG $4, T_0, T_0     // 44 bit clear mask ready | ||||
| 	VPERM  M2, M3, EX1, T_4 | ||||
| 	VPERM  M2, M3, EX2, T_5 | ||||
| 	VN     T_0, T_3, T_3 | ||||
| 	VESRLG $4, T_4, T_4 | ||||
| 	VN     T_1, T_5, T_5 | ||||
| 	VN     T_0, T_4, T_4 | ||||
| 	VMRHG  H0_1, T_3, H0_0 | ||||
| 	VMRHG  H1_1, T_4, H1_0 | ||||
| 	VMRHG  H2_1, T_5, H2_0 | ||||
| 	VMRLG  H0_1, T_3, H0_1 | ||||
| 	VMRLG  H1_1, T_4, H1_1 | ||||
| 	VMRLG  H2_1, T_5, H2_1 | ||||
| 	VLEIB  $10, $1, H2_0 | ||||
| 	VLEIB  $10, $1, H2_1 | ||||
| 	VPERM  M4, M5, EX0, T_3 | ||||
| 	VPERM  M4, M5, EX1, T_4 | ||||
| 	VPERM  M4, M5, EX2, T_5 | ||||
| 	VN     T_0, T_3, T_3 | ||||
| 	VESRLG $4, T_4, T_4 | ||||
| 	VN     T_1, T_5, T_5 | ||||
| 	VN     T_0, T_4, T_4 | ||||
| 	VMRHG  V0, T_3, M0 | ||||
| 	VMRHG  V0, T_4, M1 | ||||
| 	VMRHG  V0, T_5, M2 | ||||
| 	VMRLG  V0, T_3, M3 | ||||
| 	VMRLG  V0, T_4, M4 | ||||
| 	VMRLG  V0, T_5, M5 | ||||
| 	VLEIB  $10, $1, M2 | ||||
| 	VLEIB  $10, $1, M5 | ||||
|  | ||||
| 	MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) | ||||
| 	CMPBNE R3, $0, loop | ||||
| 	REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9) | ||||
| 	VMRHG  V0, H0_1, H0_0 | ||||
| 	VMRHG  V0, H1_1, H1_0 | ||||
| 	VMRHG  V0, H2_1, H2_0 | ||||
| 	VMRLG  V0, H0_1, H0_1 | ||||
| 	VMRLG  V0, H1_1, H1_1 | ||||
| 	VMRLG  V0, H2_1, H2_1 | ||||
|  | ||||
| 	// load EX0, EX1, EX2 | ||||
| 	MOVD $·constants<>(SB), R5 | ||||
| 	VLM  (R5), EX0, EX2 | ||||
|  | ||||
| 	// sum vectors | ||||
| 	VAQ H0_0, H0_1, H0_0 | ||||
| 	VAQ H1_0, H1_1, H1_0 | ||||
| 	VAQ H2_0, H2_1, H2_0 | ||||
|  | ||||
| 	// h may be >= 2*(2**130-5) so we need to reduce it again | ||||
| 	// M0...M4 are used as temps here | ||||
| 	REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) | ||||
|  | ||||
| next:  // carry h1->h2 | ||||
| 	VLEIB  $7, $0x28, T_1 | ||||
| 	VREPIB $4, T_2 | ||||
| 	VGBM   $0x003F, T_3 | ||||
| 	VESRLG $4, T_3 | ||||
|  | ||||
| 	// byte shift | ||||
| 	VSRLB T_1, H1_0, T_4 | ||||
|  | ||||
| 	// bit shift | ||||
| 	VSRL T_2, T_4, T_4 | ||||
|  | ||||
| 	// clear h1 carry bits | ||||
| 	VN T_3, H1_0, H1_0 | ||||
|  | ||||
| 	// add carry | ||||
| 	VAQ T_4, H2_0, H2_0 | ||||
|  | ||||
| 	// h is now < 2*(2**130-5) | ||||
| 	// pack h into h1 (hi) and h0 (lo) | ||||
| 	PACK(H0_0, H1_0, H2_0) | ||||
|  | ||||
| 	// if h > 2**130-5 then h -= 2**130-5 | ||||
| 	MOD(H0_0, H1_0, T_0, T_1, T_2) | ||||
|  | ||||
| 	// h += s | ||||
| 	MOVD  $·bswapMask<>(SB), R5 | ||||
| 	VL    (R5), T_1 | ||||
| 	VL    16(R4), T_0 | ||||
| 	VPERM T_0, T_0, T_1, T_0    // reverse bytes (to big) | ||||
| 	VAQ   T_0, H0_0, H0_0 | ||||
| 	VPERM H0_0, H0_0, T_1, H0_0 // reverse bytes (to little) | ||||
| 	VST   H0_0, (R1) | ||||
| 	RET | ||||
|  | ||||
| add: | ||||
| 	// load EX0, EX1, EX2 | ||||
| 	MOVD $·constants<>(SB), R5 | ||||
| 	VLM  (R5), EX0, EX2 | ||||
|  | ||||
| 	REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9) | ||||
| 	VMRHG  V0, H0_1, H0_0 | ||||
| 	VMRHG  V0, H1_1, H1_0 | ||||
| 	VMRHG  V0, H2_1, H2_0 | ||||
| 	VMRLG  V0, H0_1, H0_1 | ||||
| 	VMRLG  V0, H1_1, H1_1 | ||||
| 	VMRLG  V0, H2_1, H2_1 | ||||
| 	CMPBLE R3, $64, b4 | ||||
|  | ||||
| b4: | ||||
| 	CMPBLE R3, $48, b3 // 3 blocks or less | ||||
|  | ||||
| 	// 4(3+1) blocks remaining | ||||
| 	SUB    $49, R3 | ||||
| 	VLM    (R2), M0, M2 | ||||
| 	VLL    R3, 48(R2), M3 | ||||
| 	ADD    $1, R3 | ||||
| 	MOVBZ  $1, R0 | ||||
| 	CMPBEQ R3, $16, 2(PC) | ||||
| 	VLVGB  R3, R0, M3 | ||||
| 	MOVD   $64(R2), R2 | ||||
| 	EXPACC(M0, M1, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3) | ||||
| 	VLEIB  $10, $1, H2_0 | ||||
| 	VLEIB  $10, $1, H2_1 | ||||
| 	VZERO  M0 | ||||
| 	VZERO  M1 | ||||
| 	VZERO  M4 | ||||
| 	VZERO  M5 | ||||
| 	VZERO  T_4 | ||||
| 	VZERO  T_10 | ||||
| 	EXPACC(M2, M3, M0, M1, M4, M5, T_4, T_10, T_0, T_1, T_2, T_3) | ||||
| 	VLR    T_4, M2 | ||||
| 	VLEIB  $10, $1, M4 | ||||
| 	CMPBNE R3, $16, 2(PC) | ||||
| 	VLEIB  $10, $1, T_10 | ||||
| 	MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M4, M5, M2, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) | ||||
| 	REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9) | ||||
| 	VMRHG  V0, H0_1, H0_0 | ||||
| 	VMRHG  V0, H1_1, H1_0 | ||||
| 	VMRHG  V0, H2_1, H2_0 | ||||
| 	VMRLG  V0, H0_1, H0_1 | ||||
| 	VMRLG  V0, H1_1, H1_1 | ||||
| 	VMRLG  V0, H2_1, H2_1 | ||||
| 	SUB    $16, R3 | ||||
| 	CMPBLE R3, $0, square // this condition must always hold true! | ||||
|  | ||||
| b3: | ||||
| 	CMPBLE R3, $32, b2 | ||||
|  | ||||
| 	// 3 blocks remaining | ||||
|  | ||||
| 	// setup [r²,r] | ||||
| 	VSLDB $8, R_0, R_0, R_0 | ||||
| 	VSLDB $8, R_1, R_1, R_1 | ||||
| 	VSLDB $8, R_2, R_2, R_2 | ||||
| 	VSLDB $8, R5_1, R5_1, R5_1 | ||||
| 	VSLDB $8, R5_2, R5_2, R5_2 | ||||
|  | ||||
| 	VLVGG $1, RSAVE_0, R_0 | ||||
| 	VLVGG $1, RSAVE_1, R_1 | ||||
| 	VLVGG $1, RSAVE_2, R_2 | ||||
| 	VLVGG $1, R5SAVE_1, R5_1 | ||||
| 	VLVGG $1, R5SAVE_2, R5_2 | ||||
|  | ||||
| 	// setup [h0, h1] | ||||
| 	VSLDB $8, H0_0, H0_0, H0_0 | ||||
| 	VSLDB $8, H1_0, H1_0, H1_0 | ||||
| 	VSLDB $8, H2_0, H2_0, H2_0 | ||||
| 	VO    H0_1, H0_0, H0_0 | ||||
| 	VO    H1_1, H1_0, H1_0 | ||||
| 	VO    H2_1, H2_0, H2_0 | ||||
| 	VZERO H0_1 | ||||
| 	VZERO H1_1 | ||||
| 	VZERO H2_1 | ||||
|  | ||||
| 	VZERO M0 | ||||
| 	VZERO M1 | ||||
| 	VZERO M2 | ||||
| 	VZERO M3 | ||||
| 	VZERO M4 | ||||
| 	VZERO M5 | ||||
|  | ||||
| 	// H*[r**2, r] | ||||
| 	MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) | ||||
| 	REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, H0_1, H1_1, T_10, M5) | ||||
|  | ||||
| 	SUB    $33, R3 | ||||
| 	VLM    (R2), M0, M1 | ||||
| 	VLL    R3, 32(R2), M2 | ||||
| 	ADD    $1, R3 | ||||
| 	MOVBZ  $1, R0 | ||||
| 	CMPBEQ R3, $16, 2(PC) | ||||
| 	VLVGB  R3, R0, M2 | ||||
|  | ||||
| 	// H += m0 | ||||
| 	VZERO T_1 | ||||
| 	VZERO T_2 | ||||
| 	VZERO T_3 | ||||
| 	EXPACC2(M0, T_1, T_2, T_3, T_4, T_5, T_6) | ||||
| 	VLEIB $10, $1, T_3 | ||||
| 	VAG   H0_0, T_1, H0_0 | ||||
| 	VAG   H1_0, T_2, H1_0 | ||||
| 	VAG   H2_0, T_3, H2_0 | ||||
|  | ||||
| 	VZERO M0 | ||||
| 	VZERO M3 | ||||
| 	VZERO M4 | ||||
| 	VZERO M5 | ||||
| 	VZERO T_10 | ||||
|  | ||||
| 	// (H+m0)*r | ||||
| 	MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M3, M4, M5, V0, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) | ||||
| 	REDUCE2(H0_0, H1_0, H2_0, M0, M3, M4, M5, T_10, H0_1, H1_1, H2_1, T_9) | ||||
|  | ||||
| 	// H += m1 | ||||
| 	VZERO V0 | ||||
| 	VZERO T_1 | ||||
| 	VZERO T_2 | ||||
| 	VZERO T_3 | ||||
| 	EXPACC2(M1, T_1, T_2, T_3, T_4, T_5, T_6) | ||||
| 	VLEIB $10, $1, T_3 | ||||
| 	VAQ   H0_0, T_1, H0_0 | ||||
| 	VAQ   H1_0, T_2, H1_0 | ||||
| 	VAQ   H2_0, T_3, H2_0 | ||||
| 	REDUCE2(H0_0, H1_0, H2_0, M0, M3, M4, M5, T_9, H0_1, H1_1, H2_1, T_10) | ||||
|  | ||||
| 	// [H, m2] * [r**2, r] | ||||
| 	EXPACC2(M2, H0_0, H1_0, H2_0, T_1, T_2, T_3) | ||||
| 	CMPBNE R3, $16, 2(PC) | ||||
| 	VLEIB  $10, $1, H2_0 | ||||
| 	VZERO  M0 | ||||
| 	VZERO  M1 | ||||
| 	VZERO  M2 | ||||
| 	VZERO  M3 | ||||
| 	VZERO  M4 | ||||
| 	VZERO  M5 | ||||
| 	MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) | ||||
| 	REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, H0_1, H1_1, M5, T_10) | ||||
| 	SUB    $16, R3 | ||||
| 	CMPBLE R3, $0, next   // this condition must always hold true! | ||||
|  | ||||
| b2: | ||||
| 	CMPBLE R3, $16, b1 | ||||
|  | ||||
| 	// 2 blocks remaining | ||||
|  | ||||
| 	// setup [r²,r] | ||||
| 	VSLDB $8, R_0, R_0, R_0 | ||||
| 	VSLDB $8, R_1, R_1, R_1 | ||||
| 	VSLDB $8, R_2, R_2, R_2 | ||||
| 	VSLDB $8, R5_1, R5_1, R5_1 | ||||
| 	VSLDB $8, R5_2, R5_2, R5_2 | ||||
|  | ||||
| 	VLVGG $1, RSAVE_0, R_0 | ||||
| 	VLVGG $1, RSAVE_1, R_1 | ||||
| 	VLVGG $1, RSAVE_2, R_2 | ||||
| 	VLVGG $1, R5SAVE_1, R5_1 | ||||
| 	VLVGG $1, R5SAVE_2, R5_2 | ||||
|  | ||||
| 	// setup [h0, h1] | ||||
| 	VSLDB $8, H0_0, H0_0, H0_0 | ||||
| 	VSLDB $8, H1_0, H1_0, H1_0 | ||||
| 	VSLDB $8, H2_0, H2_0, H2_0 | ||||
| 	VO    H0_1, H0_0, H0_0 | ||||
| 	VO    H1_1, H1_0, H1_0 | ||||
| 	VO    H2_1, H2_0, H2_0 | ||||
| 	VZERO H0_1 | ||||
| 	VZERO H1_1 | ||||
| 	VZERO H2_1 | ||||
|  | ||||
| 	VZERO M0 | ||||
| 	VZERO M1 | ||||
| 	VZERO M2 | ||||
| 	VZERO M3 | ||||
| 	VZERO M4 | ||||
| 	VZERO M5 | ||||
|  | ||||
| 	// H*[r**2, r] | ||||
| 	MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) | ||||
| 	REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M2, M3, M4, T_4, T_5, T_2, T_7, T_8, T_9) | ||||
| 	VMRHG V0, H0_1, H0_0 | ||||
| 	VMRHG V0, H1_1, H1_0 | ||||
| 	VMRHG V0, H2_1, H2_0 | ||||
| 	VMRLG V0, H0_1, H0_1 | ||||
| 	VMRLG V0, H1_1, H1_1 | ||||
| 	VMRLG V0, H2_1, H2_1 | ||||
|  | ||||
| 	// move h to the left and 0s at the right | ||||
| 	VSLDB $8, H0_0, H0_0, H0_0 | ||||
| 	VSLDB $8, H1_0, H1_0, H1_0 | ||||
| 	VSLDB $8, H2_0, H2_0, H2_0 | ||||
|  | ||||
| 	// get message blocks and append 1 to start | ||||
| 	SUB    $17, R3 | ||||
| 	VL     (R2), M0 | ||||
| 	VLL    R3, 16(R2), M1 | ||||
| 	ADD    $1, R3 | ||||
| 	MOVBZ  $1, R0 | ||||
| 	CMPBEQ R3, $16, 2(PC) | ||||
| 	VLVGB  R3, R0, M1 | ||||
| 	VZERO  T_6 | ||||
| 	VZERO  T_7 | ||||
| 	VZERO  T_8 | ||||
| 	EXPACC2(M0, T_6, T_7, T_8, T_1, T_2, T_3) | ||||
| 	EXPACC2(M1, T_6, T_7, T_8, T_1, T_2, T_3) | ||||
| 	VLEIB  $2, $1, T_8 | ||||
| 	CMPBNE R3, $16, 2(PC) | ||||
| 	VLEIB  $10, $1, T_8 | ||||
|  | ||||
| 	// add [m0, m1] to h | ||||
| 	VAG H0_0, T_6, H0_0 | ||||
| 	VAG H1_0, T_7, H1_0 | ||||
| 	VAG H2_0, T_8, H2_0 | ||||
|  | ||||
| 	VZERO M2 | ||||
| 	VZERO M3 | ||||
| 	VZERO M4 | ||||
| 	VZERO M5 | ||||
| 	VZERO T_10 | ||||
| 	VZERO M0 | ||||
|  | ||||
| 	// at this point R_0 .. R5_2 look like [r**2, r] | ||||
| 	MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M2, M3, M4, M5, T_10, M0, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) | ||||
| 	REDUCE2(H0_0, H1_0, H2_0, M2, M3, M4, M5, T_9, H0_1, H1_1, H2_1, T_10) | ||||
| 	SUB    $16, R3, R3 | ||||
| 	CMPBLE R3, $0, next | ||||
|  | ||||
| b1: | ||||
| 	CMPBLE R3, $0, next | ||||
|  | ||||
| 	// 1 block remaining | ||||
|  | ||||
| 	// setup [r²,r] | ||||
| 	VSLDB $8, R_0, R_0, R_0 | ||||
| 	VSLDB $8, R_1, R_1, R_1 | ||||
| 	VSLDB $8, R_2, R_2, R_2 | ||||
| 	VSLDB $8, R5_1, R5_1, R5_1 | ||||
| 	VSLDB $8, R5_2, R5_2, R5_2 | ||||
|  | ||||
| 	VLVGG $1, RSAVE_0, R_0 | ||||
| 	VLVGG $1, RSAVE_1, R_1 | ||||
| 	VLVGG $1, RSAVE_2, R_2 | ||||
| 	VLVGG $1, R5SAVE_1, R5_1 | ||||
| 	VLVGG $1, R5SAVE_2, R5_2 | ||||
|  | ||||
| 	// setup [h0, h1] | ||||
| 	VSLDB $8, H0_0, H0_0, H0_0 | ||||
| 	VSLDB $8, H1_0, H1_0, H1_0 | ||||
| 	VSLDB $8, H2_0, H2_0, H2_0 | ||||
| 	VO    H0_1, H0_0, H0_0 | ||||
| 	VO    H1_1, H1_0, H1_0 | ||||
| 	VO    H2_1, H2_0, H2_0 | ||||
| 	VZERO H0_1 | ||||
| 	VZERO H1_1 | ||||
| 	VZERO H2_1 | ||||
|  | ||||
| 	VZERO M0 | ||||
| 	VZERO M1 | ||||
| 	VZERO M2 | ||||
| 	VZERO M3 | ||||
| 	VZERO M4 | ||||
| 	VZERO M5 | ||||
|  | ||||
| 	// H*[r**2, r] | ||||
| 	MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) | ||||
| 	REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) | ||||
|  | ||||
| 	// set up [0, m0] limbs | ||||
| 	SUB    $1, R3 | ||||
| 	VLL    R3, (R2), M0 | ||||
| 	ADD    $1, R3 | ||||
| 	MOVBZ  $1, R0 | ||||
| 	CMPBEQ R3, $16, 2(PC) | ||||
| 	VLVGB  R3, R0, M0 | ||||
| 	VZERO  T_1 | ||||
| 	VZERO  T_2 | ||||
| 	VZERO  T_3 | ||||
| 	EXPACC2(M0, T_1, T_2, T_3, T_4, T_5, T_6)// limbs: [0, m] | ||||
| 	CMPBNE R3, $16, 2(PC) | ||||
| 	VLEIB  $10, $1, T_3 | ||||
|  | ||||
| 	// h+m0 | ||||
| 	VAQ H0_0, T_1, H0_0 | ||||
| 	VAQ H1_0, T_2, H1_0 | ||||
| 	VAQ H2_0, T_3, H2_0 | ||||
|  | ||||
| 	VZERO M0 | ||||
| 	VZERO M1 | ||||
| 	VZERO M2 | ||||
| 	VZERO M3 | ||||
| 	VZERO M4 | ||||
| 	VZERO M5 | ||||
| 	MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) | ||||
| 	REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) | ||||
|  | ||||
| 	BR next | ||||
|  | ||||
| square: | ||||
| 	// setup [r²,r] | ||||
| 	VSLDB $8, R_0, R_0, R_0 | ||||
| 	VSLDB $8, R_1, R_1, R_1 | ||||
| 	VSLDB $8, R_2, R_2, R_2 | ||||
| 	VSLDB $8, R5_1, R5_1, R5_1 | ||||
| 	VSLDB $8, R5_2, R5_2, R5_2 | ||||
|  | ||||
| 	VLVGG $1, RSAVE_0, R_0 | ||||
| 	VLVGG $1, RSAVE_1, R_1 | ||||
| 	VLVGG $1, RSAVE_2, R_2 | ||||
| 	VLVGG $1, R5SAVE_1, R5_1 | ||||
| 	VLVGG $1, R5SAVE_2, R5_2 | ||||
|  | ||||
| 	// setup [h0, h1] | ||||
| 	VSLDB $8, H0_0, H0_0, H0_0 | ||||
| 	VSLDB $8, H1_0, H1_0, H1_0 | ||||
| 	VSLDB $8, H2_0, H2_0, H2_0 | ||||
| 	VO    H0_1, H0_0, H0_0 | ||||
| 	VO    H1_1, H1_0, H1_0 | ||||
| 	VO    H2_1, H2_0, H2_0 | ||||
| 	VZERO H0_1 | ||||
| 	VZERO H1_1 | ||||
| 	VZERO H2_1 | ||||
|  | ||||
| 	VZERO M0 | ||||
| 	VZERO M1 | ||||
| 	VZERO M2 | ||||
| 	VZERO M3 | ||||
| 	VZERO M4 | ||||
| 	VZERO M5 | ||||
|  | ||||
| 	// (h0*r**2) + (h1*r) | ||||
| 	MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) | ||||
| 	REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) | ||||
| 	BR next | ||||
|  | ||||
| TEXT ·hasVMSLFacility(SB), NOSPLIT, $24-1 | ||||
| 	MOVD  $x-24(SP), R1 | ||||
| 	XC    $24, 0(R1), 0(R1) // clear the storage | ||||
| 	MOVD  $2, R0            // R0 is the number of double words stored -1 | ||||
| 	WORD  $0xB2B01000       // STFLE 0(R1) | ||||
| 	XOR   R0, R0            // reset the value of R0 | ||||
| 	MOVBZ z-8(SP), R1 | ||||
| 	AND   $0x01, R1 | ||||
| 	BEQ   novmsl | ||||
|  | ||||
| vectorinstalled: | ||||
| 	// check if the vector instruction has been enabled | ||||
| 	VLEIB  $0, $0xF, V16 | ||||
| 	VLGVB  $0, V16, R1 | ||||
| 	CMPBNE R1, $0xF, novmsl | ||||
| 	MOVB   $1, ret+0(FP)    // have vx | ||||
| 	RET | ||||
|  | ||||
| novmsl: | ||||
| 	MOVB $0, ret+0(FP) // no vx | ||||
| 	RET | ||||
							
								
								
									
										789
									
								
								vendor/golang.org/x/crypto/ssh/agent/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										789
									
								
								vendor/golang.org/x/crypto/ssh/agent/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,789 @@ | ||||
| // Copyright 2012 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 agent implements the ssh-agent protocol, and provides both | ||||
| // a client and a server. The client can talk to a standard ssh-agent | ||||
| // that uses UNIX sockets, and one could implement an alternative | ||||
| // ssh-agent process using the sample server. | ||||
| // | ||||
| // References: | ||||
| //  [PROTOCOL.agent]: https://tools.ietf.org/html/draft-miller-ssh-agent-00 | ||||
| package agent // import "golang.org/x/crypto/ssh/agent" | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto/dsa" | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/elliptic" | ||||
| 	"crypto/rsa" | ||||
| 	"encoding/base64" | ||||
| 	"encoding/binary" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 	"sync" | ||||
|  | ||||
| 	"crypto" | ||||
| 	"golang.org/x/crypto/ed25519" | ||||
| 	"golang.org/x/crypto/ssh" | ||||
| ) | ||||
|  | ||||
| // SignatureFlags represent additional flags that can be passed to the signature | ||||
| // requests an defined in [PROTOCOL.agent] section 4.5.1. | ||||
| type SignatureFlags uint32 | ||||
|  | ||||
| // SignatureFlag values as defined in [PROTOCOL.agent] section 5.3. | ||||
| const ( | ||||
| 	SignatureFlagReserved SignatureFlags = 1 << iota | ||||
| 	SignatureFlagRsaSha256 | ||||
| 	SignatureFlagRsaSha512 | ||||
| ) | ||||
|  | ||||
| // Agent represents the capabilities of an ssh-agent. | ||||
| type Agent interface { | ||||
| 	// List returns the identities known to the agent. | ||||
| 	List() ([]*Key, error) | ||||
|  | ||||
| 	// Sign has the agent sign the data using a protocol 2 key as defined | ||||
| 	// in [PROTOCOL.agent] section 2.6.2. | ||||
| 	Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) | ||||
|  | ||||
| 	// Add adds a private key to the agent. | ||||
| 	Add(key AddedKey) error | ||||
|  | ||||
| 	// Remove removes all identities with the given public key. | ||||
| 	Remove(key ssh.PublicKey) error | ||||
|  | ||||
| 	// RemoveAll removes all identities. | ||||
| 	RemoveAll() error | ||||
|  | ||||
| 	// Lock locks the agent. Sign and Remove will fail, and List will empty an empty list. | ||||
| 	Lock(passphrase []byte) error | ||||
|  | ||||
| 	// Unlock undoes the effect of Lock | ||||
| 	Unlock(passphrase []byte) error | ||||
|  | ||||
| 	// Signers returns signers for all the known keys. | ||||
| 	Signers() ([]ssh.Signer, error) | ||||
| } | ||||
|  | ||||
| type ExtendedAgent interface { | ||||
| 	Agent | ||||
|  | ||||
| 	// SignWithFlags signs like Sign, but allows for additional flags to be sent/received | ||||
| 	SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) | ||||
|  | ||||
| 	// Extension processes a custom extension request. Standard-compliant agents are not | ||||
| 	// required to support any extensions, but this method allows agents to implement | ||||
| 	// vendor-specific methods or add experimental features. See [PROTOCOL.agent] section 4.7. | ||||
| 	// If agent extensions are unsupported entirely this method MUST return an | ||||
| 	// ErrExtensionUnsupported error. Similarly, if just the specific extensionType in | ||||
| 	// the request is unsupported by the agent then ErrExtensionUnsupported MUST be | ||||
| 	// returned. | ||||
| 	// | ||||
| 	// In the case of success, since [PROTOCOL.agent] section 4.7 specifies that the contents | ||||
| 	// of the response are unspecified (including the type of the message), the complete | ||||
| 	// response will be returned as a []byte slice, including the "type" byte of the message. | ||||
| 	Extension(extensionType string, contents []byte) ([]byte, error) | ||||
| } | ||||
|  | ||||
| // ConstraintExtension describes an optional constraint defined by users. | ||||
| type ConstraintExtension struct { | ||||
| 	// ExtensionName consist of a UTF-8 string suffixed by the | ||||
| 	// implementation domain following the naming scheme defined | ||||
| 	// in Section 4.2 of [RFC4251], e.g.  "foo@example.com". | ||||
| 	ExtensionName string | ||||
| 	// ExtensionDetails contains the actual content of the extended | ||||
| 	// constraint. | ||||
| 	ExtensionDetails []byte | ||||
| } | ||||
|  | ||||
| // AddedKey describes an SSH key to be added to an Agent. | ||||
| type AddedKey struct { | ||||
| 	// PrivateKey must be a *rsa.PrivateKey, *dsa.PrivateKey or | ||||
| 	// *ecdsa.PrivateKey, which will be inserted into the agent. | ||||
| 	PrivateKey interface{} | ||||
| 	// Certificate, if not nil, is communicated to the agent and will be | ||||
| 	// stored with the key. | ||||
| 	Certificate *ssh.Certificate | ||||
| 	// Comment is an optional, free-form string. | ||||
| 	Comment string | ||||
| 	// LifetimeSecs, if not zero, is the number of seconds that the | ||||
| 	// agent will store the key for. | ||||
| 	LifetimeSecs uint32 | ||||
| 	// ConfirmBeforeUse, if true, requests that the agent confirm with the | ||||
| 	// user before each use of this key. | ||||
| 	ConfirmBeforeUse bool | ||||
| 	// ConstraintExtensions are the experimental or private-use constraints | ||||
| 	// defined by users. | ||||
| 	ConstraintExtensions []ConstraintExtension | ||||
| } | ||||
|  | ||||
| // See [PROTOCOL.agent], section 3. | ||||
| const ( | ||||
| 	agentRequestV1Identities   = 1 | ||||
| 	agentRemoveAllV1Identities = 9 | ||||
|  | ||||
| 	// 3.2 Requests from client to agent for protocol 2 key operations | ||||
| 	agentAddIdentity         = 17 | ||||
| 	agentRemoveIdentity      = 18 | ||||
| 	agentRemoveAllIdentities = 19 | ||||
| 	agentAddIDConstrained    = 25 | ||||
|  | ||||
| 	// 3.3 Key-type independent requests from client to agent | ||||
| 	agentAddSmartcardKey            = 20 | ||||
| 	agentRemoveSmartcardKey         = 21 | ||||
| 	agentLock                       = 22 | ||||
| 	agentUnlock                     = 23 | ||||
| 	agentAddSmartcardKeyConstrained = 26 | ||||
|  | ||||
| 	// 3.7 Key constraint identifiers | ||||
| 	agentConstrainLifetime  = 1 | ||||
| 	agentConstrainConfirm   = 2 | ||||
| 	agentConstrainExtension = 3 | ||||
| ) | ||||
|  | ||||
| // maxAgentResponseBytes is the maximum agent reply size that is accepted. This | ||||
| // is a sanity check, not a limit in the spec. | ||||
| const maxAgentResponseBytes = 16 << 20 | ||||
|  | ||||
| // Agent messages: | ||||
| // These structures mirror the wire format of the corresponding ssh agent | ||||
| // messages found in [PROTOCOL.agent]. | ||||
|  | ||||
| // 3.4 Generic replies from agent to client | ||||
| const agentFailure = 5 | ||||
|  | ||||
| type failureAgentMsg struct{} | ||||
|  | ||||
| const agentSuccess = 6 | ||||
|  | ||||
| type successAgentMsg struct{} | ||||
|  | ||||
| // See [PROTOCOL.agent], section 2.5.2. | ||||
| const agentRequestIdentities = 11 | ||||
|  | ||||
| type requestIdentitiesAgentMsg struct{} | ||||
|  | ||||
| // See [PROTOCOL.agent], section 2.5.2. | ||||
| const agentIdentitiesAnswer = 12 | ||||
|  | ||||
| type identitiesAnswerAgentMsg struct { | ||||
| 	NumKeys uint32 `sshtype:"12"` | ||||
| 	Keys    []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| // See [PROTOCOL.agent], section 2.6.2. | ||||
| const agentSignRequest = 13 | ||||
|  | ||||
| type signRequestAgentMsg struct { | ||||
| 	KeyBlob []byte `sshtype:"13"` | ||||
| 	Data    []byte | ||||
| 	Flags   uint32 | ||||
| } | ||||
|  | ||||
| // See [PROTOCOL.agent], section 2.6.2. | ||||
|  | ||||
| // 3.6 Replies from agent to client for protocol 2 key operations | ||||
| const agentSignResponse = 14 | ||||
|  | ||||
| type signResponseAgentMsg struct { | ||||
| 	SigBlob []byte `sshtype:"14"` | ||||
| } | ||||
|  | ||||
| type publicKey struct { | ||||
| 	Format string | ||||
| 	Rest   []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| // 3.7 Key constraint identifiers | ||||
| type constrainLifetimeAgentMsg struct { | ||||
| 	LifetimeSecs uint32 `sshtype:"1"` | ||||
| } | ||||
|  | ||||
| type constrainExtensionAgentMsg struct { | ||||
| 	ExtensionName    string `sshtype:"3"` | ||||
| 	ExtensionDetails []byte | ||||
|  | ||||
| 	// Rest is a field used for parsing, not part of message | ||||
| 	Rest []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| // See [PROTOCOL.agent], section 4.7 | ||||
| const agentExtension = 27 | ||||
| const agentExtensionFailure = 28 | ||||
|  | ||||
| // ErrExtensionUnsupported indicates that an extension defined in | ||||
| // [PROTOCOL.agent] section 4.7 is unsupported by the agent. Specifically this | ||||
| // error indicates that the agent returned a standard SSH_AGENT_FAILURE message | ||||
| // as the result of a SSH_AGENTC_EXTENSION request. Note that the protocol | ||||
| // specification (and therefore this error) does not distinguish between a | ||||
| // specific extension being unsupported and extensions being unsupported entirely. | ||||
| var ErrExtensionUnsupported = errors.New("agent: extension unsupported") | ||||
|  | ||||
| type extensionAgentMsg struct { | ||||
| 	ExtensionType string `sshtype:"27"` | ||||
| 	Contents      []byte | ||||
| } | ||||
|  | ||||
| // Key represents a protocol 2 public key as defined in | ||||
| // [PROTOCOL.agent], section 2.5.2. | ||||
| type Key struct { | ||||
| 	Format  string | ||||
| 	Blob    []byte | ||||
| 	Comment string | ||||
| } | ||||
|  | ||||
| func clientErr(err error) error { | ||||
| 	return fmt.Errorf("agent: client error: %v", err) | ||||
| } | ||||
|  | ||||
| // String returns the storage form of an agent key with the format, base64 | ||||
| // encoded serialized key, and the comment if it is not empty. | ||||
| func (k *Key) String() string { | ||||
| 	s := string(k.Format) + " " + base64.StdEncoding.EncodeToString(k.Blob) | ||||
|  | ||||
| 	if k.Comment != "" { | ||||
| 		s += " " + k.Comment | ||||
| 	} | ||||
|  | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| // Type returns the public key type. | ||||
| func (k *Key) Type() string { | ||||
| 	return k.Format | ||||
| } | ||||
|  | ||||
| // Marshal returns key blob to satisfy the ssh.PublicKey interface. | ||||
| func (k *Key) Marshal() []byte { | ||||
| 	return k.Blob | ||||
| } | ||||
|  | ||||
| // Verify satisfies the ssh.PublicKey interface. | ||||
| func (k *Key) Verify(data []byte, sig *ssh.Signature) error { | ||||
| 	pubKey, err := ssh.ParsePublicKey(k.Blob) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("agent: bad public key: %v", err) | ||||
| 	} | ||||
| 	return pubKey.Verify(data, sig) | ||||
| } | ||||
|  | ||||
| type wireKey struct { | ||||
| 	Format string | ||||
| 	Rest   []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| func parseKey(in []byte) (out *Key, rest []byte, err error) { | ||||
| 	var record struct { | ||||
| 		Blob    []byte | ||||
| 		Comment string | ||||
| 		Rest    []byte `ssh:"rest"` | ||||
| 	} | ||||
|  | ||||
| 	if err := ssh.Unmarshal(in, &record); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	var wk wireKey | ||||
| 	if err := ssh.Unmarshal(record.Blob, &wk); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	return &Key{ | ||||
| 		Format:  wk.Format, | ||||
| 		Blob:    record.Blob, | ||||
| 		Comment: record.Comment, | ||||
| 	}, record.Rest, nil | ||||
| } | ||||
|  | ||||
| // client is a client for an ssh-agent process. | ||||
| type client struct { | ||||
| 	// conn is typically a *net.UnixConn | ||||
| 	conn io.ReadWriter | ||||
| 	// mu is used to prevent concurrent access to the agent | ||||
| 	mu sync.Mutex | ||||
| } | ||||
|  | ||||
| // NewClient returns an Agent that talks to an ssh-agent process over | ||||
| // the given connection. | ||||
| func NewClient(rw io.ReadWriter) ExtendedAgent { | ||||
| 	return &client{conn: rw} | ||||
| } | ||||
|  | ||||
| // call sends an RPC to the agent. On success, the reply is | ||||
| // unmarshaled into reply and replyType is set to the first byte of | ||||
| // the reply, which contains the type of the message. | ||||
| func (c *client) call(req []byte) (reply interface{}, err error) { | ||||
| 	buf, err := c.callRaw(req) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	reply, err = unmarshal(buf) | ||||
| 	if err != nil { | ||||
| 		return nil, clientErr(err) | ||||
| 	} | ||||
| 	return reply, nil | ||||
| } | ||||
|  | ||||
| // callRaw sends an RPC to the agent. On success, the raw | ||||
| // bytes of the response are returned; no unmarshalling is | ||||
| // performed on the response. | ||||
| func (c *client) callRaw(req []byte) (reply []byte, err error) { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
|  | ||||
| 	msg := make([]byte, 4+len(req)) | ||||
| 	binary.BigEndian.PutUint32(msg, uint32(len(req))) | ||||
| 	copy(msg[4:], req) | ||||
| 	if _, err = c.conn.Write(msg); err != nil { | ||||
| 		return nil, clientErr(err) | ||||
| 	} | ||||
|  | ||||
| 	var respSizeBuf [4]byte | ||||
| 	if _, err = io.ReadFull(c.conn, respSizeBuf[:]); err != nil { | ||||
| 		return nil, clientErr(err) | ||||
| 	} | ||||
| 	respSize := binary.BigEndian.Uint32(respSizeBuf[:]) | ||||
| 	if respSize > maxAgentResponseBytes { | ||||
| 		return nil, clientErr(errors.New("response too large")) | ||||
| 	} | ||||
|  | ||||
| 	buf := make([]byte, respSize) | ||||
| 	if _, err = io.ReadFull(c.conn, buf); err != nil { | ||||
| 		return nil, clientErr(err) | ||||
| 	} | ||||
| 	return buf, nil | ||||
| } | ||||
|  | ||||
| func (c *client) simpleCall(req []byte) error { | ||||
| 	resp, err := c.call(req) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, ok := resp.(*successAgentMsg); ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return errors.New("agent: failure") | ||||
| } | ||||
|  | ||||
| func (c *client) RemoveAll() error { | ||||
| 	return c.simpleCall([]byte{agentRemoveAllIdentities}) | ||||
| } | ||||
|  | ||||
| func (c *client) Remove(key ssh.PublicKey) error { | ||||
| 	req := ssh.Marshal(&agentRemoveIdentityMsg{ | ||||
| 		KeyBlob: key.Marshal(), | ||||
| 	}) | ||||
| 	return c.simpleCall(req) | ||||
| } | ||||
|  | ||||
| func (c *client) Lock(passphrase []byte) error { | ||||
| 	req := ssh.Marshal(&agentLockMsg{ | ||||
| 		Passphrase: passphrase, | ||||
| 	}) | ||||
| 	return c.simpleCall(req) | ||||
| } | ||||
|  | ||||
| func (c *client) Unlock(passphrase []byte) error { | ||||
| 	req := ssh.Marshal(&agentUnlockMsg{ | ||||
| 		Passphrase: passphrase, | ||||
| 	}) | ||||
| 	return c.simpleCall(req) | ||||
| } | ||||
|  | ||||
| // List returns the identities known to the agent. | ||||
| func (c *client) List() ([]*Key, error) { | ||||
| 	// see [PROTOCOL.agent] section 2.5.2. | ||||
| 	req := []byte{agentRequestIdentities} | ||||
|  | ||||
| 	msg, err := c.call(req) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	switch msg := msg.(type) { | ||||
| 	case *identitiesAnswerAgentMsg: | ||||
| 		if msg.NumKeys > maxAgentResponseBytes/8 { | ||||
| 			return nil, errors.New("agent: too many keys in agent reply") | ||||
| 		} | ||||
| 		keys := make([]*Key, msg.NumKeys) | ||||
| 		data := msg.Keys | ||||
| 		for i := uint32(0); i < msg.NumKeys; i++ { | ||||
| 			var key *Key | ||||
| 			var err error | ||||
| 			if key, data, err = parseKey(data); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			keys[i] = key | ||||
| 		} | ||||
| 		return keys, nil | ||||
| 	case *failureAgentMsg: | ||||
| 		return nil, errors.New("agent: failed to list keys") | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
|  | ||||
| // Sign has the agent sign the data using a protocol 2 key as defined | ||||
| // in [PROTOCOL.agent] section 2.6.2. | ||||
| func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { | ||||
| 	return c.SignWithFlags(key, data, 0) | ||||
| } | ||||
|  | ||||
| func (c *client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { | ||||
| 	req := ssh.Marshal(signRequestAgentMsg{ | ||||
| 		KeyBlob: key.Marshal(), | ||||
| 		Data:    data, | ||||
| 		Flags:   uint32(flags), | ||||
| 	}) | ||||
|  | ||||
| 	msg, err := c.call(req) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	switch msg := msg.(type) { | ||||
| 	case *signResponseAgentMsg: | ||||
| 		var sig ssh.Signature | ||||
| 		if err := ssh.Unmarshal(msg.SigBlob, &sig); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		return &sig, nil | ||||
| 	case *failureAgentMsg: | ||||
| 		return nil, errors.New("agent: failed to sign challenge") | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
|  | ||||
| // unmarshal parses an agent message in packet, returning the parsed | ||||
| // form and the message type of packet. | ||||
| func unmarshal(packet []byte) (interface{}, error) { | ||||
| 	if len(packet) < 1 { | ||||
| 		return nil, errors.New("agent: empty packet") | ||||
| 	} | ||||
| 	var msg interface{} | ||||
| 	switch packet[0] { | ||||
| 	case agentFailure: | ||||
| 		return new(failureAgentMsg), nil | ||||
| 	case agentSuccess: | ||||
| 		return new(successAgentMsg), nil | ||||
| 	case agentIdentitiesAnswer: | ||||
| 		msg = new(identitiesAnswerAgentMsg) | ||||
| 	case agentSignResponse: | ||||
| 		msg = new(signResponseAgentMsg) | ||||
| 	case agentV1IdentitiesAnswer: | ||||
| 		msg = new(agentV1IdentityMsg) | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("agent: unknown type tag %d", packet[0]) | ||||
| 	} | ||||
| 	if err := ssh.Unmarshal(packet, msg); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return msg, nil | ||||
| } | ||||
|  | ||||
| type rsaKeyMsg struct { | ||||
| 	Type        string `sshtype:"17|25"` | ||||
| 	N           *big.Int | ||||
| 	E           *big.Int | ||||
| 	D           *big.Int | ||||
| 	Iqmp        *big.Int // IQMP = Inverse Q Mod P | ||||
| 	P           *big.Int | ||||
| 	Q           *big.Int | ||||
| 	Comments    string | ||||
| 	Constraints []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| type dsaKeyMsg struct { | ||||
| 	Type        string `sshtype:"17|25"` | ||||
| 	P           *big.Int | ||||
| 	Q           *big.Int | ||||
| 	G           *big.Int | ||||
| 	Y           *big.Int | ||||
| 	X           *big.Int | ||||
| 	Comments    string | ||||
| 	Constraints []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| type ecdsaKeyMsg struct { | ||||
| 	Type        string `sshtype:"17|25"` | ||||
| 	Curve       string | ||||
| 	KeyBytes    []byte | ||||
| 	D           *big.Int | ||||
| 	Comments    string | ||||
| 	Constraints []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| type ed25519KeyMsg struct { | ||||
| 	Type        string `sshtype:"17|25"` | ||||
| 	Pub         []byte | ||||
| 	Priv        []byte | ||||
| 	Comments    string | ||||
| 	Constraints []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| // Insert adds a private key to the agent. | ||||
| func (c *client) insertKey(s interface{}, comment string, constraints []byte) error { | ||||
| 	var req []byte | ||||
| 	switch k := s.(type) { | ||||
| 	case *rsa.PrivateKey: | ||||
| 		if len(k.Primes) != 2 { | ||||
| 			return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes)) | ||||
| 		} | ||||
| 		k.Precompute() | ||||
| 		req = ssh.Marshal(rsaKeyMsg{ | ||||
| 			Type:        ssh.KeyAlgoRSA, | ||||
| 			N:           k.N, | ||||
| 			E:           big.NewInt(int64(k.E)), | ||||
| 			D:           k.D, | ||||
| 			Iqmp:        k.Precomputed.Qinv, | ||||
| 			P:           k.Primes[0], | ||||
| 			Q:           k.Primes[1], | ||||
| 			Comments:    comment, | ||||
| 			Constraints: constraints, | ||||
| 		}) | ||||
| 	case *dsa.PrivateKey: | ||||
| 		req = ssh.Marshal(dsaKeyMsg{ | ||||
| 			Type:        ssh.KeyAlgoDSA, | ||||
| 			P:           k.P, | ||||
| 			Q:           k.Q, | ||||
| 			G:           k.G, | ||||
| 			Y:           k.Y, | ||||
| 			X:           k.X, | ||||
| 			Comments:    comment, | ||||
| 			Constraints: constraints, | ||||
| 		}) | ||||
| 	case *ecdsa.PrivateKey: | ||||
| 		nistID := fmt.Sprintf("nistp%d", k.Params().BitSize) | ||||
| 		req = ssh.Marshal(ecdsaKeyMsg{ | ||||
| 			Type:        "ecdsa-sha2-" + nistID, | ||||
| 			Curve:       nistID, | ||||
| 			KeyBytes:    elliptic.Marshal(k.Curve, k.X, k.Y), | ||||
| 			D:           k.D, | ||||
| 			Comments:    comment, | ||||
| 			Constraints: constraints, | ||||
| 		}) | ||||
| 	case *ed25519.PrivateKey: | ||||
| 		req = ssh.Marshal(ed25519KeyMsg{ | ||||
| 			Type:        ssh.KeyAlgoED25519, | ||||
| 			Pub:         []byte(*k)[32:], | ||||
| 			Priv:        []byte(*k), | ||||
| 			Comments:    comment, | ||||
| 			Constraints: constraints, | ||||
| 		}) | ||||
| 	default: | ||||
| 		return fmt.Errorf("agent: unsupported key type %T", s) | ||||
| 	} | ||||
|  | ||||
| 	// if constraints are present then the message type needs to be changed. | ||||
| 	if len(constraints) != 0 { | ||||
| 		req[0] = agentAddIDConstrained | ||||
| 	} | ||||
|  | ||||
| 	resp, err := c.call(req) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, ok := resp.(*successAgentMsg); ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return errors.New("agent: failure") | ||||
| } | ||||
|  | ||||
| type rsaCertMsg struct { | ||||
| 	Type        string `sshtype:"17|25"` | ||||
| 	CertBytes   []byte | ||||
| 	D           *big.Int | ||||
| 	Iqmp        *big.Int // IQMP = Inverse Q Mod P | ||||
| 	P           *big.Int | ||||
| 	Q           *big.Int | ||||
| 	Comments    string | ||||
| 	Constraints []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| type dsaCertMsg struct { | ||||
| 	Type        string `sshtype:"17|25"` | ||||
| 	CertBytes   []byte | ||||
| 	X           *big.Int | ||||
| 	Comments    string | ||||
| 	Constraints []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| type ecdsaCertMsg struct { | ||||
| 	Type        string `sshtype:"17|25"` | ||||
| 	CertBytes   []byte | ||||
| 	D           *big.Int | ||||
| 	Comments    string | ||||
| 	Constraints []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| type ed25519CertMsg struct { | ||||
| 	Type        string `sshtype:"17|25"` | ||||
| 	CertBytes   []byte | ||||
| 	Pub         []byte | ||||
| 	Priv        []byte | ||||
| 	Comments    string | ||||
| 	Constraints []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| // Add adds a private key to the agent. If a certificate is given, | ||||
| // that certificate is added instead as public key. | ||||
| func (c *client) Add(key AddedKey) error { | ||||
| 	var constraints []byte | ||||
|  | ||||
| 	if secs := key.LifetimeSecs; secs != 0 { | ||||
| 		constraints = append(constraints, ssh.Marshal(constrainLifetimeAgentMsg{secs})...) | ||||
| 	} | ||||
|  | ||||
| 	if key.ConfirmBeforeUse { | ||||
| 		constraints = append(constraints, agentConstrainConfirm) | ||||
| 	} | ||||
|  | ||||
| 	cert := key.Certificate | ||||
| 	if cert == nil { | ||||
| 		return c.insertKey(key.PrivateKey, key.Comment, constraints) | ||||
| 	} | ||||
| 	return c.insertCert(key.PrivateKey, cert, key.Comment, constraints) | ||||
| } | ||||
|  | ||||
| func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string, constraints []byte) error { | ||||
| 	var req []byte | ||||
| 	switch k := s.(type) { | ||||
| 	case *rsa.PrivateKey: | ||||
| 		if len(k.Primes) != 2 { | ||||
| 			return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes)) | ||||
| 		} | ||||
| 		k.Precompute() | ||||
| 		req = ssh.Marshal(rsaCertMsg{ | ||||
| 			Type:        cert.Type(), | ||||
| 			CertBytes:   cert.Marshal(), | ||||
| 			D:           k.D, | ||||
| 			Iqmp:        k.Precomputed.Qinv, | ||||
| 			P:           k.Primes[0], | ||||
| 			Q:           k.Primes[1], | ||||
| 			Comments:    comment, | ||||
| 			Constraints: constraints, | ||||
| 		}) | ||||
| 	case *dsa.PrivateKey: | ||||
| 		req = ssh.Marshal(dsaCertMsg{ | ||||
| 			Type:        cert.Type(), | ||||
| 			CertBytes:   cert.Marshal(), | ||||
| 			X:           k.X, | ||||
| 			Comments:    comment, | ||||
| 			Constraints: constraints, | ||||
| 		}) | ||||
| 	case *ecdsa.PrivateKey: | ||||
| 		req = ssh.Marshal(ecdsaCertMsg{ | ||||
| 			Type:        cert.Type(), | ||||
| 			CertBytes:   cert.Marshal(), | ||||
| 			D:           k.D, | ||||
| 			Comments:    comment, | ||||
| 			Constraints: constraints, | ||||
| 		}) | ||||
| 	case *ed25519.PrivateKey: | ||||
| 		req = ssh.Marshal(ed25519CertMsg{ | ||||
| 			Type:        cert.Type(), | ||||
| 			CertBytes:   cert.Marshal(), | ||||
| 			Pub:         []byte(*k)[32:], | ||||
| 			Priv:        []byte(*k), | ||||
| 			Comments:    comment, | ||||
| 			Constraints: constraints, | ||||
| 		}) | ||||
| 	default: | ||||
| 		return fmt.Errorf("agent: unsupported key type %T", s) | ||||
| 	} | ||||
|  | ||||
| 	// if constraints are present then the message type needs to be changed. | ||||
| 	if len(constraints) != 0 { | ||||
| 		req[0] = agentAddIDConstrained | ||||
| 	} | ||||
|  | ||||
| 	signer, err := ssh.NewSignerFromKey(s) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { | ||||
| 		return errors.New("agent: signer and cert have different public key") | ||||
| 	} | ||||
|  | ||||
| 	resp, err := c.call(req) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, ok := resp.(*successAgentMsg); ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return errors.New("agent: failure") | ||||
| } | ||||
|  | ||||
| // Signers provides a callback for client authentication. | ||||
| func (c *client) Signers() ([]ssh.Signer, error) { | ||||
| 	keys, err := c.List() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var result []ssh.Signer | ||||
| 	for _, k := range keys { | ||||
| 		result = append(result, &agentKeyringSigner{c, k}) | ||||
| 	} | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| type agentKeyringSigner struct { | ||||
| 	agent *client | ||||
| 	pub   ssh.PublicKey | ||||
| } | ||||
|  | ||||
| func (s *agentKeyringSigner) PublicKey() ssh.PublicKey { | ||||
| 	return s.pub | ||||
| } | ||||
|  | ||||
| func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, error) { | ||||
| 	// The agent has its own entropy source, so the rand argument is ignored. | ||||
| 	return s.agent.Sign(s.pub, data) | ||||
| } | ||||
|  | ||||
| func (s *agentKeyringSigner) SignWithOpts(rand io.Reader, data []byte, opts crypto.SignerOpts) (*ssh.Signature, error) { | ||||
| 	var flags SignatureFlags | ||||
| 	if opts != nil { | ||||
| 		switch opts.HashFunc() { | ||||
| 		case crypto.SHA256: | ||||
| 			flags = SignatureFlagRsaSha256 | ||||
| 		case crypto.SHA512: | ||||
| 			flags = SignatureFlagRsaSha512 | ||||
| 		} | ||||
| 	} | ||||
| 	return s.agent.SignWithFlags(s.pub, data, flags) | ||||
| } | ||||
|  | ||||
| // Calls an extension method. It is up to the agent implementation as to whether or not | ||||
| // any particular extension is supported and may always return an error. Because the | ||||
| // type of the response is up to the implementation, this returns the bytes of the | ||||
| // response and does not attempt any type of unmarshalling. | ||||
| func (c *client) Extension(extensionType string, contents []byte) ([]byte, error) { | ||||
| 	req := ssh.Marshal(extensionAgentMsg{ | ||||
| 		ExtensionType: extensionType, | ||||
| 		Contents:      contents, | ||||
| 	}) | ||||
| 	buf, err := c.callRaw(req) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if len(buf) == 0 { | ||||
| 		return nil, errors.New("agent: failure; empty response") | ||||
| 	} | ||||
| 	// [PROTOCOL.agent] section 4.7 indicates that an SSH_AGENT_FAILURE message | ||||
| 	// represents an agent that does not support the extension | ||||
| 	if buf[0] == agentFailure { | ||||
| 		return nil, ErrExtensionUnsupported | ||||
| 	} | ||||
| 	if buf[0] == agentExtensionFailure { | ||||
| 		return nil, errors.New("agent: generic extension failure") | ||||
| 	} | ||||
|  | ||||
| 	return buf, nil | ||||
| } | ||||
							
								
								
									
										103
									
								
								vendor/golang.org/x/crypto/ssh/agent/forward.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								vendor/golang.org/x/crypto/ssh/agent/forward.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| // Copyright 2014 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 agent | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"sync" | ||||
|  | ||||
| 	"golang.org/x/crypto/ssh" | ||||
| ) | ||||
|  | ||||
| // RequestAgentForwarding sets up agent forwarding for the session. | ||||
| // ForwardToAgent or ForwardToRemote should be called to route | ||||
| // the authentication requests. | ||||
| func RequestAgentForwarding(session *ssh.Session) error { | ||||
| 	ok, err := session.SendRequest("auth-agent-req@openssh.com", true, nil) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if !ok { | ||||
| 		return errors.New("forwarding request denied") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // ForwardToAgent routes authentication requests to the given keyring. | ||||
| func ForwardToAgent(client *ssh.Client, keyring Agent) error { | ||||
| 	channels := client.HandleChannelOpen(channelType) | ||||
| 	if channels == nil { | ||||
| 		return errors.New("agent: already have handler for " + channelType) | ||||
| 	} | ||||
|  | ||||
| 	go func() { | ||||
| 		for ch := range channels { | ||||
| 			channel, reqs, err := ch.Accept() | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			go ssh.DiscardRequests(reqs) | ||||
| 			go func() { | ||||
| 				ServeAgent(keyring, channel) | ||||
| 				channel.Close() | ||||
| 			}() | ||||
| 		} | ||||
| 	}() | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| const channelType = "auth-agent@openssh.com" | ||||
|  | ||||
| // ForwardToRemote routes authentication requests to the ssh-agent | ||||
| // process serving on the given unix socket. | ||||
| func ForwardToRemote(client *ssh.Client, addr string) error { | ||||
| 	channels := client.HandleChannelOpen(channelType) | ||||
| 	if channels == nil { | ||||
| 		return errors.New("agent: already have handler for " + channelType) | ||||
| 	} | ||||
| 	conn, err := net.Dial("unix", addr) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	conn.Close() | ||||
|  | ||||
| 	go func() { | ||||
| 		for ch := range channels { | ||||
| 			channel, reqs, err := ch.Accept() | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			go ssh.DiscardRequests(reqs) | ||||
| 			go forwardUnixSocket(channel, addr) | ||||
| 		} | ||||
| 	}() | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func forwardUnixSocket(channel ssh.Channel, addr string) { | ||||
| 	conn, err := net.Dial("unix", addr) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	var wg sync.WaitGroup | ||||
| 	wg.Add(2) | ||||
| 	go func() { | ||||
| 		io.Copy(conn, channel) | ||||
| 		conn.(*net.UnixConn).CloseWrite() | ||||
| 		wg.Done() | ||||
| 	}() | ||||
| 	go func() { | ||||
| 		io.Copy(channel, conn) | ||||
| 		channel.CloseWrite() | ||||
| 		wg.Done() | ||||
| 	}() | ||||
|  | ||||
| 	wg.Wait() | ||||
| 	conn.Close() | ||||
| 	channel.Close() | ||||
| } | ||||
							
								
								
									
										241
									
								
								vendor/golang.org/x/crypto/ssh/agent/keyring.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								vendor/golang.org/x/crypto/ssh/agent/keyring.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,241 @@ | ||||
| // Copyright 2014 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 agent | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto/rand" | ||||
| 	"crypto/subtle" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"golang.org/x/crypto/ssh" | ||||
| ) | ||||
|  | ||||
| type privKey struct { | ||||
| 	signer  ssh.Signer | ||||
| 	comment string | ||||
| 	expire  *time.Time | ||||
| } | ||||
|  | ||||
| type keyring struct { | ||||
| 	mu   sync.Mutex | ||||
| 	keys []privKey | ||||
|  | ||||
| 	locked     bool | ||||
| 	passphrase []byte | ||||
| } | ||||
|  | ||||
| var errLocked = errors.New("agent: locked") | ||||
|  | ||||
| // NewKeyring returns an Agent that holds keys in memory.  It is safe | ||||
| // for concurrent use by multiple goroutines. | ||||
| func NewKeyring() Agent { | ||||
| 	return &keyring{} | ||||
| } | ||||
|  | ||||
| // RemoveAll removes all identities. | ||||
| func (r *keyring) RemoveAll() error { | ||||
| 	r.mu.Lock() | ||||
| 	defer r.mu.Unlock() | ||||
| 	if r.locked { | ||||
| 		return errLocked | ||||
| 	} | ||||
|  | ||||
| 	r.keys = nil | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // removeLocked does the actual key removal. The caller must already be holding the | ||||
| // keyring mutex. | ||||
| func (r *keyring) removeLocked(want []byte) error { | ||||
| 	found := false | ||||
| 	for i := 0; i < len(r.keys); { | ||||
| 		if bytes.Equal(r.keys[i].signer.PublicKey().Marshal(), want) { | ||||
| 			found = true | ||||
| 			r.keys[i] = r.keys[len(r.keys)-1] | ||||
| 			r.keys = r.keys[:len(r.keys)-1] | ||||
| 			continue | ||||
| 		} else { | ||||
| 			i++ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if !found { | ||||
| 		return errors.New("agent: key not found") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Remove removes all identities with the given public key. | ||||
| func (r *keyring) Remove(key ssh.PublicKey) error { | ||||
| 	r.mu.Lock() | ||||
| 	defer r.mu.Unlock() | ||||
| 	if r.locked { | ||||
| 		return errLocked | ||||
| 	} | ||||
|  | ||||
| 	return r.removeLocked(key.Marshal()) | ||||
| } | ||||
|  | ||||
| // Lock locks the agent. Sign and Remove will fail, and List will return an empty list. | ||||
| func (r *keyring) Lock(passphrase []byte) error { | ||||
| 	r.mu.Lock() | ||||
| 	defer r.mu.Unlock() | ||||
| 	if r.locked { | ||||
| 		return errLocked | ||||
| 	} | ||||
|  | ||||
| 	r.locked = true | ||||
| 	r.passphrase = passphrase | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Unlock undoes the effect of Lock | ||||
| func (r *keyring) Unlock(passphrase []byte) error { | ||||
| 	r.mu.Lock() | ||||
| 	defer r.mu.Unlock() | ||||
| 	if !r.locked { | ||||
| 		return errors.New("agent: not locked") | ||||
| 	} | ||||
| 	if 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) { | ||||
| 		return fmt.Errorf("agent: incorrect passphrase") | ||||
| 	} | ||||
|  | ||||
| 	r.locked = false | ||||
| 	r.passphrase = nil | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // expireKeysLocked removes expired keys from the keyring. If a key was added | ||||
| // with a lifetimesecs contraint and seconds >= lifetimesecs seconds have | ||||
| // ellapsed, it is removed. The caller *must* be holding the keyring mutex. | ||||
| func (r *keyring) expireKeysLocked() { | ||||
| 	for _, k := range r.keys { | ||||
| 		if k.expire != nil && time.Now().After(*k.expire) { | ||||
| 			r.removeLocked(k.signer.PublicKey().Marshal()) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // List returns the identities known to the agent. | ||||
| func (r *keyring) List() ([]*Key, error) { | ||||
| 	r.mu.Lock() | ||||
| 	defer r.mu.Unlock() | ||||
| 	if r.locked { | ||||
| 		// section 2.7: locked agents return empty. | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	r.expireKeysLocked() | ||||
| 	var ids []*Key | ||||
| 	for _, k := range r.keys { | ||||
| 		pub := k.signer.PublicKey() | ||||
| 		ids = append(ids, &Key{ | ||||
| 			Format:  pub.Type(), | ||||
| 			Blob:    pub.Marshal(), | ||||
| 			Comment: k.comment}) | ||||
| 	} | ||||
| 	return ids, nil | ||||
| } | ||||
|  | ||||
| // Insert adds a private key to the keyring. If a certificate | ||||
| // is given, that certificate is added as public key. Note that | ||||
| // any constraints given are ignored. | ||||
| func (r *keyring) Add(key AddedKey) error { | ||||
| 	r.mu.Lock() | ||||
| 	defer r.mu.Unlock() | ||||
| 	if r.locked { | ||||
| 		return errLocked | ||||
| 	} | ||||
| 	signer, err := ssh.NewSignerFromKey(key.PrivateKey) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if cert := key.Certificate; cert != nil { | ||||
| 		signer, err = ssh.NewCertSigner(cert, signer) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	p := privKey{ | ||||
| 		signer:  signer, | ||||
| 		comment: key.Comment, | ||||
| 	} | ||||
|  | ||||
| 	if key.LifetimeSecs > 0 { | ||||
| 		t := time.Now().Add(time.Duration(key.LifetimeSecs) * time.Second) | ||||
| 		p.expire = &t | ||||
| 	} | ||||
|  | ||||
| 	r.keys = append(r.keys, p) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Sign returns a signature for the data. | ||||
| func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { | ||||
| 	return r.SignWithFlags(key, data, 0) | ||||
| } | ||||
|  | ||||
| func (r *keyring) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { | ||||
| 	r.mu.Lock() | ||||
| 	defer r.mu.Unlock() | ||||
| 	if r.locked { | ||||
| 		return nil, errLocked | ||||
| 	} | ||||
|  | ||||
| 	r.expireKeysLocked() | ||||
| 	wanted := key.Marshal() | ||||
| 	for _, k := range r.keys { | ||||
| 		if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) { | ||||
| 			if flags == 0 { | ||||
| 				return k.signer.Sign(rand.Reader, data) | ||||
| 			} else { | ||||
| 				if algorithmSigner, ok := k.signer.(ssh.AlgorithmSigner); !ok { | ||||
| 					return nil, fmt.Errorf("agent: signature does not support non-default signature algorithm: %T", k.signer) | ||||
| 				} else { | ||||
| 					var algorithm string | ||||
| 					switch flags { | ||||
| 					case SignatureFlagRsaSha256: | ||||
| 						algorithm = ssh.SigAlgoRSASHA2256 | ||||
| 					case SignatureFlagRsaSha512: | ||||
| 						algorithm = ssh.SigAlgoRSASHA2512 | ||||
| 					default: | ||||
| 						return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags) | ||||
| 					} | ||||
| 					return algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, errors.New("not found") | ||||
| } | ||||
|  | ||||
| // Signers returns signers for all the known keys. | ||||
| func (r *keyring) Signers() ([]ssh.Signer, error) { | ||||
| 	r.mu.Lock() | ||||
| 	defer r.mu.Unlock() | ||||
| 	if r.locked { | ||||
| 		return nil, errLocked | ||||
| 	} | ||||
|  | ||||
| 	r.expireKeysLocked() | ||||
| 	s := make([]ssh.Signer, 0, len(r.keys)) | ||||
| 	for _, k := range r.keys { | ||||
| 		s = append(s, k.signer) | ||||
| 	} | ||||
| 	return s, nil | ||||
| } | ||||
|  | ||||
| // The keyring does not support any extensions | ||||
| func (r *keyring) Extension(extensionType string, contents []byte) ([]byte, error) { | ||||
| 	return nil, ErrExtensionUnsupported | ||||
| } | ||||
							
								
								
									
										567
									
								
								vendor/golang.org/x/crypto/ssh/agent/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										567
									
								
								vendor/golang.org/x/crypto/ssh/agent/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,567 @@ | ||||
| // Copyright 2012 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 agent | ||||
|  | ||||
| import ( | ||||
| 	"crypto/dsa" | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/elliptic" | ||||
| 	"crypto/rsa" | ||||
| 	"encoding/binary" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"math/big" | ||||
|  | ||||
| 	"golang.org/x/crypto/ed25519" | ||||
| 	"golang.org/x/crypto/ssh" | ||||
| ) | ||||
|  | ||||
| // Server wraps an Agent and uses it to implement the agent side of | ||||
| // the SSH-agent, wire protocol. | ||||
| type server struct { | ||||
| 	agent Agent | ||||
| } | ||||
|  | ||||
| func (s *server) processRequestBytes(reqData []byte) []byte { | ||||
| 	rep, err := s.processRequest(reqData) | ||||
| 	if err != nil { | ||||
| 		if err != errLocked { | ||||
| 			// TODO(hanwen): provide better logging interface? | ||||
| 			log.Printf("agent %d: %v", reqData[0], err) | ||||
| 		} | ||||
| 		return []byte{agentFailure} | ||||
| 	} | ||||
|  | ||||
| 	if err == nil && rep == nil { | ||||
| 		return []byte{agentSuccess} | ||||
| 	} | ||||
|  | ||||
| 	return ssh.Marshal(rep) | ||||
| } | ||||
|  | ||||
| func marshalKey(k *Key) []byte { | ||||
| 	var record struct { | ||||
| 		Blob    []byte | ||||
| 		Comment string | ||||
| 	} | ||||
| 	record.Blob = k.Marshal() | ||||
| 	record.Comment = k.Comment | ||||
|  | ||||
| 	return ssh.Marshal(&record) | ||||
| } | ||||
|  | ||||
| // See [PROTOCOL.agent], section 2.5.1. | ||||
| const agentV1IdentitiesAnswer = 2 | ||||
|  | ||||
| type agentV1IdentityMsg struct { | ||||
| 	Numkeys uint32 `sshtype:"2"` | ||||
| } | ||||
|  | ||||
| type agentRemoveIdentityMsg struct { | ||||
| 	KeyBlob []byte `sshtype:"18"` | ||||
| } | ||||
|  | ||||
| type agentLockMsg struct { | ||||
| 	Passphrase []byte `sshtype:"22"` | ||||
| } | ||||
|  | ||||
| type agentUnlockMsg struct { | ||||
| 	Passphrase []byte `sshtype:"23"` | ||||
| } | ||||
|  | ||||
| func (s *server) processRequest(data []byte) (interface{}, error) { | ||||
| 	switch data[0] { | ||||
| 	case agentRequestV1Identities: | ||||
| 		return &agentV1IdentityMsg{0}, nil | ||||
|  | ||||
| 	case agentRemoveAllV1Identities: | ||||
| 		return nil, nil | ||||
|  | ||||
| 	case agentRemoveIdentity: | ||||
| 		var req agentRemoveIdentityMsg | ||||
| 		if err := ssh.Unmarshal(data, &req); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		var wk wireKey | ||||
| 		if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		return nil, s.agent.Remove(&Key{Format: wk.Format, Blob: req.KeyBlob}) | ||||
|  | ||||
| 	case agentRemoveAllIdentities: | ||||
| 		return nil, s.agent.RemoveAll() | ||||
|  | ||||
| 	case agentLock: | ||||
| 		var req agentLockMsg | ||||
| 		if err := ssh.Unmarshal(data, &req); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		return nil, s.agent.Lock(req.Passphrase) | ||||
|  | ||||
| 	case agentUnlock: | ||||
| 		var req agentUnlockMsg | ||||
| 		if err := ssh.Unmarshal(data, &req); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return nil, s.agent.Unlock(req.Passphrase) | ||||
|  | ||||
| 	case agentSignRequest: | ||||
| 		var req signRequestAgentMsg | ||||
| 		if err := ssh.Unmarshal(data, &req); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		var wk wireKey | ||||
| 		if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		k := &Key{ | ||||
| 			Format: wk.Format, | ||||
| 			Blob:   req.KeyBlob, | ||||
| 		} | ||||
|  | ||||
| 		var sig *ssh.Signature | ||||
| 		var err error | ||||
| 		if extendedAgent, ok := s.agent.(ExtendedAgent); ok { | ||||
| 			sig, err = extendedAgent.SignWithFlags(k, req.Data, SignatureFlags(req.Flags)) | ||||
| 		} else { | ||||
| 			sig, err = s.agent.Sign(k, req.Data) | ||||
| 		} | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return &signResponseAgentMsg{SigBlob: ssh.Marshal(sig)}, nil | ||||
|  | ||||
| 	case agentRequestIdentities: | ||||
| 		keys, err := s.agent.List() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		rep := identitiesAnswerAgentMsg{ | ||||
| 			NumKeys: uint32(len(keys)), | ||||
| 		} | ||||
| 		for _, k := range keys { | ||||
| 			rep.Keys = append(rep.Keys, marshalKey(k)...) | ||||
| 		} | ||||
| 		return rep, nil | ||||
|  | ||||
| 	case agentAddIDConstrained, agentAddIdentity: | ||||
| 		return nil, s.insertIdentity(data) | ||||
|  | ||||
| 	case agentExtension: | ||||
| 		// Return a stub object where the whole contents of the response gets marshaled. | ||||
| 		var responseStub struct { | ||||
| 			Rest []byte `ssh:"rest"` | ||||
| 		} | ||||
|  | ||||
| 		if extendedAgent, ok := s.agent.(ExtendedAgent); !ok { | ||||
| 			// If this agent doesn't implement extensions, [PROTOCOL.agent] section 4.7 | ||||
| 			// requires that we return a standard SSH_AGENT_FAILURE message. | ||||
| 			responseStub.Rest = []byte{agentFailure} | ||||
| 		} else { | ||||
| 			var req extensionAgentMsg | ||||
| 			if err := ssh.Unmarshal(data, &req); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			res, err := extendedAgent.Extension(req.ExtensionType, req.Contents) | ||||
| 			if err != nil { | ||||
| 				// If agent extensions are unsupported, return a standard SSH_AGENT_FAILURE | ||||
| 				// message as required by [PROTOCOL.agent] section 4.7. | ||||
| 				if err == ErrExtensionUnsupported { | ||||
| 					responseStub.Rest = []byte{agentFailure} | ||||
| 				} else { | ||||
| 					// As the result of any other error processing an extension request, | ||||
| 					// [PROTOCOL.agent] section 4.7 requires that we return a | ||||
| 					// SSH_AGENT_EXTENSION_FAILURE code. | ||||
| 					responseStub.Rest = []byte{agentExtensionFailure} | ||||
| 				} | ||||
| 			} else { | ||||
| 				if len(res) == 0 { | ||||
| 					return nil, nil | ||||
| 				} | ||||
| 				responseStub.Rest = res | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return responseStub, nil | ||||
| 	} | ||||
|  | ||||
| 	return nil, fmt.Errorf("unknown opcode %d", data[0]) | ||||
| } | ||||
|  | ||||
| func parseConstraints(constraints []byte) (lifetimeSecs uint32, confirmBeforeUse bool, extensions []ConstraintExtension, err error) { | ||||
| 	for len(constraints) != 0 { | ||||
| 		switch constraints[0] { | ||||
| 		case agentConstrainLifetime: | ||||
| 			lifetimeSecs = binary.BigEndian.Uint32(constraints[1:5]) | ||||
| 			constraints = constraints[5:] | ||||
| 		case agentConstrainConfirm: | ||||
| 			confirmBeforeUse = true | ||||
| 			constraints = constraints[1:] | ||||
| 		case agentConstrainExtension: | ||||
| 			var msg constrainExtensionAgentMsg | ||||
| 			if err = ssh.Unmarshal(constraints, &msg); err != nil { | ||||
| 				return 0, false, nil, err | ||||
| 			} | ||||
| 			extensions = append(extensions, ConstraintExtension{ | ||||
| 				ExtensionName:    msg.ExtensionName, | ||||
| 				ExtensionDetails: msg.ExtensionDetails, | ||||
| 			}) | ||||
| 			constraints = msg.Rest | ||||
| 		default: | ||||
| 			return 0, false, nil, fmt.Errorf("unknown constraint type: %d", constraints[0]) | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func setConstraints(key *AddedKey, constraintBytes []byte) error { | ||||
| 	lifetimeSecs, confirmBeforeUse, constraintExtensions, err := parseConstraints(constraintBytes) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	key.LifetimeSecs = lifetimeSecs | ||||
| 	key.ConfirmBeforeUse = confirmBeforeUse | ||||
| 	key.ConstraintExtensions = constraintExtensions | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func parseRSAKey(req []byte) (*AddedKey, error) { | ||||
| 	var k rsaKeyMsg | ||||
| 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if k.E.BitLen() > 30 { | ||||
| 		return nil, errors.New("agent: RSA public exponent too large") | ||||
| 	} | ||||
| 	priv := &rsa.PrivateKey{ | ||||
| 		PublicKey: rsa.PublicKey{ | ||||
| 			E: int(k.E.Int64()), | ||||
| 			N: k.N, | ||||
| 		}, | ||||
| 		D:      k.D, | ||||
| 		Primes: []*big.Int{k.P, k.Q}, | ||||
| 	} | ||||
| 	priv.Precompute() | ||||
|  | ||||
| 	addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} | ||||
| 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return addedKey, nil | ||||
| } | ||||
|  | ||||
| func parseEd25519Key(req []byte) (*AddedKey, error) { | ||||
| 	var k ed25519KeyMsg | ||||
| 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	priv := ed25519.PrivateKey(k.Priv) | ||||
|  | ||||
| 	addedKey := &AddedKey{PrivateKey: &priv, Comment: k.Comments} | ||||
| 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return addedKey, nil | ||||
| } | ||||
|  | ||||
| func parseDSAKey(req []byte) (*AddedKey, error) { | ||||
| 	var k dsaKeyMsg | ||||
| 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	priv := &dsa.PrivateKey{ | ||||
| 		PublicKey: dsa.PublicKey{ | ||||
| 			Parameters: dsa.Parameters{ | ||||
| 				P: k.P, | ||||
| 				Q: k.Q, | ||||
| 				G: k.G, | ||||
| 			}, | ||||
| 			Y: k.Y, | ||||
| 		}, | ||||
| 		X: k.X, | ||||
| 	} | ||||
|  | ||||
| 	addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} | ||||
| 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return addedKey, nil | ||||
| } | ||||
|  | ||||
| func unmarshalECDSA(curveName string, keyBytes []byte, privScalar *big.Int) (priv *ecdsa.PrivateKey, err error) { | ||||
| 	priv = &ecdsa.PrivateKey{ | ||||
| 		D: privScalar, | ||||
| 	} | ||||
|  | ||||
| 	switch curveName { | ||||
| 	case "nistp256": | ||||
| 		priv.Curve = elliptic.P256() | ||||
| 	case "nistp384": | ||||
| 		priv.Curve = elliptic.P384() | ||||
| 	case "nistp521": | ||||
| 		priv.Curve = elliptic.P521() | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("agent: unknown curve %q", curveName) | ||||
| 	} | ||||
|  | ||||
| 	priv.X, priv.Y = elliptic.Unmarshal(priv.Curve, keyBytes) | ||||
| 	if priv.X == nil || priv.Y == nil { | ||||
| 		return nil, errors.New("agent: point not on curve") | ||||
| 	} | ||||
|  | ||||
| 	return priv, nil | ||||
| } | ||||
|  | ||||
| func parseEd25519Cert(req []byte) (*AddedKey, error) { | ||||
| 	var k ed25519CertMsg | ||||
| 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	pubKey, err := ssh.ParsePublicKey(k.CertBytes) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	priv := ed25519.PrivateKey(k.Priv) | ||||
| 	cert, ok := pubKey.(*ssh.Certificate) | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("agent: bad ED25519 certificate") | ||||
| 	} | ||||
|  | ||||
| 	addedKey := &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments} | ||||
| 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return addedKey, nil | ||||
| } | ||||
|  | ||||
| func parseECDSAKey(req []byte) (*AddedKey, error) { | ||||
| 	var k ecdsaKeyMsg | ||||
| 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	priv, err := unmarshalECDSA(k.Curve, k.KeyBytes, k.D) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} | ||||
| 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return addedKey, nil | ||||
| } | ||||
|  | ||||
| func parseRSACert(req []byte) (*AddedKey, error) { | ||||
| 	var k rsaCertMsg | ||||
| 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	pubKey, err := ssh.ParsePublicKey(k.CertBytes) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	cert, ok := pubKey.(*ssh.Certificate) | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("agent: bad RSA certificate") | ||||
| 	} | ||||
|  | ||||
| 	// An RSA publickey as marshaled by rsaPublicKey.Marshal() in keys.go | ||||
| 	var rsaPub struct { | ||||
| 		Name string | ||||
| 		E    *big.Int | ||||
| 		N    *big.Int | ||||
| 	} | ||||
| 	if err := ssh.Unmarshal(cert.Key.Marshal(), &rsaPub); err != nil { | ||||
| 		return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	if rsaPub.E.BitLen() > 30 { | ||||
| 		return nil, errors.New("agent: RSA public exponent too large") | ||||
| 	} | ||||
|  | ||||
| 	priv := rsa.PrivateKey{ | ||||
| 		PublicKey: rsa.PublicKey{ | ||||
| 			E: int(rsaPub.E.Int64()), | ||||
| 			N: rsaPub.N, | ||||
| 		}, | ||||
| 		D:      k.D, | ||||
| 		Primes: []*big.Int{k.Q, k.P}, | ||||
| 	} | ||||
| 	priv.Precompute() | ||||
|  | ||||
| 	addedKey := &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments} | ||||
| 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return addedKey, nil | ||||
| } | ||||
|  | ||||
| func parseDSACert(req []byte) (*AddedKey, error) { | ||||
| 	var k dsaCertMsg | ||||
| 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	pubKey, err := ssh.ParsePublicKey(k.CertBytes) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	cert, ok := pubKey.(*ssh.Certificate) | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("agent: bad DSA certificate") | ||||
| 	} | ||||
|  | ||||
| 	// A DSA publickey as marshaled by dsaPublicKey.Marshal() in keys.go | ||||
| 	var w struct { | ||||
| 		Name       string | ||||
| 		P, Q, G, Y *big.Int | ||||
| 	} | ||||
| 	if err := ssh.Unmarshal(cert.Key.Marshal(), &w); err != nil { | ||||
| 		return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	priv := &dsa.PrivateKey{ | ||||
| 		PublicKey: dsa.PublicKey{ | ||||
| 			Parameters: dsa.Parameters{ | ||||
| 				P: w.P, | ||||
| 				Q: w.Q, | ||||
| 				G: w.G, | ||||
| 			}, | ||||
| 			Y: w.Y, | ||||
| 		}, | ||||
| 		X: k.X, | ||||
| 	} | ||||
|  | ||||
| 	addedKey := &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments} | ||||
| 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return addedKey, nil | ||||
| } | ||||
|  | ||||
| func parseECDSACert(req []byte) (*AddedKey, error) { | ||||
| 	var k ecdsaCertMsg | ||||
| 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	pubKey, err := ssh.ParsePublicKey(k.CertBytes) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	cert, ok := pubKey.(*ssh.Certificate) | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("agent: bad ECDSA certificate") | ||||
| 	} | ||||
|  | ||||
| 	// An ECDSA publickey as marshaled by ecdsaPublicKey.Marshal() in keys.go | ||||
| 	var ecdsaPub struct { | ||||
| 		Name string | ||||
| 		ID   string | ||||
| 		Key  []byte | ||||
| 	} | ||||
| 	if err := ssh.Unmarshal(cert.Key.Marshal(), &ecdsaPub); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	priv, err := unmarshalECDSA(ecdsaPub.ID, ecdsaPub.Key, k.D) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	addedKey := &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments} | ||||
| 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return addedKey, nil | ||||
| } | ||||
|  | ||||
| func (s *server) insertIdentity(req []byte) error { | ||||
| 	var record struct { | ||||
| 		Type string `sshtype:"17|25"` | ||||
| 		Rest []byte `ssh:"rest"` | ||||
| 	} | ||||
|  | ||||
| 	if err := ssh.Unmarshal(req, &record); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	var addedKey *AddedKey | ||||
| 	var err error | ||||
|  | ||||
| 	switch record.Type { | ||||
| 	case ssh.KeyAlgoRSA: | ||||
| 		addedKey, err = parseRSAKey(req) | ||||
| 	case ssh.KeyAlgoDSA: | ||||
| 		addedKey, err = parseDSAKey(req) | ||||
| 	case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521: | ||||
| 		addedKey, err = parseECDSAKey(req) | ||||
| 	case ssh.KeyAlgoED25519: | ||||
| 		addedKey, err = parseEd25519Key(req) | ||||
| 	case ssh.CertAlgoRSAv01: | ||||
| 		addedKey, err = parseRSACert(req) | ||||
| 	case ssh.CertAlgoDSAv01: | ||||
| 		addedKey, err = parseDSACert(req) | ||||
| 	case ssh.CertAlgoECDSA256v01, ssh.CertAlgoECDSA384v01, ssh.CertAlgoECDSA521v01: | ||||
| 		addedKey, err = parseECDSACert(req) | ||||
| 	case ssh.CertAlgoED25519v01: | ||||
| 		addedKey, err = parseEd25519Cert(req) | ||||
| 	default: | ||||
| 		return fmt.Errorf("agent: not implemented: %q", record.Type) | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return s.agent.Add(*addedKey) | ||||
| } | ||||
|  | ||||
| // ServeAgent serves the agent protocol on the given connection. It | ||||
| // returns when an I/O error occurs. | ||||
| func ServeAgent(agent Agent, c io.ReadWriter) error { | ||||
| 	s := &server{agent} | ||||
|  | ||||
| 	var length [4]byte | ||||
| 	for { | ||||
| 		if _, err := io.ReadFull(c, length[:]); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		l := binary.BigEndian.Uint32(length[:]) | ||||
| 		if l > maxAgentResponseBytes { | ||||
| 			// We also cap requests. | ||||
| 			return fmt.Errorf("agent: request too large: %d", l) | ||||
| 		} | ||||
|  | ||||
| 		req := make([]byte, l) | ||||
| 		if _, err := io.ReadFull(c, req); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		repData := s.processRequestBytes(req) | ||||
| 		if len(repData) > maxAgentResponseBytes { | ||||
| 			return fmt.Errorf("agent: reply too large: %d bytes", len(repData)) | ||||
| 		} | ||||
|  | ||||
| 		binary.BigEndian.PutUint32(length[:], uint32(len(repData))) | ||||
| 		if _, err := c.Write(length[:]); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if _, err := c.Write(repData); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										97
									
								
								vendor/golang.org/x/crypto/ssh/buffer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								vendor/golang.org/x/crypto/ssh/buffer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| // Copyright 2012 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"sync" | ||||
| ) | ||||
|  | ||||
| // buffer provides a linked list buffer for data exchange | ||||
| // between producer and consumer. Theoretically the buffer is | ||||
| // of unlimited capacity as it does no allocation of its own. | ||||
| type buffer struct { | ||||
| 	// protects concurrent access to head, tail and closed | ||||
| 	*sync.Cond | ||||
|  | ||||
| 	head *element // the buffer that will be read first | ||||
| 	tail *element // the buffer that will be read last | ||||
|  | ||||
| 	closed bool | ||||
| } | ||||
|  | ||||
| // An element represents a single link in a linked list. | ||||
| type element struct { | ||||
| 	buf  []byte | ||||
| 	next *element | ||||
| } | ||||
|  | ||||
| // newBuffer returns an empty buffer that is not closed. | ||||
| func newBuffer() *buffer { | ||||
| 	e := new(element) | ||||
| 	b := &buffer{ | ||||
| 		Cond: newCond(), | ||||
| 		head: e, | ||||
| 		tail: e, | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| // write makes buf available for Read to receive. | ||||
| // buf must not be modified after the call to write. | ||||
| func (b *buffer) write(buf []byte) { | ||||
| 	b.Cond.L.Lock() | ||||
| 	e := &element{buf: buf} | ||||
| 	b.tail.next = e | ||||
| 	b.tail = e | ||||
| 	b.Cond.Signal() | ||||
| 	b.Cond.L.Unlock() | ||||
| } | ||||
|  | ||||
| // eof closes the buffer. Reads from the buffer once all | ||||
| // the data has been consumed will receive io.EOF. | ||||
| func (b *buffer) eof() { | ||||
| 	b.Cond.L.Lock() | ||||
| 	b.closed = true | ||||
| 	b.Cond.Signal() | ||||
| 	b.Cond.L.Unlock() | ||||
| } | ||||
|  | ||||
| // Read reads data from the internal buffer in buf.  Reads will block | ||||
| // if no data is available, or until the buffer is closed. | ||||
| func (b *buffer) Read(buf []byte) (n int, err error) { | ||||
| 	b.Cond.L.Lock() | ||||
| 	defer b.Cond.L.Unlock() | ||||
|  | ||||
| 	for len(buf) > 0 { | ||||
| 		// if there is data in b.head, copy it | ||||
| 		if len(b.head.buf) > 0 { | ||||
| 			r := copy(buf, b.head.buf) | ||||
| 			buf, b.head.buf = buf[r:], b.head.buf[r:] | ||||
| 			n += r | ||||
| 			continue | ||||
| 		} | ||||
| 		// if there is a next buffer, make it the head | ||||
| 		if len(b.head.buf) == 0 && b.head != b.tail { | ||||
| 			b.head = b.head.next | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// if at least one byte has been copied, return | ||||
| 		if n > 0 { | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		// if nothing was read, and there is nothing outstanding | ||||
| 		// check to see if the buffer is closed. | ||||
| 		if b.closed { | ||||
| 			err = io.EOF | ||||
| 			break | ||||
| 		} | ||||
| 		// out of buffers, wait for producer | ||||
| 		b.Cond.Wait() | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										535
									
								
								vendor/golang.org/x/crypto/ssh/certs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										535
									
								
								vendor/golang.org/x/crypto/ssh/certs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,535 @@ | ||||
| // Copyright 2012 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"sort" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // These constants from [PROTOCOL.certkeys] represent the algorithm names | ||||
| // for certificate types supported by this package. | ||||
| 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" | ||||
| 	CertAlgoED25519v01  = "ssh-ed25519-cert-v01@openssh.com" | ||||
| ) | ||||
|  | ||||
| // Certificate types distinguish between host and user | ||||
| // certificates. The values can be set in the CertType field of | ||||
| // Certificate. | ||||
| const ( | ||||
| 	UserCert = 1 | ||||
| 	HostCert = 2 | ||||
| ) | ||||
|  | ||||
| // Signature represents a cryptographic signature. | ||||
| type Signature struct { | ||||
| 	Format string | ||||
| 	Blob   []byte | ||||
| } | ||||
|  | ||||
| // CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that | ||||
| // a certificate does not expire. | ||||
| const CertTimeInfinity = 1<<64 - 1 | ||||
|  | ||||
| // An Certificate represents an OpenSSH certificate as defined in | ||||
| // [PROTOCOL.certkeys]?rev=1.8. The Certificate type implements the | ||||
| // PublicKey interface, so it can be unmarshaled using | ||||
| // ParsePublicKey. | ||||
| type Certificate struct { | ||||
| 	Nonce           []byte | ||||
| 	Key             PublicKey | ||||
| 	Serial          uint64 | ||||
| 	CertType        uint32 | ||||
| 	KeyId           string | ||||
| 	ValidPrincipals []string | ||||
| 	ValidAfter      uint64 | ||||
| 	ValidBefore     uint64 | ||||
| 	Permissions | ||||
| 	Reserved     []byte | ||||
| 	SignatureKey PublicKey | ||||
| 	Signature    *Signature | ||||
| } | ||||
|  | ||||
| // genericCertData holds the key-independent part of the certificate data. | ||||
| // Overall, certificates contain an nonce, public key fields and | ||||
| // key-independent fields. | ||||
| type genericCertData struct { | ||||
| 	Serial          uint64 | ||||
| 	CertType        uint32 | ||||
| 	KeyId           string | ||||
| 	ValidPrincipals []byte | ||||
| 	ValidAfter      uint64 | ||||
| 	ValidBefore     uint64 | ||||
| 	CriticalOptions []byte | ||||
| 	Extensions      []byte | ||||
| 	Reserved        []byte | ||||
| 	SignatureKey    []byte | ||||
| 	Signature       []byte | ||||
| } | ||||
|  | ||||
| func marshalStringList(namelist []string) []byte { | ||||
| 	var to []byte | ||||
| 	for _, name := range namelist { | ||||
| 		s := struct{ N string }{name} | ||||
| 		to = append(to, Marshal(&s)...) | ||||
| 	} | ||||
| 	return to | ||||
| } | ||||
|  | ||||
| type optionsTuple struct { | ||||
| 	Key   string | ||||
| 	Value []byte | ||||
| } | ||||
|  | ||||
| type optionsTupleValue struct { | ||||
| 	Value string | ||||
| } | ||||
|  | ||||
| // serialize a map of critical options or extensions | ||||
| // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, | ||||
| // we need two length prefixes for a non-empty string value | ||||
| func marshalTuples(tups map[string]string) []byte { | ||||
| 	keys := make([]string, 0, len(tups)) | ||||
| 	for key := range tups { | ||||
| 		keys = append(keys, key) | ||||
| 	} | ||||
| 	sort.Strings(keys) | ||||
|  | ||||
| 	var ret []byte | ||||
| 	for _, key := range keys { | ||||
| 		s := optionsTuple{Key: key} | ||||
| 		if value := tups[key]; len(value) > 0 { | ||||
| 			s.Value = Marshal(&optionsTupleValue{value}) | ||||
| 		} | ||||
| 		ret = append(ret, Marshal(&s)...) | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
|  | ||||
| // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, | ||||
| // we need two length prefixes for a non-empty option value | ||||
| func parseTuples(in []byte) (map[string]string, error) { | ||||
| 	tups := map[string]string{} | ||||
| 	var lastKey string | ||||
| 	var haveLastKey bool | ||||
|  | ||||
| 	for len(in) > 0 { | ||||
| 		var key, val, extra []byte | ||||
| 		var ok bool | ||||
|  | ||||
| 		if key, in, ok = parseString(in); !ok { | ||||
| 			return nil, errShortRead | ||||
| 		} | ||||
| 		keyStr := string(key) | ||||
| 		// according to [PROTOCOL.certkeys], the names must be in | ||||
| 		// lexical order. | ||||
| 		if haveLastKey && keyStr <= lastKey { | ||||
| 			return nil, fmt.Errorf("ssh: certificate options are not in lexical order") | ||||
| 		} | ||||
| 		lastKey, haveLastKey = keyStr, true | ||||
| 		// the next field is a data field, which if non-empty has a string embedded | ||||
| 		if val, in, ok = parseString(in); !ok { | ||||
| 			return nil, errShortRead | ||||
| 		} | ||||
| 		if len(val) > 0 { | ||||
| 			val, extra, ok = parseString(val) | ||||
| 			if !ok { | ||||
| 				return nil, errShortRead | ||||
| 			} | ||||
| 			if len(extra) > 0 { | ||||
| 				return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value") | ||||
| 			} | ||||
| 			tups[keyStr] = string(val) | ||||
| 		} else { | ||||
| 			tups[keyStr] = "" | ||||
| 		} | ||||
| 	} | ||||
| 	return tups, nil | ||||
| } | ||||
|  | ||||
| func parseCert(in []byte, privAlgo string) (*Certificate, error) { | ||||
| 	nonce, rest, ok := parseString(in) | ||||
| 	if !ok { | ||||
| 		return nil, errShortRead | ||||
| 	} | ||||
|  | ||||
| 	key, rest, err := parsePubKey(rest, privAlgo) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var g genericCertData | ||||
| 	if err := Unmarshal(rest, &g); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	c := &Certificate{ | ||||
| 		Nonce:       nonce, | ||||
| 		Key:         key, | ||||
| 		Serial:      g.Serial, | ||||
| 		CertType:    g.CertType, | ||||
| 		KeyId:       g.KeyId, | ||||
| 		ValidAfter:  g.ValidAfter, | ||||
| 		ValidBefore: g.ValidBefore, | ||||
| 	} | ||||
|  | ||||
| 	for principals := g.ValidPrincipals; len(principals) > 0; { | ||||
| 		principal, rest, ok := parseString(principals) | ||||
| 		if !ok { | ||||
| 			return nil, errShortRead | ||||
| 		} | ||||
| 		c.ValidPrincipals = append(c.ValidPrincipals, string(principal)) | ||||
| 		principals = rest | ||||
| 	} | ||||
|  | ||||
| 	c.CriticalOptions, err = parseTuples(g.CriticalOptions) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	c.Extensions, err = parseTuples(g.Extensions) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	c.Reserved = g.Reserved | ||||
| 	k, err := ParsePublicKey(g.SignatureKey) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	c.SignatureKey = k | ||||
| 	c.Signature, rest, ok = parseSignatureBody(g.Signature) | ||||
| 	if !ok || len(rest) > 0 { | ||||
| 		return nil, errors.New("ssh: signature parse error") | ||||
| 	} | ||||
|  | ||||
| 	return c, nil | ||||
| } | ||||
|  | ||||
| type openSSHCertSigner struct { | ||||
| 	pub    *Certificate | ||||
| 	signer Signer | ||||
| } | ||||
|  | ||||
| type algorithmOpenSSHCertSigner struct { | ||||
| 	*openSSHCertSigner | ||||
| 	algorithmSigner AlgorithmSigner | ||||
| } | ||||
|  | ||||
| // NewCertSigner returns a Signer that signs with the given Certificate, whose | ||||
| // private key is held by signer. It returns an error if the public key in cert | ||||
| // doesn't match the key used by signer. | ||||
| func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) { | ||||
| 	if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { | ||||
| 		return nil, errors.New("ssh: signer and cert have different public key") | ||||
| 	} | ||||
|  | ||||
| 	if algorithmSigner, ok := signer.(AlgorithmSigner); ok { | ||||
| 		return &algorithmOpenSSHCertSigner{ | ||||
| 			&openSSHCertSigner{cert, signer}, algorithmSigner}, nil | ||||
| 	} else { | ||||
| 		return &openSSHCertSigner{cert, signer}, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { | ||||
| 	return s.signer.Sign(rand, data) | ||||
| } | ||||
|  | ||||
| func (s *openSSHCertSigner) PublicKey() PublicKey { | ||||
| 	return s.pub | ||||
| } | ||||
|  | ||||
| func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { | ||||
| 	return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm) | ||||
| } | ||||
|  | ||||
| const sourceAddressCriticalOption = "source-address" | ||||
|  | ||||
| // CertChecker does the work of verifying a certificate. Its methods | ||||
| // can be plugged into ClientConfig.HostKeyCallback and | ||||
| // ServerConfig.PublicKeyCallback. For the CertChecker to work, | ||||
| // minimally, the IsAuthority callback should be set. | ||||
| type CertChecker struct { | ||||
| 	// SupportedCriticalOptions lists the CriticalOptions that the | ||||
| 	// server application layer understands. These are only used | ||||
| 	// for user certificates. | ||||
| 	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. | ||||
| 	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. | ||||
| 	IsHostAuthority func(auth PublicKey, address string) bool | ||||
|  | ||||
| 	// Clock is used for verifying time stamps. If nil, time.Now | ||||
| 	// is used. | ||||
| 	Clock func() time.Time | ||||
|  | ||||
| 	// UserKeyFallback is called when CertChecker.Authenticate encounters a | ||||
| 	// public key that is not a certificate. It must implement validation | ||||
| 	// of user keys or else, if nil, all such keys are rejected. | ||||
| 	UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) | ||||
|  | ||||
| 	// HostKeyFallback is called when CertChecker.CheckHostKey encounters a | ||||
| 	// public key that is not a certificate. It must implement host key | ||||
| 	// validation or else, if nil, all such keys are rejected. | ||||
| 	HostKeyFallback HostKeyCallback | ||||
|  | ||||
| 	// IsRevoked is called for each certificate so that revocation checking | ||||
| 	// can be implemented. It should return true if the given certificate | ||||
| 	// is revoked and false otherwise. If nil, no certificates are | ||||
| 	// considered to have been revoked. | ||||
| 	IsRevoked func(cert *Certificate) bool | ||||
| } | ||||
|  | ||||
| // CheckHostKey checks a host key certificate. This method can be | ||||
| // plugged into ClientConfig.HostKeyCallback. | ||||
| func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error { | ||||
| 	cert, ok := key.(*Certificate) | ||||
| 	if !ok { | ||||
| 		if c.HostKeyFallback != nil { | ||||
| 			return c.HostKeyFallback(addr, remote, key) | ||||
| 		} | ||||
| 		return errors.New("ssh: non-certificate host key") | ||||
| 	} | ||||
| 	if cert.CertType != HostCert { | ||||
| 		return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType) | ||||
| 	} | ||||
| 	if !c.IsHostAuthority(cert.SignatureKey, addr) { | ||||
| 		return fmt.Errorf("ssh: no authorities for hostname: %v", addr) | ||||
| 	} | ||||
|  | ||||
| 	hostname, _, err := net.SplitHostPort(addr) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// Pass hostname only as principal for host certificates (consistent with OpenSSH) | ||||
| 	return c.CheckCert(hostname, cert) | ||||
| } | ||||
|  | ||||
| // Authenticate checks a user certificate. Authenticate can be used as | ||||
| // a value for ServerConfig.PublicKeyCallback. | ||||
| func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) { | ||||
| 	cert, ok := pubKey.(*Certificate) | ||||
| 	if !ok { | ||||
| 		if c.UserKeyFallback != nil { | ||||
| 			return c.UserKeyFallback(conn, pubKey) | ||||
| 		} | ||||
| 		return nil, errors.New("ssh: normal key pairs not accepted") | ||||
| 	} | ||||
|  | ||||
| 	if cert.CertType != UserCert { | ||||
| 		return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType) | ||||
| 	} | ||||
| 	if !c.IsUserAuthority(cert.SignatureKey) { | ||||
| 		return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority") | ||||
| 	} | ||||
|  | ||||
| 	if err := c.CheckCert(conn.User(), cert); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return &cert.Permissions, nil | ||||
| } | ||||
|  | ||||
| // CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and | ||||
| // the signature of the certificate. | ||||
| func (c *CertChecker) CheckCert(principal string, cert *Certificate) error { | ||||
| 	if c.IsRevoked != nil && c.IsRevoked(cert) { | ||||
| 		return fmt.Errorf("ssh: certificate serial %d revoked", cert.Serial) | ||||
| 	} | ||||
|  | ||||
| 	for opt := range cert.CriticalOptions { | ||||
| 		// sourceAddressCriticalOption will be enforced by | ||||
| 		// serverAuthenticate | ||||
| 		if opt == sourceAddressCriticalOption { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		found := false | ||||
| 		for _, supp := range c.SupportedCriticalOptions { | ||||
| 			if supp == opt { | ||||
| 				found = true | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		if !found { | ||||
| 			return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(cert.ValidPrincipals) > 0 { | ||||
| 		// By default, certs are valid for all users/hosts. | ||||
| 		found := false | ||||
| 		for _, p := range cert.ValidPrincipals { | ||||
| 			if p == principal { | ||||
| 				found = true | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		if !found { | ||||
| 			return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	clock := c.Clock | ||||
| 	if clock == nil { | ||||
| 		clock = time.Now | ||||
| 	} | ||||
|  | ||||
| 	unixNow := clock().Unix() | ||||
| 	if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) { | ||||
| 		return fmt.Errorf("ssh: cert is not yet valid") | ||||
| 	} | ||||
| 	if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) { | ||||
| 		return fmt.Errorf("ssh: cert has expired") | ||||
| 	} | ||||
| 	if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil { | ||||
| 		return fmt.Errorf("ssh: certificate signature does not verify") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // SignCert sets c.SignatureKey to the authority's public key and stores a | ||||
| // Signature, by authority, in the 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 | ||||
| 	} | ||||
| 	c.SignatureKey = authority.PublicKey() | ||||
|  | ||||
| 	sig, err := authority.Sign(rand, c.bytesForSigning()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	c.Signature = sig | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| var certAlgoNames = map[string]string{ | ||||
| 	KeyAlgoRSA:      CertAlgoRSAv01, | ||||
| 	KeyAlgoDSA:      CertAlgoDSAv01, | ||||
| 	KeyAlgoECDSA256: CertAlgoECDSA256v01, | ||||
| 	KeyAlgoECDSA384: CertAlgoECDSA384v01, | ||||
| 	KeyAlgoECDSA521: CertAlgoECDSA521v01, | ||||
| 	KeyAlgoED25519:  CertAlgoED25519v01, | ||||
| } | ||||
|  | ||||
| // certToPrivAlgo returns the underlying algorithm for a certificate algorithm. | ||||
| // Panics if a non-certificate algorithm is passed. | ||||
| func certToPrivAlgo(algo string) string { | ||||
| 	for privAlgo, pubAlgo := range certAlgoNames { | ||||
| 		if pubAlgo == algo { | ||||
| 			return privAlgo | ||||
| 		} | ||||
| 	} | ||||
| 	panic("unknown cert algorithm") | ||||
| } | ||||
|  | ||||
| func (cert *Certificate) bytesForSigning() []byte { | ||||
| 	c2 := *cert | ||||
| 	c2.Signature = nil | ||||
| 	out := c2.Marshal() | ||||
| 	// Drop trailing signature length. | ||||
| 	return out[:len(out)-4] | ||||
| } | ||||
|  | ||||
| // Marshal serializes c into OpenSSH's wire format. It is part of the | ||||
| // PublicKey interface. | ||||
| func (c *Certificate) Marshal() []byte { | ||||
| 	generic := genericCertData{ | ||||
| 		Serial:          c.Serial, | ||||
| 		CertType:        c.CertType, | ||||
| 		KeyId:           c.KeyId, | ||||
| 		ValidPrincipals: marshalStringList(c.ValidPrincipals), | ||||
| 		ValidAfter:      uint64(c.ValidAfter), | ||||
| 		ValidBefore:     uint64(c.ValidBefore), | ||||
| 		CriticalOptions: marshalTuples(c.CriticalOptions), | ||||
| 		Extensions:      marshalTuples(c.Extensions), | ||||
| 		Reserved:        c.Reserved, | ||||
| 		SignatureKey:    c.SignatureKey.Marshal(), | ||||
| 	} | ||||
| 	if c.Signature != nil { | ||||
| 		generic.Signature = Marshal(c.Signature) | ||||
| 	} | ||||
| 	genericBytes := Marshal(&generic) | ||||
| 	keyBytes := c.Key.Marshal() | ||||
| 	_, keyBytes, _ = parseString(keyBytes) | ||||
| 	prefix := Marshal(&struct { | ||||
| 		Name  string | ||||
| 		Nonce []byte | ||||
| 		Key   []byte `ssh:"rest"` | ||||
| 	}{c.Type(), c.Nonce, keyBytes}) | ||||
|  | ||||
| 	result := make([]byte, 0, len(prefix)+len(genericBytes)) | ||||
| 	result = append(result, prefix...) | ||||
| 	result = append(result, genericBytes...) | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // Type returns the key name. It is part of the PublicKey interface. | ||||
| func (c *Certificate) Type() string { | ||||
| 	algo, ok := certAlgoNames[c.Key.Type()] | ||||
| 	if !ok { | ||||
| 		panic("unknown cert key type " + c.Key.Type()) | ||||
| 	} | ||||
| 	return algo | ||||
| } | ||||
|  | ||||
| // Verify verifies a signature against the certificate's public | ||||
| // key. It is part of the PublicKey interface. | ||||
| func (c *Certificate) Verify(data []byte, sig *Signature) error { | ||||
| 	return c.Key.Verify(data, sig) | ||||
| } | ||||
|  | ||||
| func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) { | ||||
| 	format, in, ok := parseString(in) | ||||
| 	if !ok { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	out = &Signature{ | ||||
| 		Format: string(format), | ||||
| 	} | ||||
|  | ||||
| 	if out.Blob, in, ok = parseString(in); !ok { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	return out, in, ok | ||||
| } | ||||
|  | ||||
| func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) { | ||||
| 	sigBytes, rest, ok := parseString(in) | ||||
| 	if !ok { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	out, trailing, ok := parseSignatureBody(sigBytes) | ||||
| 	if !ok || len(trailing) > 0 { | ||||
| 		return nil, nil, false | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										633
									
								
								vendor/golang.org/x/crypto/ssh/channel.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										633
									
								
								vendor/golang.org/x/crypto/ssh/channel.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,633 @@ | ||||
| // Copyright 2011 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"sync" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	minPacketLength = 9 | ||||
| 	// channelMaxPacket contains the maximum number of bytes that will be | ||||
| 	// sent in a single packet. As per RFC 4253, section 6.1, 32k is also | ||||
| 	// the minimum. | ||||
| 	channelMaxPacket = 1 << 15 | ||||
| 	// We follow OpenSSH here. | ||||
| 	channelWindowSize = 64 * channelMaxPacket | ||||
| ) | ||||
|  | ||||
| // NewChannel represents an incoming request to a channel. It must either be | ||||
| // accepted for use by calling Accept, or rejected by calling Reject. | ||||
| type NewChannel interface { | ||||
| 	// Accept accepts the channel creation request. It returns the Channel | ||||
| 	// and a Go channel containing SSH requests. The Go channel must be | ||||
| 	// serviced otherwise the Channel will hang. | ||||
| 	Accept() (Channel, <-chan *Request, error) | ||||
|  | ||||
| 	// Reject rejects the channel creation request. After calling | ||||
| 	// this, no other methods on the Channel may be called. | ||||
| 	Reject(reason RejectionReason, message string) error | ||||
|  | ||||
| 	// ChannelType returns the type of the channel, as supplied by the | ||||
| 	// client. | ||||
| 	ChannelType() string | ||||
|  | ||||
| 	// ExtraData returns the arbitrary payload for this channel, as supplied | ||||
| 	// by the client. This data is specific to the channel type. | ||||
| 	ExtraData() []byte | ||||
| } | ||||
|  | ||||
| // A Channel is an ordered, reliable, flow-controlled, duplex stream | ||||
| // that is multiplexed over an SSH connection. | ||||
| type Channel interface { | ||||
| 	// Read reads up to len(data) bytes from the channel. | ||||
| 	Read(data []byte) (int, error) | ||||
|  | ||||
| 	// Write writes len(data) bytes to the channel. | ||||
| 	Write(data []byte) (int, error) | ||||
|  | ||||
| 	// Close signals end of channel use. No data may be sent after this | ||||
| 	// call. | ||||
| 	Close() error | ||||
|  | ||||
| 	// CloseWrite signals the end of sending in-band | ||||
| 	// data. Requests may still be sent, and the other side may | ||||
| 	// still send data | ||||
| 	CloseWrite() error | ||||
|  | ||||
| 	// SendRequest sends a channel request.  If wantReply is true, | ||||
| 	// it will wait for a reply and return the result as a | ||||
| 	// boolean, otherwise the return value will be false. Channel | ||||
| 	// requests are out-of-band messages so they may be sent even | ||||
| 	// if the data stream is closed or blocked by flow control. | ||||
| 	// If the channel is closed before a reply is returned, io.EOF | ||||
| 	// is returned. | ||||
| 	SendRequest(name string, wantReply bool, payload []byte) (bool, error) | ||||
|  | ||||
| 	// Stderr returns an io.ReadWriter that writes to this channel | ||||
| 	// with the extended data type set to stderr. Stderr may | ||||
| 	// safely be read and written from a different goroutine than | ||||
| 	// Read and Write respectively. | ||||
| 	Stderr() io.ReadWriter | ||||
| } | ||||
|  | ||||
| // Request is a request sent outside of the normal stream of | ||||
| // data. Requests can either be specific to an SSH channel, or they | ||||
| // can be global. | ||||
| type Request struct { | ||||
| 	Type      string | ||||
| 	WantReply bool | ||||
| 	Payload   []byte | ||||
|  | ||||
| 	ch  *channel | ||||
| 	mux *mux | ||||
| } | ||||
|  | ||||
| // Reply sends a response to a request. It must be called for all requests | ||||
| // where WantReply is true and is a no-op otherwise. The payload argument is | ||||
| // ignored for replies to channel-specific requests. | ||||
| func (r *Request) Reply(ok bool, payload []byte) error { | ||||
| 	if !r.WantReply { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if r.ch == nil { | ||||
| 		return r.mux.ackRequest(ok, payload) | ||||
| 	} | ||||
|  | ||||
| 	return r.ch.ackRequest(ok) | ||||
| } | ||||
|  | ||||
| // RejectionReason is an enumeration used when rejecting channel creation | ||||
| // requests. See RFC 4254, section 5.1. | ||||
| type RejectionReason uint32 | ||||
|  | ||||
| const ( | ||||
| 	Prohibited RejectionReason = iota + 1 | ||||
| 	ConnectionFailed | ||||
| 	UnknownChannelType | ||||
| 	ResourceShortage | ||||
| ) | ||||
|  | ||||
| // String converts the rejection reason to human readable form. | ||||
| func (r RejectionReason) String() string { | ||||
| 	switch r { | ||||
| 	case Prohibited: | ||||
| 		return "administratively prohibited" | ||||
| 	case ConnectionFailed: | ||||
| 		return "connect failed" | ||||
| 	case UnknownChannelType: | ||||
| 		return "unknown channel type" | ||||
| 	case ResourceShortage: | ||||
| 		return "resource shortage" | ||||
| 	} | ||||
| 	return fmt.Sprintf("unknown reason %d", int(r)) | ||||
| } | ||||
|  | ||||
| func min(a uint32, b int) uint32 { | ||||
| 	if a < uint32(b) { | ||||
| 		return a | ||||
| 	} | ||||
| 	return uint32(b) | ||||
| } | ||||
|  | ||||
| type channelDirection uint8 | ||||
|  | ||||
| const ( | ||||
| 	channelInbound channelDirection = iota | ||||
| 	channelOutbound | ||||
| ) | ||||
|  | ||||
| // channel is an implementation of the Channel interface that works | ||||
| // with the mux class. | ||||
| type channel struct { | ||||
| 	// R/O after creation | ||||
| 	chanType          string | ||||
| 	extraData         []byte | ||||
| 	localId, remoteId uint32 | ||||
|  | ||||
| 	// maxIncomingPayload and maxRemotePayload are the maximum | ||||
| 	// payload sizes of normal and extended data packets for | ||||
| 	// receiving and sending, respectively. The wire packet will | ||||
| 	// be 9 or 13 bytes larger (excluding encryption overhead). | ||||
| 	maxIncomingPayload uint32 | ||||
| 	maxRemotePayload   uint32 | ||||
|  | ||||
| 	mux *mux | ||||
|  | ||||
| 	// decided is set to true if an accept or reject message has been sent | ||||
| 	// (for outbound channels) or received (for inbound channels). | ||||
| 	decided bool | ||||
|  | ||||
| 	// direction contains either channelOutbound, for channels created | ||||
| 	// locally, or channelInbound, for channels created by the peer. | ||||
| 	direction channelDirection | ||||
|  | ||||
| 	// Pending internal channel messages. | ||||
| 	msg chan interface{} | ||||
|  | ||||
| 	// Since requests have no ID, there can be only one request | ||||
| 	// with WantReply=true outstanding.  This lock is held by a | ||||
| 	// goroutine that has such an outgoing request pending. | ||||
| 	sentRequestMu sync.Mutex | ||||
|  | ||||
| 	incomingRequests chan *Request | ||||
|  | ||||
| 	sentEOF bool | ||||
|  | ||||
| 	// thread-safe data | ||||
| 	remoteWin  window | ||||
| 	pending    *buffer | ||||
| 	extPending *buffer | ||||
|  | ||||
| 	// windowMu protects myWindow, the flow-control window. | ||||
| 	windowMu sync.Mutex | ||||
| 	myWindow uint32 | ||||
|  | ||||
| 	// writeMu serializes calls to mux.conn.writePacket() and | ||||
| 	// protects sentClose and packetPool. This mutex must be | ||||
| 	// different from windowMu, as writePacket can block if there | ||||
| 	// is a key exchange pending. | ||||
| 	writeMu   sync.Mutex | ||||
| 	sentClose bool | ||||
|  | ||||
| 	// packetPool has a buffer for each extended channel ID to | ||||
| 	// save allocations during writes. | ||||
| 	packetPool map[uint32][]byte | ||||
| } | ||||
|  | ||||
| // writePacket sends a packet. If the packet is a channel close, it updates | ||||
| // sentClose. This method takes the lock c.writeMu. | ||||
| func (ch *channel) writePacket(packet []byte) error { | ||||
| 	ch.writeMu.Lock() | ||||
| 	if ch.sentClose { | ||||
| 		ch.writeMu.Unlock() | ||||
| 		return io.EOF | ||||
| 	} | ||||
| 	ch.sentClose = (packet[0] == msgChannelClose) | ||||
| 	err := ch.mux.conn.writePacket(packet) | ||||
| 	ch.writeMu.Unlock() | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (ch *channel) sendMessage(msg interface{}) error { | ||||
| 	if debugMux { | ||||
| 		log.Printf("send(%d): %#v", ch.mux.chanList.offset, msg) | ||||
| 	} | ||||
|  | ||||
| 	p := Marshal(msg) | ||||
| 	binary.BigEndian.PutUint32(p[1:], ch.remoteId) | ||||
| 	return ch.writePacket(p) | ||||
| } | ||||
|  | ||||
| // WriteExtended writes data to a specific extended stream. These streams are | ||||
| // used, for example, for stderr. | ||||
| func (ch *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err error) { | ||||
| 	if ch.sentEOF { | ||||
| 		return 0, io.EOF | ||||
| 	} | ||||
| 	// 1 byte message type, 4 bytes remoteId, 4 bytes data length | ||||
| 	opCode := byte(msgChannelData) | ||||
| 	headerLength := uint32(9) | ||||
| 	if extendedCode > 0 { | ||||
| 		headerLength += 4 | ||||
| 		opCode = msgChannelExtendedData | ||||
| 	} | ||||
|  | ||||
| 	ch.writeMu.Lock() | ||||
| 	packet := ch.packetPool[extendedCode] | ||||
| 	// We don't remove the buffer from packetPool, so | ||||
| 	// WriteExtended calls from different goroutines will be | ||||
| 	// flagged as errors by the race detector. | ||||
| 	ch.writeMu.Unlock() | ||||
|  | ||||
| 	for len(data) > 0 { | ||||
| 		space := min(ch.maxRemotePayload, len(data)) | ||||
| 		if space, err = ch.remoteWin.reserve(space); err != nil { | ||||
| 			return n, err | ||||
| 		} | ||||
| 		if want := headerLength + space; uint32(cap(packet)) < want { | ||||
| 			packet = make([]byte, want) | ||||
| 		} else { | ||||
| 			packet = packet[:want] | ||||
| 		} | ||||
|  | ||||
| 		todo := data[:space] | ||||
|  | ||||
| 		packet[0] = opCode | ||||
| 		binary.BigEndian.PutUint32(packet[1:], ch.remoteId) | ||||
| 		if extendedCode > 0 { | ||||
| 			binary.BigEndian.PutUint32(packet[5:], uint32(extendedCode)) | ||||
| 		} | ||||
| 		binary.BigEndian.PutUint32(packet[headerLength-4:], uint32(len(todo))) | ||||
| 		copy(packet[headerLength:], todo) | ||||
| 		if err = ch.writePacket(packet); err != nil { | ||||
| 			return n, err | ||||
| 		} | ||||
|  | ||||
| 		n += len(todo) | ||||
| 		data = data[len(todo):] | ||||
| 	} | ||||
|  | ||||
| 	ch.writeMu.Lock() | ||||
| 	ch.packetPool[extendedCode] = packet | ||||
| 	ch.writeMu.Unlock() | ||||
|  | ||||
| 	return n, err | ||||
| } | ||||
|  | ||||
| func (ch *channel) handleData(packet []byte) error { | ||||
| 	headerLen := 9 | ||||
| 	isExtendedData := packet[0] == msgChannelExtendedData | ||||
| 	if isExtendedData { | ||||
| 		headerLen = 13 | ||||
| 	} | ||||
| 	if len(packet) < headerLen { | ||||
| 		// malformed data packet | ||||
| 		return parseError(packet[0]) | ||||
| 	} | ||||
|  | ||||
| 	var extended uint32 | ||||
| 	if isExtendedData { | ||||
| 		extended = binary.BigEndian.Uint32(packet[5:]) | ||||
| 	} | ||||
|  | ||||
| 	length := binary.BigEndian.Uint32(packet[headerLen-4 : headerLen]) | ||||
| 	if length == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if length > ch.maxIncomingPayload { | ||||
| 		// TODO(hanwen): should send Disconnect? | ||||
| 		return errors.New("ssh: incoming packet exceeds maximum payload size") | ||||
| 	} | ||||
|  | ||||
| 	data := packet[headerLen:] | ||||
| 	if length != uint32(len(data)) { | ||||
| 		return errors.New("ssh: wrong packet length") | ||||
| 	} | ||||
|  | ||||
| 	ch.windowMu.Lock() | ||||
| 	if ch.myWindow < length { | ||||
| 		ch.windowMu.Unlock() | ||||
| 		// TODO(hanwen): should send Disconnect with reason? | ||||
| 		return errors.New("ssh: remote side wrote too much") | ||||
| 	} | ||||
| 	ch.myWindow -= length | ||||
| 	ch.windowMu.Unlock() | ||||
|  | ||||
| 	if extended == 1 { | ||||
| 		ch.extPending.write(data) | ||||
| 	} else if extended > 0 { | ||||
| 		// discard other extended data. | ||||
| 	} else { | ||||
| 		ch.pending.write(data) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *channel) adjustWindow(n uint32) error { | ||||
| 	c.windowMu.Lock() | ||||
| 	// Since myWindow is managed on our side, and can never exceed | ||||
| 	// the initial window setting, we don't worry about overflow. | ||||
| 	c.myWindow += uint32(n) | ||||
| 	c.windowMu.Unlock() | ||||
| 	return c.sendMessage(windowAdjustMsg{ | ||||
| 		AdditionalBytes: uint32(n), | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error) { | ||||
| 	switch extended { | ||||
| 	case 1: | ||||
| 		n, err = c.extPending.Read(data) | ||||
| 	case 0: | ||||
| 		n, err = c.pending.Read(data) | ||||
| 	default: | ||||
| 		return 0, fmt.Errorf("ssh: extended code %d unimplemented", extended) | ||||
| 	} | ||||
|  | ||||
| 	if n > 0 { | ||||
| 		err = c.adjustWindow(uint32(n)) | ||||
| 		// sendWindowAdjust can return io.EOF if the remote | ||||
| 		// peer has closed the connection, however we want to | ||||
| 		// defer forwarding io.EOF to the caller of Read until | ||||
| 		// the buffer has been drained. | ||||
| 		if n > 0 && err == io.EOF { | ||||
| 			err = nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return n, err | ||||
| } | ||||
|  | ||||
| func (c *channel) close() { | ||||
| 	c.pending.eof() | ||||
| 	c.extPending.eof() | ||||
| 	close(c.msg) | ||||
| 	close(c.incomingRequests) | ||||
| 	c.writeMu.Lock() | ||||
| 	// This is not necessary for a normal channel teardown, but if | ||||
| 	// there was another error, it is. | ||||
| 	c.sentClose = true | ||||
| 	c.writeMu.Unlock() | ||||
| 	// Unblock writers. | ||||
| 	c.remoteWin.close() | ||||
| } | ||||
|  | ||||
| // responseMessageReceived is called when a success or failure message is | ||||
| // received on a channel to check that such a message is reasonable for the | ||||
| // given channel. | ||||
| func (ch *channel) responseMessageReceived() error { | ||||
| 	if ch.direction == channelInbound { | ||||
| 		return errors.New("ssh: channel response message received on inbound channel") | ||||
| 	} | ||||
| 	if ch.decided { | ||||
| 		return errors.New("ssh: duplicate response received for channel") | ||||
| 	} | ||||
| 	ch.decided = true | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (ch *channel) handlePacket(packet []byte) error { | ||||
| 	switch packet[0] { | ||||
| 	case msgChannelData, msgChannelExtendedData: | ||||
| 		return ch.handleData(packet) | ||||
| 	case msgChannelClose: | ||||
| 		ch.sendMessage(channelCloseMsg{PeersID: ch.remoteId}) | ||||
| 		ch.mux.chanList.remove(ch.localId) | ||||
| 		ch.close() | ||||
| 		return nil | ||||
| 	case msgChannelEOF: | ||||
| 		// RFC 4254 is mute on how EOF affects dataExt messages but | ||||
| 		// it is logical to signal EOF at the same time. | ||||
| 		ch.extPending.eof() | ||||
| 		ch.pending.eof() | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	decoded, err := decode(packet) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	switch msg := decoded.(type) { | ||||
| 	case *channelOpenFailureMsg: | ||||
| 		if err := ch.responseMessageReceived(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		ch.mux.chanList.remove(msg.PeersID) | ||||
| 		ch.msg <- msg | ||||
| 	case *channelOpenConfirmMsg: | ||||
| 		if err := ch.responseMessageReceived(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { | ||||
| 			return fmt.Errorf("ssh: invalid MaxPacketSize %d from peer", msg.MaxPacketSize) | ||||
| 		} | ||||
| 		ch.remoteId = msg.MyID | ||||
| 		ch.maxRemotePayload = msg.MaxPacketSize | ||||
| 		ch.remoteWin.add(msg.MyWindow) | ||||
| 		ch.msg <- msg | ||||
| 	case *windowAdjustMsg: | ||||
| 		if !ch.remoteWin.add(msg.AdditionalBytes) { | ||||
| 			return fmt.Errorf("ssh: invalid window update for %d bytes", msg.AdditionalBytes) | ||||
| 		} | ||||
| 	case *channelRequestMsg: | ||||
| 		req := Request{ | ||||
| 			Type:      msg.Request, | ||||
| 			WantReply: msg.WantReply, | ||||
| 			Payload:   msg.RequestSpecificData, | ||||
| 			ch:        ch, | ||||
| 		} | ||||
|  | ||||
| 		ch.incomingRequests <- &req | ||||
| 	default: | ||||
| 		ch.msg <- msg | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *mux) newChannel(chanType string, direction channelDirection, extraData []byte) *channel { | ||||
| 	ch := &channel{ | ||||
| 		remoteWin:        window{Cond: newCond()}, | ||||
| 		myWindow:         channelWindowSize, | ||||
| 		pending:          newBuffer(), | ||||
| 		extPending:       newBuffer(), | ||||
| 		direction:        direction, | ||||
| 		incomingRequests: make(chan *Request, chanSize), | ||||
| 		msg:              make(chan interface{}, chanSize), | ||||
| 		chanType:         chanType, | ||||
| 		extraData:        extraData, | ||||
| 		mux:              m, | ||||
| 		packetPool:       make(map[uint32][]byte), | ||||
| 	} | ||||
| 	ch.localId = m.chanList.add(ch) | ||||
| 	return ch | ||||
| } | ||||
|  | ||||
| var errUndecided = errors.New("ssh: must Accept or Reject channel") | ||||
| var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once") | ||||
|  | ||||
| type extChannel struct { | ||||
| 	code uint32 | ||||
| 	ch   *channel | ||||
| } | ||||
|  | ||||
| func (e *extChannel) Write(data []byte) (n int, err error) { | ||||
| 	return e.ch.WriteExtended(data, e.code) | ||||
| } | ||||
|  | ||||
| func (e *extChannel) Read(data []byte) (n int, err error) { | ||||
| 	return e.ch.ReadExtended(data, e.code) | ||||
| } | ||||
|  | ||||
| func (ch *channel) Accept() (Channel, <-chan *Request, error) { | ||||
| 	if ch.decided { | ||||
| 		return nil, nil, errDecidedAlready | ||||
| 	} | ||||
| 	ch.maxIncomingPayload = channelMaxPacket | ||||
| 	confirm := channelOpenConfirmMsg{ | ||||
| 		PeersID:       ch.remoteId, | ||||
| 		MyID:          ch.localId, | ||||
| 		MyWindow:      ch.myWindow, | ||||
| 		MaxPacketSize: ch.maxIncomingPayload, | ||||
| 	} | ||||
| 	ch.decided = true | ||||
| 	if err := ch.sendMessage(confirm); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	return ch, ch.incomingRequests, nil | ||||
| } | ||||
|  | ||||
| func (ch *channel) Reject(reason RejectionReason, message string) error { | ||||
| 	if ch.decided { | ||||
| 		return errDecidedAlready | ||||
| 	} | ||||
| 	reject := channelOpenFailureMsg{ | ||||
| 		PeersID:  ch.remoteId, | ||||
| 		Reason:   reason, | ||||
| 		Message:  message, | ||||
| 		Language: "en", | ||||
| 	} | ||||
| 	ch.decided = true | ||||
| 	return ch.sendMessage(reject) | ||||
| } | ||||
|  | ||||
| func (ch *channel) Read(data []byte) (int, error) { | ||||
| 	if !ch.decided { | ||||
| 		return 0, errUndecided | ||||
| 	} | ||||
| 	return ch.ReadExtended(data, 0) | ||||
| } | ||||
|  | ||||
| func (ch *channel) Write(data []byte) (int, error) { | ||||
| 	if !ch.decided { | ||||
| 		return 0, errUndecided | ||||
| 	} | ||||
| 	return ch.WriteExtended(data, 0) | ||||
| } | ||||
|  | ||||
| func (ch *channel) CloseWrite() error { | ||||
| 	if !ch.decided { | ||||
| 		return errUndecided | ||||
| 	} | ||||
| 	ch.sentEOF = true | ||||
| 	return ch.sendMessage(channelEOFMsg{ | ||||
| 		PeersID: ch.remoteId}) | ||||
| } | ||||
|  | ||||
| func (ch *channel) Close() error { | ||||
| 	if !ch.decided { | ||||
| 		return errUndecided | ||||
| 	} | ||||
|  | ||||
| 	return ch.sendMessage(channelCloseMsg{ | ||||
| 		PeersID: ch.remoteId}) | ||||
| } | ||||
|  | ||||
| // Extended returns an io.ReadWriter that sends and receives data on the given, | ||||
| // SSH extended stream. Such streams are used, for example, for stderr. | ||||
| func (ch *channel) Extended(code uint32) io.ReadWriter { | ||||
| 	if !ch.decided { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return &extChannel{code, ch} | ||||
| } | ||||
|  | ||||
| func (ch *channel) Stderr() io.ReadWriter { | ||||
| 	return ch.Extended(1) | ||||
| } | ||||
|  | ||||
| func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) { | ||||
| 	if !ch.decided { | ||||
| 		return false, errUndecided | ||||
| 	} | ||||
|  | ||||
| 	if wantReply { | ||||
| 		ch.sentRequestMu.Lock() | ||||
| 		defer ch.sentRequestMu.Unlock() | ||||
| 	} | ||||
|  | ||||
| 	msg := channelRequestMsg{ | ||||
| 		PeersID:             ch.remoteId, | ||||
| 		Request:             name, | ||||
| 		WantReply:           wantReply, | ||||
| 		RequestSpecificData: payload, | ||||
| 	} | ||||
|  | ||||
| 	if err := ch.sendMessage(msg); err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
|  | ||||
| 	if wantReply { | ||||
| 		m, ok := (<-ch.msg) | ||||
| 		if !ok { | ||||
| 			return false, io.EOF | ||||
| 		} | ||||
| 		switch m.(type) { | ||||
| 		case *channelRequestFailureMsg: | ||||
| 			return false, nil | ||||
| 		case *channelRequestSuccessMsg: | ||||
| 			return true, nil | ||||
| 		default: | ||||
| 			return false, fmt.Errorf("ssh: unexpected response to channel request: %#v", m) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return false, nil | ||||
| } | ||||
|  | ||||
| // ackRequest either sends an ack or nack to the channel request. | ||||
| func (ch *channel) ackRequest(ok bool) error { | ||||
| 	if !ch.decided { | ||||
| 		return errUndecided | ||||
| 	} | ||||
|  | ||||
| 	var msg interface{} | ||||
| 	if !ok { | ||||
| 		msg = channelRequestFailureMsg{ | ||||
| 			PeersID: ch.remoteId, | ||||
| 		} | ||||
| 	} else { | ||||
| 		msg = channelRequestSuccessMsg{ | ||||
| 			PeersID: ch.remoteId, | ||||
| 		} | ||||
| 	} | ||||
| 	return ch.sendMessage(msg) | ||||
| } | ||||
|  | ||||
| func (ch *channel) ChannelType() string { | ||||
| 	return ch.chanType | ||||
| } | ||||
|  | ||||
| func (ch *channel) ExtraData() []byte { | ||||
| 	return ch.extraData | ||||
| } | ||||
							
								
								
									
										770
									
								
								vendor/golang.org/x/crypto/ssh/cipher.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										770
									
								
								vendor/golang.org/x/crypto/ssh/cipher.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,770 @@ | ||||
| // Copyright 2011 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"crypto/aes" | ||||
| 	"crypto/cipher" | ||||
| 	"crypto/des" | ||||
| 	"crypto/rc4" | ||||
| 	"crypto/subtle" | ||||
| 	"encoding/binary" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"math/bits" | ||||
|  | ||||
| 	"golang.org/x/crypto/internal/chacha20" | ||||
| 	"golang.org/x/crypto/poly1305" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher. | ||||
|  | ||||
| 	// RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations | ||||
| 	// MUST be able to process (plus a few more kilobytes for padding and mac). The RFC | ||||
| 	// indicates implementations SHOULD be able to handle larger packet sizes, but then | ||||
| 	// waffles on about reasonable limits. | ||||
| 	// | ||||
| 	// OpenSSH caps their maxPacket at 256kB so we choose to do | ||||
| 	// the same. maxPacket is also used to ensure that uint32 | ||||
| 	// length fields do not overflow, so it should remain well | ||||
| 	// below 4G. | ||||
| 	maxPacket = 256 * 1024 | ||||
| ) | ||||
|  | ||||
| // noneCipher implements cipher.Stream and provides no encryption. It is used | ||||
| // by the transport before the first key-exchange. | ||||
| type noneCipher struct{} | ||||
|  | ||||
| func (c noneCipher) XORKeyStream(dst, src []byte) { | ||||
| 	copy(dst, src) | ||||
| } | ||||
|  | ||||
| func newAESCTR(key, iv []byte) (cipher.Stream, error) { | ||||
| 	c, err := aes.NewCipher(key) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return cipher.NewCTR(c, iv), nil | ||||
| } | ||||
|  | ||||
| func newRC4(key, iv []byte) (cipher.Stream, error) { | ||||
| 	return rc4.NewCipher(key) | ||||
| } | ||||
|  | ||||
| type cipherMode struct { | ||||
| 	keySize int | ||||
| 	ivSize  int | ||||
| 	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) { | ||||
| 		stream, err := createFunc(key, iv) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		var streamDump []byte | ||||
| 		if skip > 0 { | ||||
| 			streamDump = make([]byte, 512) | ||||
| 		} | ||||
|  | ||||
| 		for remainingToDump := skip; remainingToDump > 0; { | ||||
| 			dumpThisTime := remainingToDump | ||||
| 			if dumpThisTime > len(streamDump) { | ||||
| 				dumpThisTime = len(streamDump) | ||||
| 			} | ||||
| 			stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime]) | ||||
| 			remainingToDump -= dumpThisTime | ||||
| 		} | ||||
|  | ||||
| 		mac := macModes[algs.MAC].new(macKey) | ||||
| 		return &streamPacketCipher{ | ||||
| 			mac:       mac, | ||||
| 			etm:       macModes[algs.MAC].etm, | ||||
| 			macResult: make([]byte, mac.Size()), | ||||
| 			cipher:    stream, | ||||
| 		}, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // cipherModes documents properties of supported ciphers. Ciphers not included | ||||
| // are not supported and will not be negotiated, even if explicitly requested in | ||||
| // ClientConfig.Crypto.Ciphers. | ||||
| var cipherModes = map[string]*cipherMode{ | ||||
| 	// Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms | ||||
| 	// are defined in the order specified in the RFC. | ||||
| 	"aes128-ctr": {16, aes.BlockSize, streamCipherMode(0, newAESCTR)}, | ||||
| 	"aes192-ctr": {24, aes.BlockSize, streamCipherMode(0, newAESCTR)}, | ||||
| 	"aes256-ctr": {32, aes.BlockSize, streamCipherMode(0, newAESCTR)}, | ||||
|  | ||||
| 	// Ciphers from RFC4345, which introduces security-improved arcfour ciphers. | ||||
| 	// They are defined in the order specified in the RFC. | ||||
| 	"arcfour128": {16, 0, streamCipherMode(1536, newRC4)}, | ||||
| 	"arcfour256": {32, 0, streamCipherMode(1536, newRC4)}, | ||||
|  | ||||
| 	// Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol. | ||||
| 	// Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and | ||||
| 	// RC4) has problems with weak keys, and should be used with caution." | ||||
| 	// RFC4345 introduces improved versions of Arcfour. | ||||
| 	"arcfour": {16, 0, streamCipherMode(0, newRC4)}, | ||||
|  | ||||
| 	// AEAD ciphers | ||||
| 	gcmCipherID:        {16, 12, newGCMCipher}, | ||||
| 	chacha20Poly1305ID: {64, 0, newChaCha20Cipher}, | ||||
|  | ||||
| 	// CBC mode is insecure and so is not included in the default config. | ||||
| 	// (See http://www.isg.rhul.ac.uk/~kp/SandPfinal.pdf). If absolutely | ||||
| 	// needed, it's possible to specify a custom Config to enable it. | ||||
| 	// You should expect that an active attacker can recover plaintext if | ||||
| 	// you do. | ||||
| 	aes128cbcID: {16, aes.BlockSize, newAESCBCCipher}, | ||||
|  | ||||
| 	// 3des-cbc is insecure and is not included in the default | ||||
| 	// config. | ||||
| 	tripledescbcID: {24, des.BlockSize, newTripleDESCBCCipher}, | ||||
| } | ||||
|  | ||||
| // prefixLen is the length of the packet prefix that contains the packet length | ||||
| // and number of padding bytes. | ||||
| const prefixLen = 5 | ||||
|  | ||||
| // streamPacketCipher is a packetCipher using a stream cipher. | ||||
| type streamPacketCipher struct { | ||||
| 	mac    hash.Hash | ||||
| 	cipher cipher.Stream | ||||
| 	etm    bool | ||||
|  | ||||
| 	// The following members are to avoid per-packet allocations. | ||||
| 	prefix      [prefixLen]byte | ||||
| 	seqNumBytes [4]byte | ||||
| 	padding     [2 * packetSizeMultiple]byte | ||||
| 	packetData  []byte | ||||
| 	macResult   []byte | ||||
| } | ||||
|  | ||||
| // readPacket reads and decrypt a single packet from the reader argument. | ||||
| func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | ||||
| 	if _, err := io.ReadFull(r, s.prefix[:]); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var encryptedPaddingLength [1]byte | ||||
| 	if s.mac != nil && s.etm { | ||||
| 		copy(encryptedPaddingLength[:], s.prefix[4:5]) | ||||
| 		s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5]) | ||||
| 	} else { | ||||
| 		s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) | ||||
| 	} | ||||
|  | ||||
| 	length := binary.BigEndian.Uint32(s.prefix[0:4]) | ||||
| 	paddingLength := uint32(s.prefix[4]) | ||||
|  | ||||
| 	var macSize uint32 | ||||
| 	if s.mac != nil { | ||||
| 		s.mac.Reset() | ||||
| 		binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) | ||||
| 		s.mac.Write(s.seqNumBytes[:]) | ||||
| 		if s.etm { | ||||
| 			s.mac.Write(s.prefix[:4]) | ||||
| 			s.mac.Write(encryptedPaddingLength[:]) | ||||
| 		} else { | ||||
| 			s.mac.Write(s.prefix[:]) | ||||
| 		} | ||||
| 		macSize = uint32(s.mac.Size()) | ||||
| 	} | ||||
|  | ||||
| 	if length <= paddingLength+1 { | ||||
| 		return nil, errors.New("ssh: invalid packet length, packet too small") | ||||
| 	} | ||||
|  | ||||
| 	if length > maxPacket { | ||||
| 		return nil, errors.New("ssh: invalid packet length, packet too large") | ||||
| 	} | ||||
|  | ||||
| 	// the maxPacket check above ensures that length-1+macSize | ||||
| 	// does not overflow. | ||||
| 	if uint32(cap(s.packetData)) < length-1+macSize { | ||||
| 		s.packetData = make([]byte, length-1+macSize) | ||||
| 	} else { | ||||
| 		s.packetData = s.packetData[:length-1+macSize] | ||||
| 	} | ||||
|  | ||||
| 	if _, err := io.ReadFull(r, s.packetData); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	mac := s.packetData[length-1:] | ||||
| 	data := s.packetData[:length-1] | ||||
|  | ||||
| 	if s.mac != nil && s.etm { | ||||
| 		s.mac.Write(data) | ||||
| 	} | ||||
|  | ||||
| 	s.cipher.XORKeyStream(data, data) | ||||
|  | ||||
| 	if s.mac != nil { | ||||
| 		if !s.etm { | ||||
| 			s.mac.Write(data) | ||||
| 		} | ||||
| 		s.macResult = s.mac.Sum(s.macResult[:0]) | ||||
| 		if subtle.ConstantTimeCompare(s.macResult, mac) != 1 { | ||||
| 			return nil, errors.New("ssh: MAC failure") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return s.packetData[:length-paddingLength-1], nil | ||||
| } | ||||
|  | ||||
| // writePacket encrypts and sends a packet of data to the writer argument | ||||
| func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | ||||
| 	if len(packet) > maxPacket { | ||||
| 		return errors.New("ssh: packet too large") | ||||
| 	} | ||||
|  | ||||
| 	aadlen := 0 | ||||
| 	if s.mac != nil && s.etm { | ||||
| 		// packet length is not encrypted for EtM modes | ||||
| 		aadlen = 4 | ||||
| 	} | ||||
|  | ||||
| 	paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple | ||||
| 	if paddingLength < 4 { | ||||
| 		paddingLength += packetSizeMultiple | ||||
| 	} | ||||
|  | ||||
| 	length := len(packet) + 1 + paddingLength | ||||
| 	binary.BigEndian.PutUint32(s.prefix[:], uint32(length)) | ||||
| 	s.prefix[4] = byte(paddingLength) | ||||
| 	padding := s.padding[:paddingLength] | ||||
| 	if _, err := io.ReadFull(rand, padding); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if s.mac != nil { | ||||
| 		s.mac.Reset() | ||||
| 		binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) | ||||
| 		s.mac.Write(s.seqNumBytes[:]) | ||||
|  | ||||
| 		if s.etm { | ||||
| 			// For EtM algorithms, the packet length must stay unencrypted, | ||||
| 			// but the following data (padding length) must be encrypted | ||||
| 			s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5]) | ||||
| 		} | ||||
|  | ||||
| 		s.mac.Write(s.prefix[:]) | ||||
|  | ||||
| 		if !s.etm { | ||||
| 			// For non-EtM algorithms, the algorithm is applied on unencrypted data | ||||
| 			s.mac.Write(packet) | ||||
| 			s.mac.Write(padding) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if !(s.mac != nil && s.etm) { | ||||
| 		// For EtM algorithms, the padding length has already been encrypted | ||||
| 		// and the packet length must remain unencrypted | ||||
| 		s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) | ||||
| 	} | ||||
|  | ||||
| 	s.cipher.XORKeyStream(packet, packet) | ||||
| 	s.cipher.XORKeyStream(padding, padding) | ||||
|  | ||||
| 	if s.mac != nil && s.etm { | ||||
| 		// For EtM algorithms, packet and padding must be encrypted | ||||
| 		s.mac.Write(packet) | ||||
| 		s.mac.Write(padding) | ||||
| 	} | ||||
|  | ||||
| 	if _, err := w.Write(s.prefix[:]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err := w.Write(packet); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err := w.Write(padding); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if s.mac != nil { | ||||
| 		s.macResult = s.mac.Sum(s.macResult[:0]) | ||||
| 		if _, err := w.Write(s.macResult); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type gcmCipher struct { | ||||
| 	aead   cipher.AEAD | ||||
| 	prefix [4]byte | ||||
| 	iv     []byte | ||||
| 	buf    []byte | ||||
| } | ||||
|  | ||||
| func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) { | ||||
| 	c, err := aes.NewCipher(key) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	aead, err := cipher.NewGCM(c) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return &gcmCipher{ | ||||
| 		aead: aead, | ||||
| 		iv:   iv, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| const gcmTagSize = 16 | ||||
|  | ||||
| func (c *gcmCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | ||||
| 	// Pad out to multiple of 16 bytes. This is different from the | ||||
| 	// stream cipher because that encrypts the length too. | ||||
| 	padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple) | ||||
| 	if padding < 4 { | ||||
| 		padding += packetSizeMultiple | ||||
| 	} | ||||
|  | ||||
| 	length := uint32(len(packet) + int(padding) + 1) | ||||
| 	binary.BigEndian.PutUint32(c.prefix[:], length) | ||||
| 	if _, err := w.Write(c.prefix[:]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if cap(c.buf) < int(length) { | ||||
| 		c.buf = make([]byte, length) | ||||
| 	} else { | ||||
| 		c.buf = c.buf[:length] | ||||
| 	} | ||||
|  | ||||
| 	c.buf[0] = padding | ||||
| 	copy(c.buf[1:], packet) | ||||
| 	if _, err := io.ReadFull(rand, c.buf[1+len(packet):]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	c.buf = c.aead.Seal(c.buf[:0], c.iv, c.buf, c.prefix[:]) | ||||
| 	if _, err := w.Write(c.buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	c.incIV() | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *gcmCipher) incIV() { | ||||
| 	for i := 4 + 7; i >= 4; i-- { | ||||
| 		c.iv[i]++ | ||||
| 		if c.iv[i] != 0 { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *gcmCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | ||||
| 	if _, err := io.ReadFull(r, c.prefix[:]); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	length := binary.BigEndian.Uint32(c.prefix[:]) | ||||
| 	if length > maxPacket { | ||||
| 		return nil, errors.New("ssh: max packet length exceeded") | ||||
| 	} | ||||
|  | ||||
| 	if cap(c.buf) < int(length+gcmTagSize) { | ||||
| 		c.buf = make([]byte, length+gcmTagSize) | ||||
| 	} else { | ||||
| 		c.buf = c.buf[:length+gcmTagSize] | ||||
| 	} | ||||
|  | ||||
| 	if _, err := io.ReadFull(r, c.buf); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	plain, err := c.aead.Open(c.buf[:0], c.iv, c.buf, c.prefix[:]) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	c.incIV() | ||||
|  | ||||
| 	padding := plain[0] | ||||
| 	if padding < 4 { | ||||
| 		// padding is a byte, so it automatically satisfies | ||||
| 		// the maximum size, which is 255. | ||||
| 		return nil, fmt.Errorf("ssh: illegal padding %d", padding) | ||||
| 	} | ||||
|  | ||||
| 	if int(padding+1) >= len(plain) { | ||||
| 		return nil, fmt.Errorf("ssh: padding %d too large", padding) | ||||
| 	} | ||||
| 	plain = plain[1 : length-uint32(padding)] | ||||
| 	return plain, nil | ||||
| } | ||||
|  | ||||
| // cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1 | ||||
| type cbcCipher struct { | ||||
| 	mac       hash.Hash | ||||
| 	macSize   uint32 | ||||
| 	decrypter cipher.BlockMode | ||||
| 	encrypter cipher.BlockMode | ||||
|  | ||||
| 	// The following members are to avoid per-packet allocations. | ||||
| 	seqNumBytes [4]byte | ||||
| 	packetData  []byte | ||||
| 	macResult   []byte | ||||
|  | ||||
| 	// Amount of data we should still read to hide which | ||||
| 	// verification error triggered. | ||||
| 	oracleCamouflage uint32 | ||||
| } | ||||
|  | ||||
| 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), | ||||
| 		encrypter:  cipher.NewCBCEncrypter(c, iv), | ||||
| 		packetData: make([]byte, 1024), | ||||
| 	} | ||||
| 	if cbc.mac != nil { | ||||
| 		cbc.macSize = uint32(cbc.mac.Size()) | ||||
| 	} | ||||
|  | ||||
| 	return cbc, nil | ||||
| } | ||||
|  | ||||
| func newAESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { | ||||
| 	c, err := aes.NewCipher(key) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	cbc, err := newCBCCipher(c, key, iv, macKey, algs) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return cbc, nil | ||||
| } | ||||
|  | ||||
| func newTripleDESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { | ||||
| 	c, err := des.NewTripleDESCipher(key) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	cbc, err := newCBCCipher(c, key, iv, macKey, algs) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return cbc, nil | ||||
| } | ||||
|  | ||||
| func maxUInt32(a, b int) uint32 { | ||||
| 	if a > b { | ||||
| 		return uint32(a) | ||||
| 	} | ||||
| 	return uint32(b) | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	cbcMinPacketSizeMultiple = 8 | ||||
| 	cbcMinPacketSize         = 16 | ||||
| 	cbcMinPaddingSize        = 4 | ||||
| ) | ||||
|  | ||||
| // cbcError represents a verification error that may leak information. | ||||
| type cbcError string | ||||
|  | ||||
| func (e cbcError) Error() string { return string(e) } | ||||
|  | ||||
| func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | ||||
| 	p, err := c.readPacketLeaky(seqNum, r) | ||||
| 	if err != nil { | ||||
| 		if _, ok := err.(cbcError); ok { | ||||
| 			// Verification error: read a fixed amount of | ||||
| 			// data, to make distinguishing between | ||||
| 			// failing MAC and failing length check more | ||||
| 			// difficult. | ||||
| 			io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage)) | ||||
| 		} | ||||
| 	} | ||||
| 	return p, err | ||||
| } | ||||
|  | ||||
| func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) { | ||||
| 	blockSize := c.decrypter.BlockSize() | ||||
|  | ||||
| 	// Read the header, which will include some of the subsequent data in the | ||||
| 	// case of block ciphers - this is copied back to the payload later. | ||||
| 	// How many bytes of payload/padding will be read with this first read. | ||||
| 	firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize) | ||||
| 	firstBlock := c.packetData[:firstBlockLength] | ||||
| 	if _, err := io.ReadFull(r, firstBlock); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength | ||||
|  | ||||
| 	c.decrypter.CryptBlocks(firstBlock, firstBlock) | ||||
| 	length := binary.BigEndian.Uint32(firstBlock[:4]) | ||||
| 	if length > maxPacket { | ||||
| 		return nil, cbcError("ssh: packet too large") | ||||
| 	} | ||||
| 	if length+4 < maxUInt32(cbcMinPacketSize, blockSize) { | ||||
| 		// The minimum size of a packet is 16 (or the cipher block size, whichever | ||||
| 		// is larger) bytes. | ||||
| 		return nil, cbcError("ssh: packet too small") | ||||
| 	} | ||||
| 	// The length of the packet (including the length field but not the MAC) must | ||||
| 	// be a multiple of the block size or 8, whichever is larger. | ||||
| 	if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 { | ||||
| 		return nil, cbcError("ssh: invalid packet length multiple") | ||||
| 	} | ||||
|  | ||||
| 	paddingLength := uint32(firstBlock[4]) | ||||
| 	if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 { | ||||
| 		return nil, cbcError("ssh: invalid packet length") | ||||
| 	} | ||||
|  | ||||
| 	// Positions within the c.packetData buffer: | ||||
| 	macStart := 4 + length | ||||
| 	paddingStart := macStart - paddingLength | ||||
|  | ||||
| 	// Entire packet size, starting before length, ending at end of mac. | ||||
| 	entirePacketSize := macStart + c.macSize | ||||
|  | ||||
| 	// Ensure c.packetData is large enough for the entire packet data. | ||||
| 	if uint32(cap(c.packetData)) < entirePacketSize { | ||||
| 		// Still need to upsize and copy, but this should be rare at runtime, only | ||||
| 		// on upsizing the packetData buffer. | ||||
| 		c.packetData = make([]byte, entirePacketSize) | ||||
| 		copy(c.packetData, firstBlock) | ||||
| 	} else { | ||||
| 		c.packetData = c.packetData[:entirePacketSize] | ||||
| 	} | ||||
|  | ||||
| 	n, err := io.ReadFull(r, c.packetData[firstBlockLength:]) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	c.oracleCamouflage -= uint32(n) | ||||
|  | ||||
| 	remainingCrypted := c.packetData[firstBlockLength:macStart] | ||||
| 	c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted) | ||||
|  | ||||
| 	mac := c.packetData[macStart:] | ||||
| 	if c.mac != nil { | ||||
| 		c.mac.Reset() | ||||
| 		binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) | ||||
| 		c.mac.Write(c.seqNumBytes[:]) | ||||
| 		c.mac.Write(c.packetData[:macStart]) | ||||
| 		c.macResult = c.mac.Sum(c.macResult[:0]) | ||||
| 		if subtle.ConstantTimeCompare(c.macResult, mac) != 1 { | ||||
| 			return nil, cbcError("ssh: MAC failure") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return c.packetData[prefixLen:paddingStart], nil | ||||
| } | ||||
|  | ||||
| func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | ||||
| 	effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize()) | ||||
|  | ||||
| 	// Length of encrypted portion of the packet (header, payload, padding). | ||||
| 	// Enforce minimum padding and packet size. | ||||
| 	encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize) | ||||
| 	// Enforce block size. | ||||
| 	encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize | ||||
|  | ||||
| 	length := encLength - 4 | ||||
| 	paddingLength := int(length) - (1 + len(packet)) | ||||
|  | ||||
| 	// Overall buffer contains: header, payload, padding, mac. | ||||
| 	// Space for the MAC is reserved in the capacity but not the slice length. | ||||
| 	bufferSize := encLength + c.macSize | ||||
| 	if uint32(cap(c.packetData)) < bufferSize { | ||||
| 		c.packetData = make([]byte, encLength, bufferSize) | ||||
| 	} else { | ||||
| 		c.packetData = c.packetData[:encLength] | ||||
| 	} | ||||
|  | ||||
| 	p := c.packetData | ||||
|  | ||||
| 	// Packet header. | ||||
| 	binary.BigEndian.PutUint32(p, length) | ||||
| 	p = p[4:] | ||||
| 	p[0] = byte(paddingLength) | ||||
|  | ||||
| 	// Payload. | ||||
| 	p = p[1:] | ||||
| 	copy(p, packet) | ||||
|  | ||||
| 	// Padding. | ||||
| 	p = p[len(packet):] | ||||
| 	if _, err := io.ReadFull(rand, p); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if c.mac != nil { | ||||
| 		c.mac.Reset() | ||||
| 		binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) | ||||
| 		c.mac.Write(c.seqNumBytes[:]) | ||||
| 		c.mac.Write(c.packetData) | ||||
| 		// The MAC is now appended into the capacity reserved for it earlier. | ||||
| 		c.packetData = c.mac.Sum(c.packetData) | ||||
| 	} | ||||
|  | ||||
| 	c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength]) | ||||
|  | ||||
| 	if _, err := w.Write(c.packetData); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| const chacha20Poly1305ID = "chacha20-poly1305@openssh.com" | ||||
|  | ||||
| // chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com | ||||
| // AEAD, which is described here: | ||||
| // | ||||
| //   https://tools.ietf.org/html/draft-josefsson-ssh-chacha20-poly1305-openssh-00 | ||||
| // | ||||
| // the methods here also implement padding, which RFC4253 Section 6 | ||||
| // also requires of stream ciphers. | ||||
| type chacha20Poly1305Cipher struct { | ||||
| 	lengthKey  [8]uint32 | ||||
| 	contentKey [8]uint32 | ||||
| 	buf        []byte | ||||
| } | ||||
|  | ||||
| func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) { | ||||
| 	if len(key) != 64 { | ||||
| 		panic(len(key)) | ||||
| 	} | ||||
|  | ||||
| 	c := &chacha20Poly1305Cipher{ | ||||
| 		buf: make([]byte, 256), | ||||
| 	} | ||||
|  | ||||
| 	for i := range c.contentKey { | ||||
| 		c.contentKey[i] = binary.LittleEndian.Uint32(key[i*4 : (i+1)*4]) | ||||
| 	} | ||||
| 	for i := range c.lengthKey { | ||||
| 		c.lengthKey[i] = binary.LittleEndian.Uint32(key[(i+8)*4 : (i+9)*4]) | ||||
| 	} | ||||
| 	return c, nil | ||||
| } | ||||
|  | ||||
| func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | ||||
| 	nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} | ||||
| 	s := chacha20.New(c.contentKey, nonce) | ||||
| 	var polyKey [32]byte | ||||
| 	s.XORKeyStream(polyKey[:], polyKey[:]) | ||||
| 	s.Advance() // skip next 32 bytes | ||||
|  | ||||
| 	encryptedLength := c.buf[:4] | ||||
| 	if _, err := io.ReadFull(r, encryptedLength); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var lenBytes [4]byte | ||||
| 	chacha20.New(c.lengthKey, nonce).XORKeyStream(lenBytes[:], encryptedLength) | ||||
|  | ||||
| 	length := binary.BigEndian.Uint32(lenBytes[:]) | ||||
| 	if length > maxPacket { | ||||
| 		return nil, errors.New("ssh: invalid packet length, packet too large") | ||||
| 	} | ||||
|  | ||||
| 	contentEnd := 4 + length | ||||
| 	packetEnd := contentEnd + poly1305.TagSize | ||||
| 	if uint32(cap(c.buf)) < packetEnd { | ||||
| 		c.buf = make([]byte, packetEnd) | ||||
| 		copy(c.buf[:], encryptedLength) | ||||
| 	} else { | ||||
| 		c.buf = c.buf[:packetEnd] | ||||
| 	} | ||||
|  | ||||
| 	if _, err := io.ReadFull(r, c.buf[4:packetEnd]); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var mac [poly1305.TagSize]byte | ||||
| 	copy(mac[:], c.buf[contentEnd:packetEnd]) | ||||
| 	if !poly1305.Verify(&mac, c.buf[:contentEnd], &polyKey) { | ||||
| 		return nil, errors.New("ssh: MAC failure") | ||||
| 	} | ||||
|  | ||||
| 	plain := c.buf[4:contentEnd] | ||||
| 	s.XORKeyStream(plain, plain) | ||||
|  | ||||
| 	padding := plain[0] | ||||
| 	if padding < 4 { | ||||
| 		// padding is a byte, so it automatically satisfies | ||||
| 		// the maximum size, which is 255. | ||||
| 		return nil, fmt.Errorf("ssh: illegal padding %d", padding) | ||||
| 	} | ||||
|  | ||||
| 	if int(padding)+1 >= len(plain) { | ||||
| 		return nil, fmt.Errorf("ssh: padding %d too large", padding) | ||||
| 	} | ||||
|  | ||||
| 	plain = plain[1 : len(plain)-int(padding)] | ||||
|  | ||||
| 	return plain, nil | ||||
| } | ||||
|  | ||||
| func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error { | ||||
| 	nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} | ||||
| 	s := chacha20.New(c.contentKey, nonce) | ||||
| 	var polyKey [32]byte | ||||
| 	s.XORKeyStream(polyKey[:], polyKey[:]) | ||||
| 	s.Advance() // skip next 32 bytes | ||||
|  | ||||
| 	// There is no blocksize, so fall back to multiple of 8 byte | ||||
| 	// padding, as described in RFC 4253, Sec 6. | ||||
| 	const packetSizeMultiple = 8 | ||||
|  | ||||
| 	padding := packetSizeMultiple - (1+len(payload))%packetSizeMultiple | ||||
| 	if padding < 4 { | ||||
| 		padding += packetSizeMultiple | ||||
| 	} | ||||
|  | ||||
| 	// size (4 bytes), padding (1), payload, padding, tag. | ||||
| 	totalLength := 4 + 1 + len(payload) + padding + poly1305.TagSize | ||||
| 	if cap(c.buf) < totalLength { | ||||
| 		c.buf = make([]byte, totalLength) | ||||
| 	} else { | ||||
| 		c.buf = c.buf[:totalLength] | ||||
| 	} | ||||
|  | ||||
| 	binary.BigEndian.PutUint32(c.buf, uint32(1+len(payload)+padding)) | ||||
| 	chacha20.New(c.lengthKey, nonce).XORKeyStream(c.buf, c.buf[:4]) | ||||
| 	c.buf[4] = byte(padding) | ||||
| 	copy(c.buf[5:], payload) | ||||
| 	packetEnd := 5 + len(payload) + padding | ||||
| 	if _, err := io.ReadFull(rand, c.buf[5+len(payload):packetEnd]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	s.XORKeyStream(c.buf[4:], c.buf[4:packetEnd]) | ||||
|  | ||||
| 	var mac [poly1305.TagSize]byte | ||||
| 	poly1305.Sum(&mac, c.buf[:packetEnd], &polyKey) | ||||
|  | ||||
| 	copy(c.buf[packetEnd:], mac[:]) | ||||
|  | ||||
| 	if _, err := w.Write(c.buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										278
									
								
								vendor/golang.org/x/crypto/ssh/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										278
									
								
								vendor/golang.org/x/crypto/ssh/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,278 @@ | ||||
| // Copyright 2011 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // Client implements a traditional SSH client that supports shells, | ||||
| // subprocesses, TCP port/streamlocal forwarding and tunneled dialing. | ||||
| type Client struct { | ||||
| 	Conn | ||||
|  | ||||
| 	handleForwardsOnce sync.Once // guards calling (*Client).handleForwards | ||||
|  | ||||
| 	forwards        forwardList // forwarded tcpip connections from the remote side | ||||
| 	mu              sync.Mutex | ||||
| 	channelHandlers map[string]chan NewChannel | ||||
| } | ||||
|  | ||||
| // HandleChannelOpen returns a channel on which NewChannel requests | ||||
| // for the given type are sent. If the type already is being handled, | ||||
| // nil is returned. The channel is closed when the connection is closed. | ||||
| func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	if c.channelHandlers == nil { | ||||
| 		// The SSH channel has been closed. | ||||
| 		c := make(chan NewChannel) | ||||
| 		close(c) | ||||
| 		return c | ||||
| 	} | ||||
|  | ||||
| 	ch := c.channelHandlers[channelType] | ||||
| 	if ch != nil { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	ch = make(chan NewChannel, chanSize) | ||||
| 	c.channelHandlers[channelType] = ch | ||||
| 	return ch | ||||
| } | ||||
|  | ||||
| // NewClient creates a Client on top of the given connection. | ||||
| func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client { | ||||
| 	conn := &Client{ | ||||
| 		Conn:            c, | ||||
| 		channelHandlers: make(map[string]chan NewChannel, 1), | ||||
| 	} | ||||
|  | ||||
| 	go conn.handleGlobalRequests(reqs) | ||||
| 	go conn.handleChannelOpens(chans) | ||||
| 	go func() { | ||||
| 		conn.Wait() | ||||
| 		conn.forwards.closeAll() | ||||
| 	}() | ||||
| 	return conn | ||||
| } | ||||
|  | ||||
| // NewClientConn establishes an authenticated SSH connection using c | ||||
| // as the underlying transport.  The Request and NewChannel channels | ||||
| // must be serviced or the connection will hang. | ||||
| func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) { | ||||
| 	fullConf := *config | ||||
| 	fullConf.SetDefaults() | ||||
| 	if fullConf.HostKeyCallback == nil { | ||||
| 		c.Close() | ||||
| 		return nil, nil, nil, errors.New("ssh: must specify HostKeyCallback") | ||||
| 	} | ||||
|  | ||||
| 	conn := &connection{ | ||||
| 		sshConn: sshConn{conn: c}, | ||||
| 	} | ||||
|  | ||||
| 	if err := conn.clientHandshake(addr, &fullConf); err != nil { | ||||
| 		c.Close() | ||||
| 		return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err) | ||||
| 	} | ||||
| 	conn.mux = newMux(conn.transport) | ||||
| 	return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil | ||||
| } | ||||
|  | ||||
| // clientHandshake performs the client side key exchange. See RFC 4253 Section | ||||
| // 7. | ||||
| func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error { | ||||
| 	if config.ClientVersion != "" { | ||||
| 		c.clientVersion = []byte(config.ClientVersion) | ||||
| 	} else { | ||||
| 		c.clientVersion = []byte(packageVersion) | ||||
| 	} | ||||
| 	var err error | ||||
| 	c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	c.transport = newClientTransport( | ||||
| 		newTransport(c.sshConn.conn, config.Rand, true /* is client */), | ||||
| 		c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr()) | ||||
| 	if err := c.transport.waitSession(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	c.sessionID = c.transport.getSessionID() | ||||
| 	return c.clientAuthenticate(config) | ||||
| } | ||||
|  | ||||
| // verifyHostKeySignature verifies the host key obtained in the key | ||||
| // exchange. | ||||
| func verifyHostKeySignature(hostKey PublicKey, result *kexResult) error { | ||||
| 	sig, rest, ok := parseSignatureBody(result.Signature) | ||||
| 	if len(rest) > 0 || !ok { | ||||
| 		return errors.New("ssh: signature parse error") | ||||
| 	} | ||||
|  | ||||
| 	return hostKey.Verify(result.H, sig) | ||||
| } | ||||
|  | ||||
| // NewSession opens a new Session for this client. (A session is a remote | ||||
| // execution of a program.) | ||||
| func (c *Client) NewSession() (*Session, error) { | ||||
| 	ch, in, err := c.OpenChannel("session", nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return newSession(ch, in) | ||||
| } | ||||
|  | ||||
| func (c *Client) handleGlobalRequests(incoming <-chan *Request) { | ||||
| 	for r := range incoming { | ||||
| 		// This handles keepalive messages and matches | ||||
| 		// the behaviour of OpenSSH. | ||||
| 		r.Reply(false, nil) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // handleChannelOpens channel open messages from the remote side. | ||||
| func (c *Client) handleChannelOpens(in <-chan NewChannel) { | ||||
| 	for ch := range in { | ||||
| 		c.mu.Lock() | ||||
| 		handler := c.channelHandlers[ch.ChannelType()] | ||||
| 		c.mu.Unlock() | ||||
|  | ||||
| 		if handler != nil { | ||||
| 			handler <- ch | ||||
| 		} else { | ||||
| 			ch.Reject(UnknownChannelType, fmt.Sprintf("unknown channel type: %v", ch.ChannelType())) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	c.mu.Lock() | ||||
| 	for _, ch := range c.channelHandlers { | ||||
| 		close(ch) | ||||
| 	} | ||||
| 	c.channelHandlers = nil | ||||
| 	c.mu.Unlock() | ||||
| } | ||||
|  | ||||
| // Dial starts a client connection to the given SSH server. It is a | ||||
| // convenience function that connects to the given network address, | ||||
| // initiates the SSH handshake, and then sets up a Client.  For access | ||||
| // to incoming channels and requests, use net.Dial with NewClientConn | ||||
| // instead. | ||||
| func Dial(network, addr string, config *ClientConfig) (*Client, error) { | ||||
| 	conn, err := net.DialTimeout(network, addr, config.Timeout) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	c, chans, reqs, err := NewClientConn(conn, addr, config) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return NewClient(c, chans, reqs), nil | ||||
| } | ||||
|  | ||||
| // HostKeyCallback is the function type used for verifying server | ||||
| // keys.  A HostKeyCallback must return nil if the host key is OK, or | ||||
| // an error to reject it. It receives the hostname as passed to Dial | ||||
| // or NewClientConn. The remote address is the RemoteAddr of the | ||||
| // net.Conn underlying the SSH connection. | ||||
| type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error | ||||
|  | ||||
| // BannerCallback is the function type used for treat the banner sent by | ||||
| // the server. A BannerCallback receives the message sent by the remote server. | ||||
| type BannerCallback func(message string) error | ||||
|  | ||||
| // A ClientConfig structure is used to configure a Client. It must not be | ||||
| // modified after having been passed to an SSH function. | ||||
| type ClientConfig struct { | ||||
| 	// Config contains configuration that is shared between clients and | ||||
| 	// servers. | ||||
| 	Config | ||||
|  | ||||
| 	// User contains the username to authenticate as. | ||||
| 	User string | ||||
|  | ||||
| 	// Auth contains possible authentication methods to use with the | ||||
| 	// server. Only the first instance of a particular RFC 4252 method will | ||||
| 	// be used during authentication. | ||||
| 	Auth []AuthMethod | ||||
|  | ||||
| 	// HostKeyCallback is called during the cryptographic | ||||
| 	// handshake to validate the server's host key. The client | ||||
| 	// configuration must supply this callback for the connection | ||||
| 	// to succeed. The functions InsecureIgnoreHostKey or | ||||
| 	// FixedHostKey can be used for simplistic host key checks. | ||||
| 	HostKeyCallback HostKeyCallback | ||||
|  | ||||
| 	// BannerCallback is called during the SSH dance to display a custom | ||||
| 	// server's message. The client configuration can supply this callback to | ||||
| 	// handle it as wished. The function BannerDisplayStderr can be used for | ||||
| 	// simplistic display on Stderr. | ||||
| 	BannerCallback BannerCallback | ||||
|  | ||||
| 	// ClientVersion contains the version identification string that will | ||||
| 	// be used for the connection. If empty, a reasonable default is used. | ||||
| 	ClientVersion string | ||||
|  | ||||
| 	// HostKeyAlgorithms lists the key types that the client will | ||||
| 	// accept from the server as host key, in order of | ||||
| 	// preference. If empty, a reasonable default is used. Any | ||||
| 	// string returned from PublicKey.Type method may be used, or | ||||
| 	// any of the CertAlgoXxxx and KeyAlgoXxxx constants. | ||||
| 	HostKeyAlgorithms []string | ||||
|  | ||||
| 	// Timeout is the maximum amount of time for the TCP connection to establish. | ||||
| 	// | ||||
| 	// A Timeout of zero means no timeout. | ||||
| 	Timeout time.Duration | ||||
| } | ||||
|  | ||||
| // InsecureIgnoreHostKey returns a function that can be used for | ||||
| // ClientConfig.HostKeyCallback to accept any host key. It should | ||||
| // not be used for production code. | ||||
| func InsecureIgnoreHostKey() HostKeyCallback { | ||||
| 	return func(hostname string, remote net.Addr, key PublicKey) error { | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type fixedHostKey struct { | ||||
| 	key PublicKey | ||||
| } | ||||
|  | ||||
| func (f *fixedHostKey) check(hostname string, remote net.Addr, key PublicKey) error { | ||||
| 	if f.key == nil { | ||||
| 		return fmt.Errorf("ssh: required host key was nil") | ||||
| 	} | ||||
| 	if !bytes.Equal(key.Marshal(), f.key.Marshal()) { | ||||
| 		return fmt.Errorf("ssh: host key mismatch") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // FixedHostKey returns a function for use in | ||||
| // ClientConfig.HostKeyCallback to accept only a specific host key. | ||||
| func FixedHostKey(key PublicKey) HostKeyCallback { | ||||
| 	hk := &fixedHostKey{key} | ||||
| 	return hk.check | ||||
| } | ||||
|  | ||||
| // BannerDisplayStderr returns a function that can be used for | ||||
| // ClientConfig.BannerCallback to display banners on os.Stderr. | ||||
| func BannerDisplayStderr() BannerCallback { | ||||
| 	return func(banner string) error { | ||||
| 		_, err := os.Stderr.WriteString(banner) | ||||
|  | ||||
| 		return err | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										525
									
								
								vendor/golang.org/x/crypto/ssh/client_auth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										525
									
								
								vendor/golang.org/x/crypto/ssh/client_auth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,525 @@ | ||||
| // Copyright 2011 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| type authResult int | ||||
|  | ||||
| const ( | ||||
| 	authFailure authResult = iota | ||||
| 	authPartialSuccess | ||||
| 	authSuccess | ||||
| ) | ||||
|  | ||||
| // clientAuthenticate authenticates with the remote server. See RFC 4252. | ||||
| func (c *connection) clientAuthenticate(config *ClientConfig) error { | ||||
| 	// initiate user auth session | ||||
| 	if err := c.transport.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth})); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	packet, err := c.transport.readPacket() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	var serviceAccept serviceAcceptMsg | ||||
| 	if err := Unmarshal(packet, &serviceAccept); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// during the authentication phase the client first attempts the "none" method | ||||
| 	// then any untried methods suggested by the server. | ||||
| 	tried := make(map[string]bool) | ||||
| 	var lastMethods []string | ||||
|  | ||||
| 	sessionID := c.transport.getSessionID() | ||||
| 	for auth := AuthMethod(new(noneAuth)); auth != nil; { | ||||
| 		ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if ok == authSuccess { | ||||
| 			// success | ||||
| 			return nil | ||||
| 		} else if ok == authFailure { | ||||
| 			tried[auth.method()] = true | ||||
| 		} | ||||
| 		if methods == nil { | ||||
| 			methods = lastMethods | ||||
| 		} | ||||
| 		lastMethods = methods | ||||
|  | ||||
| 		auth = nil | ||||
|  | ||||
| 	findNext: | ||||
| 		for _, a := range config.Auth { | ||||
| 			candidateMethod := a.method() | ||||
| 			if tried[candidateMethod] { | ||||
| 				continue | ||||
| 			} | ||||
| 			for _, meth := range methods { | ||||
| 				if meth == candidateMethod { | ||||
| 					auth = a | ||||
| 					break findNext | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", keys(tried)) | ||||
| } | ||||
|  | ||||
| func keys(m map[string]bool) []string { | ||||
| 	s := make([]string, 0, len(m)) | ||||
|  | ||||
| 	for key := range m { | ||||
| 		s = append(s, key) | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| // An AuthMethod represents an instance of an RFC 4252 authentication method. | ||||
| type AuthMethod interface { | ||||
| 	// auth authenticates user over transport t. | ||||
| 	// Returns true if authentication is successful. | ||||
| 	// If authentication is not successful, a []string of alternative | ||||
| 	// method names is returned. If the slice is nil, it will be ignored | ||||
| 	// and the previous set of possible methods will be reused. | ||||
| 	auth(session []byte, user string, p packetConn, rand io.Reader) (authResult, []string, error) | ||||
|  | ||||
| 	// method returns the RFC 4252 method name. | ||||
| 	method() string | ||||
| } | ||||
|  | ||||
| // "none" authentication, RFC 4252 section 5.2. | ||||
| type noneAuth int | ||||
|  | ||||
| func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { | ||||
| 	if err := c.writePacket(Marshal(&userAuthRequestMsg{ | ||||
| 		User:    user, | ||||
| 		Service: serviceSSH, | ||||
| 		Method:  "none", | ||||
| 	})); err != nil { | ||||
| 		return authFailure, nil, err | ||||
| 	} | ||||
|  | ||||
| 	return handleAuthResponse(c) | ||||
| } | ||||
|  | ||||
| func (n *noneAuth) method() string { | ||||
| 	return "none" | ||||
| } | ||||
|  | ||||
| // passwordCallback is an AuthMethod that fetches the password through | ||||
| // a function call, e.g. by prompting the user. | ||||
| type passwordCallback func() (password string, err error) | ||||
|  | ||||
| func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { | ||||
| 	type passwordAuthMsg struct { | ||||
| 		User     string `sshtype:"50"` | ||||
| 		Service  string | ||||
| 		Method   string | ||||
| 		Reply    bool | ||||
| 		Password string | ||||
| 	} | ||||
|  | ||||
| 	pw, err := cb() | ||||
| 	// REVIEW NOTE: is there a need to support skipping a password attempt? | ||||
| 	// The program may only find out that the user doesn't have a password | ||||
| 	// when prompting. | ||||
| 	if err != nil { | ||||
| 		return authFailure, nil, err | ||||
| 	} | ||||
|  | ||||
| 	if err := c.writePacket(Marshal(&passwordAuthMsg{ | ||||
| 		User:     user, | ||||
| 		Service:  serviceSSH, | ||||
| 		Method:   cb.method(), | ||||
| 		Reply:    false, | ||||
| 		Password: pw, | ||||
| 	})); err != nil { | ||||
| 		return authFailure, nil, err | ||||
| 	} | ||||
|  | ||||
| 	return handleAuthResponse(c) | ||||
| } | ||||
|  | ||||
| func (cb passwordCallback) method() string { | ||||
| 	return "password" | ||||
| } | ||||
|  | ||||
| // Password returns an AuthMethod using the given password. | ||||
| func Password(secret string) AuthMethod { | ||||
| 	return passwordCallback(func() (string, error) { return secret, nil }) | ||||
| } | ||||
|  | ||||
| // PasswordCallback returns an AuthMethod that uses a callback for | ||||
| // fetching a password. | ||||
| func PasswordCallback(prompt func() (secret string, err error)) AuthMethod { | ||||
| 	return passwordCallback(prompt) | ||||
| } | ||||
|  | ||||
| type publickeyAuthMsg struct { | ||||
| 	User    string `sshtype:"50"` | ||||
| 	Service string | ||||
| 	Method  string | ||||
| 	// HasSig indicates to the receiver packet that the auth request is signed and | ||||
| 	// should be used for authentication of the request. | ||||
| 	HasSig   bool | ||||
| 	Algoname string | ||||
| 	PubKey   []byte | ||||
| 	// Sig is tagged with "rest" so Marshal will exclude it during | ||||
| 	// validateKey | ||||
| 	Sig []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| // publicKeyCallback is an AuthMethod that uses a set of key | ||||
| // pairs for authentication. | ||||
| type publicKeyCallback func() ([]Signer, error) | ||||
|  | ||||
| func (cb publicKeyCallback) method() string { | ||||
| 	return "publickey" | ||||
| } | ||||
|  | ||||
| func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { | ||||
| 	// Authentication is performed by sending an enquiry to test if a key is | ||||
| 	// acceptable to the remote. If the key is acceptable, the client will | ||||
| 	// attempt to authenticate with the valid key.  If not the client will repeat | ||||
| 	// the process with the remaining keys. | ||||
|  | ||||
| 	signers, err := cb() | ||||
| 	if err != nil { | ||||
| 		return authFailure, nil, err | ||||
| 	} | ||||
| 	var methods []string | ||||
| 	for _, signer := range signers { | ||||
| 		ok, err := validateKey(signer.PublicKey(), user, c) | ||||
| 		if err != nil { | ||||
| 			return authFailure, nil, err | ||||
| 		} | ||||
| 		if !ok { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		pub := signer.PublicKey() | ||||
| 		pubKey := pub.Marshal() | ||||
| 		sign, err := signer.Sign(rand, buildDataSignedForAuth(session, userAuthRequestMsg{ | ||||
| 			User:    user, | ||||
| 			Service: serviceSSH, | ||||
| 			Method:  cb.method(), | ||||
| 		}, []byte(pub.Type()), pubKey)) | ||||
| 		if err != nil { | ||||
| 			return authFailure, nil, err | ||||
| 		} | ||||
|  | ||||
| 		// manually wrap the serialized signature in a string | ||||
| 		s := Marshal(sign) | ||||
| 		sig := make([]byte, stringLength(len(s))) | ||||
| 		marshalString(sig, s) | ||||
| 		msg := publickeyAuthMsg{ | ||||
| 			User:     user, | ||||
| 			Service:  serviceSSH, | ||||
| 			Method:   cb.method(), | ||||
| 			HasSig:   true, | ||||
| 			Algoname: pub.Type(), | ||||
| 			PubKey:   pubKey, | ||||
| 			Sig:      sig, | ||||
| 		} | ||||
| 		p := Marshal(&msg) | ||||
| 		if err := c.writePacket(p); err != nil { | ||||
| 			return authFailure, nil, err | ||||
| 		} | ||||
| 		var success authResult | ||||
| 		success, methods, err = handleAuthResponse(c) | ||||
| 		if err != nil { | ||||
| 			return authFailure, nil, err | ||||
| 		} | ||||
|  | ||||
| 		// If authentication succeeds or the list of available methods does not | ||||
| 		// contain the "publickey" method, do not attempt to authenticate with any | ||||
| 		// other keys.  According to RFC 4252 Section 7, the latter can occur when | ||||
| 		// additional authentication methods are required. | ||||
| 		if success == authSuccess || !containsMethod(methods, cb.method()) { | ||||
| 			return success, methods, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return authFailure, methods, nil | ||||
| } | ||||
|  | ||||
| func containsMethod(methods []string, method string) bool { | ||||
| 	for _, m := range methods { | ||||
| 		if m == method { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // validateKey validates the key provided is acceptable to the server. | ||||
| func validateKey(key PublicKey, user string, c packetConn) (bool, error) { | ||||
| 	pubKey := key.Marshal() | ||||
| 	msg := publickeyAuthMsg{ | ||||
| 		User:     user, | ||||
| 		Service:  serviceSSH, | ||||
| 		Method:   "publickey", | ||||
| 		HasSig:   false, | ||||
| 		Algoname: key.Type(), | ||||
| 		PubKey:   pubKey, | ||||
| 	} | ||||
| 	if err := c.writePacket(Marshal(&msg)); err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
|  | ||||
| 	return confirmKeyAck(key, c) | ||||
| } | ||||
|  | ||||
| func confirmKeyAck(key PublicKey, c packetConn) (bool, error) { | ||||
| 	pubKey := key.Marshal() | ||||
| 	algoname := key.Type() | ||||
|  | ||||
| 	for { | ||||
| 		packet, err := c.readPacket() | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 		switch packet[0] { | ||||
| 		case msgUserAuthBanner: | ||||
| 			if err := handleBannerResponse(c, packet); err != nil { | ||||
| 				return false, err | ||||
| 			} | ||||
| 		case msgUserAuthPubKeyOk: | ||||
| 			var msg userAuthPubKeyOkMsg | ||||
| 			if err := Unmarshal(packet, &msg); err != nil { | ||||
| 				return false, err | ||||
| 			} | ||||
| 			if msg.Algo != algoname || !bytes.Equal(msg.PubKey, pubKey) { | ||||
| 				return false, nil | ||||
| 			} | ||||
| 			return true, nil | ||||
| 		case msgUserAuthFailure: | ||||
| 			return false, nil | ||||
| 		default: | ||||
| 			return false, unexpectedMessageError(msgUserAuthSuccess, packet[0]) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // PublicKeys returns an AuthMethod that uses the given key | ||||
| // pairs. | ||||
| func PublicKeys(signers ...Signer) AuthMethod { | ||||
| 	return publicKeyCallback(func() ([]Signer, error) { return signers, nil }) | ||||
| } | ||||
|  | ||||
| // PublicKeysCallback returns an AuthMethod that runs the given | ||||
| // function to obtain a list of key pairs. | ||||
| func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMethod { | ||||
| 	return publicKeyCallback(getSigners) | ||||
| } | ||||
|  | ||||
| // handleAuthResponse returns whether the preceding authentication request succeeded | ||||
| // along with a list of remaining authentication methods to try next and | ||||
| // an error if an unexpected response was received. | ||||
| func handleAuthResponse(c packetConn) (authResult, []string, error) { | ||||
| 	for { | ||||
| 		packet, err := c.readPacket() | ||||
| 		if err != nil { | ||||
| 			return authFailure, nil, err | ||||
| 		} | ||||
|  | ||||
| 		switch packet[0] { | ||||
| 		case msgUserAuthBanner: | ||||
| 			if err := handleBannerResponse(c, packet); err != nil { | ||||
| 				return authFailure, nil, err | ||||
| 			} | ||||
| 		case msgUserAuthFailure: | ||||
| 			var msg userAuthFailureMsg | ||||
| 			if err := Unmarshal(packet, &msg); err != nil { | ||||
| 				return authFailure, nil, err | ||||
| 			} | ||||
| 			if msg.PartialSuccess { | ||||
| 				return authPartialSuccess, msg.Methods, nil | ||||
| 			} | ||||
| 			return authFailure, msg.Methods, nil | ||||
| 		case msgUserAuthSuccess: | ||||
| 			return authSuccess, nil, nil | ||||
| 		default: | ||||
| 			return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0]) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func handleBannerResponse(c packetConn, packet []byte) error { | ||||
| 	var msg userAuthBannerMsg | ||||
| 	if err := Unmarshal(packet, &msg); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	transport, ok := c.(*handshakeTransport) | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if transport.bannerCallback != nil { | ||||
| 		return transport.bannerCallback(msg.Message) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // KeyboardInteractiveChallenge should print questions, optionally | ||||
| // disabling echoing (e.g. for passwords), and return all the answers. | ||||
| // Challenge may be called multiple times in a single session. After | ||||
| // successful authentication, the server may send a challenge with no | ||||
| // questions, for which the user and instruction messages should be | ||||
| // printed.  RFC 4256 section 3.3 details how the UI should behave for | ||||
| // both CLI and GUI environments. | ||||
| type KeyboardInteractiveChallenge func(user, instruction string, questions []string, echos []bool) (answers []string, err error) | ||||
|  | ||||
| // KeyboardInteractive returns an AuthMethod using a prompt/response | ||||
| // sequence controlled by the server. | ||||
| func KeyboardInteractive(challenge KeyboardInteractiveChallenge) AuthMethod { | ||||
| 	return challenge | ||||
| } | ||||
|  | ||||
| func (cb KeyboardInteractiveChallenge) method() string { | ||||
| 	return "keyboard-interactive" | ||||
| } | ||||
|  | ||||
| func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { | ||||
| 	type initiateMsg struct { | ||||
| 		User       string `sshtype:"50"` | ||||
| 		Service    string | ||||
| 		Method     string | ||||
| 		Language   string | ||||
| 		Submethods string | ||||
| 	} | ||||
|  | ||||
| 	if err := c.writePacket(Marshal(&initiateMsg{ | ||||
| 		User:    user, | ||||
| 		Service: serviceSSH, | ||||
| 		Method:  "keyboard-interactive", | ||||
| 	})); err != nil { | ||||
| 		return authFailure, nil, err | ||||
| 	} | ||||
|  | ||||
| 	for { | ||||
| 		packet, err := c.readPacket() | ||||
| 		if err != nil { | ||||
| 			return authFailure, nil, err | ||||
| 		} | ||||
|  | ||||
| 		// like handleAuthResponse, but with less options. | ||||
| 		switch packet[0] { | ||||
| 		case msgUserAuthBanner: | ||||
| 			if err := handleBannerResponse(c, packet); err != nil { | ||||
| 				return authFailure, nil, err | ||||
| 			} | ||||
| 			continue | ||||
| 		case msgUserAuthInfoRequest: | ||||
| 			// OK | ||||
| 		case msgUserAuthFailure: | ||||
| 			var msg userAuthFailureMsg | ||||
| 			if err := Unmarshal(packet, &msg); err != nil { | ||||
| 				return authFailure, nil, err | ||||
| 			} | ||||
| 			if msg.PartialSuccess { | ||||
| 				return authPartialSuccess, msg.Methods, nil | ||||
| 			} | ||||
| 			return authFailure, msg.Methods, nil | ||||
| 		case msgUserAuthSuccess: | ||||
| 			return authSuccess, nil, nil | ||||
| 		default: | ||||
| 			return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0]) | ||||
| 		} | ||||
|  | ||||
| 		var msg userAuthInfoRequestMsg | ||||
| 		if err := Unmarshal(packet, &msg); err != nil { | ||||
| 			return authFailure, nil, err | ||||
| 		} | ||||
|  | ||||
| 		// Manually unpack the prompt/echo pairs. | ||||
| 		rest := msg.Prompts | ||||
| 		var prompts []string | ||||
| 		var echos []bool | ||||
| 		for i := 0; i < int(msg.NumPrompts); i++ { | ||||
| 			prompt, r, ok := parseString(rest) | ||||
| 			if !ok || len(r) == 0 { | ||||
| 				return authFailure, nil, errors.New("ssh: prompt format error") | ||||
| 			} | ||||
| 			prompts = append(prompts, string(prompt)) | ||||
| 			echos = append(echos, r[0] != 0) | ||||
| 			rest = r[1:] | ||||
| 		} | ||||
|  | ||||
| 		if len(rest) != 0 { | ||||
| 			return authFailure, nil, errors.New("ssh: extra data following keyboard-interactive pairs") | ||||
| 		} | ||||
|  | ||||
| 		answers, err := cb(msg.User, msg.Instruction, prompts, echos) | ||||
| 		if err != nil { | ||||
| 			return authFailure, nil, err | ||||
| 		} | ||||
|  | ||||
| 		if len(answers) != len(prompts) { | ||||
| 			return authFailure, nil, errors.New("ssh: not enough answers from keyboard-interactive callback") | ||||
| 		} | ||||
| 		responseLength := 1 + 4 | ||||
| 		for _, a := range answers { | ||||
| 			responseLength += stringLength(len(a)) | ||||
| 		} | ||||
| 		serialized := make([]byte, responseLength) | ||||
| 		p := serialized | ||||
| 		p[0] = msgUserAuthInfoResponse | ||||
| 		p = p[1:] | ||||
| 		p = marshalUint32(p, uint32(len(answers))) | ||||
| 		for _, a := range answers { | ||||
| 			p = marshalString(p, []byte(a)) | ||||
| 		} | ||||
|  | ||||
| 		if err := c.writePacket(serialized); err != nil { | ||||
| 			return authFailure, nil, err | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type retryableAuthMethod struct { | ||||
| 	authMethod AuthMethod | ||||
| 	maxTries   int | ||||
| } | ||||
|  | ||||
| func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader) (ok authResult, methods []string, err error) { | ||||
| 	for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ { | ||||
| 		ok, methods, err = r.authMethod.auth(session, user, c, rand) | ||||
| 		if ok != authFailure || err != nil { // either success, partial success or error terminate | ||||
| 			return ok, methods, err | ||||
| 		} | ||||
| 	} | ||||
| 	return ok, methods, err | ||||
| } | ||||
|  | ||||
| func (r *retryableAuthMethod) method() string { | ||||
| 	return r.authMethod.method() | ||||
| } | ||||
|  | ||||
| // RetryableAuthMethod is a decorator for other auth methods enabling them to | ||||
| // be retried up to maxTries before considering that AuthMethod itself failed. | ||||
| // If maxTries is <= 0, will retry indefinitely | ||||
| // | ||||
| // This is useful for interactive clients using challenge/response type | ||||
| // authentication (e.g. Keyboard-Interactive, Password, etc) where the user | ||||
| // could mistype their response resulting in the server issuing a | ||||
| // SSH_MSG_USERAUTH_FAILURE (rfc4252 #8 [password] and rfc4256 #3.4 | ||||
| // [keyboard-interactive]); Without this decorator, the non-retryable | ||||
| // AuthMethod would be removed from future consideration, and never tried again | ||||
| // (and so the user would never be able to retry their entry). | ||||
| func RetryableAuthMethod(auth AuthMethod, maxTries int) AuthMethod { | ||||
| 	return &retryableAuthMethod{authMethod: auth, maxTries: maxTries} | ||||
| } | ||||
							
								
								
									
										383
									
								
								vendor/golang.org/x/crypto/ssh/common.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										383
									
								
								vendor/golang.org/x/crypto/ssh/common.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,383 @@ | ||||
| // Copyright 2011 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"crypto" | ||||
| 	"crypto/rand" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math" | ||||
| 	"sync" | ||||
|  | ||||
| 	_ "crypto/sha1" | ||||
| 	_ "crypto/sha256" | ||||
| 	_ "crypto/sha512" | ||||
| ) | ||||
|  | ||||
| // These are string constants in the SSH protocol. | ||||
| const ( | ||||
| 	compressionNone = "none" | ||||
| 	serviceUserAuth = "ssh-userauth" | ||||
| 	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", | ||||
| 	chacha20Poly1305ID, | ||||
| 	"arcfour256", "arcfour128", "arcfour", | ||||
| 	aes128cbcID, | ||||
| 	tripledescbcID, | ||||
| } | ||||
|  | ||||
| // preferredCiphers specifies the default preference for ciphers. | ||||
| var preferredCiphers = []string{ | ||||
| 	"aes128-gcm@openssh.com", | ||||
| 	chacha20Poly1305ID, | ||||
| 	"aes128-ctr", "aes192-ctr", "aes256-ctr", | ||||
| } | ||||
|  | ||||
| // supportedKexAlgos specifies the supported key-exchange algorithms in | ||||
| // preference order. | ||||
| var supportedKexAlgos = []string{ | ||||
| 	kexAlgoCurve25519SHA256, | ||||
| 	// 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, | ||||
| 	kexAlgoDH14SHA1, kexAlgoDH1SHA1, | ||||
| } | ||||
|  | ||||
| // supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods | ||||
| // of authenticating servers) in preference order. | ||||
| var supportedHostKeyAlgos = []string{ | ||||
| 	CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, | ||||
| 	CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01, | ||||
|  | ||||
| 	KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, | ||||
| 	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-256", "hmac-sha1", "hmac-sha1-96", | ||||
| } | ||||
|  | ||||
| var supportedCompressions = []string{compressionNone} | ||||
|  | ||||
| // hashFuncs keeps the mapping of supported algorithms to their respective | ||||
| // hashes needed for signature verification. | ||||
| var hashFuncs = map[string]crypto.Hash{ | ||||
| 	KeyAlgoRSA:          crypto.SHA1, | ||||
| 	KeyAlgoDSA:          crypto.SHA1, | ||||
| 	KeyAlgoECDSA256:     crypto.SHA256, | ||||
| 	KeyAlgoECDSA384:     crypto.SHA384, | ||||
| 	KeyAlgoECDSA521:     crypto.SHA512, | ||||
| 	CertAlgoRSAv01:      crypto.SHA1, | ||||
| 	CertAlgoDSAv01:      crypto.SHA1, | ||||
| 	CertAlgoECDSA256v01: crypto.SHA256, | ||||
| 	CertAlgoECDSA384v01: crypto.SHA384, | ||||
| 	CertAlgoECDSA521v01: crypto.SHA512, | ||||
| } | ||||
|  | ||||
| // unexpectedMessageError results when the SSH message that we received didn't | ||||
| // match what we wanted. | ||||
| func unexpectedMessageError(expected, got uint8) error { | ||||
| 	return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected) | ||||
| } | ||||
|  | ||||
| // parseError results from a malformed SSH message. | ||||
| 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) { | ||||
| 	for _, c := range client { | ||||
| 		for _, s := range server { | ||||
| 			if c == s { | ||||
| 				return c, nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server) | ||||
| } | ||||
|  | ||||
| type directionAlgorithms struct { | ||||
| 	Cipher      string | ||||
| 	MAC         string | ||||
| 	Compression string | ||||
| } | ||||
|  | ||||
| // rekeyBytes returns a rekeying intervals in bytes. | ||||
| func (a *directionAlgorithms) rekeyBytes() int64 { | ||||
| 	// According to RFC4344 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", gcmCipherID, aes128cbcID: | ||||
| 		return 16 * (1 << 32) | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	// For others, stick with RFC4253 recommendation to rekey after 1 Gb of data. | ||||
| 	return 1 << 30 | ||||
| } | ||||
|  | ||||
| type algorithms struct { | ||||
| 	kex     string | ||||
| 	hostKey string | ||||
| 	w       directionAlgorithms | ||||
| 	r       directionAlgorithms | ||||
| } | ||||
|  | ||||
| func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) { | ||||
| 	result := &algorithms{} | ||||
|  | ||||
| 	result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	result.hostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	result.w.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	result.r.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	result.w.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	result.r.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	result.w.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	result.r.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| // If rekeythreshold is too small, we can't make any progress sending | ||||
| // stuff. | ||||
| const minRekeyThreshold uint64 = 256 | ||||
|  | ||||
| // Config contains configuration data common to both ServerConfig and | ||||
| // ClientConfig. | ||||
| type Config struct { | ||||
| 	// Rand provides the source of entropy for cryptographic | ||||
| 	// primitives. If Rand is nil, the cryptographic random reader | ||||
| 	// in package crypto/rand will be used. | ||||
| 	Rand io.Reader | ||||
|  | ||||
| 	// The maximum number of bytes sent or received after which a | ||||
| 	// new key is negotiated. It must be at least 256. If | ||||
| 	// unspecified, a size suitable for the chosen cipher is used. | ||||
| 	RekeyThreshold uint64 | ||||
|  | ||||
| 	// The allowed key exchanges algorithms. If unspecified then a | ||||
| 	// default set of algorithms is used. | ||||
| 	KeyExchanges []string | ||||
|  | ||||
| 	// The allowed cipher algorithms. If unspecified then a sensible | ||||
| 	// default is used. | ||||
| 	Ciphers []string | ||||
|  | ||||
| 	// The allowed MAC algorithms. If unspecified then a sensible default | ||||
| 	// is used. | ||||
| 	MACs []string | ||||
| } | ||||
|  | ||||
| // SetDefaults sets sensible values for unset fields in config. This is | ||||
| // exported for testing: Configs passed to SSH functions are copied and have | ||||
| // default values set automatically. | ||||
| func (c *Config) SetDefaults() { | ||||
| 	if c.Rand == nil { | ||||
| 		c.Rand = rand.Reader | ||||
| 	} | ||||
| 	if c.Ciphers == nil { | ||||
| 		c.Ciphers = preferredCiphers | ||||
| 	} | ||||
| 	var ciphers []string | ||||
| 	for _, c := range c.Ciphers { | ||||
| 		if cipherModes[c] != nil { | ||||
| 			// reject the cipher if we have no cipherModes definition | ||||
| 			ciphers = append(ciphers, c) | ||||
| 		} | ||||
| 	} | ||||
| 	c.Ciphers = ciphers | ||||
|  | ||||
| 	if c.KeyExchanges == nil { | ||||
| 		c.KeyExchanges = supportedKexAlgos | ||||
| 	} | ||||
|  | ||||
| 	if c.MACs == nil { | ||||
| 		c.MACs = supportedMACs | ||||
| 	} | ||||
|  | ||||
| 	if c.RekeyThreshold == 0 { | ||||
| 		// cipher specific default | ||||
| 	} else if c.RekeyThreshold < minRekeyThreshold { | ||||
| 		c.RekeyThreshold = minRekeyThreshold | ||||
| 	} else if c.RekeyThreshold >= math.MaxInt64 { | ||||
| 		// Avoid weirdness if somebody uses -1 as a threshold. | ||||
| 		c.RekeyThreshold = math.MaxInt64 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // buildDataSignedForAuth returns the data that is signed in order to prove | ||||
| // possession of a private key. See RFC 4252, section 7. | ||||
| func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte { | ||||
| 	data := struct { | ||||
| 		Session []byte | ||||
| 		Type    byte | ||||
| 		User    string | ||||
| 		Service string | ||||
| 		Method  string | ||||
| 		Sign    bool | ||||
| 		Algo    []byte | ||||
| 		PubKey  []byte | ||||
| 	}{ | ||||
| 		sessionID, | ||||
| 		msgUserAuthRequest, | ||||
| 		req.User, | ||||
| 		req.Service, | ||||
| 		req.Method, | ||||
| 		true, | ||||
| 		algo, | ||||
| 		pubKey, | ||||
| 	} | ||||
| 	return Marshal(data) | ||||
| } | ||||
|  | ||||
| func appendU16(buf []byte, n uint16) []byte { | ||||
| 	return append(buf, byte(n>>8), byte(n)) | ||||
| } | ||||
|  | ||||
| func appendU32(buf []byte, n uint32) []byte { | ||||
| 	return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) | ||||
| } | ||||
|  | ||||
| func appendU64(buf []byte, n uint64) []byte { | ||||
| 	return append(buf, | ||||
| 		byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), | ||||
| 		byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) | ||||
| } | ||||
|  | ||||
| func appendInt(buf []byte, n int) []byte { | ||||
| 	return appendU32(buf, uint32(n)) | ||||
| } | ||||
|  | ||||
| func appendString(buf []byte, s string) []byte { | ||||
| 	buf = appendU32(buf, uint32(len(s))) | ||||
| 	buf = append(buf, s...) | ||||
| 	return buf | ||||
| } | ||||
|  | ||||
| func appendBool(buf []byte, b bool) []byte { | ||||
| 	if b { | ||||
| 		return append(buf, 1) | ||||
| 	} | ||||
| 	return append(buf, 0) | ||||
| } | ||||
|  | ||||
| // newCond is a helper to hide the fact that there is no usable zero | ||||
| // value for sync.Cond. | ||||
| func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) } | ||||
|  | ||||
| // window represents the buffer available to clients | ||||
| // wishing to write to a channel. | ||||
| type window struct { | ||||
| 	*sync.Cond | ||||
| 	win          uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1 | ||||
| 	writeWaiters int | ||||
| 	closed       bool | ||||
| } | ||||
|  | ||||
| // add adds win to the amount of window available | ||||
| // for consumers. | ||||
| func (w *window) add(win uint32) bool { | ||||
| 	// a zero sized window adjust is a noop. | ||||
| 	if win == 0 { | ||||
| 		return true | ||||
| 	} | ||||
| 	w.L.Lock() | ||||
| 	if w.win+win < win { | ||||
| 		w.L.Unlock() | ||||
| 		return false | ||||
| 	} | ||||
| 	w.win += win | ||||
| 	// It is unusual that multiple goroutines would be attempting to reserve | ||||
| 	// window space, but not guaranteed. Use broadcast to notify all waiters | ||||
| 	// that additional window is available. | ||||
| 	w.Broadcast() | ||||
| 	w.L.Unlock() | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // close sets the window to closed, so all reservations fail | ||||
| // immediately. | ||||
| func (w *window) close() { | ||||
| 	w.L.Lock() | ||||
| 	w.closed = true | ||||
| 	w.Broadcast() | ||||
| 	w.L.Unlock() | ||||
| } | ||||
|  | ||||
| // reserve reserves win from the available window capacity. | ||||
| // If no capacity remains, reserve will block. reserve may | ||||
| // return less than requested. | ||||
| func (w *window) reserve(win uint32) (uint32, error) { | ||||
| 	var err error | ||||
| 	w.L.Lock() | ||||
| 	w.writeWaiters++ | ||||
| 	w.Broadcast() | ||||
| 	for w.win == 0 && !w.closed { | ||||
| 		w.Wait() | ||||
| 	} | ||||
| 	w.writeWaiters-- | ||||
| 	if w.win < win { | ||||
| 		win = w.win | ||||
| 	} | ||||
| 	w.win -= win | ||||
| 	if w.closed { | ||||
| 		err = io.EOF | ||||
| 	} | ||||
| 	w.L.Unlock() | ||||
| 	return win, err | ||||
| } | ||||
|  | ||||
| // waitWriterBlocked waits until some goroutine is blocked for further | ||||
| // writes. It is used in tests only. | ||||
| func (w *window) waitWriterBlocked() { | ||||
| 	w.Cond.L.Lock() | ||||
| 	for w.writeWaiters == 0 { | ||||
| 		w.Cond.Wait() | ||||
| 	} | ||||
| 	w.Cond.L.Unlock() | ||||
| } | ||||
							
								
								
									
										143
									
								
								vendor/golang.org/x/crypto/ssh/connection.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								vendor/golang.org/x/crypto/ssh/connection.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | ||||
| // Copyright 2013 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net" | ||||
| ) | ||||
|  | ||||
| // OpenChannelError is returned if the other side rejects an | ||||
| // OpenChannel request. | ||||
| type OpenChannelError struct { | ||||
| 	Reason  RejectionReason | ||||
| 	Message string | ||||
| } | ||||
|  | ||||
| func (e *OpenChannelError) Error() string { | ||||
| 	return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message) | ||||
| } | ||||
|  | ||||
| // ConnMetadata holds metadata for the connection. | ||||
| type ConnMetadata interface { | ||||
| 	// User returns the user ID for this connection. | ||||
| 	User() string | ||||
|  | ||||
| 	// SessionID returns the session hash, also denoted by H. | ||||
| 	SessionID() []byte | ||||
|  | ||||
| 	// ClientVersion returns the client's version string as hashed | ||||
| 	// into the session ID. | ||||
| 	ClientVersion() []byte | ||||
|  | ||||
| 	// ServerVersion returns the server's version string as hashed | ||||
| 	// into the session ID. | ||||
| 	ServerVersion() []byte | ||||
|  | ||||
| 	// RemoteAddr returns the remote address for this connection. | ||||
| 	RemoteAddr() net.Addr | ||||
|  | ||||
| 	// LocalAddr returns the local address for this connection. | ||||
| 	LocalAddr() net.Addr | ||||
| } | ||||
|  | ||||
| // Conn represents an SSH connection for both server and client roles. | ||||
| // Conn is the basis for implementing an application layer, such | ||||
| // as ClientConn, which implements the traditional shell access for | ||||
| // clients. | ||||
| type Conn interface { | ||||
| 	ConnMetadata | ||||
|  | ||||
| 	// SendRequest sends a global request, and returns the | ||||
| 	// reply. If wantReply is true, it returns the response status | ||||
| 	// and payload. See also RFC4254, section 4. | ||||
| 	SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) | ||||
|  | ||||
| 	// OpenChannel tries to open an channel. If the request is | ||||
| 	// rejected, it returns *OpenChannelError. On success it returns | ||||
| 	// the SSH Channel and a Go channel for incoming, out-of-band | ||||
| 	// requests. The Go channel must be serviced, or the | ||||
| 	// connection will hang. | ||||
| 	OpenChannel(name string, data []byte) (Channel, <-chan *Request, error) | ||||
|  | ||||
| 	// Close closes the underlying network connection | ||||
| 	Close() error | ||||
|  | ||||
| 	// Wait blocks until the connection has shut down, and returns the | ||||
| 	// error causing the shutdown. | ||||
| 	Wait() error | ||||
|  | ||||
| 	// TODO(hanwen): consider exposing: | ||||
| 	//   RequestKeyChange | ||||
| 	//   Disconnect | ||||
| } | ||||
|  | ||||
| // DiscardRequests consumes and rejects all requests from the | ||||
| // passed-in channel. | ||||
| func DiscardRequests(in <-chan *Request) { | ||||
| 	for req := range in { | ||||
| 		if req.WantReply { | ||||
| 			req.Reply(false, nil) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // A connection represents an incoming connection. | ||||
| type connection struct { | ||||
| 	transport *handshakeTransport | ||||
| 	sshConn | ||||
|  | ||||
| 	// The connection protocol. | ||||
| 	*mux | ||||
| } | ||||
|  | ||||
| func (c *connection) Close() error { | ||||
| 	return c.sshConn.conn.Close() | ||||
| } | ||||
|  | ||||
| // sshconn provides net.Conn metadata, but disallows direct reads and | ||||
| // writes. | ||||
| type sshConn struct { | ||||
| 	conn net.Conn | ||||
|  | ||||
| 	user          string | ||||
| 	sessionID     []byte | ||||
| 	clientVersion []byte | ||||
| 	serverVersion []byte | ||||
| } | ||||
|  | ||||
| func dup(src []byte) []byte { | ||||
| 	dst := make([]byte, len(src)) | ||||
| 	copy(dst, src) | ||||
| 	return dst | ||||
| } | ||||
|  | ||||
| func (c *sshConn) User() string { | ||||
| 	return c.user | ||||
| } | ||||
|  | ||||
| func (c *sshConn) RemoteAddr() net.Addr { | ||||
| 	return c.conn.RemoteAddr() | ||||
| } | ||||
|  | ||||
| func (c *sshConn) Close() error { | ||||
| 	return c.conn.Close() | ||||
| } | ||||
|  | ||||
| func (c *sshConn) LocalAddr() net.Addr { | ||||
| 	return c.conn.LocalAddr() | ||||
| } | ||||
|  | ||||
| func (c *sshConn) SessionID() []byte { | ||||
| 	return dup(c.sessionID) | ||||
| } | ||||
|  | ||||
| func (c *sshConn) ClientVersion() []byte { | ||||
| 	return dup(c.clientVersion) | ||||
| } | ||||
|  | ||||
| func (c *sshConn) ServerVersion() []byte { | ||||
| 	return dup(c.serverVersion) | ||||
| } | ||||
							
								
								
									
										21
									
								
								vendor/golang.org/x/crypto/ssh/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/golang.org/x/crypto/ssh/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| // Copyright 2011 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 ssh implements an SSH client and server. | ||||
|  | ||||
| SSH is a transport security protocol, an authentication protocol and a | ||||
| family of application protocols. The most typical application level | ||||
| protocol is a remote shell and this is specifically implemented.  However, | ||||
| the multiplexed nature of SSH is exposed to users that wish to support | ||||
| others. | ||||
|  | ||||
| References: | ||||
|   [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 | ||||
|  | ||||
| This package does not fall under the stability promise of the Go language itself, | ||||
| so its API may be changed when pressing needs arise. | ||||
| */ | ||||
| package ssh // import "golang.org/x/crypto/ssh" | ||||
							
								
								
									
										646
									
								
								vendor/golang.org/x/crypto/ssh/handshake.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										646
									
								
								vendor/golang.org/x/crypto/ssh/handshake.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,646 @@ | ||||
| // Copyright 2013 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"crypto/rand" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"net" | ||||
| 	"sync" | ||||
| ) | ||||
|  | ||||
| // debugHandshake, if set, prints messages sent and received.  Key | ||||
| // exchange messages are printed as if DH were used, so the debug | ||||
| // messages are wrong when using ECDH. | ||||
| const debugHandshake = false | ||||
|  | ||||
| // chanSize sets the amount of buffering SSH connections. This is | ||||
| // primarily for testing: setting chanSize=0 uncovers deadlocks more | ||||
| // quickly. | ||||
| const chanSize = 16 | ||||
|  | ||||
| // keyingTransport is a packet based transport that supports key | ||||
| // changes. It need not be thread-safe. It should pass through | ||||
| // msgNewKeys in both directions. | ||||
| type keyingTransport interface { | ||||
| 	packetConn | ||||
|  | ||||
| 	// 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 | ||||
| } | ||||
|  | ||||
| // handshakeTransport implements rekeying on top of a keyingTransport | ||||
| // and offers a thread-safe writePacket() interface. | ||||
| type handshakeTransport struct { | ||||
| 	conn   keyingTransport | ||||
| 	config *Config | ||||
|  | ||||
| 	serverVersion []byte | ||||
| 	clientVersion []byte | ||||
|  | ||||
| 	// hostKeys is non-empty if we are the server. In that case, | ||||
| 	// it contains all host keys that can be used to sign the | ||||
| 	// connection. | ||||
| 	hostKeys []Signer | ||||
|  | ||||
| 	// hostKeyAlgorithms is non-empty if we are the client. In that case, | ||||
| 	// we accept these key types from the server as host key. | ||||
| 	hostKeyAlgorithms []string | ||||
|  | ||||
| 	// On read error, incoming is closed, and readError is set. | ||||
| 	incoming  chan []byte | ||||
| 	readError error | ||||
|  | ||||
| 	mu             sync.Mutex | ||||
| 	writeError     error | ||||
| 	sentInitPacket []byte | ||||
| 	sentInitMsg    *kexInitMsg | ||||
| 	pendingPackets [][]byte // Used when a key exchange is in progress. | ||||
|  | ||||
| 	// If the read loop wants to schedule a kex, it pings this | ||||
| 	// channel, and the write loop will send out a kex | ||||
| 	// message. | ||||
| 	requestKex chan struct{} | ||||
|  | ||||
| 	// If the other side requests or confirms a kex, its kexInit | ||||
| 	// packet is sent here for the write loop to find it. | ||||
| 	startKex chan *pendingKex | ||||
|  | ||||
| 	// data for host key checking | ||||
| 	hostKeyCallback HostKeyCallback | ||||
| 	dialAddress     string | ||||
| 	remoteAddr      net.Addr | ||||
|  | ||||
| 	// bannerCallback is non-empty if we are the client and it has been set in | ||||
| 	// ClientConfig. In that case it is called during the user authentication | ||||
| 	// dance to handle a custom server's message. | ||||
| 	bannerCallback BannerCallback | ||||
|  | ||||
| 	// Algorithms agreed in the last key exchange. | ||||
| 	algorithms *algorithms | ||||
|  | ||||
| 	readPacketsLeft uint32 | ||||
| 	readBytesLeft   int64 | ||||
|  | ||||
| 	writePacketsLeft uint32 | ||||
| 	writeBytesLeft   int64 | ||||
|  | ||||
| 	// The session ID or nil if first kex did not complete yet. | ||||
| 	sessionID []byte | ||||
| } | ||||
|  | ||||
| type pendingKex struct { | ||||
| 	otherInit []byte | ||||
| 	done      chan error | ||||
| } | ||||
|  | ||||
| func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport { | ||||
| 	t := &handshakeTransport{ | ||||
| 		conn:          conn, | ||||
| 		serverVersion: serverVersion, | ||||
| 		clientVersion: clientVersion, | ||||
| 		incoming:      make(chan []byte, chanSize), | ||||
| 		requestKex:    make(chan struct{}, 1), | ||||
| 		startKex:      make(chan *pendingKex, 1), | ||||
|  | ||||
| 		config: config, | ||||
| 	} | ||||
| 	t.resetReadThresholds() | ||||
| 	t.resetWriteThresholds() | ||||
|  | ||||
| 	// We always start with a mandatory key exchange. | ||||
| 	t.requestKex <- struct{}{} | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ClientConfig, dialAddr string, addr net.Addr) *handshakeTransport { | ||||
| 	t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) | ||||
| 	t.dialAddress = dialAddr | ||||
| 	t.remoteAddr = addr | ||||
| 	t.hostKeyCallback = config.HostKeyCallback | ||||
| 	t.bannerCallback = config.BannerCallback | ||||
| 	if config.HostKeyAlgorithms != nil { | ||||
| 		t.hostKeyAlgorithms = config.HostKeyAlgorithms | ||||
| 	} else { | ||||
| 		t.hostKeyAlgorithms = supportedHostKeyAlgos | ||||
| 	} | ||||
| 	go t.readLoop() | ||||
| 	go t.kexLoop() | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport { | ||||
| 	t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) | ||||
| 	t.hostKeys = config.hostKeys | ||||
| 	go t.readLoop() | ||||
| 	go t.kexLoop() | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) getSessionID() []byte { | ||||
| 	return t.sessionID | ||||
| } | ||||
|  | ||||
| // waitSession waits for the session to be established. This should be | ||||
| // the first thing to call after instantiating handshakeTransport. | ||||
| func (t *handshakeTransport) waitSession() error { | ||||
| 	p, err := t.readPacket() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if p[0] != msgNewKeys { | ||||
| 		return fmt.Errorf("ssh: first packet should be msgNewKeys") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) id() string { | ||||
| 	if len(t.hostKeys) > 0 { | ||||
| 		return "server" | ||||
| 	} | ||||
| 	return "client" | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) printPacket(p []byte, write bool) { | ||||
| 	action := "got" | ||||
| 	if write { | ||||
| 		action = "sent" | ||||
| 	} | ||||
|  | ||||
| 	if p[0] == msgChannelData || p[0] == msgChannelExtendedData { | ||||
| 		log.Printf("%s %s data (packet %d bytes)", t.id(), action, len(p)) | ||||
| 	} else { | ||||
| 		msg, err := decode(p) | ||||
| 		log.Printf("%s %s %T %v (%v)", t.id(), action, msg, msg, err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) readPacket() ([]byte, error) { | ||||
| 	p, ok := <-t.incoming | ||||
| 	if !ok { | ||||
| 		return nil, t.readError | ||||
| 	} | ||||
| 	return p, nil | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) readLoop() { | ||||
| 	first := true | ||||
| 	for { | ||||
| 		p, err := t.readOnePacket(first) | ||||
| 		first = false | ||||
| 		if err != nil { | ||||
| 			t.readError = err | ||||
| 			close(t.incoming) | ||||
| 			break | ||||
| 		} | ||||
| 		if p[0] == msgIgnore || p[0] == msgDebug { | ||||
| 			continue | ||||
| 		} | ||||
| 		t.incoming <- p | ||||
| 	} | ||||
|  | ||||
| 	// Stop writers too. | ||||
| 	t.recordWriteError(t.readError) | ||||
|  | ||||
| 	// Unblock the writer should it wait for this. | ||||
| 	close(t.startKex) | ||||
|  | ||||
| 	// Don't close t.requestKex; it's also written to from writePacket. | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) pushPacket(p []byte) error { | ||||
| 	if debugHandshake { | ||||
| 		t.printPacket(p, true) | ||||
| 	} | ||||
| 	return t.conn.writePacket(p) | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) getWriteError() error { | ||||
| 	t.mu.Lock() | ||||
| 	defer t.mu.Unlock() | ||||
| 	return t.writeError | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) recordWriteError(err error) { | ||||
| 	t.mu.Lock() | ||||
| 	defer t.mu.Unlock() | ||||
| 	if t.writeError == nil && err != nil { | ||||
| 		t.writeError = err | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) requestKeyExchange() { | ||||
| 	select { | ||||
| 	case t.requestKex <- struct{}{}: | ||||
| 	default: | ||||
| 		// something already requested a kex, so do nothing. | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) resetWriteThresholds() { | ||||
| 	t.writePacketsLeft = packetRekeyThreshold | ||||
| 	if t.config.RekeyThreshold > 0 { | ||||
| 		t.writeBytesLeft = int64(t.config.RekeyThreshold) | ||||
| 	} else if t.algorithms != nil { | ||||
| 		t.writeBytesLeft = t.algorithms.w.rekeyBytes() | ||||
| 	} else { | ||||
| 		t.writeBytesLeft = 1 << 30 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) kexLoop() { | ||||
|  | ||||
| write: | ||||
| 	for t.getWriteError() == nil { | ||||
| 		var request *pendingKex | ||||
| 		var sent bool | ||||
|  | ||||
| 		for request == nil || !sent { | ||||
| 			var ok bool | ||||
| 			select { | ||||
| 			case request, ok = <-t.startKex: | ||||
| 				if !ok { | ||||
| 					break write | ||||
| 				} | ||||
| 			case <-t.requestKex: | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 			if !sent { | ||||
| 				if err := t.sendKexInit(); err != nil { | ||||
| 					t.recordWriteError(err) | ||||
| 					break | ||||
| 				} | ||||
| 				sent = true | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if err := t.getWriteError(); err != nil { | ||||
| 			if request != nil { | ||||
| 				request.done <- err | ||||
| 			} | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		// We're not servicing t.requestKex, but that is OK: | ||||
| 		// we never block on sending to t.requestKex. | ||||
|  | ||||
| 		// We're not servicing t.startKex, but the remote end | ||||
| 		// has just sent us a kexInitMsg, so it can't send | ||||
| 		// another key change request, until we close the done | ||||
| 		// channel on the pendingKex request. | ||||
|  | ||||
| 		err := t.enterKeyExchange(request.otherInit) | ||||
|  | ||||
| 		t.mu.Lock() | ||||
| 		t.writeError = err | ||||
| 		t.sentInitPacket = nil | ||||
| 		t.sentInitMsg = nil | ||||
|  | ||||
| 		t.resetWriteThresholds() | ||||
|  | ||||
| 		// we have completed the key exchange. Since the | ||||
| 		// reader is still blocked, it is safe to clear out | ||||
| 		// the requestKex channel. This avoids the situation | ||||
| 		// where: 1) we consumed our own request for the | ||||
| 		// initial kex, and 2) the kex from the remote side | ||||
| 		// caused another send on the requestKex channel, | ||||
| 	clear: | ||||
| 		for { | ||||
| 			select { | ||||
| 			case <-t.requestKex: | ||||
| 				// | ||||
| 			default: | ||||
| 				break clear | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		request.done <- t.writeError | ||||
|  | ||||
| 		// kex finished. Push packets that we received while | ||||
| 		// the kex was in progress. Don't look at t.startKex | ||||
| 		// and don't increment writtenSinceKex: if we trigger | ||||
| 		// another kex while we are still busy with the last | ||||
| 		// one, things will become very confusing. | ||||
| 		for _, p := range t.pendingPackets { | ||||
| 			t.writeError = t.pushPacket(p) | ||||
| 			if t.writeError != nil { | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		t.pendingPackets = t.pendingPackets[:0] | ||||
| 		t.mu.Unlock() | ||||
| 	} | ||||
|  | ||||
| 	// drain startKex channel. We don't service t.requestKex | ||||
| 	// because nobody does blocking sends there. | ||||
| 	go func() { | ||||
| 		for init := range t.startKex { | ||||
| 			init.done <- t.writeError | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	// Unblock reader. | ||||
| 	t.conn.Close() | ||||
| } | ||||
|  | ||||
| // The protocol uses uint32 for packet counters, so we can't let them | ||||
| // reach 1<<32.  We will actually read and write more packets than | ||||
| // this, though: the other side may send more packets, and after we | ||||
| // hit this limit on writing we will send a few more packets for the | ||||
| // key exchange itself. | ||||
| const packetRekeyThreshold = (1 << 31) | ||||
|  | ||||
| func (t *handshakeTransport) resetReadThresholds() { | ||||
| 	t.readPacketsLeft = packetRekeyThreshold | ||||
| 	if t.config.RekeyThreshold > 0 { | ||||
| 		t.readBytesLeft = int64(t.config.RekeyThreshold) | ||||
| 	} else if t.algorithms != nil { | ||||
| 		t.readBytesLeft = t.algorithms.r.rekeyBytes() | ||||
| 	} else { | ||||
| 		t.readBytesLeft = 1 << 30 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) { | ||||
| 	p, err := t.conn.readPacket() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if t.readPacketsLeft > 0 { | ||||
| 		t.readPacketsLeft-- | ||||
| 	} else { | ||||
| 		t.requestKeyExchange() | ||||
| 	} | ||||
|  | ||||
| 	if t.readBytesLeft > 0 { | ||||
| 		t.readBytesLeft -= int64(len(p)) | ||||
| 	} else { | ||||
| 		t.requestKeyExchange() | ||||
| 	} | ||||
|  | ||||
| 	if debugHandshake { | ||||
| 		t.printPacket(p, false) | ||||
| 	} | ||||
|  | ||||
| 	if first && p[0] != msgKexInit { | ||||
| 		return nil, fmt.Errorf("ssh: first packet should be msgKexInit") | ||||
| 	} | ||||
|  | ||||
| 	if p[0] != msgKexInit { | ||||
| 		return p, nil | ||||
| 	} | ||||
|  | ||||
| 	firstKex := t.sessionID == nil | ||||
|  | ||||
| 	kex := pendingKex{ | ||||
| 		done:      make(chan error, 1), | ||||
| 		otherInit: p, | ||||
| 	} | ||||
| 	t.startKex <- &kex | ||||
| 	err = <-kex.done | ||||
|  | ||||
| 	if debugHandshake { | ||||
| 		log.Printf("%s exited key exchange (first %v), err %v", t.id(), firstKex, err) | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	t.resetReadThresholds() | ||||
|  | ||||
| 	// By default, a key exchange is hidden from higher layers by | ||||
| 	// translating it into msgIgnore. | ||||
| 	successPacket := []byte{msgIgnore} | ||||
| 	if firstKex { | ||||
| 		// sendKexInit() for the first kex waits for | ||||
| 		// msgNewKeys so the authentication process is | ||||
| 		// guaranteed to happen over an encrypted transport. | ||||
| 		successPacket = []byte{msgNewKeys} | ||||
| 	} | ||||
|  | ||||
| 	return successPacket, nil | ||||
| } | ||||
|  | ||||
| // sendKexInit sends a key change message. | ||||
| func (t *handshakeTransport) sendKexInit() error { | ||||
| 	t.mu.Lock() | ||||
| 	defer t.mu.Unlock() | ||||
| 	if t.sentInitMsg != nil { | ||||
| 		// kexInits may be sent either in response to the other side, | ||||
| 		// or because our side wants to initiate a key change, so we | ||||
| 		// may have already sent a kexInit. In that case, don't send a | ||||
| 		// second kexInit. | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	msg := &kexInitMsg{ | ||||
| 		KexAlgos:                t.config.KeyExchanges, | ||||
| 		CiphersClientServer:     t.config.Ciphers, | ||||
| 		CiphersServerClient:     t.config.Ciphers, | ||||
| 		MACsClientServer:        t.config.MACs, | ||||
| 		MACsServerClient:        t.config.MACs, | ||||
| 		CompressionClientServer: supportedCompressions, | ||||
| 		CompressionServerClient: supportedCompressions, | ||||
| 	} | ||||
| 	io.ReadFull(rand.Reader, msg.Cookie[:]) | ||||
|  | ||||
| 	if len(t.hostKeys) > 0 { | ||||
| 		for _, k := range t.hostKeys { | ||||
| 			msg.ServerHostKeyAlgos = append( | ||||
| 				msg.ServerHostKeyAlgos, k.PublicKey().Type()) | ||||
| 		} | ||||
| 	} else { | ||||
| 		msg.ServerHostKeyAlgos = t.hostKeyAlgorithms | ||||
| 	} | ||||
| 	packet := Marshal(msg) | ||||
|  | ||||
| 	// writePacket destroys the contents, so save a copy. | ||||
| 	packetCopy := make([]byte, len(packet)) | ||||
| 	copy(packetCopy, packet) | ||||
|  | ||||
| 	if err := t.pushPacket(packetCopy); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	t.sentInitMsg = msg | ||||
| 	t.sentInitPacket = packet | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) writePacket(p []byte) error { | ||||
| 	switch p[0] { | ||||
| 	case msgKexInit: | ||||
| 		return errors.New("ssh: only handshakeTransport can send kexInit") | ||||
| 	case msgNewKeys: | ||||
| 		return errors.New("ssh: only handshakeTransport can send newKeys") | ||||
| 	} | ||||
|  | ||||
| 	t.mu.Lock() | ||||
| 	defer t.mu.Unlock() | ||||
| 	if t.writeError != nil { | ||||
| 		return t.writeError | ||||
| 	} | ||||
|  | ||||
| 	if t.sentInitMsg != nil { | ||||
| 		// Copy the packet so the writer can reuse the buffer. | ||||
| 		cp := make([]byte, len(p)) | ||||
| 		copy(cp, p) | ||||
| 		t.pendingPackets = append(t.pendingPackets, cp) | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if t.writeBytesLeft > 0 { | ||||
| 		t.writeBytesLeft -= int64(len(p)) | ||||
| 	} else { | ||||
| 		t.requestKeyExchange() | ||||
| 	} | ||||
|  | ||||
| 	if t.writePacketsLeft > 0 { | ||||
| 		t.writePacketsLeft-- | ||||
| 	} else { | ||||
| 		t.requestKeyExchange() | ||||
| 	} | ||||
|  | ||||
| 	if err := t.pushPacket(p); err != nil { | ||||
| 		t.writeError = err | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) Close() error { | ||||
| 	return t.conn.Close() | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { | ||||
| 	if debugHandshake { | ||||
| 		log.Printf("%s entered key exchange", t.id()) | ||||
| 	} | ||||
|  | ||||
| 	otherInit := &kexInitMsg{} | ||||
| 	if err := Unmarshal(otherInitPacket, otherInit); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	magics := handshakeMagics{ | ||||
| 		clientVersion: t.clientVersion, | ||||
| 		serverVersion: t.serverVersion, | ||||
| 		clientKexInit: otherInitPacket, | ||||
| 		serverKexInit: t.sentInitPacket, | ||||
| 	} | ||||
|  | ||||
| 	clientInit := otherInit | ||||
| 	serverInit := t.sentInitMsg | ||||
| 	if len(t.hostKeys) == 0 { | ||||
| 		clientInit, serverInit = serverInit, clientInit | ||||
|  | ||||
| 		magics.clientKexInit = t.sentInitPacket | ||||
| 		magics.serverKexInit = otherInitPacket | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	t.algorithms, err = findAgreedAlgorithms(clientInit, serverInit) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// We don't send FirstKexFollows, but we handle receiving it. | ||||
| 	// | ||||
| 	// RFC 4253 section 7 defines the kex and the agreement method for | ||||
| 	// first_kex_packet_follows. It states that the guessed packet | ||||
| 	// should be ignored if the "kex algorithm and/or the host | ||||
| 	// key algorithm is guessed wrong (server and client have | ||||
| 	// different preferred algorithm), or if any of the other | ||||
| 	// algorithms cannot be agreed upon". The other algorithms have | ||||
| 	// already been checked above so the kex algorithm and host key | ||||
| 	// algorithm are checked here. | ||||
| 	if otherInit.FirstKexFollows && (clientInit.KexAlgos[0] != serverInit.KexAlgos[0] || clientInit.ServerHostKeyAlgos[0] != serverInit.ServerHostKeyAlgos[0]) { | ||||
| 		// other side sent a kex message for the wrong algorithm, | ||||
| 		// which we have to ignore. | ||||
| 		if _, err := t.conn.readPacket(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	kex, ok := kexAlgoMap[t.algorithms.kex] | ||||
| 	if !ok { | ||||
| 		return fmt.Errorf("ssh: unexpected key exchange algorithm %v", t.algorithms.kex) | ||||
| 	} | ||||
|  | ||||
| 	var result *kexResult | ||||
| 	if len(t.hostKeys) > 0 { | ||||
| 		result, err = t.server(kex, t.algorithms, &magics) | ||||
| 	} else { | ||||
| 		result, err = t.client(kex, t.algorithms, &magics) | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if t.sessionID == nil { | ||||
| 		t.sessionID = result.H | ||||
| 	} | ||||
| 	result.SessionID = t.sessionID | ||||
|  | ||||
| 	if err := t.conn.prepareKeyChange(t.algorithms, result); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if packet, err := t.conn.readPacket(); err != nil { | ||||
| 		return err | ||||
| 	} else if packet[0] != msgNewKeys { | ||||
| 		return unexpectedMessageError(msgNewKeys, packet[0]) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) server(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { | ||||
| 	var hostKey Signer | ||||
| 	for _, k := range t.hostKeys { | ||||
| 		if algs.hostKey == k.PublicKey().Type() { | ||||
| 			hostKey = k | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey) | ||||
| 	return r, err | ||||
| } | ||||
|  | ||||
| func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { | ||||
| 	result, err := kex.Client(t.conn, t.config.Rand, magics) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	hostKey, err := ParsePublicKey(result.HostKey) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if err := verifyHostKeySignature(hostKey, result); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
							
								
								
									
										540
									
								
								vendor/golang.org/x/crypto/ssh/kex.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										540
									
								
								vendor/golang.org/x/crypto/ssh/kex.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,540 @@ | ||||
| // Copyright 2013 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"crypto" | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/elliptic" | ||||
| 	"crypto/rand" | ||||
| 	"crypto/subtle" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
|  | ||||
| 	"golang.org/x/crypto/curve25519" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	kexAlgoDH1SHA1          = "diffie-hellman-group1-sha1" | ||||
| 	kexAlgoDH14SHA1         = "diffie-hellman-group14-sha1" | ||||
| 	kexAlgoECDH256          = "ecdh-sha2-nistp256" | ||||
| 	kexAlgoECDH384          = "ecdh-sha2-nistp384" | ||||
| 	kexAlgoECDH521          = "ecdh-sha2-nistp521" | ||||
| 	kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org" | ||||
| ) | ||||
|  | ||||
| // kexResult captures the outcome of a key exchange. | ||||
| type kexResult struct { | ||||
| 	// Session hash. See also RFC 4253, section 8. | ||||
| 	H []byte | ||||
|  | ||||
| 	// Shared secret. See also RFC 4253, section 8. | ||||
| 	K []byte | ||||
|  | ||||
| 	// Host key as hashed into H. | ||||
| 	HostKey []byte | ||||
|  | ||||
| 	// Signature of H. | ||||
| 	Signature []byte | ||||
|  | ||||
| 	// A cryptographic hash function that matches the security | ||||
| 	// level of the key exchange algorithm. It is used for | ||||
| 	// calculating H, and for deriving keys from H and K. | ||||
| 	Hash crypto.Hash | ||||
|  | ||||
| 	// The session ID, which is the first H computed. This is used | ||||
| 	// to derive key material inside the transport. | ||||
| 	SessionID []byte | ||||
| } | ||||
|  | ||||
| // handshakeMagics contains data that is always included in the | ||||
| // session hash. | ||||
| type handshakeMagics struct { | ||||
| 	clientVersion, serverVersion []byte | ||||
| 	clientKexInit, serverKexInit []byte | ||||
| } | ||||
|  | ||||
| func (m *handshakeMagics) write(w io.Writer) { | ||||
| 	writeString(w, m.clientVersion) | ||||
| 	writeString(w, m.serverVersion) | ||||
| 	writeString(w, m.clientKexInit) | ||||
| 	writeString(w, m.serverKexInit) | ||||
| } | ||||
|  | ||||
| // kexAlgorithm abstracts different key exchange algorithms. | ||||
| type kexAlgorithm interface { | ||||
| 	// Server runs server-side key agreement, signing the result | ||||
| 	// with a hostkey. | ||||
| 	Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error) | ||||
|  | ||||
| 	// Client runs the client-side key agreement. Caller is | ||||
| 	// responsible for verifying the host key signature. | ||||
| 	Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) | ||||
| } | ||||
|  | ||||
| // dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. | ||||
| type dhGroup struct { | ||||
| 	g, p, pMinus1 *big.Int | ||||
| } | ||||
|  | ||||
| func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { | ||||
| 	if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 { | ||||
| 		return nil, errors.New("ssh: DH parameter out of bounds") | ||||
| 	} | ||||
| 	return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil | ||||
| } | ||||
|  | ||||
| func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { | ||||
| 	hashFunc := crypto.SHA1 | ||||
|  | ||||
| 	var x *big.Int | ||||
| 	for { | ||||
| 		var err error | ||||
| 		if x, err = rand.Int(randSource, group.pMinus1); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if x.Sign() > 0 { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	X := new(big.Int).Exp(group.g, x, group.p) | ||||
| 	kexDHInit := kexDHInitMsg{ | ||||
| 		X: X, | ||||
| 	} | ||||
| 	if err := c.writePacket(Marshal(&kexDHInit)); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	packet, err := c.readPacket() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var kexDHReply kexDHReplyMsg | ||||
| 	if err = Unmarshal(packet, &kexDHReply); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	ki, err := group.diffieHellman(kexDHReply.Y, x) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	h := hashFunc.New() | ||||
| 	magics.write(h) | ||||
| 	writeString(h, kexDHReply.HostKey) | ||||
| 	writeInt(h, X) | ||||
| 	writeInt(h, kexDHReply.Y) | ||||
| 	K := make([]byte, intLength(ki)) | ||||
| 	marshalInt(K, ki) | ||||
| 	h.Write(K) | ||||
|  | ||||
| 	return &kexResult{ | ||||
| 		H:         h.Sum(nil), | ||||
| 		K:         K, | ||||
| 		HostKey:   kexDHReply.HostKey, | ||||
| 		Signature: kexDHReply.Signature, | ||||
| 		Hash:      crypto.SHA1, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { | ||||
| 	hashFunc := crypto.SHA1 | ||||
| 	packet, err := c.readPacket() | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	var kexDHInit kexDHInitMsg | ||||
| 	if err = Unmarshal(packet, &kexDHInit); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	var y *big.Int | ||||
| 	for { | ||||
| 		if y, err = rand.Int(randSource, group.pMinus1); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if y.Sign() > 0 { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	Y := new(big.Int).Exp(group.g, y, group.p) | ||||
| 	ki, err := group.diffieHellman(kexDHInit.X, y) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	hostKeyBytes := priv.PublicKey().Marshal() | ||||
|  | ||||
| 	h := hashFunc.New() | ||||
| 	magics.write(h) | ||||
| 	writeString(h, hostKeyBytes) | ||||
| 	writeInt(h, kexDHInit.X) | ||||
| 	writeInt(h, Y) | ||||
|  | ||||
| 	K := make([]byte, intLength(ki)) | ||||
| 	marshalInt(K, ki) | ||||
| 	h.Write(K) | ||||
|  | ||||
| 	H := h.Sum(nil) | ||||
|  | ||||
| 	// H is already a hash, but the hostkey signing will apply its | ||||
| 	// own key-specific hash algorithm. | ||||
| 	sig, err := signAndMarshal(priv, randSource, H) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	kexDHReply := kexDHReplyMsg{ | ||||
| 		HostKey:   hostKeyBytes, | ||||
| 		Y:         Y, | ||||
| 		Signature: sig, | ||||
| 	} | ||||
| 	packet = Marshal(&kexDHReply) | ||||
|  | ||||
| 	err = c.writePacket(packet) | ||||
| 	return &kexResult{ | ||||
| 		H:         H, | ||||
| 		K:         K, | ||||
| 		HostKey:   hostKeyBytes, | ||||
| 		Signature: sig, | ||||
| 		Hash:      crypto.SHA1, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // ecdh performs Elliptic Curve Diffie-Hellman key exchange as | ||||
| // described in RFC 5656, section 4. | ||||
| type ecdh struct { | ||||
| 	curve elliptic.Curve | ||||
| } | ||||
|  | ||||
| func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { | ||||
| 	ephKey, err := ecdsa.GenerateKey(kex.curve, rand) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	kexInit := kexECDHInitMsg{ | ||||
| 		ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y), | ||||
| 	} | ||||
|  | ||||
| 	serialized := Marshal(&kexInit) | ||||
| 	if err := c.writePacket(serialized); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	packet, err := c.readPacket() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var reply kexECDHReplyMsg | ||||
| 	if err = Unmarshal(packet, &reply); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// generate shared secret | ||||
| 	secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes()) | ||||
|  | ||||
| 	h := ecHash(kex.curve).New() | ||||
| 	magics.write(h) | ||||
| 	writeString(h, reply.HostKey) | ||||
| 	writeString(h, kexInit.ClientPubKey) | ||||
| 	writeString(h, reply.EphemeralPubKey) | ||||
| 	K := make([]byte, intLength(secret)) | ||||
| 	marshalInt(K, secret) | ||||
| 	h.Write(K) | ||||
|  | ||||
| 	return &kexResult{ | ||||
| 		H:         h.Sum(nil), | ||||
| 		K:         K, | ||||
| 		HostKey:   reply.HostKey, | ||||
| 		Signature: reply.Signature, | ||||
| 		Hash:      ecHash(kex.curve), | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // unmarshalECKey parses and checks an EC key. | ||||
| func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) { | ||||
| 	x, y = elliptic.Unmarshal(curve, pubkey) | ||||
| 	if x == nil { | ||||
| 		return nil, nil, errors.New("ssh: elliptic.Unmarshal failure") | ||||
| 	} | ||||
| 	if !validateECPublicKey(curve, x, y) { | ||||
| 		return nil, nil, errors.New("ssh: public key not on curve") | ||||
| 	} | ||||
| 	return x, y, nil | ||||
| } | ||||
|  | ||||
| // validateECPublicKey checks that the point is a valid public key for | ||||
| // the given curve. See [SEC1], 3.2.2 | ||||
| func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool { | ||||
| 	if x.Sign() == 0 && y.Sign() == 0 { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	if x.Cmp(curve.Params().P) >= 0 { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	if y.Cmp(curve.Params().P) >= 0 { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	if !curve.IsOnCurve(x, y) { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	// We don't check if N * PubKey == 0, since | ||||
| 	// | ||||
| 	// - the NIST curves have cofactor = 1, so this is implicit. | ||||
| 	// (We don't foresee an implementation that supports non NIST | ||||
| 	// curves) | ||||
| 	// | ||||
| 	// - for ephemeral keys, we don't need to worry about small | ||||
| 	// subgroup attacks. | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { | ||||
| 	packet, err := c.readPacket() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var kexECDHInit kexECDHInitMsg | ||||
| 	if err = Unmarshal(packet, &kexECDHInit); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// We could cache this key across multiple users/multiple | ||||
| 	// connection attempts, but the benefit is small. OpenSSH | ||||
| 	// generates a new key for each incoming connection. | ||||
| 	ephKey, err := ecdsa.GenerateKey(kex.curve, rand) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	hostKeyBytes := priv.PublicKey().Marshal() | ||||
|  | ||||
| 	serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y) | ||||
|  | ||||
| 	// generate shared secret | ||||
| 	secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes()) | ||||
|  | ||||
| 	h := ecHash(kex.curve).New() | ||||
| 	magics.write(h) | ||||
| 	writeString(h, hostKeyBytes) | ||||
| 	writeString(h, kexECDHInit.ClientPubKey) | ||||
| 	writeString(h, serializedEphKey) | ||||
|  | ||||
| 	K := make([]byte, intLength(secret)) | ||||
| 	marshalInt(K, secret) | ||||
| 	h.Write(K) | ||||
|  | ||||
| 	H := h.Sum(nil) | ||||
|  | ||||
| 	// H is already a hash, but the hostkey signing will apply its | ||||
| 	// own key-specific hash algorithm. | ||||
| 	sig, err := signAndMarshal(priv, rand, H) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	reply := kexECDHReplyMsg{ | ||||
| 		EphemeralPubKey: serializedEphKey, | ||||
| 		HostKey:         hostKeyBytes, | ||||
| 		Signature:       sig, | ||||
| 	} | ||||
|  | ||||
| 	serialized := Marshal(&reply) | ||||
| 	if err := c.writePacket(serialized); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return &kexResult{ | ||||
| 		H:         H, | ||||
| 		K:         K, | ||||
| 		HostKey:   reply.HostKey, | ||||
| 		Signature: sig, | ||||
| 		Hash:      ecHash(kex.curve), | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| 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{ | ||||
| 		g:       new(big.Int).SetInt64(2), | ||||
| 		p:       p, | ||||
| 		pMinus1: new(big.Int).Sub(p, bigOne), | ||||
| 	} | ||||
|  | ||||
| 	// 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) | ||||
|  | ||||
| 	kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{ | ||||
| 		g:       new(big.Int).SetInt64(2), | ||||
| 		p:       p, | ||||
| 		pMinus1: new(big.Int).Sub(p, bigOne), | ||||
| 	} | ||||
|  | ||||
| 	kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()} | ||||
| 	kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()} | ||||
| 	kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()} | ||||
| 	kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{} | ||||
| } | ||||
|  | ||||
| // curve25519sha256 implements the curve25519-sha256@libssh.org key | ||||
| // agreement protocol, as described in | ||||
| // https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt | ||||
| type curve25519sha256 struct{} | ||||
|  | ||||
| type curve25519KeyPair struct { | ||||
| 	priv [32]byte | ||||
| 	pub  [32]byte | ||||
| } | ||||
|  | ||||
| func (kp *curve25519KeyPair) generate(rand io.Reader) error { | ||||
| 	if _, err := io.ReadFull(rand, kp.priv[:]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	curve25519.ScalarBaseMult(&kp.pub, &kp.priv) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // curve25519Zeros is just an array of 32 zero bytes so that we have something | ||||
| // convenient to compare against in order to reject curve25519 points with the | ||||
| // wrong order. | ||||
| var curve25519Zeros [32]byte | ||||
|  | ||||
| func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { | ||||
| 	var kp curve25519KeyPair | ||||
| 	if err := kp.generate(rand); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	packet, err := c.readPacket() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var reply kexECDHReplyMsg | ||||
| 	if err = Unmarshal(packet, &reply); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if len(reply.EphemeralPubKey) != 32 { | ||||
| 		return nil, errors.New("ssh: peer's curve25519 public value has wrong length") | ||||
| 	} | ||||
|  | ||||
| 	var servPub, secret [32]byte | ||||
| 	copy(servPub[:], reply.EphemeralPubKey) | ||||
| 	curve25519.ScalarMult(&secret, &kp.priv, &servPub) | ||||
| 	if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { | ||||
| 		return nil, errors.New("ssh: peer's curve25519 public value has wrong order") | ||||
| 	} | ||||
|  | ||||
| 	h := crypto.SHA256.New() | ||||
| 	magics.write(h) | ||||
| 	writeString(h, reply.HostKey) | ||||
| 	writeString(h, kp.pub[:]) | ||||
| 	writeString(h, reply.EphemeralPubKey) | ||||
|  | ||||
| 	ki := new(big.Int).SetBytes(secret[:]) | ||||
| 	K := make([]byte, intLength(ki)) | ||||
| 	marshalInt(K, ki) | ||||
| 	h.Write(K) | ||||
|  | ||||
| 	return &kexResult{ | ||||
| 		H:         h.Sum(nil), | ||||
| 		K:         K, | ||||
| 		HostKey:   reply.HostKey, | ||||
| 		Signature: reply.Signature, | ||||
| 		Hash:      crypto.SHA256, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { | ||||
| 	packet, err := c.readPacket() | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	var kexInit kexECDHInitMsg | ||||
| 	if err = Unmarshal(packet, &kexInit); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if len(kexInit.ClientPubKey) != 32 { | ||||
| 		return nil, errors.New("ssh: peer's curve25519 public value has wrong length") | ||||
| 	} | ||||
|  | ||||
| 	var kp curve25519KeyPair | ||||
| 	if err := kp.generate(rand); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var clientPub, secret [32]byte | ||||
| 	copy(clientPub[:], kexInit.ClientPubKey) | ||||
| 	curve25519.ScalarMult(&secret, &kp.priv, &clientPub) | ||||
| 	if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { | ||||
| 		return nil, errors.New("ssh: peer's curve25519 public value has wrong order") | ||||
| 	} | ||||
|  | ||||
| 	hostKeyBytes := priv.PublicKey().Marshal() | ||||
|  | ||||
| 	h := crypto.SHA256.New() | ||||
| 	magics.write(h) | ||||
| 	writeString(h, hostKeyBytes) | ||||
| 	writeString(h, kexInit.ClientPubKey) | ||||
| 	writeString(h, kp.pub[:]) | ||||
|  | ||||
| 	ki := new(big.Int).SetBytes(secret[:]) | ||||
| 	K := make([]byte, intLength(ki)) | ||||
| 	marshalInt(K, ki) | ||||
| 	h.Write(K) | ||||
|  | ||||
| 	H := h.Sum(nil) | ||||
|  | ||||
| 	sig, err := signAndMarshal(priv, rand, H) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	reply := kexECDHReplyMsg{ | ||||
| 		EphemeralPubKey: kp.pub[:], | ||||
| 		HostKey:         hostKeyBytes, | ||||
| 		Signature:       sig, | ||||
| 	} | ||||
| 	if err := c.writePacket(Marshal(&reply)); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &kexResult{ | ||||
| 		H:         H, | ||||
| 		K:         K, | ||||
| 		HostKey:   hostKeyBytes, | ||||
| 		Signature: sig, | ||||
| 		Hash:      crypto.SHA256, | ||||
| 	}, nil | ||||
| } | ||||
							
								
								
									
										1100
									
								
								vendor/golang.org/x/crypto/ssh/keys.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1100
									
								
								vendor/golang.org/x/crypto/ssh/keys.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										61
									
								
								vendor/golang.org/x/crypto/ssh/mac.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								vendor/golang.org/x/crypto/ssh/mac.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| // Copyright 2012 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 ssh | ||||
|  | ||||
| // Message authentication support | ||||
|  | ||||
| import ( | ||||
| 	"crypto/hmac" | ||||
| 	"crypto/sha1" | ||||
| 	"crypto/sha256" | ||||
| 	"hash" | ||||
| ) | ||||
|  | ||||
| type macMode struct { | ||||
| 	keySize int | ||||
| 	etm     bool | ||||
| 	new     func(key []byte) hash.Hash | ||||
| } | ||||
|  | ||||
| // truncatingMAC wraps around a hash.Hash and truncates the output digest to | ||||
| // a given size. | ||||
| type truncatingMAC struct { | ||||
| 	length int | ||||
| 	hmac   hash.Hash | ||||
| } | ||||
|  | ||||
| func (t truncatingMAC) Write(data []byte) (int, error) { | ||||
| 	return t.hmac.Write(data) | ||||
| } | ||||
|  | ||||
| func (t truncatingMAC) Sum(in []byte) []byte { | ||||
| 	out := t.hmac.Sum(in) | ||||
| 	return out[:len(in)+t.length] | ||||
| } | ||||
|  | ||||
| func (t truncatingMAC) Reset() { | ||||
| 	t.hmac.Reset() | ||||
| } | ||||
|  | ||||
| func (t truncatingMAC) Size() int { | ||||
| 	return t.length | ||||
| } | ||||
|  | ||||
| func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } | ||||
|  | ||||
| var macModes = map[string]*macMode{ | ||||
| 	"hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash { | ||||
| 		return hmac.New(sha256.New, key) | ||||
| 	}}, | ||||
| 	"hmac-sha2-256": {32, false, func(key []byte) hash.Hash { | ||||
| 		return hmac.New(sha256.New, key) | ||||
| 	}}, | ||||
| 	"hmac-sha1": {20, false, func(key []byte) hash.Hash { | ||||
| 		return hmac.New(sha1.New, key) | ||||
| 	}}, | ||||
| 	"hmac-sha1-96": {20, false, func(key []byte) hash.Hash { | ||||
| 		return truncatingMAC{12, hmac.New(sha1.New, key)} | ||||
| 	}}, | ||||
| } | ||||
							
								
								
									
										766
									
								
								vendor/golang.org/x/crypto/ssh/messages.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										766
									
								
								vendor/golang.org/x/crypto/ssh/messages.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,766 @@ | ||||
| // Copyright 2011 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/binary" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // These are SSH message type numbers. They are scattered around several | ||||
| // documents but many were taken from [SSH-PARAMETERS]. | ||||
| const ( | ||||
| 	msgIgnore        = 2 | ||||
| 	msgUnimplemented = 3 | ||||
| 	msgDebug         = 4 | ||||
| 	msgNewKeys       = 21 | ||||
| ) | ||||
|  | ||||
| // SSH messages: | ||||
| // | ||||
| // These structures mirror the wire format of the corresponding SSH messages. | ||||
| // They are marshaled using reflection with the marshal and unmarshal functions | ||||
| // in this file. The only wrinkle is that a final member of type []byte with a | ||||
| // ssh tag of "rest" receives the remainder of a packet when unmarshaling. | ||||
|  | ||||
| // See RFC 4253, section 11.1. | ||||
| const msgDisconnect = 1 | ||||
|  | ||||
| // disconnectMsg is the message that signals a disconnect. It is also | ||||
| // the error type returned from mux.Wait() | ||||
| type disconnectMsg struct { | ||||
| 	Reason   uint32 `sshtype:"1"` | ||||
| 	Message  string | ||||
| 	Language string | ||||
| } | ||||
|  | ||||
| func (d *disconnectMsg) Error() string { | ||||
| 	return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message) | ||||
| } | ||||
|  | ||||
| // See RFC 4253, section 7.1. | ||||
| const msgKexInit = 20 | ||||
|  | ||||
| type kexInitMsg struct { | ||||
| 	Cookie                  [16]byte `sshtype:"20"` | ||||
| 	KexAlgos                []string | ||||
| 	ServerHostKeyAlgos      []string | ||||
| 	CiphersClientServer     []string | ||||
| 	CiphersServerClient     []string | ||||
| 	MACsClientServer        []string | ||||
| 	MACsServerClient        []string | ||||
| 	CompressionClientServer []string | ||||
| 	CompressionServerClient []string | ||||
| 	LanguagesClientServer   []string | ||||
| 	LanguagesServerClient   []string | ||||
| 	FirstKexFollows         bool | ||||
| 	Reserved                uint32 | ||||
| } | ||||
|  | ||||
| // See RFC 4253, section 8. | ||||
|  | ||||
| // Diffie-Helman | ||||
| const msgKexDHInit = 30 | ||||
|  | ||||
| type kexDHInitMsg struct { | ||||
| 	X *big.Int `sshtype:"30"` | ||||
| } | ||||
|  | ||||
| const msgKexECDHInit = 30 | ||||
|  | ||||
| type kexECDHInitMsg struct { | ||||
| 	ClientPubKey []byte `sshtype:"30"` | ||||
| } | ||||
|  | ||||
| const msgKexECDHReply = 31 | ||||
|  | ||||
| type kexECDHReplyMsg struct { | ||||
| 	HostKey         []byte `sshtype:"31"` | ||||
| 	EphemeralPubKey []byte | ||||
| 	Signature       []byte | ||||
| } | ||||
|  | ||||
| const msgKexDHReply = 31 | ||||
|  | ||||
| type kexDHReplyMsg struct { | ||||
| 	HostKey   []byte `sshtype:"31"` | ||||
| 	Y         *big.Int | ||||
| 	Signature []byte | ||||
| } | ||||
|  | ||||
| // See RFC 4253, section 10. | ||||
| const msgServiceRequest = 5 | ||||
|  | ||||
| type serviceRequestMsg struct { | ||||
| 	Service string `sshtype:"5"` | ||||
| } | ||||
|  | ||||
| // See RFC 4253, section 10. | ||||
| const msgServiceAccept = 6 | ||||
|  | ||||
| type serviceAcceptMsg struct { | ||||
| 	Service string `sshtype:"6"` | ||||
| } | ||||
|  | ||||
| // See RFC 4252, section 5. | ||||
| const msgUserAuthRequest = 50 | ||||
|  | ||||
| type userAuthRequestMsg struct { | ||||
| 	User    string `sshtype:"50"` | ||||
| 	Service string | ||||
| 	Method  string | ||||
| 	Payload []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| // Used for debug printouts of packets. | ||||
| type userAuthSuccessMsg struct { | ||||
| } | ||||
|  | ||||
| // See RFC 4252, section 5.1 | ||||
| const msgUserAuthFailure = 51 | ||||
|  | ||||
| type userAuthFailureMsg struct { | ||||
| 	Methods        []string `sshtype:"51"` | ||||
| 	PartialSuccess bool | ||||
| } | ||||
|  | ||||
| // See RFC 4252, section 5.1 | ||||
| const msgUserAuthSuccess = 52 | ||||
|  | ||||
| // See RFC 4252, section 5.4 | ||||
| const msgUserAuthBanner = 53 | ||||
|  | ||||
| type userAuthBannerMsg struct { | ||||
| 	Message string `sshtype:"53"` | ||||
| 	// unused, but required to allow message parsing | ||||
| 	Language string | ||||
| } | ||||
|  | ||||
| // See RFC 4256, section 3.2 | ||||
| const msgUserAuthInfoRequest = 60 | ||||
| const msgUserAuthInfoResponse = 61 | ||||
|  | ||||
| type userAuthInfoRequestMsg struct { | ||||
| 	User               string `sshtype:"60"` | ||||
| 	Instruction        string | ||||
| 	DeprecatedLanguage string | ||||
| 	NumPrompts         uint32 | ||||
| 	Prompts            []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| // See RFC 4254, section 5.1. | ||||
| const msgChannelOpen = 90 | ||||
|  | ||||
| type channelOpenMsg struct { | ||||
| 	ChanType         string `sshtype:"90"` | ||||
| 	PeersID          uint32 | ||||
| 	PeersWindow      uint32 | ||||
| 	MaxPacketSize    uint32 | ||||
| 	TypeSpecificData []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| const msgChannelExtendedData = 95 | ||||
| const msgChannelData = 94 | ||||
|  | ||||
| // Used for debug print outs of packets. | ||||
| type channelDataMsg struct { | ||||
| 	PeersID uint32 `sshtype:"94"` | ||||
| 	Length  uint32 | ||||
| 	Rest    []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| // See RFC 4254, section 5.1. | ||||
| const msgChannelOpenConfirm = 91 | ||||
|  | ||||
| type channelOpenConfirmMsg struct { | ||||
| 	PeersID          uint32 `sshtype:"91"` | ||||
| 	MyID             uint32 | ||||
| 	MyWindow         uint32 | ||||
| 	MaxPacketSize    uint32 | ||||
| 	TypeSpecificData []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| // See RFC 4254, section 5.1. | ||||
| const msgChannelOpenFailure = 92 | ||||
|  | ||||
| type channelOpenFailureMsg struct { | ||||
| 	PeersID  uint32 `sshtype:"92"` | ||||
| 	Reason   RejectionReason | ||||
| 	Message  string | ||||
| 	Language string | ||||
| } | ||||
|  | ||||
| const msgChannelRequest = 98 | ||||
|  | ||||
| type channelRequestMsg struct { | ||||
| 	PeersID             uint32 `sshtype:"98"` | ||||
| 	Request             string | ||||
| 	WantReply           bool | ||||
| 	RequestSpecificData []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| // See RFC 4254, section 5.4. | ||||
| const msgChannelSuccess = 99 | ||||
|  | ||||
| type channelRequestSuccessMsg struct { | ||||
| 	PeersID uint32 `sshtype:"99"` | ||||
| } | ||||
|  | ||||
| // See RFC 4254, section 5.4. | ||||
| const msgChannelFailure = 100 | ||||
|  | ||||
| type channelRequestFailureMsg struct { | ||||
| 	PeersID uint32 `sshtype:"100"` | ||||
| } | ||||
|  | ||||
| // See RFC 4254, section 5.3 | ||||
| const msgChannelClose = 97 | ||||
|  | ||||
| type channelCloseMsg struct { | ||||
| 	PeersID uint32 `sshtype:"97"` | ||||
| } | ||||
|  | ||||
| // See RFC 4254, section 5.3 | ||||
| const msgChannelEOF = 96 | ||||
|  | ||||
| type channelEOFMsg struct { | ||||
| 	PeersID uint32 `sshtype:"96"` | ||||
| } | ||||
|  | ||||
| // See RFC 4254, section 4 | ||||
| const msgGlobalRequest = 80 | ||||
|  | ||||
| type globalRequestMsg struct { | ||||
| 	Type      string `sshtype:"80"` | ||||
| 	WantReply bool | ||||
| 	Data      []byte `ssh:"rest"` | ||||
| } | ||||
|  | ||||
| // See RFC 4254, section 4 | ||||
| const msgRequestSuccess = 81 | ||||
|  | ||||
| type globalRequestSuccessMsg struct { | ||||
| 	Data []byte `ssh:"rest" sshtype:"81"` | ||||
| } | ||||
|  | ||||
| // See RFC 4254, section 4 | ||||
| const msgRequestFailure = 82 | ||||
|  | ||||
| type globalRequestFailureMsg struct { | ||||
| 	Data []byte `ssh:"rest" sshtype:"82"` | ||||
| } | ||||
|  | ||||
| // See RFC 4254, section 5.2 | ||||
| const msgChannelWindowAdjust = 93 | ||||
|  | ||||
| type windowAdjustMsg struct { | ||||
| 	PeersID         uint32 `sshtype:"93"` | ||||
| 	AdditionalBytes uint32 | ||||
| } | ||||
|  | ||||
| // See RFC 4252, section 7 | ||||
| const msgUserAuthPubKeyOk = 60 | ||||
|  | ||||
| type userAuthPubKeyOkMsg struct { | ||||
| 	Algo   string `sshtype:"60"` | ||||
| 	PubKey []byte | ||||
| } | ||||
|  | ||||
| // typeTags returns the possible type bytes for the given reflect.Type, which | ||||
| // should be a struct. The possible values are separated by a '|' character. | ||||
| func typeTags(structType reflect.Type) (tags []byte) { | ||||
| 	tagStr := structType.Field(0).Tag.Get("sshtype") | ||||
|  | ||||
| 	for _, tag := range strings.Split(tagStr, "|") { | ||||
| 		i, err := strconv.Atoi(tag) | ||||
| 		if err == nil { | ||||
| 			tags = append(tags, byte(i)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return tags | ||||
| } | ||||
|  | ||||
| func fieldError(t reflect.Type, field int, problem string) error { | ||||
| 	if problem != "" { | ||||
| 		problem = ": " + problem | ||||
| 	} | ||||
| 	return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", t.Field(field).Name, t.Name(), problem) | ||||
| } | ||||
|  | ||||
| var errShortRead = errors.New("ssh: short read") | ||||
|  | ||||
| // Unmarshal parses data in SSH wire format into a structure. The out | ||||
| // argument should be a pointer to struct. If the first member of the | ||||
| // struct has the "sshtype" tag set to a '|'-separated set of numbers | ||||
| // in decimal, the packet must start with one of those numbers. In | ||||
| // case of error, Unmarshal returns a ParseError or | ||||
| // UnexpectedMessageError. | ||||
| func Unmarshal(data []byte, out interface{}) error { | ||||
| 	v := reflect.ValueOf(out).Elem() | ||||
| 	structType := v.Type() | ||||
| 	expectedTypes := typeTags(structType) | ||||
|  | ||||
| 	var expectedType byte | ||||
| 	if len(expectedTypes) > 0 { | ||||
| 		expectedType = expectedTypes[0] | ||||
| 	} | ||||
|  | ||||
| 	if len(data) == 0 { | ||||
| 		return parseError(expectedType) | ||||
| 	} | ||||
|  | ||||
| 	if len(expectedTypes) > 0 { | ||||
| 		goodType := false | ||||
| 		for _, e := range expectedTypes { | ||||
| 			if e > 0 && data[0] == e { | ||||
| 				goodType = true | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		if !goodType { | ||||
| 			return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", data[0], expectedTypes) | ||||
| 		} | ||||
| 		data = data[1:] | ||||
| 	} | ||||
|  | ||||
| 	var ok bool | ||||
| 	for i := 0; i < v.NumField(); i++ { | ||||
| 		field := v.Field(i) | ||||
| 		t := field.Type() | ||||
| 		switch t.Kind() { | ||||
| 		case reflect.Bool: | ||||
| 			if len(data) < 1 { | ||||
| 				return errShortRead | ||||
| 			} | ||||
| 			field.SetBool(data[0] != 0) | ||||
| 			data = data[1:] | ||||
| 		case reflect.Array: | ||||
| 			if t.Elem().Kind() != reflect.Uint8 { | ||||
| 				return fieldError(structType, i, "array of unsupported type") | ||||
| 			} | ||||
| 			if len(data) < t.Len() { | ||||
| 				return errShortRead | ||||
| 			} | ||||
| 			for j, n := 0, t.Len(); j < n; j++ { | ||||
| 				field.Index(j).Set(reflect.ValueOf(data[j])) | ||||
| 			} | ||||
| 			data = data[t.Len():] | ||||
| 		case reflect.Uint64: | ||||
| 			var u64 uint64 | ||||
| 			if u64, data, ok = parseUint64(data); !ok { | ||||
| 				return errShortRead | ||||
| 			} | ||||
| 			field.SetUint(u64) | ||||
| 		case reflect.Uint32: | ||||
| 			var u32 uint32 | ||||
| 			if u32, data, ok = parseUint32(data); !ok { | ||||
| 				return errShortRead | ||||
| 			} | ||||
| 			field.SetUint(uint64(u32)) | ||||
| 		case reflect.Uint8: | ||||
| 			if len(data) < 1 { | ||||
| 				return errShortRead | ||||
| 			} | ||||
| 			field.SetUint(uint64(data[0])) | ||||
| 			data = data[1:] | ||||
| 		case reflect.String: | ||||
| 			var s []byte | ||||
| 			if s, data, ok = parseString(data); !ok { | ||||
| 				return fieldError(structType, i, "") | ||||
| 			} | ||||
| 			field.SetString(string(s)) | ||||
| 		case reflect.Slice: | ||||
| 			switch t.Elem().Kind() { | ||||
| 			case reflect.Uint8: | ||||
| 				if structType.Field(i).Tag.Get("ssh") == "rest" { | ||||
| 					field.Set(reflect.ValueOf(data)) | ||||
| 					data = nil | ||||
| 				} else { | ||||
| 					var s []byte | ||||
| 					if s, data, ok = parseString(data); !ok { | ||||
| 						return errShortRead | ||||
| 					} | ||||
| 					field.Set(reflect.ValueOf(s)) | ||||
| 				} | ||||
| 			case reflect.String: | ||||
| 				var nl []string | ||||
| 				if nl, data, ok = parseNameList(data); !ok { | ||||
| 					return errShortRead | ||||
| 				} | ||||
| 				field.Set(reflect.ValueOf(nl)) | ||||
| 			default: | ||||
| 				return fieldError(structType, i, "slice of unsupported type") | ||||
| 			} | ||||
| 		case reflect.Ptr: | ||||
| 			if t == bigIntType { | ||||
| 				var n *big.Int | ||||
| 				if n, data, ok = parseInt(data); !ok { | ||||
| 					return errShortRead | ||||
| 				} | ||||
| 				field.Set(reflect.ValueOf(n)) | ||||
| 			} else { | ||||
| 				return fieldError(structType, i, "pointer to unsupported type") | ||||
| 			} | ||||
| 		default: | ||||
| 			return fieldError(structType, i, fmt.Sprintf("unsupported type: %v", t)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(data) != 0 { | ||||
| 		return parseError(expectedType) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Marshal serializes the message in msg to SSH wire format.  The msg | ||||
| // argument should be a struct or pointer to struct. If the first | ||||
| // member has the "sshtype" tag set to a number in decimal, that | ||||
| // number is prepended to the result. If the last of member has the | ||||
| // "ssh" tag set to "rest", its contents are appended to the output. | ||||
| func Marshal(msg interface{}) []byte { | ||||
| 	out := make([]byte, 0, 64) | ||||
| 	return marshalStruct(out, msg) | ||||
| } | ||||
|  | ||||
| func marshalStruct(out []byte, msg interface{}) []byte { | ||||
| 	v := reflect.Indirect(reflect.ValueOf(msg)) | ||||
| 	msgTypes := typeTags(v.Type()) | ||||
| 	if len(msgTypes) > 0 { | ||||
| 		out = append(out, msgTypes[0]) | ||||
| 	} | ||||
|  | ||||
| 	for i, n := 0, v.NumField(); i < n; i++ { | ||||
| 		field := v.Field(i) | ||||
| 		switch t := field.Type(); t.Kind() { | ||||
| 		case reflect.Bool: | ||||
| 			var v uint8 | ||||
| 			if field.Bool() { | ||||
| 				v = 1 | ||||
| 			} | ||||
| 			out = append(out, v) | ||||
| 		case reflect.Array: | ||||
| 			if t.Elem().Kind() != reflect.Uint8 { | ||||
| 				panic(fmt.Sprintf("array of non-uint8 in field %d: %T", i, field.Interface())) | ||||
| 			} | ||||
| 			for j, l := 0, t.Len(); j < l; j++ { | ||||
| 				out = append(out, uint8(field.Index(j).Uint())) | ||||
| 			} | ||||
| 		case reflect.Uint32: | ||||
| 			out = appendU32(out, uint32(field.Uint())) | ||||
| 		case reflect.Uint64: | ||||
| 			out = appendU64(out, uint64(field.Uint())) | ||||
| 		case reflect.Uint8: | ||||
| 			out = append(out, uint8(field.Uint())) | ||||
| 		case reflect.String: | ||||
| 			s := field.String() | ||||
| 			out = appendInt(out, len(s)) | ||||
| 			out = append(out, s...) | ||||
| 		case reflect.Slice: | ||||
| 			switch t.Elem().Kind() { | ||||
| 			case reflect.Uint8: | ||||
| 				if v.Type().Field(i).Tag.Get("ssh") != "rest" { | ||||
| 					out = appendInt(out, field.Len()) | ||||
| 				} | ||||
| 				out = append(out, field.Bytes()...) | ||||
| 			case reflect.String: | ||||
| 				offset := len(out) | ||||
| 				out = appendU32(out, 0) | ||||
| 				if n := field.Len(); n > 0 { | ||||
| 					for j := 0; j < n; j++ { | ||||
| 						f := field.Index(j) | ||||
| 						if j != 0 { | ||||
| 							out = append(out, ',') | ||||
| 						} | ||||
| 						out = append(out, f.String()...) | ||||
| 					} | ||||
| 					// overwrite length value | ||||
| 					binary.BigEndian.PutUint32(out[offset:], uint32(len(out)-offset-4)) | ||||
| 				} | ||||
| 			default: | ||||
| 				panic(fmt.Sprintf("slice of unknown type in field %d: %T", i, field.Interface())) | ||||
| 			} | ||||
| 		case reflect.Ptr: | ||||
| 			if t == bigIntType { | ||||
| 				var n *big.Int | ||||
| 				nValue := reflect.ValueOf(&n) | ||||
| 				nValue.Elem().Set(field) | ||||
| 				needed := intLength(n) | ||||
| 				oldLength := len(out) | ||||
|  | ||||
| 				if cap(out)-len(out) < needed { | ||||
| 					newOut := make([]byte, len(out), 2*(len(out)+needed)) | ||||
| 					copy(newOut, out) | ||||
| 					out = newOut | ||||
| 				} | ||||
| 				out = out[:oldLength+needed] | ||||
| 				marshalInt(out[oldLength:], n) | ||||
| 			} else { | ||||
| 				panic(fmt.Sprintf("pointer to unknown type in field %d: %T", i, field.Interface())) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return out | ||||
| } | ||||
|  | ||||
| var bigOne = big.NewInt(1) | ||||
|  | ||||
| func parseString(in []byte) (out, rest []byte, ok bool) { | ||||
| 	if len(in) < 4 { | ||||
| 		return | ||||
| 	} | ||||
| 	length := binary.BigEndian.Uint32(in) | ||||
| 	in = in[4:] | ||||
| 	if uint32(len(in)) < length { | ||||
| 		return | ||||
| 	} | ||||
| 	out = in[:length] | ||||
| 	rest = in[length:] | ||||
| 	ok = true | ||||
| 	return | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	comma         = []byte{','} | ||||
| 	emptyNameList = []string{} | ||||
| ) | ||||
|  | ||||
| func parseNameList(in []byte) (out []string, rest []byte, ok bool) { | ||||
| 	contents, rest, ok := parseString(in) | ||||
| 	if !ok { | ||||
| 		return | ||||
| 	} | ||||
| 	if len(contents) == 0 { | ||||
| 		out = emptyNameList | ||||
| 		return | ||||
| 	} | ||||
| 	parts := bytes.Split(contents, comma) | ||||
| 	out = make([]string, len(parts)) | ||||
| 	for i, part := range parts { | ||||
| 		out[i] = string(part) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) { | ||||
| 	contents, rest, ok := parseString(in) | ||||
| 	if !ok { | ||||
| 		return | ||||
| 	} | ||||
| 	out = new(big.Int) | ||||
|  | ||||
| 	if len(contents) > 0 && contents[0]&0x80 == 0x80 { | ||||
| 		// This is a negative number | ||||
| 		notBytes := make([]byte, len(contents)) | ||||
| 		for i := range notBytes { | ||||
| 			notBytes[i] = ^contents[i] | ||||
| 		} | ||||
| 		out.SetBytes(notBytes) | ||||
| 		out.Add(out, bigOne) | ||||
| 		out.Neg(out) | ||||
| 	} else { | ||||
| 		// Positive number | ||||
| 		out.SetBytes(contents) | ||||
| 	} | ||||
| 	ok = true | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func parseUint32(in []byte) (uint32, []byte, bool) { | ||||
| 	if len(in) < 4 { | ||||
| 		return 0, nil, false | ||||
| 	} | ||||
| 	return binary.BigEndian.Uint32(in), in[4:], true | ||||
| } | ||||
|  | ||||
| func parseUint64(in []byte) (uint64, []byte, bool) { | ||||
| 	if len(in) < 8 { | ||||
| 		return 0, nil, false | ||||
| 	} | ||||
| 	return binary.BigEndian.Uint64(in), in[8:], true | ||||
| } | ||||
|  | ||||
| func intLength(n *big.Int) int { | ||||
| 	length := 4 /* length bytes */ | ||||
| 	if n.Sign() < 0 { | ||||
| 		nMinus1 := new(big.Int).Neg(n) | ||||
| 		nMinus1.Sub(nMinus1, bigOne) | ||||
| 		bitLen := nMinus1.BitLen() | ||||
| 		if bitLen%8 == 0 { | ||||
| 			// The number will need 0xff padding | ||||
| 			length++ | ||||
| 		} | ||||
| 		length += (bitLen + 7) / 8 | ||||
| 	} else if n.Sign() == 0 { | ||||
| 		// A zero is the zero length string | ||||
| 	} else { | ||||
| 		bitLen := n.BitLen() | ||||
| 		if bitLen%8 == 0 { | ||||
| 			// The number will need 0x00 padding | ||||
| 			length++ | ||||
| 		} | ||||
| 		length += (bitLen + 7) / 8 | ||||
| 	} | ||||
|  | ||||
| 	return length | ||||
| } | ||||
|  | ||||
| func marshalUint32(to []byte, n uint32) []byte { | ||||
| 	binary.BigEndian.PutUint32(to, n) | ||||
| 	return to[4:] | ||||
| } | ||||
|  | ||||
| func marshalUint64(to []byte, n uint64) []byte { | ||||
| 	binary.BigEndian.PutUint64(to, n) | ||||
| 	return to[8:] | ||||
| } | ||||
|  | ||||
| func marshalInt(to []byte, n *big.Int) []byte { | ||||
| 	lengthBytes := to | ||||
| 	to = to[4:] | ||||
| 	length := 0 | ||||
|  | ||||
| 	if n.Sign() < 0 { | ||||
| 		// A negative number has to be converted to two's-complement | ||||
| 		// form. So we'll subtract 1 and invert. If the | ||||
| 		// most-significant-bit isn't set then we'll need to pad the | ||||
| 		// beginning with 0xff in order to keep the number negative. | ||||
| 		nMinus1 := new(big.Int).Neg(n) | ||||
| 		nMinus1.Sub(nMinus1, bigOne) | ||||
| 		bytes := nMinus1.Bytes() | ||||
| 		for i := range bytes { | ||||
| 			bytes[i] ^= 0xff | ||||
| 		} | ||||
| 		if len(bytes) == 0 || bytes[0]&0x80 == 0 { | ||||
| 			to[0] = 0xff | ||||
| 			to = to[1:] | ||||
| 			length++ | ||||
| 		} | ||||
| 		nBytes := copy(to, bytes) | ||||
| 		to = to[nBytes:] | ||||
| 		length += nBytes | ||||
| 	} else if n.Sign() == 0 { | ||||
| 		// A zero is the zero length string | ||||
| 	} else { | ||||
| 		bytes := n.Bytes() | ||||
| 		if len(bytes) > 0 && bytes[0]&0x80 != 0 { | ||||
| 			// We'll have to pad this with a 0x00 in order to | ||||
| 			// stop it looking like a negative number. | ||||
| 			to[0] = 0 | ||||
| 			to = to[1:] | ||||
| 			length++ | ||||
| 		} | ||||
| 		nBytes := copy(to, bytes) | ||||
| 		to = to[nBytes:] | ||||
| 		length += nBytes | ||||
| 	} | ||||
|  | ||||
| 	lengthBytes[0] = byte(length >> 24) | ||||
| 	lengthBytes[1] = byte(length >> 16) | ||||
| 	lengthBytes[2] = byte(length >> 8) | ||||
| 	lengthBytes[3] = byte(length) | ||||
| 	return to | ||||
| } | ||||
|  | ||||
| func writeInt(w io.Writer, n *big.Int) { | ||||
| 	length := intLength(n) | ||||
| 	buf := make([]byte, length) | ||||
| 	marshalInt(buf, n) | ||||
| 	w.Write(buf) | ||||
| } | ||||
|  | ||||
| func writeString(w io.Writer, s []byte) { | ||||
| 	var lengthBytes [4]byte | ||||
| 	lengthBytes[0] = byte(len(s) >> 24) | ||||
| 	lengthBytes[1] = byte(len(s) >> 16) | ||||
| 	lengthBytes[2] = byte(len(s) >> 8) | ||||
| 	lengthBytes[3] = byte(len(s)) | ||||
| 	w.Write(lengthBytes[:]) | ||||
| 	w.Write(s) | ||||
| } | ||||
|  | ||||
| func stringLength(n int) int { | ||||
| 	return 4 + n | ||||
| } | ||||
|  | ||||
| func marshalString(to []byte, s []byte) []byte { | ||||
| 	to[0] = byte(len(s) >> 24) | ||||
| 	to[1] = byte(len(s) >> 16) | ||||
| 	to[2] = byte(len(s) >> 8) | ||||
| 	to[3] = byte(len(s)) | ||||
| 	to = to[4:] | ||||
| 	copy(to, s) | ||||
| 	return to[len(s):] | ||||
| } | ||||
|  | ||||
| var bigIntType = reflect.TypeOf((*big.Int)(nil)) | ||||
|  | ||||
| // Decode a packet into its corresponding message. | ||||
| func decode(packet []byte) (interface{}, error) { | ||||
| 	var msg interface{} | ||||
| 	switch packet[0] { | ||||
| 	case msgDisconnect: | ||||
| 		msg = new(disconnectMsg) | ||||
| 	case msgServiceRequest: | ||||
| 		msg = new(serviceRequestMsg) | ||||
| 	case msgServiceAccept: | ||||
| 		msg = new(serviceAcceptMsg) | ||||
| 	case msgKexInit: | ||||
| 		msg = new(kexInitMsg) | ||||
| 	case msgKexDHInit: | ||||
| 		msg = new(kexDHInitMsg) | ||||
| 	case msgKexDHReply: | ||||
| 		msg = new(kexDHReplyMsg) | ||||
| 	case msgUserAuthRequest: | ||||
| 		msg = new(userAuthRequestMsg) | ||||
| 	case msgUserAuthSuccess: | ||||
| 		return new(userAuthSuccessMsg), nil | ||||
| 	case msgUserAuthFailure: | ||||
| 		msg = new(userAuthFailureMsg) | ||||
| 	case msgUserAuthPubKeyOk: | ||||
| 		msg = new(userAuthPubKeyOkMsg) | ||||
| 	case msgGlobalRequest: | ||||
| 		msg = new(globalRequestMsg) | ||||
| 	case msgRequestSuccess: | ||||
| 		msg = new(globalRequestSuccessMsg) | ||||
| 	case msgRequestFailure: | ||||
| 		msg = new(globalRequestFailureMsg) | ||||
| 	case msgChannelOpen: | ||||
| 		msg = new(channelOpenMsg) | ||||
| 	case msgChannelData: | ||||
| 		msg = new(channelDataMsg) | ||||
| 	case msgChannelOpenConfirm: | ||||
| 		msg = new(channelOpenConfirmMsg) | ||||
| 	case msgChannelOpenFailure: | ||||
| 		msg = new(channelOpenFailureMsg) | ||||
| 	case msgChannelWindowAdjust: | ||||
| 		msg = new(windowAdjustMsg) | ||||
| 	case msgChannelEOF: | ||||
| 		msg = new(channelEOFMsg) | ||||
| 	case msgChannelClose: | ||||
| 		msg = new(channelCloseMsg) | ||||
| 	case msgChannelRequest: | ||||
| 		msg = new(channelRequestMsg) | ||||
| 	case msgChannelSuccess: | ||||
| 		msg = new(channelRequestSuccessMsg) | ||||
| 	case msgChannelFailure: | ||||
| 		msg = new(channelRequestFailureMsg) | ||||
| 	default: | ||||
| 		return nil, unexpectedMessageError(0, packet[0]) | ||||
| 	} | ||||
| 	if err := Unmarshal(packet, msg); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return msg, nil | ||||
| } | ||||
							
								
								
									
										330
									
								
								vendor/golang.org/x/crypto/ssh/mux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										330
									
								
								vendor/golang.org/x/crypto/ssh/mux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,330 @@ | ||||
| // Copyright 2013 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
| ) | ||||
|  | ||||
| // debugMux, if set, causes messages in the connection protocol to be | ||||
| // logged. | ||||
| const debugMux = false | ||||
|  | ||||
| // chanList is a thread safe channel list. | ||||
| type chanList struct { | ||||
| 	// protects concurrent access to chans | ||||
| 	sync.Mutex | ||||
|  | ||||
| 	// chans are indexed by the local id of the channel, which the | ||||
| 	// other side should send in the PeersId field. | ||||
| 	chans []*channel | ||||
|  | ||||
| 	// This is a debugging aid: it offsets all IDs by this | ||||
| 	// amount. This helps distinguish otherwise identical | ||||
| 	// server/client muxes | ||||
| 	offset uint32 | ||||
| } | ||||
|  | ||||
| // Assigns a channel ID to the given channel. | ||||
| func (c *chanList) add(ch *channel) uint32 { | ||||
| 	c.Lock() | ||||
| 	defer c.Unlock() | ||||
| 	for i := range c.chans { | ||||
| 		if c.chans[i] == nil { | ||||
| 			c.chans[i] = ch | ||||
| 			return uint32(i) + c.offset | ||||
| 		} | ||||
| 	} | ||||
| 	c.chans = append(c.chans, ch) | ||||
| 	return uint32(len(c.chans)-1) + c.offset | ||||
| } | ||||
|  | ||||
| // getChan returns the channel for the given ID. | ||||
| func (c *chanList) getChan(id uint32) *channel { | ||||
| 	id -= c.offset | ||||
|  | ||||
| 	c.Lock() | ||||
| 	defer c.Unlock() | ||||
| 	if id < uint32(len(c.chans)) { | ||||
| 		return c.chans[id] | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *chanList) remove(id uint32) { | ||||
| 	id -= c.offset | ||||
| 	c.Lock() | ||||
| 	if id < uint32(len(c.chans)) { | ||||
| 		c.chans[id] = nil | ||||
| 	} | ||||
| 	c.Unlock() | ||||
| } | ||||
|  | ||||
| // dropAll forgets all channels it knows, returning them in a slice. | ||||
| func (c *chanList) dropAll() []*channel { | ||||
| 	c.Lock() | ||||
| 	defer c.Unlock() | ||||
| 	var r []*channel | ||||
|  | ||||
| 	for _, ch := range c.chans { | ||||
| 		if ch == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		r = append(r, ch) | ||||
| 	} | ||||
| 	c.chans = nil | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // mux represents the state for the SSH connection protocol, which | ||||
| // multiplexes many channels onto a single packet transport. | ||||
| type mux struct { | ||||
| 	conn     packetConn | ||||
| 	chanList chanList | ||||
|  | ||||
| 	incomingChannels chan NewChannel | ||||
|  | ||||
| 	globalSentMu     sync.Mutex | ||||
| 	globalResponses  chan interface{} | ||||
| 	incomingRequests chan *Request | ||||
|  | ||||
| 	errCond *sync.Cond | ||||
| 	err     error | ||||
| } | ||||
|  | ||||
| // When debugging, each new chanList instantiation has a different | ||||
| // offset. | ||||
| var globalOff uint32 | ||||
|  | ||||
| func (m *mux) Wait() error { | ||||
| 	m.errCond.L.Lock() | ||||
| 	defer m.errCond.L.Unlock() | ||||
| 	for m.err == nil { | ||||
| 		m.errCond.Wait() | ||||
| 	} | ||||
| 	return m.err | ||||
| } | ||||
|  | ||||
| // newMux returns a mux that runs over the given connection. | ||||
| func newMux(p packetConn) *mux { | ||||
| 	m := &mux{ | ||||
| 		conn:             p, | ||||
| 		incomingChannels: make(chan NewChannel, chanSize), | ||||
| 		globalResponses:  make(chan interface{}, 1), | ||||
| 		incomingRequests: make(chan *Request, chanSize), | ||||
| 		errCond:          newCond(), | ||||
| 	} | ||||
| 	if debugMux { | ||||
| 		m.chanList.offset = atomic.AddUint32(&globalOff, 1) | ||||
| 	} | ||||
|  | ||||
| 	go m.loop() | ||||
| 	return m | ||||
| } | ||||
|  | ||||
| func (m *mux) sendMessage(msg interface{}) error { | ||||
| 	p := Marshal(msg) | ||||
| 	if debugMux { | ||||
| 		log.Printf("send global(%d): %#v", m.chanList.offset, msg) | ||||
| 	} | ||||
| 	return m.conn.writePacket(p) | ||||
| } | ||||
|  | ||||
| func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) { | ||||
| 	if wantReply { | ||||
| 		m.globalSentMu.Lock() | ||||
| 		defer m.globalSentMu.Unlock() | ||||
| 	} | ||||
|  | ||||
| 	if err := m.sendMessage(globalRequestMsg{ | ||||
| 		Type:      name, | ||||
| 		WantReply: wantReply, | ||||
| 		Data:      payload, | ||||
| 	}); err != nil { | ||||
| 		return false, nil, err | ||||
| 	} | ||||
|  | ||||
| 	if !wantReply { | ||||
| 		return false, nil, nil | ||||
| 	} | ||||
|  | ||||
| 	msg, ok := <-m.globalResponses | ||||
| 	if !ok { | ||||
| 		return false, nil, io.EOF | ||||
| 	} | ||||
| 	switch msg := msg.(type) { | ||||
| 	case *globalRequestFailureMsg: | ||||
| 		return false, msg.Data, nil | ||||
| 	case *globalRequestSuccessMsg: | ||||
| 		return true, msg.Data, nil | ||||
| 	default: | ||||
| 		return false, nil, fmt.Errorf("ssh: unexpected response to request: %#v", msg) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ackRequest must be called after processing a global request that | ||||
| // has WantReply set. | ||||
| func (m *mux) ackRequest(ok bool, data []byte) error { | ||||
| 	if ok { | ||||
| 		return m.sendMessage(globalRequestSuccessMsg{Data: data}) | ||||
| 	} | ||||
| 	return m.sendMessage(globalRequestFailureMsg{Data: data}) | ||||
| } | ||||
|  | ||||
| func (m *mux) Close() error { | ||||
| 	return m.conn.Close() | ||||
| } | ||||
|  | ||||
| // loop runs the connection machine. It will process packets until an | ||||
| // error is encountered. To synchronize on loop exit, use mux.Wait. | ||||
| func (m *mux) loop() { | ||||
| 	var err error | ||||
| 	for err == nil { | ||||
| 		err = m.onePacket() | ||||
| 	} | ||||
|  | ||||
| 	for _, ch := range m.chanList.dropAll() { | ||||
| 		ch.close() | ||||
| 	} | ||||
|  | ||||
| 	close(m.incomingChannels) | ||||
| 	close(m.incomingRequests) | ||||
| 	close(m.globalResponses) | ||||
|  | ||||
| 	m.conn.Close() | ||||
|  | ||||
| 	m.errCond.L.Lock() | ||||
| 	m.err = err | ||||
| 	m.errCond.Broadcast() | ||||
| 	m.errCond.L.Unlock() | ||||
|  | ||||
| 	if debugMux { | ||||
| 		log.Println("loop exit", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // onePacket reads and processes one packet. | ||||
| func (m *mux) onePacket() error { | ||||
| 	packet, err := m.conn.readPacket() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if debugMux { | ||||
| 		if packet[0] == msgChannelData || packet[0] == msgChannelExtendedData { | ||||
| 			log.Printf("decoding(%d): data packet - %d bytes", m.chanList.offset, len(packet)) | ||||
| 		} else { | ||||
| 			p, _ := decode(packet) | ||||
| 			log.Printf("decoding(%d): %d %#v - %d bytes", m.chanList.offset, packet[0], p, len(packet)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	switch packet[0] { | ||||
| 	case msgChannelOpen: | ||||
| 		return m.handleChannelOpen(packet) | ||||
| 	case msgGlobalRequest, msgRequestSuccess, msgRequestFailure: | ||||
| 		return m.handleGlobalPacket(packet) | ||||
| 	} | ||||
|  | ||||
| 	// assume a channel packet. | ||||
| 	if len(packet) < 5 { | ||||
| 		return parseError(packet[0]) | ||||
| 	} | ||||
| 	id := binary.BigEndian.Uint32(packet[1:]) | ||||
| 	ch := m.chanList.getChan(id) | ||||
| 	if ch == nil { | ||||
| 		return fmt.Errorf("ssh: invalid channel %d", id) | ||||
| 	} | ||||
|  | ||||
| 	return ch.handlePacket(packet) | ||||
| } | ||||
|  | ||||
| func (m *mux) handleGlobalPacket(packet []byte) error { | ||||
| 	msg, err := decode(packet) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	switch msg := msg.(type) { | ||||
| 	case *globalRequestMsg: | ||||
| 		m.incomingRequests <- &Request{ | ||||
| 			Type:      msg.Type, | ||||
| 			WantReply: msg.WantReply, | ||||
| 			Payload:   msg.Data, | ||||
| 			mux:       m, | ||||
| 		} | ||||
| 	case *globalRequestSuccessMsg, *globalRequestFailureMsg: | ||||
| 		m.globalResponses <- msg | ||||
| 	default: | ||||
| 		panic(fmt.Sprintf("not a global message %#v", msg)) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // handleChannelOpen schedules a channel to be Accept()ed. | ||||
| func (m *mux) handleChannelOpen(packet []byte) error { | ||||
| 	var msg channelOpenMsg | ||||
| 	if err := Unmarshal(packet, &msg); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { | ||||
| 		failMsg := channelOpenFailureMsg{ | ||||
| 			PeersID:  msg.PeersID, | ||||
| 			Reason:   ConnectionFailed, | ||||
| 			Message:  "invalid request", | ||||
| 			Language: "en_US.UTF-8", | ||||
| 		} | ||||
| 		return m.sendMessage(failMsg) | ||||
| 	} | ||||
|  | ||||
| 	c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData) | ||||
| 	c.remoteId = msg.PeersID | ||||
| 	c.maxRemotePayload = msg.MaxPacketSize | ||||
| 	c.remoteWin.add(msg.PeersWindow) | ||||
| 	m.incomingChannels <- c | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Request, error) { | ||||
| 	ch, err := m.openChannel(chanType, extra) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	return ch, ch.incomingRequests, nil | ||||
| } | ||||
|  | ||||
| func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) { | ||||
| 	ch := m.newChannel(chanType, channelOutbound, extra) | ||||
|  | ||||
| 	ch.maxIncomingPayload = channelMaxPacket | ||||
|  | ||||
| 	open := channelOpenMsg{ | ||||
| 		ChanType:         chanType, | ||||
| 		PeersWindow:      ch.myWindow, | ||||
| 		MaxPacketSize:    ch.maxIncomingPayload, | ||||
| 		TypeSpecificData: extra, | ||||
| 		PeersID:          ch.localId, | ||||
| 	} | ||||
| 	if err := m.sendMessage(open); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	switch msg := (<-ch.msg).(type) { | ||||
| 	case *channelOpenConfirmMsg: | ||||
| 		return ch, nil | ||||
| 	case *channelOpenFailureMsg: | ||||
| 		return nil, &OpenChannelError{msg.Reason, msg.Message} | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										594
									
								
								vendor/golang.org/x/crypto/ssh/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										594
									
								
								vendor/golang.org/x/crypto/ssh/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,594 @@ | ||||
| // Copyright 2011 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // The Permissions type holds fine-grained permissions that are | ||||
| // specific to a user or a specific authentication method for a user. | ||||
| // The Permissions value for a successful authentication attempt is | ||||
| // available in ServerConn, so it can be used to pass information from | ||||
| // the user-authentication phase to the application layer. | ||||
| type Permissions struct { | ||||
| 	// CriticalOptions indicate restrictions to the default | ||||
| 	// permissions, and are typically used in conjunction with | ||||
| 	// user certificates. The standard for SSH certificates | ||||
| 	// defines "force-command" (only allow the given command to | ||||
| 	// execute) and "source-address" (only allow connections from | ||||
| 	// the given address). The SSH package currently only enforces | ||||
| 	// the "source-address" critical option. It is up to server | ||||
| 	// implementations to enforce other critical options, such as | ||||
| 	// "force-command", by checking them after the SSH handshake | ||||
| 	// is successful. In general, SSH servers should reject | ||||
| 	// connections that specify critical options that are unknown | ||||
| 	// or not supported. | ||||
| 	CriticalOptions map[string]string | ||||
|  | ||||
| 	// Extensions are extra functionality that the server may | ||||
| 	// offer on authenticated connections. Lack of support for an | ||||
| 	// extension does not preclude authenticating a user. Common | ||||
| 	// extensions are "permit-agent-forwarding", | ||||
| 	// "permit-X11-forwarding". The Go SSH library currently does | ||||
| 	// not act on any extension, and it is up to server | ||||
| 	// implementations to honor them. Extensions can be used to | ||||
| 	// pass data from the authentication callbacks to the server | ||||
| 	// application layer. | ||||
| 	Extensions map[string]string | ||||
| } | ||||
|  | ||||
| // ServerConfig holds server specific configuration data. | ||||
| type ServerConfig struct { | ||||
| 	// Config contains configuration shared between client and server. | ||||
| 	Config | ||||
|  | ||||
| 	hostKeys []Signer | ||||
|  | ||||
| 	// NoClientAuth is true if clients are allowed to connect without | ||||
| 	// authenticating. | ||||
| 	NoClientAuth bool | ||||
|  | ||||
| 	// MaxAuthTries specifies the maximum number of authentication attempts | ||||
| 	// permitted per connection. If set to a negative number, the number of | ||||
| 	// attempts are unlimited. If set to zero, the number of attempts are limited | ||||
| 	// to 6. | ||||
| 	MaxAuthTries int | ||||
|  | ||||
| 	// PasswordCallback, if non-nil, is called when a user | ||||
| 	// attempts to authenticate using a password. | ||||
| 	PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error) | ||||
|  | ||||
| 	// PublicKeyCallback, if non-nil, is called when a client | ||||
| 	// offers a public key for authentication. It must return a nil error | ||||
| 	// if the given public key can be used to authenticate the | ||||
| 	// given user. For example, see CertChecker.Authenticate. A | ||||
| 	// call to this function does not guarantee that the key | ||||
| 	// offered is in fact used to authenticate. To record any data | ||||
| 	// depending on the public key, store it inside a | ||||
| 	// Permissions.Extensions entry. | ||||
| 	PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) | ||||
|  | ||||
| 	// KeyboardInteractiveCallback, if non-nil, is called when | ||||
| 	// keyboard-interactive authentication is selected (RFC | ||||
| 	// 4256). The client object's Challenge function should be | ||||
| 	// used to query the user. The callback may offer multiple | ||||
| 	// Challenge rounds. To avoid information leaks, the client | ||||
| 	// should be presented a challenge even if the user is | ||||
| 	// unknown. | ||||
| 	KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error) | ||||
|  | ||||
| 	// AuthLogCallback, if non-nil, is called to log all authentication | ||||
| 	// attempts. | ||||
| 	AuthLogCallback func(conn ConnMetadata, method string, err error) | ||||
|  | ||||
| 	// ServerVersion is the version identification string to announce in | ||||
| 	// the public handshake. | ||||
| 	// If empty, a reasonable default is used. | ||||
| 	// Note that RFC 4253 section 4.2 requires that this string start with | ||||
| 	// "SSH-2.0-". | ||||
| 	ServerVersion string | ||||
|  | ||||
| 	// BannerCallback, if present, is called and the return string is sent to | ||||
| 	// the client after key exchange completed but before authentication. | ||||
| 	BannerCallback func(conn ConnMetadata) string | ||||
| } | ||||
|  | ||||
| // AddHostKey adds a private key as a host key. If an existing host | ||||
| // key exists with the same algorithm, it is overwritten. Each server | ||||
| // config must have at least one host key. | ||||
| func (s *ServerConfig) AddHostKey(key Signer) { | ||||
| 	for i, k := range s.hostKeys { | ||||
| 		if k.PublicKey().Type() == key.PublicKey().Type() { | ||||
| 			s.hostKeys[i] = key | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	s.hostKeys = append(s.hostKeys, key) | ||||
| } | ||||
|  | ||||
| // cachedPubKey contains the results of querying whether a public key is | ||||
| // acceptable for a user. | ||||
| type cachedPubKey struct { | ||||
| 	user       string | ||||
| 	pubKeyData []byte | ||||
| 	result     error | ||||
| 	perms      *Permissions | ||||
| } | ||||
|  | ||||
| const maxCachedPubKeys = 16 | ||||
|  | ||||
| // pubKeyCache caches tests for public keys.  Since SSH clients | ||||
| // will query whether a public key is acceptable before attempting to | ||||
| // authenticate with it, we end up with duplicate queries for public | ||||
| // key validity.  The cache only applies to a single ServerConn. | ||||
| type pubKeyCache struct { | ||||
| 	keys []cachedPubKey | ||||
| } | ||||
|  | ||||
| // get returns the result for a given user/algo/key tuple. | ||||
| func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) { | ||||
| 	for _, k := range c.keys { | ||||
| 		if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) { | ||||
| 			return k, true | ||||
| 		} | ||||
| 	} | ||||
| 	return cachedPubKey{}, false | ||||
| } | ||||
|  | ||||
| // add adds the given tuple to the cache. | ||||
| func (c *pubKeyCache) add(candidate cachedPubKey) { | ||||
| 	if len(c.keys) < maxCachedPubKeys { | ||||
| 		c.keys = append(c.keys, candidate) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ServerConn is an authenticated SSH connection, as seen from the | ||||
| // server | ||||
| type ServerConn struct { | ||||
| 	Conn | ||||
|  | ||||
| 	// If the succeeding authentication callback returned a | ||||
| 	// non-nil Permissions pointer, it is stored here. | ||||
| 	Permissions *Permissions | ||||
| } | ||||
|  | ||||
| // NewServerConn starts a new SSH server with c as the underlying | ||||
| // transport.  It starts with a handshake and, if the handshake is | ||||
| // unsuccessful, it closes the connection and returns an error.  The | ||||
| // Request and NewChannel channels must be serviced, or the connection | ||||
| // will hang. | ||||
| // | ||||
| // The returned error may be of type *ServerAuthError for | ||||
| // authentication errors. | ||||
| func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) { | ||||
| 	fullConf := *config | ||||
| 	fullConf.SetDefaults() | ||||
| 	if fullConf.MaxAuthTries == 0 { | ||||
| 		fullConf.MaxAuthTries = 6 | ||||
| 	} | ||||
|  | ||||
| 	s := &connection{ | ||||
| 		sshConn: sshConn{conn: c}, | ||||
| 	} | ||||
| 	perms, err := s.serverHandshake(&fullConf) | ||||
| 	if err != nil { | ||||
| 		c.Close() | ||||
| 		return nil, nil, nil, err | ||||
| 	} | ||||
| 	return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil | ||||
| } | ||||
|  | ||||
| // signAndMarshal signs the data with the appropriate algorithm, | ||||
| // and serializes the result in SSH wire format. | ||||
| func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) { | ||||
| 	sig, err := k.Sign(rand, data) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return Marshal(sig), nil | ||||
| } | ||||
|  | ||||
| // handshake performs key exchange and user authentication. | ||||
| func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) { | ||||
| 	if len(config.hostKeys) == 0 { | ||||
| 		return nil, errors.New("ssh: server has no host keys") | ||||
| 	} | ||||
|  | ||||
| 	if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && config.KeyboardInteractiveCallback == nil { | ||||
| 		return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") | ||||
| 	} | ||||
|  | ||||
| 	if config.ServerVersion != "" { | ||||
| 		s.serverVersion = []byte(config.ServerVersion) | ||||
| 	} else { | ||||
| 		s.serverVersion = []byte(packageVersion) | ||||
| 	} | ||||
| 	var err error | ||||
| 	s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */) | ||||
| 	s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config) | ||||
|  | ||||
| 	if err := s.transport.waitSession(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// We just did the key change, so the session ID is established. | ||||
| 	s.sessionID = s.transport.getSessionID() | ||||
|  | ||||
| 	var packet []byte | ||||
| 	if packet, err = s.transport.readPacket(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var serviceRequest serviceRequestMsg | ||||
| 	if err = Unmarshal(packet, &serviceRequest); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if serviceRequest.Service != serviceUserAuth { | ||||
| 		return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating") | ||||
| 	} | ||||
| 	serviceAccept := serviceAcceptMsg{ | ||||
| 		Service: serviceUserAuth, | ||||
| 	} | ||||
| 	if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	perms, err := s.serverAuthenticate(config) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	s.mux = newMux(s.transport) | ||||
| 	return perms, err | ||||
| } | ||||
|  | ||||
| func isAcceptableAlgo(algo string) bool { | ||||
| 	switch algo { | ||||
| 	case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoED25519, | ||||
| 		CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01: | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func checkSourceAddress(addr net.Addr, sourceAddrs string) error { | ||||
| 	if addr == nil { | ||||
| 		return errors.New("ssh: no address known for client, but source-address match required") | ||||
| 	} | ||||
|  | ||||
| 	tcpAddr, ok := addr.(*net.TCPAddr) | ||||
| 	if !ok { | ||||
| 		return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr) | ||||
| 	} | ||||
|  | ||||
| 	for _, sourceAddr := range strings.Split(sourceAddrs, ",") { | ||||
| 		if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil { | ||||
| 			if allowedIP.Equal(tcpAddr.IP) { | ||||
| 				return nil | ||||
| 			} | ||||
| 		} else { | ||||
| 			_, ipNet, err := net.ParseCIDR(sourceAddr) | ||||
| 			if err != nil { | ||||
| 				return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err) | ||||
| 			} | ||||
|  | ||||
| 			if ipNet.Contains(tcpAddr.IP) { | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr) | ||||
| } | ||||
|  | ||||
| // ServerAuthError represents server authentication errors and is | ||||
| // sometimes returned by NewServerConn. It appends any authentication | ||||
| // errors that may occur, and is returned if all of the authentication | ||||
| // methods provided by the user failed to authenticate. | ||||
| type ServerAuthError struct { | ||||
| 	// Errors contains authentication errors returned by the authentication | ||||
| 	// callback methods. The first entry is typically ErrNoAuth. | ||||
| 	Errors []error | ||||
| } | ||||
|  | ||||
| func (l ServerAuthError) Error() string { | ||||
| 	var errs []string | ||||
| 	for _, err := range l.Errors { | ||||
| 		errs = append(errs, err.Error()) | ||||
| 	} | ||||
| 	return "[" + strings.Join(errs, ", ") + "]" | ||||
| } | ||||
|  | ||||
| // ErrNoAuth is the error value returned if no | ||||
| // authentication method has been passed yet. This happens as a normal | ||||
| // part of the authentication loop, since the client first tries | ||||
| // 'none' authentication to discover available methods. | ||||
| // It is returned in ServerAuthError.Errors from NewServerConn. | ||||
| var ErrNoAuth = errors.New("ssh: no auth passed yet") | ||||
|  | ||||
| func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) { | ||||
| 	sessionID := s.transport.getSessionID() | ||||
| 	var cache pubKeyCache | ||||
| 	var perms *Permissions | ||||
|  | ||||
| 	authFailures := 0 | ||||
| 	var authErrs []error | ||||
| 	var displayedBanner bool | ||||
|  | ||||
| userAuthLoop: | ||||
| 	for { | ||||
| 		if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 { | ||||
| 			discMsg := &disconnectMsg{ | ||||
| 				Reason:  2, | ||||
| 				Message: "too many authentication failures", | ||||
| 			} | ||||
|  | ||||
| 			if err := s.transport.writePacket(Marshal(discMsg)); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			return nil, discMsg | ||||
| 		} | ||||
|  | ||||
| 		var userAuthReq userAuthRequestMsg | ||||
| 		if packet, err := s.transport.readPacket(); err != nil { | ||||
| 			if err == io.EOF { | ||||
| 				return nil, &ServerAuthError{Errors: authErrs} | ||||
| 			} | ||||
| 			return nil, err | ||||
| 		} else if err = Unmarshal(packet, &userAuthReq); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		if userAuthReq.Service != serviceSSH { | ||||
| 			return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service) | ||||
| 		} | ||||
|  | ||||
| 		s.user = userAuthReq.User | ||||
|  | ||||
| 		if !displayedBanner && config.BannerCallback != nil { | ||||
| 			displayedBanner = true | ||||
| 			msg := config.BannerCallback(s) | ||||
| 			if msg != "" { | ||||
| 				bannerMsg := &userAuthBannerMsg{ | ||||
| 					Message: msg, | ||||
| 				} | ||||
| 				if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		perms = nil | ||||
| 		authErr := ErrNoAuth | ||||
|  | ||||
| 		switch userAuthReq.Method { | ||||
| 		case "none": | ||||
| 			if config.NoClientAuth { | ||||
| 				authErr = nil | ||||
| 			} | ||||
|  | ||||
| 			// allow initial attempt of 'none' without penalty | ||||
| 			if authFailures == 0 { | ||||
| 				authFailures-- | ||||
| 			} | ||||
| 		case "password": | ||||
| 			if config.PasswordCallback == nil { | ||||
| 				authErr = errors.New("ssh: password auth not configured") | ||||
| 				break | ||||
| 			} | ||||
| 			payload := userAuthReq.Payload | ||||
| 			if len(payload) < 1 || payload[0] != 0 { | ||||
| 				return nil, parseError(msgUserAuthRequest) | ||||
| 			} | ||||
| 			payload = payload[1:] | ||||
| 			password, payload, ok := parseString(payload) | ||||
| 			if !ok || len(payload) > 0 { | ||||
| 				return nil, parseError(msgUserAuthRequest) | ||||
| 			} | ||||
|  | ||||
| 			perms, authErr = config.PasswordCallback(s, password) | ||||
| 		case "keyboard-interactive": | ||||
| 			if config.KeyboardInteractiveCallback == nil { | ||||
| 				authErr = errors.New("ssh: keyboard-interactive auth not configured") | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 			prompter := &sshClientKeyboardInteractive{s} | ||||
| 			perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge) | ||||
| 		case "publickey": | ||||
| 			if config.PublicKeyCallback == nil { | ||||
| 				authErr = errors.New("ssh: publickey auth not configured") | ||||
| 				break | ||||
| 			} | ||||
| 			payload := userAuthReq.Payload | ||||
| 			if len(payload) < 1 { | ||||
| 				return nil, parseError(msgUserAuthRequest) | ||||
| 			} | ||||
| 			isQuery := payload[0] == 0 | ||||
| 			payload = payload[1:] | ||||
| 			algoBytes, payload, ok := parseString(payload) | ||||
| 			if !ok { | ||||
| 				return nil, parseError(msgUserAuthRequest) | ||||
| 			} | ||||
| 			algo := string(algoBytes) | ||||
| 			if !isAcceptableAlgo(algo) { | ||||
| 				authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo) | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 			pubKeyData, payload, ok := parseString(payload) | ||||
| 			if !ok { | ||||
| 				return nil, parseError(msgUserAuthRequest) | ||||
| 			} | ||||
|  | ||||
| 			pubKey, err := ParsePublicKey(pubKeyData) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			candidate, ok := cache.get(s.user, pubKeyData) | ||||
| 			if !ok { | ||||
| 				candidate.user = s.user | ||||
| 				candidate.pubKeyData = pubKeyData | ||||
| 				candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey) | ||||
| 				if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" { | ||||
| 					candidate.result = checkSourceAddress( | ||||
| 						s.RemoteAddr(), | ||||
| 						candidate.perms.CriticalOptions[sourceAddressCriticalOption]) | ||||
| 				} | ||||
| 				cache.add(candidate) | ||||
| 			} | ||||
|  | ||||
| 			if isQuery { | ||||
| 				// The client can query if the given public key | ||||
| 				// would be okay. | ||||
|  | ||||
| 				if len(payload) > 0 { | ||||
| 					return nil, parseError(msgUserAuthRequest) | ||||
| 				} | ||||
|  | ||||
| 				if candidate.result == nil { | ||||
| 					okMsg := userAuthPubKeyOkMsg{ | ||||
| 						Algo:   algo, | ||||
| 						PubKey: pubKeyData, | ||||
| 					} | ||||
| 					if err = s.transport.writePacket(Marshal(&okMsg)); err != nil { | ||||
| 						return nil, err | ||||
| 					} | ||||
| 					continue userAuthLoop | ||||
| 				} | ||||
| 				authErr = candidate.result | ||||
| 			} else { | ||||
| 				sig, payload, ok := parseSignature(payload) | ||||
| 				if !ok || len(payload) > 0 { | ||||
| 					return nil, parseError(msgUserAuthRequest) | ||||
| 				} | ||||
| 				// Ensure the public key algo and signature algo | ||||
| 				// are supported.  Compare the private key | ||||
| 				// algorithm name that corresponds to algo with | ||||
| 				// sig.Format.  This is usually the same, but | ||||
| 				// for certs, the names differ. | ||||
| 				if !isAcceptableAlgo(sig.Format) { | ||||
| 					authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format) | ||||
| 					break | ||||
| 				} | ||||
| 				signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) | ||||
|  | ||||
| 				if err := pubKey.Verify(signedData, sig); err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
|  | ||||
| 				authErr = candidate.result | ||||
| 				perms = candidate.perms | ||||
| 			} | ||||
| 		default: | ||||
| 			authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method) | ||||
| 		} | ||||
|  | ||||
| 		authErrs = append(authErrs, authErr) | ||||
|  | ||||
| 		if config.AuthLogCallback != nil { | ||||
| 			config.AuthLogCallback(s, userAuthReq.Method, authErr) | ||||
| 		} | ||||
|  | ||||
| 		if authErr == nil { | ||||
| 			break userAuthLoop | ||||
| 		} | ||||
|  | ||||
| 		authFailures++ | ||||
|  | ||||
| 		var failureMsg userAuthFailureMsg | ||||
| 		if config.PasswordCallback != nil { | ||||
| 			failureMsg.Methods = append(failureMsg.Methods, "password") | ||||
| 		} | ||||
| 		if config.PublicKeyCallback != nil { | ||||
| 			failureMsg.Methods = append(failureMsg.Methods, "publickey") | ||||
| 		} | ||||
| 		if config.KeyboardInteractiveCallback != nil { | ||||
| 			failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive") | ||||
| 		} | ||||
|  | ||||
| 		if len(failureMsg.Methods) == 0 { | ||||
| 			return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") | ||||
| 		} | ||||
|  | ||||
| 		if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return perms, nil | ||||
| } | ||||
|  | ||||
| // sshClientKeyboardInteractive implements a ClientKeyboardInteractive by | ||||
| // asking the client on the other side of a ServerConn. | ||||
| type sshClientKeyboardInteractive struct { | ||||
| 	*connection | ||||
| } | ||||
|  | ||||
| func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) { | ||||
| 	if len(questions) != len(echos) { | ||||
| 		return nil, errors.New("ssh: echos and questions must have equal length") | ||||
| 	} | ||||
|  | ||||
| 	var prompts []byte | ||||
| 	for i := range questions { | ||||
| 		prompts = appendString(prompts, questions[i]) | ||||
| 		prompts = appendBool(prompts, echos[i]) | ||||
| 	} | ||||
|  | ||||
| 	if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{ | ||||
| 		Instruction: instruction, | ||||
| 		NumPrompts:  uint32(len(questions)), | ||||
| 		Prompts:     prompts, | ||||
| 	})); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	packet, err := c.transport.readPacket() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if packet[0] != msgUserAuthInfoResponse { | ||||
| 		return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0]) | ||||
| 	} | ||||
| 	packet = packet[1:] | ||||
|  | ||||
| 	n, packet, ok := parseUint32(packet) | ||||
| 	if !ok || int(n) != len(questions) { | ||||
| 		return nil, parseError(msgUserAuthInfoResponse) | ||||
| 	} | ||||
|  | ||||
| 	for i := uint32(0); i < n; i++ { | ||||
| 		ans, rest, ok := parseString(packet) | ||||
| 		if !ok { | ||||
| 			return nil, parseError(msgUserAuthInfoResponse) | ||||
| 		} | ||||
|  | ||||
| 		answers = append(answers, string(ans)) | ||||
| 		packet = rest | ||||
| 	} | ||||
| 	if len(packet) != 0 { | ||||
| 		return nil, errors.New("ssh: junk at end of message") | ||||
| 	} | ||||
|  | ||||
| 	return answers, nil | ||||
| } | ||||
							
								
								
									
										647
									
								
								vendor/golang.org/x/crypto/ssh/session.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										647
									
								
								vendor/golang.org/x/crypto/ssh/session.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,647 @@ | ||||
| // Copyright 2011 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 ssh | ||||
|  | ||||
| // Session implements an interactive session described in | ||||
| // "RFC 4254, section 6". | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/binary" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"sync" | ||||
| ) | ||||
|  | ||||
| type Signal string | ||||
|  | ||||
| // POSIX signals as listed in RFC 4254 Section 6.10. | ||||
| const ( | ||||
| 	SIGABRT Signal = "ABRT" | ||||
| 	SIGALRM Signal = "ALRM" | ||||
| 	SIGFPE  Signal = "FPE" | ||||
| 	SIGHUP  Signal = "HUP" | ||||
| 	SIGILL  Signal = "ILL" | ||||
| 	SIGINT  Signal = "INT" | ||||
| 	SIGKILL Signal = "KILL" | ||||
| 	SIGPIPE Signal = "PIPE" | ||||
| 	SIGQUIT Signal = "QUIT" | ||||
| 	SIGSEGV Signal = "SEGV" | ||||
| 	SIGTERM Signal = "TERM" | ||||
| 	SIGUSR1 Signal = "USR1" | ||||
| 	SIGUSR2 Signal = "USR2" | ||||
| ) | ||||
|  | ||||
| var signals = map[Signal]int{ | ||||
| 	SIGABRT: 6, | ||||
| 	SIGALRM: 14, | ||||
| 	SIGFPE:  8, | ||||
| 	SIGHUP:  1, | ||||
| 	SIGILL:  4, | ||||
| 	SIGINT:  2, | ||||
| 	SIGKILL: 9, | ||||
| 	SIGPIPE: 13, | ||||
| 	SIGQUIT: 3, | ||||
| 	SIGSEGV: 11, | ||||
| 	SIGTERM: 15, | ||||
| } | ||||
|  | ||||
| type TerminalModes map[uint8]uint32 | ||||
|  | ||||
| // POSIX terminal mode flags as listed in RFC 4254 Section 8. | ||||
| const ( | ||||
| 	tty_OP_END    = 0 | ||||
| 	VINTR         = 1 | ||||
| 	VQUIT         = 2 | ||||
| 	VERASE        = 3 | ||||
| 	VKILL         = 4 | ||||
| 	VEOF          = 5 | ||||
| 	VEOL          = 6 | ||||
| 	VEOL2         = 7 | ||||
| 	VSTART        = 8 | ||||
| 	VSTOP         = 9 | ||||
| 	VSUSP         = 10 | ||||
| 	VDSUSP        = 11 | ||||
| 	VREPRINT      = 12 | ||||
| 	VWERASE       = 13 | ||||
| 	VLNEXT        = 14 | ||||
| 	VFLUSH        = 15 | ||||
| 	VSWTCH        = 16 | ||||
| 	VSTATUS       = 17 | ||||
| 	VDISCARD      = 18 | ||||
| 	IGNPAR        = 30 | ||||
| 	PARMRK        = 31 | ||||
| 	INPCK         = 32 | ||||
| 	ISTRIP        = 33 | ||||
| 	INLCR         = 34 | ||||
| 	IGNCR         = 35 | ||||
| 	ICRNL         = 36 | ||||
| 	IUCLC         = 37 | ||||
| 	IXON          = 38 | ||||
| 	IXANY         = 39 | ||||
| 	IXOFF         = 40 | ||||
| 	IMAXBEL       = 41 | ||||
| 	ISIG          = 50 | ||||
| 	ICANON        = 51 | ||||
| 	XCASE         = 52 | ||||
| 	ECHO          = 53 | ||||
| 	ECHOE         = 54 | ||||
| 	ECHOK         = 55 | ||||
| 	ECHONL        = 56 | ||||
| 	NOFLSH        = 57 | ||||
| 	TOSTOP        = 58 | ||||
| 	IEXTEN        = 59 | ||||
| 	ECHOCTL       = 60 | ||||
| 	ECHOKE        = 61 | ||||
| 	PENDIN        = 62 | ||||
| 	OPOST         = 70 | ||||
| 	OLCUC         = 71 | ||||
| 	ONLCR         = 72 | ||||
| 	OCRNL         = 73 | ||||
| 	ONOCR         = 74 | ||||
| 	ONLRET        = 75 | ||||
| 	CS7           = 90 | ||||
| 	CS8           = 91 | ||||
| 	PARENB        = 92 | ||||
| 	PARODD        = 93 | ||||
| 	TTY_OP_ISPEED = 128 | ||||
| 	TTY_OP_OSPEED = 129 | ||||
| ) | ||||
|  | ||||
| // A Session represents a connection to a remote command or shell. | ||||
| type Session struct { | ||||
| 	// Stdin specifies the remote process's standard input. | ||||
| 	// If Stdin is nil, the remote process reads from an empty | ||||
| 	// bytes.Buffer. | ||||
| 	Stdin io.Reader | ||||
|  | ||||
| 	// Stdout and Stderr specify the remote process's standard | ||||
| 	// output and error. | ||||
| 	// | ||||
| 	// If either is nil, Run connects the corresponding file | ||||
| 	// descriptor to an instance of ioutil.Discard. There is a | ||||
| 	// fixed amount of buffering that is shared for the two streams. | ||||
| 	// If either blocks it may eventually cause the remote | ||||
| 	// command to block. | ||||
| 	Stdout io.Writer | ||||
| 	Stderr io.Writer | ||||
|  | ||||
| 	ch        Channel // the channel backing this session | ||||
| 	started   bool    // true once Start, Run or Shell is invoked. | ||||
| 	copyFuncs []func() error | ||||
| 	errors    chan error // one send per copyFunc | ||||
|  | ||||
| 	// true if pipe method is active | ||||
| 	stdinpipe, stdoutpipe, stderrpipe bool | ||||
|  | ||||
| 	// stdinPipeWriter is non-nil if StdinPipe has not been called | ||||
| 	// and Stdin was specified by the user; it is the write end of | ||||
| 	// a pipe connecting Session.Stdin to the stdin channel. | ||||
| 	stdinPipeWriter io.WriteCloser | ||||
|  | ||||
| 	exitStatus chan error | ||||
| } | ||||
|  | ||||
| // SendRequest sends an out-of-band channel request on the SSH channel | ||||
| // underlying the session. | ||||
| func (s *Session) SendRequest(name string, wantReply bool, payload []byte) (bool, error) { | ||||
| 	return s.ch.SendRequest(name, wantReply, payload) | ||||
| } | ||||
|  | ||||
| func (s *Session) Close() error { | ||||
| 	return s.ch.Close() | ||||
| } | ||||
|  | ||||
| // RFC 4254 Section 6.4. | ||||
| type setenvRequest struct { | ||||
| 	Name  string | ||||
| 	Value string | ||||
| } | ||||
|  | ||||
| // Setenv sets an environment variable that will be applied to any | ||||
| // command executed by Shell or Run. | ||||
| func (s *Session) Setenv(name, value string) error { | ||||
| 	msg := setenvRequest{ | ||||
| 		Name:  name, | ||||
| 		Value: value, | ||||
| 	} | ||||
| 	ok, err := s.ch.SendRequest("env", true, Marshal(&msg)) | ||||
| 	if err == nil && !ok { | ||||
| 		err = errors.New("ssh: setenv failed") | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // RFC 4254 Section 6.2. | ||||
| type ptyRequestMsg struct { | ||||
| 	Term     string | ||||
| 	Columns  uint32 | ||||
| 	Rows     uint32 | ||||
| 	Width    uint32 | ||||
| 	Height   uint32 | ||||
| 	Modelist string | ||||
| } | ||||
|  | ||||
| // RequestPty requests the association of a pty with the session on the remote host. | ||||
| func (s *Session) RequestPty(term string, h, w int, termmodes TerminalModes) error { | ||||
| 	var tm []byte | ||||
| 	for k, v := range termmodes { | ||||
| 		kv := struct { | ||||
| 			Key byte | ||||
| 			Val uint32 | ||||
| 		}{k, v} | ||||
|  | ||||
| 		tm = append(tm, Marshal(&kv)...) | ||||
| 	} | ||||
| 	tm = append(tm, tty_OP_END) | ||||
| 	req := ptyRequestMsg{ | ||||
| 		Term:     term, | ||||
| 		Columns:  uint32(w), | ||||
| 		Rows:     uint32(h), | ||||
| 		Width:    uint32(w * 8), | ||||
| 		Height:   uint32(h * 8), | ||||
| 		Modelist: string(tm), | ||||
| 	} | ||||
| 	ok, err := s.ch.SendRequest("pty-req", true, Marshal(&req)) | ||||
| 	if err == nil && !ok { | ||||
| 		err = errors.New("ssh: pty-req failed") | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // RFC 4254 Section 6.5. | ||||
| type subsystemRequestMsg struct { | ||||
| 	Subsystem string | ||||
| } | ||||
|  | ||||
| // RequestSubsystem requests the association of a subsystem with the session on the remote host. | ||||
| // A subsystem is a predefined command that runs in the background when the ssh session is initiated | ||||
| func (s *Session) RequestSubsystem(subsystem string) error { | ||||
| 	msg := subsystemRequestMsg{ | ||||
| 		Subsystem: subsystem, | ||||
| 	} | ||||
| 	ok, err := s.ch.SendRequest("subsystem", true, Marshal(&msg)) | ||||
| 	if err == nil && !ok { | ||||
| 		err = errors.New("ssh: subsystem request failed") | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // RFC 4254 Section 6.7. | ||||
| type ptyWindowChangeMsg struct { | ||||
| 	Columns uint32 | ||||
| 	Rows    uint32 | ||||
| 	Width   uint32 | ||||
| 	Height  uint32 | ||||
| } | ||||
|  | ||||
| // WindowChange informs the remote host about a terminal window dimension change to h rows and w columns. | ||||
| func (s *Session) WindowChange(h, w int) error { | ||||
| 	req := ptyWindowChangeMsg{ | ||||
| 		Columns: uint32(w), | ||||
| 		Rows:    uint32(h), | ||||
| 		Width:   uint32(w * 8), | ||||
| 		Height:  uint32(h * 8), | ||||
| 	} | ||||
| 	_, err := s.ch.SendRequest("window-change", false, Marshal(&req)) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // RFC 4254 Section 6.9. | ||||
| type signalMsg struct { | ||||
| 	Signal string | ||||
| } | ||||
|  | ||||
| // Signal sends the given signal to the remote process. | ||||
| // sig is one of the SIG* constants. | ||||
| func (s *Session) Signal(sig Signal) error { | ||||
| 	msg := signalMsg{ | ||||
| 		Signal: string(sig), | ||||
| 	} | ||||
|  | ||||
| 	_, err := s.ch.SendRequest("signal", false, Marshal(&msg)) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // RFC 4254 Section 6.5. | ||||
| type execMsg struct { | ||||
| 	Command string | ||||
| } | ||||
|  | ||||
| // Start runs cmd on the remote host. Typically, the remote | ||||
| // server passes cmd to the shell for interpretation. | ||||
| // A Session only accepts one call to Run, Start or Shell. | ||||
| func (s *Session) Start(cmd string) error { | ||||
| 	if s.started { | ||||
| 		return errors.New("ssh: session already started") | ||||
| 	} | ||||
| 	req := execMsg{ | ||||
| 		Command: cmd, | ||||
| 	} | ||||
|  | ||||
| 	ok, err := s.ch.SendRequest("exec", true, Marshal(&req)) | ||||
| 	if err == nil && !ok { | ||||
| 		err = fmt.Errorf("ssh: command %v failed", cmd) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return s.start() | ||||
| } | ||||
|  | ||||
| // Run runs cmd on the remote host. Typically, the remote | ||||
| // server passes cmd to the shell for interpretation. | ||||
| // A Session only accepts one call to Run, Start, Shell, Output, | ||||
| // or CombinedOutput. | ||||
| // | ||||
| // The returned error is nil if the command runs, has no problems | ||||
| // copying stdin, stdout, and stderr, and exits with a zero exit | ||||
| // status. | ||||
| // | ||||
| // If the remote server does not send an exit status, an error of type | ||||
| // *ExitMissingError is returned. If the command completes | ||||
| // unsuccessfully or is interrupted by a signal, the error is of type | ||||
| // *ExitError. Other error types may be returned for I/O problems. | ||||
| func (s *Session) Run(cmd string) error { | ||||
| 	err := s.Start(cmd) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return s.Wait() | ||||
| } | ||||
|  | ||||
| // Output runs cmd on the remote host and returns its standard output. | ||||
| func (s *Session) Output(cmd string) ([]byte, error) { | ||||
| 	if s.Stdout != nil { | ||||
| 		return nil, errors.New("ssh: Stdout already set") | ||||
| 	} | ||||
| 	var b bytes.Buffer | ||||
| 	s.Stdout = &b | ||||
| 	err := s.Run(cmd) | ||||
| 	return b.Bytes(), err | ||||
| } | ||||
|  | ||||
| type singleWriter struct { | ||||
| 	b  bytes.Buffer | ||||
| 	mu sync.Mutex | ||||
| } | ||||
|  | ||||
| func (w *singleWriter) Write(p []byte) (int, error) { | ||||
| 	w.mu.Lock() | ||||
| 	defer w.mu.Unlock() | ||||
| 	return w.b.Write(p) | ||||
| } | ||||
|  | ||||
| // CombinedOutput runs cmd on the remote host and returns its combined | ||||
| // standard output and standard error. | ||||
| func (s *Session) CombinedOutput(cmd string) ([]byte, error) { | ||||
| 	if s.Stdout != nil { | ||||
| 		return nil, errors.New("ssh: Stdout already set") | ||||
| 	} | ||||
| 	if s.Stderr != nil { | ||||
| 		return nil, errors.New("ssh: Stderr already set") | ||||
| 	} | ||||
| 	var b singleWriter | ||||
| 	s.Stdout = &b | ||||
| 	s.Stderr = &b | ||||
| 	err := s.Run(cmd) | ||||
| 	return b.b.Bytes(), err | ||||
| } | ||||
|  | ||||
| // Shell starts a login shell on the remote host. A Session only | ||||
| // accepts one call to Run, Start, Shell, Output, or CombinedOutput. | ||||
| func (s *Session) Shell() error { | ||||
| 	if s.started { | ||||
| 		return errors.New("ssh: session already started") | ||||
| 	} | ||||
|  | ||||
| 	ok, err := s.ch.SendRequest("shell", true, nil) | ||||
| 	if err == nil && !ok { | ||||
| 		return errors.New("ssh: could not start shell") | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return s.start() | ||||
| } | ||||
|  | ||||
| func (s *Session) start() error { | ||||
| 	s.started = true | ||||
|  | ||||
| 	type F func(*Session) | ||||
| 	for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} { | ||||
| 		setupFd(s) | ||||
| 	} | ||||
|  | ||||
| 	s.errors = make(chan error, len(s.copyFuncs)) | ||||
| 	for _, fn := range s.copyFuncs { | ||||
| 		go func(fn func() error) { | ||||
| 			s.errors <- fn() | ||||
| 		}(fn) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Wait waits for the remote command to exit. | ||||
| // | ||||
| // The returned error is nil if the command runs, has no problems | ||||
| // copying stdin, stdout, and stderr, and exits with a zero exit | ||||
| // status. | ||||
| // | ||||
| // If the remote server does not send an exit status, an error of type | ||||
| // *ExitMissingError is returned. If the command completes | ||||
| // unsuccessfully or is interrupted by a signal, the error is of type | ||||
| // *ExitError. Other error types may be returned for I/O problems. | ||||
| func (s *Session) Wait() error { | ||||
| 	if !s.started { | ||||
| 		return errors.New("ssh: session not started") | ||||
| 	} | ||||
| 	waitErr := <-s.exitStatus | ||||
|  | ||||
| 	if s.stdinPipeWriter != nil { | ||||
| 		s.stdinPipeWriter.Close() | ||||
| 	} | ||||
| 	var copyError error | ||||
| 	for range s.copyFuncs { | ||||
| 		if err := <-s.errors; err != nil && copyError == nil { | ||||
| 			copyError = err | ||||
| 		} | ||||
| 	} | ||||
| 	if waitErr != nil { | ||||
| 		return waitErr | ||||
| 	} | ||||
| 	return copyError | ||||
| } | ||||
|  | ||||
| func (s *Session) wait(reqs <-chan *Request) error { | ||||
| 	wm := Waitmsg{status: -1} | ||||
| 	// Wait for msg channel to be closed before returning. | ||||
| 	for msg := range reqs { | ||||
| 		switch msg.Type { | ||||
| 		case "exit-status": | ||||
| 			wm.status = int(binary.BigEndian.Uint32(msg.Payload)) | ||||
| 		case "exit-signal": | ||||
| 			var sigval struct { | ||||
| 				Signal     string | ||||
| 				CoreDumped bool | ||||
| 				Error      string | ||||
| 				Lang       string | ||||
| 			} | ||||
| 			if err := Unmarshal(msg.Payload, &sigval); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			// Must sanitize strings? | ||||
| 			wm.signal = sigval.Signal | ||||
| 			wm.msg = sigval.Error | ||||
| 			wm.lang = sigval.Lang | ||||
| 		default: | ||||
| 			// This handles keepalives and matches | ||||
| 			// OpenSSH's behaviour. | ||||
| 			if msg.WantReply { | ||||
| 				msg.Reply(false, nil) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if wm.status == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if wm.status == -1 { | ||||
| 		// exit-status was never sent from server | ||||
| 		if wm.signal == "" { | ||||
| 			// signal was not sent either.  RFC 4254 | ||||
| 			// section 6.10 recommends against this | ||||
| 			// behavior, but it is allowed, so we let | ||||
| 			// clients handle it. | ||||
| 			return &ExitMissingError{} | ||||
| 		} | ||||
| 		wm.status = 128 | ||||
| 		if _, ok := signals[Signal(wm.signal)]; ok { | ||||
| 			wm.status += signals[Signal(wm.signal)] | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return &ExitError{wm} | ||||
| } | ||||
|  | ||||
| // ExitMissingError is returned if a session is torn down cleanly, but | ||||
| // the server sends no confirmation of the exit status. | ||||
| type ExitMissingError struct{} | ||||
|  | ||||
| func (e *ExitMissingError) Error() string { | ||||
| 	return "wait: remote command exited without exit status or exit signal" | ||||
| } | ||||
|  | ||||
| func (s *Session) stdin() { | ||||
| 	if s.stdinpipe { | ||||
| 		return | ||||
| 	} | ||||
| 	var stdin io.Reader | ||||
| 	if s.Stdin == nil { | ||||
| 		stdin = new(bytes.Buffer) | ||||
| 	} else { | ||||
| 		r, w := io.Pipe() | ||||
| 		go func() { | ||||
| 			_, err := io.Copy(w, s.Stdin) | ||||
| 			w.CloseWithError(err) | ||||
| 		}() | ||||
| 		stdin, s.stdinPipeWriter = r, w | ||||
| 	} | ||||
| 	s.copyFuncs = append(s.copyFuncs, func() error { | ||||
| 		_, err := io.Copy(s.ch, stdin) | ||||
| 		if err1 := s.ch.CloseWrite(); err == nil && err1 != io.EOF { | ||||
| 			err = err1 | ||||
| 		} | ||||
| 		return err | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (s *Session) stdout() { | ||||
| 	if s.stdoutpipe { | ||||
| 		return | ||||
| 	} | ||||
| 	if s.Stdout == nil { | ||||
| 		s.Stdout = ioutil.Discard | ||||
| 	} | ||||
| 	s.copyFuncs = append(s.copyFuncs, func() error { | ||||
| 		_, err := io.Copy(s.Stdout, s.ch) | ||||
| 		return err | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (s *Session) stderr() { | ||||
| 	if s.stderrpipe { | ||||
| 		return | ||||
| 	} | ||||
| 	if s.Stderr == nil { | ||||
| 		s.Stderr = ioutil.Discard | ||||
| 	} | ||||
| 	s.copyFuncs = append(s.copyFuncs, func() error { | ||||
| 		_, err := io.Copy(s.Stderr, s.ch.Stderr()) | ||||
| 		return err | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // sessionStdin reroutes Close to CloseWrite. | ||||
| type sessionStdin struct { | ||||
| 	io.Writer | ||||
| 	ch Channel | ||||
| } | ||||
|  | ||||
| func (s *sessionStdin) Close() error { | ||||
| 	return s.ch.CloseWrite() | ||||
| } | ||||
|  | ||||
| // StdinPipe returns a pipe that will be connected to the | ||||
| // remote command's standard input when the command starts. | ||||
| func (s *Session) StdinPipe() (io.WriteCloser, error) { | ||||
| 	if s.Stdin != nil { | ||||
| 		return nil, errors.New("ssh: Stdin already set") | ||||
| 	} | ||||
| 	if s.started { | ||||
| 		return nil, errors.New("ssh: StdinPipe after process started") | ||||
| 	} | ||||
| 	s.stdinpipe = true | ||||
| 	return &sessionStdin{s.ch, s.ch}, nil | ||||
| } | ||||
|  | ||||
| // StdoutPipe returns a pipe that will be connected to the | ||||
| // remote command's standard output when the command starts. | ||||
| // There is a fixed amount of buffering that is shared between | ||||
| // stdout and stderr streams. If the StdoutPipe reader is | ||||
| // not serviced fast enough it may eventually cause the | ||||
| // remote command to block. | ||||
| func (s *Session) StdoutPipe() (io.Reader, error) { | ||||
| 	if s.Stdout != nil { | ||||
| 		return nil, errors.New("ssh: Stdout already set") | ||||
| 	} | ||||
| 	if s.started { | ||||
| 		return nil, errors.New("ssh: StdoutPipe after process started") | ||||
| 	} | ||||
| 	s.stdoutpipe = true | ||||
| 	return s.ch, nil | ||||
| } | ||||
|  | ||||
| // StderrPipe returns a pipe that will be connected to the | ||||
| // remote command's standard error when the command starts. | ||||
| // There is a fixed amount of buffering that is shared between | ||||
| // stdout and stderr streams. If the StderrPipe reader is | ||||
| // not serviced fast enough it may eventually cause the | ||||
| // remote command to block. | ||||
| func (s *Session) StderrPipe() (io.Reader, error) { | ||||
| 	if s.Stderr != nil { | ||||
| 		return nil, errors.New("ssh: Stderr already set") | ||||
| 	} | ||||
| 	if s.started { | ||||
| 		return nil, errors.New("ssh: StderrPipe after process started") | ||||
| 	} | ||||
| 	s.stderrpipe = true | ||||
| 	return s.ch.Stderr(), nil | ||||
| } | ||||
|  | ||||
| // newSession returns a new interactive session on the remote host. | ||||
| func newSession(ch Channel, reqs <-chan *Request) (*Session, error) { | ||||
| 	s := &Session{ | ||||
| 		ch: ch, | ||||
| 	} | ||||
| 	s.exitStatus = make(chan error, 1) | ||||
| 	go func() { | ||||
| 		s.exitStatus <- s.wait(reqs) | ||||
| 	}() | ||||
|  | ||||
| 	return s, nil | ||||
| } | ||||
|  | ||||
| // An ExitError reports unsuccessful completion of a remote command. | ||||
| type ExitError struct { | ||||
| 	Waitmsg | ||||
| } | ||||
|  | ||||
| func (e *ExitError) Error() string { | ||||
| 	return e.Waitmsg.String() | ||||
| } | ||||
|  | ||||
| // Waitmsg stores the information about an exited remote command | ||||
| // as reported by Wait. | ||||
| type Waitmsg struct { | ||||
| 	status int | ||||
| 	signal string | ||||
| 	msg    string | ||||
| 	lang   string | ||||
| } | ||||
|  | ||||
| // ExitStatus returns the exit status of the remote command. | ||||
| func (w Waitmsg) ExitStatus() int { | ||||
| 	return w.status | ||||
| } | ||||
|  | ||||
| // Signal returns the exit signal of the remote command if | ||||
| // it was terminated violently. | ||||
| func (w Waitmsg) Signal() string { | ||||
| 	return w.signal | ||||
| } | ||||
|  | ||||
| // Msg returns the exit message given by the remote command | ||||
| func (w Waitmsg) Msg() string { | ||||
| 	return w.msg | ||||
| } | ||||
|  | ||||
| // Lang returns the language tag. See RFC 3066 | ||||
| func (w Waitmsg) Lang() string { | ||||
| 	return w.lang | ||||
| } | ||||
|  | ||||
| func (w Waitmsg) String() string { | ||||
| 	str := fmt.Sprintf("Process exited with status %v", w.status) | ||||
| 	if w.signal != "" { | ||||
| 		str += fmt.Sprintf(" from signal %v", w.signal) | ||||
| 	} | ||||
| 	if w.msg != "" { | ||||
| 		str += fmt.Sprintf(". Reason was: %v", w.msg) | ||||
| 	} | ||||
| 	return str | ||||
| } | ||||
							
								
								
									
										116
									
								
								vendor/golang.org/x/crypto/ssh/streamlocal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								vendor/golang.org/x/crypto/ssh/streamlocal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | ||||
| package ssh | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"net" | ||||
| ) | ||||
|  | ||||
| // streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message | ||||
| // with "direct-streamlocal@openssh.com" string. | ||||
| // | ||||
| // See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding | ||||
| // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235 | ||||
| type streamLocalChannelOpenDirectMsg struct { | ||||
| 	socketPath string | ||||
| 	reserved0  string | ||||
| 	reserved1  uint32 | ||||
| } | ||||
|  | ||||
| // forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message | ||||
| // with "forwarded-streamlocal@openssh.com" string. | ||||
| type forwardedStreamLocalPayload struct { | ||||
| 	SocketPath string | ||||
| 	Reserved0  string | ||||
| } | ||||
|  | ||||
| // streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message | ||||
| // with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string. | ||||
| type streamLocalChannelForwardMsg struct { | ||||
| 	socketPath string | ||||
| } | ||||
|  | ||||
| // ListenUnix is similar to ListenTCP but uses a Unix domain socket. | ||||
| func (c *Client) ListenUnix(socketPath string) (net.Listener, error) { | ||||
| 	c.handleForwardsOnce.Do(c.handleForwards) | ||||
| 	m := streamLocalChannelForwardMsg{ | ||||
| 		socketPath, | ||||
| 	} | ||||
| 	// send message | ||||
| 	ok, _, err := c.SendRequest("streamlocal-forward@openssh.com", true, Marshal(&m)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer") | ||||
| 	} | ||||
| 	ch := c.forwards.add(&net.UnixAddr{Name: socketPath, Net: "unix"}) | ||||
|  | ||||
| 	return &unixListener{socketPath, c, ch}, nil | ||||
| } | ||||
|  | ||||
| func (c *Client) dialStreamLocal(socketPath string) (Channel, error) { | ||||
| 	msg := streamLocalChannelOpenDirectMsg{ | ||||
| 		socketPath: socketPath, | ||||
| 	} | ||||
| 	ch, in, err := c.OpenChannel("direct-streamlocal@openssh.com", Marshal(&msg)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	go DiscardRequests(in) | ||||
| 	return ch, err | ||||
| } | ||||
|  | ||||
| type unixListener struct { | ||||
| 	socketPath string | ||||
|  | ||||
| 	conn *Client | ||||
| 	in   <-chan forward | ||||
| } | ||||
|  | ||||
| // Accept waits for and returns the next connection to the listener. | ||||
| func (l *unixListener) Accept() (net.Conn, error) { | ||||
| 	s, ok := <-l.in | ||||
| 	if !ok { | ||||
| 		return nil, io.EOF | ||||
| 	} | ||||
| 	ch, incoming, err := s.newCh.Accept() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	go DiscardRequests(incoming) | ||||
|  | ||||
| 	return &chanConn{ | ||||
| 		Channel: ch, | ||||
| 		laddr: &net.UnixAddr{ | ||||
| 			Name: l.socketPath, | ||||
| 			Net:  "unix", | ||||
| 		}, | ||||
| 		raddr: &net.UnixAddr{ | ||||
| 			Name: "@", | ||||
| 			Net:  "unix", | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // Close closes the listener. | ||||
| func (l *unixListener) Close() error { | ||||
| 	// this also closes the listener. | ||||
| 	l.conn.forwards.remove(&net.UnixAddr{Name: l.socketPath, Net: "unix"}) | ||||
| 	m := streamLocalChannelForwardMsg{ | ||||
| 		l.socketPath, | ||||
| 	} | ||||
| 	ok, _, err := l.conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&m)) | ||||
| 	if err == nil && !ok { | ||||
| 		err = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed") | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // Addr returns the listener's network address. | ||||
| func (l *unixListener) Addr() net.Addr { | ||||
| 	return &net.UnixAddr{ | ||||
| 		Name: l.socketPath, | ||||
| 		Net:  "unix", | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										474
									
								
								vendor/golang.org/x/crypto/ssh/tcpip.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										474
									
								
								vendor/golang.org/x/crypto/ssh/tcpip.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,474 @@ | ||||
| // Copyright 2011 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math/rand" | ||||
| 	"net" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // Listen requests the remote peer open a listening socket on | ||||
| // addr. Incoming connections will be available by calling Accept on | ||||
| // the returned net.Listener. The listener must be serviced, or the | ||||
| // SSH connection may hang. | ||||
| // N must be "tcp", "tcp4", "tcp6", or "unix". | ||||
| func (c *Client) Listen(n, addr string) (net.Listener, error) { | ||||
| 	switch n { | ||||
| 	case "tcp", "tcp4", "tcp6": | ||||
| 		laddr, err := net.ResolveTCPAddr(n, addr) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return c.ListenTCP(laddr) | ||||
| 	case "unix": | ||||
| 		return c.ListenUnix(addr) | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("ssh: unsupported protocol: %s", n) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Automatic port allocation is broken with OpenSSH before 6.0. See | ||||
| // also https://bugzilla.mindrot.org/show_bug.cgi?id=2017.  In | ||||
| // particular, OpenSSH 5.9 sends a channelOpenMsg with port number 0, | ||||
| // rather than the actual port number. This means you can never open | ||||
| // two different listeners with auto allocated ports. We work around | ||||
| // this by trying explicit ports until we succeed. | ||||
|  | ||||
| const openSSHPrefix = "OpenSSH_" | ||||
|  | ||||
| var portRandomizer = rand.New(rand.NewSource(time.Now().UnixNano())) | ||||
|  | ||||
| // isBrokenOpenSSHVersion returns true if the given version string | ||||
| // specifies a version of OpenSSH that is known to have a bug in port | ||||
| // forwarding. | ||||
| func isBrokenOpenSSHVersion(versionStr string) bool { | ||||
| 	i := strings.Index(versionStr, openSSHPrefix) | ||||
| 	if i < 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	i += len(openSSHPrefix) | ||||
| 	j := i | ||||
| 	for ; j < len(versionStr); j++ { | ||||
| 		if versionStr[j] < '0' || versionStr[j] > '9' { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	version, _ := strconv.Atoi(versionStr[i:j]) | ||||
| 	return version < 6 | ||||
| } | ||||
|  | ||||
| // autoPortListenWorkaround simulates automatic port allocation by | ||||
| // trying random ports repeatedly. | ||||
| func (c *Client) autoPortListenWorkaround(laddr *net.TCPAddr) (net.Listener, error) { | ||||
| 	var sshListener net.Listener | ||||
| 	var err error | ||||
| 	const tries = 10 | ||||
| 	for i := 0; i < tries; i++ { | ||||
| 		addr := *laddr | ||||
| 		addr.Port = 1024 + portRandomizer.Intn(60000) | ||||
| 		sshListener, err = c.ListenTCP(&addr) | ||||
| 		if err == nil { | ||||
| 			laddr.Port = addr.Port | ||||
| 			return sshListener, err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("ssh: listen on random port failed after %d tries: %v", tries, err) | ||||
| } | ||||
|  | ||||
| // RFC 4254 7.1 | ||||
| type channelForwardMsg struct { | ||||
| 	addr  string | ||||
| 	rport uint32 | ||||
| } | ||||
|  | ||||
| // handleForwards starts goroutines handling forwarded connections. | ||||
| // It's called on first use by (*Client).ListenTCP to not launch | ||||
| // goroutines until needed. | ||||
| func (c *Client) handleForwards() { | ||||
| 	go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-tcpip")) | ||||
| 	go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-streamlocal@openssh.com")) | ||||
| } | ||||
|  | ||||
| // ListenTCP requests the remote peer open a listening socket | ||||
| // on laddr. Incoming connections will be available by calling | ||||
| // Accept on the returned net.Listener. | ||||
| func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) { | ||||
| 	c.handleForwardsOnce.Do(c.handleForwards) | ||||
| 	if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) { | ||||
| 		return c.autoPortListenWorkaround(laddr) | ||||
| 	} | ||||
|  | ||||
| 	m := channelForwardMsg{ | ||||
| 		laddr.IP.String(), | ||||
| 		uint32(laddr.Port), | ||||
| 	} | ||||
| 	// send message | ||||
| 	ok, resp, err := c.SendRequest("tcpip-forward", true, Marshal(&m)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("ssh: tcpip-forward request denied by peer") | ||||
| 	} | ||||
|  | ||||
| 	// If the original port was 0, then the remote side will | ||||
| 	// supply a real port number in the response. | ||||
| 	if laddr.Port == 0 { | ||||
| 		var p struct { | ||||
| 			Port uint32 | ||||
| 		} | ||||
| 		if err := Unmarshal(resp, &p); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		laddr.Port = int(p.Port) | ||||
| 	} | ||||
|  | ||||
| 	// Register this forward, using the port number we obtained. | ||||
| 	ch := c.forwards.add(laddr) | ||||
|  | ||||
| 	return &tcpListener{laddr, c, ch}, nil | ||||
| } | ||||
|  | ||||
| // forwardList stores a mapping between remote | ||||
| // forward requests and the tcpListeners. | ||||
| type forwardList struct { | ||||
| 	sync.Mutex | ||||
| 	entries []forwardEntry | ||||
| } | ||||
|  | ||||
| // forwardEntry represents an established mapping of a laddr on a | ||||
| // remote ssh server to a channel connected to a tcpListener. | ||||
| type forwardEntry struct { | ||||
| 	laddr net.Addr | ||||
| 	c     chan forward | ||||
| } | ||||
|  | ||||
| // forward represents an incoming forwarded tcpip connection. The | ||||
| // arguments to add/remove/lookup should be address as specified in | ||||
| // the original forward-request. | ||||
| type forward struct { | ||||
| 	newCh NewChannel // the ssh client channel underlying this forward | ||||
| 	raddr net.Addr   // the raddr of the incoming connection | ||||
| } | ||||
|  | ||||
| func (l *forwardList) add(addr net.Addr) chan forward { | ||||
| 	l.Lock() | ||||
| 	defer l.Unlock() | ||||
| 	f := forwardEntry{ | ||||
| 		laddr: addr, | ||||
| 		c:     make(chan forward, 1), | ||||
| 	} | ||||
| 	l.entries = append(l.entries, f) | ||||
| 	return f.c | ||||
| } | ||||
|  | ||||
| // See RFC 4254, section 7.2 | ||||
| type forwardedTCPPayload struct { | ||||
| 	Addr       string | ||||
| 	Port       uint32 | ||||
| 	OriginAddr string | ||||
| 	OriginPort uint32 | ||||
| } | ||||
|  | ||||
| // parseTCPAddr parses the originating address from the remote into a *net.TCPAddr. | ||||
| func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) { | ||||
| 	if port == 0 || port > 65535 { | ||||
| 		return nil, fmt.Errorf("ssh: port number out of range: %d", port) | ||||
| 	} | ||||
| 	ip := net.ParseIP(string(addr)) | ||||
| 	if ip == nil { | ||||
| 		return nil, fmt.Errorf("ssh: cannot parse IP address %q", addr) | ||||
| 	} | ||||
| 	return &net.TCPAddr{IP: ip, Port: int(port)}, nil | ||||
| } | ||||
|  | ||||
| func (l *forwardList) handleChannels(in <-chan NewChannel) { | ||||
| 	for ch := range in { | ||||
| 		var ( | ||||
| 			laddr net.Addr | ||||
| 			raddr net.Addr | ||||
| 			err   error | ||||
| 		) | ||||
| 		switch channelType := ch.ChannelType(); channelType { | ||||
| 		case "forwarded-tcpip": | ||||
| 			var payload forwardedTCPPayload | ||||
| 			if err = Unmarshal(ch.ExtraData(), &payload); err != nil { | ||||
| 				ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error()) | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			// RFC 4254 section 7.2 specifies that incoming | ||||
| 			// addresses should list the address, in string | ||||
| 			// format. It is implied that this should be an IP | ||||
| 			// address, as it would be impossible to connect to it | ||||
| 			// otherwise. | ||||
| 			laddr, err = parseTCPAddr(payload.Addr, payload.Port) | ||||
| 			if err != nil { | ||||
| 				ch.Reject(ConnectionFailed, err.Error()) | ||||
| 				continue | ||||
| 			} | ||||
| 			raddr, err = parseTCPAddr(payload.OriginAddr, payload.OriginPort) | ||||
| 			if err != nil { | ||||
| 				ch.Reject(ConnectionFailed, err.Error()) | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 		case "forwarded-streamlocal@openssh.com": | ||||
| 			var payload forwardedStreamLocalPayload | ||||
| 			if err = Unmarshal(ch.ExtraData(), &payload); err != nil { | ||||
| 				ch.Reject(ConnectionFailed, "could not parse forwarded-streamlocal@openssh.com payload: "+err.Error()) | ||||
| 				continue | ||||
| 			} | ||||
| 			laddr = &net.UnixAddr{ | ||||
| 				Name: payload.SocketPath, | ||||
| 				Net:  "unix", | ||||
| 			} | ||||
| 			raddr = &net.UnixAddr{ | ||||
| 				Name: "@", | ||||
| 				Net:  "unix", | ||||
| 			} | ||||
| 		default: | ||||
| 			panic(fmt.Errorf("ssh: unknown channel type %s", channelType)) | ||||
| 		} | ||||
| 		if ok := l.forward(laddr, raddr, ch); !ok { | ||||
| 			// Section 7.2, implementations MUST reject spurious incoming | ||||
| 			// connections. | ||||
| 			ch.Reject(Prohibited, "no forward for address") | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // remove removes the forward entry, and the channel feeding its | ||||
| // listener. | ||||
| func (l *forwardList) remove(addr net.Addr) { | ||||
| 	l.Lock() | ||||
| 	defer l.Unlock() | ||||
| 	for i, f := range l.entries { | ||||
| 		if addr.Network() == f.laddr.Network() && addr.String() == f.laddr.String() { | ||||
| 			l.entries = append(l.entries[:i], l.entries[i+1:]...) | ||||
| 			close(f.c) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // closeAll closes and clears all forwards. | ||||
| func (l *forwardList) closeAll() { | ||||
| 	l.Lock() | ||||
| 	defer l.Unlock() | ||||
| 	for _, f := range l.entries { | ||||
| 		close(f.c) | ||||
| 	} | ||||
| 	l.entries = nil | ||||
| } | ||||
|  | ||||
| func (l *forwardList) forward(laddr, raddr net.Addr, ch NewChannel) bool { | ||||
| 	l.Lock() | ||||
| 	defer l.Unlock() | ||||
| 	for _, f := range l.entries { | ||||
| 		if laddr.Network() == f.laddr.Network() && laddr.String() == f.laddr.String() { | ||||
| 			f.c <- forward{newCh: ch, raddr: raddr} | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| type tcpListener struct { | ||||
| 	laddr *net.TCPAddr | ||||
|  | ||||
| 	conn *Client | ||||
| 	in   <-chan forward | ||||
| } | ||||
|  | ||||
| // Accept waits for and returns the next connection to the listener. | ||||
| func (l *tcpListener) Accept() (net.Conn, error) { | ||||
| 	s, ok := <-l.in | ||||
| 	if !ok { | ||||
| 		return nil, io.EOF | ||||
| 	} | ||||
| 	ch, incoming, err := s.newCh.Accept() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	go DiscardRequests(incoming) | ||||
|  | ||||
| 	return &chanConn{ | ||||
| 		Channel: ch, | ||||
| 		laddr:   l.laddr, | ||||
| 		raddr:   s.raddr, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // Close closes the listener. | ||||
| func (l *tcpListener) Close() error { | ||||
| 	m := channelForwardMsg{ | ||||
| 		l.laddr.IP.String(), | ||||
| 		uint32(l.laddr.Port), | ||||
| 	} | ||||
|  | ||||
| 	// this also closes the listener. | ||||
| 	l.conn.forwards.remove(l.laddr) | ||||
| 	ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m)) | ||||
| 	if err == nil && !ok { | ||||
| 		err = errors.New("ssh: cancel-tcpip-forward failed") | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // Addr returns the listener's network address. | ||||
| func (l *tcpListener) Addr() net.Addr { | ||||
| 	return l.laddr | ||||
| } | ||||
|  | ||||
| // Dial initiates a connection to the addr from the remote host. | ||||
| // The resulting connection has a zero LocalAddr() and RemoteAddr(). | ||||
| func (c *Client) Dial(n, addr string) (net.Conn, error) { | ||||
| 	var ch Channel | ||||
| 	switch n { | ||||
| 	case "tcp", "tcp4", "tcp6": | ||||
| 		// Parse the address into host and numeric port. | ||||
| 		host, portString, err := net.SplitHostPort(addr) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		port, err := strconv.ParseUint(portString, 10, 16) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		ch, err = c.dial(net.IPv4zero.String(), 0, host, int(port)) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		// Use a zero address for local and remote address. | ||||
| 		zeroAddr := &net.TCPAddr{ | ||||
| 			IP:   net.IPv4zero, | ||||
| 			Port: 0, | ||||
| 		} | ||||
| 		return &chanConn{ | ||||
| 			Channel: ch, | ||||
| 			laddr:   zeroAddr, | ||||
| 			raddr:   zeroAddr, | ||||
| 		}, nil | ||||
| 	case "unix": | ||||
| 		var err error | ||||
| 		ch, err = c.dialStreamLocal(addr) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return &chanConn{ | ||||
| 			Channel: ch, | ||||
| 			laddr: &net.UnixAddr{ | ||||
| 				Name: "@", | ||||
| 				Net:  "unix", | ||||
| 			}, | ||||
| 			raddr: &net.UnixAddr{ | ||||
| 				Name: addr, | ||||
| 				Net:  "unix", | ||||
| 			}, | ||||
| 		}, nil | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("ssh: unsupported protocol: %s", n) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DialTCP connects to the remote address raddr on the network net, | ||||
| // which must be "tcp", "tcp4", or "tcp6".  If laddr is not nil, it is used | ||||
| // as the local address for the connection. | ||||
| func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) { | ||||
| 	if laddr == nil { | ||||
| 		laddr = &net.TCPAddr{ | ||||
| 			IP:   net.IPv4zero, | ||||
| 			Port: 0, | ||||
| 		} | ||||
| 	} | ||||
| 	ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &chanConn{ | ||||
| 		Channel: ch, | ||||
| 		laddr:   laddr, | ||||
| 		raddr:   raddr, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // RFC 4254 7.2 | ||||
| type channelOpenDirectMsg struct { | ||||
| 	raddr string | ||||
| 	rport uint32 | ||||
| 	laddr string | ||||
| 	lport uint32 | ||||
| } | ||||
|  | ||||
| func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel, error) { | ||||
| 	msg := channelOpenDirectMsg{ | ||||
| 		raddr: raddr, | ||||
| 		rport: uint32(rport), | ||||
| 		laddr: laddr, | ||||
| 		lport: uint32(lport), | ||||
| 	} | ||||
| 	ch, in, err := c.OpenChannel("direct-tcpip", Marshal(&msg)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	go DiscardRequests(in) | ||||
| 	return ch, err | ||||
| } | ||||
|  | ||||
| type tcpChan struct { | ||||
| 	Channel // the backing channel | ||||
| } | ||||
|  | ||||
| // chanConn fulfills the net.Conn interface without | ||||
| // the tcpChan having to hold laddr or raddr directly. | ||||
| type chanConn struct { | ||||
| 	Channel | ||||
| 	laddr, raddr net.Addr | ||||
| } | ||||
|  | ||||
| // LocalAddr returns the local network address. | ||||
| func (t *chanConn) LocalAddr() net.Addr { | ||||
| 	return t.laddr | ||||
| } | ||||
|  | ||||
| // RemoteAddr returns the remote network address. | ||||
| func (t *chanConn) RemoteAddr() net.Addr { | ||||
| 	return t.raddr | ||||
| } | ||||
|  | ||||
| // SetDeadline sets the read and write deadlines associated | ||||
| // with the connection. | ||||
| func (t *chanConn) SetDeadline(deadline time.Time) error { | ||||
| 	if err := t.SetReadDeadline(deadline); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return t.SetWriteDeadline(deadline) | ||||
| } | ||||
|  | ||||
| // SetReadDeadline sets the read deadline. | ||||
| // A zero value for t means Read will not time out. | ||||
| // After the deadline, the error from Read will implement net.Error | ||||
| // with Timeout() == true. | ||||
| func (t *chanConn) SetReadDeadline(deadline time.Time) error { | ||||
| 	// for compatibility with previous version, | ||||
| 	// the error message contains "tcpChan" | ||||
| 	return errors.New("ssh: tcpChan: deadline not supported") | ||||
| } | ||||
|  | ||||
| // SetWriteDeadline exists to satisfy the net.Conn interface | ||||
| // but is not implemented by this type.  It always returns an error. | ||||
| func (t *chanConn) SetWriteDeadline(deadline time.Time) error { | ||||
| 	return errors.New("ssh: tcpChan: deadline not supported") | ||||
| } | ||||
							
								
								
									
										4
									
								
								vendor/golang.org/x/crypto/ssh/terminal/terminal.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/golang.org/x/crypto/ssh/terminal/terminal.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -159,6 +159,10 @@ func bytesToKey(b []byte, pasteActive bool) (rune, []byte) { | ||||
| 			return keyClearScreen, b[1:] | ||||
| 		case 23: // ^W | ||||
| 			return keyDeleteWord, b[1:] | ||||
| 		case 14: // ^N | ||||
| 			return keyDown, b[1:] | ||||
| 		case 16: // ^P | ||||
| 			return keyUp, b[1:] | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
							
								
								
									
										353
									
								
								vendor/golang.org/x/crypto/ssh/transport.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										353
									
								
								vendor/golang.org/x/crypto/ssh/transport.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,353 @@ | ||||
| // Copyright 2011 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 ssh | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"log" | ||||
| ) | ||||
|  | ||||
| // debugTransport if set, will print packet types as they go over the | ||||
| // wire. No message decoding is done, to minimize the impact on timing. | ||||
| const debugTransport = false | ||||
|  | ||||
| const ( | ||||
| 	gcmCipherID    = "aes128-gcm@openssh.com" | ||||
| 	aes128cbcID    = "aes128-cbc" | ||||
| 	tripledescbcID = "3des-cbc" | ||||
| ) | ||||
|  | ||||
| // packetConn represents a transport that implements packet based | ||||
| // operations. | ||||
| type packetConn interface { | ||||
| 	// Encrypt and send a packet of data to the remote peer. | ||||
| 	writePacket(packet []byte) error | ||||
|  | ||||
| 	// Read a packet from the connection. The read is blocking, | ||||
| 	// i.e. if error is nil, then the returned byte slice is | ||||
| 	// always non-empty. | ||||
| 	readPacket() ([]byte, error) | ||||
|  | ||||
| 	// Close closes the write-side of the connection. | ||||
| 	Close() error | ||||
| } | ||||
|  | ||||
| // transport is the keyingTransport that implements the SSH packet | ||||
| // protocol. | ||||
| type transport struct { | ||||
| 	reader connectionState | ||||
| 	writer connectionState | ||||
|  | ||||
| 	bufReader *bufio.Reader | ||||
| 	bufWriter *bufio.Writer | ||||
| 	rand      io.Reader | ||||
| 	isClient  bool | ||||
| 	io.Closer | ||||
| } | ||||
|  | ||||
| // packetCipher represents a combination of SSH encryption/MAC | ||||
| // protocol.  A single instance should be used for one direction only. | ||||
| type packetCipher interface { | ||||
| 	// writePacket encrypts the packet and writes it to w. The | ||||
| 	// contents of the packet are generally scrambled. | ||||
| 	writePacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error | ||||
|  | ||||
| 	// readPacket reads and decrypts a packet of data. The | ||||
| 	// returned packet may be overwritten by future calls of | ||||
| 	// readPacket. | ||||
| 	readPacket(seqnum uint32, r io.Reader) ([]byte, error) | ||||
| } | ||||
|  | ||||
| // connectionState represents one side (read or write) of the | ||||
| // connection. This is necessary because each direction has its own | ||||
| // keys, and can even have its own algorithms | ||||
| type connectionState struct { | ||||
| 	packetCipher | ||||
| 	seqNum           uint32 | ||||
| 	dir              direction | ||||
| 	pendingKeyChange chan packetCipher | ||||
| } | ||||
|  | ||||
| // 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) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	t.reader.pendingKeyChange <- ciph | ||||
|  | ||||
| 	ciph, err = newPacketCipher(t.writer.dir, algs.w, kexResult) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	t.writer.pendingKeyChange <- ciph | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (t *transport) printPacket(p []byte, write bool) { | ||||
| 	if len(p) == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	who := "server" | ||||
| 	if t.isClient { | ||||
| 		who = "client" | ||||
| 	} | ||||
| 	what := "read" | ||||
| 	if write { | ||||
| 		what = "write" | ||||
| 	} | ||||
|  | ||||
| 	log.Println(what, who, p[0]) | ||||
| } | ||||
|  | ||||
| // Read and decrypt next packet. | ||||
| func (t *transport) readPacket() (p []byte, err error) { | ||||
| 	for { | ||||
| 		p, err = t.reader.readPacket(t.bufReader) | ||||
| 		if err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		if len(p) == 0 || (p[0] != msgIgnore && p[0] != msgDebug) { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	if debugTransport { | ||||
| 		t.printPacket(p, false) | ||||
| 	} | ||||
|  | ||||
| 	return p, err | ||||
| } | ||||
|  | ||||
| func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { | ||||
| 	packet, err := s.packetCipher.readPacket(s.seqNum, r) | ||||
| 	s.seqNum++ | ||||
| 	if err == nil && len(packet) == 0 { | ||||
| 		err = errors.New("ssh: zero length packet") | ||||
| 	} | ||||
|  | ||||
| 	if len(packet) > 0 { | ||||
| 		switch packet[0] { | ||||
| 		case msgNewKeys: | ||||
| 			select { | ||||
| 			case cipher := <-s.pendingKeyChange: | ||||
| 				s.packetCipher = cipher | ||||
| 			default: | ||||
| 				return nil, errors.New("ssh: got bogus newkeys message") | ||||
| 			} | ||||
|  | ||||
| 		case msgDisconnect: | ||||
| 			// Transform a disconnect message into an | ||||
| 			// error. Since this is lowest level at which | ||||
| 			// we interpret message types, doing it here | ||||
| 			// ensures that we don't have to handle it | ||||
| 			// elsewhere. | ||||
| 			var msg disconnectMsg | ||||
| 			if err := Unmarshal(packet, &msg); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			return nil, &msg | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// The packet may point to an internal buffer, so copy the | ||||
| 	// packet out here. | ||||
| 	fresh := make([]byte, len(packet)) | ||||
| 	copy(fresh, packet) | ||||
|  | ||||
| 	return fresh, err | ||||
| } | ||||
|  | ||||
| func (t *transport) writePacket(packet []byte) error { | ||||
| 	if debugTransport { | ||||
| 		t.printPacket(packet, true) | ||||
| 	} | ||||
| 	return t.writer.writePacket(t.bufWriter, t.rand, packet) | ||||
| } | ||||
|  | ||||
| func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error { | ||||
| 	changeKeys := len(packet) > 0 && packet[0] == msgNewKeys | ||||
|  | ||||
| 	err := s.packetCipher.writePacket(s.seqNum, w, rand, packet) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err = w.Flush(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	s.seqNum++ | ||||
| 	if changeKeys { | ||||
| 		select { | ||||
| 		case cipher := <-s.pendingKeyChange: | ||||
| 			s.packetCipher = cipher | ||||
| 		default: | ||||
| 			panic("ssh: no key material for msgNewKeys") | ||||
| 		} | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transport { | ||||
| 	t := &transport{ | ||||
| 		bufReader: bufio.NewReader(rwc), | ||||
| 		bufWriter: bufio.NewWriter(rwc), | ||||
| 		rand:      rand, | ||||
| 		reader: connectionState{ | ||||
| 			packetCipher:     &streamPacketCipher{cipher: noneCipher{}}, | ||||
| 			pendingKeyChange: make(chan packetCipher, 1), | ||||
| 		}, | ||||
| 		writer: connectionState{ | ||||
| 			packetCipher:     &streamPacketCipher{cipher: noneCipher{}}, | ||||
| 			pendingKeyChange: make(chan packetCipher, 1), | ||||
| 		}, | ||||
| 		Closer: rwc, | ||||
| 	} | ||||
| 	t.isClient = isClient | ||||
|  | ||||
| 	if isClient { | ||||
| 		t.reader.dir = serverKeys | ||||
| 		t.writer.dir = clientKeys | ||||
| 	} else { | ||||
| 		t.reader.dir = clientKeys | ||||
| 		t.writer.dir = serverKeys | ||||
| 	} | ||||
|  | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| type direction struct { | ||||
| 	ivTag     []byte | ||||
| 	keyTag    []byte | ||||
| 	macKeyTag []byte | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}} | ||||
| 	clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}} | ||||
| ) | ||||
|  | ||||
| // setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as | ||||
| // described in RFC 4253, section 6.4. direction should either be serverKeys | ||||
| // (to setup server->client keys) or clientKeys (for client->server keys). | ||||
| func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) { | ||||
| 	cipherMode := cipherModes[algs.Cipher] | ||||
| 	macMode := macModes[algs.MAC] | ||||
|  | ||||
| 	iv := make([]byte, cipherMode.ivSize) | ||||
| 	key := make([]byte, cipherMode.keySize) | ||||
| 	macKey := make([]byte, macMode.keySize) | ||||
|  | ||||
| 	generateKeyMaterial(iv, d.ivTag, kex) | ||||
| 	generateKeyMaterial(key, d.keyTag, kex) | ||||
| 	generateKeyMaterial(macKey, d.macKeyTag, kex) | ||||
|  | ||||
| 	return cipherModes[algs.Cipher].create(key, iv, macKey, algs) | ||||
| } | ||||
|  | ||||
| // generateKeyMaterial fills out with key material generated from tag, K, H | ||||
| // and sessionId, as specified in RFC 4253, section 7.2. | ||||
| func generateKeyMaterial(out, tag []byte, r *kexResult) { | ||||
| 	var digestsSoFar []byte | ||||
|  | ||||
| 	h := r.Hash.New() | ||||
| 	for len(out) > 0 { | ||||
| 		h.Reset() | ||||
| 		h.Write(r.K) | ||||
| 		h.Write(r.H) | ||||
|  | ||||
| 		if len(digestsSoFar) == 0 { | ||||
| 			h.Write(tag) | ||||
| 			h.Write(r.SessionID) | ||||
| 		} else { | ||||
| 			h.Write(digestsSoFar) | ||||
| 		} | ||||
|  | ||||
| 		digest := h.Sum(nil) | ||||
| 		n := copy(out, digest) | ||||
| 		out = out[n:] | ||||
| 		if len(out) > 0 { | ||||
| 			digestsSoFar = append(digestsSoFar, digest...) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| const packageVersion = "SSH-2.0-Go" | ||||
|  | ||||
| // Sends and receives a version line.  The versionLine string should | ||||
| // be US ASCII, start with "SSH-2.0-", and should not include a | ||||
| // newline. exchangeVersions returns the other side's version line. | ||||
| func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err error) { | ||||
| 	// Contrary to the RFC, we do not ignore lines that don't | ||||
| 	// start with "SSH-2.0-" to make the library usable with | ||||
| 	// nonconforming servers. | ||||
| 	for _, c := range versionLine { | ||||
| 		// The spec disallows non US-ASCII chars, and | ||||
| 		// specifically forbids null chars. | ||||
| 		if c < 32 { | ||||
| 			return nil, errors.New("ssh: junk character in version line") | ||||
| 		} | ||||
| 	} | ||||
| 	if _, err = rw.Write(append(versionLine, '\r', '\n')); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	them, err = readVersion(rw) | ||||
| 	return them, err | ||||
| } | ||||
|  | ||||
| // maxVersionStringBytes is the maximum number of bytes that we'll | ||||
| // accept as a version string. RFC 4253 section 4.2 limits this at 255 | ||||
| // chars | ||||
| const maxVersionStringBytes = 255 | ||||
|  | ||||
| // Read version string as specified by RFC 4253, section 4.2. | ||||
| func readVersion(r io.Reader) ([]byte, error) { | ||||
| 	versionString := make([]byte, 0, 64) | ||||
| 	var ok bool | ||||
| 	var buf [1]byte | ||||
|  | ||||
| 	for length := 0; length < maxVersionStringBytes; length++ { | ||||
| 		_, err := io.ReadFull(r, buf[:]) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		// The RFC says that the version should be terminated with \r\n | ||||
| 		// but several SSH servers actually only send a \n. | ||||
| 		if buf[0] == '\n' { | ||||
| 			if !bytes.HasPrefix(versionString, []byte("SSH-")) { | ||||
| 				// RFC 4253 says we need to ignore all version string lines | ||||
| 				// except the one containing the SSH version (provided that | ||||
| 				// all the lines do not exceed 255 bytes in total). | ||||
| 				versionString = versionString[:0] | ||||
| 				continue | ||||
| 			} | ||||
| 			ok = true | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		// non ASCII chars are disallowed, but we are lenient, | ||||
| 		// since Go doesn't use null-terminated strings. | ||||
|  | ||||
| 		// The RFC allows a comment after a space, however, | ||||
| 		// all of it (version and comments) goes into the | ||||
| 		// session hash. | ||||
| 		versionString = append(versionString, buf[0]) | ||||
| 	} | ||||
|  | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("ssh: overflow reading version string") | ||||
| 	} | ||||
|  | ||||
| 	// There might be a '\r' on the end which we should remove. | ||||
| 	if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' { | ||||
| 		versionString = versionString[:len(versionString)-1] | ||||
| 	} | ||||
| 	return versionString, nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Tonis Tiigi
					Tonis Tiigi