vendor is not needed
This commit is contained in:
parent
dfbcce84ae
commit
e231769f84
3
vendor/golang.org/x/crypto/AUTHORS
generated
vendored
3
vendor/golang.org/x/crypto/AUTHORS
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
# This source code refers to The Go Authors for copyright purposes.
|
|
||||||
# The master list of authors is in the main Go distribution,
|
|
||||||
# visible at https://tip.golang.org/AUTHORS.
|
|
3
vendor/golang.org/x/crypto/CONTRIBUTORS
generated
vendored
3
vendor/golang.org/x/crypto/CONTRIBUTORS
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
# This source code was written by the Go contributors.
|
|
||||||
# The master list of contributors is in the main Go distribution,
|
|
||||||
# visible at https://tip.golang.org/CONTRIBUTORS.
|
|
27
vendor/golang.org/x/crypto/LICENSE
generated
vendored
27
vendor/golang.org/x/crypto/LICENSE
generated
vendored
@ -1,27 +0,0 @@
|
|||||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
22
vendor/golang.org/x/crypto/PATENTS
generated
vendored
22
vendor/golang.org/x/crypto/PATENTS
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
Additional IP Rights Grant (Patents)
|
|
||||||
|
|
||||||
"This implementation" means the copyrightable works distributed by
|
|
||||||
Google as part of the Go project.
|
|
||||||
|
|
||||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
||||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
|
||||||
patent license to make, have made, use, offer to sell, sell, import,
|
|
||||||
transfer and otherwise run, modify and propagate the contents of this
|
|
||||||
implementation of Go, where such license applies only to those patent
|
|
||||||
claims, both currently owned or controlled by Google and acquired in
|
|
||||||
the future, licensable by Google that are necessarily infringed by this
|
|
||||||
implementation of Go. This grant does not include claims that would be
|
|
||||||
infringed only as a consequence of further modification of this
|
|
||||||
implementation. If you or your agent or exclusive licensee institute or
|
|
||||||
order or agree to the institution of patent litigation against any
|
|
||||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
|
||||||
that this implementation of Go or any code incorporated within this
|
|
||||||
implementation of Go constitutes direct or contributory patent
|
|
||||||
infringement, or inducement of patent infringement, then any patent
|
|
||||||
rights granted to you under this License for this implementation of Go
|
|
||||||
shall terminate as of the date such litigation is filed.
|
|
8
vendor/golang.org/x/crypto/curve25519/const_amd64.h
generated
vendored
8
vendor/golang.org/x/crypto/curve25519/const_amd64.h
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
// 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
20
vendor/golang.org/x/crypto/curve25519/const_amd64.s
generated
vendored
@ -1,20 +0,0 @@
|
|||||||
// 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
65
vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
generated
vendored
@ -1,65 +0,0 @@
|
|||||||
// 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
834
vendor/golang.org/x/crypto/curve25519/curve25519.go
generated
vendored
@ -1,834 +0,0 @@
|
|||||||
// 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:]) & 0x7fffff) << 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
23
vendor/golang.org/x/crypto/curve25519/doc.go
generated
vendored
@ -1,23 +0,0 @@
|
|||||||
// 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
73
vendor/golang.org/x/crypto/curve25519/freeze_amd64.s
generated
vendored
@ -1,73 +0,0 @@
|
|||||||
// 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
1377
vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s
generated
vendored
File diff suppressed because it is too large
Load Diff
240
vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go
generated
vendored
240
vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go
generated
vendored
@ -1,240 +0,0 @@
|
|||||||
// 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
169
vendor/golang.org/x/crypto/curve25519/mul_amd64.s
generated
vendored
@ -1,169 +0,0 @@
|
|||||||
// 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,R8,R9
|
|
||||||
ANDQ SI,R8
|
|
||||||
SHLQ $13,R10,R11
|
|
||||||
ANDQ SI,R10
|
|
||||||
ADDQ R9,R10
|
|
||||||
SHLQ $13,R12,R13
|
|
||||||
ANDQ SI,R12
|
|
||||||
ADDQ R11,R12
|
|
||||||
SHLQ $13,R14,R15
|
|
||||||
ANDQ SI,R14
|
|
||||||
ADDQ R13,R14
|
|
||||||
SHLQ $13,BX,BP
|
|
||||||
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
132
vendor/golang.org/x/crypto/curve25519/square_amd64.s
generated
vendored
@ -1,132 +0,0 @@
|
|||||||
// 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,CX,R8
|
|
||||||
ANDQ SI,CX
|
|
||||||
SHLQ $13,R9,R10
|
|
||||||
ANDQ SI,R9
|
|
||||||
ADDQ R8,R9
|
|
||||||
SHLQ $13,R11,R12
|
|
||||||
ANDQ SI,R11
|
|
||||||
ADDQ R10,R11
|
|
||||||
SHLQ $13,R13,R14
|
|
||||||
ANDQ SI,R13
|
|
||||||
ADDQ R12,R13
|
|
||||||
SHLQ $13,R15,BX
|
|
||||||
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
|
|
222
vendor/golang.org/x/crypto/ed25519/ed25519.go
generated
vendored
222
vendor/golang.org/x/crypto/ed25519/ed25519.go
generated
vendored
@ -1,222 +0,0 @@
|
|||||||
// Copyright 2016 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// In Go 1.13, the ed25519 package was promoted to the standard library as
|
|
||||||
// crypto/ed25519, and this package became a wrapper for the standard library one.
|
|
||||||
//
|
|
||||||
// +build !go1.13
|
|
||||||
|
|
||||||
// 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[:])
|
|
||||||
}
|
|
73
vendor/golang.org/x/crypto/ed25519/ed25519_go113.go
generated
vendored
73
vendor/golang.org/x/crypto/ed25519/ed25519_go113.go
generated
vendored
@ -1,73 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build go1.13
|
|
||||||
|
|
||||||
// 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”.
|
|
||||||
//
|
|
||||||
// Beginning with Go 1.13, the functionality of this package was moved to the
|
|
||||||
// standard library as crypto/ed25519. This package only acts as a compatibility
|
|
||||||
// wrapper.
|
|
||||||
package ed25519
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ed25519"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
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.
|
|
||||||
//
|
|
||||||
// This type is an alias for crypto/ed25519's PublicKey type.
|
|
||||||
// See the crypto/ed25519 package for the methods on this type.
|
|
||||||
type PublicKey = ed25519.PublicKey
|
|
||||||
|
|
||||||
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
|
|
||||||
//
|
|
||||||
// This type is an alias for crypto/ed25519's PrivateKey type.
|
|
||||||
// See the crypto/ed25519 package for the methods on this type.
|
|
||||||
type PrivateKey = ed25519.PrivateKey
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
return ed25519.GenerateKey(rand)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
return ed25519.NewKeyFromSeed(seed)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
return ed25519.Sign(privateKey, message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
return ed25519.Verify(publicKey, message, sig)
|
|
||||||
}
|
|
1422
vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
generated
vendored
1422
vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
generated
vendored
File diff suppressed because it is too large
Load Diff
1793
vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
1793
vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
File diff suppressed because it is too large
Load Diff
308
vendor/golang.org/x/crypto/internal/chacha20/asm_arm64.s
generated
vendored
308
vendor/golang.org/x/crypto/internal/chacha20/asm_arm64.s
generated
vendored
@ -1,308 +0,0 @@
|
|||||||
// 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 go1.11
|
|
||||||
// +build !gccgo,!appengine
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
#define NUM_ROUNDS 10
|
|
||||||
|
|
||||||
// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
|
|
||||||
TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0
|
|
||||||
MOVD dst+0(FP), R1
|
|
||||||
MOVD src+24(FP), R2
|
|
||||||
MOVD src_len+32(FP), R3
|
|
||||||
MOVD key+48(FP), R4
|
|
||||||
MOVD nonce+56(FP), R6
|
|
||||||
MOVD counter+64(FP), R7
|
|
||||||
|
|
||||||
MOVD $·constants(SB), R10
|
|
||||||
MOVD $·incRotMatrix(SB), R11
|
|
||||||
|
|
||||||
MOVW (R7), R20
|
|
||||||
|
|
||||||
AND $~255, R3, R13
|
|
||||||
ADD R2, R13, R12 // R12 for block end
|
|
||||||
AND $255, R3, R13
|
|
||||||
loop:
|
|
||||||
MOVD $NUM_ROUNDS, R21
|
|
||||||
VLD1 (R11), [V30.S4, V31.S4]
|
|
||||||
|
|
||||||
// load contants
|
|
||||||
// VLD4R (R10), [V0.S4, V1.S4, V2.S4, V3.S4]
|
|
||||||
WORD $0x4D60E940
|
|
||||||
|
|
||||||
// load keys
|
|
||||||
// VLD4R 16(R4), [V4.S4, V5.S4, V6.S4, V7.S4]
|
|
||||||
WORD $0x4DFFE884
|
|
||||||
// VLD4R 16(R4), [V8.S4, V9.S4, V10.S4, V11.S4]
|
|
||||||
WORD $0x4DFFE888
|
|
||||||
SUB $32, R4
|
|
||||||
|
|
||||||
// load counter + nonce
|
|
||||||
// VLD1R (R7), [V12.S4]
|
|
||||||
WORD $0x4D40C8EC
|
|
||||||
|
|
||||||
// VLD3R (R6), [V13.S4, V14.S4, V15.S4]
|
|
||||||
WORD $0x4D40E8CD
|
|
||||||
|
|
||||||
// update counter
|
|
||||||
VADD V30.S4, V12.S4, V12.S4
|
|
||||||
|
|
||||||
chacha:
|
|
||||||
// V0..V3 += V4..V7
|
|
||||||
// V12..V15 <<<= ((V12..V15 XOR V0..V3), 16)
|
|
||||||
VADD V0.S4, V4.S4, V0.S4
|
|
||||||
VADD V1.S4, V5.S4, V1.S4
|
|
||||||
VADD V2.S4, V6.S4, V2.S4
|
|
||||||
VADD V3.S4, V7.S4, V3.S4
|
|
||||||
VEOR V12.B16, V0.B16, V12.B16
|
|
||||||
VEOR V13.B16, V1.B16, V13.B16
|
|
||||||
VEOR V14.B16, V2.B16, V14.B16
|
|
||||||
VEOR V15.B16, V3.B16, V15.B16
|
|
||||||
VREV32 V12.H8, V12.H8
|
|
||||||
VREV32 V13.H8, V13.H8
|
|
||||||
VREV32 V14.H8, V14.H8
|
|
||||||
VREV32 V15.H8, V15.H8
|
|
||||||
// V8..V11 += V12..V15
|
|
||||||
// V4..V7 <<<= ((V4..V7 XOR V8..V11), 12)
|
|
||||||
VADD V8.S4, V12.S4, V8.S4
|
|
||||||
VADD V9.S4, V13.S4, V9.S4
|
|
||||||
VADD V10.S4, V14.S4, V10.S4
|
|
||||||
VADD V11.S4, V15.S4, V11.S4
|
|
||||||
VEOR V8.B16, V4.B16, V16.B16
|
|
||||||
VEOR V9.B16, V5.B16, V17.B16
|
|
||||||
VEOR V10.B16, V6.B16, V18.B16
|
|
||||||
VEOR V11.B16, V7.B16, V19.B16
|
|
||||||
VSHL $12, V16.S4, V4.S4
|
|
||||||
VSHL $12, V17.S4, V5.S4
|
|
||||||
VSHL $12, V18.S4, V6.S4
|
|
||||||
VSHL $12, V19.S4, V7.S4
|
|
||||||
VSRI $20, V16.S4, V4.S4
|
|
||||||
VSRI $20, V17.S4, V5.S4
|
|
||||||
VSRI $20, V18.S4, V6.S4
|
|
||||||
VSRI $20, V19.S4, V7.S4
|
|
||||||
|
|
||||||
// V0..V3 += V4..V7
|
|
||||||
// V12..V15 <<<= ((V12..V15 XOR V0..V3), 8)
|
|
||||||
VADD V0.S4, V4.S4, V0.S4
|
|
||||||
VADD V1.S4, V5.S4, V1.S4
|
|
||||||
VADD V2.S4, V6.S4, V2.S4
|
|
||||||
VADD V3.S4, V7.S4, V3.S4
|
|
||||||
VEOR V12.B16, V0.B16, V12.B16
|
|
||||||
VEOR V13.B16, V1.B16, V13.B16
|
|
||||||
VEOR V14.B16, V2.B16, V14.B16
|
|
||||||
VEOR V15.B16, V3.B16, V15.B16
|
|
||||||
VTBL V31.B16, [V12.B16], V12.B16
|
|
||||||
VTBL V31.B16, [V13.B16], V13.B16
|
|
||||||
VTBL V31.B16, [V14.B16], V14.B16
|
|
||||||
VTBL V31.B16, [V15.B16], V15.B16
|
|
||||||
|
|
||||||
// V8..V11 += V12..V15
|
|
||||||
// V4..V7 <<<= ((V4..V7 XOR V8..V11), 7)
|
|
||||||
VADD V12.S4, V8.S4, V8.S4
|
|
||||||
VADD V13.S4, V9.S4, V9.S4
|
|
||||||
VADD V14.S4, V10.S4, V10.S4
|
|
||||||
VADD V15.S4, V11.S4, V11.S4
|
|
||||||
VEOR V8.B16, V4.B16, V16.B16
|
|
||||||
VEOR V9.B16, V5.B16, V17.B16
|
|
||||||
VEOR V10.B16, V6.B16, V18.B16
|
|
||||||
VEOR V11.B16, V7.B16, V19.B16
|
|
||||||
VSHL $7, V16.S4, V4.S4
|
|
||||||
VSHL $7, V17.S4, V5.S4
|
|
||||||
VSHL $7, V18.S4, V6.S4
|
|
||||||
VSHL $7, V19.S4, V7.S4
|
|
||||||
VSRI $25, V16.S4, V4.S4
|
|
||||||
VSRI $25, V17.S4, V5.S4
|
|
||||||
VSRI $25, V18.S4, V6.S4
|
|
||||||
VSRI $25, V19.S4, V7.S4
|
|
||||||
|
|
||||||
// V0..V3 += V5..V7, V4
|
|
||||||
// V15,V12-V14 <<<= ((V15,V12-V14 XOR V0..V3), 16)
|
|
||||||
VADD V0.S4, V5.S4, V0.S4
|
|
||||||
VADD V1.S4, V6.S4, V1.S4
|
|
||||||
VADD V2.S4, V7.S4, V2.S4
|
|
||||||
VADD V3.S4, V4.S4, V3.S4
|
|
||||||
VEOR V15.B16, V0.B16, V15.B16
|
|
||||||
VEOR V12.B16, V1.B16, V12.B16
|
|
||||||
VEOR V13.B16, V2.B16, V13.B16
|
|
||||||
VEOR V14.B16, V3.B16, V14.B16
|
|
||||||
VREV32 V12.H8, V12.H8
|
|
||||||
VREV32 V13.H8, V13.H8
|
|
||||||
VREV32 V14.H8, V14.H8
|
|
||||||
VREV32 V15.H8, V15.H8
|
|
||||||
|
|
||||||
// V10 += V15; V5 <<<= ((V10 XOR V5), 12)
|
|
||||||
// ...
|
|
||||||
VADD V15.S4, V10.S4, V10.S4
|
|
||||||
VADD V12.S4, V11.S4, V11.S4
|
|
||||||
VADD V13.S4, V8.S4, V8.S4
|
|
||||||
VADD V14.S4, V9.S4, V9.S4
|
|
||||||
VEOR V10.B16, V5.B16, V16.B16
|
|
||||||
VEOR V11.B16, V6.B16, V17.B16
|
|
||||||
VEOR V8.B16, V7.B16, V18.B16
|
|
||||||
VEOR V9.B16, V4.B16, V19.B16
|
|
||||||
VSHL $12, V16.S4, V5.S4
|
|
||||||
VSHL $12, V17.S4, V6.S4
|
|
||||||
VSHL $12, V18.S4, V7.S4
|
|
||||||
VSHL $12, V19.S4, V4.S4
|
|
||||||
VSRI $20, V16.S4, V5.S4
|
|
||||||
VSRI $20, V17.S4, V6.S4
|
|
||||||
VSRI $20, V18.S4, V7.S4
|
|
||||||
VSRI $20, V19.S4, V4.S4
|
|
||||||
|
|
||||||
// V0 += V5; V15 <<<= ((V0 XOR V15), 8)
|
|
||||||
// ...
|
|
||||||
VADD V5.S4, V0.S4, V0.S4
|
|
||||||
VADD V6.S4, V1.S4, V1.S4
|
|
||||||
VADD V7.S4, V2.S4, V2.S4
|
|
||||||
VADD V4.S4, V3.S4, V3.S4
|
|
||||||
VEOR V0.B16, V15.B16, V15.B16
|
|
||||||
VEOR V1.B16, V12.B16, V12.B16
|
|
||||||
VEOR V2.B16, V13.B16, V13.B16
|
|
||||||
VEOR V3.B16, V14.B16, V14.B16
|
|
||||||
VTBL V31.B16, [V12.B16], V12.B16
|
|
||||||
VTBL V31.B16, [V13.B16], V13.B16
|
|
||||||
VTBL V31.B16, [V14.B16], V14.B16
|
|
||||||
VTBL V31.B16, [V15.B16], V15.B16
|
|
||||||
|
|
||||||
// V10 += V15; V5 <<<= ((V10 XOR V5), 7)
|
|
||||||
// ...
|
|
||||||
VADD V15.S4, V10.S4, V10.S4
|
|
||||||
VADD V12.S4, V11.S4, V11.S4
|
|
||||||
VADD V13.S4, V8.S4, V8.S4
|
|
||||||
VADD V14.S4, V9.S4, V9.S4
|
|
||||||
VEOR V10.B16, V5.B16, V16.B16
|
|
||||||
VEOR V11.B16, V6.B16, V17.B16
|
|
||||||
VEOR V8.B16, V7.B16, V18.B16
|
|
||||||
VEOR V9.B16, V4.B16, V19.B16
|
|
||||||
VSHL $7, V16.S4, V5.S4
|
|
||||||
VSHL $7, V17.S4, V6.S4
|
|
||||||
VSHL $7, V18.S4, V7.S4
|
|
||||||
VSHL $7, V19.S4, V4.S4
|
|
||||||
VSRI $25, V16.S4, V5.S4
|
|
||||||
VSRI $25, V17.S4, V6.S4
|
|
||||||
VSRI $25, V18.S4, V7.S4
|
|
||||||
VSRI $25, V19.S4, V4.S4
|
|
||||||
|
|
||||||
SUB $1, R21
|
|
||||||
CBNZ R21, chacha
|
|
||||||
|
|
||||||
// VLD4R (R10), [V16.S4, V17.S4, V18.S4, V19.S4]
|
|
||||||
WORD $0x4D60E950
|
|
||||||
|
|
||||||
// VLD4R 16(R4), [V20.S4, V21.S4, V22.S4, V23.S4]
|
|
||||||
WORD $0x4DFFE894
|
|
||||||
VADD V30.S4, V12.S4, V12.S4
|
|
||||||
VADD V16.S4, V0.S4, V0.S4
|
|
||||||
VADD V17.S4, V1.S4, V1.S4
|
|
||||||
VADD V18.S4, V2.S4, V2.S4
|
|
||||||
VADD V19.S4, V3.S4, V3.S4
|
|
||||||
// VLD4R 16(R4), [V24.S4, V25.S4, V26.S4, V27.S4]
|
|
||||||
WORD $0x4DFFE898
|
|
||||||
// restore R4
|
|
||||||
SUB $32, R4
|
|
||||||
|
|
||||||
// load counter + nonce
|
|
||||||
// VLD1R (R7), [V28.S4]
|
|
||||||
WORD $0x4D40C8FC
|
|
||||||
// VLD3R (R6), [V29.S4, V30.S4, V31.S4]
|
|
||||||
WORD $0x4D40E8DD
|
|
||||||
|
|
||||||
VADD V20.S4, V4.S4, V4.S4
|
|
||||||
VADD V21.S4, V5.S4, V5.S4
|
|
||||||
VADD V22.S4, V6.S4, V6.S4
|
|
||||||
VADD V23.S4, V7.S4, V7.S4
|
|
||||||
VADD V24.S4, V8.S4, V8.S4
|
|
||||||
VADD V25.S4, V9.S4, V9.S4
|
|
||||||
VADD V26.S4, V10.S4, V10.S4
|
|
||||||
VADD V27.S4, V11.S4, V11.S4
|
|
||||||
VADD V28.S4, V12.S4, V12.S4
|
|
||||||
VADD V29.S4, V13.S4, V13.S4
|
|
||||||
VADD V30.S4, V14.S4, V14.S4
|
|
||||||
VADD V31.S4, V15.S4, V15.S4
|
|
||||||
|
|
||||||
VZIP1 V1.S4, V0.S4, V16.S4
|
|
||||||
VZIP2 V1.S4, V0.S4, V17.S4
|
|
||||||
VZIP1 V3.S4, V2.S4, V18.S4
|
|
||||||
VZIP2 V3.S4, V2.S4, V19.S4
|
|
||||||
VZIP1 V5.S4, V4.S4, V20.S4
|
|
||||||
VZIP2 V5.S4, V4.S4, V21.S4
|
|
||||||
VZIP1 V7.S4, V6.S4, V22.S4
|
|
||||||
VZIP2 V7.S4, V6.S4, V23.S4
|
|
||||||
VZIP1 V9.S4, V8.S4, V24.S4
|
|
||||||
VZIP2 V9.S4, V8.S4, V25.S4
|
|
||||||
VZIP1 V11.S4, V10.S4, V26.S4
|
|
||||||
VZIP2 V11.S4, V10.S4, V27.S4
|
|
||||||
VZIP1 V13.S4, V12.S4, V28.S4
|
|
||||||
VZIP2 V13.S4, V12.S4, V29.S4
|
|
||||||
VZIP1 V15.S4, V14.S4, V30.S4
|
|
||||||
VZIP2 V15.S4, V14.S4, V31.S4
|
|
||||||
VZIP1 V18.D2, V16.D2, V0.D2
|
|
||||||
VZIP2 V18.D2, V16.D2, V4.D2
|
|
||||||
VZIP1 V19.D2, V17.D2, V8.D2
|
|
||||||
VZIP2 V19.D2, V17.D2, V12.D2
|
|
||||||
VLD1.P 64(R2), [V16.B16, V17.B16, V18.B16, V19.B16]
|
|
||||||
|
|
||||||
VZIP1 V22.D2, V20.D2, V1.D2
|
|
||||||
VZIP2 V22.D2, V20.D2, V5.D2
|
|
||||||
VZIP1 V23.D2, V21.D2, V9.D2
|
|
||||||
VZIP2 V23.D2, V21.D2, V13.D2
|
|
||||||
VLD1.P 64(R2), [V20.B16, V21.B16, V22.B16, V23.B16]
|
|
||||||
VZIP1 V26.D2, V24.D2, V2.D2
|
|
||||||
VZIP2 V26.D2, V24.D2, V6.D2
|
|
||||||
VZIP1 V27.D2, V25.D2, V10.D2
|
|
||||||
VZIP2 V27.D2, V25.D2, V14.D2
|
|
||||||
VLD1.P 64(R2), [V24.B16, V25.B16, V26.B16, V27.B16]
|
|
||||||
VZIP1 V30.D2, V28.D2, V3.D2
|
|
||||||
VZIP2 V30.D2, V28.D2, V7.D2
|
|
||||||
VZIP1 V31.D2, V29.D2, V11.D2
|
|
||||||
VZIP2 V31.D2, V29.D2, V15.D2
|
|
||||||
VLD1.P 64(R2), [V28.B16, V29.B16, V30.B16, V31.B16]
|
|
||||||
VEOR V0.B16, V16.B16, V16.B16
|
|
||||||
VEOR V1.B16, V17.B16, V17.B16
|
|
||||||
VEOR V2.B16, V18.B16, V18.B16
|
|
||||||
VEOR V3.B16, V19.B16, V19.B16
|
|
||||||
VST1.P [V16.B16, V17.B16, V18.B16, V19.B16], 64(R1)
|
|
||||||
VEOR V4.B16, V20.B16, V20.B16
|
|
||||||
VEOR V5.B16, V21.B16, V21.B16
|
|
||||||
VEOR V6.B16, V22.B16, V22.B16
|
|
||||||
VEOR V7.B16, V23.B16, V23.B16
|
|
||||||
VST1.P [V20.B16, V21.B16, V22.B16, V23.B16], 64(R1)
|
|
||||||
VEOR V8.B16, V24.B16, V24.B16
|
|
||||||
VEOR V9.B16, V25.B16, V25.B16
|
|
||||||
VEOR V10.B16, V26.B16, V26.B16
|
|
||||||
VEOR V11.B16, V27.B16, V27.B16
|
|
||||||
VST1.P [V24.B16, V25.B16, V26.B16, V27.B16], 64(R1)
|
|
||||||
VEOR V12.B16, V28.B16, V28.B16
|
|
||||||
VEOR V13.B16, V29.B16, V29.B16
|
|
||||||
VEOR V14.B16, V30.B16, V30.B16
|
|
||||||
VEOR V15.B16, V31.B16, V31.B16
|
|
||||||
VST1.P [V28.B16, V29.B16, V30.B16, V31.B16], 64(R1)
|
|
||||||
|
|
||||||
ADD $4, R20
|
|
||||||
MOVW R20, (R7) // update counter
|
|
||||||
|
|
||||||
CMP R2, R12
|
|
||||||
BGT loop
|
|
||||||
|
|
||||||
RET
|
|
||||||
|
|
||||||
|
|
||||||
DATA ·constants+0x00(SB)/4, $0x61707865
|
|
||||||
DATA ·constants+0x04(SB)/4, $0x3320646e
|
|
||||||
DATA ·constants+0x08(SB)/4, $0x79622d32
|
|
||||||
DATA ·constants+0x0c(SB)/4, $0x6b206574
|
|
||||||
GLOBL ·constants(SB), NOPTR|RODATA, $32
|
|
||||||
|
|
||||||
DATA ·incRotMatrix+0x00(SB)/4, $0x00000000
|
|
||||||
DATA ·incRotMatrix+0x04(SB)/4, $0x00000001
|
|
||||||
DATA ·incRotMatrix+0x08(SB)/4, $0x00000002
|
|
||||||
DATA ·incRotMatrix+0x0c(SB)/4, $0x00000003
|
|
||||||
DATA ·incRotMatrix+0x10(SB)/4, $0x02010003
|
|
||||||
DATA ·incRotMatrix+0x14(SB)/4, $0x06050407
|
|
||||||
DATA ·incRotMatrix+0x18(SB)/4, $0x0A09080B
|
|
||||||
DATA ·incRotMatrix+0x1c(SB)/4, $0x0E0D0C0F
|
|
||||||
GLOBL ·incRotMatrix(SB), NOPTR|RODATA, $32
|
|
668
vendor/golang.org/x/crypto/internal/chacha20/asm_ppc64le.s
generated
vendored
668
vendor/golang.org/x/crypto/internal/chacha20/asm_ppc64le.s
generated
vendored
@ -1,668 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Based on CRYPTOGAMS code with the following comment:
|
|
||||||
// # ====================================================================
|
|
||||||
// # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
|
|
||||||
// # project. The module is, however, dual licensed under OpenSSL and
|
|
||||||
// # CRYPTOGAMS licenses depending on where you obtain it. For further
|
|
||||||
// # details see http://www.openssl.org/~appro/cryptogams/.
|
|
||||||
// # ====================================================================
|
|
||||||
|
|
||||||
// Original code can be found at the link below:
|
|
||||||
// https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91e5c39ca79126a4a876d5d8ff
|
|
||||||
|
|
||||||
// There are some differences between CRYPTOGAMS code and this one. The round
|
|
||||||
// loop for "_int" isn't the same as the original. Some adjustments were
|
|
||||||
// necessary because there are less vector registers available. For example, some
|
|
||||||
// X variables (r12, r13, r14, and r15) share the same register used by the
|
|
||||||
// counter. The original code uses ctr to name the counter. Here we use CNT
|
|
||||||
// because golang uses CTR as the counter register name.
|
|
||||||
|
|
||||||
// +build ppc64le,!gccgo,!appengine
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
#define OUT R3
|
|
||||||
#define INP R4
|
|
||||||
#define LEN R5
|
|
||||||
#define KEY R6
|
|
||||||
#define CNT R7
|
|
||||||
|
|
||||||
#define TEMP R8
|
|
||||||
|
|
||||||
#define X0 R11
|
|
||||||
#define X1 R12
|
|
||||||
#define X2 R14
|
|
||||||
#define X3 R15
|
|
||||||
#define X4 R16
|
|
||||||
#define X5 R17
|
|
||||||
#define X6 R18
|
|
||||||
#define X7 R19
|
|
||||||
#define X8 R20
|
|
||||||
#define X9 R21
|
|
||||||
#define X10 R22
|
|
||||||
#define X11 R23
|
|
||||||
#define X12 R24
|
|
||||||
#define X13 R25
|
|
||||||
#define X14 R26
|
|
||||||
#define X15 R27
|
|
||||||
|
|
||||||
#define CON0 X0
|
|
||||||
#define CON1 X1
|
|
||||||
#define CON2 X2
|
|
||||||
#define CON3 X3
|
|
||||||
|
|
||||||
#define KEY0 X4
|
|
||||||
#define KEY1 X5
|
|
||||||
#define KEY2 X6
|
|
||||||
#define KEY3 X7
|
|
||||||
#define KEY4 X8
|
|
||||||
#define KEY5 X9
|
|
||||||
#define KEY6 X10
|
|
||||||
#define KEY7 X11
|
|
||||||
|
|
||||||
#define CNT0 X12
|
|
||||||
#define CNT1 X13
|
|
||||||
#define CNT2 X14
|
|
||||||
#define CNT3 X15
|
|
||||||
|
|
||||||
#define TMP0 R9
|
|
||||||
#define TMP1 R10
|
|
||||||
#define TMP2 R28
|
|
||||||
#define TMP3 R29
|
|
||||||
|
|
||||||
#define CONSTS R8
|
|
||||||
|
|
||||||
#define A0 V0
|
|
||||||
#define B0 V1
|
|
||||||
#define C0 V2
|
|
||||||
#define D0 V3
|
|
||||||
#define A1 V4
|
|
||||||
#define B1 V5
|
|
||||||
#define C1 V6
|
|
||||||
#define D1 V7
|
|
||||||
#define A2 V8
|
|
||||||
#define B2 V9
|
|
||||||
#define C2 V10
|
|
||||||
#define D2 V11
|
|
||||||
#define T0 V12
|
|
||||||
#define T1 V13
|
|
||||||
#define T2 V14
|
|
||||||
|
|
||||||
#define K0 V15
|
|
||||||
#define K1 V16
|
|
||||||
#define K2 V17
|
|
||||||
#define K3 V18
|
|
||||||
#define K4 V19
|
|
||||||
#define K5 V20
|
|
||||||
|
|
||||||
#define FOUR V21
|
|
||||||
#define SIXTEEN V22
|
|
||||||
#define TWENTY4 V23
|
|
||||||
#define TWENTY V24
|
|
||||||
#define TWELVE V25
|
|
||||||
#define TWENTY5 V26
|
|
||||||
#define SEVEN V27
|
|
||||||
|
|
||||||
#define INPPERM V28
|
|
||||||
#define OUTPERM V29
|
|
||||||
#define OUTMASK V30
|
|
||||||
|
|
||||||
#define DD0 V31
|
|
||||||
#define DD1 SEVEN
|
|
||||||
#define DD2 T0
|
|
||||||
#define DD3 T1
|
|
||||||
#define DD4 T2
|
|
||||||
|
|
||||||
DATA ·consts+0x00(SB)/8, $0x3320646e61707865
|
|
||||||
DATA ·consts+0x08(SB)/8, $0x6b20657479622d32
|
|
||||||
DATA ·consts+0x10(SB)/8, $0x0000000000000001
|
|
||||||
DATA ·consts+0x18(SB)/8, $0x0000000000000000
|
|
||||||
DATA ·consts+0x20(SB)/8, $0x0000000000000004
|
|
||||||
DATA ·consts+0x28(SB)/8, $0x0000000000000000
|
|
||||||
DATA ·consts+0x30(SB)/8, $0x0a0b08090e0f0c0d
|
|
||||||
DATA ·consts+0x38(SB)/8, $0x0203000106070405
|
|
||||||
DATA ·consts+0x40(SB)/8, $0x090a0b080d0e0f0c
|
|
||||||
DATA ·consts+0x48(SB)/8, $0x0102030005060704
|
|
||||||
GLOBL ·consts(SB), RODATA, $80
|
|
||||||
|
|
||||||
//func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[32]byte, counter *[16]byte)
|
|
||||||
TEXT ·chaCha20_ctr32_vmx(SB),NOSPLIT|NOFRAME,$0
|
|
||||||
// Load the arguments inside the registers
|
|
||||||
MOVD out+0(FP), OUT
|
|
||||||
MOVD inp+8(FP), INP
|
|
||||||
MOVD len+16(FP), LEN
|
|
||||||
MOVD key+24(FP), KEY
|
|
||||||
MOVD counter+32(FP), CNT
|
|
||||||
|
|
||||||
MOVD $·consts(SB), CONSTS // point to consts addr
|
|
||||||
|
|
||||||
MOVD $16, X0
|
|
||||||
MOVD $32, X1
|
|
||||||
MOVD $48, X2
|
|
||||||
MOVD $64, X3
|
|
||||||
MOVD $31, X4
|
|
||||||
MOVD $15, X5
|
|
||||||
|
|
||||||
// Load key
|
|
||||||
LVX (KEY)(R0), K1
|
|
||||||
LVSR (KEY)(R0), T0
|
|
||||||
LVX (KEY)(X0), K2
|
|
||||||
LVX (KEY)(X4), DD0
|
|
||||||
|
|
||||||
// Load counter
|
|
||||||
LVX (CNT)(R0), K3
|
|
||||||
LVSR (CNT)(R0), T1
|
|
||||||
LVX (CNT)(X5), DD1
|
|
||||||
|
|
||||||
// Load constants
|
|
||||||
LVX (CONSTS)(R0), K0
|
|
||||||
LVX (CONSTS)(X0), K5
|
|
||||||
LVX (CONSTS)(X1), FOUR
|
|
||||||
LVX (CONSTS)(X2), SIXTEEN
|
|
||||||
LVX (CONSTS)(X3), TWENTY4
|
|
||||||
|
|
||||||
// Align key and counter
|
|
||||||
VPERM K2, K1, T0, K1
|
|
||||||
VPERM DD0, K2, T0, K2
|
|
||||||
VPERM DD1, K3, T1, K3
|
|
||||||
|
|
||||||
// Load counter to GPR
|
|
||||||
MOVWZ 0(CNT), CNT0
|
|
||||||
MOVWZ 4(CNT), CNT1
|
|
||||||
MOVWZ 8(CNT), CNT2
|
|
||||||
MOVWZ 12(CNT), CNT3
|
|
||||||
|
|
||||||
// Adjust vectors for the initial state
|
|
||||||
VADDUWM K3, K5, K3
|
|
||||||
VADDUWM K3, K5, K4
|
|
||||||
VADDUWM K4, K5, K5
|
|
||||||
|
|
||||||
// Synthesized constants
|
|
||||||
VSPLTISW $-12, TWENTY
|
|
||||||
VSPLTISW $12, TWELVE
|
|
||||||
VSPLTISW $-7, TWENTY5
|
|
||||||
|
|
||||||
VXOR T0, T0, T0
|
|
||||||
VSPLTISW $-1, OUTMASK
|
|
||||||
LVSR (INP)(R0), INPPERM
|
|
||||||
LVSL (OUT)(R0), OUTPERM
|
|
||||||
VPERM OUTMASK, T0, OUTPERM, OUTMASK
|
|
||||||
|
|
||||||
loop_outer_vmx:
|
|
||||||
// Load constant
|
|
||||||
MOVD $0x61707865, CON0
|
|
||||||
MOVD $0x3320646e, CON1
|
|
||||||
MOVD $0x79622d32, CON2
|
|
||||||
MOVD $0x6b206574, CON3
|
|
||||||
|
|
||||||
VOR K0, K0, A0
|
|
||||||
VOR K0, K0, A1
|
|
||||||
VOR K0, K0, A2
|
|
||||||
VOR K1, K1, B0
|
|
||||||
|
|
||||||
MOVD $10, TEMP
|
|
||||||
|
|
||||||
// Load key to GPR
|
|
||||||
MOVWZ 0(KEY), X4
|
|
||||||
MOVWZ 4(KEY), X5
|
|
||||||
MOVWZ 8(KEY), X6
|
|
||||||
MOVWZ 12(KEY), X7
|
|
||||||
VOR K1, K1, B1
|
|
||||||
VOR K1, K1, B2
|
|
||||||
MOVWZ 16(KEY), X8
|
|
||||||
MOVWZ 0(CNT), X12
|
|
||||||
MOVWZ 20(KEY), X9
|
|
||||||
MOVWZ 4(CNT), X13
|
|
||||||
VOR K2, K2, C0
|
|
||||||
VOR K2, K2, C1
|
|
||||||
MOVWZ 24(KEY), X10
|
|
||||||
MOVWZ 8(CNT), X14
|
|
||||||
VOR K2, K2, C2
|
|
||||||
VOR K3, K3, D0
|
|
||||||
MOVWZ 28(KEY), X11
|
|
||||||
MOVWZ 12(CNT), X15
|
|
||||||
VOR K4, K4, D1
|
|
||||||
VOR K5, K5, D2
|
|
||||||
|
|
||||||
MOVD X4, TMP0
|
|
||||||
MOVD X5, TMP1
|
|
||||||
MOVD X6, TMP2
|
|
||||||
MOVD X7, TMP3
|
|
||||||
VSPLTISW $7, SEVEN
|
|
||||||
|
|
||||||
MOVD TEMP, CTR
|
|
||||||
|
|
||||||
loop_vmx:
|
|
||||||
// CRYPTOGAMS uses a macro to create a loop using perl. This isn't possible
|
|
||||||
// using assembly macros. Therefore, the macro expansion result was used
|
|
||||||
// in order to maintain the algorithm efficiency.
|
|
||||||
// This loop generates three keystream blocks using VMX instructions and,
|
|
||||||
// in parallel, one keystream block using scalar instructions.
|
|
||||||
ADD X4, X0, X0
|
|
||||||
ADD X5, X1, X1
|
|
||||||
VADDUWM A0, B0, A0
|
|
||||||
VADDUWM A1, B1, A1
|
|
||||||
ADD X6, X2, X2
|
|
||||||
ADD X7, X3, X3
|
|
||||||
VADDUWM A2, B2, A2
|
|
||||||
VXOR D0, A0, D0
|
|
||||||
XOR X0, X12, X12
|
|
||||||
XOR X1, X13, X13
|
|
||||||
VXOR D1, A1, D1
|
|
||||||
VXOR D2, A2, D2
|
|
||||||
XOR X2, X14, X14
|
|
||||||
XOR X3, X15, X15
|
|
||||||
VPERM D0, D0, SIXTEEN, D0
|
|
||||||
VPERM D1, D1, SIXTEEN, D1
|
|
||||||
ROTLW $16, X12, X12
|
|
||||||
ROTLW $16, X13, X13
|
|
||||||
VPERM D2, D2, SIXTEEN, D2
|
|
||||||
VADDUWM C0, D0, C0
|
|
||||||
ROTLW $16, X14, X14
|
|
||||||
ROTLW $16, X15, X15
|
|
||||||
VADDUWM C1, D1, C1
|
|
||||||
VADDUWM C2, D2, C2
|
|
||||||
ADD X12, X8, X8
|
|
||||||
ADD X13, X9, X9
|
|
||||||
VXOR B0, C0, T0
|
|
||||||
VXOR B1, C1, T1
|
|
||||||
ADD X14, X10, X10
|
|
||||||
ADD X15, X11, X11
|
|
||||||
VXOR B2, C2, T2
|
|
||||||
VRLW T0, TWELVE, B0
|
|
||||||
XOR X8, X4, X4
|
|
||||||
XOR X9, X5, X5
|
|
||||||
VRLW T1, TWELVE, B1
|
|
||||||
VRLW T2, TWELVE, B2
|
|
||||||
XOR X10, X6, X6
|
|
||||||
XOR X11, X7, X7
|
|
||||||
VADDUWM A0, B0, A0
|
|
||||||
VADDUWM A1, B1, A1
|
|
||||||
ROTLW $12, X4, X4
|
|
||||||
ROTLW $12, X5, X5
|
|
||||||
VADDUWM A2, B2, A2
|
|
||||||
VXOR D0, A0, D0
|
|
||||||
ROTLW $12, X6, X6
|
|
||||||
ROTLW $12, X7, X7
|
|
||||||
VXOR D1, A1, D1
|
|
||||||
VXOR D2, A2, D2
|
|
||||||
ADD X4, X0, X0
|
|
||||||
ADD X5, X1, X1
|
|
||||||
VPERM D0, D0, TWENTY4, D0
|
|
||||||
VPERM D1, D1, TWENTY4, D1
|
|
||||||
ADD X6, X2, X2
|
|
||||||
ADD X7, X3, X3
|
|
||||||
VPERM D2, D2, TWENTY4, D2
|
|
||||||
VADDUWM C0, D0, C0
|
|
||||||
XOR X0, X12, X12
|
|
||||||
XOR X1, X13, X13
|
|
||||||
VADDUWM C1, D1, C1
|
|
||||||
VADDUWM C2, D2, C2
|
|
||||||
XOR X2, X14, X14
|
|
||||||
XOR X3, X15, X15
|
|
||||||
VXOR B0, C0, T0
|
|
||||||
VXOR B1, C1, T1
|
|
||||||
ROTLW $8, X12, X12
|
|
||||||
ROTLW $8, X13, X13
|
|
||||||
VXOR B2, C2, T2
|
|
||||||
VRLW T0, SEVEN, B0
|
|
||||||
ROTLW $8, X14, X14
|
|
||||||
ROTLW $8, X15, X15
|
|
||||||
VRLW T1, SEVEN, B1
|
|
||||||
VRLW T2, SEVEN, B2
|
|
||||||
ADD X12, X8, X8
|
|
||||||
ADD X13, X9, X9
|
|
||||||
VSLDOI $8, C0, C0, C0
|
|
||||||
VSLDOI $8, C1, C1, C1
|
|
||||||
ADD X14, X10, X10
|
|
||||||
ADD X15, X11, X11
|
|
||||||
VSLDOI $8, C2, C2, C2
|
|
||||||
VSLDOI $12, B0, B0, B0
|
|
||||||
XOR X8, X4, X4
|
|
||||||
XOR X9, X5, X5
|
|
||||||
VSLDOI $12, B1, B1, B1
|
|
||||||
VSLDOI $12, B2, B2, B2
|
|
||||||
XOR X10, X6, X6
|
|
||||||
XOR X11, X7, X7
|
|
||||||
VSLDOI $4, D0, D0, D0
|
|
||||||
VSLDOI $4, D1, D1, D1
|
|
||||||
ROTLW $7, X4, X4
|
|
||||||
ROTLW $7, X5, X5
|
|
||||||
VSLDOI $4, D2, D2, D2
|
|
||||||
VADDUWM A0, B0, A0
|
|
||||||
ROTLW $7, X6, X6
|
|
||||||
ROTLW $7, X7, X7
|
|
||||||
VADDUWM A1, B1, A1
|
|
||||||
VADDUWM A2, B2, A2
|
|
||||||
ADD X5, X0, X0
|
|
||||||
ADD X6, X1, X1
|
|
||||||
VXOR D0, A0, D0
|
|
||||||
VXOR D1, A1, D1
|
|
||||||
ADD X7, X2, X2
|
|
||||||
ADD X4, X3, X3
|
|
||||||
VXOR D2, A2, D2
|
|
||||||
VPERM D0, D0, SIXTEEN, D0
|
|
||||||
XOR X0, X15, X15
|
|
||||||
XOR X1, X12, X12
|
|
||||||
VPERM D1, D1, SIXTEEN, D1
|
|
||||||
VPERM D2, D2, SIXTEEN, D2
|
|
||||||
XOR X2, X13, X13
|
|
||||||
XOR X3, X14, X14
|
|
||||||
VADDUWM C0, D0, C0
|
|
||||||
VADDUWM C1, D1, C1
|
|
||||||
ROTLW $16, X15, X15
|
|
||||||
ROTLW $16, X12, X12
|
|
||||||
VADDUWM C2, D2, C2
|
|
||||||
VXOR B0, C0, T0
|
|
||||||
ROTLW $16, X13, X13
|
|
||||||
ROTLW $16, X14, X14
|
|
||||||
VXOR B1, C1, T1
|
|
||||||
VXOR B2, C2, T2
|
|
||||||
ADD X15, X10, X10
|
|
||||||
ADD X12, X11, X11
|
|
||||||
VRLW T0, TWELVE, B0
|
|
||||||
VRLW T1, TWELVE, B1
|
|
||||||
ADD X13, X8, X8
|
|
||||||
ADD X14, X9, X9
|
|
||||||
VRLW T2, TWELVE, B2
|
|
||||||
VADDUWM A0, B0, A0
|
|
||||||
XOR X10, X5, X5
|
|
||||||
XOR X11, X6, X6
|
|
||||||
VADDUWM A1, B1, A1
|
|
||||||
VADDUWM A2, B2, A2
|
|
||||||
XOR X8, X7, X7
|
|
||||||
XOR X9, X4, X4
|
|
||||||
VXOR D0, A0, D0
|
|
||||||
VXOR D1, A1, D1
|
|
||||||
ROTLW $12, X5, X5
|
|
||||||
ROTLW $12, X6, X6
|
|
||||||
VXOR D2, A2, D2
|
|
||||||
VPERM D0, D0, TWENTY4, D0
|
|
||||||
ROTLW $12, X7, X7
|
|
||||||
ROTLW $12, X4, X4
|
|
||||||
VPERM D1, D1, TWENTY4, D1
|
|
||||||
VPERM D2, D2, TWENTY4, D2
|
|
||||||
ADD X5, X0, X0
|
|
||||||
ADD X6, X1, X1
|
|
||||||
VADDUWM C0, D0, C0
|
|
||||||
VADDUWM C1, D1, C1
|
|
||||||
ADD X7, X2, X2
|
|
||||||
ADD X4, X3, X3
|
|
||||||
VADDUWM C2, D2, C2
|
|
||||||
VXOR B0, C0, T0
|
|
||||||
XOR X0, X15, X15
|
|
||||||
XOR X1, X12, X12
|
|
||||||
VXOR B1, C1, T1
|
|
||||||
VXOR B2, C2, T2
|
|
||||||
XOR X2, X13, X13
|
|
||||||
XOR X3, X14, X14
|
|
||||||
VRLW T0, SEVEN, B0
|
|
||||||
VRLW T1, SEVEN, B1
|
|
||||||
ROTLW $8, X15, X15
|
|
||||||
ROTLW $8, X12, X12
|
|
||||||
VRLW T2, SEVEN, B2
|
|
||||||
VSLDOI $8, C0, C0, C0
|
|
||||||
ROTLW $8, X13, X13
|
|
||||||
ROTLW $8, X14, X14
|
|
||||||
VSLDOI $8, C1, C1, C1
|
|
||||||
VSLDOI $8, C2, C2, C2
|
|
||||||
ADD X15, X10, X10
|
|
||||||
ADD X12, X11, X11
|
|
||||||
VSLDOI $4, B0, B0, B0
|
|
||||||
VSLDOI $4, B1, B1, B1
|
|
||||||
ADD X13, X8, X8
|
|
||||||
ADD X14, X9, X9
|
|
||||||
VSLDOI $4, B2, B2, B2
|
|
||||||
VSLDOI $12, D0, D0, D0
|
|
||||||
XOR X10, X5, X5
|
|
||||||
XOR X11, X6, X6
|
|
||||||
VSLDOI $12, D1, D1, D1
|
|
||||||
VSLDOI $12, D2, D2, D2
|
|
||||||
XOR X8, X7, X7
|
|
||||||
XOR X9, X4, X4
|
|
||||||
ROTLW $7, X5, X5
|
|
||||||
ROTLW $7, X6, X6
|
|
||||||
ROTLW $7, X7, X7
|
|
||||||
ROTLW $7, X4, X4
|
|
||||||
BC 0x10, 0, loop_vmx
|
|
||||||
|
|
||||||
SUB $256, LEN, LEN
|
|
||||||
|
|
||||||
// Accumulate key block
|
|
||||||
ADD $0x61707865, X0, X0
|
|
||||||
ADD $0x3320646e, X1, X1
|
|
||||||
ADD $0x79622d32, X2, X2
|
|
||||||
ADD $0x6b206574, X3, X3
|
|
||||||
ADD TMP0, X4, X4
|
|
||||||
ADD TMP1, X5, X5
|
|
||||||
ADD TMP2, X6, X6
|
|
||||||
ADD TMP3, X7, X7
|
|
||||||
MOVWZ 16(KEY), TMP0
|
|
||||||
MOVWZ 20(KEY), TMP1
|
|
||||||
MOVWZ 24(KEY), TMP2
|
|
||||||
MOVWZ 28(KEY), TMP3
|
|
||||||
ADD TMP0, X8, X8
|
|
||||||
ADD TMP1, X9, X9
|
|
||||||
ADD TMP2, X10, X10
|
|
||||||
ADD TMP3, X11, X11
|
|
||||||
|
|
||||||
MOVWZ 12(CNT), TMP0
|
|
||||||
MOVWZ 8(CNT), TMP1
|
|
||||||
MOVWZ 4(CNT), TMP2
|
|
||||||
MOVWZ 0(CNT), TEMP
|
|
||||||
ADD TMP0, X15, X15
|
|
||||||
ADD TMP1, X14, X14
|
|
||||||
ADD TMP2, X13, X13
|
|
||||||
ADD TEMP, X12, X12
|
|
||||||
|
|
||||||
// Accumulate key block
|
|
||||||
VADDUWM A0, K0, A0
|
|
||||||
VADDUWM A1, K0, A1
|
|
||||||
VADDUWM A2, K0, A2
|
|
||||||
VADDUWM B0, K1, B0
|
|
||||||
VADDUWM B1, K1, B1
|
|
||||||
VADDUWM B2, K1, B2
|
|
||||||
VADDUWM C0, K2, C0
|
|
||||||
VADDUWM C1, K2, C1
|
|
||||||
VADDUWM C2, K2, C2
|
|
||||||
VADDUWM D0, K3, D0
|
|
||||||
VADDUWM D1, K4, D1
|
|
||||||
VADDUWM D2, K5, D2
|
|
||||||
|
|
||||||
// Increment counter
|
|
||||||
ADD $4, TEMP, TEMP
|
|
||||||
MOVW TEMP, 0(CNT)
|
|
||||||
|
|
||||||
VADDUWM K3, FOUR, K3
|
|
||||||
VADDUWM K4, FOUR, K4
|
|
||||||
VADDUWM K5, FOUR, K5
|
|
||||||
|
|
||||||
// XOR the input slice (INP) with the keystream, which is stored in GPRs (X0-X3).
|
|
||||||
|
|
||||||
// Load input (aligned or not)
|
|
||||||
MOVWZ 0(INP), TMP0
|
|
||||||
MOVWZ 4(INP), TMP1
|
|
||||||
MOVWZ 8(INP), TMP2
|
|
||||||
MOVWZ 12(INP), TMP3
|
|
||||||
|
|
||||||
// XOR with input
|
|
||||||
XOR TMP0, X0, X0
|
|
||||||
XOR TMP1, X1, X1
|
|
||||||
XOR TMP2, X2, X2
|
|
||||||
XOR TMP3, X3, X3
|
|
||||||
MOVWZ 16(INP), TMP0
|
|
||||||
MOVWZ 20(INP), TMP1
|
|
||||||
MOVWZ 24(INP), TMP2
|
|
||||||
MOVWZ 28(INP), TMP3
|
|
||||||
XOR TMP0, X4, X4
|
|
||||||
XOR TMP1, X5, X5
|
|
||||||
XOR TMP2, X6, X6
|
|
||||||
XOR TMP3, X7, X7
|
|
||||||
MOVWZ 32(INP), TMP0
|
|
||||||
MOVWZ 36(INP), TMP1
|
|
||||||
MOVWZ 40(INP), TMP2
|
|
||||||
MOVWZ 44(INP), TMP3
|
|
||||||
XOR TMP0, X8, X8
|
|
||||||
XOR TMP1, X9, X9
|
|
||||||
XOR TMP2, X10, X10
|
|
||||||
XOR TMP3, X11, X11
|
|
||||||
MOVWZ 48(INP), TMP0
|
|
||||||
MOVWZ 52(INP), TMP1
|
|
||||||
MOVWZ 56(INP), TMP2
|
|
||||||
MOVWZ 60(INP), TMP3
|
|
||||||
XOR TMP0, X12, X12
|
|
||||||
XOR TMP1, X13, X13
|
|
||||||
XOR TMP2, X14, X14
|
|
||||||
XOR TMP3, X15, X15
|
|
||||||
|
|
||||||
// Store output (aligned or not)
|
|
||||||
MOVW X0, 0(OUT)
|
|
||||||
MOVW X1, 4(OUT)
|
|
||||||
MOVW X2, 8(OUT)
|
|
||||||
MOVW X3, 12(OUT)
|
|
||||||
|
|
||||||
ADD $64, INP, INP // INP points to the end of the slice for the alignment code below
|
|
||||||
|
|
||||||
MOVW X4, 16(OUT)
|
|
||||||
MOVD $16, TMP0
|
|
||||||
MOVW X5, 20(OUT)
|
|
||||||
MOVD $32, TMP1
|
|
||||||
MOVW X6, 24(OUT)
|
|
||||||
MOVD $48, TMP2
|
|
||||||
MOVW X7, 28(OUT)
|
|
||||||
MOVD $64, TMP3
|
|
||||||
MOVW X8, 32(OUT)
|
|
||||||
MOVW X9, 36(OUT)
|
|
||||||
MOVW X10, 40(OUT)
|
|
||||||
MOVW X11, 44(OUT)
|
|
||||||
MOVW X12, 48(OUT)
|
|
||||||
MOVW X13, 52(OUT)
|
|
||||||
MOVW X14, 56(OUT)
|
|
||||||
MOVW X15, 60(OUT)
|
|
||||||
ADD $64, OUT, OUT
|
|
||||||
|
|
||||||
// Load input
|
|
||||||
LVX (INP)(R0), DD0
|
|
||||||
LVX (INP)(TMP0), DD1
|
|
||||||
LVX (INP)(TMP1), DD2
|
|
||||||
LVX (INP)(TMP2), DD3
|
|
||||||
LVX (INP)(TMP3), DD4
|
|
||||||
ADD $64, INP, INP
|
|
||||||
|
|
||||||
VPERM DD1, DD0, INPPERM, DD0 // Align input
|
|
||||||
VPERM DD2, DD1, INPPERM, DD1
|
|
||||||
VPERM DD3, DD2, INPPERM, DD2
|
|
||||||
VPERM DD4, DD3, INPPERM, DD3
|
|
||||||
VXOR A0, DD0, A0 // XOR with input
|
|
||||||
VXOR B0, DD1, B0
|
|
||||||
LVX (INP)(TMP0), DD1 // Keep loading input
|
|
||||||
VXOR C0, DD2, C0
|
|
||||||
LVX (INP)(TMP1), DD2
|
|
||||||
VXOR D0, DD3, D0
|
|
||||||
LVX (INP)(TMP2), DD3
|
|
||||||
LVX (INP)(TMP3), DD0
|
|
||||||
ADD $64, INP, INP
|
|
||||||
MOVD $63, TMP3 // 63 is not a typo
|
|
||||||
VPERM A0, A0, OUTPERM, A0
|
|
||||||
VPERM B0, B0, OUTPERM, B0
|
|
||||||
VPERM C0, C0, OUTPERM, C0
|
|
||||||
VPERM D0, D0, OUTPERM, D0
|
|
||||||
|
|
||||||
VPERM DD1, DD4, INPPERM, DD4 // Align input
|
|
||||||
VPERM DD2, DD1, INPPERM, DD1
|
|
||||||
VPERM DD3, DD2, INPPERM, DD2
|
|
||||||
VPERM DD0, DD3, INPPERM, DD3
|
|
||||||
VXOR A1, DD4, A1
|
|
||||||
VXOR B1, DD1, B1
|
|
||||||
LVX (INP)(TMP0), DD1 // Keep loading
|
|
||||||
VXOR C1, DD2, C1
|
|
||||||
LVX (INP)(TMP1), DD2
|
|
||||||
VXOR D1, DD3, D1
|
|
||||||
LVX (INP)(TMP2), DD3
|
|
||||||
|
|
||||||
// Note that the LVX address is always rounded down to the nearest 16-byte
|
|
||||||
// boundary, and that it always points to at most 15 bytes beyond the end of
|
|
||||||
// the slice, so we cannot cross a page boundary.
|
|
||||||
LVX (INP)(TMP3), DD4 // Redundant in aligned case.
|
|
||||||
ADD $64, INP, INP
|
|
||||||
VPERM A1, A1, OUTPERM, A1 // Pre-misalign output
|
|
||||||
VPERM B1, B1, OUTPERM, B1
|
|
||||||
VPERM C1, C1, OUTPERM, C1
|
|
||||||
VPERM D1, D1, OUTPERM, D1
|
|
||||||
|
|
||||||
VPERM DD1, DD0, INPPERM, DD0 // Align Input
|
|
||||||
VPERM DD2, DD1, INPPERM, DD1
|
|
||||||
VPERM DD3, DD2, INPPERM, DD2
|
|
||||||
VPERM DD4, DD3, INPPERM, DD3
|
|
||||||
VXOR A2, DD0, A2
|
|
||||||
VXOR B2, DD1, B2
|
|
||||||
VXOR C2, DD2, C2
|
|
||||||
VXOR D2, DD3, D2
|
|
||||||
VPERM A2, A2, OUTPERM, A2
|
|
||||||
VPERM B2, B2, OUTPERM, B2
|
|
||||||
VPERM C2, C2, OUTPERM, C2
|
|
||||||
VPERM D2, D2, OUTPERM, D2
|
|
||||||
|
|
||||||
ANDCC $15, OUT, X1 // Is out aligned?
|
|
||||||
MOVD OUT, X0
|
|
||||||
|
|
||||||
VSEL A0, B0, OUTMASK, DD0 // Collect pre-misaligned output
|
|
||||||
VSEL B0, C0, OUTMASK, DD1
|
|
||||||
VSEL C0, D0, OUTMASK, DD2
|
|
||||||
VSEL D0, A1, OUTMASK, DD3
|
|
||||||
VSEL A1, B1, OUTMASK, B0
|
|
||||||
VSEL B1, C1, OUTMASK, C0
|
|
||||||
VSEL C1, D1, OUTMASK, D0
|
|
||||||
VSEL D1, A2, OUTMASK, A1
|
|
||||||
VSEL A2, B2, OUTMASK, B1
|
|
||||||
VSEL B2, C2, OUTMASK, C1
|
|
||||||
VSEL C2, D2, OUTMASK, D1
|
|
||||||
|
|
||||||
STVX DD0, (OUT+TMP0)
|
|
||||||
STVX DD1, (OUT+TMP1)
|
|
||||||
STVX DD2, (OUT+TMP2)
|
|
||||||
ADD $64, OUT, OUT
|
|
||||||
STVX DD3, (OUT+R0)
|
|
||||||
STVX B0, (OUT+TMP0)
|
|
||||||
STVX C0, (OUT+TMP1)
|
|
||||||
STVX D0, (OUT+TMP2)
|
|
||||||
ADD $64, OUT, OUT
|
|
||||||
STVX A1, (OUT+R0)
|
|
||||||
STVX B1, (OUT+TMP0)
|
|
||||||
STVX C1, (OUT+TMP1)
|
|
||||||
STVX D1, (OUT+TMP2)
|
|
||||||
ADD $64, OUT, OUT
|
|
||||||
|
|
||||||
BEQ aligned_vmx
|
|
||||||
|
|
||||||
SUB X1, OUT, X2 // in misaligned case edges
|
|
||||||
MOVD $0, X3 // are written byte-by-byte
|
|
||||||
|
|
||||||
unaligned_tail_vmx:
|
|
||||||
STVEBX D2, (X2+X3)
|
|
||||||
ADD $1, X3, X3
|
|
||||||
CMPW X3, X1
|
|
||||||
BNE unaligned_tail_vmx
|
|
||||||
SUB X1, X0, X2
|
|
||||||
|
|
||||||
unaligned_head_vmx:
|
|
||||||
STVEBX A0, (X2+X1)
|
|
||||||
CMPW X1, $15
|
|
||||||
ADD $1, X1, X1
|
|
||||||
BNE unaligned_head_vmx
|
|
||||||
|
|
||||||
CMPU LEN, $255 // done with 256-byte block yet?
|
|
||||||
BGT loop_outer_vmx
|
|
||||||
|
|
||||||
JMP done_vmx
|
|
||||||
|
|
||||||
aligned_vmx:
|
|
||||||
STVX A0, (X0+R0)
|
|
||||||
CMPU LEN, $255 // done with 256-byte block yet?
|
|
||||||
BGT loop_outer_vmx
|
|
||||||
|
|
||||||
done_vmx:
|
|
||||||
RET
|
|
31
vendor/golang.org/x/crypto/internal/chacha20/chacha_arm64.go
generated
vendored
31
vendor/golang.org/x/crypto/internal/chacha20/chacha_arm64.go
generated
vendored
@ -1,31 +0,0 @@
|
|||||||
// 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 go1.11
|
|
||||||
// +build !gccgo
|
|
||||||
|
|
||||||
package chacha20
|
|
||||||
|
|
||||||
const (
|
|
||||||
haveAsm = true
|
|
||||||
bufSize = 256
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
|
|
||||||
|
|
||||||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
|
||||||
|
|
||||||
if len(src) >= bufSize {
|
|
||||||
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(src)%bufSize != 0 {
|
|
||||||
i := len(src) - len(src)%bufSize
|
|
||||||
c.buf = [bufSize]byte{}
|
|
||||||
copy(c.buf[:], src[i:])
|
|
||||||
xorKeyStreamVX(c.buf[:], c.buf[:], &c.key, &c.nonce, &c.counter)
|
|
||||||
c.len = bufSize - copy(dst[i:], c.buf[:len(src)%bufSize])
|
|
||||||
}
|
|
||||||
}
|
|
264
vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go
generated
vendored
264
vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go
generated
vendored
@ -1,264 +0,0 @@
|
|||||||
// Copyright 2016 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// 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
16
vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
// 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 !ppc64le,!arm64,!s390x arm64,!go1.11 gccgo appengine
|
|
||||||
|
|
||||||
package chacha20
|
|
||||||
|
|
||||||
const (
|
|
||||||
bufSize = 64
|
|
||||||
haveAsm = false
|
|
||||||
)
|
|
||||||
|
|
||||||
func (*Cipher) xorKeyStreamAsm(dst, src []byte) {
|
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
52
vendor/golang.org/x/crypto/internal/chacha20/chacha_ppc64le.go
generated
vendored
52
vendor/golang.org/x/crypto/internal/chacha20/chacha_ppc64le.go
generated
vendored
@ -1,52 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build ppc64le,!gccgo,!appengine
|
|
||||||
|
|
||||||
package chacha20
|
|
||||||
|
|
||||||
import "encoding/binary"
|
|
||||||
|
|
||||||
const (
|
|
||||||
bufSize = 256
|
|
||||||
haveAsm = true
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
|
|
||||||
|
|
||||||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
|
||||||
if len(src) >= bufSize {
|
|
||||||
chaCha20_ctr32_vmx(&dst[0], &src[0], len(src)-len(src)%bufSize, &c.key, &c.counter)
|
|
||||||
}
|
|
||||||
if len(src)%bufSize != 0 {
|
|
||||||
chaCha20_ctr32_vmx(&c.buf[0], &c.buf[0], bufSize, &c.key, &c.counter)
|
|
||||||
start := len(src) - len(src)%bufSize
|
|
||||||
ts, td, tb := src[start:], dst[start:], c.buf[:]
|
|
||||||
// Unroll loop to XOR 32 bytes per iteration.
|
|
||||||
for i := 0; i < len(ts)-32; i += 32 {
|
|
||||||
td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination
|
|
||||||
s0 := binary.LittleEndian.Uint64(ts[0:8])
|
|
||||||
s1 := binary.LittleEndian.Uint64(ts[8:16])
|
|
||||||
s2 := binary.LittleEndian.Uint64(ts[16:24])
|
|
||||||
s3 := binary.LittleEndian.Uint64(ts[24:32])
|
|
||||||
b0 := binary.LittleEndian.Uint64(tb[0:8])
|
|
||||||
b1 := binary.LittleEndian.Uint64(tb[8:16])
|
|
||||||
b2 := binary.LittleEndian.Uint64(tb[16:24])
|
|
||||||
b3 := binary.LittleEndian.Uint64(tb[24:32])
|
|
||||||
binary.LittleEndian.PutUint64(td[0:8], s0^b0)
|
|
||||||
binary.LittleEndian.PutUint64(td[8:16], s1^b1)
|
|
||||||
binary.LittleEndian.PutUint64(td[16:24], s2^b2)
|
|
||||||
binary.LittleEndian.PutUint64(td[24:32], s3^b3)
|
|
||||||
ts, td, tb = ts[32:], td[32:], tb[32:]
|
|
||||||
}
|
|
||||||
td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination
|
|
||||||
for i, v := range ts {
|
|
||||||
td[i] = tb[i] ^ v
|
|
||||||
}
|
|
||||||
c.len = bufSize - (len(src) % bufSize)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
29
vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go
generated
vendored
29
vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go
generated
vendored
@ -1,29 +0,0 @@
|
|||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/sys/cpu"
|
|
||||||
)
|
|
||||||
|
|
||||||
var haveAsm = cpu.S390X.HasVX
|
|
||||||
|
|
||||||
const bufSize = 256
|
|
||||||
|
|
||||||
// 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()
|
|
260
vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s
generated
vendored
260
vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s
generated
vendored
@ -1,260 +0,0 @@
|
|||||||
// 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
|
|
43
vendor/golang.org/x/crypto/internal/chacha20/xor.go
generated
vendored
43
vendor/golang.org/x/crypto/internal/chacha20/xor.go
generated
vendored
@ -1,43 +0,0 @@
|
|||||||
// 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
32
vendor/golang.org/x/crypto/internal/subtle/aliasing.go
generated
vendored
@ -1,32 +0,0 @@
|
|||||||
// 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
35
vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go
generated
vendored
@ -1,35 +0,0 @@
|
|||||||
// 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)
|
|
||||||
}
|
|
11
vendor/golang.org/x/crypto/poly1305/mac_noasm.go
generated
vendored
11
vendor/golang.org/x/crypto/poly1305/mac_noasm.go
generated
vendored
@ -1,11 +0,0 @@
|
|||||||
// 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 !amd64,!ppc64le gccgo appengine
|
|
||||||
|
|
||||||
package poly1305
|
|
||||||
|
|
||||||
type mac struct{ macGeneric }
|
|
||||||
|
|
||||||
func newMAC(key *[32]byte) mac { return mac{newMACGeneric(key)} }
|
|
83
vendor/golang.org/x/crypto/poly1305/poly1305.go
generated
vendored
83
vendor/golang.org/x/crypto/poly1305/poly1305.go
generated
vendored
@ -1,83 +0,0 @@
|
|||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a new MAC computing an authentication
|
|
||||||
// tag of all data written to it with the given key.
|
|
||||||
// This allows writing the message progressively instead
|
|
||||||
// of passing it as a single slice. Common users should use
|
|
||||||
// the Sum function instead.
|
|
||||||
//
|
|
||||||
// The key must be unique for each message, as authenticating
|
|
||||||
// two different messages with the same key allows an attacker
|
|
||||||
// to forge messages at will.
|
|
||||||
func New(key *[32]byte) *MAC {
|
|
||||||
return &MAC{
|
|
||||||
mac: newMAC(key),
|
|
||||||
finalized: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MAC is an io.Writer computing an authentication tag
|
|
||||||
// of the data written to it.
|
|
||||||
//
|
|
||||||
// MAC cannot be used like common hash.Hash implementations,
|
|
||||||
// because using a poly1305 key twice breaks its security.
|
|
||||||
// Therefore writing data to a running MAC after calling
|
|
||||||
// Sum causes it to panic.
|
|
||||||
type MAC struct {
|
|
||||||
mac // platform-dependent implementation
|
|
||||||
|
|
||||||
finalized bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size returns the number of bytes Sum will return.
|
|
||||||
func (h *MAC) Size() int { return TagSize }
|
|
||||||
|
|
||||||
// Write adds more data to the running message authentication code.
|
|
||||||
// It never returns an error.
|
|
||||||
//
|
|
||||||
// It must not be called after the first call of Sum.
|
|
||||||
func (h *MAC) Write(p []byte) (n int, err error) {
|
|
||||||
if h.finalized {
|
|
||||||
panic("poly1305: write to MAC after Sum")
|
|
||||||
}
|
|
||||||
return h.mac.Write(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sum computes the authenticator of all data written to the
|
|
||||||
// message authentication code.
|
|
||||||
func (h *MAC) Sum(b []byte) []byte {
|
|
||||||
var mac [TagSize]byte
|
|
||||||
h.mac.Sum(&mac)
|
|
||||||
h.finalized = true
|
|
||||||
return append(b, mac[:]...)
|
|
||||||
}
|
|
68
vendor/golang.org/x/crypto/poly1305/sum_amd64.go
generated
vendored
68
vendor/golang.org/x/crypto/poly1305/sum_amd64.go
generated
vendored
@ -1,68 +0,0 @@
|
|||||||
// 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
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func initialize(state *[7]uint64, key *[32]byte)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func update(state *[7]uint64, msg []byte)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func finalize(tag *[TagSize]byte, state *[7]uint64)
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
h := newMAC(key)
|
|
||||||
h.Write(m)
|
|
||||||
h.Sum(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMAC(key *[32]byte) (h mac) {
|
|
||||||
initialize(&h.state, key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type mac struct {
|
|
||||||
state [7]uint64 // := uint64{ h0, h1, h2, r0, r1, pad0, pad1 }
|
|
||||||
|
|
||||||
buffer [TagSize]byte
|
|
||||||
offset int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *mac) Write(p []byte) (n int, err error) {
|
|
||||||
n = len(p)
|
|
||||||
if h.offset > 0 {
|
|
||||||
remaining := TagSize - h.offset
|
|
||||||
if n < remaining {
|
|
||||||
h.offset += copy(h.buffer[h.offset:], p)
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
copy(h.buffer[h.offset:], p[:remaining])
|
|
||||||
p = p[remaining:]
|
|
||||||
h.offset = 0
|
|
||||||
update(&h.state, h.buffer[:])
|
|
||||||
}
|
|
||||||
if nn := len(p) - (len(p) % TagSize); nn > 0 {
|
|
||||||
update(&h.state, p[:nn])
|
|
||||||
p = p[nn:]
|
|
||||||
}
|
|
||||||
if len(p) > 0 {
|
|
||||||
h.offset += copy(h.buffer[h.offset:], p)
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *mac) Sum(out *[16]byte) {
|
|
||||||
state := h.state
|
|
||||||
if h.offset > 0 {
|
|
||||||
update(&state, h.buffer[:h.offset])
|
|
||||||
}
|
|
||||||
finalize(out, &state)
|
|
||||||
}
|
|
148
vendor/golang.org/x/crypto/poly1305/sum_amd64.s
generated
vendored
148
vendor/golang.org/x/crypto/poly1305/sum_amd64.s
generated
vendored
@ -1,148 +0,0 @@
|
|||||||
// 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 update(state *[7]uint64, msg []byte)
|
|
||||||
TEXT ·update(SB), $0-32
|
|
||||||
MOVQ state+0(FP), DI
|
|
||||||
MOVQ msg_base+8(FP), SI
|
|
||||||
MOVQ msg_len+16(FP), R15
|
|
||||||
|
|
||||||
MOVQ 0(DI), R8 // h0
|
|
||||||
MOVQ 8(DI), R9 // h1
|
|
||||||
MOVQ 16(DI), R10 // h2
|
|
||||||
MOVQ 24(DI), R11 // r0
|
|
||||||
MOVQ 32(DI), R12 // r1
|
|
||||||
|
|
||||||
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, 0(DI)
|
|
||||||
MOVQ R9, 8(DI)
|
|
||||||
MOVQ R10, 16(DI)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func initialize(state *[7]uint64, key *[32]byte)
|
|
||||||
TEXT ·initialize(SB), $0-16
|
|
||||||
MOVQ state+0(FP), DI
|
|
||||||
MOVQ key+8(FP), SI
|
|
||||||
|
|
||||||
// state[0...7] is initialized with zero
|
|
||||||
MOVOU 0(SI), X0
|
|
||||||
MOVOU 16(SI), X1
|
|
||||||
MOVOU ·poly1305Mask<>(SB), X2
|
|
||||||
PAND X2, X0
|
|
||||||
MOVOU X0, 24(DI)
|
|
||||||
MOVOU X1, 40(DI)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func finalize(tag *[TagSize]byte, state *[7]uint64)
|
|
||||||
TEXT ·finalize(SB), $0-16
|
|
||||||
MOVQ tag+0(FP), DI
|
|
||||||
MOVQ state+8(FP), SI
|
|
||||||
|
|
||||||
MOVQ 0(SI), AX
|
|
||||||
MOVQ 8(SI), BX
|
|
||||||
MOVQ 16(SI), CX
|
|
||||||
MOVQ AX, R8
|
|
||||||
MOVQ BX, R9
|
|
||||||
SUBQ $0xFFFFFFFFFFFFFFFB, AX
|
|
||||||
SBBQ $0xFFFFFFFFFFFFFFFF, BX
|
|
||||||
SBBQ $3, CX
|
|
||||||
CMOVQCS R8, AX
|
|
||||||
CMOVQCS R9, BX
|
|
||||||
ADDQ 40(SI), AX
|
|
||||||
ADCQ 48(SI), BX
|
|
||||||
|
|
||||||
MOVQ AX, 0(DI)
|
|
||||||
MOVQ BX, 8(DI)
|
|
||||||
RET
|
|
22
vendor/golang.org/x/crypto/poly1305/sum_arm.go
generated
vendored
22
vendor/golang.org/x/crypto/poly1305/sum_arm.go
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
// 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
427
vendor/golang.org/x/crypto/poly1305/sum_arm.s
generated
vendored
@ -1,427 +0,0 @@
|
|||||||
// 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
|
|
172
vendor/golang.org/x/crypto/poly1305/sum_generic.go
generated
vendored
172
vendor/golang.org/x/crypto/poly1305/sum_generic.go
generated
vendored
@ -1,172 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
package poly1305
|
|
||||||
|
|
||||||
import "encoding/binary"
|
|
||||||
|
|
||||||
const (
|
|
||||||
msgBlock = uint32(1 << 24)
|
|
||||||
finalBlock = uint32(0)
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
h := newMACGeneric(key)
|
|
||||||
h.Write(msg)
|
|
||||||
h.Sum(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMACGeneric(key *[32]byte) (h macGeneric) {
|
|
||||||
h.r[0] = binary.LittleEndian.Uint32(key[0:]) & 0x3ffffff
|
|
||||||
h.r[1] = (binary.LittleEndian.Uint32(key[3:]) >> 2) & 0x3ffff03
|
|
||||||
h.r[2] = (binary.LittleEndian.Uint32(key[6:]) >> 4) & 0x3ffc0ff
|
|
||||||
h.r[3] = (binary.LittleEndian.Uint32(key[9:]) >> 6) & 0x3f03fff
|
|
||||||
h.r[4] = (binary.LittleEndian.Uint32(key[12:]) >> 8) & 0x00fffff
|
|
||||||
|
|
||||||
h.s[0] = binary.LittleEndian.Uint32(key[16:])
|
|
||||||
h.s[1] = binary.LittleEndian.Uint32(key[20:])
|
|
||||||
h.s[2] = binary.LittleEndian.Uint32(key[24:])
|
|
||||||
h.s[3] = binary.LittleEndian.Uint32(key[28:])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type macGeneric struct {
|
|
||||||
h, r [5]uint32
|
|
||||||
s [4]uint32
|
|
||||||
|
|
||||||
buffer [TagSize]byte
|
|
||||||
offset int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *macGeneric) Write(p []byte) (n int, err error) {
|
|
||||||
n = len(p)
|
|
||||||
if h.offset > 0 {
|
|
||||||
remaining := TagSize - h.offset
|
|
||||||
if n < remaining {
|
|
||||||
h.offset += copy(h.buffer[h.offset:], p)
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
copy(h.buffer[h.offset:], p[:remaining])
|
|
||||||
p = p[remaining:]
|
|
||||||
h.offset = 0
|
|
||||||
updateGeneric(h.buffer[:], msgBlock, &(h.h), &(h.r))
|
|
||||||
}
|
|
||||||
if nn := len(p) - (len(p) % TagSize); nn > 0 {
|
|
||||||
updateGeneric(p, msgBlock, &(h.h), &(h.r))
|
|
||||||
p = p[nn:]
|
|
||||||
}
|
|
||||||
if len(p) > 0 {
|
|
||||||
h.offset += copy(h.buffer[h.offset:], p)
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *macGeneric) Sum(out *[16]byte) {
|
|
||||||
H, R := h.h, h.r
|
|
||||||
if h.offset > 0 {
|
|
||||||
var buffer [TagSize]byte
|
|
||||||
copy(buffer[:], h.buffer[:h.offset])
|
|
||||||
buffer[h.offset] = 1 // invariant: h.offset < TagSize
|
|
||||||
updateGeneric(buffer[:], finalBlock, &H, &R)
|
|
||||||
}
|
|
||||||
finalizeGeneric(out, &H, &(h.s))
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateGeneric(msg []byte, flag uint32, h, r *[5]uint32) {
|
|
||||||
h0, h1, h2, h3, h4 := h[0], h[1], h[2], h[3], h[4]
|
|
||||||
r0, r1, r2, r3, r4 := uint64(r[0]), uint64(r[1]), uint64(r[2]), uint64(r[3]), uint64(r[4])
|
|
||||||
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) | flag
|
|
||||||
|
|
||||||
// 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:]
|
|
||||||
}
|
|
||||||
|
|
||||||
h[0], h[1], h[2], h[3], h[4] = h0, h1, h2, h3, h4
|
|
||||||
}
|
|
||||||
|
|
||||||
func finalizeGeneric(out *[TagSize]byte, h *[5]uint32, s *[4]uint32) {
|
|
||||||
h0, h1, h2, h3, h4 := h[0], h[1], h[2], h[3], h[4]
|
|
||||||
|
|
||||||
// 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(s[0])
|
|
||||||
h0 = uint32(t)
|
|
||||||
t = uint64(h1) + uint64(s[1]) + (t >> 32)
|
|
||||||
h1 = uint32(t)
|
|
||||||
t = uint64(h2) + uint64(s[2]) + (t >> 32)
|
|
||||||
h2 = uint32(t)
|
|
||||||
t = uint64(h3) + uint64(s[3]) + (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)
|
|
||||||
}
|
|
16
vendor/golang.org/x/crypto/poly1305/sum_noasm.go
generated
vendored
16
vendor/golang.org/x/crypto/poly1305/sum_noasm.go
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
// 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,!ppc64le 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) {
|
|
||||||
h := newMAC(key)
|
|
||||||
h.Write(msg)
|
|
||||||
h.Sum(out)
|
|
||||||
}
|
|
68
vendor/golang.org/x/crypto/poly1305/sum_ppc64le.go
generated
vendored
68
vendor/golang.org/x/crypto/poly1305/sum_ppc64le.go
generated
vendored
@ -1,68 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build ppc64le,!gccgo,!appengine
|
|
||||||
|
|
||||||
package poly1305
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func initialize(state *[7]uint64, key *[32]byte)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func update(state *[7]uint64, msg []byte)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func finalize(tag *[TagSize]byte, state *[7]uint64)
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
h := newMAC(key)
|
|
||||||
h.Write(m)
|
|
||||||
h.Sum(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMAC(key *[32]byte) (h mac) {
|
|
||||||
initialize(&h.state, key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type mac struct {
|
|
||||||
state [7]uint64 // := uint64{ h0, h1, h2, r0, r1, pad0, pad1 }
|
|
||||||
|
|
||||||
buffer [TagSize]byte
|
|
||||||
offset int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *mac) Write(p []byte) (n int, err error) {
|
|
||||||
n = len(p)
|
|
||||||
if h.offset > 0 {
|
|
||||||
remaining := TagSize - h.offset
|
|
||||||
if n < remaining {
|
|
||||||
h.offset += copy(h.buffer[h.offset:], p)
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
copy(h.buffer[h.offset:], p[:remaining])
|
|
||||||
p = p[remaining:]
|
|
||||||
h.offset = 0
|
|
||||||
update(&h.state, h.buffer[:])
|
|
||||||
}
|
|
||||||
if nn := len(p) - (len(p) % TagSize); nn > 0 {
|
|
||||||
update(&h.state, p[:nn])
|
|
||||||
p = p[nn:]
|
|
||||||
}
|
|
||||||
if len(p) > 0 {
|
|
||||||
h.offset += copy(h.buffer[h.offset:], p)
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *mac) Sum(out *[16]byte) {
|
|
||||||
state := h.state
|
|
||||||
if h.offset > 0 {
|
|
||||||
update(&state, h.buffer[:h.offset])
|
|
||||||
}
|
|
||||||
finalize(out, &state)
|
|
||||||
}
|
|
247
vendor/golang.org/x/crypto/poly1305/sum_ppc64le.s
generated
vendored
247
vendor/golang.org/x/crypto/poly1305/sum_ppc64le.s
generated
vendored
@ -1,247 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build ppc64le,!gccgo,!appengine
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// This was ported from the amd64 implementation.
|
|
||||||
|
|
||||||
#define POLY1305_ADD(msg, h0, h1, h2, t0, t1, t2) \
|
|
||||||
MOVD (msg), t0; \
|
|
||||||
MOVD 8(msg), t1; \
|
|
||||||
MOVD $1, t2; \
|
|
||||||
ADDC t0, h0, h0; \
|
|
||||||
ADDE t1, h1, h1; \
|
|
||||||
ADDE t2, h2; \
|
|
||||||
ADD $16, msg
|
|
||||||
|
|
||||||
#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3, t4, t5) \
|
|
||||||
MULLD r0, h0, t0; \
|
|
||||||
MULLD r0, h1, t4; \
|
|
||||||
MULHDU r0, h0, t1; \
|
|
||||||
MULHDU r0, h1, t5; \
|
|
||||||
ADDC t4, t1, t1; \
|
|
||||||
MULLD r0, h2, t2; \
|
|
||||||
ADDZE t5; \
|
|
||||||
MULHDU r1, h0, t4; \
|
|
||||||
MULLD r1, h0, h0; \
|
|
||||||
ADD t5, t2, t2; \
|
|
||||||
ADDC h0, t1, t1; \
|
|
||||||
MULLD h2, r1, t3; \
|
|
||||||
ADDZE t4, h0; \
|
|
||||||
MULHDU r1, h1, t5; \
|
|
||||||
MULLD r1, h1, t4; \
|
|
||||||
ADDC t4, t2, t2; \
|
|
||||||
ADDE t5, t3, t3; \
|
|
||||||
ADDC h0, t2, t2; \
|
|
||||||
MOVD $-4, t4; \
|
|
||||||
MOVD t0, h0; \
|
|
||||||
MOVD t1, h1; \
|
|
||||||
ADDZE t3; \
|
|
||||||
ANDCC $3, t2, h2; \
|
|
||||||
AND t2, t4, t0; \
|
|
||||||
ADDC t0, h0, h0; \
|
|
||||||
ADDE t3, h1, h1; \
|
|
||||||
SLD $62, t3, t4; \
|
|
||||||
SRD $2, t2; \
|
|
||||||
ADDZE h2; \
|
|
||||||
OR t4, t2, t2; \
|
|
||||||
SRD $2, t3; \
|
|
||||||
ADDC t2, h0, h0; \
|
|
||||||
ADDE t3, h1, h1; \
|
|
||||||
ADDZE h2
|
|
||||||
|
|
||||||
DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
|
|
||||||
DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
|
|
||||||
GLOBL ·poly1305Mask<>(SB), RODATA, $16
|
|
||||||
|
|
||||||
// func update(state *[7]uint64, msg []byte)
|
|
||||||
|
|
||||||
TEXT ·update(SB), $0-32
|
|
||||||
MOVD state+0(FP), R3
|
|
||||||
MOVD msg_base+8(FP), R4
|
|
||||||
MOVD msg_len+16(FP), R5
|
|
||||||
|
|
||||||
MOVD 0(R3), R8 // h0
|
|
||||||
MOVD 8(R3), R9 // h1
|
|
||||||
MOVD 16(R3), R10 // h2
|
|
||||||
MOVD 24(R3), R11 // r0
|
|
||||||
MOVD 32(R3), R12 // r1
|
|
||||||
|
|
||||||
CMP R5, $16
|
|
||||||
BLT bytes_between_0_and_15
|
|
||||||
|
|
||||||
loop:
|
|
||||||
POLY1305_ADD(R4, R8, R9, R10, R20, R21, R22)
|
|
||||||
|
|
||||||
multiply:
|
|
||||||
POLY1305_MUL(R8, R9, R10, R11, R12, R16, R17, R18, R14, R20, R21)
|
|
||||||
ADD $-16, R5
|
|
||||||
CMP R5, $16
|
|
||||||
BGE loop
|
|
||||||
|
|
||||||
bytes_between_0_and_15:
|
|
||||||
CMP $0, R5
|
|
||||||
BEQ done
|
|
||||||
MOVD $0, R16 // h0
|
|
||||||
MOVD $0, R17 // h1
|
|
||||||
|
|
||||||
flush_buffer:
|
|
||||||
CMP R5, $8
|
|
||||||
BLE just1
|
|
||||||
|
|
||||||
MOVD $8, R21
|
|
||||||
SUB R21, R5, R21
|
|
||||||
|
|
||||||
// Greater than 8 -- load the rightmost remaining bytes in msg
|
|
||||||
// and put into R17 (h1)
|
|
||||||
MOVD (R4)(R21), R17
|
|
||||||
MOVD $16, R22
|
|
||||||
|
|
||||||
// Find the offset to those bytes
|
|
||||||
SUB R5, R22, R22
|
|
||||||
SLD $3, R22
|
|
||||||
|
|
||||||
// Shift to get only the bytes in msg
|
|
||||||
SRD R22, R17, R17
|
|
||||||
|
|
||||||
// Put 1 at high end
|
|
||||||
MOVD $1, R23
|
|
||||||
SLD $3, R21
|
|
||||||
SLD R21, R23, R23
|
|
||||||
OR R23, R17, R17
|
|
||||||
|
|
||||||
// Remainder is 8
|
|
||||||
MOVD $8, R5
|
|
||||||
|
|
||||||
just1:
|
|
||||||
CMP R5, $8
|
|
||||||
BLT less8
|
|
||||||
|
|
||||||
// Exactly 8
|
|
||||||
MOVD (R4), R16
|
|
||||||
|
|
||||||
CMP $0, R17
|
|
||||||
|
|
||||||
// Check if we've already set R17; if not
|
|
||||||
// set 1 to indicate end of msg.
|
|
||||||
BNE carry
|
|
||||||
MOVD $1, R17
|
|
||||||
BR carry
|
|
||||||
|
|
||||||
less8:
|
|
||||||
MOVD $0, R16 // h0
|
|
||||||
MOVD $0, R22 // shift count
|
|
||||||
CMP R5, $4
|
|
||||||
BLT less4
|
|
||||||
MOVWZ (R4), R16
|
|
||||||
ADD $4, R4
|
|
||||||
ADD $-4, R5
|
|
||||||
MOVD $32, R22
|
|
||||||
|
|
||||||
less4:
|
|
||||||
CMP R5, $2
|
|
||||||
BLT less2
|
|
||||||
MOVHZ (R4), R21
|
|
||||||
SLD R22, R21, R21
|
|
||||||
OR R16, R21, R16
|
|
||||||
ADD $16, R22
|
|
||||||
ADD $-2, R5
|
|
||||||
ADD $2, R4
|
|
||||||
|
|
||||||
less2:
|
|
||||||
CMP $0, R5
|
|
||||||
BEQ insert1
|
|
||||||
MOVBZ (R4), R21
|
|
||||||
SLD R22, R21, R21
|
|
||||||
OR R16, R21, R16
|
|
||||||
ADD $8, R22
|
|
||||||
|
|
||||||
insert1:
|
|
||||||
// Insert 1 at end of msg
|
|
||||||
MOVD $1, R21
|
|
||||||
SLD R22, R21, R21
|
|
||||||
OR R16, R21, R16
|
|
||||||
|
|
||||||
carry:
|
|
||||||
// Add new values to h0, h1, h2
|
|
||||||
ADDC R16, R8
|
|
||||||
ADDE R17, R9
|
|
||||||
ADDE $0, R10
|
|
||||||
MOVD $16, R5
|
|
||||||
ADD R5, R4
|
|
||||||
BR multiply
|
|
||||||
|
|
||||||
done:
|
|
||||||
// Save h0, h1, h2 in state
|
|
||||||
MOVD R8, 0(R3)
|
|
||||||
MOVD R9, 8(R3)
|
|
||||||
MOVD R10, 16(R3)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func initialize(state *[7]uint64, key *[32]byte)
|
|
||||||
TEXT ·initialize(SB), $0-16
|
|
||||||
MOVD state+0(FP), R3
|
|
||||||
MOVD key+8(FP), R4
|
|
||||||
|
|
||||||
// state[0...7] is initialized with zero
|
|
||||||
// Load key
|
|
||||||
MOVD 0(R4), R5
|
|
||||||
MOVD 8(R4), R6
|
|
||||||
MOVD 16(R4), R7
|
|
||||||
MOVD 24(R4), R8
|
|
||||||
|
|
||||||
// Address of key mask
|
|
||||||
MOVD $·poly1305Mask<>(SB), R9
|
|
||||||
|
|
||||||
// Save original key in state
|
|
||||||
MOVD R7, 40(R3)
|
|
||||||
MOVD R8, 48(R3)
|
|
||||||
|
|
||||||
// Get mask
|
|
||||||
MOVD (R9), R7
|
|
||||||
MOVD 8(R9), R8
|
|
||||||
|
|
||||||
// And with key
|
|
||||||
AND R5, R7, R5
|
|
||||||
AND R6, R8, R6
|
|
||||||
|
|
||||||
// Save masked key in state
|
|
||||||
MOVD R5, 24(R3)
|
|
||||||
MOVD R6, 32(R3)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func finalize(tag *[TagSize]byte, state *[7]uint64)
|
|
||||||
TEXT ·finalize(SB), $0-16
|
|
||||||
MOVD tag+0(FP), R3
|
|
||||||
MOVD state+8(FP), R4
|
|
||||||
|
|
||||||
// Get h0, h1, h2 from state
|
|
||||||
MOVD 0(R4), R5
|
|
||||||
MOVD 8(R4), R6
|
|
||||||
MOVD 16(R4), R7
|
|
||||||
|
|
||||||
// Save h0, h1
|
|
||||||
MOVD R5, R8
|
|
||||||
MOVD R6, R9
|
|
||||||
MOVD $3, R20
|
|
||||||
MOVD $-1, R21
|
|
||||||
SUBC $-5, R5
|
|
||||||
SUBE R21, R6
|
|
||||||
SUBE R20, R7
|
|
||||||
MOVD $0, R21
|
|
||||||
SUBZE R21
|
|
||||||
|
|
||||||
// Check for carry
|
|
||||||
CMP $0, R21
|
|
||||||
ISEL $2, R5, R8, R5
|
|
||||||
ISEL $2, R6, R9, R6
|
|
||||||
MOVD 40(R4), R8
|
|
||||||
MOVD 48(R4), R9
|
|
||||||
ADDC R8, R5
|
|
||||||
ADDE R9, R6
|
|
||||||
MOVD R5, 0(R3)
|
|
||||||
MOVD R6, 8(R3)
|
|
||||||
RET
|
|
42
vendor/golang.org/x/crypto/poly1305/sum_s390x.go
generated
vendored
42
vendor/golang.org/x/crypto/poly1305/sum_s390x.go
generated
vendored
@ -1,42 +0,0 @@
|
|||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/sys/cpu"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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 cpu.S390X.HasVX {
|
|
||||||
var mPtr *byte
|
|
||||||
if len(m) > 0 {
|
|
||||||
mPtr = &m[0]
|
|
||||||
}
|
|
||||||
if cpu.S390X.HasVXE && len(m) > 256 {
|
|
||||||
poly1305vmsl(out, mPtr, uint64(len(m)), key)
|
|
||||||
} else {
|
|
||||||
poly1305vx(out, mPtr, uint64(len(m)), key)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sumGeneric(out, m, key)
|
|
||||||
}
|
|
||||||
}
|
|
378
vendor/golang.org/x/crypto/poly1305/sum_s390x.s
generated
vendored
378
vendor/golang.org/x/crypto/poly1305/sum_s390x.s
generated
vendored
@ -1,378 +0,0 @@
|
|||||||
// 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
|
|
909
vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s
generated
vendored
909
vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s
generated
vendored
@ -1,909 +0,0 @@
|
|||||||
// 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
|
|
97
vendor/golang.org/x/crypto/ssh/buffer.go
generated
vendored
97
vendor/golang.org/x/crypto/ssh/buffer.go
generated
vendored
@ -1,97 +0,0 @@
|
|||||||
// 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
535
vendor/golang.org/x/crypto/ssh/certs.go
generated
vendored
@ -1,535 +0,0 @@
|
|||||||
// 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
633
vendor/golang.org/x/crypto/ssh/channel.go
generated
vendored
@ -1,633 +0,0 @@
|
|||||||
// 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
770
vendor/golang.org/x/crypto/ssh/cipher.go
generated
vendored
@ -1,770 +0,0 @@
|
|||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// readCipherPacket reads and decrypt a single packet from the reader argument.
|
|
||||||
func (s *streamPacketCipher) readCipherPacket(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
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeCipherPacket encrypts and sends a packet of data to the writer argument
|
|
||||||
func (s *streamPacketCipher) writeCipherPacket(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) writeCipherPacket(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) readCipherPacket(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) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
|
|
||||||
p, err := c.readCipherPacketLeaky(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) readCipherPacketLeaky(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) writeCipherPacket(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) readCipherPacket(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) writeCipherPacket(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
278
vendor/golang.org/x/crypto/ssh/client.go
generated
vendored
@ -1,278 +0,0 @@
|
|||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
|
639
vendor/golang.org/x/crypto/ssh/client_auth.go
generated
vendored
639
vendor/golang.org/x/crypto/ssh/client_auth.go
generated
vendored
@ -1,639 +0,0 @@
|
|||||||
// 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}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GSSAPIWithMICAuthMethod is an AuthMethod with "gssapi-with-mic" authentication.
|
|
||||||
// See RFC 4462 section 3
|
|
||||||
// gssAPIClient is implementation of the GSSAPIClient interface, see the definition of the interface for details.
|
|
||||||
// target is the server host you want to log in to.
|
|
||||||
func GSSAPIWithMICAuthMethod(gssAPIClient GSSAPIClient, target string) AuthMethod {
|
|
||||||
if gssAPIClient == nil {
|
|
||||||
panic("gss-api client must be not nil with enable gssapi-with-mic")
|
|
||||||
}
|
|
||||||
return &gssAPIWithMICCallback{gssAPIClient: gssAPIClient, target: target}
|
|
||||||
}
|
|
||||||
|
|
||||||
type gssAPIWithMICCallback struct {
|
|
||||||
gssAPIClient GSSAPIClient
|
|
||||||
target string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *gssAPIWithMICCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) {
|
|
||||||
m := &userAuthRequestMsg{
|
|
||||||
User: user,
|
|
||||||
Service: serviceSSH,
|
|
||||||
Method: g.method(),
|
|
||||||
}
|
|
||||||
// The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST.
|
|
||||||
// See RFC 4462 section 3.2.
|
|
||||||
m.Payload = appendU32(m.Payload, 1)
|
|
||||||
m.Payload = appendString(m.Payload, string(krb5OID))
|
|
||||||
if err := c.writePacket(Marshal(m)); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
// The server responds to the SSH_MSG_USERAUTH_REQUEST with either an
|
|
||||||
// SSH_MSG_USERAUTH_FAILURE if none of the mechanisms are supported or
|
|
||||||
// with an SSH_MSG_USERAUTH_GSSAPI_RESPONSE.
|
|
||||||
// See RFC 4462 section 3.3.
|
|
||||||
// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,so I don't want to check
|
|
||||||
// selected mech if it is valid.
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
userAuthGSSAPIResp := &userAuthGSSAPIResponse{}
|
|
||||||
if err := Unmarshal(packet, userAuthGSSAPIResp); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
// Start the loop into the exchange token.
|
|
||||||
// See RFC 4462 section 3.4.
|
|
||||||
var token []byte
|
|
||||||
defer g.gssAPIClient.DeleteSecContext()
|
|
||||||
for {
|
|
||||||
// Initiates the establishment of a security context between the application and a remote peer.
|
|
||||||
nextToken, needContinue, err := g.gssAPIClient.InitSecContext("host@"+g.target, token, false)
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
if len(nextToken) > 0 {
|
|
||||||
if err := c.writePacket(Marshal(&userAuthGSSAPIToken{
|
|
||||||
Token: nextToken,
|
|
||||||
})); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !needContinue {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
packet, err = c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
switch packet[0] {
|
|
||||||
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 msgUserAuthGSSAPIError:
|
|
||||||
userAuthGSSAPIErrorResp := &userAuthGSSAPIError{}
|
|
||||||
if err := Unmarshal(packet, userAuthGSSAPIErrorResp); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
return authFailure, nil, fmt.Errorf("GSS-API Error:\n"+
|
|
||||||
"Major Status: %d\n"+
|
|
||||||
"Minor Status: %d\n"+
|
|
||||||
"Error Message: %s\n", userAuthGSSAPIErrorResp.MajorStatus, userAuthGSSAPIErrorResp.MinorStatus,
|
|
||||||
userAuthGSSAPIErrorResp.Message)
|
|
||||||
case msgUserAuthGSSAPIToken:
|
|
||||||
userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
|
|
||||||
if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
token = userAuthGSSAPITokenReq.Token
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Binding Encryption Keys.
|
|
||||||
// See RFC 4462 section 3.5.
|
|
||||||
micField := buildMIC(string(session), user, "ssh-connection", "gssapi-with-mic")
|
|
||||||
micToken, err := g.gssAPIClient.GetMIC(micField)
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
if err := c.writePacket(Marshal(&userAuthGSSAPIMIC{
|
|
||||||
MIC: micToken,
|
|
||||||
})); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
return handleAuthResponse(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *gssAPIWithMICCallback) method() string {
|
|
||||||
return "gssapi-with-mic"
|
|
||||||
}
|
|
396
vendor/golang.org/x/crypto/ssh/common.go
generated
vendored
396
vendor/golang.org/x/crypto/ssh/common.go
generated
vendored
@ -1,396 +0,0 @@
|
|||||||
// 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,
|
|
||||||
}
|
|
||||||
|
|
||||||
// serverForbiddenKexAlgos contains key exchange algorithms, that are forbidden
|
|
||||||
// for the server half.
|
|
||||||
var serverForbiddenKexAlgos = map[string]struct{}{
|
|
||||||
kexAlgoDHGEXSHA1: {}, // server half implementation is only minimal to satisfy the automated tests
|
|
||||||
kexAlgoDHGEXSHA256: {}, // server half implementation is only minimal to satisfy the automated tests
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// directionAlgorithms records algorithm choices in one direction (either read or write)
|
|
||||||
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(isClient bool, 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
|
|
||||||
}
|
|
||||||
|
|
||||||
stoc, ctos := &result.w, &result.r
|
|
||||||
if isClient {
|
|
||||||
ctos, stoc = stoc, ctos
|
|
||||||
}
|
|
||||||
|
|
||||||
ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctos.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stoc.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
143
vendor/golang.org/x/crypto/ssh/connection.go
generated
vendored
@ -1,143 +0,0 @@
|
|||||||
// 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
21
vendor/golang.org/x/crypto/ssh/doc.go
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
// 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"
|
|
647
vendor/golang.org/x/crypto/ssh/handshake.go
generated
vendored
647
vendor/golang.org/x/crypto/ssh/handshake.go
generated
vendored
@ -1,647 +0,0 @@
|
|||||||
// 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
|
|
||||||
isClient := len(t.hostKeys) == 0
|
|
||||||
if isClient {
|
|
||||||
clientInit, serverInit = serverInit, clientInit
|
|
||||||
|
|
||||||
magics.clientKexInit = t.sentInitPacket
|
|
||||||
magics.serverKexInit = otherInitPacket
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
t.algorithms, err = findAgreedAlgorithms(isClient, 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
|
|
||||||
}
|
|
789
vendor/golang.org/x/crypto/ssh/kex.go
generated
vendored
789
vendor/golang.org/x/crypto/ssh/kex.go
generated
vendored
@ -1,789 +0,0 @@
|
|||||||
// 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"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"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"
|
|
||||||
|
|
||||||
// For the following kex only the client half contains a production
|
|
||||||
// ready implementation. The server half only consists of a minimal
|
|
||||||
// implementation to satisfy the automated tests.
|
|
||||||
kexAlgoDHGEXSHA1 = "diffie-hellman-group-exchange-sha1"
|
|
||||||
kexAlgoDHGEXSHA256 = "diffie-hellman-group-exchange-sha256"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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{}
|
|
||||||
kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
|
|
||||||
kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// dhGEXSHA implements the diffie-hellman-group-exchange-sha1 and
|
|
||||||
// diffie-hellman-group-exchange-sha256 key agreement protocols,
|
|
||||||
// as described in RFC 4419
|
|
||||||
type dhGEXSHA struct {
|
|
||||||
g, p *big.Int
|
|
||||||
hashFunc crypto.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
const numMRTests = 64
|
|
||||||
|
|
||||||
const (
|
|
||||||
dhGroupExchangeMinimumBits = 2048
|
|
||||||
dhGroupExchangePreferredBits = 2048
|
|
||||||
dhGroupExchangeMaximumBits = 8192
|
|
||||||
)
|
|
||||||
|
|
||||||
func (gex *dhGEXSHA) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
|
|
||||||
if theirPublic.Sign() <= 0 || theirPublic.Cmp(gex.p) >= 0 {
|
|
||||||
return nil, fmt.Errorf("ssh: DH parameter out of bounds")
|
|
||||||
}
|
|
||||||
return new(big.Int).Exp(theirPublic, myPrivate, gex.p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
|
|
||||||
// Send GexRequest
|
|
||||||
kexDHGexRequest := kexDHGexRequestMsg{
|
|
||||||
MinBits: dhGroupExchangeMinimumBits,
|
|
||||||
PreferedBits: dhGroupExchangePreferredBits,
|
|
||||||
MaxBits: dhGroupExchangeMaximumBits,
|
|
||||||
}
|
|
||||||
if err := c.writePacket(Marshal(&kexDHGexRequest)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive GexGroup
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var kexDHGexGroup kexDHGexGroupMsg
|
|
||||||
if err = Unmarshal(packet, &kexDHGexGroup); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits
|
|
||||||
if kexDHGexGroup.P.BitLen() < dhGroupExchangeMinimumBits || kexDHGexGroup.P.BitLen() > dhGroupExchangeMaximumBits {
|
|
||||||
return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", kexDHGexGroup.P.BitLen())
|
|
||||||
}
|
|
||||||
|
|
||||||
gex.p = kexDHGexGroup.P
|
|
||||||
gex.g = kexDHGexGroup.G
|
|
||||||
|
|
||||||
// Check if p is safe by verifing that p and (p-1)/2 are primes
|
|
||||||
one := big.NewInt(1)
|
|
||||||
var pHalf = &big.Int{}
|
|
||||||
pHalf.Rsh(gex.p, 1)
|
|
||||||
if !gex.p.ProbablyPrime(numMRTests) || !pHalf.ProbablyPrime(numMRTests) {
|
|
||||||
return nil, fmt.Errorf("ssh: server provided gex p is not safe")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if g is safe by verifing that g > 1 and g < p - 1
|
|
||||||
var pMinusOne = &big.Int{}
|
|
||||||
pMinusOne.Sub(gex.p, one)
|
|
||||||
if gex.g.Cmp(one) != 1 && gex.g.Cmp(pMinusOne) != -1 {
|
|
||||||
return nil, fmt.Errorf("ssh: server provided gex g is not safe")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send GexInit
|
|
||||||
x, err := rand.Int(randSource, pHalf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
X := new(big.Int).Exp(gex.g, x, gex.p)
|
|
||||||
kexDHGexInit := kexDHGexInitMsg{
|
|
||||||
X: X,
|
|
||||||
}
|
|
||||||
if err := c.writePacket(Marshal(&kexDHGexInit)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive GexReply
|
|
||||||
packet, err = c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var kexDHGexReply kexDHGexReplyMsg
|
|
||||||
if err = Unmarshal(packet, &kexDHGexReply); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
kInt, err := gex.diffieHellman(kexDHGexReply.Y, x)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if k is safe by verifing that k > 1 and k < p - 1
|
|
||||||
if kInt.Cmp(one) != 1 && kInt.Cmp(pMinusOne) != -1 {
|
|
||||||
return nil, fmt.Errorf("ssh: derived k is not safe")
|
|
||||||
}
|
|
||||||
|
|
||||||
h := gex.hashFunc.New()
|
|
||||||
magics.write(h)
|
|
||||||
writeString(h, kexDHGexReply.HostKey)
|
|
||||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
|
|
||||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
|
|
||||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
|
|
||||||
writeInt(h, gex.p)
|
|
||||||
writeInt(h, gex.g)
|
|
||||||
writeInt(h, X)
|
|
||||||
writeInt(h, kexDHGexReply.Y)
|
|
||||||
K := make([]byte, intLength(kInt))
|
|
||||||
marshalInt(K, kInt)
|
|
||||||
h.Write(K)
|
|
||||||
|
|
||||||
return &kexResult{
|
|
||||||
H: h.Sum(nil),
|
|
||||||
K: K,
|
|
||||||
HostKey: kexDHGexReply.HostKey,
|
|
||||||
Signature: kexDHGexReply.Signature,
|
|
||||||
Hash: gex.hashFunc,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256.
|
|
||||||
//
|
|
||||||
// This is a minimal implementation to satisfy the automated tests.
|
|
||||||
func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
|
|
||||||
// Receive GexRequest
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var kexDHGexRequest kexDHGexRequestMsg
|
|
||||||
if err = Unmarshal(packet, &kexDHGexRequest); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// smoosh the user's preferred size into our own limits
|
|
||||||
if kexDHGexRequest.PreferedBits > dhGroupExchangeMaximumBits {
|
|
||||||
kexDHGexRequest.PreferedBits = dhGroupExchangeMaximumBits
|
|
||||||
}
|
|
||||||
if kexDHGexRequest.PreferedBits < dhGroupExchangeMinimumBits {
|
|
||||||
kexDHGexRequest.PreferedBits = dhGroupExchangeMinimumBits
|
|
||||||
}
|
|
||||||
// fix min/max if they're inconsistent. technically, we could just pout
|
|
||||||
// and hang up, but there's no harm in giving them the benefit of the
|
|
||||||
// doubt and just picking a bitsize for them.
|
|
||||||
if kexDHGexRequest.MinBits > kexDHGexRequest.PreferedBits {
|
|
||||||
kexDHGexRequest.MinBits = kexDHGexRequest.PreferedBits
|
|
||||||
}
|
|
||||||
if kexDHGexRequest.MaxBits < kexDHGexRequest.PreferedBits {
|
|
||||||
kexDHGexRequest.MaxBits = kexDHGexRequest.PreferedBits
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send GexGroup
|
|
||||||
// This is the group called diffie-hellman-group14-sha1 in RFC
|
|
||||||
// 4253 and Oakley Group 14 in RFC 3526.
|
|
||||||
p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
|
|
||||||
gex.p = p
|
|
||||||
gex.g = big.NewInt(2)
|
|
||||||
|
|
||||||
kexDHGexGroup := kexDHGexGroupMsg{
|
|
||||||
P: gex.p,
|
|
||||||
G: gex.g,
|
|
||||||
}
|
|
||||||
if err := c.writePacket(Marshal(&kexDHGexGroup)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive GexInit
|
|
||||||
packet, err = c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var kexDHGexInit kexDHGexInitMsg
|
|
||||||
if err = Unmarshal(packet, &kexDHGexInit); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var pHalf = &big.Int{}
|
|
||||||
pHalf.Rsh(gex.p, 1)
|
|
||||||
|
|
||||||
y, err := rand.Int(randSource, pHalf)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Y := new(big.Int).Exp(gex.g, y, gex.p)
|
|
||||||
kInt, err := gex.diffieHellman(kexDHGexInit.X, y)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
hostKeyBytes := priv.PublicKey().Marshal()
|
|
||||||
|
|
||||||
h := gex.hashFunc.New()
|
|
||||||
magics.write(h)
|
|
||||||
writeString(h, hostKeyBytes)
|
|
||||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
|
|
||||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
|
|
||||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
|
|
||||||
writeInt(h, gex.p)
|
|
||||||
writeInt(h, gex.g)
|
|
||||||
writeInt(h, kexDHGexInit.X)
|
|
||||||
writeInt(h, Y)
|
|
||||||
|
|
||||||
K := make([]byte, intLength(kInt))
|
|
||||||
marshalInt(K, kInt)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
kexDHGexReply := kexDHGexReplyMsg{
|
|
||||||
HostKey: hostKeyBytes,
|
|
||||||
Y: Y,
|
|
||||||
Signature: sig,
|
|
||||||
}
|
|
||||||
packet = Marshal(&kexDHGexReply)
|
|
||||||
|
|
||||||
err = c.writePacket(packet)
|
|
||||||
|
|
||||||
return &kexResult{
|
|
||||||
H: H,
|
|
||||||
K: K,
|
|
||||||
HostKey: hostKeyBytes,
|
|
||||||
Signature: sig,
|
|
||||||
Hash: gex.hashFunc,
|
|
||||||
}, err
|
|
||||||
}
|
|
1100
vendor/golang.org/x/crypto/ssh/keys.go
generated
vendored
1100
vendor/golang.org/x/crypto/ssh/keys.go
generated
vendored
File diff suppressed because it is too large
Load Diff
61
vendor/golang.org/x/crypto/ssh/mac.go
generated
vendored
61
vendor/golang.org/x/crypto/ssh/mac.go
generated
vendored
@ -1,61 +0,0 @@
|
|||||||
// 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)}
|
|
||||||
}},
|
|
||||||
}
|
|
866
vendor/golang.org/x/crypto/ssh/messages.go
generated
vendored
866
vendor/golang.org/x/crypto/ssh/messages.go
generated
vendored
@ -1,866 +0,0 @@
|
|||||||
// 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 4419, section 5.
|
|
||||||
const msgKexDHGexGroup = 31
|
|
||||||
|
|
||||||
type kexDHGexGroupMsg struct {
|
|
||||||
P *big.Int `sshtype:"31"`
|
|
||||||
G *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgKexDHGexInit = 32
|
|
||||||
|
|
||||||
type kexDHGexInitMsg struct {
|
|
||||||
X *big.Int `sshtype:"32"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgKexDHGexReply = 33
|
|
||||||
|
|
||||||
type kexDHGexReplyMsg struct {
|
|
||||||
HostKey []byte `sshtype:"33"`
|
|
||||||
Y *big.Int
|
|
||||||
Signature []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgKexDHGexRequest = 34
|
|
||||||
|
|
||||||
type kexDHGexRequestMsg struct {
|
|
||||||
MinBits uint32 `sshtype:"34"`
|
|
||||||
PreferedBits uint32
|
|
||||||
MaxBits uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4462, section 3
|
|
||||||
const msgUserAuthGSSAPIResponse = 60
|
|
||||||
|
|
||||||
type userAuthGSSAPIResponse struct {
|
|
||||||
SupportMech []byte `sshtype:"60"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgUserAuthGSSAPIToken = 61
|
|
||||||
|
|
||||||
type userAuthGSSAPIToken struct {
|
|
||||||
Token []byte `sshtype:"61"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgUserAuthGSSAPIMIC = 66
|
|
||||||
|
|
||||||
type userAuthGSSAPIMIC struct {
|
|
||||||
MIC []byte `sshtype:"66"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4462, section 3.9
|
|
||||||
const msgUserAuthGSSAPIErrTok = 64
|
|
||||||
|
|
||||||
type userAuthGSSAPIErrTok struct {
|
|
||||||
ErrorToken []byte `sshtype:"64"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4462, section 3.8
|
|
||||||
const msgUserAuthGSSAPIError = 65
|
|
||||||
|
|
||||||
type userAuthGSSAPIError struct {
|
|
||||||
MajorStatus uint32 `sshtype:"65"`
|
|
||||||
MinorStatus uint32
|
|
||||||
Message string
|
|
||||||
LanguageTag string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
case msgUserAuthGSSAPIToken:
|
|
||||||
msg = new(userAuthGSSAPIToken)
|
|
||||||
case msgUserAuthGSSAPIMIC:
|
|
||||||
msg = new(userAuthGSSAPIMIC)
|
|
||||||
case msgUserAuthGSSAPIErrTok:
|
|
||||||
msg = new(userAuthGSSAPIErrTok)
|
|
||||||
case msgUserAuthGSSAPIError:
|
|
||||||
msg = new(userAuthGSSAPIError)
|
|
||||||
default:
|
|
||||||
return nil, unexpectedMessageError(0, packet[0])
|
|
||||||
}
|
|
||||||
if err := Unmarshal(packet, msg); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return msg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var packetTypeNames = map[byte]string{
|
|
||||||
msgDisconnect: "disconnectMsg",
|
|
||||||
msgServiceRequest: "serviceRequestMsg",
|
|
||||||
msgServiceAccept: "serviceAcceptMsg",
|
|
||||||
msgKexInit: "kexInitMsg",
|
|
||||||
msgKexDHInit: "kexDHInitMsg",
|
|
||||||
msgKexDHReply: "kexDHReplyMsg",
|
|
||||||
msgUserAuthRequest: "userAuthRequestMsg",
|
|
||||||
msgUserAuthSuccess: "userAuthSuccessMsg",
|
|
||||||
msgUserAuthFailure: "userAuthFailureMsg",
|
|
||||||
msgUserAuthPubKeyOk: "userAuthPubKeyOkMsg",
|
|
||||||
msgGlobalRequest: "globalRequestMsg",
|
|
||||||
msgRequestSuccess: "globalRequestSuccessMsg",
|
|
||||||
msgRequestFailure: "globalRequestFailureMsg",
|
|
||||||
msgChannelOpen: "channelOpenMsg",
|
|
||||||
msgChannelData: "channelDataMsg",
|
|
||||||
msgChannelOpenConfirm: "channelOpenConfirmMsg",
|
|
||||||
msgChannelOpenFailure: "channelOpenFailureMsg",
|
|
||||||
msgChannelWindowAdjust: "windowAdjustMsg",
|
|
||||||
msgChannelEOF: "channelEOFMsg",
|
|
||||||
msgChannelClose: "channelCloseMsg",
|
|
||||||
msgChannelRequest: "channelRequestMsg",
|
|
||||||
msgChannelSuccess: "channelRequestSuccessMsg",
|
|
||||||
msgChannelFailure: "channelRequestFailureMsg",
|
|
||||||
}
|
|
330
vendor/golang.org/x/crypto/ssh/mux.go
generated
vendored
330
vendor/golang.org/x/crypto/ssh/mux.go
generated
vendored
@ -1,330 +0,0 @@
|
|||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
716
vendor/golang.org/x/crypto/ssh/server.go
generated
vendored
716
vendor/golang.org/x/crypto/ssh/server.go
generated
vendored
@ -1,716 +0,0 @@
|
|||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
type GSSAPIWithMICConfig struct {
|
|
||||||
// AllowLogin, must be set, is called when gssapi-with-mic
|
|
||||||
// authentication is selected (RFC 4462 section 3). The srcName is from the
|
|
||||||
// results of the GSS-API authentication. The format is username@DOMAIN.
|
|
||||||
// GSSAPI just guarantees to the server who the user is, but not if they can log in, and with what permissions.
|
|
||||||
// This callback is called after the user identity is established with GSSAPI to decide if the user can login with
|
|
||||||
// which permissions. If the user is allowed to login, it should return a nil error.
|
|
||||||
AllowLogin func(conn ConnMetadata, srcName string) (*Permissions, error)
|
|
||||||
|
|
||||||
// Server must be set. It's the implementation
|
|
||||||
// of the GSSAPIServer interface. See GSSAPIServer interface for details.
|
|
||||||
Server GSSAPIServer
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// GSSAPIWithMICConfig includes gssapi server and callback, which if both non-nil, is used
|
|
||||||
// when gssapi-with-mic authentication is selected (RFC 4462 section 3).
|
|
||||||
GSSAPIWithMICConfig *GSSAPIWithMICConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
// Check if the config contains any unsupported key exchanges
|
|
||||||
for _, kex := range fullConf.KeyExchanges {
|
|
||||||
if _, ok := serverForbiddenKexAlgos[kex]; ok {
|
|
||||||
return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 && (config.GSSAPIWithMICConfig == nil ||
|
|
||||||
config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *connection,
|
|
||||||
sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
|
|
||||||
gssAPIServer := gssapiConfig.Server
|
|
||||||
defer gssAPIServer.DeleteSecContext()
|
|
||||||
var srcName string
|
|
||||||
for {
|
|
||||||
var (
|
|
||||||
outToken []byte
|
|
||||||
needContinue bool
|
|
||||||
)
|
|
||||||
outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(firstToken)
|
|
||||||
if err != nil {
|
|
||||||
return err, nil, nil
|
|
||||||
}
|
|
||||||
if len(outToken) != 0 {
|
|
||||||
if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{
|
|
||||||
Token: outToken,
|
|
||||||
})); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !needContinue {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
packet, err := s.transport.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
|
|
||||||
if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
packet, err := s.transport.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{}
|
|
||||||
if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method)
|
|
||||||
if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil {
|
|
||||||
return err, nil, nil
|
|
||||||
}
|
|
||||||
perms, authErr = gssapiConfig.AllowLogin(s, srcName)
|
|
||||||
return authErr, perms, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
case "gssapi-with-mic":
|
|
||||||
gssapiConfig := config.GSSAPIWithMICConfig
|
|
||||||
userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload)
|
|
||||||
if err != nil {
|
|
||||||
return nil, parseError(msgUserAuthRequest)
|
|
||||||
}
|
|
||||||
// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication.
|
|
||||||
if userAuthRequestGSSAPI.N == 0 {
|
|
||||||
authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
var i uint32
|
|
||||||
present := false
|
|
||||||
for i = 0; i < userAuthRequestGSSAPI.N; i++ {
|
|
||||||
if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) {
|
|
||||||
present = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !present {
|
|
||||||
authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// Initial server response, see RFC 4462 section 3.3.
|
|
||||||
if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{
|
|
||||||
SupportMech: krb5OID,
|
|
||||||
})); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Exchange token, see RFC 4462 section 3.4.
|
|
||||||
packet, err := s.transport.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
|
|
||||||
if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID,
|
|
||||||
userAuthReq)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
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 config.GSSAPIWithMICConfig != nil && config.GSSAPIWithMICConfig.Server != nil &&
|
|
||||||
config.GSSAPIWithMICConfig.AllowLogin != nil {
|
|
||||||
failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic")
|
|
||||||
}
|
|
||||||
|
|
||||||
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
647
vendor/golang.org/x/crypto/ssh/session.go
generated
vendored
@ -1,647 +0,0 @@
|
|||||||
// 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
|
|
||||||
}
|
|
139
vendor/golang.org/x/crypto/ssh/ssh_gss.go
generated
vendored
139
vendor/golang.org/x/crypto/ssh/ssh_gss.go
generated
vendored
@ -1,139 +0,0 @@
|
|||||||
// 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/asn1"
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
var krb5OID []byte
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
krb5OID, _ = asn1.Marshal(krb5Mesh)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GSSAPIClient provides the API to plug-in GSSAPI authentication for client logins.
|
|
||||||
type GSSAPIClient interface {
|
|
||||||
// InitSecContext initiates the establishment of a security context for GSS-API between the
|
|
||||||
// ssh client and ssh server. Initially the token parameter should be specified as nil.
|
|
||||||
// The routine may return a outputToken which should be transferred to
|
|
||||||
// the ssh server, where the ssh server will present it to
|
|
||||||
// AcceptSecContext. If no token need be sent, InitSecContext will indicate this by setting
|
|
||||||
// needContinue to false. To complete the context
|
|
||||||
// establishment, one or more reply tokens may be required from the ssh
|
|
||||||
// server;if so, InitSecContext will return a needContinue which is true.
|
|
||||||
// In this case, InitSecContext should be called again when the
|
|
||||||
// reply token is received from the ssh server, passing the reply
|
|
||||||
// token to InitSecContext via the token parameters.
|
|
||||||
// See RFC 2743 section 2.2.1 and RFC 4462 section 3.4.
|
|
||||||
InitSecContext(target string, token []byte, isGSSDelegCreds bool) (outputToken []byte, needContinue bool, err error)
|
|
||||||
// GetMIC generates a cryptographic MIC for the SSH2 message, and places
|
|
||||||
// the MIC in a token for transfer to the ssh server.
|
|
||||||
// The contents of the MIC field are obtained by calling GSS_GetMIC()
|
|
||||||
// over the following, using the GSS-API context that was just
|
|
||||||
// established:
|
|
||||||
// string session identifier
|
|
||||||
// byte SSH_MSG_USERAUTH_REQUEST
|
|
||||||
// string user name
|
|
||||||
// string service
|
|
||||||
// string "gssapi-with-mic"
|
|
||||||
// See RFC 2743 section 2.3.1 and RFC 4462 3.5.
|
|
||||||
GetMIC(micFiled []byte) ([]byte, error)
|
|
||||||
// Whenever possible, it should be possible for
|
|
||||||
// DeleteSecContext() calls to be successfully processed even
|
|
||||||
// if other calls cannot succeed, thereby enabling context-related
|
|
||||||
// resources to be released.
|
|
||||||
// In addition to deleting established security contexts,
|
|
||||||
// gss_delete_sec_context must also be able to delete "half-built"
|
|
||||||
// security contexts resulting from an incomplete sequence of
|
|
||||||
// InitSecContext()/AcceptSecContext() calls.
|
|
||||||
// See RFC 2743 section 2.2.3.
|
|
||||||
DeleteSecContext() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// GSSAPIServer provides the API to plug in GSSAPI authentication for server logins.
|
|
||||||
type GSSAPIServer interface {
|
|
||||||
// AcceptSecContext allows a remotely initiated security context between the application
|
|
||||||
// and a remote peer to be established by the ssh client. The routine may return a
|
|
||||||
// outputToken which should be transferred to the ssh client,
|
|
||||||
// where the ssh client will present it to InitSecContext.
|
|
||||||
// If no token need be sent, AcceptSecContext will indicate this
|
|
||||||
// by setting the needContinue to false. To
|
|
||||||
// complete the context establishment, one or more reply tokens may be
|
|
||||||
// required from the ssh client. if so, AcceptSecContext
|
|
||||||
// will return a needContinue which is true, in which case it
|
|
||||||
// should be called again when the reply token is received from the ssh
|
|
||||||
// client, passing the token to AcceptSecContext via the
|
|
||||||
// token parameters.
|
|
||||||
// The srcName return value is the authenticated username.
|
|
||||||
// See RFC 2743 section 2.2.2 and RFC 4462 section 3.4.
|
|
||||||
AcceptSecContext(token []byte) (outputToken []byte, srcName string, needContinue bool, err error)
|
|
||||||
// VerifyMIC verifies that a cryptographic MIC, contained in the token parameter,
|
|
||||||
// fits the supplied message is received from the ssh client.
|
|
||||||
// See RFC 2743 section 2.3.2.
|
|
||||||
VerifyMIC(micField []byte, micToken []byte) error
|
|
||||||
// Whenever possible, it should be possible for
|
|
||||||
// DeleteSecContext() calls to be successfully processed even
|
|
||||||
// if other calls cannot succeed, thereby enabling context-related
|
|
||||||
// resources to be released.
|
|
||||||
// In addition to deleting established security contexts,
|
|
||||||
// gss_delete_sec_context must also be able to delete "half-built"
|
|
||||||
// security contexts resulting from an incomplete sequence of
|
|
||||||
// InitSecContext()/AcceptSecContext() calls.
|
|
||||||
// See RFC 2743 section 2.2.3.
|
|
||||||
DeleteSecContext() error
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,
|
|
||||||
// so we also support the krb5 mechanism only.
|
|
||||||
// See RFC 1964 section 1.
|
|
||||||
krb5Mesh = asn1.ObjectIdentifier{1, 2, 840, 113554, 1, 2, 2}
|
|
||||||
)
|
|
||||||
|
|
||||||
// The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST
|
|
||||||
// See RFC 4462 section 3.2.
|
|
||||||
type userAuthRequestGSSAPI struct {
|
|
||||||
N uint32
|
|
||||||
OIDS []asn1.ObjectIdentifier
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) {
|
|
||||||
n, rest, ok := parseUint32(payload)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("parse uint32 failed")
|
|
||||||
}
|
|
||||||
s := &userAuthRequestGSSAPI{
|
|
||||||
N: n,
|
|
||||||
OIDS: make([]asn1.ObjectIdentifier, n),
|
|
||||||
}
|
|
||||||
for i := 0; i < int(n); i++ {
|
|
||||||
var (
|
|
||||||
desiredMech []byte
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
desiredMech, rest, ok = parseString(rest)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("parse string failed")
|
|
||||||
}
|
|
||||||
if rest, err = asn1.Unmarshal(desiredMech, &s.OIDS[i]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4462 section 3.6.
|
|
||||||
func buildMIC(sessionID string, username string, service string, authMethod string) []byte {
|
|
||||||
out := make([]byte, 0, 0)
|
|
||||||
out = appendString(out, sessionID)
|
|
||||||
out = append(out, msgUserAuthRequest)
|
|
||||||
out = appendString(out, username)
|
|
||||||
out = appendString(out, service)
|
|
||||||
out = appendString(out, authMethod)
|
|
||||||
return out
|
|
||||||
}
|
|
116
vendor/golang.org/x/crypto/ssh/streamlocal.go
generated
vendored
116
vendor/golang.org/x/crypto/ssh/streamlocal.go
generated
vendored
@ -1,116 +0,0 @@
|
|||||||
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
474
vendor/golang.org/x/crypto/ssh/tcpip.go
generated
vendored
@ -1,474 +0,0 @@
|
|||||||
// 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")
|
|
||||||
}
|
|
353
vendor/golang.org/x/crypto/ssh/transport.go
generated
vendored
353
vendor/golang.org/x/crypto/ssh/transport.go
generated
vendored
@ -1,353 +0,0 @@
|
|||||||
// 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 {
|
|
||||||
// writeCipherPacket encrypts the packet and writes it to w. The
|
|
||||||
// contents of the packet are generally scrambled.
|
|
||||||
writeCipherPacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error
|
|
||||||
|
|
||||||
// readCipherPacket reads and decrypts a packet of data. The
|
|
||||||
// returned packet may be overwritten by future calls of
|
|
||||||
// readPacket.
|
|
||||||
readCipherPacket(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.readCipherPacket(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.writeCipherPacket(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
|
|
||||||
}
|
|
3
vendor/golang.org/x/sys/AUTHORS
generated
vendored
3
vendor/golang.org/x/sys/AUTHORS
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
# This source code refers to The Go Authors for copyright purposes.
|
|
||||||
# The master list of authors is in the main Go distribution,
|
|
||||||
# visible at http://tip.golang.org/AUTHORS.
|
|
3
vendor/golang.org/x/sys/CONTRIBUTORS
generated
vendored
3
vendor/golang.org/x/sys/CONTRIBUTORS
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
# This source code was written by the Go contributors.
|
|
||||||
# The master list of contributors is in the main Go distribution,
|
|
||||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
|
27
vendor/golang.org/x/sys/LICENSE
generated
vendored
27
vendor/golang.org/x/sys/LICENSE
generated
vendored
@ -1,27 +0,0 @@
|
|||||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
22
vendor/golang.org/x/sys/PATENTS
generated
vendored
22
vendor/golang.org/x/sys/PATENTS
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
Additional IP Rights Grant (Patents)
|
|
||||||
|
|
||||||
"This implementation" means the copyrightable works distributed by
|
|
||||||
Google as part of the Go project.
|
|
||||||
|
|
||||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
||||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
|
||||||
patent license to make, have made, use, offer to sell, sell, import,
|
|
||||||
transfer and otherwise run, modify and propagate the contents of this
|
|
||||||
implementation of Go, where such license applies only to those patent
|
|
||||||
claims, both currently owned or controlled by Google and acquired in
|
|
||||||
the future, licensable by Google that are necessarily infringed by this
|
|
||||||
implementation of Go. This grant does not include claims that would be
|
|
||||||
infringed only as a consequence of further modification of this
|
|
||||||
implementation. If you or your agent or exclusive licensee institute or
|
|
||||||
order or agree to the institution of patent litigation against any
|
|
||||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
|
||||||
that this implementation of Go or any code incorporated within this
|
|
||||||
implementation of Go constitutes direct or contributory patent
|
|
||||||
infringement, or inducement of patent infringement, then any patent
|
|
||||||
rights granted to you under this License for this implementation of Go
|
|
||||||
shall terminate as of the date such litigation is filed.
|
|
17
vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s
generated
vendored
17
vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s
generated
vendored
@ -1,17 +0,0 @@
|
|||||||
// 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 !gccgo
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go
|
|
||||||
//
|
|
||||||
|
|
||||||
TEXT ·syscall6(SB),NOSPLIT,$0-88
|
|
||||||
JMP syscall·syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·rawSyscall6(SB),NOSPLIT,$0-88
|
|
||||||
JMP syscall·rawSyscall6(SB)
|
|
30
vendor/golang.org/x/sys/cpu/byteorder.go
generated
vendored
30
vendor/golang.org/x/sys/cpu/byteorder.go
generated
vendored
@ -1,30 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// hostByteOrder returns binary.LittleEndian on little-endian machines and
|
|
||||||
// binary.BigEndian on big-endian machines.
|
|
||||||
func hostByteOrder() binary.ByteOrder {
|
|
||||||
switch runtime.GOARCH {
|
|
||||||
case "386", "amd64", "amd64p32",
|
|
||||||
"arm", "arm64",
|
|
||||||
"mipsle", "mips64le", "mips64p32le",
|
|
||||||
"ppc64le",
|
|
||||||
"riscv", "riscv64":
|
|
||||||
return binary.LittleEndian
|
|
||||||
case "armbe", "arm64be",
|
|
||||||
"mips", "mips64", "mips64p32",
|
|
||||||
"ppc", "ppc64",
|
|
||||||
"s390", "s390x",
|
|
||||||
"sparc", "sparc64":
|
|
||||||
return binary.BigEndian
|
|
||||||
}
|
|
||||||
panic("unknown architecture")
|
|
||||||
}
|
|
126
vendor/golang.org/x/sys/cpu/cpu.go
generated
vendored
126
vendor/golang.org/x/sys/cpu/cpu.go
generated
vendored
@ -1,126 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
// Package cpu implements processor feature detection for
|
|
||||||
// various CPU architectures.
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
// Initialized reports whether the CPU features were initialized.
|
|
||||||
//
|
|
||||||
// For some GOOS/GOARCH combinations initialization of the CPU features depends
|
|
||||||
// on reading an operating specific file, e.g. /proc/self/auxv on linux/arm
|
|
||||||
// Initialized will report false if reading the file fails.
|
|
||||||
var Initialized bool
|
|
||||||
|
|
||||||
// CacheLinePad is used to pad structs to avoid false sharing.
|
|
||||||
type CacheLinePad struct{ _ [cacheLineSize]byte }
|
|
||||||
|
|
||||||
// X86 contains the supported CPU features of the
|
|
||||||
// current X86/AMD64 platform. If the current platform
|
|
||||||
// is not X86/AMD64 then all feature flags are false.
|
|
||||||
//
|
|
||||||
// X86 is padded to avoid false sharing. Further the HasAVX
|
|
||||||
// and HasAVX2 are only set if the OS supports XMM and YMM
|
|
||||||
// registers in addition to the CPUID feature bit being set.
|
|
||||||
var X86 struct {
|
|
||||||
_ CacheLinePad
|
|
||||||
HasAES bool // AES hardware implementation (AES NI)
|
|
||||||
HasADX bool // Multi-precision add-carry instruction extensions
|
|
||||||
HasAVX bool // Advanced vector extension
|
|
||||||
HasAVX2 bool // Advanced vector extension 2
|
|
||||||
HasBMI1 bool // Bit manipulation instruction set 1
|
|
||||||
HasBMI2 bool // Bit manipulation instruction set 2
|
|
||||||
HasERMS bool // Enhanced REP for MOVSB and STOSB
|
|
||||||
HasFMA bool // Fused-multiply-add instructions
|
|
||||||
HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers.
|
|
||||||
HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM
|
|
||||||
HasPOPCNT bool // Hamming weight instruction POPCNT.
|
|
||||||
HasRDRAND bool // RDRAND instruction (on-chip random number generator)
|
|
||||||
HasRDSEED bool // RDSEED instruction (on-chip random number generator)
|
|
||||||
HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64)
|
|
||||||
HasSSE3 bool // Streaming SIMD extension 3
|
|
||||||
HasSSSE3 bool // Supplemental streaming SIMD extension 3
|
|
||||||
HasSSE41 bool // Streaming SIMD extension 4 and 4.1
|
|
||||||
HasSSE42 bool // Streaming SIMD extension 4 and 4.2
|
|
||||||
_ CacheLinePad
|
|
||||||
}
|
|
||||||
|
|
||||||
// ARM64 contains the supported CPU features of the
|
|
||||||
// current ARMv8(aarch64) platform. If the current platform
|
|
||||||
// is not arm64 then all feature flags are false.
|
|
||||||
var ARM64 struct {
|
|
||||||
_ CacheLinePad
|
|
||||||
HasFP bool // Floating-point instruction set (always available)
|
|
||||||
HasASIMD bool // Advanced SIMD (always available)
|
|
||||||
HasEVTSTRM bool // Event stream support
|
|
||||||
HasAES bool // AES hardware implementation
|
|
||||||
HasPMULL bool // Polynomial multiplication instruction set
|
|
||||||
HasSHA1 bool // SHA1 hardware implementation
|
|
||||||
HasSHA2 bool // SHA2 hardware implementation
|
|
||||||
HasCRC32 bool // CRC32 hardware implementation
|
|
||||||
HasATOMICS bool // Atomic memory operation instruction set
|
|
||||||
HasFPHP bool // Half precision floating-point instruction set
|
|
||||||
HasASIMDHP bool // Advanced SIMD half precision instruction set
|
|
||||||
HasCPUID bool // CPUID identification scheme registers
|
|
||||||
HasASIMDRDM bool // Rounding double multiply add/subtract instruction set
|
|
||||||
HasJSCVT bool // Javascript conversion from floating-point to integer
|
|
||||||
HasFCMA bool // Floating-point multiplication and addition of complex numbers
|
|
||||||
HasLRCPC bool // Release Consistent processor consistent support
|
|
||||||
HasDCPOP bool // Persistent memory support
|
|
||||||
HasSHA3 bool // SHA3 hardware implementation
|
|
||||||
HasSM3 bool // SM3 hardware implementation
|
|
||||||
HasSM4 bool // SM4 hardware implementation
|
|
||||||
HasASIMDDP bool // Advanced SIMD double precision instruction set
|
|
||||||
HasSHA512 bool // SHA512 hardware implementation
|
|
||||||
HasSVE bool // Scalable Vector Extensions
|
|
||||||
HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32
|
|
||||||
_ CacheLinePad
|
|
||||||
}
|
|
||||||
|
|
||||||
// PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms.
|
|
||||||
// If the current platform is not ppc64/ppc64le then all feature flags are false.
|
|
||||||
//
|
|
||||||
// For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00,
|
|
||||||
// since there are no optional categories. There are some exceptions that also
|
|
||||||
// require kernel support to work (DARN, SCV), so there are feature bits for
|
|
||||||
// those as well. The minimum processor requirement is POWER8 (ISA 2.07).
|
|
||||||
// The struct is padded to avoid false sharing.
|
|
||||||
var PPC64 struct {
|
|
||||||
_ CacheLinePad
|
|
||||||
HasDARN bool // Hardware random number generator (requires kernel enablement)
|
|
||||||
HasSCV bool // Syscall vectored (requires kernel enablement)
|
|
||||||
IsPOWER8 bool // ISA v2.07 (POWER8)
|
|
||||||
IsPOWER9 bool // ISA v3.00 (POWER9)
|
|
||||||
_ CacheLinePad
|
|
||||||
}
|
|
||||||
|
|
||||||
// S390X contains the supported CPU features of the current IBM Z
|
|
||||||
// (s390x) platform. If the current platform is not IBM Z then all
|
|
||||||
// feature flags are false.
|
|
||||||
//
|
|
||||||
// S390X is padded to avoid false sharing. Further HasVX is only set
|
|
||||||
// if the OS supports vector registers in addition to the STFLE
|
|
||||||
// feature bit being set.
|
|
||||||
var S390X struct {
|
|
||||||
_ CacheLinePad
|
|
||||||
HasZARCH bool // z/Architecture mode is active [mandatory]
|
|
||||||
HasSTFLE bool // store facility list extended
|
|
||||||
HasLDISP bool // long (20-bit) displacements
|
|
||||||
HasEIMM bool // 32-bit immediates
|
|
||||||
HasDFP bool // decimal floating point
|
|
||||||
HasETF3EH bool // ETF-3 enhanced
|
|
||||||
HasMSA bool // message security assist (CPACF)
|
|
||||||
HasAES bool // KM-AES{128,192,256} functions
|
|
||||||
HasAESCBC bool // KMC-AES{128,192,256} functions
|
|
||||||
HasAESCTR bool // KMCTR-AES{128,192,256} functions
|
|
||||||
HasAESGCM bool // KMA-GCM-AES{128,192,256} functions
|
|
||||||
HasGHASH bool // KIMD-GHASH function
|
|
||||||
HasSHA1 bool // K{I,L}MD-SHA-1 functions
|
|
||||||
HasSHA256 bool // K{I,L}MD-SHA-256 functions
|
|
||||||
HasSHA512 bool // K{I,L}MD-SHA-512 functions
|
|
||||||
HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions
|
|
||||||
HasVX bool // vector facility
|
|
||||||
HasVXE bool // vector-enhancements facility 1
|
|
||||||
_ CacheLinePad
|
|
||||||
}
|
|
34
vendor/golang.org/x/sys/cpu/cpu_aix_ppc64.go
generated
vendored
34
vendor/golang.org/x/sys/cpu/cpu_aix_ppc64.go
generated
vendored
@ -1,34 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build aix,ppc64
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 128
|
|
||||||
|
|
||||||
const (
|
|
||||||
// getsystemcfg constants
|
|
||||||
_SC_IMPL = 2
|
|
||||||
_IMPL_POWER8 = 0x10000
|
|
||||||
_IMPL_POWER9 = 0x20000
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
impl := getsystemcfg(_SC_IMPL)
|
|
||||||
if impl&_IMPL_POWER8 != 0 {
|
|
||||||
PPC64.IsPOWER8 = true
|
|
||||||
}
|
|
||||||
if impl&_IMPL_POWER9 != 0 {
|
|
||||||
PPC64.IsPOWER9 = true
|
|
||||||
}
|
|
||||||
|
|
||||||
Initialized = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func getsystemcfg(label int) (n uint64) {
|
|
||||||
r0, _ := callgetsystemcfg(label)
|
|
||||||
n = uint64(r0)
|
|
||||||
return
|
|
||||||
}
|
|
9
vendor/golang.org/x/sys/cpu/cpu_arm.go
generated
vendored
9
vendor/golang.org/x/sys/cpu/cpu_arm.go
generated
vendored
@ -1,9 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 32
|
|
||||||
|
|
||||||
func doinit() {}
|
|
21
vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go
generated
vendored
21
vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !gccgo
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
// haveAsmFunctions reports whether the other functions in this file can
|
|
||||||
// be safely called.
|
|
||||||
func haveAsmFunctions() bool { return true }
|
|
||||||
|
|
||||||
// The following feature detection functions are defined in cpu_s390x.s.
|
|
||||||
// They are likely to be expensive to call so the results should be cached.
|
|
||||||
func stfle() facilityList
|
|
||||||
func kmQuery() queryResult
|
|
||||||
func kmcQuery() queryResult
|
|
||||||
func kmctrQuery() queryResult
|
|
||||||
func kmaQuery() queryResult
|
|
||||||
func kimdQuery() queryResult
|
|
||||||
func klmdQuery() queryResult
|
|
16
vendor/golang.org/x/sys/cpu/cpu_gc_x86.go
generated
vendored
16
vendor/golang.org/x/sys/cpu/cpu_gc_x86.go
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
// 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 386 amd64 amd64p32
|
|
||||||
// +build !gccgo
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
// cpuid is implemented in cpu_x86.s for gc compiler
|
|
||||||
// and in cpu_gccgo.c for gccgo.
|
|
||||||
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
|
||||||
|
|
||||||
// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler
|
|
||||||
// and in cpu_gccgo.c for gccgo.
|
|
||||||
func xgetbv() (eax, edx uint32)
|
|
43
vendor/golang.org/x/sys/cpu/cpu_gccgo.c
generated
vendored
43
vendor/golang.org/x/sys/cpu/cpu_gccgo.c
generated
vendored
@ -1,43 +0,0 @@
|
|||||||
// 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 386 amd64 amd64p32
|
|
||||||
// +build gccgo
|
|
||||||
|
|
||||||
#include <cpuid.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
// Need to wrap __get_cpuid_count because it's declared as static.
|
|
||||||
int
|
|
||||||
gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf,
|
|
||||||
uint32_t *eax, uint32_t *ebx,
|
|
||||||
uint32_t *ecx, uint32_t *edx)
|
|
||||||
{
|
|
||||||
return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx);
|
|
||||||
}
|
|
||||||
|
|
||||||
// xgetbv reads the contents of an XCR (Extended Control Register)
|
|
||||||
// specified in the ECX register into registers EDX:EAX.
|
|
||||||
// Currently, the only supported value for XCR is 0.
|
|
||||||
//
|
|
||||||
// TODO: Replace with a better alternative:
|
|
||||||
//
|
|
||||||
// #include <xsaveintrin.h>
|
|
||||||
//
|
|
||||||
// #pragma GCC target("xsave")
|
|
||||||
//
|
|
||||||
// void gccgoXgetbv(uint32_t *eax, uint32_t *edx) {
|
|
||||||
// unsigned long long x = _xgetbv(0);
|
|
||||||
// *eax = x & 0xffffffff;
|
|
||||||
// *edx = (x >> 32) & 0xffffffff;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Note that _xgetbv is defined starting with GCC 8.
|
|
||||||
void
|
|
||||||
gccgoXgetbv(uint32_t *eax, uint32_t *edx)
|
|
||||||
{
|
|
||||||
__asm(" xorl %%ecx, %%ecx\n"
|
|
||||||
" xgetbv"
|
|
||||||
: "=a"(*eax), "=d"(*edx));
|
|
||||||
}
|
|
26
vendor/golang.org/x/sys/cpu/cpu_gccgo.go
generated
vendored
26
vendor/golang.org/x/sys/cpu/cpu_gccgo.go
generated
vendored
@ -1,26 +0,0 @@
|
|||||||
// 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 386 amd64 amd64p32
|
|
||||||
// +build gccgo
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
//extern gccgoGetCpuidCount
|
|
||||||
func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32)
|
|
||||||
|
|
||||||
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) {
|
|
||||||
var a, b, c, d uint32
|
|
||||||
gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d)
|
|
||||||
return a, b, c, d
|
|
||||||
}
|
|
||||||
|
|
||||||
//extern gccgoXgetbv
|
|
||||||
func gccgoXgetbv(eax, edx *uint32)
|
|
||||||
|
|
||||||
func xgetbv() (eax, edx uint32) {
|
|
||||||
var a, d uint32
|
|
||||||
gccgoXgetbv(&a, &d)
|
|
||||||
return a, d
|
|
||||||
}
|
|
22
vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go
generated
vendored
22
vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build gccgo
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
// haveAsmFunctions reports whether the other functions in this file can
|
|
||||||
// be safely called.
|
|
||||||
func haveAsmFunctions() bool { return false }
|
|
||||||
|
|
||||||
// TODO(mundaym): the following feature detection functions are currently
|
|
||||||
// stubs. See https://golang.org/cl/162887 for how to fix this.
|
|
||||||
// They are likely to be expensive to call so the results should be cached.
|
|
||||||
func stfle() facilityList { panic("not implemented for gccgo") }
|
|
||||||
func kmQuery() queryResult { panic("not implemented for gccgo") }
|
|
||||||
func kmcQuery() queryResult { panic("not implemented for gccgo") }
|
|
||||||
func kmctrQuery() queryResult { panic("not implemented for gccgo") }
|
|
||||||
func kmaQuery() queryResult { panic("not implemented for gccgo") }
|
|
||||||
func kimdQuery() queryResult { panic("not implemented for gccgo") }
|
|
||||||
func klmdQuery() queryResult { panic("not implemented for gccgo") }
|
|
59
vendor/golang.org/x/sys/cpu/cpu_linux.go
generated
vendored
59
vendor/golang.org/x/sys/cpu/cpu_linux.go
generated
vendored
@ -1,59 +0,0 @@
|
|||||||
// 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 !amd64,!amd64p32,!386
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
_AT_HWCAP = 16
|
|
||||||
_AT_HWCAP2 = 26
|
|
||||||
|
|
||||||
procAuxv = "/proc/self/auxv"
|
|
||||||
|
|
||||||
uintSize = int(32 << (^uint(0) >> 63))
|
|
||||||
)
|
|
||||||
|
|
||||||
// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2
|
|
||||||
// These are initialized in cpu_$GOARCH.go
|
|
||||||
// and should not be changed after they are initialized.
|
|
||||||
var hwCap uint
|
|
||||||
var hwCap2 uint
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
buf, err := ioutil.ReadFile(procAuxv)
|
|
||||||
if err != nil {
|
|
||||||
// e.g. on android /proc/self/auxv is not accessible, so silently
|
|
||||||
// ignore the error and leave Initialized = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bo := hostByteOrder()
|
|
||||||
for len(buf) >= 2*(uintSize/8) {
|
|
||||||
var tag, val uint
|
|
||||||
switch uintSize {
|
|
||||||
case 32:
|
|
||||||
tag = uint(bo.Uint32(buf[0:]))
|
|
||||||
val = uint(bo.Uint32(buf[4:]))
|
|
||||||
buf = buf[8:]
|
|
||||||
case 64:
|
|
||||||
tag = uint(bo.Uint64(buf[0:]))
|
|
||||||
val = uint(bo.Uint64(buf[8:]))
|
|
||||||
buf = buf[16:]
|
|
||||||
}
|
|
||||||
switch tag {
|
|
||||||
case _AT_HWCAP:
|
|
||||||
hwCap = val
|
|
||||||
case _AT_HWCAP2:
|
|
||||||
hwCap2 = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
doinit()
|
|
||||||
|
|
||||||
Initialized = true
|
|
||||||
}
|
|
67
vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go
generated
vendored
67
vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go
generated
vendored
@ -1,67 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 64
|
|
||||||
|
|
||||||
// HWCAP/HWCAP2 bits. These are exposed by Linux.
|
|
||||||
const (
|
|
||||||
hwcap_FP = 1 << 0
|
|
||||||
hwcap_ASIMD = 1 << 1
|
|
||||||
hwcap_EVTSTRM = 1 << 2
|
|
||||||
hwcap_AES = 1 << 3
|
|
||||||
hwcap_PMULL = 1 << 4
|
|
||||||
hwcap_SHA1 = 1 << 5
|
|
||||||
hwcap_SHA2 = 1 << 6
|
|
||||||
hwcap_CRC32 = 1 << 7
|
|
||||||
hwcap_ATOMICS = 1 << 8
|
|
||||||
hwcap_FPHP = 1 << 9
|
|
||||||
hwcap_ASIMDHP = 1 << 10
|
|
||||||
hwcap_CPUID = 1 << 11
|
|
||||||
hwcap_ASIMDRDM = 1 << 12
|
|
||||||
hwcap_JSCVT = 1 << 13
|
|
||||||
hwcap_FCMA = 1 << 14
|
|
||||||
hwcap_LRCPC = 1 << 15
|
|
||||||
hwcap_DCPOP = 1 << 16
|
|
||||||
hwcap_SHA3 = 1 << 17
|
|
||||||
hwcap_SM3 = 1 << 18
|
|
||||||
hwcap_SM4 = 1 << 19
|
|
||||||
hwcap_ASIMDDP = 1 << 20
|
|
||||||
hwcap_SHA512 = 1 << 21
|
|
||||||
hwcap_SVE = 1 << 22
|
|
||||||
hwcap_ASIMDFHM = 1 << 23
|
|
||||||
)
|
|
||||||
|
|
||||||
func doinit() {
|
|
||||||
// HWCAP feature bits
|
|
||||||
ARM64.HasFP = isSet(hwCap, hwcap_FP)
|
|
||||||
ARM64.HasASIMD = isSet(hwCap, hwcap_ASIMD)
|
|
||||||
ARM64.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM)
|
|
||||||
ARM64.HasAES = isSet(hwCap, hwcap_AES)
|
|
||||||
ARM64.HasPMULL = isSet(hwCap, hwcap_PMULL)
|
|
||||||
ARM64.HasSHA1 = isSet(hwCap, hwcap_SHA1)
|
|
||||||
ARM64.HasSHA2 = isSet(hwCap, hwcap_SHA2)
|
|
||||||
ARM64.HasCRC32 = isSet(hwCap, hwcap_CRC32)
|
|
||||||
ARM64.HasATOMICS = isSet(hwCap, hwcap_ATOMICS)
|
|
||||||
ARM64.HasFPHP = isSet(hwCap, hwcap_FPHP)
|
|
||||||
ARM64.HasASIMDHP = isSet(hwCap, hwcap_ASIMDHP)
|
|
||||||
ARM64.HasCPUID = isSet(hwCap, hwcap_CPUID)
|
|
||||||
ARM64.HasASIMDRDM = isSet(hwCap, hwcap_ASIMDRDM)
|
|
||||||
ARM64.HasJSCVT = isSet(hwCap, hwcap_JSCVT)
|
|
||||||
ARM64.HasFCMA = isSet(hwCap, hwcap_FCMA)
|
|
||||||
ARM64.HasLRCPC = isSet(hwCap, hwcap_LRCPC)
|
|
||||||
ARM64.HasDCPOP = isSet(hwCap, hwcap_DCPOP)
|
|
||||||
ARM64.HasSHA3 = isSet(hwCap, hwcap_SHA3)
|
|
||||||
ARM64.HasSM3 = isSet(hwCap, hwcap_SM3)
|
|
||||||
ARM64.HasSM4 = isSet(hwCap, hwcap_SM4)
|
|
||||||
ARM64.HasASIMDDP = isSet(hwCap, hwcap_ASIMDDP)
|
|
||||||
ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512)
|
|
||||||
ARM64.HasSVE = isSet(hwCap, hwcap_SVE)
|
|
||||||
ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isSet(hwc uint, value uint) bool {
|
|
||||||
return hwc&value != 0
|
|
||||||
}
|
|
33
vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go
generated
vendored
33
vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go
generated
vendored
@ -1,33 +0,0 @@
|
|||||||
// 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 linux
|
|
||||||
// +build ppc64 ppc64le
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 128
|
|
||||||
|
|
||||||
// HWCAP/HWCAP2 bits. These are exposed by the kernel.
|
|
||||||
const (
|
|
||||||
// ISA Level
|
|
||||||
_PPC_FEATURE2_ARCH_2_07 = 0x80000000
|
|
||||||
_PPC_FEATURE2_ARCH_3_00 = 0x00800000
|
|
||||||
|
|
||||||
// CPU features
|
|
||||||
_PPC_FEATURE2_DARN = 0x00200000
|
|
||||||
_PPC_FEATURE2_SCV = 0x00100000
|
|
||||||
)
|
|
||||||
|
|
||||||
func doinit() {
|
|
||||||
// HWCAP2 feature bits
|
|
||||||
PPC64.IsPOWER8 = isSet(hwCap2, _PPC_FEATURE2_ARCH_2_07)
|
|
||||||
PPC64.IsPOWER9 = isSet(hwCap2, _PPC_FEATURE2_ARCH_3_00)
|
|
||||||
PPC64.HasDARN = isSet(hwCap2, _PPC_FEATURE2_DARN)
|
|
||||||
PPC64.HasSCV = isSet(hwCap2, _PPC_FEATURE2_SCV)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isSet(hwc uint, value uint) bool {
|
|
||||||
return hwc&value != 0
|
|
||||||
}
|
|
161
vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go
generated
vendored
161
vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go
generated
vendored
@ -1,161 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 256
|
|
||||||
|
|
||||||
const (
|
|
||||||
// bit mask values from /usr/include/bits/hwcap.h
|
|
||||||
hwcap_ZARCH = 2
|
|
||||||
hwcap_STFLE = 4
|
|
||||||
hwcap_MSA = 8
|
|
||||||
hwcap_LDISP = 16
|
|
||||||
hwcap_EIMM = 32
|
|
||||||
hwcap_DFP = 64
|
|
||||||
hwcap_ETF3EH = 256
|
|
||||||
hwcap_VX = 2048
|
|
||||||
hwcap_VXE = 8192
|
|
||||||
)
|
|
||||||
|
|
||||||
// bitIsSet reports whether the bit at index is set. The bit index
|
|
||||||
// is in big endian order, so bit index 0 is the leftmost bit.
|
|
||||||
func bitIsSet(bits []uint64, index uint) bool {
|
|
||||||
return bits[index/64]&((1<<63)>>(index%64)) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// function is the code for the named cryptographic function.
|
|
||||||
type function uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
// KM{,A,C,CTR} function codes
|
|
||||||
aes128 function = 18 // AES-128
|
|
||||||
aes192 function = 19 // AES-192
|
|
||||||
aes256 function = 20 // AES-256
|
|
||||||
|
|
||||||
// K{I,L}MD function codes
|
|
||||||
sha1 function = 1 // SHA-1
|
|
||||||
sha256 function = 2 // SHA-256
|
|
||||||
sha512 function = 3 // SHA-512
|
|
||||||
sha3_224 function = 32 // SHA3-224
|
|
||||||
sha3_256 function = 33 // SHA3-256
|
|
||||||
sha3_384 function = 34 // SHA3-384
|
|
||||||
sha3_512 function = 35 // SHA3-512
|
|
||||||
shake128 function = 36 // SHAKE-128
|
|
||||||
shake256 function = 37 // SHAKE-256
|
|
||||||
|
|
||||||
// KLMD function codes
|
|
||||||
ghash function = 65 // GHASH
|
|
||||||
)
|
|
||||||
|
|
||||||
// queryResult contains the result of a Query function
|
|
||||||
// call. Bits are numbered in big endian order so the
|
|
||||||
// leftmost bit (the MSB) is at index 0.
|
|
||||||
type queryResult struct {
|
|
||||||
bits [2]uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Has reports whether the given functions are present.
|
|
||||||
func (q *queryResult) Has(fns ...function) bool {
|
|
||||||
if len(fns) == 0 {
|
|
||||||
panic("no function codes provided")
|
|
||||||
}
|
|
||||||
for _, f := range fns {
|
|
||||||
if !bitIsSet(q.bits[:], uint(f)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// facility is a bit index for the named facility.
|
|
||||||
type facility uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
// cryptography facilities
|
|
||||||
msa4 facility = 77 // message-security-assist extension 4
|
|
||||||
msa8 facility = 146 // message-security-assist extension 8
|
|
||||||
)
|
|
||||||
|
|
||||||
// facilityList contains the result of an STFLE call.
|
|
||||||
// Bits are numbered in big endian order so the
|
|
||||||
// leftmost bit (the MSB) is at index 0.
|
|
||||||
type facilityList struct {
|
|
||||||
bits [4]uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Has reports whether the given facilities are present.
|
|
||||||
func (s *facilityList) Has(fs ...facility) bool {
|
|
||||||
if len(fs) == 0 {
|
|
||||||
panic("no facility bits provided")
|
|
||||||
}
|
|
||||||
for _, f := range fs {
|
|
||||||
if !bitIsSet(s.bits[:], uint(f)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func doinit() {
|
|
||||||
// test HWCAP bit vector
|
|
||||||
has := func(featureMask uint) bool {
|
|
||||||
return hwCap&featureMask == featureMask
|
|
||||||
}
|
|
||||||
|
|
||||||
// mandatory
|
|
||||||
S390X.HasZARCH = has(hwcap_ZARCH)
|
|
||||||
|
|
||||||
// optional
|
|
||||||
S390X.HasSTFLE = has(hwcap_STFLE)
|
|
||||||
S390X.HasLDISP = has(hwcap_LDISP)
|
|
||||||
S390X.HasEIMM = has(hwcap_EIMM)
|
|
||||||
S390X.HasETF3EH = has(hwcap_ETF3EH)
|
|
||||||
S390X.HasDFP = has(hwcap_DFP)
|
|
||||||
S390X.HasMSA = has(hwcap_MSA)
|
|
||||||
S390X.HasVX = has(hwcap_VX)
|
|
||||||
if S390X.HasVX {
|
|
||||||
S390X.HasVXE = has(hwcap_VXE)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need implementations of stfle, km and so on
|
|
||||||
// to detect cryptographic features.
|
|
||||||
if !haveAsmFunctions() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// optional cryptographic functions
|
|
||||||
if S390X.HasMSA {
|
|
||||||
aes := []function{aes128, aes192, aes256}
|
|
||||||
|
|
||||||
// cipher message
|
|
||||||
km, kmc := kmQuery(), kmcQuery()
|
|
||||||
S390X.HasAES = km.Has(aes...)
|
|
||||||
S390X.HasAESCBC = kmc.Has(aes...)
|
|
||||||
if S390X.HasSTFLE {
|
|
||||||
facilities := stfle()
|
|
||||||
if facilities.Has(msa4) {
|
|
||||||
kmctr := kmctrQuery()
|
|
||||||
S390X.HasAESCTR = kmctr.Has(aes...)
|
|
||||||
}
|
|
||||||
if facilities.Has(msa8) {
|
|
||||||
kma := kmaQuery()
|
|
||||||
S390X.HasAESGCM = kma.Has(aes...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute message digest
|
|
||||||
kimd := kimdQuery() // intermediate (no padding)
|
|
||||||
klmd := klmdQuery() // last (padding)
|
|
||||||
S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1)
|
|
||||||
S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256)
|
|
||||||
S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512)
|
|
||||||
S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist
|
|
||||||
sha3 := []function{
|
|
||||||
sha3_224, sha3_256, sha3_384, sha3_512,
|
|
||||||
shake128, shake256,
|
|
||||||
}
|
|
||||||
S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...)
|
|
||||||
}
|
|
||||||
}
|
|
11
vendor/golang.org/x/sys/cpu/cpu_mips64x.go
generated
vendored
11
vendor/golang.org/x/sys/cpu/cpu_mips64x.go
generated
vendored
@ -1,11 +0,0 @@
|
|||||||
// 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 mips64 mips64le
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 32
|
|
||||||
|
|
||||||
func doinit() {}
|
|
11
vendor/golang.org/x/sys/cpu/cpu_mipsx.go
generated
vendored
11
vendor/golang.org/x/sys/cpu/cpu_mipsx.go
generated
vendored
@ -1,11 +0,0 @@
|
|||||||
// 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 mips mipsle
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 32
|
|
||||||
|
|
||||||
func doinit() {}
|
|
11
vendor/golang.org/x/sys/cpu/cpu_other_arm64.go
generated
vendored
11
vendor/golang.org/x/sys/cpu/cpu_other_arm64.go
generated
vendored
@ -1,11 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !linux,arm64
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 64
|
|
||||||
|
|
||||||
func doinit() {}
|
|
57
vendor/golang.org/x/sys/cpu/cpu_s390x.s
generated
vendored
57
vendor/golang.org/x/sys/cpu/cpu_s390x.s
generated
vendored
@ -1,57 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !gccgo
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// func stfle() facilityList
|
|
||||||
TEXT ·stfle(SB), NOSPLIT|NOFRAME, $0-32
|
|
||||||
MOVD $ret+0(FP), R1
|
|
||||||
MOVD $3, R0 // last doubleword index to store
|
|
||||||
XC $32, (R1), (R1) // clear 4 doublewords (32 bytes)
|
|
||||||
WORD $0xb2b01000 // store facility list extended (STFLE)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func kmQuery() queryResult
|
|
||||||
TEXT ·kmQuery(SB), NOSPLIT|NOFRAME, $0-16
|
|
||||||
MOVD $0, R0 // set function code to 0 (KM-Query)
|
|
||||||
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
|
||||||
WORD $0xB92E0024 // cipher message (KM)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func kmcQuery() queryResult
|
|
||||||
TEXT ·kmcQuery(SB), NOSPLIT|NOFRAME, $0-16
|
|
||||||
MOVD $0, R0 // set function code to 0 (KMC-Query)
|
|
||||||
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
|
||||||
WORD $0xB92F0024 // cipher message with chaining (KMC)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func kmctrQuery() queryResult
|
|
||||||
TEXT ·kmctrQuery(SB), NOSPLIT|NOFRAME, $0-16
|
|
||||||
MOVD $0, R0 // set function code to 0 (KMCTR-Query)
|
|
||||||
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
|
||||||
WORD $0xB92D4024 // cipher message with counter (KMCTR)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func kmaQuery() queryResult
|
|
||||||
TEXT ·kmaQuery(SB), NOSPLIT|NOFRAME, $0-16
|
|
||||||
MOVD $0, R0 // set function code to 0 (KMA-Query)
|
|
||||||
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
|
||||||
WORD $0xb9296024 // cipher message with authentication (KMA)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func kimdQuery() queryResult
|
|
||||||
TEXT ·kimdQuery(SB), NOSPLIT|NOFRAME, $0-16
|
|
||||||
MOVD $0, R0 // set function code to 0 (KIMD-Query)
|
|
||||||
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
|
||||||
WORD $0xB93E0024 // compute intermediate message digest (KIMD)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func klmdQuery() queryResult
|
|
||||||
TEXT ·klmdQuery(SB), NOSPLIT|NOFRAME, $0-16
|
|
||||||
MOVD $0, R0 // set function code to 0 (KLMD-Query)
|
|
||||||
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
|
||||||
WORD $0xB93F0024 // compute last message digest (KLMD)
|
|
||||||
RET
|
|
15
vendor/golang.org/x/sys/cpu/cpu_wasm.go
generated
vendored
15
vendor/golang.org/x/sys/cpu/cpu_wasm.go
generated
vendored
@ -1,15 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build wasm
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
// We're compiling the cpu package for an unknown (software-abstracted) CPU.
|
|
||||||
// Make CacheLinePad an empty struct and hope that the usual struct alignment
|
|
||||||
// rules are good enough.
|
|
||||||
|
|
||||||
const cacheLineSize = 0
|
|
||||||
|
|
||||||
func doinit() {}
|
|
59
vendor/golang.org/x/sys/cpu/cpu_x86.go
generated
vendored
59
vendor/golang.org/x/sys/cpu/cpu_x86.go
generated
vendored
@ -1,59 +0,0 @@
|
|||||||
// 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 386 amd64 amd64p32
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 64
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
Initialized = true
|
|
||||||
|
|
||||||
maxID, _, _, _ := cpuid(0, 0)
|
|
||||||
|
|
||||||
if maxID < 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _, ecx1, edx1 := cpuid(1, 0)
|
|
||||||
X86.HasSSE2 = isSet(26, edx1)
|
|
||||||
|
|
||||||
X86.HasSSE3 = isSet(0, ecx1)
|
|
||||||
X86.HasPCLMULQDQ = isSet(1, ecx1)
|
|
||||||
X86.HasSSSE3 = isSet(9, ecx1)
|
|
||||||
X86.HasFMA = isSet(12, ecx1)
|
|
||||||
X86.HasSSE41 = isSet(19, ecx1)
|
|
||||||
X86.HasSSE42 = isSet(20, ecx1)
|
|
||||||
X86.HasPOPCNT = isSet(23, ecx1)
|
|
||||||
X86.HasAES = isSet(25, ecx1)
|
|
||||||
X86.HasOSXSAVE = isSet(27, ecx1)
|
|
||||||
X86.HasRDRAND = isSet(30, ecx1)
|
|
||||||
|
|
||||||
osSupportsAVX := false
|
|
||||||
// For XGETBV, OSXSAVE bit is required and sufficient.
|
|
||||||
if X86.HasOSXSAVE {
|
|
||||||
eax, _ := xgetbv()
|
|
||||||
// Check if XMM and YMM registers have OS support.
|
|
||||||
osSupportsAVX = isSet(1, eax) && isSet(2, eax)
|
|
||||||
}
|
|
||||||
|
|
||||||
X86.HasAVX = isSet(28, ecx1) && osSupportsAVX
|
|
||||||
|
|
||||||
if maxID < 7 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, ebx7, _, _ := cpuid(7, 0)
|
|
||||||
X86.HasBMI1 = isSet(3, ebx7)
|
|
||||||
X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX
|
|
||||||
X86.HasBMI2 = isSet(8, ebx7)
|
|
||||||
X86.HasERMS = isSet(9, ebx7)
|
|
||||||
X86.HasRDSEED = isSet(18, ebx7)
|
|
||||||
X86.HasADX = isSet(19, ebx7)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isSet(bitpos uint, value uint32) bool {
|
|
||||||
return value&(1<<bitpos) != 0
|
|
||||||
}
|
|
27
vendor/golang.org/x/sys/cpu/cpu_x86.s
generated
vendored
27
vendor/golang.org/x/sys/cpu/cpu_x86.s
generated
vendored
@ -1,27 +0,0 @@
|
|||||||
// 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 386 amd64 amd64p32
|
|
||||||
// +build !gccgo
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
|
||||||
TEXT ·cpuid(SB), NOSPLIT, $0-24
|
|
||||||
MOVL eaxArg+0(FP), AX
|
|
||||||
MOVL ecxArg+4(FP), CX
|
|
||||||
CPUID
|
|
||||||
MOVL AX, eax+8(FP)
|
|
||||||
MOVL BX, ebx+12(FP)
|
|
||||||
MOVL CX, ecx+16(FP)
|
|
||||||
MOVL DX, edx+20(FP)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func xgetbv() (eax, edx uint32)
|
|
||||||
TEXT ·xgetbv(SB),NOSPLIT,$0-8
|
|
||||||
MOVL $0, CX
|
|
||||||
XGETBV
|
|
||||||
MOVL AX, eax+0(FP)
|
|
||||||
MOVL DX, edx+4(FP)
|
|
||||||
RET
|
|
36
vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go
generated
vendored
36
vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go
generated
vendored
@ -1,36 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Minimal copy of x/sys/unix so the cpu package can make a
|
|
||||||
// system call on AIX without depending on x/sys/unix.
|
|
||||||
// (See golang.org/issue/32102)
|
|
||||||
|
|
||||||
// +build aix,ppc64
|
|
||||||
// +build !gccgo
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:cgo_import_dynamic libc_getsystemcfg getsystemcfg "libc.a/shr_64.o"
|
|
||||||
|
|
||||||
//go:linkname libc_getsystemcfg libc_getsystemcfg
|
|
||||||
|
|
||||||
type syscallFunc uintptr
|
|
||||||
|
|
||||||
var libc_getsystemcfg syscallFunc
|
|
||||||
|
|
||||||
type errno = syscall.Errno
|
|
||||||
|
|
||||||
// Implemented in runtime/syscall_aix.go.
|
|
||||||
func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno)
|
|
||||||
func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno)
|
|
||||||
|
|
||||||
func callgetsystemcfg(label int) (r1 uintptr, e1 errno) {
|
|
||||||
r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getsystemcfg)), 1, uintptr(label), 0, 0, 0, 0, 0)
|
|
||||||
return
|
|
||||||
}
|
|
12
vendor/gopkg.in/yaml.v2/.travis.yml
generated
vendored
12
vendor/gopkg.in/yaml.v2/.travis.yml
generated
vendored
@ -1,12 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.4
|
|
||||||
- 1.5
|
|
||||||
- 1.6
|
|
||||||
- 1.7
|
|
||||||
- 1.8
|
|
||||||
- 1.9
|
|
||||||
- tip
|
|
||||||
|
|
||||||
go_import_path: gopkg.in/yaml.v2
|
|
201
vendor/gopkg.in/yaml.v2/LICENSE
generated
vendored
201
vendor/gopkg.in/yaml.v2/LICENSE
generated
vendored
@ -1,201 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright {yyyy} {name of copyright owner}
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
31
vendor/gopkg.in/yaml.v2/LICENSE.libyaml
generated
vendored
31
vendor/gopkg.in/yaml.v2/LICENSE.libyaml
generated
vendored
@ -1,31 +0,0 @@
|
|||||||
The following files were ported to Go from C files of libyaml, and thus
|
|
||||||
are still covered by their original copyright and license:
|
|
||||||
|
|
||||||
apic.go
|
|
||||||
emitterc.go
|
|
||||||
parserc.go
|
|
||||||
readerc.go
|
|
||||||
scannerc.go
|
|
||||||
writerc.go
|
|
||||||
yamlh.go
|
|
||||||
yamlprivateh.go
|
|
||||||
|
|
||||||
Copyright (c) 2006 Kirill Simonov
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
13
vendor/gopkg.in/yaml.v2/NOTICE
generated
vendored
13
vendor/gopkg.in/yaml.v2/NOTICE
generated
vendored
@ -1,13 +0,0 @@
|
|||||||
Copyright 2011-2016 Canonical Ltd.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
133
vendor/gopkg.in/yaml.v2/README.md
generated
vendored
133
vendor/gopkg.in/yaml.v2/README.md
generated
vendored
@ -1,133 +0,0 @@
|
|||||||
# YAML support for the Go language
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
------------
|
|
||||||
|
|
||||||
The yaml package enables Go programs to comfortably encode and decode YAML
|
|
||||||
values. It was developed within [Canonical](https://www.canonical.com) as
|
|
||||||
part of the [juju](https://juju.ubuntu.com) project, and is based on a
|
|
||||||
pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML)
|
|
||||||
C library to parse and generate YAML data quickly and reliably.
|
|
||||||
|
|
||||||
Compatibility
|
|
||||||
-------------
|
|
||||||
|
|
||||||
The yaml package supports most of YAML 1.1 and 1.2, including support for
|
|
||||||
anchors, tags, map merging, etc. Multi-document unmarshalling is not yet
|
|
||||||
implemented, and base-60 floats from YAML 1.1 are purposefully not
|
|
||||||
supported since they're a poor design and are gone in YAML 1.2.
|
|
||||||
|
|
||||||
Installation and usage
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
The import path for the package is *gopkg.in/yaml.v2*.
|
|
||||||
|
|
||||||
To install it, run:
|
|
||||||
|
|
||||||
go get gopkg.in/yaml.v2
|
|
||||||
|
|
||||||
API documentation
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
If opened in a browser, the import path itself leads to the API documentation:
|
|
||||||
|
|
||||||
* [https://gopkg.in/yaml.v2](https://gopkg.in/yaml.v2)
|
|
||||||
|
|
||||||
API stability
|
|
||||||
-------------
|
|
||||||
|
|
||||||
The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in).
|
|
||||||
|
|
||||||
|
|
||||||
License
|
|
||||||
-------
|
|
||||||
|
|
||||||
The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details.
|
|
||||||
|
|
||||||
|
|
||||||
Example
|
|
||||||
-------
|
|
||||||
|
|
||||||
```Go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var data = `
|
|
||||||
a: Easy!
|
|
||||||
b:
|
|
||||||
c: 2
|
|
||||||
d: [3, 4]
|
|
||||||
`
|
|
||||||
|
|
||||||
// Note: struct fields must be public in order for unmarshal to
|
|
||||||
// correctly populate the data.
|
|
||||||
type T struct {
|
|
||||||
A string
|
|
||||||
B struct {
|
|
||||||
RenamedC int `yaml:"c"`
|
|
||||||
D []int `yaml:",flow"`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
t := T{}
|
|
||||||
|
|
||||||
err := yaml.Unmarshal([]byte(data), &t)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Printf("--- t:\n%v\n\n", t)
|
|
||||||
|
|
||||||
d, err := yaml.Marshal(&t)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Printf("--- t dump:\n%s\n\n", string(d))
|
|
||||||
|
|
||||||
m := make(map[interface{}]interface{})
|
|
||||||
|
|
||||||
err = yaml.Unmarshal([]byte(data), &m)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Printf("--- m:\n%v\n\n", m)
|
|
||||||
|
|
||||||
d, err = yaml.Marshal(&m)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Printf("--- m dump:\n%s\n\n", string(d))
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This example will generate the following output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--- t:
|
|
||||||
{Easy! {2 [3 4]}}
|
|
||||||
|
|
||||||
--- t dump:
|
|
||||||
a: Easy!
|
|
||||||
b:
|
|
||||||
c: 2
|
|
||||||
d: [3, 4]
|
|
||||||
|
|
||||||
|
|
||||||
--- m:
|
|
||||||
map[a:Easy! b:map[c:2 d:[3 4]]]
|
|
||||||
|
|
||||||
--- m dump:
|
|
||||||
a: Easy!
|
|
||||||
b:
|
|
||||||
c: 2
|
|
||||||
d:
|
|
||||||
- 3
|
|
||||||
- 4
|
|
||||||
```
|
|
||||||
|
|
739
vendor/gopkg.in/yaml.v2/apic.go
generated
vendored
739
vendor/gopkg.in/yaml.v2/apic.go
generated
vendored
@ -1,739 +0,0 @@
|
|||||||
package yaml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) {
|
|
||||||
//fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens))
|
|
||||||
|
|
||||||
// Check if we can move the queue at the beginning of the buffer.
|
|
||||||
if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) {
|
|
||||||
if parser.tokens_head != len(parser.tokens) {
|
|
||||||
copy(parser.tokens, parser.tokens[parser.tokens_head:])
|
|
||||||
}
|
|
||||||
parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head]
|
|
||||||
parser.tokens_head = 0
|
|
||||||
}
|
|
||||||
parser.tokens = append(parser.tokens, *token)
|
|
||||||
if pos < 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:])
|
|
||||||
parser.tokens[parser.tokens_head+pos] = *token
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new parser object.
|
|
||||||
func yaml_parser_initialize(parser *yaml_parser_t) bool {
|
|
||||||
*parser = yaml_parser_t{
|
|
||||||
raw_buffer: make([]byte, 0, input_raw_buffer_size),
|
|
||||||
buffer: make([]byte, 0, input_buffer_size),
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy a parser object.
|
|
||||||
func yaml_parser_delete(parser *yaml_parser_t) {
|
|
||||||
*parser = yaml_parser_t{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String read handler.
|
|
||||||
func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
|
|
||||||
if parser.input_pos == len(parser.input) {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
n = copy(buffer, parser.input[parser.input_pos:])
|
|
||||||
parser.input_pos += n
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reader read handler.
|
|
||||||
func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
|
|
||||||
return parser.input_reader.Read(buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a string input.
|
|
||||||
func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) {
|
|
||||||
if parser.read_handler != nil {
|
|
||||||
panic("must set the input source only once")
|
|
||||||
}
|
|
||||||
parser.read_handler = yaml_string_read_handler
|
|
||||||
parser.input = input
|
|
||||||
parser.input_pos = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a file input.
|
|
||||||
func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) {
|
|
||||||
if parser.read_handler != nil {
|
|
||||||
panic("must set the input source only once")
|
|
||||||
}
|
|
||||||
parser.read_handler = yaml_reader_read_handler
|
|
||||||
parser.input_reader = r
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the source encoding.
|
|
||||||
func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
|
|
||||||
if parser.encoding != yaml_ANY_ENCODING {
|
|
||||||
panic("must set the encoding only once")
|
|
||||||
}
|
|
||||||
parser.encoding = encoding
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new emitter object.
|
|
||||||
func yaml_emitter_initialize(emitter *yaml_emitter_t) {
|
|
||||||
*emitter = yaml_emitter_t{
|
|
||||||
buffer: make([]byte, output_buffer_size),
|
|
||||||
raw_buffer: make([]byte, 0, output_raw_buffer_size),
|
|
||||||
states: make([]yaml_emitter_state_t, 0, initial_stack_size),
|
|
||||||
events: make([]yaml_event_t, 0, initial_queue_size),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy an emitter object.
|
|
||||||
func yaml_emitter_delete(emitter *yaml_emitter_t) {
|
|
||||||
*emitter = yaml_emitter_t{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String write handler.
|
|
||||||
func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
|
|
||||||
*emitter.output_buffer = append(*emitter.output_buffer, buffer...)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// yaml_writer_write_handler uses emitter.output_writer to write the
|
|
||||||
// emitted text.
|
|
||||||
func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
|
|
||||||
_, err := emitter.output_writer.Write(buffer)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a string output.
|
|
||||||
func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) {
|
|
||||||
if emitter.write_handler != nil {
|
|
||||||
panic("must set the output target only once")
|
|
||||||
}
|
|
||||||
emitter.write_handler = yaml_string_write_handler
|
|
||||||
emitter.output_buffer = output_buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a file output.
|
|
||||||
func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) {
|
|
||||||
if emitter.write_handler != nil {
|
|
||||||
panic("must set the output target only once")
|
|
||||||
}
|
|
||||||
emitter.write_handler = yaml_writer_write_handler
|
|
||||||
emitter.output_writer = w
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the output encoding.
|
|
||||||
func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) {
|
|
||||||
if emitter.encoding != yaml_ANY_ENCODING {
|
|
||||||
panic("must set the output encoding only once")
|
|
||||||
}
|
|
||||||
emitter.encoding = encoding
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the canonical output style.
|
|
||||||
func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) {
|
|
||||||
emitter.canonical = canonical
|
|
||||||
}
|
|
||||||
|
|
||||||
//// Set the indentation increment.
|
|
||||||
func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) {
|
|
||||||
if indent < 2 || indent > 9 {
|
|
||||||
indent = 2
|
|
||||||
}
|
|
||||||
emitter.best_indent = indent
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the preferred line width.
|
|
||||||
func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) {
|
|
||||||
if width < 0 {
|
|
||||||
width = -1
|
|
||||||
}
|
|
||||||
emitter.best_width = width
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set if unescaped non-ASCII characters are allowed.
|
|
||||||
func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) {
|
|
||||||
emitter.unicode = unicode
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the preferred line break character.
|
|
||||||
func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) {
|
|
||||||
emitter.line_break = line_break
|
|
||||||
}
|
|
||||||
|
|
||||||
///*
|
|
||||||
// * Destroy a token object.
|
|
||||||
// */
|
|
||||||
//
|
|
||||||
//YAML_DECLARE(void)
|
|
||||||
//yaml_token_delete(yaml_token_t *token)
|
|
||||||
//{
|
|
||||||
// assert(token); // Non-NULL token object expected.
|
|
||||||
//
|
|
||||||
// switch (token.type)
|
|
||||||
// {
|
|
||||||
// case YAML_TAG_DIRECTIVE_TOKEN:
|
|
||||||
// yaml_free(token.data.tag_directive.handle);
|
|
||||||
// yaml_free(token.data.tag_directive.prefix);
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// case YAML_ALIAS_TOKEN:
|
|
||||||
// yaml_free(token.data.alias.value);
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// case YAML_ANCHOR_TOKEN:
|
|
||||||
// yaml_free(token.data.anchor.value);
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// case YAML_TAG_TOKEN:
|
|
||||||
// yaml_free(token.data.tag.handle);
|
|
||||||
// yaml_free(token.data.tag.suffix);
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// case YAML_SCALAR_TOKEN:
|
|
||||||
// yaml_free(token.data.scalar.value);
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// default:
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// memset(token, 0, sizeof(yaml_token_t));
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
///*
|
|
||||||
// * Check if a string is a valid UTF-8 sequence.
|
|
||||||
// *
|
|
||||||
// * Check 'reader.c' for more details on UTF-8 encoding.
|
|
||||||
// */
|
|
||||||
//
|
|
||||||
//static int
|
|
||||||
//yaml_check_utf8(yaml_char_t *start, size_t length)
|
|
||||||
//{
|
|
||||||
// yaml_char_t *end = start+length;
|
|
||||||
// yaml_char_t *pointer = start;
|
|
||||||
//
|
|
||||||
// while (pointer < end) {
|
|
||||||
// unsigned char octet;
|
|
||||||
// unsigned int width;
|
|
||||||
// unsigned int value;
|
|
||||||
// size_t k;
|
|
||||||
//
|
|
||||||
// octet = pointer[0];
|
|
||||||
// width = (octet & 0x80) == 0x00 ? 1 :
|
|
||||||
// (octet & 0xE0) == 0xC0 ? 2 :
|
|
||||||
// (octet & 0xF0) == 0xE0 ? 3 :
|
|
||||||
// (octet & 0xF8) == 0xF0 ? 4 : 0;
|
|
||||||
// value = (octet & 0x80) == 0x00 ? octet & 0x7F :
|
|
||||||
// (octet & 0xE0) == 0xC0 ? octet & 0x1F :
|
|
||||||
// (octet & 0xF0) == 0xE0 ? octet & 0x0F :
|
|
||||||
// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
|
|
||||||
// if (!width) return 0;
|
|
||||||
// if (pointer+width > end) return 0;
|
|
||||||
// for (k = 1; k < width; k ++) {
|
|
||||||
// octet = pointer[k];
|
|
||||||
// if ((octet & 0xC0) != 0x80) return 0;
|
|
||||||
// value = (value << 6) + (octet & 0x3F);
|
|
||||||
// }
|
|
||||||
// if (!((width == 1) ||
|
|
||||||
// (width == 2 && value >= 0x80) ||
|
|
||||||
// (width == 3 && value >= 0x800) ||
|
|
||||||
// (width == 4 && value >= 0x10000))) return 0;
|
|
||||||
//
|
|
||||||
// pointer += width;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return 1;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
|
|
||||||
// Create STREAM-START.
|
|
||||||
func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) {
|
|
||||||
*event = yaml_event_t{
|
|
||||||
typ: yaml_STREAM_START_EVENT,
|
|
||||||
encoding: encoding,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create STREAM-END.
|
|
||||||
func yaml_stream_end_event_initialize(event *yaml_event_t) {
|
|
||||||
*event = yaml_event_t{
|
|
||||||
typ: yaml_STREAM_END_EVENT,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create DOCUMENT-START.
|
|
||||||
func yaml_document_start_event_initialize(
|
|
||||||
event *yaml_event_t,
|
|
||||||
version_directive *yaml_version_directive_t,
|
|
||||||
tag_directives []yaml_tag_directive_t,
|
|
||||||
implicit bool,
|
|
||||||
) {
|
|
||||||
*event = yaml_event_t{
|
|
||||||
typ: yaml_DOCUMENT_START_EVENT,
|
|
||||||
version_directive: version_directive,
|
|
||||||
tag_directives: tag_directives,
|
|
||||||
implicit: implicit,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create DOCUMENT-END.
|
|
||||||
func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) {
|
|
||||||
*event = yaml_event_t{
|
|
||||||
typ: yaml_DOCUMENT_END_EVENT,
|
|
||||||
implicit: implicit,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///*
|
|
||||||
// * Create ALIAS.
|
|
||||||
// */
|
|
||||||
//
|
|
||||||
//YAML_DECLARE(int)
|
|
||||||
//yaml_alias_event_initialize(event *yaml_event_t, anchor *yaml_char_t)
|
|
||||||
//{
|
|
||||||
// mark yaml_mark_t = { 0, 0, 0 }
|
|
||||||
// anchor_copy *yaml_char_t = NULL
|
|
||||||
//
|
|
||||||
// assert(event) // Non-NULL event object is expected.
|
|
||||||
// assert(anchor) // Non-NULL anchor is expected.
|
|
||||||
//
|
|
||||||
// if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0
|
|
||||||
//
|
|
||||||
// anchor_copy = yaml_strdup(anchor)
|
|
||||||
// if (!anchor_copy)
|
|
||||||
// return 0
|
|
||||||
//
|
|
||||||
// ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark)
|
|
||||||
//
|
|
||||||
// return 1
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Create SCALAR.
|
|
||||||
func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool {
|
|
||||||
*event = yaml_event_t{
|
|
||||||
typ: yaml_SCALAR_EVENT,
|
|
||||||
anchor: anchor,
|
|
||||||
tag: tag,
|
|
||||||
value: value,
|
|
||||||
implicit: plain_implicit,
|
|
||||||
quoted_implicit: quoted_implicit,
|
|
||||||
style: yaml_style_t(style),
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create SEQUENCE-START.
|
|
||||||
func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool {
|
|
||||||
*event = yaml_event_t{
|
|
||||||
typ: yaml_SEQUENCE_START_EVENT,
|
|
||||||
anchor: anchor,
|
|
||||||
tag: tag,
|
|
||||||
implicit: implicit,
|
|
||||||
style: yaml_style_t(style),
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create SEQUENCE-END.
|
|
||||||
func yaml_sequence_end_event_initialize(event *yaml_event_t) bool {
|
|
||||||
*event = yaml_event_t{
|
|
||||||
typ: yaml_SEQUENCE_END_EVENT,
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create MAPPING-START.
|
|
||||||
func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) {
|
|
||||||
*event = yaml_event_t{
|
|
||||||
typ: yaml_MAPPING_START_EVENT,
|
|
||||||
anchor: anchor,
|
|
||||||
tag: tag,
|
|
||||||
implicit: implicit,
|
|
||||||
style: yaml_style_t(style),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create MAPPING-END.
|
|
||||||
func yaml_mapping_end_event_initialize(event *yaml_event_t) {
|
|
||||||
*event = yaml_event_t{
|
|
||||||
typ: yaml_MAPPING_END_EVENT,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy an event object.
|
|
||||||
func yaml_event_delete(event *yaml_event_t) {
|
|
||||||
*event = yaml_event_t{}
|
|
||||||
}
|
|
||||||
|
|
||||||
///*
|
|
||||||
// * Create a document object.
|
|
||||||
// */
|
|
||||||
//
|
|
||||||
//YAML_DECLARE(int)
|
|
||||||
//yaml_document_initialize(document *yaml_document_t,
|
|
||||||
// version_directive *yaml_version_directive_t,
|
|
||||||
// tag_directives_start *yaml_tag_directive_t,
|
|
||||||
// tag_directives_end *yaml_tag_directive_t,
|
|
||||||
// start_implicit int, end_implicit int)
|
|
||||||
//{
|
|
||||||
// struct {
|
|
||||||
// error yaml_error_type_t
|
|
||||||
// } context
|
|
||||||
// struct {
|
|
||||||
// start *yaml_node_t
|
|
||||||
// end *yaml_node_t
|
|
||||||
// top *yaml_node_t
|
|
||||||
// } nodes = { NULL, NULL, NULL }
|
|
||||||
// version_directive_copy *yaml_version_directive_t = NULL
|
|
||||||
// struct {
|
|
||||||
// start *yaml_tag_directive_t
|
|
||||||
// end *yaml_tag_directive_t
|
|
||||||
// top *yaml_tag_directive_t
|
|
||||||
// } tag_directives_copy = { NULL, NULL, NULL }
|
|
||||||
// value yaml_tag_directive_t = { NULL, NULL }
|
|
||||||
// mark yaml_mark_t = { 0, 0, 0 }
|
|
||||||
//
|
|
||||||
// assert(document) // Non-NULL document object is expected.
|
|
||||||
// assert((tag_directives_start && tag_directives_end) ||
|
|
||||||
// (tag_directives_start == tag_directives_end))
|
|
||||||
// // Valid tag directives are expected.
|
|
||||||
//
|
|
||||||
// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error
|
|
||||||
//
|
|
||||||
// if (version_directive) {
|
|
||||||
// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t))
|
|
||||||
// if (!version_directive_copy) goto error
|
|
||||||
// version_directive_copy.major = version_directive.major
|
|
||||||
// version_directive_copy.minor = version_directive.minor
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (tag_directives_start != tag_directives_end) {
|
|
||||||
// tag_directive *yaml_tag_directive_t
|
|
||||||
// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
|
|
||||||
// goto error
|
|
||||||
// for (tag_directive = tag_directives_start
|
|
||||||
// tag_directive != tag_directives_end; tag_directive ++) {
|
|
||||||
// assert(tag_directive.handle)
|
|
||||||
// assert(tag_directive.prefix)
|
|
||||||
// if (!yaml_check_utf8(tag_directive.handle,
|
|
||||||
// strlen((char *)tag_directive.handle)))
|
|
||||||
// goto error
|
|
||||||
// if (!yaml_check_utf8(tag_directive.prefix,
|
|
||||||
// strlen((char *)tag_directive.prefix)))
|
|
||||||
// goto error
|
|
||||||
// value.handle = yaml_strdup(tag_directive.handle)
|
|
||||||
// value.prefix = yaml_strdup(tag_directive.prefix)
|
|
||||||
// if (!value.handle || !value.prefix) goto error
|
|
||||||
// if (!PUSH(&context, tag_directives_copy, value))
|
|
||||||
// goto error
|
|
||||||
// value.handle = NULL
|
|
||||||
// value.prefix = NULL
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
|
|
||||||
// tag_directives_copy.start, tag_directives_copy.top,
|
|
||||||
// start_implicit, end_implicit, mark, mark)
|
|
||||||
//
|
|
||||||
// return 1
|
|
||||||
//
|
|
||||||
//error:
|
|
||||||
// STACK_DEL(&context, nodes)
|
|
||||||
// yaml_free(version_directive_copy)
|
|
||||||
// while (!STACK_EMPTY(&context, tag_directives_copy)) {
|
|
||||||
// value yaml_tag_directive_t = POP(&context, tag_directives_copy)
|
|
||||||
// yaml_free(value.handle)
|
|
||||||
// yaml_free(value.prefix)
|
|
||||||
// }
|
|
||||||
// STACK_DEL(&context, tag_directives_copy)
|
|
||||||
// yaml_free(value.handle)
|
|
||||||
// yaml_free(value.prefix)
|
|
||||||
//
|
|
||||||
// return 0
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
///*
|
|
||||||
// * Destroy a document object.
|
|
||||||
// */
|
|
||||||
//
|
|
||||||
//YAML_DECLARE(void)
|
|
||||||
//yaml_document_delete(document *yaml_document_t)
|
|
||||||
//{
|
|
||||||
// struct {
|
|
||||||
// error yaml_error_type_t
|
|
||||||
// } context
|
|
||||||
// tag_directive *yaml_tag_directive_t
|
|
||||||
//
|
|
||||||
// context.error = YAML_NO_ERROR // Eliminate a compiler warning.
|
|
||||||
//
|
|
||||||
// assert(document) // Non-NULL document object is expected.
|
|
||||||
//
|
|
||||||
// while (!STACK_EMPTY(&context, document.nodes)) {
|
|
||||||
// node yaml_node_t = POP(&context, document.nodes)
|
|
||||||
// yaml_free(node.tag)
|
|
||||||
// switch (node.type) {
|
|
||||||
// case YAML_SCALAR_NODE:
|
|
||||||
// yaml_free(node.data.scalar.value)
|
|
||||||
// break
|
|
||||||
// case YAML_SEQUENCE_NODE:
|
|
||||||
// STACK_DEL(&context, node.data.sequence.items)
|
|
||||||
// break
|
|
||||||
// case YAML_MAPPING_NODE:
|
|
||||||
// STACK_DEL(&context, node.data.mapping.pairs)
|
|
||||||
// break
|
|
||||||
// default:
|
|
||||||
// assert(0) // Should not happen.
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// STACK_DEL(&context, document.nodes)
|
|
||||||
//
|
|
||||||
// yaml_free(document.version_directive)
|
|
||||||
// for (tag_directive = document.tag_directives.start
|
|
||||||
// tag_directive != document.tag_directives.end
|
|
||||||
// tag_directive++) {
|
|
||||||
// yaml_free(tag_directive.handle)
|
|
||||||
// yaml_free(tag_directive.prefix)
|
|
||||||
// }
|
|
||||||
// yaml_free(document.tag_directives.start)
|
|
||||||
//
|
|
||||||
// memset(document, 0, sizeof(yaml_document_t))
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
///**
|
|
||||||
// * Get a document node.
|
|
||||||
// */
|
|
||||||
//
|
|
||||||
//YAML_DECLARE(yaml_node_t *)
|
|
||||||
//yaml_document_get_node(document *yaml_document_t, index int)
|
|
||||||
//{
|
|
||||||
// assert(document) // Non-NULL document object is expected.
|
|
||||||
//
|
|
||||||
// if (index > 0 && document.nodes.start + index <= document.nodes.top) {
|
|
||||||
// return document.nodes.start + index - 1
|
|
||||||
// }
|
|
||||||
// return NULL
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
///**
|
|
||||||
// * Get the root object.
|
|
||||||
// */
|
|
||||||
//
|
|
||||||
//YAML_DECLARE(yaml_node_t *)
|
|
||||||
//yaml_document_get_root_node(document *yaml_document_t)
|
|
||||||
//{
|
|
||||||
// assert(document) // Non-NULL document object is expected.
|
|
||||||
//
|
|
||||||
// if (document.nodes.top != document.nodes.start) {
|
|
||||||
// return document.nodes.start
|
|
||||||
// }
|
|
||||||
// return NULL
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
///*
|
|
||||||
// * Add a scalar node to a document.
|
|
||||||
// */
|
|
||||||
//
|
|
||||||
//YAML_DECLARE(int)
|
|
||||||
//yaml_document_add_scalar(document *yaml_document_t,
|
|
||||||
// tag *yaml_char_t, value *yaml_char_t, length int,
|
|
||||||
// style yaml_scalar_style_t)
|
|
||||||
//{
|
|
||||||
// struct {
|
|
||||||
// error yaml_error_type_t
|
|
||||||
// } context
|
|
||||||
// mark yaml_mark_t = { 0, 0, 0 }
|
|
||||||
// tag_copy *yaml_char_t = NULL
|
|
||||||
// value_copy *yaml_char_t = NULL
|
|
||||||
// node yaml_node_t
|
|
||||||
//
|
|
||||||
// assert(document) // Non-NULL document object is expected.
|
|
||||||
// assert(value) // Non-NULL value is expected.
|
|
||||||
//
|
|
||||||
// if (!tag) {
|
|
||||||
// tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
|
|
||||||
// tag_copy = yaml_strdup(tag)
|
|
||||||
// if (!tag_copy) goto error
|
|
||||||
//
|
|
||||||
// if (length < 0) {
|
|
||||||
// length = strlen((char *)value)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (!yaml_check_utf8(value, length)) goto error
|
|
||||||
// value_copy = yaml_malloc(length+1)
|
|
||||||
// if (!value_copy) goto error
|
|
||||||
// memcpy(value_copy, value, length)
|
|
||||||
// value_copy[length] = '\0'
|
|
||||||
//
|
|
||||||
// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark)
|
|
||||||
// if (!PUSH(&context, document.nodes, node)) goto error
|
|
||||||
//
|
|
||||||
// return document.nodes.top - document.nodes.start
|
|
||||||
//
|
|
||||||
//error:
|
|
||||||
// yaml_free(tag_copy)
|
|
||||||
// yaml_free(value_copy)
|
|
||||||
//
|
|
||||||
// return 0
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
///*
|
|
||||||
// * Add a sequence node to a document.
|
|
||||||
// */
|
|
||||||
//
|
|
||||||
//YAML_DECLARE(int)
|
|
||||||
//yaml_document_add_sequence(document *yaml_document_t,
|
|
||||||
// tag *yaml_char_t, style yaml_sequence_style_t)
|
|
||||||
//{
|
|
||||||
// struct {
|
|
||||||
// error yaml_error_type_t
|
|
||||||
// } context
|
|
||||||
// mark yaml_mark_t = { 0, 0, 0 }
|
|
||||||
// tag_copy *yaml_char_t = NULL
|
|
||||||
// struct {
|
|
||||||
// start *yaml_node_item_t
|
|
||||||
// end *yaml_node_item_t
|
|
||||||
// top *yaml_node_item_t
|
|
||||||
// } items = { NULL, NULL, NULL }
|
|
||||||
// node yaml_node_t
|
|
||||||
//
|
|
||||||
// assert(document) // Non-NULL document object is expected.
|
|
||||||
//
|
|
||||||
// if (!tag) {
|
|
||||||
// tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
|
|
||||||
// tag_copy = yaml_strdup(tag)
|
|
||||||
// if (!tag_copy) goto error
|
|
||||||
//
|
|
||||||
// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error
|
|
||||||
//
|
|
||||||
// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
|
|
||||||
// style, mark, mark)
|
|
||||||
// if (!PUSH(&context, document.nodes, node)) goto error
|
|
||||||
//
|
|
||||||
// return document.nodes.top - document.nodes.start
|
|
||||||
//
|
|
||||||
//error:
|
|
||||||
// STACK_DEL(&context, items)
|
|
||||||
// yaml_free(tag_copy)
|
|
||||||
//
|
|
||||||
// return 0
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
///*
|
|
||||||
// * Add a mapping node to a document.
|
|
||||||
// */
|
|
||||||
//
|
|
||||||
//YAML_DECLARE(int)
|
|
||||||
//yaml_document_add_mapping(document *yaml_document_t,
|
|
||||||
// tag *yaml_char_t, style yaml_mapping_style_t)
|
|
||||||
//{
|
|
||||||
// struct {
|
|
||||||
// error yaml_error_type_t
|
|
||||||
// } context
|
|
||||||
// mark yaml_mark_t = { 0, 0, 0 }
|
|
||||||
// tag_copy *yaml_char_t = NULL
|
|
||||||
// struct {
|
|
||||||
// start *yaml_node_pair_t
|
|
||||||
// end *yaml_node_pair_t
|
|
||||||
// top *yaml_node_pair_t
|
|
||||||
// } pairs = { NULL, NULL, NULL }
|
|
||||||
// node yaml_node_t
|
|
||||||
//
|
|
||||||
// assert(document) // Non-NULL document object is expected.
|
|
||||||
//
|
|
||||||
// if (!tag) {
|
|
||||||
// tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
|
|
||||||
// tag_copy = yaml_strdup(tag)
|
|
||||||
// if (!tag_copy) goto error
|
|
||||||
//
|
|
||||||
// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error
|
|
||||||
//
|
|
||||||
// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
|
|
||||||
// style, mark, mark)
|
|
||||||
// if (!PUSH(&context, document.nodes, node)) goto error
|
|
||||||
//
|
|
||||||
// return document.nodes.top - document.nodes.start
|
|
||||||
//
|
|
||||||
//error:
|
|
||||||
// STACK_DEL(&context, pairs)
|
|
||||||
// yaml_free(tag_copy)
|
|
||||||
//
|
|
||||||
// return 0
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
///*
|
|
||||||
// * Append an item to a sequence node.
|
|
||||||
// */
|
|
||||||
//
|
|
||||||
//YAML_DECLARE(int)
|
|
||||||
//yaml_document_append_sequence_item(document *yaml_document_t,
|
|
||||||
// sequence int, item int)
|
|
||||||
//{
|
|
||||||
// struct {
|
|
||||||
// error yaml_error_type_t
|
|
||||||
// } context
|
|
||||||
//
|
|
||||||
// assert(document) // Non-NULL document is required.
|
|
||||||
// assert(sequence > 0
|
|
||||||
// && document.nodes.start + sequence <= document.nodes.top)
|
|
||||||
// // Valid sequence id is required.
|
|
||||||
// assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE)
|
|
||||||
// // A sequence node is required.
|
|
||||||
// assert(item > 0 && document.nodes.start + item <= document.nodes.top)
|
|
||||||
// // Valid item id is required.
|
|
||||||
//
|
|
||||||
// if (!PUSH(&context,
|
|
||||||
// document.nodes.start[sequence-1].data.sequence.items, item))
|
|
||||||
// return 0
|
|
||||||
//
|
|
||||||
// return 1
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
///*
|
|
||||||
// * Append a pair of a key and a value to a mapping node.
|
|
||||||
// */
|
|
||||||
//
|
|
||||||
//YAML_DECLARE(int)
|
|
||||||
//yaml_document_append_mapping_pair(document *yaml_document_t,
|
|
||||||
// mapping int, key int, value int)
|
|
||||||
//{
|
|
||||||
// struct {
|
|
||||||
// error yaml_error_type_t
|
|
||||||
// } context
|
|
||||||
//
|
|
||||||
// pair yaml_node_pair_t
|
|
||||||
//
|
|
||||||
// assert(document) // Non-NULL document is required.
|
|
||||||
// assert(mapping > 0
|
|
||||||
// && document.nodes.start + mapping <= document.nodes.top)
|
|
||||||
// // Valid mapping id is required.
|
|
||||||
// assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE)
|
|
||||||
// // A mapping node is required.
|
|
||||||
// assert(key > 0 && document.nodes.start + key <= document.nodes.top)
|
|
||||||
// // Valid key id is required.
|
|
||||||
// assert(value > 0 && document.nodes.start + value <= document.nodes.top)
|
|
||||||
// // Valid value id is required.
|
|
||||||
//
|
|
||||||
// pair.key = key
|
|
||||||
// pair.value = value
|
|
||||||
//
|
|
||||||
// if (!PUSH(&context,
|
|
||||||
// document.nodes.start[mapping-1].data.mapping.pairs, pair))
|
|
||||||
// return 0
|
|
||||||
//
|
|
||||||
// return 1
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//
|
|
775
vendor/gopkg.in/yaml.v2/decode.go
generated
vendored
775
vendor/gopkg.in/yaml.v2/decode.go
generated
vendored
@ -1,775 +0,0 @@
|
|||||||
package yaml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding"
|
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
documentNode = 1 << iota
|
|
||||||
mappingNode
|
|
||||||
sequenceNode
|
|
||||||
scalarNode
|
|
||||||
aliasNode
|
|
||||||
)
|
|
||||||
|
|
||||||
type node struct {
|
|
||||||
kind int
|
|
||||||
line, column int
|
|
||||||
tag string
|
|
||||||
// For an alias node, alias holds the resolved alias.
|
|
||||||
alias *node
|
|
||||||
value string
|
|
||||||
implicit bool
|
|
||||||
children []*node
|
|
||||||
anchors map[string]*node
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Parser, produces a node tree out of a libyaml event stream.
|
|
||||||
|
|
||||||
type parser struct {
|
|
||||||
parser yaml_parser_t
|
|
||||||
event yaml_event_t
|
|
||||||
doc *node
|
|
||||||
doneInit bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newParser(b []byte) *parser {
|
|
||||||
p := parser{}
|
|
||||||
if !yaml_parser_initialize(&p.parser) {
|
|
||||||
panic("failed to initialize YAML emitter")
|
|
||||||
}
|
|
||||||
if len(b) == 0 {
|
|
||||||
b = []byte{'\n'}
|
|
||||||
}
|
|
||||||
yaml_parser_set_input_string(&p.parser, b)
|
|
||||||
return &p
|
|
||||||
}
|
|
||||||
|
|
||||||
func newParserFromReader(r io.Reader) *parser {
|
|
||||||
p := parser{}
|
|
||||||
if !yaml_parser_initialize(&p.parser) {
|
|
||||||
panic("failed to initialize YAML emitter")
|
|
||||||
}
|
|
||||||
yaml_parser_set_input_reader(&p.parser, r)
|
|
||||||
return &p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parser) init() {
|
|
||||||
if p.doneInit {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.expect(yaml_STREAM_START_EVENT)
|
|
||||||
p.doneInit = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parser) destroy() {
|
|
||||||
if p.event.typ != yaml_NO_EVENT {
|
|
||||||
yaml_event_delete(&p.event)
|
|
||||||
}
|
|
||||||
yaml_parser_delete(&p.parser)
|
|
||||||
}
|
|
||||||
|
|
||||||
// expect consumes an event from the event stream and
|
|
||||||
// checks that it's of the expected type.
|
|
||||||
func (p *parser) expect(e yaml_event_type_t) {
|
|
||||||
if p.event.typ == yaml_NO_EVENT {
|
|
||||||
if !yaml_parser_parse(&p.parser, &p.event) {
|
|
||||||
p.fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if p.event.typ == yaml_STREAM_END_EVENT {
|
|
||||||
failf("attempted to go past the end of stream; corrupted value?")
|
|
||||||
}
|
|
||||||
if p.event.typ != e {
|
|
||||||
p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
|
|
||||||
p.fail()
|
|
||||||
}
|
|
||||||
yaml_event_delete(&p.event)
|
|
||||||
p.event.typ = yaml_NO_EVENT
|
|
||||||
}
|
|
||||||
|
|
||||||
// peek peeks at the next event in the event stream,
|
|
||||||
// puts the results into p.event and returns the event type.
|
|
||||||
func (p *parser) peek() yaml_event_type_t {
|
|
||||||
if p.event.typ != yaml_NO_EVENT {
|
|
||||||
return p.event.typ
|
|
||||||
}
|
|
||||||
if !yaml_parser_parse(&p.parser, &p.event) {
|
|
||||||
p.fail()
|
|
||||||
}
|
|
||||||
return p.event.typ
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parser) fail() {
|
|
||||||
var where string
|
|
||||||
var line int
|
|
||||||
if p.parser.problem_mark.line != 0 {
|
|
||||||
line = p.parser.problem_mark.line
|
|
||||||
// Scanner errors don't iterate line before returning error
|
|
||||||
if p.parser.error == yaml_SCANNER_ERROR {
|
|
||||||
line++
|
|
||||||
}
|
|
||||||
} else if p.parser.context_mark.line != 0 {
|
|
||||||
line = p.parser.context_mark.line
|
|
||||||
}
|
|
||||||
if line != 0 {
|
|
||||||
where = "line " + strconv.Itoa(line) + ": "
|
|
||||||
}
|
|
||||||
var msg string
|
|
||||||
if len(p.parser.problem) > 0 {
|
|
||||||
msg = p.parser.problem
|
|
||||||
} else {
|
|
||||||
msg = "unknown problem parsing YAML content"
|
|
||||||
}
|
|
||||||
failf("%s%s", where, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parser) anchor(n *node, anchor []byte) {
|
|
||||||
if anchor != nil {
|
|
||||||
p.doc.anchors[string(anchor)] = n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parser) parse() *node {
|
|
||||||
p.init()
|
|
||||||
switch p.peek() {
|
|
||||||
case yaml_SCALAR_EVENT:
|
|
||||||
return p.scalar()
|
|
||||||
case yaml_ALIAS_EVENT:
|
|
||||||
return p.alias()
|
|
||||||
case yaml_MAPPING_START_EVENT:
|
|
||||||
return p.mapping()
|
|
||||||
case yaml_SEQUENCE_START_EVENT:
|
|
||||||
return p.sequence()
|
|
||||||
case yaml_DOCUMENT_START_EVENT:
|
|
||||||
return p.document()
|
|
||||||
case yaml_STREAM_END_EVENT:
|
|
||||||
// Happens when attempting to decode an empty buffer.
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
panic("attempted to parse unknown event: " + p.event.typ.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parser) node(kind int) *node {
|
|
||||||
return &node{
|
|
||||||
kind: kind,
|
|
||||||
line: p.event.start_mark.line,
|
|
||||||
column: p.event.start_mark.column,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parser) document() *node {
|
|
||||||
n := p.node(documentNode)
|
|
||||||
n.anchors = make(map[string]*node)
|
|
||||||
p.doc = n
|
|
||||||
p.expect(yaml_DOCUMENT_START_EVENT)
|
|
||||||
n.children = append(n.children, p.parse())
|
|
||||||
p.expect(yaml_DOCUMENT_END_EVENT)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parser) alias() *node {
|
|
||||||
n := p.node(aliasNode)
|
|
||||||
n.value = string(p.event.anchor)
|
|
||||||
n.alias = p.doc.anchors[n.value]
|
|
||||||
if n.alias == nil {
|
|
||||||
failf("unknown anchor '%s' referenced", n.value)
|
|
||||||
}
|
|
||||||
p.expect(yaml_ALIAS_EVENT)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parser) scalar() *node {
|
|
||||||
n := p.node(scalarNode)
|
|
||||||
n.value = string(p.event.value)
|
|
||||||
n.tag = string(p.event.tag)
|
|
||||||
n.implicit = p.event.implicit
|
|
||||||
p.anchor(n, p.event.anchor)
|
|
||||||
p.expect(yaml_SCALAR_EVENT)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parser) sequence() *node {
|
|
||||||
n := p.node(sequenceNode)
|
|
||||||
p.anchor(n, p.event.anchor)
|
|
||||||
p.expect(yaml_SEQUENCE_START_EVENT)
|
|
||||||
for p.peek() != yaml_SEQUENCE_END_EVENT {
|
|
||||||
n.children = append(n.children, p.parse())
|
|
||||||
}
|
|
||||||
p.expect(yaml_SEQUENCE_END_EVENT)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parser) mapping() *node {
|
|
||||||
n := p.node(mappingNode)
|
|
||||||
p.anchor(n, p.event.anchor)
|
|
||||||
p.expect(yaml_MAPPING_START_EVENT)
|
|
||||||
for p.peek() != yaml_MAPPING_END_EVENT {
|
|
||||||
n.children = append(n.children, p.parse(), p.parse())
|
|
||||||
}
|
|
||||||
p.expect(yaml_MAPPING_END_EVENT)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Decoder, unmarshals a node into a provided value.
|
|
||||||
|
|
||||||
type decoder struct {
|
|
||||||
doc *node
|
|
||||||
aliases map[*node]bool
|
|
||||||
mapType reflect.Type
|
|
||||||
terrors []string
|
|
||||||
strict bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
mapItemType = reflect.TypeOf(MapItem{})
|
|
||||||
durationType = reflect.TypeOf(time.Duration(0))
|
|
||||||
defaultMapType = reflect.TypeOf(map[interface{}]interface{}{})
|
|
||||||
ifaceType = defaultMapType.Elem()
|
|
||||||
timeType = reflect.TypeOf(time.Time{})
|
|
||||||
ptrTimeType = reflect.TypeOf(&time.Time{})
|
|
||||||
)
|
|
||||||
|
|
||||||
func newDecoder(strict bool) *decoder {
|
|
||||||
d := &decoder{mapType: defaultMapType, strict: strict}
|
|
||||||
d.aliases = make(map[*node]bool)
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *decoder) terror(n *node, tag string, out reflect.Value) {
|
|
||||||
if n.tag != "" {
|
|
||||||
tag = n.tag
|
|
||||||
}
|
|
||||||
value := n.value
|
|
||||||
if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG {
|
|
||||||
if len(value) > 10 {
|
|
||||||
value = " `" + value[:7] + "...`"
|
|
||||||
} else {
|
|
||||||
value = " `" + value + "`"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) {
|
|
||||||
terrlen := len(d.terrors)
|
|
||||||
err := u.UnmarshalYAML(func(v interface{}) (err error) {
|
|
||||||
defer handleErr(&err)
|
|
||||||
d.unmarshal(n, reflect.ValueOf(v))
|
|
||||||
if len(d.terrors) > terrlen {
|
|
||||||
issues := d.terrors[terrlen:]
|
|
||||||
d.terrors = d.terrors[:terrlen]
|
|
||||||
return &TypeError{issues}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if e, ok := err.(*TypeError); ok {
|
|
||||||
d.terrors = append(d.terrors, e.Errors...)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
fail(err)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// d.prepare initializes and dereferences pointers and calls UnmarshalYAML
|
|
||||||
// if a value is found to implement it.
|
|
||||||
// It returns the initialized and dereferenced out value, whether
|
|
||||||
// unmarshalling was already done by UnmarshalYAML, and if so whether
|
|
||||||
// its types unmarshalled appropriately.
|
|
||||||
//
|
|
||||||
// If n holds a null value, prepare returns before doing anything.
|
|
||||||
func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
|
|
||||||
if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) {
|
|
||||||
return out, false, false
|
|
||||||
}
|
|
||||||
again := true
|
|
||||||
for again {
|
|
||||||
again = false
|
|
||||||
if out.Kind() == reflect.Ptr {
|
|
||||||
if out.IsNil() {
|
|
||||||
out.Set(reflect.New(out.Type().Elem()))
|
|
||||||
}
|
|
||||||
out = out.Elem()
|
|
||||||
again = true
|
|
||||||
}
|
|
||||||
if out.CanAddr() {
|
|
||||||
if u, ok := out.Addr().Interface().(Unmarshaler); ok {
|
|
||||||
good = d.callUnmarshaler(n, u)
|
|
||||||
return out, true, good
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out, false, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) {
|
|
||||||
switch n.kind {
|
|
||||||
case documentNode:
|
|
||||||
return d.document(n, out)
|
|
||||||
case aliasNode:
|
|
||||||
return d.alias(n, out)
|
|
||||||
}
|
|
||||||
out, unmarshaled, good := d.prepare(n, out)
|
|
||||||
if unmarshaled {
|
|
||||||
return good
|
|
||||||
}
|
|
||||||
switch n.kind {
|
|
||||||
case scalarNode:
|
|
||||||
good = d.scalar(n, out)
|
|
||||||
case mappingNode:
|
|
||||||
good = d.mapping(n, out)
|
|
||||||
case sequenceNode:
|
|
||||||
good = d.sequence(n, out)
|
|
||||||
default:
|
|
||||||
panic("internal error: unknown node kind: " + strconv.Itoa(n.kind))
|
|
||||||
}
|
|
||||||
return good
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *decoder) document(n *node, out reflect.Value) (good bool) {
|
|
||||||
if len(n.children) == 1 {
|
|
||||||
d.doc = n
|
|
||||||
d.unmarshal(n.children[0], out)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *decoder) alias(n *node, out reflect.Value) (good bool) {
|
|
||||||
if d.aliases[n] {
|
|
||||||
// TODO this could actually be allowed in some circumstances.
|
|
||||||
failf("anchor '%s' value contains itself", n.value)
|
|
||||||
}
|
|
||||||
d.aliases[n] = true
|
|
||||||
good = d.unmarshal(n.alias, out)
|
|
||||||
delete(d.aliases, n)
|
|
||||||
return good
|
|
||||||
}
|
|
||||||
|
|
||||||
var zeroValue reflect.Value
|
|
||||||
|
|
||||||
func resetMap(out reflect.Value) {
|
|
||||||
for _, k := range out.MapKeys() {
|
|
||||||
out.SetMapIndex(k, zeroValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *decoder) scalar(n *node, out reflect.Value) bool {
|
|
||||||
var tag string
|
|
||||||
var resolved interface{}
|
|
||||||
if n.tag == "" && !n.implicit {
|
|
||||||
tag = yaml_STR_TAG
|
|
||||||
resolved = n.value
|
|
||||||
} else {
|
|
||||||
tag, resolved = resolve(n.tag, n.value)
|
|
||||||
if tag == yaml_BINARY_TAG {
|
|
||||||
data, err := base64.StdEncoding.DecodeString(resolved.(string))
|
|
||||||
if err != nil {
|
|
||||||
failf("!!binary value contains invalid base64 data")
|
|
||||||
}
|
|
||||||
resolved = string(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if resolved == nil {
|
|
||||||
if out.Kind() == reflect.Map && !out.CanAddr() {
|
|
||||||
resetMap(out)
|
|
||||||
} else {
|
|
||||||
out.Set(reflect.Zero(out.Type()))
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
|
|
||||||
// We've resolved to exactly the type we want, so use that.
|
|
||||||
out.Set(resolvedv)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Perhaps we can use the value as a TextUnmarshaler to
|
|
||||||
// set its value.
|
|
||||||
if out.CanAddr() {
|
|
||||||
u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)
|
|
||||||
if ok {
|
|
||||||
var text []byte
|
|
||||||
if tag == yaml_BINARY_TAG {
|
|
||||||
text = []byte(resolved.(string))
|
|
||||||
} else {
|
|
||||||
// We let any value be unmarshaled into TextUnmarshaler.
|
|
||||||
// That might be more lax than we'd like, but the
|
|
||||||
// TextUnmarshaler itself should bowl out any dubious values.
|
|
||||||
text = []byte(n.value)
|
|
||||||
}
|
|
||||||
err := u.UnmarshalText(text)
|
|
||||||
if err != nil {
|
|
||||||
fail(err)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch out.Kind() {
|
|
||||||
case reflect.String:
|
|
||||||
if tag == yaml_BINARY_TAG {
|
|
||||||
out.SetString(resolved.(string))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if resolved != nil {
|
|
||||||
out.SetString(n.value)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case reflect.Interface:
|
|
||||||
if resolved == nil {
|
|
||||||
out.Set(reflect.Zero(out.Type()))
|
|
||||||
} else if tag == yaml_TIMESTAMP_TAG {
|
|
||||||
// It looks like a timestamp but for backward compatibility
|
|
||||||
// reasons we set it as a string, so that code that unmarshals
|
|
||||||
// timestamp-like values into interface{} will continue to
|
|
||||||
// see a string and not a time.Time.
|
|
||||||
// TODO(v3) Drop this.
|
|
||||||
out.Set(reflect.ValueOf(n.value))
|
|
||||||
} else {
|
|
||||||
out.Set(reflect.ValueOf(resolved))
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
switch resolved := resolved.(type) {
|
|
||||||
case int:
|
|
||||||
if !out.OverflowInt(int64(resolved)) {
|
|
||||||
out.SetInt(int64(resolved))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case int64:
|
|
||||||
if !out.OverflowInt(resolved) {
|
|
||||||
out.SetInt(resolved)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case uint64:
|
|
||||||
if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
|
|
||||||
out.SetInt(int64(resolved))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case float64:
|
|
||||||
if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
|
|
||||||
out.SetInt(int64(resolved))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case string:
|
|
||||||
if out.Type() == durationType {
|
|
||||||
d, err := time.ParseDuration(resolved)
|
|
||||||
if err == nil {
|
|
||||||
out.SetInt(int64(d))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
switch resolved := resolved.(type) {
|
|
||||||
case int:
|
|
||||||
if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
|
|
||||||
out.SetUint(uint64(resolved))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case int64:
|
|
||||||
if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
|
|
||||||
out.SetUint(uint64(resolved))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case uint64:
|
|
||||||
if !out.OverflowUint(uint64(resolved)) {
|
|
||||||
out.SetUint(uint64(resolved))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case float64:
|
|
||||||
if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
|
|
||||||
out.SetUint(uint64(resolved))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case reflect.Bool:
|
|
||||||
switch resolved := resolved.(type) {
|
|
||||||
case bool:
|
|
||||||
out.SetBool(resolved)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
switch resolved := resolved.(type) {
|
|
||||||
case int:
|
|
||||||
out.SetFloat(float64(resolved))
|
|
||||||
return true
|
|
||||||
case int64:
|
|
||||||
out.SetFloat(float64(resolved))
|
|
||||||
return true
|
|
||||||
case uint64:
|
|
||||||
out.SetFloat(float64(resolved))
|
|
||||||
return true
|
|
||||||
case float64:
|
|
||||||
out.SetFloat(resolved)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case reflect.Struct:
|
|
||||||
if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
|
|
||||||
out.Set(resolvedv)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case reflect.Ptr:
|
|
||||||
if out.Type().Elem() == reflect.TypeOf(resolved) {
|
|
||||||
// TODO DOes this make sense? When is out a Ptr except when decoding a nil value?
|
|
||||||
elem := reflect.New(out.Type().Elem())
|
|
||||||
elem.Elem().Set(reflect.ValueOf(resolved))
|
|
||||||
out.Set(elem)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.terror(n, tag, out)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func settableValueOf(i interface{}) reflect.Value {
|
|
||||||
v := reflect.ValueOf(i)
|
|
||||||
sv := reflect.New(v.Type()).Elem()
|
|
||||||
sv.Set(v)
|
|
||||||
return sv
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *decoder) sequence(n *node, out reflect.Value) (good bool) {
|
|
||||||
l := len(n.children)
|
|
||||||
|
|
||||||
var iface reflect.Value
|
|
||||||
switch out.Kind() {
|
|
||||||
case reflect.Slice:
|
|
||||||
out.Set(reflect.MakeSlice(out.Type(), l, l))
|
|
||||||
case reflect.Array:
|
|
||||||
if l != out.Len() {
|
|
||||||
failf("invalid array: want %d elements but got %d", out.Len(), l)
|
|
||||||
}
|
|
||||||
case reflect.Interface:
|
|
||||||
// No type hints. Will have to use a generic sequence.
|
|
||||||
iface = out
|
|
||||||
out = settableValueOf(make([]interface{}, l))
|
|
||||||
default:
|
|
||||||
d.terror(n, yaml_SEQ_TAG, out)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
et := out.Type().Elem()
|
|
||||||
|
|
||||||
j := 0
|
|
||||||
for i := 0; i < l; i++ {
|
|
||||||
e := reflect.New(et).Elem()
|
|
||||||
if ok := d.unmarshal(n.children[i], e); ok {
|
|
||||||
out.Index(j).Set(e)
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if out.Kind() != reflect.Array {
|
|
||||||
out.Set(out.Slice(0, j))
|
|
||||||
}
|
|
||||||
if iface.IsValid() {
|
|
||||||
iface.Set(out)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *decoder) mapping(n *node, out reflect.Value) (good bool) {
|
|
||||||
switch out.Kind() {
|
|
||||||
case reflect.Struct:
|
|
||||||
return d.mappingStruct(n, out)
|
|
||||||
case reflect.Slice:
|
|
||||||
return d.mappingSlice(n, out)
|
|
||||||
case reflect.Map:
|
|
||||||
// okay
|
|
||||||
case reflect.Interface:
|
|
||||||
if d.mapType.Kind() == reflect.Map {
|
|
||||||
iface := out
|
|
||||||
out = reflect.MakeMap(d.mapType)
|
|
||||||
iface.Set(out)
|
|
||||||
} else {
|
|
||||||
slicev := reflect.New(d.mapType).Elem()
|
|
||||||
if !d.mappingSlice(n, slicev) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
out.Set(slicev)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
d.terror(n, yaml_MAP_TAG, out)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
outt := out.Type()
|
|
||||||
kt := outt.Key()
|
|
||||||
et := outt.Elem()
|
|
||||||
|
|
||||||
mapType := d.mapType
|
|
||||||
if outt.Key() == ifaceType && outt.Elem() == ifaceType {
|
|
||||||
d.mapType = outt
|
|
||||||
}
|
|
||||||
|
|
||||||
if out.IsNil() {
|
|
||||||
out.Set(reflect.MakeMap(outt))
|
|
||||||
}
|
|
||||||
l := len(n.children)
|
|
||||||
for i := 0; i < l; i += 2 {
|
|
||||||
if isMerge(n.children[i]) {
|
|
||||||
d.merge(n.children[i+1], out)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
k := reflect.New(kt).Elem()
|
|
||||||
if d.unmarshal(n.children[i], k) {
|
|
||||||
kkind := k.Kind()
|
|
||||||
if kkind == reflect.Interface {
|
|
||||||
kkind = k.Elem().Kind()
|
|
||||||
}
|
|
||||||
if kkind == reflect.Map || kkind == reflect.Slice {
|
|
||||||
failf("invalid map key: %#v", k.Interface())
|
|
||||||
}
|
|
||||||
e := reflect.New(et).Elem()
|
|
||||||
if d.unmarshal(n.children[i+1], e) {
|
|
||||||
d.setMapIndex(n.children[i+1], out, k, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.mapType = mapType
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *decoder) setMapIndex(n *node, out, k, v reflect.Value) {
|
|
||||||
if d.strict && out.MapIndex(k) != zeroValue {
|
|
||||||
d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.line+1, k.Interface()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
out.SetMapIndex(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) {
|
|
||||||
outt := out.Type()
|
|
||||||
if outt.Elem() != mapItemType {
|
|
||||||
d.terror(n, yaml_MAP_TAG, out)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
mapType := d.mapType
|
|
||||||
d.mapType = outt
|
|
||||||
|
|
||||||
var slice []MapItem
|
|
||||||
var l = len(n.children)
|
|
||||||
for i := 0; i < l; i += 2 {
|
|
||||||
if isMerge(n.children[i]) {
|
|
||||||
d.merge(n.children[i+1], out)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
item := MapItem{}
|
|
||||||
k := reflect.ValueOf(&item.Key).Elem()
|
|
||||||
if d.unmarshal(n.children[i], k) {
|
|
||||||
v := reflect.ValueOf(&item.Value).Elem()
|
|
||||||
if d.unmarshal(n.children[i+1], v) {
|
|
||||||
slice = append(slice, item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.Set(reflect.ValueOf(slice))
|
|
||||||
d.mapType = mapType
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
|
|
||||||
sinfo, err := getStructInfo(out.Type())
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
name := settableValueOf("")
|
|
||||||
l := len(n.children)
|
|
||||||
|
|
||||||
var inlineMap reflect.Value
|
|
||||||
var elemType reflect.Type
|
|
||||||
if sinfo.InlineMap != -1 {
|
|
||||||
inlineMap = out.Field(sinfo.InlineMap)
|
|
||||||
inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
|
|
||||||
elemType = inlineMap.Type().Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
var doneFields []bool
|
|
||||||
if d.strict {
|
|
||||||
doneFields = make([]bool, len(sinfo.FieldsList))
|
|
||||||
}
|
|
||||||
for i := 0; i < l; i += 2 {
|
|
||||||
ni := n.children[i]
|
|
||||||
if isMerge(ni) {
|
|
||||||
d.merge(n.children[i+1], out)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !d.unmarshal(ni, name) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if info, ok := sinfo.FieldsMap[name.String()]; ok {
|
|
||||||
if d.strict {
|
|
||||||
if doneFields[info.Id] {
|
|
||||||
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.line+1, name.String(), out.Type()))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
doneFields[info.Id] = true
|
|
||||||
}
|
|
||||||
var field reflect.Value
|
|
||||||
if info.Inline == nil {
|
|
||||||
field = out.Field(info.Num)
|
|
||||||
} else {
|
|
||||||
field = out.FieldByIndex(info.Inline)
|
|
||||||
}
|
|
||||||
d.unmarshal(n.children[i+1], field)
|
|
||||||
} else if sinfo.InlineMap != -1 {
|
|
||||||
if inlineMap.IsNil() {
|
|
||||||
inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
|
|
||||||
}
|
|
||||||
value := reflect.New(elemType).Elem()
|
|
||||||
d.unmarshal(n.children[i+1], value)
|
|
||||||
d.setMapIndex(n.children[i+1], inlineMap, name, value)
|
|
||||||
} else if d.strict {
|
|
||||||
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.line+1, name.String(), out.Type()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func failWantMap() {
|
|
||||||
failf("map merge requires map or sequence of maps as the value")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *decoder) merge(n *node, out reflect.Value) {
|
|
||||||
switch n.kind {
|
|
||||||
case mappingNode:
|
|
||||||
d.unmarshal(n, out)
|
|
||||||
case aliasNode:
|
|
||||||
an, ok := d.doc.anchors[n.value]
|
|
||||||
if ok && an.kind != mappingNode {
|
|
||||||
failWantMap()
|
|
||||||
}
|
|
||||||
d.unmarshal(n, out)
|
|
||||||
case sequenceNode:
|
|
||||||
// Step backwards as earlier nodes take precedence.
|
|
||||||
for i := len(n.children) - 1; i >= 0; i-- {
|
|
||||||
ni := n.children[i]
|
|
||||||
if ni.kind == aliasNode {
|
|
||||||
an, ok := d.doc.anchors[ni.value]
|
|
||||||
if ok && an.kind != mappingNode {
|
|
||||||
failWantMap()
|
|
||||||
}
|
|
||||||
} else if ni.kind != mappingNode {
|
|
||||||
failWantMap()
|
|
||||||
}
|
|
||||||
d.unmarshal(ni, out)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
failWantMap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isMerge(n *node) bool {
|
|
||||||
return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG)
|
|
||||||
}
|
|
1685
vendor/gopkg.in/yaml.v2/emitterc.go
generated
vendored
1685
vendor/gopkg.in/yaml.v2/emitterc.go
generated
vendored
File diff suppressed because it is too large
Load Diff
390
vendor/gopkg.in/yaml.v2/encode.go
generated
vendored
390
vendor/gopkg.in/yaml.v2/encode.go
generated
vendored
@ -1,390 +0,0 @@
|
|||||||
package yaml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// jsonNumber is the interface of the encoding/json.Number datatype.
|
|
||||||
// Repeating the interface here avoids a dependency on encoding/json, and also
|
|
||||||
// supports other libraries like jsoniter, which use a similar datatype with
|
|
||||||
// the same interface. Detecting this interface is useful when dealing with
|
|
||||||
// structures containing json.Number, which is a string under the hood. The
|
|
||||||
// encoder should prefer the use of Int64(), Float64() and string(), in that
|
|
||||||
// order, when encoding this type.
|
|
||||||
type jsonNumber interface {
|
|
||||||
Float64() (float64, error)
|
|
||||||
Int64() (int64, error)
|
|
||||||
String() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type encoder struct {
|
|
||||||
emitter yaml_emitter_t
|
|
||||||
event yaml_event_t
|
|
||||||
out []byte
|
|
||||||
flow bool
|
|
||||||
// doneInit holds whether the initial stream_start_event has been
|
|
||||||
// emitted.
|
|
||||||
doneInit bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newEncoder() *encoder {
|
|
||||||
e := &encoder{}
|
|
||||||
yaml_emitter_initialize(&e.emitter)
|
|
||||||
yaml_emitter_set_output_string(&e.emitter, &e.out)
|
|
||||||
yaml_emitter_set_unicode(&e.emitter, true)
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
func newEncoderWithWriter(w io.Writer) *encoder {
|
|
||||||
e := &encoder{}
|
|
||||||
yaml_emitter_initialize(&e.emitter)
|
|
||||||
yaml_emitter_set_output_writer(&e.emitter, w)
|
|
||||||
yaml_emitter_set_unicode(&e.emitter, true)
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) init() {
|
|
||||||
if e.doneInit {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)
|
|
||||||
e.emit()
|
|
||||||
e.doneInit = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) finish() {
|
|
||||||
e.emitter.open_ended = false
|
|
||||||
yaml_stream_end_event_initialize(&e.event)
|
|
||||||
e.emit()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) destroy() {
|
|
||||||
yaml_emitter_delete(&e.emitter)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) emit() {
|
|
||||||
// This will internally delete the e.event value.
|
|
||||||
e.must(yaml_emitter_emit(&e.emitter, &e.event))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) must(ok bool) {
|
|
||||||
if !ok {
|
|
||||||
msg := e.emitter.problem
|
|
||||||
if msg == "" {
|
|
||||||
msg = "unknown problem generating YAML content"
|
|
||||||
}
|
|
||||||
failf("%s", msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) marshalDoc(tag string, in reflect.Value) {
|
|
||||||
e.init()
|
|
||||||
yaml_document_start_event_initialize(&e.event, nil, nil, true)
|
|
||||||
e.emit()
|
|
||||||
e.marshal(tag, in)
|
|
||||||
yaml_document_end_event_initialize(&e.event, true)
|
|
||||||
e.emit()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) marshal(tag string, in reflect.Value) {
|
|
||||||
if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() {
|
|
||||||
e.nilv()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
iface := in.Interface()
|
|
||||||
switch m := iface.(type) {
|
|
||||||
case jsonNumber:
|
|
||||||
integer, err := m.Int64()
|
|
||||||
if err == nil {
|
|
||||||
// In this case the json.Number is a valid int64
|
|
||||||
in = reflect.ValueOf(integer)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
float, err := m.Float64()
|
|
||||||
if err == nil {
|
|
||||||
// In this case the json.Number is a valid float64
|
|
||||||
in = reflect.ValueOf(float)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// fallback case - no number could be obtained
|
|
||||||
in = reflect.ValueOf(m.String())
|
|
||||||
case time.Time, *time.Time:
|
|
||||||
// Although time.Time implements TextMarshaler,
|
|
||||||
// we don't want to treat it as a string for YAML
|
|
||||||
// purposes because YAML has special support for
|
|
||||||
// timestamps.
|
|
||||||
case Marshaler:
|
|
||||||
v, err := m.MarshalYAML()
|
|
||||||
if err != nil {
|
|
||||||
fail(err)
|
|
||||||
}
|
|
||||||
if v == nil {
|
|
||||||
e.nilv()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
in = reflect.ValueOf(v)
|
|
||||||
case encoding.TextMarshaler:
|
|
||||||
text, err := m.MarshalText()
|
|
||||||
if err != nil {
|
|
||||||
fail(err)
|
|
||||||
}
|
|
||||||
in = reflect.ValueOf(string(text))
|
|
||||||
case nil:
|
|
||||||
e.nilv()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch in.Kind() {
|
|
||||||
case reflect.Interface:
|
|
||||||
e.marshal(tag, in.Elem())
|
|
||||||
case reflect.Map:
|
|
||||||
e.mapv(tag, in)
|
|
||||||
case reflect.Ptr:
|
|
||||||
if in.Type() == ptrTimeType {
|
|
||||||
e.timev(tag, in.Elem())
|
|
||||||
} else {
|
|
||||||
e.marshal(tag, in.Elem())
|
|
||||||
}
|
|
||||||
case reflect.Struct:
|
|
||||||
if in.Type() == timeType {
|
|
||||||
e.timev(tag, in)
|
|
||||||
} else {
|
|
||||||
e.structv(tag, in)
|
|
||||||
}
|
|
||||||
case reflect.Slice, reflect.Array:
|
|
||||||
if in.Type().Elem() == mapItemType {
|
|
||||||
e.itemsv(tag, in)
|
|
||||||
} else {
|
|
||||||
e.slicev(tag, in)
|
|
||||||
}
|
|
||||||
case reflect.String:
|
|
||||||
e.stringv(tag, in)
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
if in.Type() == durationType {
|
|
||||||
e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String()))
|
|
||||||
} else {
|
|
||||||
e.intv(tag, in)
|
|
||||||
}
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
e.uintv(tag, in)
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
e.floatv(tag, in)
|
|
||||||
case reflect.Bool:
|
|
||||||
e.boolv(tag, in)
|
|
||||||
default:
|
|
||||||
panic("cannot marshal type: " + in.Type().String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) mapv(tag string, in reflect.Value) {
|
|
||||||
e.mappingv(tag, func() {
|
|
||||||
keys := keyList(in.MapKeys())
|
|
||||||
sort.Sort(keys)
|
|
||||||
for _, k := range keys {
|
|
||||||
e.marshal("", k)
|
|
||||||
e.marshal("", in.MapIndex(k))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) itemsv(tag string, in reflect.Value) {
|
|
||||||
e.mappingv(tag, func() {
|
|
||||||
slice := in.Convert(reflect.TypeOf([]MapItem{})).Interface().([]MapItem)
|
|
||||||
for _, item := range slice {
|
|
||||||
e.marshal("", reflect.ValueOf(item.Key))
|
|
||||||
e.marshal("", reflect.ValueOf(item.Value))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) structv(tag string, in reflect.Value) {
|
|
||||||
sinfo, err := getStructInfo(in.Type())
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
e.mappingv(tag, func() {
|
|
||||||
for _, info := range sinfo.FieldsList {
|
|
||||||
var value reflect.Value
|
|
||||||
if info.Inline == nil {
|
|
||||||
value = in.Field(info.Num)
|
|
||||||
} else {
|
|
||||||
value = in.FieldByIndex(info.Inline)
|
|
||||||
}
|
|
||||||
if info.OmitEmpty && isZero(value) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
e.marshal("", reflect.ValueOf(info.Key))
|
|
||||||
e.flow = info.Flow
|
|
||||||
e.marshal("", value)
|
|
||||||
}
|
|
||||||
if sinfo.InlineMap >= 0 {
|
|
||||||
m := in.Field(sinfo.InlineMap)
|
|
||||||
if m.Len() > 0 {
|
|
||||||
e.flow = false
|
|
||||||
keys := keyList(m.MapKeys())
|
|
||||||
sort.Sort(keys)
|
|
||||||
for _, k := range keys {
|
|
||||||
if _, found := sinfo.FieldsMap[k.String()]; found {
|
|
||||||
panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", k.String()))
|
|
||||||
}
|
|
||||||
e.marshal("", k)
|
|
||||||
e.flow = false
|
|
||||||
e.marshal("", m.MapIndex(k))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) mappingv(tag string, f func()) {
|
|
||||||
implicit := tag == ""
|
|
||||||
style := yaml_BLOCK_MAPPING_STYLE
|
|
||||||
if e.flow {
|
|
||||||
e.flow = false
|
|
||||||
style = yaml_FLOW_MAPPING_STYLE
|
|
||||||
}
|
|
||||||
yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)
|
|
||||||
e.emit()
|
|
||||||
f()
|
|
||||||
yaml_mapping_end_event_initialize(&e.event)
|
|
||||||
e.emit()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) slicev(tag string, in reflect.Value) {
|
|
||||||
implicit := tag == ""
|
|
||||||
style := yaml_BLOCK_SEQUENCE_STYLE
|
|
||||||
if e.flow {
|
|
||||||
e.flow = false
|
|
||||||
style = yaml_FLOW_SEQUENCE_STYLE
|
|
||||||
}
|
|
||||||
e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
|
|
||||||
e.emit()
|
|
||||||
n := in.Len()
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
e.marshal("", in.Index(i))
|
|
||||||
}
|
|
||||||
e.must(yaml_sequence_end_event_initialize(&e.event))
|
|
||||||
e.emit()
|
|
||||||
}
|
|
||||||
|
|
||||||
// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1.
|
|
||||||
//
|
|
||||||
// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported
|
|
||||||
// in YAML 1.2 and by this package, but these should be marshalled quoted for
|
|
||||||
// the time being for compatibility with other parsers.
|
|
||||||
func isBase60Float(s string) (result bool) {
|
|
||||||
// Fast path.
|
|
||||||
if s == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
c := s[0]
|
|
||||||
if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// Do the full match.
|
|
||||||
return base60float.MatchString(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// From http://yaml.org/type/float.html, except the regular expression there
|
|
||||||
// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix.
|
|
||||||
var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`)
|
|
||||||
|
|
||||||
func (e *encoder) stringv(tag string, in reflect.Value) {
|
|
||||||
var style yaml_scalar_style_t
|
|
||||||
s := in.String()
|
|
||||||
canUsePlain := true
|
|
||||||
switch {
|
|
||||||
case !utf8.ValidString(s):
|
|
||||||
if tag == yaml_BINARY_TAG {
|
|
||||||
failf("explicitly tagged !!binary data must be base64-encoded")
|
|
||||||
}
|
|
||||||
if tag != "" {
|
|
||||||
failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
|
|
||||||
}
|
|
||||||
// It can't be encoded directly as YAML so use a binary tag
|
|
||||||
// and encode it as base64.
|
|
||||||
tag = yaml_BINARY_TAG
|
|
||||||
s = encodeBase64(s)
|
|
||||||
case tag == "":
|
|
||||||
// Check to see if it would resolve to a specific
|
|
||||||
// tag when encoded unquoted. If it doesn't,
|
|
||||||
// there's no need to quote it.
|
|
||||||
rtag, _ := resolve("", s)
|
|
||||||
canUsePlain = rtag == yaml_STR_TAG && !isBase60Float(s)
|
|
||||||
}
|
|
||||||
// Note: it's possible for user code to emit invalid YAML
|
|
||||||
// if they explicitly specify a tag and a string containing
|
|
||||||
// text that's incompatible with that tag.
|
|
||||||
switch {
|
|
||||||
case strings.Contains(s, "\n"):
|
|
||||||
style = yaml_LITERAL_SCALAR_STYLE
|
|
||||||
case canUsePlain:
|
|
||||||
style = yaml_PLAIN_SCALAR_STYLE
|
|
||||||
default:
|
|
||||||
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
|
|
||||||
}
|
|
||||||
e.emitScalar(s, "", tag, style)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) boolv(tag string, in reflect.Value) {
|
|
||||||
var s string
|
|
||||||
if in.Bool() {
|
|
||||||
s = "true"
|
|
||||||
} else {
|
|
||||||
s = "false"
|
|
||||||
}
|
|
||||||
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) intv(tag string, in reflect.Value) {
|
|
||||||
s := strconv.FormatInt(in.Int(), 10)
|
|
||||||
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) uintv(tag string, in reflect.Value) {
|
|
||||||
s := strconv.FormatUint(in.Uint(), 10)
|
|
||||||
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) timev(tag string, in reflect.Value) {
|
|
||||||
t := in.Interface().(time.Time)
|
|
||||||
s := t.Format(time.RFC3339Nano)
|
|
||||||
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) floatv(tag string, in reflect.Value) {
|
|
||||||
// Issue #352: When formatting, use the precision of the underlying value
|
|
||||||
precision := 64
|
|
||||||
if in.Kind() == reflect.Float32 {
|
|
||||||
precision = 32
|
|
||||||
}
|
|
||||||
|
|
||||||
s := strconv.FormatFloat(in.Float(), 'g', -1, precision)
|
|
||||||
switch s {
|
|
||||||
case "+Inf":
|
|
||||||
s = ".inf"
|
|
||||||
case "-Inf":
|
|
||||||
s = "-.inf"
|
|
||||||
case "NaN":
|
|
||||||
s = ".nan"
|
|
||||||
}
|
|
||||||
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) nilv() {
|
|
||||||
e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) {
|
|
||||||
implicit := tag == ""
|
|
||||||
e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style))
|
|
||||||
e.emit()
|
|
||||||
}
|
|
5
vendor/gopkg.in/yaml.v2/go.mod
generated
vendored
5
vendor/gopkg.in/yaml.v2/go.mod
generated
vendored
@ -1,5 +0,0 @@
|
|||||||
module "gopkg.in/yaml.v2"
|
|
||||||
|
|
||||||
require (
|
|
||||||
"gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405
|
|
||||||
)
|
|
1095
vendor/gopkg.in/yaml.v2/parserc.go
generated
vendored
1095
vendor/gopkg.in/yaml.v2/parserc.go
generated
vendored
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user