├── .gitignore ├── .vexor.yml ├── LICENSE ├── Makefile ├── README.md ├── bin └── main.go ├── utils.go ├── vendor └── golang.org │ └── x │ └── crypto │ ├── LICENSE │ ├── PATENTS │ ├── curve25519 │ ├── const_amd64.s │ ├── cswap_amd64.s │ ├── curve25519.go │ ├── doc.go │ ├── freeze_amd64.s │ ├── ladderstep_amd64.s │ ├── mont25519_amd64.go │ ├── mul_amd64.s │ └── square_amd64.s │ └── ssh │ ├── agent │ ├── client.go │ ├── forward.go │ ├── keyring.go │ └── server.go │ ├── buffer.go │ ├── certs.go │ ├── channel.go │ ├── cipher.go │ ├── client.go │ ├── client_auth.go │ ├── common.go │ ├── connection.go │ ├── doc.go │ ├── handshake.go │ ├── kex.go │ ├── keys.go │ ├── mac.go │ ├── messages.go │ ├── mux.go │ ├── server.go │ ├── session.go │ ├── tcpip.go │ ├── terminal │ ├── terminal.go │ ├── util.go │ ├── util_bsd.go │ ├── util_linux.go │ └── util_windows.go │ ├── test │ └── doc.go │ └── transport.go ├── vscale.go └── vscale_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | bin/docker* 26 | -------------------------------------------------------------------------------- /.vexor.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.5.1 4 | 5 | env: 6 | global: 7 | - GO15VENDOREXPERIMENT=1 8 | 9 | before_install: 10 | - go get -d -v -u github.com/evrone/docker-machine-vscale 11 | script: go test ./... -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Evrone 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Support go1.5 vendoring (let us avoid messing with GOPATH or using godep) 2 | export GO15VENDOREXPERIMENT = 1 3 | 4 | default: build 5 | 6 | bin/docker-machine-driver-vscale: fetch 7 | go build -i -o ./bin/docker-machine-driver-vscale ./bin/ 8 | 9 | test: fetch 10 | go test ./... 11 | 12 | fetch: 13 | go get -t -v ./... 14 | 15 | build: clean bin/docker-machine-driver-vscale 16 | 17 | clean: 18 | $(RM) -rf ./bin/docker* 19 | 20 | install: bin/docker-machine-driver-vscale 21 | cp -f ./bin/docker-machine-driver-vscale $(GOPATH)/bin/ && \ 22 | chmod +x $(GOPATH)/bin/docker-machine-driver-vscale 23 | 24 | .PHONY: clean fetch test build bin/docker-machine-driver-vscale 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker Machine Vscale Driver 2 | 3 | [![Vexor status](https://ci.vexor.io/projects/2c3724f0-4de6-4e28-9bdd-19fb71795812/status.svg)](https://ci.vexor.io/ui/projects/2c3724f0-4de6-4e28-9bdd-19fb71795812/builds) 4 | 5 | This is a plugin for [Docker Machine](https://docs.docker.com/machine/) allowing 6 | to create Doker hosts on [Vscale]( http://vscale.io ) cloud services. 7 | 8 | ## Installation 9 | 10 | Compile driver for your platform 11 | 12 | ```console 13 | $ make install 14 | ``` 15 | 16 | ## Usage 17 | 18 | After compile you can use driver for creating docker hosts. 19 | Get Vscale access token from [your profile](https://vscale.io/panel/settings/tokens/) then run: 20 | 21 | ```console 22 | $ docker-machine create -d vscale --vscale-access-token YOUR_VSCALE_ACCESS_TOKEN machine_name 23 | ``` 24 | 25 | You should see simple log of operations: 26 | 27 | ``` 28 | Running pre-create checks... 29 | Creating machine... 30 | (vscale) Creating SSH key... 31 | (vscale) Creating Vscale scalet... 32 | (vscale) Waiting for IP address to be assigned to the Scalet... 33 | Waiting for machine to be running, this may take a few minutes... 34 | Machine is running, waiting for SSH to be available... 35 | Detecting operating system of created instance... 36 | Detecting the provisioner... 37 | Provisioning with ubuntu(upstart)... 38 | Installing Docker... 39 | Copying certs to the local machine directory... 40 | Copying certs to the remote machine... 41 | Setting Docker configuration on the remote daemon... 42 | Checking connection to Docker... 43 | Docker is up and running! 44 | To see how to connect Docker to this machine, run: docker-machine env vscale 45 | ``` 46 | 47 | Just insert in command line this: 48 | ```console 49 | $ docker-machine env vscale 50 | ``` 51 | and follow instructions. 52 | 53 | If you did everything correctly, run the command, you will see information about the host: 54 | 55 | ```console 56 | $ docker info 57 | ``` 58 | 59 | ## Contribution Guidelines 60 | 61 | 01. Fork 62 | 02. Change 63 | 03. PR 64 | -------------------------------------------------------------------------------- /bin/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/docker/machine/libmachine/drivers/plugin" 5 | "github.com/evrone/docker-machine-vscale" 6 | ) 7 | 8 | func main() { 9 | plugin.RegisterDriver(vscale.NewDriver("", "")) 10 | } 11 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | package vscale 2 | 3 | import ( 4 | "io/ioutil" 5 | 6 | "github.com/docker/machine/libmachine/ssh" 7 | api "github.com/evrone/vscale_api" 8 | ) 9 | 10 | func (d *Driver) publicSSHKeyPath() string { 11 | return d.GetSSHKeyPath() + ".pub" 12 | } 13 | 14 | func (d *Driver) createSSHKey() (*api.SSHKey, error) { 15 | if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { 16 | return nil, err 17 | } 18 | 19 | publicKey, err := ioutil.ReadFile(d.publicSSHKeyPath()) 20 | if err != nil { 21 | return nil, err 22 | } 23 | 24 | createRequest := &api.SSHKeyCreateRequest{ 25 | Name: d.MachineName, 26 | Key: string(publicKey), 27 | } 28 | 29 | key, _, err := d.getClient().SSHKey.Create(createRequest) 30 | return key, err 31 | } 32 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/curve25519/const_amd64.s: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This code was translated into a form compatible with 6a from the public 6 | // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html 7 | 8 | // +build amd64,!gccgo,!appengine 9 | 10 | DATA ·REDMASK51(SB)/8, $0x0007FFFFFFFFFFFF 11 | GLOBL ·REDMASK51(SB), 8, $8 12 | 13 | DATA ·_121666_213(SB)/8, $996687872 14 | GLOBL ·_121666_213(SB), 8, $8 15 | 16 | DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA 17 | GLOBL ·_2P0(SB), 8, $8 18 | 19 | DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE 20 | GLOBL ·_2P1234(SB), 8, $8 21 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/curve25519/cswap_amd64.s: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This code was translated into a form compatible with 6a from the public 6 | // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html 7 | 8 | // +build amd64,!gccgo,!appengine 9 | 10 | // func cswap(inout *[5]uint64, v uint64) 11 | TEXT ·cswap(SB),7,$0 12 | MOVQ inout+0(FP),DI 13 | MOVQ v+8(FP),SI 14 | 15 | CMPQ SI,$1 16 | MOVQ 0(DI),SI 17 | MOVQ 80(DI),DX 18 | MOVQ 8(DI),CX 19 | MOVQ 88(DI),R8 20 | MOVQ SI,R9 21 | CMOVQEQ DX,SI 22 | CMOVQEQ R9,DX 23 | MOVQ CX,R9 24 | CMOVQEQ R8,CX 25 | CMOVQEQ R9,R8 26 | MOVQ SI,0(DI) 27 | MOVQ DX,80(DI) 28 | MOVQ CX,8(DI) 29 | MOVQ R8,88(DI) 30 | MOVQ 16(DI),SI 31 | MOVQ 96(DI),DX 32 | MOVQ 24(DI),CX 33 | MOVQ 104(DI),R8 34 | MOVQ SI,R9 35 | CMOVQEQ DX,SI 36 | CMOVQEQ R9,DX 37 | MOVQ CX,R9 38 | CMOVQEQ R8,CX 39 | CMOVQEQ R9,R8 40 | MOVQ SI,16(DI) 41 | MOVQ DX,96(DI) 42 | MOVQ CX,24(DI) 43 | MOVQ R8,104(DI) 44 | MOVQ 32(DI),SI 45 | MOVQ 112(DI),DX 46 | MOVQ 40(DI),CX 47 | MOVQ 120(DI),R8 48 | MOVQ SI,R9 49 | CMOVQEQ DX,SI 50 | CMOVQEQ R9,DX 51 | MOVQ CX,R9 52 | CMOVQEQ R8,CX 53 | CMOVQEQ R9,R8 54 | MOVQ SI,32(DI) 55 | MOVQ DX,112(DI) 56 | MOVQ CX,40(DI) 57 | MOVQ R8,120(DI) 58 | MOVQ 48(DI),SI 59 | MOVQ 128(DI),DX 60 | MOVQ 56(DI),CX 61 | MOVQ 136(DI),R8 62 | MOVQ SI,R9 63 | CMOVQEQ DX,SI 64 | CMOVQEQ R9,DX 65 | MOVQ CX,R9 66 | CMOVQEQ R8,CX 67 | CMOVQEQ R9,R8 68 | MOVQ SI,48(DI) 69 | MOVQ DX,128(DI) 70 | MOVQ CX,56(DI) 71 | MOVQ R8,136(DI) 72 | MOVQ 64(DI),SI 73 | MOVQ 144(DI),DX 74 | MOVQ 72(DI),CX 75 | MOVQ 152(DI),R8 76 | MOVQ SI,R9 77 | CMOVQEQ DX,SI 78 | CMOVQEQ R9,DX 79 | MOVQ CX,R9 80 | CMOVQEQ R8,CX 81 | CMOVQEQ R9,R8 82 | MOVQ SI,64(DI) 83 | MOVQ DX,144(DI) 84 | MOVQ CX,72(DI) 85 | MOVQ R8,152(DI) 86 | MOVQ DI,AX 87 | MOVQ SI,DX 88 | RET 89 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/curve25519/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package curve25519 provides an implementation of scalar multiplication on 6 | // the elliptic curve known as curve25519. See http://cr.yp.to/ecdh.html 7 | package curve25519 8 | 9 | // basePoint is the x coordinate of the generator of the curve. 10 | 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} 11 | 12 | // ScalarMult sets dst to the product in*base where dst and base are the x 13 | // coordinates of group points and all values are in little-endian form. 14 | func ScalarMult(dst, in, base *[32]byte) { 15 | scalarMult(dst, in, base) 16 | } 17 | 18 | // ScalarBaseMult sets dst to the product in*base where dst and base are the x 19 | // coordinates of group points, base is the standard generator and all values 20 | // are in little-endian form. 21 | func ScalarBaseMult(dst, in *[32]byte) { 22 | ScalarMult(dst, in, &basePoint) 23 | } 24 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/curve25519/freeze_amd64.s: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This code was translated into a form compatible with 6a from the public 6 | // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html 7 | 8 | // +build amd64,!gccgo,!appengine 9 | 10 | // func freeze(inout *[5]uint64) 11 | TEXT ·freeze(SB),7,$96-8 12 | MOVQ inout+0(FP), DI 13 | 14 | MOVQ SP,R11 15 | MOVQ $31,CX 16 | NOTQ CX 17 | ANDQ CX,SP 18 | ADDQ $32,SP 19 | 20 | MOVQ R11,0(SP) 21 | MOVQ R12,8(SP) 22 | MOVQ R13,16(SP) 23 | MOVQ R14,24(SP) 24 | MOVQ R15,32(SP) 25 | MOVQ BX,40(SP) 26 | MOVQ BP,48(SP) 27 | MOVQ 0(DI),SI 28 | MOVQ 8(DI),DX 29 | MOVQ 16(DI),CX 30 | MOVQ 24(DI),R8 31 | MOVQ 32(DI),R9 32 | MOVQ ·REDMASK51(SB),AX 33 | MOVQ AX,R10 34 | SUBQ $18,R10 35 | MOVQ $3,R11 36 | REDUCELOOP: 37 | MOVQ SI,R12 38 | SHRQ $51,R12 39 | ANDQ AX,SI 40 | ADDQ R12,DX 41 | MOVQ DX,R12 42 | SHRQ $51,R12 43 | ANDQ AX,DX 44 | ADDQ R12,CX 45 | MOVQ CX,R12 46 | SHRQ $51,R12 47 | ANDQ AX,CX 48 | ADDQ R12,R8 49 | MOVQ R8,R12 50 | SHRQ $51,R12 51 | ANDQ AX,R8 52 | ADDQ R12,R9 53 | MOVQ R9,R12 54 | SHRQ $51,R12 55 | ANDQ AX,R9 56 | IMUL3Q $19,R12,R12 57 | ADDQ R12,SI 58 | SUBQ $1,R11 59 | JA REDUCELOOP 60 | MOVQ $1,R12 61 | CMPQ R10,SI 62 | CMOVQLT R11,R12 63 | CMPQ AX,DX 64 | CMOVQNE R11,R12 65 | CMPQ AX,CX 66 | CMOVQNE R11,R12 67 | CMPQ AX,R8 68 | CMOVQNE R11,R12 69 | CMPQ AX,R9 70 | CMOVQNE R11,R12 71 | NEGQ R12 72 | ANDQ R12,AX 73 | ANDQ R12,R10 74 | SUBQ R10,SI 75 | SUBQ AX,DX 76 | SUBQ AX,CX 77 | SUBQ AX,R8 78 | SUBQ AX,R9 79 | MOVQ SI,0(DI) 80 | MOVQ DX,8(DI) 81 | MOVQ CX,16(DI) 82 | MOVQ R8,24(DI) 83 | MOVQ R9,32(DI) 84 | MOVQ 0(SP),R11 85 | MOVQ 8(SP),R12 86 | MOVQ 16(SP),R13 87 | MOVQ 24(SP),R14 88 | MOVQ 32(SP),R15 89 | MOVQ 40(SP),BX 90 | MOVQ 48(SP),BP 91 | MOVQ R11,SP 92 | MOVQ DI,AX 93 | MOVQ SI,DX 94 | RET 95 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build amd64,!gccgo,!appengine 6 | 7 | package curve25519 8 | 9 | // These functions are implemented in the .s files. The names of the functions 10 | // in the rest of the file are also taken from the SUPERCOP sources to help 11 | // people following along. 12 | 13 | //go:noescape 14 | 15 | func cswap(inout *[5]uint64, v uint64) 16 | 17 | //go:noescape 18 | 19 | func ladderstep(inout *[5][5]uint64) 20 | 21 | //go:noescape 22 | 23 | func freeze(inout *[5]uint64) 24 | 25 | //go:noescape 26 | 27 | func mul(dest, a, b *[5]uint64) 28 | 29 | //go:noescape 30 | 31 | func square(out, in *[5]uint64) 32 | 33 | // mladder uses a Montgomery ladder to calculate (xr/zr) *= s. 34 | func mladder(xr, zr *[5]uint64, s *[32]byte) { 35 | var work [5][5]uint64 36 | 37 | work[0] = *xr 38 | setint(&work[1], 1) 39 | setint(&work[2], 0) 40 | work[3] = *xr 41 | setint(&work[4], 1) 42 | 43 | j := uint(6) 44 | var prevbit byte 45 | 46 | for i := 31; i >= 0; i-- { 47 | for j < 8 { 48 | bit := ((*s)[i] >> j) & 1 49 | swap := bit ^ prevbit 50 | prevbit = bit 51 | cswap(&work[1], uint64(swap)) 52 | ladderstep(&work) 53 | j-- 54 | } 55 | j = 7 56 | } 57 | 58 | *xr = work[1] 59 | *zr = work[2] 60 | } 61 | 62 | func scalarMult(out, in, base *[32]byte) { 63 | var e [32]byte 64 | copy(e[:], (*in)[:]) 65 | e[0] &= 248 66 | e[31] &= 127 67 | e[31] |= 64 68 | 69 | var t, z [5]uint64 70 | unpack(&t, base) 71 | mladder(&t, &z, &e) 72 | invert(&z, &z) 73 | mul(&t, &t, &z) 74 | pack(out, &t) 75 | } 76 | 77 | func setint(r *[5]uint64, v uint64) { 78 | r[0] = v 79 | r[1] = 0 80 | r[2] = 0 81 | r[3] = 0 82 | r[4] = 0 83 | } 84 | 85 | // unpack sets r = x where r consists of 5, 51-bit limbs in little-endian 86 | // order. 87 | func unpack(r *[5]uint64, x *[32]byte) { 88 | r[0] = uint64(x[0]) | 89 | uint64(x[1])<<8 | 90 | uint64(x[2])<<16 | 91 | uint64(x[3])<<24 | 92 | uint64(x[4])<<32 | 93 | uint64(x[5])<<40 | 94 | uint64(x[6]&7)<<48 95 | 96 | r[1] = uint64(x[6])>>3 | 97 | uint64(x[7])<<5 | 98 | uint64(x[8])<<13 | 99 | uint64(x[9])<<21 | 100 | uint64(x[10])<<29 | 101 | uint64(x[11])<<37 | 102 | uint64(x[12]&63)<<45 103 | 104 | r[2] = uint64(x[12])>>6 | 105 | uint64(x[13])<<2 | 106 | uint64(x[14])<<10 | 107 | uint64(x[15])<<18 | 108 | uint64(x[16])<<26 | 109 | uint64(x[17])<<34 | 110 | uint64(x[18])<<42 | 111 | uint64(x[19]&1)<<50 112 | 113 | r[3] = uint64(x[19])>>1 | 114 | uint64(x[20])<<7 | 115 | uint64(x[21])<<15 | 116 | uint64(x[22])<<23 | 117 | uint64(x[23])<<31 | 118 | uint64(x[24])<<39 | 119 | uint64(x[25]&15)<<47 120 | 121 | r[4] = uint64(x[25])>>4 | 122 | uint64(x[26])<<4 | 123 | uint64(x[27])<<12 | 124 | uint64(x[28])<<20 | 125 | uint64(x[29])<<28 | 126 | uint64(x[30])<<36 | 127 | uint64(x[31]&127)<<44 128 | } 129 | 130 | // pack sets out = x where out is the usual, little-endian form of the 5, 131 | // 51-bit limbs in x. 132 | func pack(out *[32]byte, x *[5]uint64) { 133 | t := *x 134 | freeze(&t) 135 | 136 | out[0] = byte(t[0]) 137 | out[1] = byte(t[0] >> 8) 138 | out[2] = byte(t[0] >> 16) 139 | out[3] = byte(t[0] >> 24) 140 | out[4] = byte(t[0] >> 32) 141 | out[5] = byte(t[0] >> 40) 142 | out[6] = byte(t[0] >> 48) 143 | 144 | out[6] ^= byte(t[1]<<3) & 0xf8 145 | out[7] = byte(t[1] >> 5) 146 | out[8] = byte(t[1] >> 13) 147 | out[9] = byte(t[1] >> 21) 148 | out[10] = byte(t[1] >> 29) 149 | out[11] = byte(t[1] >> 37) 150 | out[12] = byte(t[1] >> 45) 151 | 152 | out[12] ^= byte(t[2]<<6) & 0xc0 153 | out[13] = byte(t[2] >> 2) 154 | out[14] = byte(t[2] >> 10) 155 | out[15] = byte(t[2] >> 18) 156 | out[16] = byte(t[2] >> 26) 157 | out[17] = byte(t[2] >> 34) 158 | out[18] = byte(t[2] >> 42) 159 | out[19] = byte(t[2] >> 50) 160 | 161 | out[19] ^= byte(t[3]<<1) & 0xfe 162 | out[20] = byte(t[3] >> 7) 163 | out[21] = byte(t[3] >> 15) 164 | out[22] = byte(t[3] >> 23) 165 | out[23] = byte(t[3] >> 31) 166 | out[24] = byte(t[3] >> 39) 167 | out[25] = byte(t[3] >> 47) 168 | 169 | out[25] ^= byte(t[4]<<4) & 0xf0 170 | out[26] = byte(t[4] >> 4) 171 | out[27] = byte(t[4] >> 12) 172 | out[28] = byte(t[4] >> 20) 173 | out[29] = byte(t[4] >> 28) 174 | out[30] = byte(t[4] >> 36) 175 | out[31] = byte(t[4] >> 44) 176 | } 177 | 178 | // invert calculates r = x^-1 mod p using Fermat's little theorem. 179 | func invert(r *[5]uint64, x *[5]uint64) { 180 | var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64 181 | 182 | square(&z2, x) /* 2 */ 183 | square(&t, &z2) /* 4 */ 184 | square(&t, &t) /* 8 */ 185 | mul(&z9, &t, x) /* 9 */ 186 | mul(&z11, &z9, &z2) /* 11 */ 187 | square(&t, &z11) /* 22 */ 188 | mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */ 189 | 190 | square(&t, &z2_5_0) /* 2^6 - 2^1 */ 191 | for i := 1; i < 5; i++ { /* 2^20 - 2^10 */ 192 | square(&t, &t) 193 | } 194 | mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */ 195 | 196 | square(&t, &z2_10_0) /* 2^11 - 2^1 */ 197 | for i := 1; i < 10; i++ { /* 2^20 - 2^10 */ 198 | square(&t, &t) 199 | } 200 | mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */ 201 | 202 | square(&t, &z2_20_0) /* 2^21 - 2^1 */ 203 | for i := 1; i < 20; i++ { /* 2^40 - 2^20 */ 204 | square(&t, &t) 205 | } 206 | mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */ 207 | 208 | square(&t, &t) /* 2^41 - 2^1 */ 209 | for i := 1; i < 10; i++ { /* 2^50 - 2^10 */ 210 | square(&t, &t) 211 | } 212 | mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */ 213 | 214 | square(&t, &z2_50_0) /* 2^51 - 2^1 */ 215 | for i := 1; i < 50; i++ { /* 2^100 - 2^50 */ 216 | square(&t, &t) 217 | } 218 | mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */ 219 | 220 | square(&t, &z2_100_0) /* 2^101 - 2^1 */ 221 | for i := 1; i < 100; i++ { /* 2^200 - 2^100 */ 222 | square(&t, &t) 223 | } 224 | mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */ 225 | 226 | square(&t, &t) /* 2^201 - 2^1 */ 227 | for i := 1; i < 50; i++ { /* 2^250 - 2^50 */ 228 | square(&t, &t) 229 | } 230 | mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */ 231 | 232 | square(&t, &t) /* 2^251 - 2^1 */ 233 | square(&t, &t) /* 2^252 - 2^2 */ 234 | square(&t, &t) /* 2^253 - 2^3 */ 235 | 236 | square(&t, &t) /* 2^254 - 2^4 */ 237 | 238 | square(&t, &t) /* 2^255 - 2^5 */ 239 | mul(r, &t, &z11) /* 2^255 - 21 */ 240 | } 241 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/curve25519/mul_amd64.s: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This code was translated into a form compatible with 6a from the public 6 | // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html 7 | 8 | // +build amd64,!gccgo,!appengine 9 | 10 | // func mul(dest, a, b *[5]uint64) 11 | TEXT ·mul(SB),0,$128-24 12 | MOVQ dest+0(FP), DI 13 | MOVQ a+8(FP), SI 14 | MOVQ b+16(FP), DX 15 | 16 | MOVQ SP,R11 17 | MOVQ $31,CX 18 | NOTQ CX 19 | ANDQ CX,SP 20 | ADDQ $32,SP 21 | 22 | MOVQ R11,0(SP) 23 | MOVQ R12,8(SP) 24 | MOVQ R13,16(SP) 25 | MOVQ R14,24(SP) 26 | MOVQ R15,32(SP) 27 | MOVQ BX,40(SP) 28 | MOVQ BP,48(SP) 29 | MOVQ DI,56(SP) 30 | MOVQ DX,CX 31 | MOVQ 24(SI),DX 32 | IMUL3Q $19,DX,AX 33 | MOVQ AX,64(SP) 34 | MULQ 16(CX) 35 | MOVQ AX,R8 36 | MOVQ DX,R9 37 | MOVQ 32(SI),DX 38 | IMUL3Q $19,DX,AX 39 | MOVQ AX,72(SP) 40 | MULQ 8(CX) 41 | ADDQ AX,R8 42 | ADCQ DX,R9 43 | MOVQ 0(SI),AX 44 | MULQ 0(CX) 45 | ADDQ AX,R8 46 | ADCQ DX,R9 47 | MOVQ 0(SI),AX 48 | MULQ 8(CX) 49 | MOVQ AX,R10 50 | MOVQ DX,R11 51 | MOVQ 0(SI),AX 52 | MULQ 16(CX) 53 | MOVQ AX,R12 54 | MOVQ DX,R13 55 | MOVQ 0(SI),AX 56 | MULQ 24(CX) 57 | MOVQ AX,R14 58 | MOVQ DX,R15 59 | MOVQ 0(SI),AX 60 | MULQ 32(CX) 61 | MOVQ AX,BX 62 | MOVQ DX,BP 63 | MOVQ 8(SI),AX 64 | MULQ 0(CX) 65 | ADDQ AX,R10 66 | ADCQ DX,R11 67 | MOVQ 8(SI),AX 68 | MULQ 8(CX) 69 | ADDQ AX,R12 70 | ADCQ DX,R13 71 | MOVQ 8(SI),AX 72 | MULQ 16(CX) 73 | ADDQ AX,R14 74 | ADCQ DX,R15 75 | MOVQ 8(SI),AX 76 | MULQ 24(CX) 77 | ADDQ AX,BX 78 | ADCQ DX,BP 79 | MOVQ 8(SI),DX 80 | IMUL3Q $19,DX,AX 81 | MULQ 32(CX) 82 | ADDQ AX,R8 83 | ADCQ DX,R9 84 | MOVQ 16(SI),AX 85 | MULQ 0(CX) 86 | ADDQ AX,R12 87 | ADCQ DX,R13 88 | MOVQ 16(SI),AX 89 | MULQ 8(CX) 90 | ADDQ AX,R14 91 | ADCQ DX,R15 92 | MOVQ 16(SI),AX 93 | MULQ 16(CX) 94 | ADDQ AX,BX 95 | ADCQ DX,BP 96 | MOVQ 16(SI),DX 97 | IMUL3Q $19,DX,AX 98 | MULQ 24(CX) 99 | ADDQ AX,R8 100 | ADCQ DX,R9 101 | MOVQ 16(SI),DX 102 | IMUL3Q $19,DX,AX 103 | MULQ 32(CX) 104 | ADDQ AX,R10 105 | ADCQ DX,R11 106 | MOVQ 24(SI),AX 107 | MULQ 0(CX) 108 | ADDQ AX,R14 109 | ADCQ DX,R15 110 | MOVQ 24(SI),AX 111 | MULQ 8(CX) 112 | ADDQ AX,BX 113 | ADCQ DX,BP 114 | MOVQ 64(SP),AX 115 | MULQ 24(CX) 116 | ADDQ AX,R10 117 | ADCQ DX,R11 118 | MOVQ 64(SP),AX 119 | MULQ 32(CX) 120 | ADDQ AX,R12 121 | ADCQ DX,R13 122 | MOVQ 32(SI),AX 123 | MULQ 0(CX) 124 | ADDQ AX,BX 125 | ADCQ DX,BP 126 | MOVQ 72(SP),AX 127 | MULQ 16(CX) 128 | ADDQ AX,R10 129 | ADCQ DX,R11 130 | MOVQ 72(SP),AX 131 | MULQ 24(CX) 132 | ADDQ AX,R12 133 | ADCQ DX,R13 134 | MOVQ 72(SP),AX 135 | MULQ 32(CX) 136 | ADDQ AX,R14 137 | ADCQ DX,R15 138 | MOVQ ·REDMASK51(SB),SI 139 | SHLQ $13,R9:R8 140 | ANDQ SI,R8 141 | SHLQ $13,R11:R10 142 | ANDQ SI,R10 143 | ADDQ R9,R10 144 | SHLQ $13,R13:R12 145 | ANDQ SI,R12 146 | ADDQ R11,R12 147 | SHLQ $13,R15:R14 148 | ANDQ SI,R14 149 | ADDQ R13,R14 150 | SHLQ $13,BP:BX 151 | ANDQ SI,BX 152 | ADDQ R15,BX 153 | IMUL3Q $19,BP,DX 154 | ADDQ DX,R8 155 | MOVQ R8,DX 156 | SHRQ $51,DX 157 | ADDQ R10,DX 158 | MOVQ DX,CX 159 | SHRQ $51,DX 160 | ANDQ SI,R8 161 | ADDQ R12,DX 162 | MOVQ DX,R9 163 | SHRQ $51,DX 164 | ANDQ SI,CX 165 | ADDQ R14,DX 166 | MOVQ DX,AX 167 | SHRQ $51,DX 168 | ANDQ SI,R9 169 | ADDQ BX,DX 170 | MOVQ DX,R10 171 | SHRQ $51,DX 172 | ANDQ SI,AX 173 | IMUL3Q $19,DX,DX 174 | ADDQ DX,R8 175 | ANDQ SI,R10 176 | MOVQ R8,0(DI) 177 | MOVQ CX,8(DI) 178 | MOVQ R9,16(DI) 179 | MOVQ AX,24(DI) 180 | MOVQ R10,32(DI) 181 | MOVQ 0(SP),R11 182 | MOVQ 8(SP),R12 183 | MOVQ 16(SP),R13 184 | MOVQ 24(SP),R14 185 | MOVQ 32(SP),R15 186 | MOVQ 40(SP),BX 187 | MOVQ 48(SP),BP 188 | MOVQ R11,SP 189 | MOVQ DI,AX 190 | MOVQ SI,DX 191 | RET 192 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/curve25519/square_amd64.s: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This code was translated into a form compatible with 6a from the public 6 | // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html 7 | 8 | // +build amd64,!gccgo,!appengine 9 | 10 | // func square(out, in *[5]uint64) 11 | TEXT ·square(SB),7,$96-16 12 | MOVQ out+0(FP), DI 13 | MOVQ in+8(FP), SI 14 | 15 | MOVQ SP,R11 16 | MOVQ $31,CX 17 | NOTQ CX 18 | ANDQ CX,SP 19 | ADDQ $32, SP 20 | 21 | MOVQ R11,0(SP) 22 | MOVQ R12,8(SP) 23 | MOVQ R13,16(SP) 24 | MOVQ R14,24(SP) 25 | MOVQ R15,32(SP) 26 | MOVQ BX,40(SP) 27 | MOVQ BP,48(SP) 28 | MOVQ 0(SI),AX 29 | MULQ 0(SI) 30 | MOVQ AX,CX 31 | MOVQ DX,R8 32 | MOVQ 0(SI),AX 33 | SHLQ $1,AX 34 | MULQ 8(SI) 35 | MOVQ AX,R9 36 | MOVQ DX,R10 37 | MOVQ 0(SI),AX 38 | SHLQ $1,AX 39 | MULQ 16(SI) 40 | MOVQ AX,R11 41 | MOVQ DX,R12 42 | MOVQ 0(SI),AX 43 | SHLQ $1,AX 44 | MULQ 24(SI) 45 | MOVQ AX,R13 46 | MOVQ DX,R14 47 | MOVQ 0(SI),AX 48 | SHLQ $1,AX 49 | MULQ 32(SI) 50 | MOVQ AX,R15 51 | MOVQ DX,BX 52 | MOVQ 8(SI),AX 53 | MULQ 8(SI) 54 | ADDQ AX,R11 55 | ADCQ DX,R12 56 | MOVQ 8(SI),AX 57 | SHLQ $1,AX 58 | MULQ 16(SI) 59 | ADDQ AX,R13 60 | ADCQ DX,R14 61 | MOVQ 8(SI),AX 62 | SHLQ $1,AX 63 | MULQ 24(SI) 64 | ADDQ AX,R15 65 | ADCQ DX,BX 66 | MOVQ 8(SI),DX 67 | IMUL3Q $38,DX,AX 68 | MULQ 32(SI) 69 | ADDQ AX,CX 70 | ADCQ DX,R8 71 | MOVQ 16(SI),AX 72 | MULQ 16(SI) 73 | ADDQ AX,R15 74 | ADCQ DX,BX 75 | MOVQ 16(SI),DX 76 | IMUL3Q $38,DX,AX 77 | MULQ 24(SI) 78 | ADDQ AX,CX 79 | ADCQ DX,R8 80 | MOVQ 16(SI),DX 81 | IMUL3Q $38,DX,AX 82 | MULQ 32(SI) 83 | ADDQ AX,R9 84 | ADCQ DX,R10 85 | MOVQ 24(SI),DX 86 | IMUL3Q $19,DX,AX 87 | MULQ 24(SI) 88 | ADDQ AX,R9 89 | ADCQ DX,R10 90 | MOVQ 24(SI),DX 91 | IMUL3Q $38,DX,AX 92 | MULQ 32(SI) 93 | ADDQ AX,R11 94 | ADCQ DX,R12 95 | MOVQ 32(SI),DX 96 | IMUL3Q $19,DX,AX 97 | MULQ 32(SI) 98 | ADDQ AX,R13 99 | ADCQ DX,R14 100 | MOVQ ·REDMASK51(SB),SI 101 | SHLQ $13,R8:CX 102 | ANDQ SI,CX 103 | SHLQ $13,R10:R9 104 | ANDQ SI,R9 105 | ADDQ R8,R9 106 | SHLQ $13,R12:R11 107 | ANDQ SI,R11 108 | ADDQ R10,R11 109 | SHLQ $13,R14:R13 110 | ANDQ SI,R13 111 | ADDQ R12,R13 112 | SHLQ $13,BX:R15 113 | ANDQ SI,R15 114 | ADDQ R14,R15 115 | IMUL3Q $19,BX,DX 116 | ADDQ DX,CX 117 | MOVQ CX,DX 118 | SHRQ $51,DX 119 | ADDQ R9,DX 120 | ANDQ SI,CX 121 | MOVQ DX,R8 122 | SHRQ $51,DX 123 | ADDQ R11,DX 124 | ANDQ SI,R8 125 | MOVQ DX,R9 126 | SHRQ $51,DX 127 | ADDQ R13,DX 128 | ANDQ SI,R9 129 | MOVQ DX,AX 130 | SHRQ $51,DX 131 | ADDQ R15,DX 132 | ANDQ SI,AX 133 | MOVQ DX,R10 134 | SHRQ $51,DX 135 | IMUL3Q $19,DX,DX 136 | ADDQ DX,CX 137 | ANDQ SI,R10 138 | MOVQ CX,0(DI) 139 | MOVQ R8,8(DI) 140 | MOVQ R9,16(DI) 141 | MOVQ AX,24(DI) 142 | MOVQ R10,32(DI) 143 | MOVQ 0(SP),R11 144 | MOVQ 8(SP),R12 145 | MOVQ 16(SP),R13 146 | MOVQ 24(SP),R14 147 | MOVQ 32(SP),R15 148 | MOVQ 40(SP),BX 149 | MOVQ 48(SP),BP 150 | MOVQ R11,SP 151 | MOVQ DI,AX 152 | MOVQ SI,DX 153 | RET 154 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/agent/forward.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package agent 6 | 7 | import ( 8 | "errors" 9 | "io" 10 | "net" 11 | "sync" 12 | 13 | "golang.org/x/crypto/ssh" 14 | ) 15 | 16 | // RequestAgentForwarding sets up agent forwarding for the session. 17 | // ForwardToAgent or ForwardToRemote should be called to route 18 | // the authentication requests. 19 | func RequestAgentForwarding(session *ssh.Session) error { 20 | ok, err := session.SendRequest("auth-agent-req@openssh.com", true, nil) 21 | if err != nil { 22 | return err 23 | } 24 | if !ok { 25 | return errors.New("forwarding request denied") 26 | } 27 | return nil 28 | } 29 | 30 | // ForwardToAgent routes authentication requests to the given keyring. 31 | func ForwardToAgent(client *ssh.Client, keyring Agent) error { 32 | channels := client.HandleChannelOpen(channelType) 33 | if channels == nil { 34 | return errors.New("agent: already have handler for " + channelType) 35 | } 36 | 37 | go func() { 38 | for ch := range channels { 39 | channel, reqs, err := ch.Accept() 40 | if err != nil { 41 | continue 42 | } 43 | go ssh.DiscardRequests(reqs) 44 | go func() { 45 | ServeAgent(keyring, channel) 46 | channel.Close() 47 | }() 48 | } 49 | }() 50 | return nil 51 | } 52 | 53 | const channelType = "auth-agent@openssh.com" 54 | 55 | // ForwardToRemote routes authentication requests to the ssh-agent 56 | // process serving on the given unix socket. 57 | func ForwardToRemote(client *ssh.Client, addr string) error { 58 | channels := client.HandleChannelOpen(channelType) 59 | if channels == nil { 60 | return errors.New("agent: already have handler for " + channelType) 61 | } 62 | conn, err := net.Dial("unix", addr) 63 | if err != nil { 64 | return err 65 | } 66 | conn.Close() 67 | 68 | go func() { 69 | for ch := range channels { 70 | channel, reqs, err := ch.Accept() 71 | if err != nil { 72 | continue 73 | } 74 | go ssh.DiscardRequests(reqs) 75 | go forwardUnixSocket(channel, addr) 76 | } 77 | }() 78 | return nil 79 | } 80 | 81 | func forwardUnixSocket(channel ssh.Channel, addr string) { 82 | conn, err := net.Dial("unix", addr) 83 | if err != nil { 84 | return 85 | } 86 | 87 | var wg sync.WaitGroup 88 | wg.Add(2) 89 | go func() { 90 | io.Copy(conn, channel) 91 | conn.(*net.UnixConn).CloseWrite() 92 | wg.Done() 93 | }() 94 | go func() { 95 | io.Copy(channel, conn) 96 | channel.CloseWrite() 97 | wg.Done() 98 | }() 99 | 100 | wg.Wait() 101 | conn.Close() 102 | channel.Close() 103 | } 104 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/agent/keyring.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package agent 6 | 7 | import ( 8 | "bytes" 9 | "crypto/rand" 10 | "crypto/subtle" 11 | "errors" 12 | "fmt" 13 | "sync" 14 | 15 | "golang.org/x/crypto/ssh" 16 | ) 17 | 18 | type privKey struct { 19 | signer ssh.Signer 20 | comment string 21 | } 22 | 23 | type keyring struct { 24 | mu sync.Mutex 25 | keys []privKey 26 | 27 | locked bool 28 | passphrase []byte 29 | } 30 | 31 | var errLocked = errors.New("agent: locked") 32 | 33 | // NewKeyring returns an Agent that holds keys in memory. It is safe 34 | // for concurrent use by multiple goroutines. 35 | func NewKeyring() Agent { 36 | return &keyring{} 37 | } 38 | 39 | // RemoveAll removes all identities. 40 | func (r *keyring) RemoveAll() error { 41 | r.mu.Lock() 42 | defer r.mu.Unlock() 43 | if r.locked { 44 | return errLocked 45 | } 46 | 47 | r.keys = nil 48 | return nil 49 | } 50 | 51 | // Remove removes all identities with the given public key. 52 | func (r *keyring) Remove(key ssh.PublicKey) error { 53 | r.mu.Lock() 54 | defer r.mu.Unlock() 55 | if r.locked { 56 | return errLocked 57 | } 58 | 59 | want := key.Marshal() 60 | found := false 61 | for i := 0; i < len(r.keys); { 62 | if bytes.Equal(r.keys[i].signer.PublicKey().Marshal(), want) { 63 | found = true 64 | r.keys[i] = r.keys[len(r.keys)-1] 65 | r.keys = r.keys[len(r.keys)-1:] 66 | continue 67 | } else { 68 | i++ 69 | } 70 | } 71 | 72 | if !found { 73 | return errors.New("agent: key not found") 74 | } 75 | return nil 76 | } 77 | 78 | // Lock locks the agent. Sign and Remove will fail, and List will empty an empty list. 79 | func (r *keyring) Lock(passphrase []byte) error { 80 | r.mu.Lock() 81 | defer r.mu.Unlock() 82 | if r.locked { 83 | return errLocked 84 | } 85 | 86 | r.locked = true 87 | r.passphrase = passphrase 88 | return nil 89 | } 90 | 91 | // Unlock undoes the effect of Lock 92 | func (r *keyring) Unlock(passphrase []byte) error { 93 | r.mu.Lock() 94 | defer r.mu.Unlock() 95 | if !r.locked { 96 | return errors.New("agent: not locked") 97 | } 98 | if len(passphrase) != len(r.passphrase) || 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) { 99 | return fmt.Errorf("agent: incorrect passphrase") 100 | } 101 | 102 | r.locked = false 103 | r.passphrase = nil 104 | return nil 105 | } 106 | 107 | // List returns the identities known to the agent. 108 | func (r *keyring) List() ([]*Key, error) { 109 | r.mu.Lock() 110 | defer r.mu.Unlock() 111 | if r.locked { 112 | // section 2.7: locked agents return empty. 113 | return nil, nil 114 | } 115 | 116 | var ids []*Key 117 | for _, k := range r.keys { 118 | pub := k.signer.PublicKey() 119 | ids = append(ids, &Key{ 120 | Format: pub.Type(), 121 | Blob: pub.Marshal(), 122 | Comment: k.comment}) 123 | } 124 | return ids, nil 125 | } 126 | 127 | // Insert adds a private key to the keyring. If a certificate 128 | // is given, that certificate is added as public key. Note that 129 | // any constraints given are ignored. 130 | func (r *keyring) Add(key AddedKey) error { 131 | r.mu.Lock() 132 | defer r.mu.Unlock() 133 | if r.locked { 134 | return errLocked 135 | } 136 | signer, err := ssh.NewSignerFromKey(key.PrivateKey) 137 | 138 | if err != nil { 139 | return err 140 | } 141 | 142 | if cert := key.Certificate; cert != nil { 143 | signer, err = ssh.NewCertSigner(cert, signer) 144 | if err != nil { 145 | return err 146 | } 147 | } 148 | 149 | r.keys = append(r.keys, privKey{signer, key.Comment}) 150 | 151 | return nil 152 | } 153 | 154 | // Sign returns a signature for the data. 155 | func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { 156 | r.mu.Lock() 157 | defer r.mu.Unlock() 158 | if r.locked { 159 | return nil, errLocked 160 | } 161 | 162 | wanted := key.Marshal() 163 | for _, k := range r.keys { 164 | if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) { 165 | return k.signer.Sign(rand.Reader, data) 166 | } 167 | } 168 | return nil, errors.New("not found") 169 | } 170 | 171 | // Signers returns signers for all the known keys. 172 | func (r *keyring) Signers() ([]ssh.Signer, error) { 173 | r.mu.Lock() 174 | defer r.mu.Unlock() 175 | if r.locked { 176 | return nil, errLocked 177 | } 178 | 179 | s := make([]ssh.Signer, 0, len(r.keys)) 180 | for _, k := range r.keys { 181 | s = append(s, k.signer) 182 | } 183 | return s, nil 184 | } 185 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/agent/server.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package agent 6 | 7 | import ( 8 | "crypto/rsa" 9 | "encoding/binary" 10 | "fmt" 11 | "io" 12 | "log" 13 | "math/big" 14 | 15 | "golang.org/x/crypto/ssh" 16 | ) 17 | 18 | // Server wraps an Agent and uses it to implement the agent side of 19 | // the SSH-agent, wire protocol. 20 | type server struct { 21 | agent Agent 22 | } 23 | 24 | func (s *server) processRequestBytes(reqData []byte) []byte { 25 | rep, err := s.processRequest(reqData) 26 | if err != nil { 27 | if err != errLocked { 28 | // TODO(hanwen): provide better logging interface? 29 | log.Printf("agent %d: %v", reqData[0], err) 30 | } 31 | return []byte{agentFailure} 32 | } 33 | 34 | if err == nil && rep == nil { 35 | return []byte{agentSuccess} 36 | } 37 | 38 | return ssh.Marshal(rep) 39 | } 40 | 41 | func marshalKey(k *Key) []byte { 42 | var record struct { 43 | Blob []byte 44 | Comment string 45 | } 46 | record.Blob = k.Marshal() 47 | record.Comment = k.Comment 48 | 49 | return ssh.Marshal(&record) 50 | } 51 | 52 | type agentV1IdentityMsg struct { 53 | Numkeys uint32 `sshtype:"2"` 54 | } 55 | 56 | type agentRemoveIdentityMsg struct { 57 | KeyBlob []byte `sshtype:"18"` 58 | } 59 | 60 | type agentLockMsg struct { 61 | Passphrase []byte `sshtype:"22"` 62 | } 63 | 64 | type agentUnlockMsg struct { 65 | Passphrase []byte `sshtype:"23"` 66 | } 67 | 68 | func (s *server) processRequest(data []byte) (interface{}, error) { 69 | switch data[0] { 70 | case agentRequestV1Identities: 71 | return &agentV1IdentityMsg{0}, nil 72 | case agentRemoveIdentity: 73 | var req agentRemoveIdentityMsg 74 | if err := ssh.Unmarshal(data, &req); err != nil { 75 | return nil, err 76 | } 77 | 78 | var wk wireKey 79 | if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { 80 | return nil, err 81 | } 82 | 83 | return nil, s.agent.Remove(&Key{Format: wk.Format, Blob: req.KeyBlob}) 84 | 85 | case agentRemoveAllIdentities: 86 | return nil, s.agent.RemoveAll() 87 | 88 | case agentLock: 89 | var req agentLockMsg 90 | if err := ssh.Unmarshal(data, &req); err != nil { 91 | return nil, err 92 | } 93 | 94 | return nil, s.agent.Lock(req.Passphrase) 95 | 96 | case agentUnlock: 97 | var req agentLockMsg 98 | if err := ssh.Unmarshal(data, &req); err != nil { 99 | return nil, err 100 | } 101 | return nil, s.agent.Unlock(req.Passphrase) 102 | 103 | case agentSignRequest: 104 | var req signRequestAgentMsg 105 | if err := ssh.Unmarshal(data, &req); err != nil { 106 | return nil, err 107 | } 108 | 109 | var wk wireKey 110 | if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { 111 | return nil, err 112 | } 113 | 114 | k := &Key{ 115 | Format: wk.Format, 116 | Blob: req.KeyBlob, 117 | } 118 | 119 | sig, err := s.agent.Sign(k, req.Data) // TODO(hanwen): flags. 120 | if err != nil { 121 | return nil, err 122 | } 123 | return &signResponseAgentMsg{SigBlob: ssh.Marshal(sig)}, nil 124 | case agentRequestIdentities: 125 | keys, err := s.agent.List() 126 | if err != nil { 127 | return nil, err 128 | } 129 | 130 | rep := identitiesAnswerAgentMsg{ 131 | NumKeys: uint32(len(keys)), 132 | } 133 | for _, k := range keys { 134 | rep.Keys = append(rep.Keys, marshalKey(k)...) 135 | } 136 | return rep, nil 137 | case agentAddIdentity: 138 | return nil, s.insertIdentity(data) 139 | } 140 | 141 | return nil, fmt.Errorf("unknown opcode %d", data[0]) 142 | } 143 | 144 | func (s *server) insertIdentity(req []byte) error { 145 | var record struct { 146 | Type string `sshtype:"17"` 147 | Rest []byte `ssh:"rest"` 148 | } 149 | if err := ssh.Unmarshal(req, &record); err != nil { 150 | return err 151 | } 152 | 153 | switch record.Type { 154 | case ssh.KeyAlgoRSA: 155 | var k rsaKeyMsg 156 | if err := ssh.Unmarshal(req, &k); err != nil { 157 | return err 158 | } 159 | 160 | priv := rsa.PrivateKey{ 161 | PublicKey: rsa.PublicKey{ 162 | E: int(k.E.Int64()), 163 | N: k.N, 164 | }, 165 | D: k.D, 166 | Primes: []*big.Int{k.P, k.Q}, 167 | } 168 | priv.Precompute() 169 | 170 | return s.agent.Add(AddedKey{PrivateKey: &priv, Comment: k.Comments}) 171 | } 172 | return fmt.Errorf("not implemented: %s", record.Type) 173 | } 174 | 175 | // ServeAgent serves the agent protocol on the given connection. It 176 | // returns when an I/O error occurs. 177 | func ServeAgent(agent Agent, c io.ReadWriter) error { 178 | s := &server{agent} 179 | 180 | var length [4]byte 181 | for { 182 | if _, err := io.ReadFull(c, length[:]); err != nil { 183 | return err 184 | } 185 | l := binary.BigEndian.Uint32(length[:]) 186 | if l > maxAgentResponseBytes { 187 | // We also cap requests. 188 | return fmt.Errorf("agent: request too large: %d", l) 189 | } 190 | 191 | req := make([]byte, l) 192 | if _, err := io.ReadFull(c, req); err != nil { 193 | return err 194 | } 195 | 196 | repData := s.processRequestBytes(req) 197 | if len(repData) > maxAgentResponseBytes { 198 | return fmt.Errorf("agent: reply too large: %d bytes", len(repData)) 199 | } 200 | 201 | binary.BigEndian.PutUint32(length[:], uint32(len(repData))) 202 | if _, err := c.Write(length[:]); err != nil { 203 | return err 204 | } 205 | if _, err := c.Write(repData); err != nil { 206 | return err 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/buffer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "io" 9 | "sync" 10 | ) 11 | 12 | // buffer provides a linked list buffer for data exchange 13 | // between producer and consumer. Theoretically the buffer is 14 | // of unlimited capacity as it does no allocation of its own. 15 | type buffer struct { 16 | // protects concurrent access to head, tail and closed 17 | *sync.Cond 18 | 19 | head *element // the buffer that will be read first 20 | tail *element // the buffer that will be read last 21 | 22 | closed bool 23 | } 24 | 25 | // An element represents a single link in a linked list. 26 | type element struct { 27 | buf []byte 28 | next *element 29 | } 30 | 31 | // newBuffer returns an empty buffer that is not closed. 32 | func newBuffer() *buffer { 33 | e := new(element) 34 | b := &buffer{ 35 | Cond: newCond(), 36 | head: e, 37 | tail: e, 38 | } 39 | return b 40 | } 41 | 42 | // write makes buf available for Read to receive. 43 | // buf must not be modified after the call to write. 44 | func (b *buffer) write(buf []byte) { 45 | b.Cond.L.Lock() 46 | e := &element{buf: buf} 47 | b.tail.next = e 48 | b.tail = e 49 | b.Cond.Signal() 50 | b.Cond.L.Unlock() 51 | } 52 | 53 | // eof closes the buffer. Reads from the buffer once all 54 | // the data has been consumed will receive os.EOF. 55 | func (b *buffer) eof() error { 56 | b.Cond.L.Lock() 57 | b.closed = true 58 | b.Cond.Signal() 59 | b.Cond.L.Unlock() 60 | return nil 61 | } 62 | 63 | // Read reads data from the internal buffer in buf. Reads will block 64 | // if no data is available, or until the buffer is closed. 65 | func (b *buffer) Read(buf []byte) (n int, err error) { 66 | b.Cond.L.Lock() 67 | defer b.Cond.L.Unlock() 68 | 69 | for len(buf) > 0 { 70 | // if there is data in b.head, copy it 71 | if len(b.head.buf) > 0 { 72 | r := copy(buf, b.head.buf) 73 | buf, b.head.buf = buf[r:], b.head.buf[r:] 74 | n += r 75 | continue 76 | } 77 | // if there is a next buffer, make it the head 78 | if len(b.head.buf) == 0 && b.head != b.tail { 79 | b.head = b.head.next 80 | continue 81 | } 82 | 83 | // if at least one byte has been copied, return 84 | if n > 0 { 85 | break 86 | } 87 | 88 | // if nothing was read, and there is nothing outstanding 89 | // check to see if the buffer is closed. 90 | if b.closed { 91 | err = io.EOF 92 | break 93 | } 94 | // out of buffers, wait for producer 95 | b.Cond.Wait() 96 | } 97 | return 98 | } 99 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/certs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "bytes" 9 | "errors" 10 | "fmt" 11 | "io" 12 | "net" 13 | "sort" 14 | "time" 15 | ) 16 | 17 | // These constants from [PROTOCOL.certkeys] represent the algorithm names 18 | // for certificate types supported by this package. 19 | const ( 20 | CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com" 21 | CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com" 22 | CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com" 23 | CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com" 24 | CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com" 25 | ) 26 | 27 | // Certificate types distinguish between host and user 28 | // certificates. The values can be set in the CertType field of 29 | // Certificate. 30 | const ( 31 | UserCert = 1 32 | HostCert = 2 33 | ) 34 | 35 | // Signature represents a cryptographic signature. 36 | type Signature struct { 37 | Format string 38 | Blob []byte 39 | } 40 | 41 | // CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that 42 | // a certificate does not expire. 43 | const CertTimeInfinity = 1<<64 - 1 44 | 45 | // An Certificate represents an OpenSSH certificate as defined in 46 | // [PROTOCOL.certkeys]?rev=1.8. 47 | type Certificate struct { 48 | Nonce []byte 49 | Key PublicKey 50 | Serial uint64 51 | CertType uint32 52 | KeyId string 53 | ValidPrincipals []string 54 | ValidAfter uint64 55 | ValidBefore uint64 56 | Permissions 57 | Reserved []byte 58 | SignatureKey PublicKey 59 | Signature *Signature 60 | } 61 | 62 | // genericCertData holds the key-independent part of the certificate data. 63 | // Overall, certificates contain an nonce, public key fields and 64 | // key-independent fields. 65 | type genericCertData struct { 66 | Serial uint64 67 | CertType uint32 68 | KeyId string 69 | ValidPrincipals []byte 70 | ValidAfter uint64 71 | ValidBefore uint64 72 | CriticalOptions []byte 73 | Extensions []byte 74 | Reserved []byte 75 | SignatureKey []byte 76 | Signature []byte 77 | } 78 | 79 | func marshalStringList(namelist []string) []byte { 80 | var to []byte 81 | for _, name := range namelist { 82 | s := struct{ N string }{name} 83 | to = append(to, Marshal(&s)...) 84 | } 85 | return to 86 | } 87 | 88 | type optionsTuple struct { 89 | Key string 90 | Value []byte 91 | } 92 | 93 | type optionsTupleValue struct { 94 | Value string 95 | } 96 | 97 | // serialize a map of critical options or extensions 98 | // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, 99 | // we need two length prefixes for a non-empty string value 100 | func marshalTuples(tups map[string]string) []byte { 101 | keys := make([]string, 0, len(tups)) 102 | for key := range tups { 103 | keys = append(keys, key) 104 | } 105 | sort.Strings(keys) 106 | 107 | var ret []byte 108 | for _, key := range keys { 109 | s := optionsTuple{Key: key} 110 | if value := tups[key]; len(value) > 0 { 111 | s.Value = Marshal(&optionsTupleValue{value}) 112 | } 113 | ret = append(ret, Marshal(&s)...) 114 | } 115 | return ret 116 | } 117 | 118 | // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, 119 | // we need two length prefixes for a non-empty option value 120 | func parseTuples(in []byte) (map[string]string, error) { 121 | tups := map[string]string{} 122 | var lastKey string 123 | var haveLastKey bool 124 | 125 | for len(in) > 0 { 126 | var key, val, extra []byte 127 | var ok bool 128 | 129 | if key, in, ok = parseString(in); !ok { 130 | return nil, errShortRead 131 | } 132 | keyStr := string(key) 133 | // according to [PROTOCOL.certkeys], the names must be in 134 | // lexical order. 135 | if haveLastKey && keyStr <= lastKey { 136 | return nil, fmt.Errorf("ssh: certificate options are not in lexical order") 137 | } 138 | lastKey, haveLastKey = keyStr, true 139 | // the next field is a data field, which if non-empty has a string embedded 140 | if val, in, ok = parseString(in); !ok { 141 | return nil, errShortRead 142 | } 143 | if len(val) > 0 { 144 | val, extra, ok = parseString(val) 145 | if !ok { 146 | return nil, errShortRead 147 | } 148 | if len(extra) > 0 { 149 | return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value") 150 | } 151 | tups[keyStr] = string(val) 152 | } else { 153 | tups[keyStr] = "" 154 | } 155 | } 156 | return tups, nil 157 | } 158 | 159 | func parseCert(in []byte, privAlgo string) (*Certificate, error) { 160 | nonce, rest, ok := parseString(in) 161 | if !ok { 162 | return nil, errShortRead 163 | } 164 | 165 | key, rest, err := parsePubKey(rest, privAlgo) 166 | if err != nil { 167 | return nil, err 168 | } 169 | 170 | var g genericCertData 171 | if err := Unmarshal(rest, &g); err != nil { 172 | return nil, err 173 | } 174 | 175 | c := &Certificate{ 176 | Nonce: nonce, 177 | Key: key, 178 | Serial: g.Serial, 179 | CertType: g.CertType, 180 | KeyId: g.KeyId, 181 | ValidAfter: g.ValidAfter, 182 | ValidBefore: g.ValidBefore, 183 | } 184 | 185 | for principals := g.ValidPrincipals; len(principals) > 0; { 186 | principal, rest, ok := parseString(principals) 187 | if !ok { 188 | return nil, errShortRead 189 | } 190 | c.ValidPrincipals = append(c.ValidPrincipals, string(principal)) 191 | principals = rest 192 | } 193 | 194 | c.CriticalOptions, err = parseTuples(g.CriticalOptions) 195 | if err != nil { 196 | return nil, err 197 | } 198 | c.Extensions, err = parseTuples(g.Extensions) 199 | if err != nil { 200 | return nil, err 201 | } 202 | c.Reserved = g.Reserved 203 | k, err := ParsePublicKey(g.SignatureKey) 204 | if err != nil { 205 | return nil, err 206 | } 207 | 208 | c.SignatureKey = k 209 | c.Signature, rest, ok = parseSignatureBody(g.Signature) 210 | if !ok || len(rest) > 0 { 211 | return nil, errors.New("ssh: signature parse error") 212 | } 213 | 214 | return c, nil 215 | } 216 | 217 | type openSSHCertSigner struct { 218 | pub *Certificate 219 | signer Signer 220 | } 221 | 222 | // NewCertSigner returns a Signer that signs with the given Certificate, whose 223 | // private key is held by signer. It returns an error if the public key in cert 224 | // doesn't match the key used by signer. 225 | func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) { 226 | if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { 227 | return nil, errors.New("ssh: signer and cert have different public key") 228 | } 229 | 230 | return &openSSHCertSigner{cert, signer}, nil 231 | } 232 | 233 | func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { 234 | return s.signer.Sign(rand, data) 235 | } 236 | 237 | func (s *openSSHCertSigner) PublicKey() PublicKey { 238 | return s.pub 239 | } 240 | 241 | const sourceAddressCriticalOption = "source-address" 242 | 243 | // CertChecker does the work of verifying a certificate. Its methods 244 | // can be plugged into ClientConfig.HostKeyCallback and 245 | // ServerConfig.PublicKeyCallback. For the CertChecker to work, 246 | // minimally, the IsAuthority callback should be set. 247 | type CertChecker struct { 248 | // SupportedCriticalOptions lists the CriticalOptions that the 249 | // server application layer understands. These are only used 250 | // for user certificates. 251 | SupportedCriticalOptions []string 252 | 253 | // IsAuthority should return true if the key is recognized as 254 | // an authority. This allows for certificates to be signed by other 255 | // certificates. 256 | IsAuthority func(auth PublicKey) bool 257 | 258 | // Clock is used for verifying time stamps. If nil, time.Now 259 | // is used. 260 | Clock func() time.Time 261 | 262 | // UserKeyFallback is called when CertChecker.Authenticate encounters a 263 | // public key that is not a certificate. It must implement validation 264 | // of user keys or else, if nil, all such keys are rejected. 265 | UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) 266 | 267 | // HostKeyFallback is called when CertChecker.CheckHostKey encounters a 268 | // public key that is not a certificate. It must implement host key 269 | // validation or else, if nil, all such keys are rejected. 270 | HostKeyFallback func(addr string, remote net.Addr, key PublicKey) error 271 | 272 | // IsRevoked is called for each certificate so that revocation checking 273 | // can be implemented. It should return true if the given certificate 274 | // is revoked and false otherwise. If nil, no certificates are 275 | // considered to have been revoked. 276 | IsRevoked func(cert *Certificate) bool 277 | } 278 | 279 | // CheckHostKey checks a host key certificate. This method can be 280 | // plugged into ClientConfig.HostKeyCallback. 281 | func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error { 282 | cert, ok := key.(*Certificate) 283 | if !ok { 284 | if c.HostKeyFallback != nil { 285 | return c.HostKeyFallback(addr, remote, key) 286 | } 287 | return errors.New("ssh: non-certificate host key") 288 | } 289 | if cert.CertType != HostCert { 290 | return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType) 291 | } 292 | 293 | return c.CheckCert(addr, cert) 294 | } 295 | 296 | // Authenticate checks a user certificate. Authenticate can be used as 297 | // a value for ServerConfig.PublicKeyCallback. 298 | func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) { 299 | cert, ok := pubKey.(*Certificate) 300 | if !ok { 301 | if c.UserKeyFallback != nil { 302 | return c.UserKeyFallback(conn, pubKey) 303 | } 304 | return nil, errors.New("ssh: normal key pairs not accepted") 305 | } 306 | 307 | if cert.CertType != UserCert { 308 | return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType) 309 | } 310 | 311 | if err := c.CheckCert(conn.User(), cert); err != nil { 312 | return nil, err 313 | } 314 | 315 | return &cert.Permissions, nil 316 | } 317 | 318 | // CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and 319 | // the signature of the certificate. 320 | func (c *CertChecker) CheckCert(principal string, cert *Certificate) error { 321 | if c.IsRevoked != nil && c.IsRevoked(cert) { 322 | return fmt.Errorf("ssh: certicate serial %d revoked", cert.Serial) 323 | } 324 | 325 | for opt, _ := range cert.CriticalOptions { 326 | // sourceAddressCriticalOption will be enforced by 327 | // serverAuthenticate 328 | if opt == sourceAddressCriticalOption { 329 | continue 330 | } 331 | 332 | found := false 333 | for _, supp := range c.SupportedCriticalOptions { 334 | if supp == opt { 335 | found = true 336 | break 337 | } 338 | } 339 | if !found { 340 | return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt) 341 | } 342 | } 343 | 344 | if len(cert.ValidPrincipals) > 0 { 345 | // By default, certs are valid for all users/hosts. 346 | found := false 347 | for _, p := range cert.ValidPrincipals { 348 | if p == principal { 349 | found = true 350 | break 351 | } 352 | } 353 | if !found { 354 | return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals) 355 | } 356 | } 357 | 358 | if !c.IsAuthority(cert.SignatureKey) { 359 | return fmt.Errorf("ssh: certificate signed by unrecognized authority") 360 | } 361 | 362 | clock := c.Clock 363 | if clock == nil { 364 | clock = time.Now 365 | } 366 | 367 | unixNow := clock().Unix() 368 | if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) { 369 | return fmt.Errorf("ssh: cert is not yet valid") 370 | } 371 | if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) { 372 | return fmt.Errorf("ssh: cert has expired") 373 | } 374 | if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil { 375 | return fmt.Errorf("ssh: certificate signature does not verify") 376 | } 377 | 378 | return nil 379 | } 380 | 381 | // SignCert sets c.SignatureKey to the authority's public key and stores a 382 | // Signature, by authority, in the certificate. 383 | func (c *Certificate) SignCert(rand io.Reader, authority Signer) error { 384 | c.Nonce = make([]byte, 32) 385 | if _, err := io.ReadFull(rand, c.Nonce); err != nil { 386 | return err 387 | } 388 | c.SignatureKey = authority.PublicKey() 389 | 390 | sig, err := authority.Sign(rand, c.bytesForSigning()) 391 | if err != nil { 392 | return err 393 | } 394 | c.Signature = sig 395 | return nil 396 | } 397 | 398 | var certAlgoNames = map[string]string{ 399 | KeyAlgoRSA: CertAlgoRSAv01, 400 | KeyAlgoDSA: CertAlgoDSAv01, 401 | KeyAlgoECDSA256: CertAlgoECDSA256v01, 402 | KeyAlgoECDSA384: CertAlgoECDSA384v01, 403 | KeyAlgoECDSA521: CertAlgoECDSA521v01, 404 | } 405 | 406 | // certToPrivAlgo returns the underlying algorithm for a certificate algorithm. 407 | // Panics if a non-certificate algorithm is passed. 408 | func certToPrivAlgo(algo string) string { 409 | for privAlgo, pubAlgo := range certAlgoNames { 410 | if pubAlgo == algo { 411 | return privAlgo 412 | } 413 | } 414 | panic("unknown cert algorithm") 415 | } 416 | 417 | func (cert *Certificate) bytesForSigning() []byte { 418 | c2 := *cert 419 | c2.Signature = nil 420 | out := c2.Marshal() 421 | // Drop trailing signature length. 422 | return out[:len(out)-4] 423 | } 424 | 425 | // Marshal serializes c into OpenSSH's wire format. It is part of the 426 | // PublicKey interface. 427 | func (c *Certificate) Marshal() []byte { 428 | generic := genericCertData{ 429 | Serial: c.Serial, 430 | CertType: c.CertType, 431 | KeyId: c.KeyId, 432 | ValidPrincipals: marshalStringList(c.ValidPrincipals), 433 | ValidAfter: uint64(c.ValidAfter), 434 | ValidBefore: uint64(c.ValidBefore), 435 | CriticalOptions: marshalTuples(c.CriticalOptions), 436 | Extensions: marshalTuples(c.Extensions), 437 | Reserved: c.Reserved, 438 | SignatureKey: c.SignatureKey.Marshal(), 439 | } 440 | if c.Signature != nil { 441 | generic.Signature = Marshal(c.Signature) 442 | } 443 | genericBytes := Marshal(&generic) 444 | keyBytes := c.Key.Marshal() 445 | _, keyBytes, _ = parseString(keyBytes) 446 | prefix := Marshal(&struct { 447 | Name string 448 | Nonce []byte 449 | Key []byte `ssh:"rest"` 450 | }{c.Type(), c.Nonce, keyBytes}) 451 | 452 | result := make([]byte, 0, len(prefix)+len(genericBytes)) 453 | result = append(result, prefix...) 454 | result = append(result, genericBytes...) 455 | return result 456 | } 457 | 458 | // Type returns the key name. It is part of the PublicKey interface. 459 | func (c *Certificate) Type() string { 460 | algo, ok := certAlgoNames[c.Key.Type()] 461 | if !ok { 462 | panic("unknown cert key type") 463 | } 464 | return algo 465 | } 466 | 467 | // Verify verifies a signature against the certificate's public 468 | // key. It is part of the PublicKey interface. 469 | func (c *Certificate) Verify(data []byte, sig *Signature) error { 470 | return c.Key.Verify(data, sig) 471 | } 472 | 473 | func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) { 474 | format, in, ok := parseString(in) 475 | if !ok { 476 | return 477 | } 478 | 479 | out = &Signature{ 480 | Format: string(format), 481 | } 482 | 483 | if out.Blob, in, ok = parseString(in); !ok { 484 | return 485 | } 486 | 487 | return out, in, ok 488 | } 489 | 490 | func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) { 491 | sigBytes, rest, ok := parseString(in) 492 | if !ok { 493 | return 494 | } 495 | 496 | out, trailing, ok := parseSignatureBody(sigBytes) 497 | if !ok || len(trailing) > 0 { 498 | return nil, nil, false 499 | } 500 | return 501 | } 502 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/cipher.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "crypto/aes" 9 | "crypto/cipher" 10 | "crypto/rc4" 11 | "crypto/subtle" 12 | "encoding/binary" 13 | "errors" 14 | "fmt" 15 | "hash" 16 | "io" 17 | "io/ioutil" 18 | ) 19 | 20 | const ( 21 | packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher. 22 | 23 | // RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations 24 | // MUST be able to process (plus a few more kilobytes for padding and mac). The RFC 25 | // indicates implementations SHOULD be able to handle larger packet sizes, but then 26 | // waffles on about reasonable limits. 27 | // 28 | // OpenSSH caps their maxPacket at 256kB so we choose to do 29 | // the same. maxPacket is also used to ensure that uint32 30 | // length fields do not overflow, so it should remain well 31 | // below 4G. 32 | maxPacket = 256 * 1024 33 | ) 34 | 35 | // noneCipher implements cipher.Stream and provides no encryption. It is used 36 | // by the transport before the first key-exchange. 37 | type noneCipher struct{} 38 | 39 | func (c noneCipher) XORKeyStream(dst, src []byte) { 40 | copy(dst, src) 41 | } 42 | 43 | func newAESCTR(key, iv []byte) (cipher.Stream, error) { 44 | c, err := aes.NewCipher(key) 45 | if err != nil { 46 | return nil, err 47 | } 48 | return cipher.NewCTR(c, iv), nil 49 | } 50 | 51 | func newRC4(key, iv []byte) (cipher.Stream, error) { 52 | return rc4.NewCipher(key) 53 | } 54 | 55 | type streamCipherMode struct { 56 | keySize int 57 | ivSize int 58 | skip int 59 | createFunc func(key, iv []byte) (cipher.Stream, error) 60 | } 61 | 62 | func (c *streamCipherMode) createStream(key, iv []byte) (cipher.Stream, error) { 63 | if len(key) < c.keySize { 64 | panic("ssh: key length too small for cipher") 65 | } 66 | if len(iv) < c.ivSize { 67 | panic("ssh: iv too small for cipher") 68 | } 69 | 70 | stream, err := c.createFunc(key[:c.keySize], iv[:c.ivSize]) 71 | if err != nil { 72 | return nil, err 73 | } 74 | 75 | var streamDump []byte 76 | if c.skip > 0 { 77 | streamDump = make([]byte, 512) 78 | } 79 | 80 | for remainingToDump := c.skip; remainingToDump > 0; { 81 | dumpThisTime := remainingToDump 82 | if dumpThisTime > len(streamDump) { 83 | dumpThisTime = len(streamDump) 84 | } 85 | stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime]) 86 | remainingToDump -= dumpThisTime 87 | } 88 | 89 | return stream, nil 90 | } 91 | 92 | // cipherModes documents properties of supported ciphers. Ciphers not included 93 | // are not supported and will not be negotiated, even if explicitly requested in 94 | // ClientConfig.Crypto.Ciphers. 95 | var cipherModes = map[string]*streamCipherMode{ 96 | // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms 97 | // are defined in the order specified in the RFC. 98 | "aes128-ctr": {16, aes.BlockSize, 0, newAESCTR}, 99 | "aes192-ctr": {24, aes.BlockSize, 0, newAESCTR}, 100 | "aes256-ctr": {32, aes.BlockSize, 0, newAESCTR}, 101 | 102 | // Ciphers from RFC4345, which introduces security-improved arcfour ciphers. 103 | // They are defined in the order specified in the RFC. 104 | "arcfour128": {16, 0, 1536, newRC4}, 105 | "arcfour256": {32, 0, 1536, newRC4}, 106 | 107 | // Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol. 108 | // Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and 109 | // RC4) has problems with weak keys, and should be used with caution." 110 | // RFC4345 introduces improved versions of Arcfour. 111 | "arcfour": {16, 0, 0, newRC4}, 112 | 113 | // AES-GCM is not a stream cipher, so it is constructed with a 114 | // special case. If we add any more non-stream ciphers, we 115 | // should invest a cleaner way to do this. 116 | gcmCipherID: {16, 12, 0, nil}, 117 | 118 | // insecure cipher, see http://www.isg.rhul.ac.uk/~kp/SandPfinal.pdf 119 | // uncomment below to enable it. 120 | // aes128cbcID: {16, aes.BlockSize, 0, nil}, 121 | } 122 | 123 | // prefixLen is the length of the packet prefix that contains the packet length 124 | // and number of padding bytes. 125 | const prefixLen = 5 126 | 127 | // streamPacketCipher is a packetCipher using a stream cipher. 128 | type streamPacketCipher struct { 129 | mac hash.Hash 130 | cipher cipher.Stream 131 | 132 | // The following members are to avoid per-packet allocations. 133 | prefix [prefixLen]byte 134 | seqNumBytes [4]byte 135 | padding [2 * packetSizeMultiple]byte 136 | packetData []byte 137 | macResult []byte 138 | } 139 | 140 | // readPacket reads and decrypt a single packet from the reader argument. 141 | func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { 142 | if _, err := io.ReadFull(r, s.prefix[:]); err != nil { 143 | return nil, err 144 | } 145 | 146 | s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) 147 | length := binary.BigEndian.Uint32(s.prefix[0:4]) 148 | paddingLength := uint32(s.prefix[4]) 149 | 150 | var macSize uint32 151 | if s.mac != nil { 152 | s.mac.Reset() 153 | binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) 154 | s.mac.Write(s.seqNumBytes[:]) 155 | s.mac.Write(s.prefix[:]) 156 | macSize = uint32(s.mac.Size()) 157 | } 158 | 159 | if length <= paddingLength+1 { 160 | return nil, errors.New("ssh: invalid packet length, packet too small") 161 | } 162 | 163 | if length > maxPacket { 164 | return nil, errors.New("ssh: invalid packet length, packet too large") 165 | } 166 | 167 | // the maxPacket check above ensures that length-1+macSize 168 | // does not overflow. 169 | if uint32(cap(s.packetData)) < length-1+macSize { 170 | s.packetData = make([]byte, length-1+macSize) 171 | } else { 172 | s.packetData = s.packetData[:length-1+macSize] 173 | } 174 | 175 | if _, err := io.ReadFull(r, s.packetData); err != nil { 176 | return nil, err 177 | } 178 | mac := s.packetData[length-1:] 179 | data := s.packetData[:length-1] 180 | s.cipher.XORKeyStream(data, data) 181 | 182 | if s.mac != nil { 183 | s.mac.Write(data) 184 | s.macResult = s.mac.Sum(s.macResult[:0]) 185 | if subtle.ConstantTimeCompare(s.macResult, mac) != 1 { 186 | return nil, errors.New("ssh: MAC failure") 187 | } 188 | } 189 | 190 | return s.packetData[:length-paddingLength-1], nil 191 | } 192 | 193 | // writePacket encrypts and sends a packet of data to the writer argument 194 | func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { 195 | if len(packet) > maxPacket { 196 | return errors.New("ssh: packet too large") 197 | } 198 | 199 | paddingLength := packetSizeMultiple - (prefixLen+len(packet))%packetSizeMultiple 200 | if paddingLength < 4 { 201 | paddingLength += packetSizeMultiple 202 | } 203 | 204 | length := len(packet) + 1 + paddingLength 205 | binary.BigEndian.PutUint32(s.prefix[:], uint32(length)) 206 | s.prefix[4] = byte(paddingLength) 207 | padding := s.padding[:paddingLength] 208 | if _, err := io.ReadFull(rand, padding); err != nil { 209 | return err 210 | } 211 | 212 | if s.mac != nil { 213 | s.mac.Reset() 214 | binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) 215 | s.mac.Write(s.seqNumBytes[:]) 216 | s.mac.Write(s.prefix[:]) 217 | s.mac.Write(packet) 218 | s.mac.Write(padding) 219 | } 220 | 221 | s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) 222 | s.cipher.XORKeyStream(packet, packet) 223 | s.cipher.XORKeyStream(padding, padding) 224 | 225 | if _, err := w.Write(s.prefix[:]); err != nil { 226 | return err 227 | } 228 | if _, err := w.Write(packet); err != nil { 229 | return err 230 | } 231 | if _, err := w.Write(padding); err != nil { 232 | return err 233 | } 234 | 235 | if s.mac != nil { 236 | s.macResult = s.mac.Sum(s.macResult[:0]) 237 | if _, err := w.Write(s.macResult); err != nil { 238 | return err 239 | } 240 | } 241 | 242 | return nil 243 | } 244 | 245 | type gcmCipher struct { 246 | aead cipher.AEAD 247 | prefix [4]byte 248 | iv []byte 249 | buf []byte 250 | } 251 | 252 | func newGCMCipher(iv, key, macKey []byte) (packetCipher, error) { 253 | c, err := aes.NewCipher(key) 254 | if err != nil { 255 | return nil, err 256 | } 257 | 258 | aead, err := cipher.NewGCM(c) 259 | if err != nil { 260 | return nil, err 261 | } 262 | 263 | return &gcmCipher{ 264 | aead: aead, 265 | iv: iv, 266 | }, nil 267 | } 268 | 269 | const gcmTagSize = 16 270 | 271 | func (c *gcmCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { 272 | // Pad out to multiple of 16 bytes. This is different from the 273 | // stream cipher because that encrypts the length too. 274 | padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple) 275 | if padding < 4 { 276 | padding += packetSizeMultiple 277 | } 278 | 279 | length := uint32(len(packet) + int(padding) + 1) 280 | binary.BigEndian.PutUint32(c.prefix[:], length) 281 | if _, err := w.Write(c.prefix[:]); err != nil { 282 | return err 283 | } 284 | 285 | if cap(c.buf) < int(length) { 286 | c.buf = make([]byte, length) 287 | } else { 288 | c.buf = c.buf[:length] 289 | } 290 | 291 | c.buf[0] = padding 292 | copy(c.buf[1:], packet) 293 | if _, err := io.ReadFull(rand, c.buf[1+len(packet):]); err != nil { 294 | return err 295 | } 296 | c.buf = c.aead.Seal(c.buf[:0], c.iv, c.buf, c.prefix[:]) 297 | if _, err := w.Write(c.buf); err != nil { 298 | return err 299 | } 300 | c.incIV() 301 | 302 | return nil 303 | } 304 | 305 | func (c *gcmCipher) incIV() { 306 | for i := 4 + 7; i >= 4; i-- { 307 | c.iv[i]++ 308 | if c.iv[i] != 0 { 309 | break 310 | } 311 | } 312 | } 313 | 314 | func (c *gcmCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { 315 | if _, err := io.ReadFull(r, c.prefix[:]); err != nil { 316 | return nil, err 317 | } 318 | length := binary.BigEndian.Uint32(c.prefix[:]) 319 | if length > maxPacket { 320 | return nil, errors.New("ssh: max packet length exceeded.") 321 | } 322 | 323 | if cap(c.buf) < int(length+gcmTagSize) { 324 | c.buf = make([]byte, length+gcmTagSize) 325 | } else { 326 | c.buf = c.buf[:length+gcmTagSize] 327 | } 328 | 329 | if _, err := io.ReadFull(r, c.buf); err != nil { 330 | return nil, err 331 | } 332 | 333 | plain, err := c.aead.Open(c.buf[:0], c.iv, c.buf, c.prefix[:]) 334 | if err != nil { 335 | return nil, err 336 | } 337 | c.incIV() 338 | 339 | padding := plain[0] 340 | if padding < 4 || padding >= 20 { 341 | return nil, fmt.Errorf("ssh: illegal padding %d", padding) 342 | } 343 | 344 | if int(padding+1) >= len(plain) { 345 | return nil, fmt.Errorf("ssh: padding %d too large", padding) 346 | } 347 | plain = plain[1 : length-uint32(padding)] 348 | return plain, nil 349 | } 350 | 351 | // cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1 352 | type cbcCipher struct { 353 | mac hash.Hash 354 | macSize uint32 355 | decrypter cipher.BlockMode 356 | encrypter cipher.BlockMode 357 | 358 | // The following members are to avoid per-packet allocations. 359 | seqNumBytes [4]byte 360 | packetData []byte 361 | macResult []byte 362 | 363 | // Amount of data we should still read to hide which 364 | // verification error triggered. 365 | oracleCamouflage uint32 366 | } 367 | 368 | func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { 369 | c, err := aes.NewCipher(key) 370 | if err != nil { 371 | return nil, err 372 | } 373 | 374 | cbc := &cbcCipher{ 375 | mac: macModes[algs.MAC].new(macKey), 376 | decrypter: cipher.NewCBCDecrypter(c, iv), 377 | encrypter: cipher.NewCBCEncrypter(c, iv), 378 | packetData: make([]byte, 1024), 379 | } 380 | if cbc.mac != nil { 381 | cbc.macSize = uint32(cbc.mac.Size()) 382 | } 383 | 384 | return cbc, nil 385 | } 386 | 387 | func maxUInt32(a, b int) uint32 { 388 | if a > b { 389 | return uint32(a) 390 | } 391 | return uint32(b) 392 | } 393 | 394 | const ( 395 | cbcMinPacketSizeMultiple = 8 396 | cbcMinPacketSize = 16 397 | cbcMinPaddingSize = 4 398 | ) 399 | 400 | // cbcError represents a verification error that may leak information. 401 | type cbcError string 402 | 403 | func (e cbcError) Error() string { return string(e) } 404 | 405 | func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { 406 | p, err := c.readPacketLeaky(seqNum, r) 407 | if err != nil { 408 | if _, ok := err.(cbcError); ok { 409 | // Verification error: read a fixed amount of 410 | // data, to make distinguishing between 411 | // failing MAC and failing length check more 412 | // difficult. 413 | io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage)) 414 | } 415 | } 416 | return p, err 417 | } 418 | 419 | func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) { 420 | blockSize := c.decrypter.BlockSize() 421 | 422 | // Read the header, which will include some of the subsequent data in the 423 | // case of block ciphers - this is copied back to the payload later. 424 | // How many bytes of payload/padding will be read with this first read. 425 | firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize) 426 | firstBlock := c.packetData[:firstBlockLength] 427 | if _, err := io.ReadFull(r, firstBlock); err != nil { 428 | return nil, err 429 | } 430 | 431 | c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength 432 | 433 | c.decrypter.CryptBlocks(firstBlock, firstBlock) 434 | length := binary.BigEndian.Uint32(firstBlock[:4]) 435 | if length > maxPacket { 436 | return nil, cbcError("ssh: packet too large") 437 | } 438 | if length+4 < maxUInt32(cbcMinPacketSize, blockSize) { 439 | // The minimum size of a packet is 16 (or the cipher block size, whichever 440 | // is larger) bytes. 441 | return nil, cbcError("ssh: packet too small") 442 | } 443 | // The length of the packet (including the length field but not the MAC) must 444 | // be a multiple of the block size or 8, whichever is larger. 445 | if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 { 446 | return nil, cbcError("ssh: invalid packet length multiple") 447 | } 448 | 449 | paddingLength := uint32(firstBlock[4]) 450 | if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 { 451 | return nil, cbcError("ssh: invalid packet length") 452 | } 453 | 454 | // Positions within the c.packetData buffer: 455 | macStart := 4 + length 456 | paddingStart := macStart - paddingLength 457 | 458 | // Entire packet size, starting before length, ending at end of mac. 459 | entirePacketSize := macStart + c.macSize 460 | 461 | // Ensure c.packetData is large enough for the entire packet data. 462 | if uint32(cap(c.packetData)) < entirePacketSize { 463 | // Still need to upsize and copy, but this should be rare at runtime, only 464 | // on upsizing the packetData buffer. 465 | c.packetData = make([]byte, entirePacketSize) 466 | copy(c.packetData, firstBlock) 467 | } else { 468 | c.packetData = c.packetData[:entirePacketSize] 469 | } 470 | 471 | if n, err := io.ReadFull(r, c.packetData[firstBlockLength:]); err != nil { 472 | return nil, err 473 | } else { 474 | c.oracleCamouflage -= uint32(n) 475 | } 476 | 477 | remainingCrypted := c.packetData[firstBlockLength:macStart] 478 | c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted) 479 | 480 | mac := c.packetData[macStart:] 481 | if c.mac != nil { 482 | c.mac.Reset() 483 | binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) 484 | c.mac.Write(c.seqNumBytes[:]) 485 | c.mac.Write(c.packetData[:macStart]) 486 | c.macResult = c.mac.Sum(c.macResult[:0]) 487 | if subtle.ConstantTimeCompare(c.macResult, mac) != 1 { 488 | return nil, cbcError("ssh: MAC failure") 489 | } 490 | } 491 | 492 | return c.packetData[prefixLen:paddingStart], nil 493 | } 494 | 495 | func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { 496 | effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize()) 497 | 498 | // Length of encrypted portion of the packet (header, payload, padding). 499 | // Enforce minimum padding and packet size. 500 | encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize) 501 | // Enforce block size. 502 | encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize 503 | 504 | length := encLength - 4 505 | paddingLength := int(length) - (1 + len(packet)) 506 | 507 | // Overall buffer contains: header, payload, padding, mac. 508 | // Space for the MAC is reserved in the capacity but not the slice length. 509 | bufferSize := encLength + c.macSize 510 | if uint32(cap(c.packetData)) < bufferSize { 511 | c.packetData = make([]byte, encLength, bufferSize) 512 | } else { 513 | c.packetData = c.packetData[:encLength] 514 | } 515 | 516 | p := c.packetData 517 | 518 | // Packet header. 519 | binary.BigEndian.PutUint32(p, length) 520 | p = p[4:] 521 | p[0] = byte(paddingLength) 522 | 523 | // Payload. 524 | p = p[1:] 525 | copy(p, packet) 526 | 527 | // Padding. 528 | p = p[len(packet):] 529 | if _, err := io.ReadFull(rand, p); err != nil { 530 | return err 531 | } 532 | 533 | if c.mac != nil { 534 | c.mac.Reset() 535 | binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) 536 | c.mac.Write(c.seqNumBytes[:]) 537 | c.mac.Write(c.packetData) 538 | // The MAC is now appended into the capacity reserved for it earlier. 539 | c.packetData = c.mac.Sum(c.packetData) 540 | } 541 | 542 | c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength]) 543 | 544 | if _, err := w.Write(c.packetData); err != nil { 545 | return err 546 | } 547 | 548 | return nil 549 | } 550 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "net" 11 | "sync" 12 | ) 13 | 14 | // Client implements a traditional SSH client that supports shells, 15 | // subprocesses, port forwarding and tunneled dialing. 16 | type Client struct { 17 | Conn 18 | 19 | forwards forwardList // forwarded tcpip connections from the remote side 20 | mu sync.Mutex 21 | channelHandlers map[string]chan NewChannel 22 | } 23 | 24 | // HandleChannelOpen returns a channel on which NewChannel requests 25 | // for the given type are sent. If the type already is being handled, 26 | // nil is returned. The channel is closed when the connection is closed. 27 | func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel { 28 | c.mu.Lock() 29 | defer c.mu.Unlock() 30 | if c.channelHandlers == nil { 31 | // The SSH channel has been closed. 32 | c := make(chan NewChannel) 33 | close(c) 34 | return c 35 | } 36 | 37 | ch := c.channelHandlers[channelType] 38 | if ch != nil { 39 | return nil 40 | } 41 | 42 | ch = make(chan NewChannel, 16) 43 | c.channelHandlers[channelType] = ch 44 | return ch 45 | } 46 | 47 | // NewClient creates a Client on top of the given connection. 48 | func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client { 49 | conn := &Client{ 50 | Conn: c, 51 | channelHandlers: make(map[string]chan NewChannel, 1), 52 | } 53 | 54 | go conn.handleGlobalRequests(reqs) 55 | go conn.handleChannelOpens(chans) 56 | go func() { 57 | conn.Wait() 58 | conn.forwards.closeAll() 59 | }() 60 | go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip")) 61 | return conn 62 | } 63 | 64 | // NewClientConn establishes an authenticated SSH connection using c 65 | // as the underlying transport. The Request and NewChannel channels 66 | // must be serviced or the connection will hang. 67 | func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) { 68 | fullConf := *config 69 | fullConf.SetDefaults() 70 | conn := &connection{ 71 | sshConn: sshConn{conn: c}, 72 | } 73 | 74 | if err := conn.clientHandshake(addr, &fullConf); err != nil { 75 | c.Close() 76 | return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err) 77 | } 78 | conn.mux = newMux(conn.transport) 79 | return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil 80 | } 81 | 82 | // clientHandshake performs the client side key exchange. See RFC 4253 Section 83 | // 7. 84 | func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error { 85 | if config.ClientVersion != "" { 86 | c.clientVersion = []byte(config.ClientVersion) 87 | } else { 88 | c.clientVersion = []byte(packageVersion) 89 | } 90 | var err error 91 | c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion) 92 | if err != nil { 93 | return err 94 | } 95 | 96 | c.transport = newClientTransport( 97 | newTransport(c.sshConn.conn, config.Rand, true /* is client */), 98 | c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr()) 99 | if err := c.transport.requestKeyChange(); err != nil { 100 | return err 101 | } 102 | 103 | if packet, err := c.transport.readPacket(); err != nil { 104 | return err 105 | } else if packet[0] != msgNewKeys { 106 | return unexpectedMessageError(msgNewKeys, packet[0]) 107 | } 108 | 109 | // We just did the key change, so the session ID is established. 110 | c.sessionID = c.transport.getSessionID() 111 | 112 | return c.clientAuthenticate(config) 113 | } 114 | 115 | // verifyHostKeySignature verifies the host key obtained in the key 116 | // exchange. 117 | func verifyHostKeySignature(hostKey PublicKey, result *kexResult) error { 118 | sig, rest, ok := parseSignatureBody(result.Signature) 119 | if len(rest) > 0 || !ok { 120 | return errors.New("ssh: signature parse error") 121 | } 122 | 123 | return hostKey.Verify(result.H, sig) 124 | } 125 | 126 | // NewSession opens a new Session for this client. (A session is a remote 127 | // execution of a program.) 128 | func (c *Client) NewSession() (*Session, error) { 129 | ch, in, err := c.OpenChannel("session", nil) 130 | if err != nil { 131 | return nil, err 132 | } 133 | return newSession(ch, in) 134 | } 135 | 136 | func (c *Client) handleGlobalRequests(incoming <-chan *Request) { 137 | for r := range incoming { 138 | // This handles keepalive messages and matches 139 | // the behaviour of OpenSSH. 140 | r.Reply(false, nil) 141 | } 142 | } 143 | 144 | // handleChannelOpens channel open messages from the remote side. 145 | func (c *Client) handleChannelOpens(in <-chan NewChannel) { 146 | for ch := range in { 147 | c.mu.Lock() 148 | handler := c.channelHandlers[ch.ChannelType()] 149 | c.mu.Unlock() 150 | 151 | if handler != nil { 152 | handler <- ch 153 | } else { 154 | ch.Reject(UnknownChannelType, fmt.Sprintf("unknown channel type: %v", ch.ChannelType())) 155 | } 156 | } 157 | 158 | c.mu.Lock() 159 | for _, ch := range c.channelHandlers { 160 | close(ch) 161 | } 162 | c.channelHandlers = nil 163 | c.mu.Unlock() 164 | } 165 | 166 | // Dial starts a client connection to the given SSH server. It is a 167 | // convenience function that connects to the given network address, 168 | // initiates the SSH handshake, and then sets up a Client. For access 169 | // to incoming channels and requests, use net.Dial with NewClientConn 170 | // instead. 171 | func Dial(network, addr string, config *ClientConfig) (*Client, error) { 172 | conn, err := net.Dial(network, addr) 173 | if err != nil { 174 | return nil, err 175 | } 176 | c, chans, reqs, err := NewClientConn(conn, addr, config) 177 | if err != nil { 178 | return nil, err 179 | } 180 | return NewClient(c, chans, reqs), nil 181 | } 182 | 183 | // A ClientConfig structure is used to configure a Client. It must not be 184 | // modified after having been passed to an SSH function. 185 | type ClientConfig struct { 186 | // Config contains configuration that is shared between clients and 187 | // servers. 188 | Config 189 | 190 | // User contains the username to authenticate as. 191 | User string 192 | 193 | // Auth contains possible authentication methods to use with the 194 | // server. Only the first instance of a particular RFC 4252 method will 195 | // be used during authentication. 196 | Auth []AuthMethod 197 | 198 | // HostKeyCallback, if not nil, is called during the cryptographic 199 | // handshake to validate the server's host key. A nil HostKeyCallback 200 | // implies that all host keys are accepted. 201 | HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error 202 | 203 | // ClientVersion contains the version identification string that will 204 | // be used for the connection. If empty, a reasonable default is used. 205 | ClientVersion string 206 | 207 | // HostKeyAlgorithms lists the key types that the client will 208 | // accept from the server as host key, in order of 209 | // preference. If empty, a reasonable default is used. Any 210 | // string returned from PublicKey.Type method may be used, or 211 | // any of the CertAlgoXxxx and KeyAlgoXxxx constants. 212 | HostKeyAlgorithms []string 213 | } 214 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/client_auth.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "bytes" 9 | "errors" 10 | "fmt" 11 | "io" 12 | ) 13 | 14 | // clientAuthenticate authenticates with the remote server. See RFC 4252. 15 | func (c *connection) clientAuthenticate(config *ClientConfig) error { 16 | // initiate user auth session 17 | if err := c.transport.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth})); err != nil { 18 | return err 19 | } 20 | packet, err := c.transport.readPacket() 21 | if err != nil { 22 | return err 23 | } 24 | var serviceAccept serviceAcceptMsg 25 | if err := Unmarshal(packet, &serviceAccept); err != nil { 26 | return err 27 | } 28 | 29 | // during the authentication phase the client first attempts the "none" method 30 | // then any untried methods suggested by the server. 31 | tried := make(map[string]bool) 32 | var lastMethods []string 33 | for auth := AuthMethod(new(noneAuth)); auth != nil; { 34 | ok, methods, err := auth.auth(c.transport.getSessionID(), config.User, c.transport, config.Rand) 35 | if err != nil { 36 | return err 37 | } 38 | if ok { 39 | // success 40 | return nil 41 | } 42 | tried[auth.method()] = true 43 | if methods == nil { 44 | methods = lastMethods 45 | } 46 | lastMethods = methods 47 | 48 | auth = nil 49 | 50 | findNext: 51 | for _, a := range config.Auth { 52 | candidateMethod := a.method() 53 | if tried[candidateMethod] { 54 | continue 55 | } 56 | for _, meth := range methods { 57 | if meth == candidateMethod { 58 | auth = a 59 | break findNext 60 | } 61 | } 62 | } 63 | } 64 | return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", keys(tried)) 65 | } 66 | 67 | func keys(m map[string]bool) []string { 68 | s := make([]string, 0, len(m)) 69 | 70 | for key := range m { 71 | s = append(s, key) 72 | } 73 | return s 74 | } 75 | 76 | // An AuthMethod represents an instance of an RFC 4252 authentication method. 77 | type AuthMethod interface { 78 | // auth authenticates user over transport t. 79 | // Returns true if authentication is successful. 80 | // If authentication is not successful, a []string of alternative 81 | // method names is returned. If the slice is nil, it will be ignored 82 | // and the previous set of possible methods will be reused. 83 | auth(session []byte, user string, p packetConn, rand io.Reader) (bool, []string, error) 84 | 85 | // method returns the RFC 4252 method name. 86 | method() string 87 | } 88 | 89 | // "none" authentication, RFC 4252 section 5.2. 90 | type noneAuth int 91 | 92 | func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { 93 | if err := c.writePacket(Marshal(&userAuthRequestMsg{ 94 | User: user, 95 | Service: serviceSSH, 96 | Method: "none", 97 | })); err != nil { 98 | return false, nil, err 99 | } 100 | 101 | return handleAuthResponse(c) 102 | } 103 | 104 | func (n *noneAuth) method() string { 105 | return "none" 106 | } 107 | 108 | // passwordCallback is an AuthMethod that fetches the password through 109 | // a function call, e.g. by prompting the user. 110 | type passwordCallback func() (password string, err error) 111 | 112 | func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { 113 | type passwordAuthMsg struct { 114 | User string `sshtype:"50"` 115 | Service string 116 | Method string 117 | Reply bool 118 | Password string 119 | } 120 | 121 | pw, err := cb() 122 | // REVIEW NOTE: is there a need to support skipping a password attempt? 123 | // The program may only find out that the user doesn't have a password 124 | // when prompting. 125 | if err != nil { 126 | return false, nil, err 127 | } 128 | 129 | if err := c.writePacket(Marshal(&passwordAuthMsg{ 130 | User: user, 131 | Service: serviceSSH, 132 | Method: cb.method(), 133 | Reply: false, 134 | Password: pw, 135 | })); err != nil { 136 | return false, nil, err 137 | } 138 | 139 | return handleAuthResponse(c) 140 | } 141 | 142 | func (cb passwordCallback) method() string { 143 | return "password" 144 | } 145 | 146 | // Password returns an AuthMethod using the given password. 147 | func Password(secret string) AuthMethod { 148 | return passwordCallback(func() (string, error) { return secret, nil }) 149 | } 150 | 151 | // PasswordCallback returns an AuthMethod that uses a callback for 152 | // fetching a password. 153 | func PasswordCallback(prompt func() (secret string, err error)) AuthMethod { 154 | return passwordCallback(prompt) 155 | } 156 | 157 | type publickeyAuthMsg struct { 158 | User string `sshtype:"50"` 159 | Service string 160 | Method string 161 | // HasSig indicates to the receiver packet that the auth request is signed and 162 | // should be used for authentication of the request. 163 | HasSig bool 164 | Algoname string 165 | PubKey []byte 166 | // Sig is tagged with "rest" so Marshal will exclude it during 167 | // validateKey 168 | Sig []byte `ssh:"rest"` 169 | } 170 | 171 | // publicKeyCallback is an AuthMethod that uses a set of key 172 | // pairs for authentication. 173 | type publicKeyCallback func() ([]Signer, error) 174 | 175 | func (cb publicKeyCallback) method() string { 176 | return "publickey" 177 | } 178 | 179 | func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { 180 | // Authentication is performed in two stages. The first stage sends an 181 | // enquiry to test if each key is acceptable to the remote. The second 182 | // stage attempts to authenticate with the valid keys obtained in the 183 | // first stage. 184 | 185 | signers, err := cb() 186 | if err != nil { 187 | return false, nil, err 188 | } 189 | var validKeys []Signer 190 | for _, signer := range signers { 191 | if ok, err := validateKey(signer.PublicKey(), user, c); ok { 192 | validKeys = append(validKeys, signer) 193 | } else { 194 | if err != nil { 195 | return false, nil, err 196 | } 197 | } 198 | } 199 | 200 | // methods that may continue if this auth is not successful. 201 | var methods []string 202 | for _, signer := range validKeys { 203 | pub := signer.PublicKey() 204 | 205 | pubKey := pub.Marshal() 206 | sign, err := signer.Sign(rand, buildDataSignedForAuth(session, userAuthRequestMsg{ 207 | User: user, 208 | Service: serviceSSH, 209 | Method: cb.method(), 210 | }, []byte(pub.Type()), pubKey)) 211 | if err != nil { 212 | return false, nil, err 213 | } 214 | 215 | // manually wrap the serialized signature in a string 216 | s := Marshal(sign) 217 | sig := make([]byte, stringLength(len(s))) 218 | marshalString(sig, s) 219 | msg := publickeyAuthMsg{ 220 | User: user, 221 | Service: serviceSSH, 222 | Method: cb.method(), 223 | HasSig: true, 224 | Algoname: pub.Type(), 225 | PubKey: pubKey, 226 | Sig: sig, 227 | } 228 | p := Marshal(&msg) 229 | if err := c.writePacket(p); err != nil { 230 | return false, nil, err 231 | } 232 | var success bool 233 | success, methods, err = handleAuthResponse(c) 234 | if err != nil { 235 | return false, nil, err 236 | } 237 | if success { 238 | return success, methods, err 239 | } 240 | } 241 | return false, methods, nil 242 | } 243 | 244 | // validateKey validates the key provided is acceptable to the server. 245 | func validateKey(key PublicKey, user string, c packetConn) (bool, error) { 246 | pubKey := key.Marshal() 247 | msg := publickeyAuthMsg{ 248 | User: user, 249 | Service: serviceSSH, 250 | Method: "publickey", 251 | HasSig: false, 252 | Algoname: key.Type(), 253 | PubKey: pubKey, 254 | } 255 | if err := c.writePacket(Marshal(&msg)); err != nil { 256 | return false, err 257 | } 258 | 259 | return confirmKeyAck(key, c) 260 | } 261 | 262 | func confirmKeyAck(key PublicKey, c packetConn) (bool, error) { 263 | pubKey := key.Marshal() 264 | algoname := key.Type() 265 | 266 | for { 267 | packet, err := c.readPacket() 268 | if err != nil { 269 | return false, err 270 | } 271 | switch packet[0] { 272 | case msgUserAuthBanner: 273 | // TODO(gpaul): add callback to present the banner to the user 274 | case msgUserAuthPubKeyOk: 275 | var msg userAuthPubKeyOkMsg 276 | if err := Unmarshal(packet, &msg); err != nil { 277 | return false, err 278 | } 279 | if msg.Algo != algoname || !bytes.Equal(msg.PubKey, pubKey) { 280 | return false, nil 281 | } 282 | return true, nil 283 | case msgUserAuthFailure: 284 | return false, nil 285 | default: 286 | return false, unexpectedMessageError(msgUserAuthSuccess, packet[0]) 287 | } 288 | } 289 | } 290 | 291 | // PublicKeys returns an AuthMethod that uses the given key 292 | // pairs. 293 | func PublicKeys(signers ...Signer) AuthMethod { 294 | return publicKeyCallback(func() ([]Signer, error) { return signers, nil }) 295 | } 296 | 297 | // PublicKeysCallback returns an AuthMethod that runs the given 298 | // function to obtain a list of key pairs. 299 | func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMethod { 300 | return publicKeyCallback(getSigners) 301 | } 302 | 303 | // handleAuthResponse returns whether the preceding authentication request succeeded 304 | // along with a list of remaining authentication methods to try next and 305 | // an error if an unexpected response was received. 306 | func handleAuthResponse(c packetConn) (bool, []string, error) { 307 | for { 308 | packet, err := c.readPacket() 309 | if err != nil { 310 | return false, nil, err 311 | } 312 | 313 | switch packet[0] { 314 | case msgUserAuthBanner: 315 | // TODO: add callback to present the banner to the user 316 | case msgUserAuthFailure: 317 | var msg userAuthFailureMsg 318 | if err := Unmarshal(packet, &msg); err != nil { 319 | return false, nil, err 320 | } 321 | return false, msg.Methods, nil 322 | case msgUserAuthSuccess: 323 | return true, nil, nil 324 | case msgDisconnect: 325 | return false, nil, io.EOF 326 | default: 327 | return false, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0]) 328 | } 329 | } 330 | } 331 | 332 | // KeyboardInteractiveChallenge should print questions, optionally 333 | // disabling echoing (e.g. for passwords), and return all the answers. 334 | // Challenge may be called multiple times in a single session. After 335 | // successful authentication, the server may send a challenge with no 336 | // questions, for which the user and instruction messages should be 337 | // printed. RFC 4256 section 3.3 details how the UI should behave for 338 | // both CLI and GUI environments. 339 | type KeyboardInteractiveChallenge func(user, instruction string, questions []string, echos []bool) (answers []string, err error) 340 | 341 | // KeyboardInteractive returns a AuthMethod using a prompt/response 342 | // sequence controlled by the server. 343 | func KeyboardInteractive(challenge KeyboardInteractiveChallenge) AuthMethod { 344 | return challenge 345 | } 346 | 347 | func (cb KeyboardInteractiveChallenge) method() string { 348 | return "keyboard-interactive" 349 | } 350 | 351 | func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { 352 | type initiateMsg struct { 353 | User string `sshtype:"50"` 354 | Service string 355 | Method string 356 | Language string 357 | Submethods string 358 | } 359 | 360 | if err := c.writePacket(Marshal(&initiateMsg{ 361 | User: user, 362 | Service: serviceSSH, 363 | Method: "keyboard-interactive", 364 | })); err != nil { 365 | return false, nil, err 366 | } 367 | 368 | for { 369 | packet, err := c.readPacket() 370 | if err != nil { 371 | return false, nil, err 372 | } 373 | 374 | // like handleAuthResponse, but with less options. 375 | switch packet[0] { 376 | case msgUserAuthBanner: 377 | // TODO: Print banners during userauth. 378 | continue 379 | case msgUserAuthInfoRequest: 380 | // OK 381 | case msgUserAuthFailure: 382 | var msg userAuthFailureMsg 383 | if err := Unmarshal(packet, &msg); err != nil { 384 | return false, nil, err 385 | } 386 | return false, msg.Methods, nil 387 | case msgUserAuthSuccess: 388 | return true, nil, nil 389 | default: 390 | return false, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0]) 391 | } 392 | 393 | var msg userAuthInfoRequestMsg 394 | if err := Unmarshal(packet, &msg); err != nil { 395 | return false, nil, err 396 | } 397 | 398 | // Manually unpack the prompt/echo pairs. 399 | rest := msg.Prompts 400 | var prompts []string 401 | var echos []bool 402 | for i := 0; i < int(msg.NumPrompts); i++ { 403 | prompt, r, ok := parseString(rest) 404 | if !ok || len(r) == 0 { 405 | return false, nil, errors.New("ssh: prompt format error") 406 | } 407 | prompts = append(prompts, string(prompt)) 408 | echos = append(echos, r[0] != 0) 409 | rest = r[1:] 410 | } 411 | 412 | if len(rest) != 0 { 413 | return false, nil, errors.New("ssh: extra data following keyboard-interactive pairs") 414 | } 415 | 416 | answers, err := cb(msg.User, msg.Instruction, prompts, echos) 417 | if err != nil { 418 | return false, nil, err 419 | } 420 | 421 | if len(answers) != len(prompts) { 422 | return false, nil, errors.New("ssh: not enough answers from keyboard-interactive callback") 423 | } 424 | responseLength := 1 + 4 425 | for _, a := range answers { 426 | responseLength += stringLength(len(a)) 427 | } 428 | serialized := make([]byte, responseLength) 429 | p := serialized 430 | p[0] = msgUserAuthInfoResponse 431 | p = p[1:] 432 | p = marshalUint32(p, uint32(len(answers))) 433 | for _, a := range answers { 434 | p = marshalString(p, []byte(a)) 435 | } 436 | 437 | if err := c.writePacket(serialized); err != nil { 438 | return false, nil, err 439 | } 440 | } 441 | } 442 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/common.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "crypto" 9 | "crypto/rand" 10 | "fmt" 11 | "io" 12 | "sync" 13 | 14 | _ "crypto/sha1" 15 | _ "crypto/sha256" 16 | _ "crypto/sha512" 17 | ) 18 | 19 | // These are string constants in the SSH protocol. 20 | const ( 21 | compressionNone = "none" 22 | serviceUserAuth = "ssh-userauth" 23 | serviceSSH = "ssh-connection" 24 | ) 25 | 26 | // supportedCiphers specifies the supported ciphers in preference order. 27 | var supportedCiphers = []string{ 28 | "aes128-ctr", "aes192-ctr", "aes256-ctr", 29 | "aes128-gcm@openssh.com", 30 | "arcfour256", "arcfour128", 31 | } 32 | 33 | // supportedKexAlgos specifies the supported key-exchange algorithms in 34 | // preference order. 35 | var supportedKexAlgos = []string{ 36 | kexAlgoCurve25519SHA256, 37 | // P384 and P521 are not constant-time yet, but since we don't 38 | // reuse ephemeral keys, using them for ECDH should be OK. 39 | kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, 40 | kexAlgoDH14SHA1, kexAlgoDH1SHA1, 41 | } 42 | 43 | // supportedKexAlgos specifies the supported host-key algorithms (i.e. methods 44 | // of authenticating servers) in preference order. 45 | var supportedHostKeyAlgos = []string{ 46 | CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, 47 | CertAlgoECDSA384v01, CertAlgoECDSA521v01, 48 | 49 | KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, 50 | KeyAlgoRSA, KeyAlgoDSA, 51 | } 52 | 53 | // supportedMACs specifies a default set of MAC algorithms in preference order. 54 | // This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed 55 | // because they have reached the end of their useful life. 56 | var supportedMACs = []string{ 57 | "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96", 58 | } 59 | 60 | var supportedCompressions = []string{compressionNone} 61 | 62 | // hashFuncs keeps the mapping of supported algorithms to their respective 63 | // hashes needed for signature verification. 64 | var hashFuncs = map[string]crypto.Hash{ 65 | KeyAlgoRSA: crypto.SHA1, 66 | KeyAlgoDSA: crypto.SHA1, 67 | KeyAlgoECDSA256: crypto.SHA256, 68 | KeyAlgoECDSA384: crypto.SHA384, 69 | KeyAlgoECDSA521: crypto.SHA512, 70 | CertAlgoRSAv01: crypto.SHA1, 71 | CertAlgoDSAv01: crypto.SHA1, 72 | CertAlgoECDSA256v01: crypto.SHA256, 73 | CertAlgoECDSA384v01: crypto.SHA384, 74 | CertAlgoECDSA521v01: crypto.SHA512, 75 | } 76 | 77 | // unexpectedMessageError results when the SSH message that we received didn't 78 | // match what we wanted. 79 | func unexpectedMessageError(expected, got uint8) error { 80 | return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected) 81 | } 82 | 83 | // parseError results from a malformed SSH message. 84 | func parseError(tag uint8) error { 85 | return fmt.Errorf("ssh: parse error in message type %d", tag) 86 | } 87 | 88 | func findCommon(what string, client []string, server []string) (common string, err error) { 89 | for _, c := range client { 90 | for _, s := range server { 91 | if c == s { 92 | return c, nil 93 | } 94 | } 95 | } 96 | return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server) 97 | } 98 | 99 | type directionAlgorithms struct { 100 | Cipher string 101 | MAC string 102 | Compression string 103 | } 104 | 105 | type algorithms struct { 106 | kex string 107 | hostKey string 108 | w directionAlgorithms 109 | r directionAlgorithms 110 | } 111 | 112 | func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) { 113 | result := &algorithms{} 114 | 115 | result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos) 116 | if err != nil { 117 | return 118 | } 119 | 120 | result.hostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos) 121 | if err != nil { 122 | return 123 | } 124 | 125 | result.w.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) 126 | if err != nil { 127 | return 128 | } 129 | 130 | result.r.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) 131 | if err != nil { 132 | return 133 | } 134 | 135 | result.w.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer) 136 | if err != nil { 137 | return 138 | } 139 | 140 | result.r.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient) 141 | if err != nil { 142 | return 143 | } 144 | 145 | result.w.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer) 146 | if err != nil { 147 | return 148 | } 149 | 150 | result.r.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient) 151 | if err != nil { 152 | return 153 | } 154 | 155 | return result, nil 156 | } 157 | 158 | // If rekeythreshold is too small, we can't make any progress sending 159 | // stuff. 160 | const minRekeyThreshold uint64 = 256 161 | 162 | // Config contains configuration data common to both ServerConfig and 163 | // ClientConfig. 164 | type Config struct { 165 | // Rand provides the source of entropy for cryptographic 166 | // primitives. If Rand is nil, the cryptographic random reader 167 | // in package crypto/rand will be used. 168 | Rand io.Reader 169 | 170 | // The maximum number of bytes sent or received after which a 171 | // new key is negotiated. It must be at least 256. If 172 | // unspecified, 1 gigabyte is used. 173 | RekeyThreshold uint64 174 | 175 | // The allowed key exchanges algorithms. If unspecified then a 176 | // default set of algorithms is used. 177 | KeyExchanges []string 178 | 179 | // The allowed cipher algorithms. If unspecified then a sensible 180 | // default is used. 181 | Ciphers []string 182 | 183 | // The allowed MAC algorithms. If unspecified then a sensible default 184 | // is used. 185 | MACs []string 186 | } 187 | 188 | // SetDefaults sets sensible values for unset fields in config. This is 189 | // exported for testing: Configs passed to SSH functions are copied and have 190 | // default values set automatically. 191 | func (c *Config) SetDefaults() { 192 | if c.Rand == nil { 193 | c.Rand = rand.Reader 194 | } 195 | if c.Ciphers == nil { 196 | c.Ciphers = supportedCiphers 197 | } 198 | var ciphers []string 199 | for _, c := range c.Ciphers { 200 | if cipherModes[c] != nil { 201 | // reject the cipher if we have no cipherModes definition 202 | ciphers = append(ciphers, c) 203 | } 204 | } 205 | c.Ciphers = ciphers 206 | 207 | if c.KeyExchanges == nil { 208 | c.KeyExchanges = supportedKexAlgos 209 | } 210 | 211 | if c.MACs == nil { 212 | c.MACs = supportedMACs 213 | } 214 | 215 | if c.RekeyThreshold == 0 { 216 | // RFC 4253, section 9 suggests rekeying after 1G. 217 | c.RekeyThreshold = 1 << 30 218 | } 219 | if c.RekeyThreshold < minRekeyThreshold { 220 | c.RekeyThreshold = minRekeyThreshold 221 | } 222 | } 223 | 224 | // buildDataSignedForAuth returns the data that is signed in order to prove 225 | // possession of a private key. See RFC 4252, section 7. 226 | func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte { 227 | data := struct { 228 | Session []byte 229 | Type byte 230 | User string 231 | Service string 232 | Method string 233 | Sign bool 234 | Algo []byte 235 | PubKey []byte 236 | }{ 237 | sessionId, 238 | msgUserAuthRequest, 239 | req.User, 240 | req.Service, 241 | req.Method, 242 | true, 243 | algo, 244 | pubKey, 245 | } 246 | return Marshal(data) 247 | } 248 | 249 | func appendU16(buf []byte, n uint16) []byte { 250 | return append(buf, byte(n>>8), byte(n)) 251 | } 252 | 253 | func appendU32(buf []byte, n uint32) []byte { 254 | return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) 255 | } 256 | 257 | func appendU64(buf []byte, n uint64) []byte { 258 | return append(buf, 259 | byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), 260 | byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) 261 | } 262 | 263 | func appendInt(buf []byte, n int) []byte { 264 | return appendU32(buf, uint32(n)) 265 | } 266 | 267 | func appendString(buf []byte, s string) []byte { 268 | buf = appendU32(buf, uint32(len(s))) 269 | buf = append(buf, s...) 270 | return buf 271 | } 272 | 273 | func appendBool(buf []byte, b bool) []byte { 274 | if b { 275 | return append(buf, 1) 276 | } 277 | return append(buf, 0) 278 | } 279 | 280 | // newCond is a helper to hide the fact that there is no usable zero 281 | // value for sync.Cond. 282 | func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) } 283 | 284 | // window represents the buffer available to clients 285 | // wishing to write to a channel. 286 | type window struct { 287 | *sync.Cond 288 | win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1 289 | writeWaiters int 290 | closed bool 291 | } 292 | 293 | // add adds win to the amount of window available 294 | // for consumers. 295 | func (w *window) add(win uint32) bool { 296 | // a zero sized window adjust is a noop. 297 | if win == 0 { 298 | return true 299 | } 300 | w.L.Lock() 301 | if w.win+win < win { 302 | w.L.Unlock() 303 | return false 304 | } 305 | w.win += win 306 | // It is unusual that multiple goroutines would be attempting to reserve 307 | // window space, but not guaranteed. Use broadcast to notify all waiters 308 | // that additional window is available. 309 | w.Broadcast() 310 | w.L.Unlock() 311 | return true 312 | } 313 | 314 | // close sets the window to closed, so all reservations fail 315 | // immediately. 316 | func (w *window) close() { 317 | w.L.Lock() 318 | w.closed = true 319 | w.Broadcast() 320 | w.L.Unlock() 321 | } 322 | 323 | // reserve reserves win from the available window capacity. 324 | // If no capacity remains, reserve will block. reserve may 325 | // return less than requested. 326 | func (w *window) reserve(win uint32) (uint32, error) { 327 | var err error 328 | w.L.Lock() 329 | w.writeWaiters++ 330 | w.Broadcast() 331 | for w.win == 0 && !w.closed { 332 | w.Wait() 333 | } 334 | w.writeWaiters-- 335 | if w.win < win { 336 | win = w.win 337 | } 338 | w.win -= win 339 | if w.closed { 340 | err = io.EOF 341 | } 342 | w.L.Unlock() 343 | return win, err 344 | } 345 | 346 | // waitWriterBlocked waits until some goroutine is blocked for further 347 | // writes. It is used in tests only. 348 | func (w *window) waitWriterBlocked() { 349 | w.Cond.L.Lock() 350 | for w.writeWaiters == 0 { 351 | w.Cond.Wait() 352 | } 353 | w.Cond.L.Unlock() 354 | } 355 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/connection.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "fmt" 9 | "net" 10 | ) 11 | 12 | // OpenChannelError is returned if the other side rejects an 13 | // OpenChannel request. 14 | type OpenChannelError struct { 15 | Reason RejectionReason 16 | Message string 17 | } 18 | 19 | func (e *OpenChannelError) Error() string { 20 | return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message) 21 | } 22 | 23 | // ConnMetadata holds metadata for the connection. 24 | type ConnMetadata interface { 25 | // User returns the user ID for this connection. 26 | // It is empty if no authentication is used. 27 | User() string 28 | 29 | // SessionID returns the sesson hash, also denoted by H. 30 | SessionID() []byte 31 | 32 | // ClientVersion returns the client's version string as hashed 33 | // into the session ID. 34 | ClientVersion() []byte 35 | 36 | // ServerVersion returns the server's version string as hashed 37 | // into the session ID. 38 | ServerVersion() []byte 39 | 40 | // RemoteAddr returns the remote address for this connection. 41 | RemoteAddr() net.Addr 42 | 43 | // LocalAddr returns the local address for this connection. 44 | LocalAddr() net.Addr 45 | } 46 | 47 | // Conn represents an SSH connection for both server and client roles. 48 | // Conn is the basis for implementing an application layer, such 49 | // as ClientConn, which implements the traditional shell access for 50 | // clients. 51 | type Conn interface { 52 | ConnMetadata 53 | 54 | // SendRequest sends a global request, and returns the 55 | // reply. If wantReply is true, it returns the response status 56 | // and payload. See also RFC4254, section 4. 57 | SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) 58 | 59 | // OpenChannel tries to open an channel. If the request is 60 | // rejected, it returns *OpenChannelError. On success it returns 61 | // the SSH Channel and a Go channel for incoming, out-of-band 62 | // requests. The Go channel must be serviced, or the 63 | // connection will hang. 64 | OpenChannel(name string, data []byte) (Channel, <-chan *Request, error) 65 | 66 | // Close closes the underlying network connection 67 | Close() error 68 | 69 | // Wait blocks until the connection has shut down, and returns the 70 | // error causing the shutdown. 71 | Wait() error 72 | 73 | // TODO(hanwen): consider exposing: 74 | // RequestKeyChange 75 | // Disconnect 76 | } 77 | 78 | // DiscardRequests consumes and rejects all requests from the 79 | // passed-in channel. 80 | func DiscardRequests(in <-chan *Request) { 81 | for req := range in { 82 | if req.WantReply { 83 | req.Reply(false, nil) 84 | } 85 | } 86 | } 87 | 88 | // A connection represents an incoming connection. 89 | type connection struct { 90 | transport *handshakeTransport 91 | sshConn 92 | 93 | // The connection protocol. 94 | *mux 95 | } 96 | 97 | func (c *connection) Close() error { 98 | return c.sshConn.conn.Close() 99 | } 100 | 101 | // sshconn provides net.Conn metadata, but disallows direct reads and 102 | // writes. 103 | type sshConn struct { 104 | conn net.Conn 105 | 106 | user string 107 | sessionID []byte 108 | clientVersion []byte 109 | serverVersion []byte 110 | } 111 | 112 | func dup(src []byte) []byte { 113 | dst := make([]byte, len(src)) 114 | copy(dst, src) 115 | return dst 116 | } 117 | 118 | func (c *sshConn) User() string { 119 | return c.user 120 | } 121 | 122 | func (c *sshConn) RemoteAddr() net.Addr { 123 | return c.conn.RemoteAddr() 124 | } 125 | 126 | func (c *sshConn) Close() error { 127 | return c.conn.Close() 128 | } 129 | 130 | func (c *sshConn) LocalAddr() net.Addr { 131 | return c.conn.LocalAddr() 132 | } 133 | 134 | func (c *sshConn) SessionID() []byte { 135 | return dup(c.sessionID) 136 | } 137 | 138 | func (c *sshConn) ClientVersion() []byte { 139 | return dup(c.clientVersion) 140 | } 141 | 142 | func (c *sshConn) ServerVersion() []byte { 143 | return dup(c.serverVersion) 144 | } 145 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Package ssh implements an SSH client and server. 7 | 8 | SSH is a transport security protocol, an authentication protocol and a 9 | family of application protocols. The most typical application level 10 | protocol is a remote shell and this is specifically implemented. However, 11 | the multiplexed nature of SSH is exposed to users that wish to support 12 | others. 13 | 14 | References: 15 | [PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD 16 | [SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1 17 | */ 18 | package ssh 19 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/handshake.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "crypto/rand" 9 | "errors" 10 | "fmt" 11 | "io" 12 | "log" 13 | "net" 14 | "sync" 15 | ) 16 | 17 | // debugHandshake, if set, prints messages sent and received. Key 18 | // exchange messages are printed as if DH were used, so the debug 19 | // messages are wrong when using ECDH. 20 | const debugHandshake = false 21 | 22 | // keyingTransport is a packet based transport that supports key 23 | // changes. It need not be thread-safe. It should pass through 24 | // msgNewKeys in both directions. 25 | type keyingTransport interface { 26 | packetConn 27 | 28 | // prepareKeyChange sets up a key change. The key change for a 29 | // direction will be effected if a msgNewKeys message is sent 30 | // or received. 31 | prepareKeyChange(*algorithms, *kexResult) error 32 | 33 | // getSessionID returns the session ID. prepareKeyChange must 34 | // have been called once. 35 | getSessionID() []byte 36 | } 37 | 38 | // rekeyingTransport is the interface of handshakeTransport that we 39 | // (internally) expose to ClientConn and ServerConn. 40 | type rekeyingTransport interface { 41 | packetConn 42 | 43 | // requestKeyChange asks the remote side to change keys. All 44 | // writes are blocked until the key change succeeds, which is 45 | // signaled by reading a msgNewKeys. 46 | requestKeyChange() error 47 | 48 | // getSessionID returns the session ID. This is only valid 49 | // after the first key change has completed. 50 | getSessionID() []byte 51 | } 52 | 53 | // handshakeTransport implements rekeying on top of a keyingTransport 54 | // and offers a thread-safe writePacket() interface. 55 | type handshakeTransport struct { 56 | conn keyingTransport 57 | config *Config 58 | 59 | serverVersion []byte 60 | clientVersion []byte 61 | 62 | // hostKeys is non-empty if we are the server. In that case, 63 | // it contains all host keys that can be used to sign the 64 | // connection. 65 | hostKeys []Signer 66 | 67 | // hostKeyAlgorithms is non-empty if we are the client. In that case, 68 | // we accept these key types from the server as host key. 69 | hostKeyAlgorithms []string 70 | 71 | // On read error, incoming is closed, and readError is set. 72 | incoming chan []byte 73 | readError error 74 | 75 | // data for host key checking 76 | hostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error 77 | dialAddress string 78 | remoteAddr net.Addr 79 | 80 | readSinceKex uint64 81 | 82 | // Protects the writing side of the connection 83 | mu sync.Mutex 84 | cond *sync.Cond 85 | sentInitPacket []byte 86 | sentInitMsg *kexInitMsg 87 | writtenSinceKex uint64 88 | writeError error 89 | } 90 | 91 | func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport { 92 | t := &handshakeTransport{ 93 | conn: conn, 94 | serverVersion: serverVersion, 95 | clientVersion: clientVersion, 96 | incoming: make(chan []byte, 16), 97 | config: config, 98 | } 99 | t.cond = sync.NewCond(&t.mu) 100 | return t 101 | } 102 | 103 | func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ClientConfig, dialAddr string, addr net.Addr) *handshakeTransport { 104 | t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) 105 | t.dialAddress = dialAddr 106 | t.remoteAddr = addr 107 | t.hostKeyCallback = config.HostKeyCallback 108 | if config.HostKeyAlgorithms != nil { 109 | t.hostKeyAlgorithms = config.HostKeyAlgorithms 110 | } else { 111 | t.hostKeyAlgorithms = supportedHostKeyAlgos 112 | } 113 | go t.readLoop() 114 | return t 115 | } 116 | 117 | func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport { 118 | t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) 119 | t.hostKeys = config.hostKeys 120 | go t.readLoop() 121 | return t 122 | } 123 | 124 | func (t *handshakeTransport) getSessionID() []byte { 125 | return t.conn.getSessionID() 126 | } 127 | 128 | func (t *handshakeTransport) id() string { 129 | if len(t.hostKeys) > 0 { 130 | return "server" 131 | } 132 | return "client" 133 | } 134 | 135 | func (t *handshakeTransport) readPacket() ([]byte, error) { 136 | p, ok := <-t.incoming 137 | if !ok { 138 | return nil, t.readError 139 | } 140 | return p, nil 141 | } 142 | 143 | func (t *handshakeTransport) readLoop() { 144 | for { 145 | p, err := t.readOnePacket() 146 | if err != nil { 147 | t.readError = err 148 | close(t.incoming) 149 | break 150 | } 151 | if p[0] == msgIgnore || p[0] == msgDebug { 152 | continue 153 | } 154 | t.incoming <- p 155 | } 156 | 157 | // If we can't read, declare the writing part dead too. 158 | t.mu.Lock() 159 | defer t.mu.Unlock() 160 | if t.writeError == nil { 161 | t.writeError = t.readError 162 | } 163 | t.cond.Broadcast() 164 | } 165 | 166 | func (t *handshakeTransport) readOnePacket() ([]byte, error) { 167 | if t.readSinceKex > t.config.RekeyThreshold { 168 | if err := t.requestKeyChange(); err != nil { 169 | return nil, err 170 | } 171 | } 172 | 173 | p, err := t.conn.readPacket() 174 | if err != nil { 175 | return nil, err 176 | } 177 | 178 | t.readSinceKex += uint64(len(p)) 179 | if debugHandshake { 180 | msg, err := decode(p) 181 | log.Printf("%s got %T %v (%v)", t.id(), msg, msg, err) 182 | } 183 | if p[0] != msgKexInit { 184 | return p, nil 185 | } 186 | err = t.enterKeyExchange(p) 187 | 188 | t.mu.Lock() 189 | if err != nil { 190 | // drop connection 191 | t.conn.Close() 192 | t.writeError = err 193 | } 194 | 195 | if debugHandshake { 196 | log.Printf("%s exited key exchange, err %v", t.id(), err) 197 | } 198 | 199 | // Unblock writers. 200 | t.sentInitMsg = nil 201 | t.sentInitPacket = nil 202 | t.cond.Broadcast() 203 | t.writtenSinceKex = 0 204 | t.mu.Unlock() 205 | 206 | if err != nil { 207 | return nil, err 208 | } 209 | 210 | t.readSinceKex = 0 211 | return []byte{msgNewKeys}, nil 212 | } 213 | 214 | // sendKexInit sends a key change message, and returns the message 215 | // that was sent. After initiating the key change, all writes will be 216 | // blocked until the change is done, and a failed key change will 217 | // close the underlying transport. This function is safe for 218 | // concurrent use by multiple goroutines. 219 | func (t *handshakeTransport) sendKexInit() (*kexInitMsg, []byte, error) { 220 | t.mu.Lock() 221 | defer t.mu.Unlock() 222 | return t.sendKexInitLocked() 223 | } 224 | 225 | func (t *handshakeTransport) requestKeyChange() error { 226 | _, _, err := t.sendKexInit() 227 | return err 228 | } 229 | 230 | // sendKexInitLocked sends a key change message. t.mu must be locked 231 | // while this happens. 232 | func (t *handshakeTransport) sendKexInitLocked() (*kexInitMsg, []byte, error) { 233 | // kexInits may be sent either in response to the other side, 234 | // or because our side wants to initiate a key change, so we 235 | // may have already sent a kexInit. In that case, don't send a 236 | // second kexInit. 237 | if t.sentInitMsg != nil { 238 | return t.sentInitMsg, t.sentInitPacket, nil 239 | } 240 | msg := &kexInitMsg{ 241 | KexAlgos: t.config.KeyExchanges, 242 | CiphersClientServer: t.config.Ciphers, 243 | CiphersServerClient: t.config.Ciphers, 244 | MACsClientServer: t.config.MACs, 245 | MACsServerClient: t.config.MACs, 246 | CompressionClientServer: supportedCompressions, 247 | CompressionServerClient: supportedCompressions, 248 | } 249 | io.ReadFull(rand.Reader, msg.Cookie[:]) 250 | 251 | if len(t.hostKeys) > 0 { 252 | for _, k := range t.hostKeys { 253 | msg.ServerHostKeyAlgos = append( 254 | msg.ServerHostKeyAlgos, k.PublicKey().Type()) 255 | } 256 | } else { 257 | msg.ServerHostKeyAlgos = t.hostKeyAlgorithms 258 | } 259 | packet := Marshal(msg) 260 | 261 | // writePacket destroys the contents, so save a copy. 262 | packetCopy := make([]byte, len(packet)) 263 | copy(packetCopy, packet) 264 | 265 | if err := t.conn.writePacket(packetCopy); err != nil { 266 | return nil, nil, err 267 | } 268 | 269 | t.sentInitMsg = msg 270 | t.sentInitPacket = packet 271 | return msg, packet, nil 272 | } 273 | 274 | func (t *handshakeTransport) writePacket(p []byte) error { 275 | t.mu.Lock() 276 | defer t.mu.Unlock() 277 | 278 | if t.writtenSinceKex > t.config.RekeyThreshold { 279 | t.sendKexInitLocked() 280 | } 281 | for t.sentInitMsg != nil && t.writeError == nil { 282 | t.cond.Wait() 283 | } 284 | if t.writeError != nil { 285 | return t.writeError 286 | } 287 | t.writtenSinceKex += uint64(len(p)) 288 | 289 | switch p[0] { 290 | case msgKexInit: 291 | return errors.New("ssh: only handshakeTransport can send kexInit") 292 | case msgNewKeys: 293 | return errors.New("ssh: only handshakeTransport can send newKeys") 294 | default: 295 | return t.conn.writePacket(p) 296 | } 297 | } 298 | 299 | func (t *handshakeTransport) Close() error { 300 | return t.conn.Close() 301 | } 302 | 303 | // enterKeyExchange runs the key exchange. 304 | func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { 305 | if debugHandshake { 306 | log.Printf("%s entered key exchange", t.id()) 307 | } 308 | myInit, myInitPacket, err := t.sendKexInit() 309 | if err != nil { 310 | return err 311 | } 312 | 313 | otherInit := &kexInitMsg{} 314 | if err := Unmarshal(otherInitPacket, otherInit); err != nil { 315 | return err 316 | } 317 | 318 | magics := handshakeMagics{ 319 | clientVersion: t.clientVersion, 320 | serverVersion: t.serverVersion, 321 | clientKexInit: otherInitPacket, 322 | serverKexInit: myInitPacket, 323 | } 324 | 325 | clientInit := otherInit 326 | serverInit := myInit 327 | if len(t.hostKeys) == 0 { 328 | clientInit = myInit 329 | serverInit = otherInit 330 | 331 | magics.clientKexInit = myInitPacket 332 | magics.serverKexInit = otherInitPacket 333 | } 334 | 335 | algs, err := findAgreedAlgorithms(clientInit, serverInit) 336 | if err != nil { 337 | return err 338 | } 339 | 340 | // We don't send FirstKexFollows, but we handle receiving it. 341 | if otherInit.FirstKexFollows && algs.kex != otherInit.KexAlgos[0] { 342 | // other side sent a kex message for the wrong algorithm, 343 | // which we have to ignore. 344 | if _, err := t.conn.readPacket(); err != nil { 345 | return err 346 | } 347 | } 348 | 349 | kex, ok := kexAlgoMap[algs.kex] 350 | if !ok { 351 | return fmt.Errorf("ssh: unexpected key exchange algorithm %v", algs.kex) 352 | } 353 | 354 | var result *kexResult 355 | if len(t.hostKeys) > 0 { 356 | result, err = t.server(kex, algs, &magics) 357 | } else { 358 | result, err = t.client(kex, algs, &magics) 359 | } 360 | 361 | if err != nil { 362 | return err 363 | } 364 | 365 | t.conn.prepareKeyChange(algs, result) 366 | if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil { 367 | return err 368 | } 369 | if packet, err := t.conn.readPacket(); err != nil { 370 | return err 371 | } else if packet[0] != msgNewKeys { 372 | return unexpectedMessageError(msgNewKeys, packet[0]) 373 | } 374 | return nil 375 | } 376 | 377 | func (t *handshakeTransport) server(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { 378 | var hostKey Signer 379 | for _, k := range t.hostKeys { 380 | if algs.hostKey == k.PublicKey().Type() { 381 | hostKey = k 382 | } 383 | } 384 | 385 | r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey) 386 | return r, err 387 | } 388 | 389 | func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { 390 | result, err := kex.Client(t.conn, t.config.Rand, magics) 391 | if err != nil { 392 | return nil, err 393 | } 394 | 395 | hostKey, err := ParsePublicKey(result.HostKey) 396 | if err != nil { 397 | return nil, err 398 | } 399 | 400 | if err := verifyHostKeySignature(hostKey, result); err != nil { 401 | return nil, err 402 | } 403 | 404 | if t.hostKeyCallback != nil { 405 | err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey) 406 | if err != nil { 407 | return nil, err 408 | } 409 | } 410 | 411 | return result, nil 412 | } 413 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/kex.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "crypto" 9 | "crypto/ecdsa" 10 | "crypto/elliptic" 11 | "crypto/subtle" 12 | "crypto/rand" 13 | "errors" 14 | "io" 15 | "math/big" 16 | 17 | "golang.org/x/crypto/curve25519" 18 | ) 19 | 20 | const ( 21 | kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1" 22 | kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1" 23 | kexAlgoECDH256 = "ecdh-sha2-nistp256" 24 | kexAlgoECDH384 = "ecdh-sha2-nistp384" 25 | kexAlgoECDH521 = "ecdh-sha2-nistp521" 26 | kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org" 27 | ) 28 | 29 | // kexResult captures the outcome of a key exchange. 30 | type kexResult struct { 31 | // Session hash. See also RFC 4253, section 8. 32 | H []byte 33 | 34 | // Shared secret. See also RFC 4253, section 8. 35 | K []byte 36 | 37 | // Host key as hashed into H. 38 | HostKey []byte 39 | 40 | // Signature of H. 41 | Signature []byte 42 | 43 | // A cryptographic hash function that matches the security 44 | // level of the key exchange algorithm. It is used for 45 | // calculating H, and for deriving keys from H and K. 46 | Hash crypto.Hash 47 | 48 | // The session ID, which is the first H computed. This is used 49 | // to signal data inside transport. 50 | SessionID []byte 51 | } 52 | 53 | // handshakeMagics contains data that is always included in the 54 | // session hash. 55 | type handshakeMagics struct { 56 | clientVersion, serverVersion []byte 57 | clientKexInit, serverKexInit []byte 58 | } 59 | 60 | func (m *handshakeMagics) write(w io.Writer) { 61 | writeString(w, m.clientVersion) 62 | writeString(w, m.serverVersion) 63 | writeString(w, m.clientKexInit) 64 | writeString(w, m.serverKexInit) 65 | } 66 | 67 | // kexAlgorithm abstracts different key exchange algorithms. 68 | type kexAlgorithm interface { 69 | // Server runs server-side key agreement, signing the result 70 | // with a hostkey. 71 | Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error) 72 | 73 | // Client runs the client-side key agreement. Caller is 74 | // responsible for verifying the host key signature. 75 | Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) 76 | } 77 | 78 | // dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. 79 | type dhGroup struct { 80 | g, p *big.Int 81 | } 82 | 83 | func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { 84 | if theirPublic.Sign() <= 0 || theirPublic.Cmp(group.p) >= 0 { 85 | return nil, errors.New("ssh: DH parameter out of bounds") 86 | } 87 | return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil 88 | } 89 | 90 | func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { 91 | hashFunc := crypto.SHA1 92 | 93 | x, err := rand.Int(randSource, group.p) 94 | if err != nil { 95 | return nil, err 96 | } 97 | X := new(big.Int).Exp(group.g, x, group.p) 98 | kexDHInit := kexDHInitMsg{ 99 | X: X, 100 | } 101 | if err := c.writePacket(Marshal(&kexDHInit)); err != nil { 102 | return nil, err 103 | } 104 | 105 | packet, err := c.readPacket() 106 | if err != nil { 107 | return nil, err 108 | } 109 | 110 | var kexDHReply kexDHReplyMsg 111 | if err = Unmarshal(packet, &kexDHReply); err != nil { 112 | return nil, err 113 | } 114 | 115 | kInt, err := group.diffieHellman(kexDHReply.Y, x) 116 | if err != nil { 117 | return nil, err 118 | } 119 | 120 | h := hashFunc.New() 121 | magics.write(h) 122 | writeString(h, kexDHReply.HostKey) 123 | writeInt(h, X) 124 | writeInt(h, kexDHReply.Y) 125 | K := make([]byte, intLength(kInt)) 126 | marshalInt(K, kInt) 127 | h.Write(K) 128 | 129 | return &kexResult{ 130 | H: h.Sum(nil), 131 | K: K, 132 | HostKey: kexDHReply.HostKey, 133 | Signature: kexDHReply.Signature, 134 | Hash: crypto.SHA1, 135 | }, nil 136 | } 137 | 138 | func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 139 | hashFunc := crypto.SHA1 140 | packet, err := c.readPacket() 141 | if err != nil { 142 | return 143 | } 144 | var kexDHInit kexDHInitMsg 145 | if err = Unmarshal(packet, &kexDHInit); err != nil { 146 | return 147 | } 148 | 149 | y, err := rand.Int(randSource, group.p) 150 | if err != nil { 151 | return 152 | } 153 | 154 | Y := new(big.Int).Exp(group.g, y, group.p) 155 | kInt, err := group.diffieHellman(kexDHInit.X, y) 156 | if err != nil { 157 | return nil, err 158 | } 159 | 160 | hostKeyBytes := priv.PublicKey().Marshal() 161 | 162 | h := hashFunc.New() 163 | magics.write(h) 164 | writeString(h, hostKeyBytes) 165 | writeInt(h, kexDHInit.X) 166 | writeInt(h, Y) 167 | 168 | K := make([]byte, intLength(kInt)) 169 | marshalInt(K, kInt) 170 | h.Write(K) 171 | 172 | H := h.Sum(nil) 173 | 174 | // H is already a hash, but the hostkey signing will apply its 175 | // own key-specific hash algorithm. 176 | sig, err := signAndMarshal(priv, randSource, H) 177 | if err != nil { 178 | return nil, err 179 | } 180 | 181 | kexDHReply := kexDHReplyMsg{ 182 | HostKey: hostKeyBytes, 183 | Y: Y, 184 | Signature: sig, 185 | } 186 | packet = Marshal(&kexDHReply) 187 | 188 | err = c.writePacket(packet) 189 | return &kexResult{ 190 | H: H, 191 | K: K, 192 | HostKey: hostKeyBytes, 193 | Signature: sig, 194 | Hash: crypto.SHA1, 195 | }, nil 196 | } 197 | 198 | // ecdh performs Elliptic Curve Diffie-Hellman key exchange as 199 | // described in RFC 5656, section 4. 200 | type ecdh struct { 201 | curve elliptic.Curve 202 | } 203 | 204 | func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { 205 | ephKey, err := ecdsa.GenerateKey(kex.curve, rand) 206 | if err != nil { 207 | return nil, err 208 | } 209 | 210 | kexInit := kexECDHInitMsg{ 211 | ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y), 212 | } 213 | 214 | serialized := Marshal(&kexInit) 215 | if err := c.writePacket(serialized); err != nil { 216 | return nil, err 217 | } 218 | 219 | packet, err := c.readPacket() 220 | if err != nil { 221 | return nil, err 222 | } 223 | 224 | var reply kexECDHReplyMsg 225 | if err = Unmarshal(packet, &reply); err != nil { 226 | return nil, err 227 | } 228 | 229 | x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey) 230 | if err != nil { 231 | return nil, err 232 | } 233 | 234 | // generate shared secret 235 | secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes()) 236 | 237 | h := ecHash(kex.curve).New() 238 | magics.write(h) 239 | writeString(h, reply.HostKey) 240 | writeString(h, kexInit.ClientPubKey) 241 | writeString(h, reply.EphemeralPubKey) 242 | K := make([]byte, intLength(secret)) 243 | marshalInt(K, secret) 244 | h.Write(K) 245 | 246 | return &kexResult{ 247 | H: h.Sum(nil), 248 | K: K, 249 | HostKey: reply.HostKey, 250 | Signature: reply.Signature, 251 | Hash: ecHash(kex.curve), 252 | }, nil 253 | } 254 | 255 | // unmarshalECKey parses and checks an EC key. 256 | func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) { 257 | x, y = elliptic.Unmarshal(curve, pubkey) 258 | if x == nil { 259 | return nil, nil, errors.New("ssh: elliptic.Unmarshal failure") 260 | } 261 | if !validateECPublicKey(curve, x, y) { 262 | return nil, nil, errors.New("ssh: public key not on curve") 263 | } 264 | return x, y, nil 265 | } 266 | 267 | // validateECPublicKey checks that the point is a valid public key for 268 | // the given curve. See [SEC1], 3.2.2 269 | func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool { 270 | if x.Sign() == 0 && y.Sign() == 0 { 271 | return false 272 | } 273 | 274 | if x.Cmp(curve.Params().P) >= 0 { 275 | return false 276 | } 277 | 278 | if y.Cmp(curve.Params().P) >= 0 { 279 | return false 280 | } 281 | 282 | if !curve.IsOnCurve(x, y) { 283 | return false 284 | } 285 | 286 | // We don't check if N * PubKey == 0, since 287 | // 288 | // - the NIST curves have cofactor = 1, so this is implicit. 289 | // (We don't foresee an implementation that supports non NIST 290 | // curves) 291 | // 292 | // - for ephemeral keys, we don't need to worry about small 293 | // subgroup attacks. 294 | return true 295 | } 296 | 297 | func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 298 | packet, err := c.readPacket() 299 | if err != nil { 300 | return nil, err 301 | } 302 | 303 | var kexECDHInit kexECDHInitMsg 304 | if err = Unmarshal(packet, &kexECDHInit); err != nil { 305 | return nil, err 306 | } 307 | 308 | clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey) 309 | if err != nil { 310 | return nil, err 311 | } 312 | 313 | // We could cache this key across multiple users/multiple 314 | // connection attempts, but the benefit is small. OpenSSH 315 | // generates a new key for each incoming connection. 316 | ephKey, err := ecdsa.GenerateKey(kex.curve, rand) 317 | if err != nil { 318 | return nil, err 319 | } 320 | 321 | hostKeyBytes := priv.PublicKey().Marshal() 322 | 323 | serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y) 324 | 325 | // generate shared secret 326 | secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes()) 327 | 328 | h := ecHash(kex.curve).New() 329 | magics.write(h) 330 | writeString(h, hostKeyBytes) 331 | writeString(h, kexECDHInit.ClientPubKey) 332 | writeString(h, serializedEphKey) 333 | 334 | K := make([]byte, intLength(secret)) 335 | marshalInt(K, secret) 336 | h.Write(K) 337 | 338 | H := h.Sum(nil) 339 | 340 | // H is already a hash, but the hostkey signing will apply its 341 | // own key-specific hash algorithm. 342 | sig, err := signAndMarshal(priv, rand, H) 343 | if err != nil { 344 | return nil, err 345 | } 346 | 347 | reply := kexECDHReplyMsg{ 348 | EphemeralPubKey: serializedEphKey, 349 | HostKey: hostKeyBytes, 350 | Signature: sig, 351 | } 352 | 353 | serialized := Marshal(&reply) 354 | if err := c.writePacket(serialized); err != nil { 355 | return nil, err 356 | } 357 | 358 | return &kexResult{ 359 | H: H, 360 | K: K, 361 | HostKey: reply.HostKey, 362 | Signature: sig, 363 | Hash: ecHash(kex.curve), 364 | }, nil 365 | } 366 | 367 | var kexAlgoMap = map[string]kexAlgorithm{} 368 | 369 | func init() { 370 | // This is the group called diffie-hellman-group1-sha1 in RFC 371 | // 4253 and Oakley Group 2 in RFC 2409. 372 | p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16) 373 | kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{ 374 | g: new(big.Int).SetInt64(2), 375 | p: p, 376 | } 377 | 378 | // This is the group called diffie-hellman-group14-sha1 in RFC 379 | // 4253 and Oakley Group 14 in RFC 3526. 380 | p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) 381 | 382 | kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{ 383 | g: new(big.Int).SetInt64(2), 384 | p: p, 385 | } 386 | 387 | kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()} 388 | kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()} 389 | kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()} 390 | kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{} 391 | } 392 | 393 | // curve25519sha256 implements the curve25519-sha256@libssh.org key 394 | // agreement protocol, as described in 395 | // https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt 396 | type curve25519sha256 struct{} 397 | 398 | type curve25519KeyPair struct { 399 | priv [32]byte 400 | pub [32]byte 401 | } 402 | 403 | func (kp *curve25519KeyPair) generate(rand io.Reader) error { 404 | if _, err := io.ReadFull(rand, kp.priv[:]); err != nil { 405 | return err 406 | } 407 | curve25519.ScalarBaseMult(&kp.pub, &kp.priv) 408 | return nil 409 | } 410 | 411 | // curve25519Zeros is just an array of 32 zero bytes so that we have something 412 | // convenient to compare against in order to reject curve25519 points with the 413 | // wrong order. 414 | var curve25519Zeros [32]byte 415 | 416 | func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { 417 | var kp curve25519KeyPair 418 | if err := kp.generate(rand); err != nil { 419 | return nil, err 420 | } 421 | if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil { 422 | return nil, err 423 | } 424 | 425 | packet, err := c.readPacket() 426 | if err != nil { 427 | return nil, err 428 | } 429 | 430 | var reply kexECDHReplyMsg 431 | if err = Unmarshal(packet, &reply); err != nil { 432 | return nil, err 433 | } 434 | if len(reply.EphemeralPubKey) != 32 { 435 | return nil, errors.New("ssh: peer's curve25519 public value has wrong length") 436 | } 437 | 438 | var servPub, secret [32]byte 439 | copy(servPub[:], reply.EphemeralPubKey) 440 | curve25519.ScalarMult(&secret, &kp.priv, &servPub) 441 | if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { 442 | return nil, errors.New("ssh: peer's curve25519 public value has wrong order") 443 | } 444 | 445 | h := crypto.SHA256.New() 446 | magics.write(h) 447 | writeString(h, reply.HostKey) 448 | writeString(h, kp.pub[:]) 449 | writeString(h, reply.EphemeralPubKey) 450 | 451 | kInt := new(big.Int).SetBytes(secret[:]) 452 | K := make([]byte, intLength(kInt)) 453 | marshalInt(K, kInt) 454 | h.Write(K) 455 | 456 | return &kexResult{ 457 | H: h.Sum(nil), 458 | K: K, 459 | HostKey: reply.HostKey, 460 | Signature: reply.Signature, 461 | Hash: crypto.SHA256, 462 | }, nil 463 | } 464 | 465 | func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 466 | packet, err := c.readPacket() 467 | if err != nil { 468 | return 469 | } 470 | var kexInit kexECDHInitMsg 471 | if err = Unmarshal(packet, &kexInit); err != nil { 472 | return 473 | } 474 | 475 | if len(kexInit.ClientPubKey) != 32 { 476 | return nil, errors.New("ssh: peer's curve25519 public value has wrong length") 477 | } 478 | 479 | var kp curve25519KeyPair 480 | if err := kp.generate(rand); err != nil { 481 | return nil, err 482 | } 483 | 484 | var clientPub, secret [32]byte 485 | copy(clientPub[:], kexInit.ClientPubKey) 486 | curve25519.ScalarMult(&secret, &kp.priv, &clientPub) 487 | if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { 488 | return nil, errors.New("ssh: peer's curve25519 public value has wrong order") 489 | } 490 | 491 | hostKeyBytes := priv.PublicKey().Marshal() 492 | 493 | h := crypto.SHA256.New() 494 | magics.write(h) 495 | writeString(h, hostKeyBytes) 496 | writeString(h, kexInit.ClientPubKey) 497 | writeString(h, kp.pub[:]) 498 | 499 | kInt := new(big.Int).SetBytes(secret[:]) 500 | K := make([]byte, intLength(kInt)) 501 | marshalInt(K, kInt) 502 | h.Write(K) 503 | 504 | H := h.Sum(nil) 505 | 506 | sig, err := signAndMarshal(priv, rand, H) 507 | if err != nil { 508 | return nil, err 509 | } 510 | 511 | reply := kexECDHReplyMsg{ 512 | EphemeralPubKey: kp.pub[:], 513 | HostKey: hostKeyBytes, 514 | Signature: sig, 515 | } 516 | if err := c.writePacket(Marshal(&reply)); err != nil { 517 | return nil, err 518 | } 519 | return &kexResult{ 520 | H: H, 521 | K: K, 522 | HostKey: hostKeyBytes, 523 | Signature: sig, 524 | Hash: crypto.SHA256, 525 | }, nil 526 | } 527 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/mac.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | // Message authentication support 8 | 9 | import ( 10 | "crypto/hmac" 11 | "crypto/sha1" 12 | "crypto/sha256" 13 | "hash" 14 | ) 15 | 16 | type macMode struct { 17 | keySize int 18 | new func(key []byte) hash.Hash 19 | } 20 | 21 | // truncatingMAC wraps around a hash.Hash and truncates the output digest to 22 | // a given size. 23 | type truncatingMAC struct { 24 | length int 25 | hmac hash.Hash 26 | } 27 | 28 | func (t truncatingMAC) Write(data []byte) (int, error) { 29 | return t.hmac.Write(data) 30 | } 31 | 32 | func (t truncatingMAC) Sum(in []byte) []byte { 33 | out := t.hmac.Sum(in) 34 | return out[:len(in)+t.length] 35 | } 36 | 37 | func (t truncatingMAC) Reset() { 38 | t.hmac.Reset() 39 | } 40 | 41 | func (t truncatingMAC) Size() int { 42 | return t.length 43 | } 44 | 45 | func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } 46 | 47 | var macModes = map[string]*macMode{ 48 | "hmac-sha2-256": {32, func(key []byte) hash.Hash { 49 | return hmac.New(sha256.New, key) 50 | }}, 51 | "hmac-sha1": {20, func(key []byte) hash.Hash { 52 | return hmac.New(sha1.New, key) 53 | }}, 54 | "hmac-sha1-96": {20, func(key []byte) hash.Hash { 55 | return truncatingMAC{12, hmac.New(sha1.New, key)} 56 | }}, 57 | } 58 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/mux.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "encoding/binary" 9 | "fmt" 10 | "io" 11 | "log" 12 | "sync" 13 | "sync/atomic" 14 | ) 15 | 16 | // debugMux, if set, causes messages in the connection protocol to be 17 | // logged. 18 | const debugMux = false 19 | 20 | // chanList is a thread safe channel list. 21 | type chanList struct { 22 | // protects concurrent access to chans 23 | sync.Mutex 24 | 25 | // chans are indexed by the local id of the channel, which the 26 | // other side should send in the PeersId field. 27 | chans []*channel 28 | 29 | // This is a debugging aid: it offsets all IDs by this 30 | // amount. This helps distinguish otherwise identical 31 | // server/client muxes 32 | offset uint32 33 | } 34 | 35 | // Assigns a channel ID to the given channel. 36 | func (c *chanList) add(ch *channel) uint32 { 37 | c.Lock() 38 | defer c.Unlock() 39 | for i := range c.chans { 40 | if c.chans[i] == nil { 41 | c.chans[i] = ch 42 | return uint32(i) + c.offset 43 | } 44 | } 45 | c.chans = append(c.chans, ch) 46 | return uint32(len(c.chans)-1) + c.offset 47 | } 48 | 49 | // getChan returns the channel for the given ID. 50 | func (c *chanList) getChan(id uint32) *channel { 51 | id -= c.offset 52 | 53 | c.Lock() 54 | defer c.Unlock() 55 | if id < uint32(len(c.chans)) { 56 | return c.chans[id] 57 | } 58 | return nil 59 | } 60 | 61 | func (c *chanList) remove(id uint32) { 62 | id -= c.offset 63 | c.Lock() 64 | if id < uint32(len(c.chans)) { 65 | c.chans[id] = nil 66 | } 67 | c.Unlock() 68 | } 69 | 70 | // dropAll forgets all channels it knows, returning them in a slice. 71 | func (c *chanList) dropAll() []*channel { 72 | c.Lock() 73 | defer c.Unlock() 74 | var r []*channel 75 | 76 | for _, ch := range c.chans { 77 | if ch == nil { 78 | continue 79 | } 80 | r = append(r, ch) 81 | } 82 | c.chans = nil 83 | return r 84 | } 85 | 86 | // mux represents the state for the SSH connection protocol, which 87 | // multiplexes many channels onto a single packet transport. 88 | type mux struct { 89 | conn packetConn 90 | chanList chanList 91 | 92 | incomingChannels chan NewChannel 93 | 94 | globalSentMu sync.Mutex 95 | globalResponses chan interface{} 96 | incomingRequests chan *Request 97 | 98 | errCond *sync.Cond 99 | err error 100 | } 101 | 102 | // When debugging, each new chanList instantiation has a different 103 | // offset. 104 | var globalOff uint32 105 | 106 | func (m *mux) Wait() error { 107 | m.errCond.L.Lock() 108 | defer m.errCond.L.Unlock() 109 | for m.err == nil { 110 | m.errCond.Wait() 111 | } 112 | return m.err 113 | } 114 | 115 | // newMux returns a mux that runs over the given connection. 116 | func newMux(p packetConn) *mux { 117 | m := &mux{ 118 | conn: p, 119 | incomingChannels: make(chan NewChannel, 16), 120 | globalResponses: make(chan interface{}, 1), 121 | incomingRequests: make(chan *Request, 16), 122 | errCond: newCond(), 123 | } 124 | if debugMux { 125 | m.chanList.offset = atomic.AddUint32(&globalOff, 1) 126 | } 127 | 128 | go m.loop() 129 | return m 130 | } 131 | 132 | func (m *mux) sendMessage(msg interface{}) error { 133 | p := Marshal(msg) 134 | return m.conn.writePacket(p) 135 | } 136 | 137 | func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) { 138 | if wantReply { 139 | m.globalSentMu.Lock() 140 | defer m.globalSentMu.Unlock() 141 | } 142 | 143 | if err := m.sendMessage(globalRequestMsg{ 144 | Type: name, 145 | WantReply: wantReply, 146 | Data: payload, 147 | }); err != nil { 148 | return false, nil, err 149 | } 150 | 151 | if !wantReply { 152 | return false, nil, nil 153 | } 154 | 155 | msg, ok := <-m.globalResponses 156 | if !ok { 157 | return false, nil, io.EOF 158 | } 159 | switch msg := msg.(type) { 160 | case *globalRequestFailureMsg: 161 | return false, msg.Data, nil 162 | case *globalRequestSuccessMsg: 163 | return true, msg.Data, nil 164 | default: 165 | return false, nil, fmt.Errorf("ssh: unexpected response to request: %#v", msg) 166 | } 167 | } 168 | 169 | // ackRequest must be called after processing a global request that 170 | // has WantReply set. 171 | func (m *mux) ackRequest(ok bool, data []byte) error { 172 | if ok { 173 | return m.sendMessage(globalRequestSuccessMsg{Data: data}) 174 | } 175 | return m.sendMessage(globalRequestFailureMsg{Data: data}) 176 | } 177 | 178 | // TODO(hanwen): Disconnect is a transport layer message. We should 179 | // probably send and receive Disconnect somewhere in the transport 180 | // code. 181 | 182 | // Disconnect sends a disconnect message. 183 | func (m *mux) Disconnect(reason uint32, message string) error { 184 | return m.sendMessage(disconnectMsg{ 185 | Reason: reason, 186 | Message: message, 187 | }) 188 | } 189 | 190 | func (m *mux) Close() error { 191 | return m.conn.Close() 192 | } 193 | 194 | // loop runs the connection machine. It will process packets until an 195 | // error is encountered. To synchronize on loop exit, use mux.Wait. 196 | func (m *mux) loop() { 197 | var err error 198 | for err == nil { 199 | err = m.onePacket() 200 | } 201 | 202 | for _, ch := range m.chanList.dropAll() { 203 | ch.close() 204 | } 205 | 206 | close(m.incomingChannels) 207 | close(m.incomingRequests) 208 | close(m.globalResponses) 209 | 210 | m.conn.Close() 211 | 212 | m.errCond.L.Lock() 213 | m.err = err 214 | m.errCond.Broadcast() 215 | m.errCond.L.Unlock() 216 | 217 | if debugMux { 218 | log.Println("loop exit", err) 219 | } 220 | } 221 | 222 | // onePacket reads and processes one packet. 223 | func (m *mux) onePacket() error { 224 | packet, err := m.conn.readPacket() 225 | if err != nil { 226 | return err 227 | } 228 | 229 | if debugMux { 230 | if packet[0] == msgChannelData || packet[0] == msgChannelExtendedData { 231 | log.Printf("decoding(%d): data packet - %d bytes", m.chanList.offset, len(packet)) 232 | } else { 233 | p, _ := decode(packet) 234 | log.Printf("decoding(%d): %d %#v - %d bytes", m.chanList.offset, packet[0], p, len(packet)) 235 | } 236 | } 237 | 238 | switch packet[0] { 239 | case msgNewKeys: 240 | // Ignore notification of key change. 241 | return nil 242 | case msgDisconnect: 243 | return m.handleDisconnect(packet) 244 | case msgChannelOpen: 245 | return m.handleChannelOpen(packet) 246 | case msgGlobalRequest, msgRequestSuccess, msgRequestFailure: 247 | return m.handleGlobalPacket(packet) 248 | } 249 | 250 | // assume a channel packet. 251 | if len(packet) < 5 { 252 | return parseError(packet[0]) 253 | } 254 | id := binary.BigEndian.Uint32(packet[1:]) 255 | ch := m.chanList.getChan(id) 256 | if ch == nil { 257 | return fmt.Errorf("ssh: invalid channel %d", id) 258 | } 259 | 260 | return ch.handlePacket(packet) 261 | } 262 | 263 | func (m *mux) handleDisconnect(packet []byte) error { 264 | var d disconnectMsg 265 | if err := Unmarshal(packet, &d); err != nil { 266 | return err 267 | } 268 | 269 | if debugMux { 270 | log.Printf("caught disconnect: %v", d) 271 | } 272 | return &d 273 | } 274 | 275 | func (m *mux) handleGlobalPacket(packet []byte) error { 276 | msg, err := decode(packet) 277 | if err != nil { 278 | return err 279 | } 280 | 281 | switch msg := msg.(type) { 282 | case *globalRequestMsg: 283 | m.incomingRequests <- &Request{ 284 | Type: msg.Type, 285 | WantReply: msg.WantReply, 286 | Payload: msg.Data, 287 | mux: m, 288 | } 289 | case *globalRequestSuccessMsg, *globalRequestFailureMsg: 290 | m.globalResponses <- msg 291 | default: 292 | panic(fmt.Sprintf("not a global message %#v", msg)) 293 | } 294 | 295 | return nil 296 | } 297 | 298 | // handleChannelOpen schedules a channel to be Accept()ed. 299 | func (m *mux) handleChannelOpen(packet []byte) error { 300 | var msg channelOpenMsg 301 | if err := Unmarshal(packet, &msg); err != nil { 302 | return err 303 | } 304 | 305 | if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { 306 | failMsg := channelOpenFailureMsg{ 307 | PeersId: msg.PeersId, 308 | Reason: ConnectionFailed, 309 | Message: "invalid request", 310 | Language: "en_US.UTF-8", 311 | } 312 | return m.sendMessage(failMsg) 313 | } 314 | 315 | c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData) 316 | c.remoteId = msg.PeersId 317 | c.maxRemotePayload = msg.MaxPacketSize 318 | c.remoteWin.add(msg.PeersWindow) 319 | m.incomingChannels <- c 320 | return nil 321 | } 322 | 323 | func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Request, error) { 324 | ch, err := m.openChannel(chanType, extra) 325 | if err != nil { 326 | return nil, nil, err 327 | } 328 | 329 | return ch, ch.incomingRequests, nil 330 | } 331 | 332 | func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) { 333 | ch := m.newChannel(chanType, channelOutbound, extra) 334 | 335 | ch.maxIncomingPayload = channelMaxPacket 336 | 337 | open := channelOpenMsg{ 338 | ChanType: chanType, 339 | PeersWindow: ch.myWindow, 340 | MaxPacketSize: ch.maxIncomingPayload, 341 | TypeSpecificData: extra, 342 | PeersId: ch.localId, 343 | } 344 | if err := m.sendMessage(open); err != nil { 345 | return nil, err 346 | } 347 | 348 | switch msg := (<-ch.msg).(type) { 349 | case *channelOpenConfirmMsg: 350 | return ch, nil 351 | case *channelOpenFailureMsg: 352 | return nil, &OpenChannelError{msg.Reason, msg.Message} 353 | default: 354 | return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg) 355 | } 356 | } 357 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/server.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "bytes" 9 | "errors" 10 | "fmt" 11 | "io" 12 | "net" 13 | ) 14 | 15 | // The Permissions type holds fine-grained permissions that are 16 | // specific to a user or a specific authentication method for a 17 | // user. Permissions, except for "source-address", must be enforced in 18 | // the server application layer, after successful authentication. The 19 | // Permissions are passed on in ServerConn so a server implementation 20 | // can honor them. 21 | type Permissions struct { 22 | // Critical options restrict default permissions. Common 23 | // restrictions are "source-address" and "force-command". If 24 | // the server cannot enforce the restriction, or does not 25 | // recognize it, the user should not authenticate. 26 | CriticalOptions map[string]string 27 | 28 | // Extensions are extra functionality that the server may 29 | // offer on authenticated connections. Common extensions are 30 | // "permit-agent-forwarding", "permit-X11-forwarding". Lack of 31 | // support for an extension does not preclude authenticating a 32 | // user. 33 | Extensions map[string]string 34 | } 35 | 36 | // ServerConfig holds server specific configuration data. 37 | type ServerConfig struct { 38 | // Config contains configuration shared between client and server. 39 | Config 40 | 41 | hostKeys []Signer 42 | 43 | // NoClientAuth is true if clients are allowed to connect without 44 | // authenticating. 45 | NoClientAuth bool 46 | 47 | // PasswordCallback, if non-nil, is called when a user 48 | // attempts to authenticate using a password. 49 | PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error) 50 | 51 | // PublicKeyCallback, if non-nil, is called when a client attempts public 52 | // key authentication. It must return true if the given public key is 53 | // valid for the given user. For example, see CertChecker.Authenticate. 54 | PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) 55 | 56 | // KeyboardInteractiveCallback, if non-nil, is called when 57 | // keyboard-interactive authentication is selected (RFC 58 | // 4256). The client object's Challenge function should be 59 | // used to query the user. The callback may offer multiple 60 | // Challenge rounds. To avoid information leaks, the client 61 | // should be presented a challenge even if the user is 62 | // unknown. 63 | KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error) 64 | 65 | // AuthLogCallback, if non-nil, is called to log all authentication 66 | // attempts. 67 | AuthLogCallback func(conn ConnMetadata, method string, err error) 68 | 69 | // ServerVersion is the version identification string to announce in 70 | // the public handshake. 71 | // If empty, a reasonable default is used. 72 | // Note that RFC 4253 section 4.2 requires that this string start with 73 | // "SSH-2.0-". 74 | ServerVersion string 75 | } 76 | 77 | // AddHostKey adds a private key as a host key. If an existing host 78 | // key exists with the same algorithm, it is overwritten. Each server 79 | // config must have at least one host key. 80 | func (s *ServerConfig) AddHostKey(key Signer) { 81 | for i, k := range s.hostKeys { 82 | if k.PublicKey().Type() == key.PublicKey().Type() { 83 | s.hostKeys[i] = key 84 | return 85 | } 86 | } 87 | 88 | s.hostKeys = append(s.hostKeys, key) 89 | } 90 | 91 | // cachedPubKey contains the results of querying whether a public key is 92 | // acceptable for a user. 93 | type cachedPubKey struct { 94 | user string 95 | pubKeyData []byte 96 | result error 97 | perms *Permissions 98 | } 99 | 100 | const maxCachedPubKeys = 16 101 | 102 | // pubKeyCache caches tests for public keys. Since SSH clients 103 | // will query whether a public key is acceptable before attempting to 104 | // authenticate with it, we end up with duplicate queries for public 105 | // key validity. The cache only applies to a single ServerConn. 106 | type pubKeyCache struct { 107 | keys []cachedPubKey 108 | } 109 | 110 | // get returns the result for a given user/algo/key tuple. 111 | func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) { 112 | for _, k := range c.keys { 113 | if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) { 114 | return k, true 115 | } 116 | } 117 | return cachedPubKey{}, false 118 | } 119 | 120 | // add adds the given tuple to the cache. 121 | func (c *pubKeyCache) add(candidate cachedPubKey) { 122 | if len(c.keys) < maxCachedPubKeys { 123 | c.keys = append(c.keys, candidate) 124 | } 125 | } 126 | 127 | // ServerConn is an authenticated SSH connection, as seen from the 128 | // server 129 | type ServerConn struct { 130 | Conn 131 | 132 | // If the succeeding authentication callback returned a 133 | // non-nil Permissions pointer, it is stored here. 134 | Permissions *Permissions 135 | } 136 | 137 | // NewServerConn starts a new SSH server with c as the underlying 138 | // transport. It starts with a handshake and, if the handshake is 139 | // unsuccessful, it closes the connection and returns an error. The 140 | // Request and NewChannel channels must be serviced, or the connection 141 | // will hang. 142 | func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) { 143 | fullConf := *config 144 | fullConf.SetDefaults() 145 | s := &connection{ 146 | sshConn: sshConn{conn: c}, 147 | } 148 | perms, err := s.serverHandshake(&fullConf) 149 | if err != nil { 150 | c.Close() 151 | return nil, nil, nil, err 152 | } 153 | return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil 154 | } 155 | 156 | // signAndMarshal signs the data with the appropriate algorithm, 157 | // and serializes the result in SSH wire format. 158 | func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) { 159 | sig, err := k.Sign(rand, data) 160 | if err != nil { 161 | return nil, err 162 | } 163 | 164 | return Marshal(sig), nil 165 | } 166 | 167 | // handshake performs key exchange and user authentication. 168 | func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) { 169 | if len(config.hostKeys) == 0 { 170 | return nil, errors.New("ssh: server has no host keys") 171 | } 172 | 173 | if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && config.KeyboardInteractiveCallback == nil { 174 | return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") 175 | } 176 | 177 | if config.ServerVersion != "" { 178 | s.serverVersion = []byte(config.ServerVersion) 179 | } else { 180 | s.serverVersion = []byte(packageVersion) 181 | } 182 | var err error 183 | s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion) 184 | if err != nil { 185 | return nil, err 186 | } 187 | 188 | tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */) 189 | s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config) 190 | 191 | if err := s.transport.requestKeyChange(); err != nil { 192 | return nil, err 193 | } 194 | 195 | if packet, err := s.transport.readPacket(); err != nil { 196 | return nil, err 197 | } else if packet[0] != msgNewKeys { 198 | return nil, unexpectedMessageError(msgNewKeys, packet[0]) 199 | } 200 | 201 | // We just did the key change, so the session ID is established. 202 | s.sessionID = s.transport.getSessionID() 203 | 204 | var packet []byte 205 | if packet, err = s.transport.readPacket(); err != nil { 206 | return nil, err 207 | } 208 | 209 | var serviceRequest serviceRequestMsg 210 | if err = Unmarshal(packet, &serviceRequest); err != nil { 211 | return nil, err 212 | } 213 | if serviceRequest.Service != serviceUserAuth { 214 | return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating") 215 | } 216 | serviceAccept := serviceAcceptMsg{ 217 | Service: serviceUserAuth, 218 | } 219 | if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil { 220 | return nil, err 221 | } 222 | 223 | perms, err := s.serverAuthenticate(config) 224 | if err != nil { 225 | return nil, err 226 | } 227 | s.mux = newMux(s.transport) 228 | return perms, err 229 | } 230 | 231 | func isAcceptableAlgo(algo string) bool { 232 | switch algo { 233 | case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, 234 | CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01: 235 | return true 236 | } 237 | return false 238 | } 239 | 240 | func checkSourceAddress(addr net.Addr, sourceAddr string) error { 241 | if addr == nil { 242 | return errors.New("ssh: no address known for client, but source-address match required") 243 | } 244 | 245 | tcpAddr, ok := addr.(*net.TCPAddr) 246 | if !ok { 247 | return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr) 248 | } 249 | 250 | if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil { 251 | if bytes.Equal(allowedIP, tcpAddr.IP) { 252 | return nil 253 | } 254 | } else { 255 | _, ipNet, err := net.ParseCIDR(sourceAddr) 256 | if err != nil { 257 | return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err) 258 | } 259 | 260 | if ipNet.Contains(tcpAddr.IP) { 261 | return nil 262 | } 263 | } 264 | 265 | return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr) 266 | } 267 | 268 | func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) { 269 | var err error 270 | var cache pubKeyCache 271 | var perms *Permissions 272 | 273 | userAuthLoop: 274 | for { 275 | var userAuthReq userAuthRequestMsg 276 | if packet, err := s.transport.readPacket(); err != nil { 277 | return nil, err 278 | } else if err = Unmarshal(packet, &userAuthReq); err != nil { 279 | return nil, err 280 | } 281 | 282 | if userAuthReq.Service != serviceSSH { 283 | return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service) 284 | } 285 | 286 | s.user = userAuthReq.User 287 | perms = nil 288 | authErr := errors.New("no auth passed yet") 289 | 290 | switch userAuthReq.Method { 291 | case "none": 292 | if config.NoClientAuth { 293 | s.user = "" 294 | authErr = nil 295 | } 296 | case "password": 297 | if config.PasswordCallback == nil { 298 | authErr = errors.New("ssh: password auth not configured") 299 | break 300 | } 301 | payload := userAuthReq.Payload 302 | if len(payload) < 1 || payload[0] != 0 { 303 | return nil, parseError(msgUserAuthRequest) 304 | } 305 | payload = payload[1:] 306 | password, payload, ok := parseString(payload) 307 | if !ok || len(payload) > 0 { 308 | return nil, parseError(msgUserAuthRequest) 309 | } 310 | 311 | perms, authErr = config.PasswordCallback(s, password) 312 | case "keyboard-interactive": 313 | if config.KeyboardInteractiveCallback == nil { 314 | authErr = errors.New("ssh: keyboard-interactive auth not configubred") 315 | break 316 | } 317 | 318 | prompter := &sshClientKeyboardInteractive{s} 319 | perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge) 320 | case "publickey": 321 | if config.PublicKeyCallback == nil { 322 | authErr = errors.New("ssh: publickey auth not configured") 323 | break 324 | } 325 | payload := userAuthReq.Payload 326 | if len(payload) < 1 { 327 | return nil, parseError(msgUserAuthRequest) 328 | } 329 | isQuery := payload[0] == 0 330 | payload = payload[1:] 331 | algoBytes, payload, ok := parseString(payload) 332 | if !ok { 333 | return nil, parseError(msgUserAuthRequest) 334 | } 335 | algo := string(algoBytes) 336 | if !isAcceptableAlgo(algo) { 337 | authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo) 338 | break 339 | } 340 | 341 | pubKeyData, payload, ok := parseString(payload) 342 | if !ok { 343 | return nil, parseError(msgUserAuthRequest) 344 | } 345 | 346 | pubKey, err := ParsePublicKey(pubKeyData) 347 | if err != nil { 348 | return nil, err 349 | } 350 | 351 | candidate, ok := cache.get(s.user, pubKeyData) 352 | if !ok { 353 | candidate.user = s.user 354 | candidate.pubKeyData = pubKeyData 355 | candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey) 356 | if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" { 357 | candidate.result = checkSourceAddress( 358 | s.RemoteAddr(), 359 | candidate.perms.CriticalOptions[sourceAddressCriticalOption]) 360 | } 361 | cache.add(candidate) 362 | } 363 | 364 | if isQuery { 365 | // The client can query if the given public key 366 | // would be okay. 367 | if len(payload) > 0 { 368 | return nil, parseError(msgUserAuthRequest) 369 | } 370 | 371 | if candidate.result == nil { 372 | okMsg := userAuthPubKeyOkMsg{ 373 | Algo: algo, 374 | PubKey: pubKeyData, 375 | } 376 | if err = s.transport.writePacket(Marshal(&okMsg)); err != nil { 377 | return nil, err 378 | } 379 | continue userAuthLoop 380 | } 381 | authErr = candidate.result 382 | } else { 383 | sig, payload, ok := parseSignature(payload) 384 | if !ok || len(payload) > 0 { 385 | return nil, parseError(msgUserAuthRequest) 386 | } 387 | // Ensure the public key algo and signature algo 388 | // are supported. Compare the private key 389 | // algorithm name that corresponds to algo with 390 | // sig.Format. This is usually the same, but 391 | // for certs, the names differ. 392 | if !isAcceptableAlgo(sig.Format) { 393 | break 394 | } 395 | signedData := buildDataSignedForAuth(s.transport.getSessionID(), userAuthReq, algoBytes, pubKeyData) 396 | 397 | if err := pubKey.Verify(signedData, sig); err != nil { 398 | return nil, err 399 | } 400 | 401 | authErr = candidate.result 402 | perms = candidate.perms 403 | } 404 | default: 405 | authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method) 406 | } 407 | 408 | if config.AuthLogCallback != nil { 409 | config.AuthLogCallback(s, userAuthReq.Method, authErr) 410 | } 411 | 412 | if authErr == nil { 413 | break userAuthLoop 414 | } 415 | 416 | var failureMsg userAuthFailureMsg 417 | if config.PasswordCallback != nil { 418 | failureMsg.Methods = append(failureMsg.Methods, "password") 419 | } 420 | if config.PublicKeyCallback != nil { 421 | failureMsg.Methods = append(failureMsg.Methods, "publickey") 422 | } 423 | if config.KeyboardInteractiveCallback != nil { 424 | failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive") 425 | } 426 | 427 | if len(failureMsg.Methods) == 0 { 428 | return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") 429 | } 430 | 431 | if err = s.transport.writePacket(Marshal(&failureMsg)); err != nil { 432 | return nil, err 433 | } 434 | } 435 | 436 | if err = s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil { 437 | return nil, err 438 | } 439 | return perms, nil 440 | } 441 | 442 | // sshClientKeyboardInteractive implements a ClientKeyboardInteractive by 443 | // asking the client on the other side of a ServerConn. 444 | type sshClientKeyboardInteractive struct { 445 | *connection 446 | } 447 | 448 | func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) { 449 | if len(questions) != len(echos) { 450 | return nil, errors.New("ssh: echos and questions must have equal length") 451 | } 452 | 453 | var prompts []byte 454 | for i := range questions { 455 | prompts = appendString(prompts, questions[i]) 456 | prompts = appendBool(prompts, echos[i]) 457 | } 458 | 459 | if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{ 460 | Instruction: instruction, 461 | NumPrompts: uint32(len(questions)), 462 | Prompts: prompts, 463 | })); err != nil { 464 | return nil, err 465 | } 466 | 467 | packet, err := c.transport.readPacket() 468 | if err != nil { 469 | return nil, err 470 | } 471 | if packet[0] != msgUserAuthInfoResponse { 472 | return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0]) 473 | } 474 | packet = packet[1:] 475 | 476 | n, packet, ok := parseUint32(packet) 477 | if !ok || int(n) != len(questions) { 478 | return nil, parseError(msgUserAuthInfoResponse) 479 | } 480 | 481 | for i := uint32(0); i < n; i++ { 482 | ans, rest, ok := parseString(packet) 483 | if !ok { 484 | return nil, parseError(msgUserAuthInfoResponse) 485 | } 486 | 487 | answers = append(answers, string(ans)) 488 | packet = rest 489 | } 490 | if len(packet) != 0 { 491 | return nil, errors.New("ssh: junk at end of message") 492 | } 493 | 494 | return answers, nil 495 | } 496 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/session.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | // Session implements an interactive session described in 8 | // "RFC 4254, section 6". 9 | 10 | import ( 11 | "bytes" 12 | "errors" 13 | "fmt" 14 | "io" 15 | "io/ioutil" 16 | "sync" 17 | ) 18 | 19 | type Signal string 20 | 21 | // POSIX signals as listed in RFC 4254 Section 6.10. 22 | const ( 23 | SIGABRT Signal = "ABRT" 24 | SIGALRM Signal = "ALRM" 25 | SIGFPE Signal = "FPE" 26 | SIGHUP Signal = "HUP" 27 | SIGILL Signal = "ILL" 28 | SIGINT Signal = "INT" 29 | SIGKILL Signal = "KILL" 30 | SIGPIPE Signal = "PIPE" 31 | SIGQUIT Signal = "QUIT" 32 | SIGSEGV Signal = "SEGV" 33 | SIGTERM Signal = "TERM" 34 | SIGUSR1 Signal = "USR1" 35 | SIGUSR2 Signal = "USR2" 36 | ) 37 | 38 | var signals = map[Signal]int{ 39 | SIGABRT: 6, 40 | SIGALRM: 14, 41 | SIGFPE: 8, 42 | SIGHUP: 1, 43 | SIGILL: 4, 44 | SIGINT: 2, 45 | SIGKILL: 9, 46 | SIGPIPE: 13, 47 | SIGQUIT: 3, 48 | SIGSEGV: 11, 49 | SIGTERM: 15, 50 | } 51 | 52 | type TerminalModes map[uint8]uint32 53 | 54 | // POSIX terminal mode flags as listed in RFC 4254 Section 8. 55 | const ( 56 | tty_OP_END = 0 57 | VINTR = 1 58 | VQUIT = 2 59 | VERASE = 3 60 | VKILL = 4 61 | VEOF = 5 62 | VEOL = 6 63 | VEOL2 = 7 64 | VSTART = 8 65 | VSTOP = 9 66 | VSUSP = 10 67 | VDSUSP = 11 68 | VREPRINT = 12 69 | VWERASE = 13 70 | VLNEXT = 14 71 | VFLUSH = 15 72 | VSWTCH = 16 73 | VSTATUS = 17 74 | VDISCARD = 18 75 | IGNPAR = 30 76 | PARMRK = 31 77 | INPCK = 32 78 | ISTRIP = 33 79 | INLCR = 34 80 | IGNCR = 35 81 | ICRNL = 36 82 | IUCLC = 37 83 | IXON = 38 84 | IXANY = 39 85 | IXOFF = 40 86 | IMAXBEL = 41 87 | ISIG = 50 88 | ICANON = 51 89 | XCASE = 52 90 | ECHO = 53 91 | ECHOE = 54 92 | ECHOK = 55 93 | ECHONL = 56 94 | NOFLSH = 57 95 | TOSTOP = 58 96 | IEXTEN = 59 97 | ECHOCTL = 60 98 | ECHOKE = 61 99 | PENDIN = 62 100 | OPOST = 70 101 | OLCUC = 71 102 | ONLCR = 72 103 | OCRNL = 73 104 | ONOCR = 74 105 | ONLRET = 75 106 | CS7 = 90 107 | CS8 = 91 108 | PARENB = 92 109 | PARODD = 93 110 | TTY_OP_ISPEED = 128 111 | TTY_OP_OSPEED = 129 112 | ) 113 | 114 | // A Session represents a connection to a remote command or shell. 115 | type Session struct { 116 | // Stdin specifies the remote process's standard input. 117 | // If Stdin is nil, the remote process reads from an empty 118 | // bytes.Buffer. 119 | Stdin io.Reader 120 | 121 | // Stdout and Stderr specify the remote process's standard 122 | // output and error. 123 | // 124 | // If either is nil, Run connects the corresponding file 125 | // descriptor to an instance of ioutil.Discard. There is a 126 | // fixed amount of buffering that is shared for the two streams. 127 | // If either blocks it may eventually cause the remote 128 | // command to block. 129 | Stdout io.Writer 130 | Stderr io.Writer 131 | 132 | ch Channel // the channel backing this session 133 | started bool // true once Start, Run or Shell is invoked. 134 | copyFuncs []func() error 135 | errors chan error // one send per copyFunc 136 | 137 | // true if pipe method is active 138 | stdinpipe, stdoutpipe, stderrpipe bool 139 | 140 | // stdinPipeWriter is non-nil if StdinPipe has not been called 141 | // and Stdin was specified by the user; it is the write end of 142 | // a pipe connecting Session.Stdin to the stdin channel. 143 | stdinPipeWriter io.WriteCloser 144 | 145 | exitStatus chan error 146 | } 147 | 148 | // SendRequest sends an out-of-band channel request on the SSH channel 149 | // underlying the session. 150 | func (s *Session) SendRequest(name string, wantReply bool, payload []byte) (bool, error) { 151 | return s.ch.SendRequest(name, wantReply, payload) 152 | } 153 | 154 | func (s *Session) Close() error { 155 | return s.ch.Close() 156 | } 157 | 158 | // RFC 4254 Section 6.4. 159 | type setenvRequest struct { 160 | Name string 161 | Value string 162 | } 163 | 164 | // Setenv sets an environment variable that will be applied to any 165 | // command executed by Shell or Run. 166 | func (s *Session) Setenv(name, value string) error { 167 | msg := setenvRequest{ 168 | Name: name, 169 | Value: value, 170 | } 171 | ok, err := s.ch.SendRequest("env", true, Marshal(&msg)) 172 | if err == nil && !ok { 173 | err = errors.New("ssh: setenv failed") 174 | } 175 | return err 176 | } 177 | 178 | // RFC 4254 Section 6.2. 179 | type ptyRequestMsg struct { 180 | Term string 181 | Columns uint32 182 | Rows uint32 183 | Width uint32 184 | Height uint32 185 | Modelist string 186 | } 187 | 188 | // RequestPty requests the association of a pty with the session on the remote host. 189 | func (s *Session) RequestPty(term string, h, w int, termmodes TerminalModes) error { 190 | var tm []byte 191 | for k, v := range termmodes { 192 | kv := struct { 193 | Key byte 194 | Val uint32 195 | }{k, v} 196 | 197 | tm = append(tm, Marshal(&kv)...) 198 | } 199 | tm = append(tm, tty_OP_END) 200 | req := ptyRequestMsg{ 201 | Term: term, 202 | Columns: uint32(w), 203 | Rows: uint32(h), 204 | Width: uint32(w * 8), 205 | Height: uint32(h * 8), 206 | Modelist: string(tm), 207 | } 208 | ok, err := s.ch.SendRequest("pty-req", true, Marshal(&req)) 209 | if err == nil && !ok { 210 | err = errors.New("ssh: pty-req failed") 211 | } 212 | return err 213 | } 214 | 215 | // RFC 4254 Section 6.5. 216 | type subsystemRequestMsg struct { 217 | Subsystem string 218 | } 219 | 220 | // RequestSubsystem requests the association of a subsystem with the session on the remote host. 221 | // A subsystem is a predefined command that runs in the background when the ssh session is initiated 222 | func (s *Session) RequestSubsystem(subsystem string) error { 223 | msg := subsystemRequestMsg{ 224 | Subsystem: subsystem, 225 | } 226 | ok, err := s.ch.SendRequest("subsystem", true, Marshal(&msg)) 227 | if err == nil && !ok { 228 | err = errors.New("ssh: subsystem request failed") 229 | } 230 | return err 231 | } 232 | 233 | // RFC 4254 Section 6.9. 234 | type signalMsg struct { 235 | Signal string 236 | } 237 | 238 | // Signal sends the given signal to the remote process. 239 | // sig is one of the SIG* constants. 240 | func (s *Session) Signal(sig Signal) error { 241 | msg := signalMsg{ 242 | Signal: string(sig), 243 | } 244 | 245 | _, err := s.ch.SendRequest("signal", false, Marshal(&msg)) 246 | return err 247 | } 248 | 249 | // RFC 4254 Section 6.5. 250 | type execMsg struct { 251 | Command string 252 | } 253 | 254 | // Start runs cmd on the remote host. Typically, the remote 255 | // server passes cmd to the shell for interpretation. 256 | // A Session only accepts one call to Run, Start or Shell. 257 | func (s *Session) Start(cmd string) error { 258 | if s.started { 259 | return errors.New("ssh: session already started") 260 | } 261 | req := execMsg{ 262 | Command: cmd, 263 | } 264 | 265 | ok, err := s.ch.SendRequest("exec", true, Marshal(&req)) 266 | if err == nil && !ok { 267 | err = fmt.Errorf("ssh: command %v failed", cmd) 268 | } 269 | if err != nil { 270 | return err 271 | } 272 | return s.start() 273 | } 274 | 275 | // Run runs cmd on the remote host. Typically, the remote 276 | // server passes cmd to the shell for interpretation. 277 | // A Session only accepts one call to Run, Start, Shell, Output, 278 | // or CombinedOutput. 279 | // 280 | // The returned error is nil if the command runs, has no problems 281 | // copying stdin, stdout, and stderr, and exits with a zero exit 282 | // status. 283 | // 284 | // If the command fails to run or doesn't complete successfully, the 285 | // error is of type *ExitError. Other error types may be 286 | // returned for I/O problems. 287 | func (s *Session) Run(cmd string) error { 288 | err := s.Start(cmd) 289 | if err != nil { 290 | return err 291 | } 292 | return s.Wait() 293 | } 294 | 295 | // Output runs cmd on the remote host and returns its standard output. 296 | func (s *Session) Output(cmd string) ([]byte, error) { 297 | if s.Stdout != nil { 298 | return nil, errors.New("ssh: Stdout already set") 299 | } 300 | var b bytes.Buffer 301 | s.Stdout = &b 302 | err := s.Run(cmd) 303 | return b.Bytes(), err 304 | } 305 | 306 | type singleWriter struct { 307 | b bytes.Buffer 308 | mu sync.Mutex 309 | } 310 | 311 | func (w *singleWriter) Write(p []byte) (int, error) { 312 | w.mu.Lock() 313 | defer w.mu.Unlock() 314 | return w.b.Write(p) 315 | } 316 | 317 | // CombinedOutput runs cmd on the remote host and returns its combined 318 | // standard output and standard error. 319 | func (s *Session) CombinedOutput(cmd string) ([]byte, error) { 320 | if s.Stdout != nil { 321 | return nil, errors.New("ssh: Stdout already set") 322 | } 323 | if s.Stderr != nil { 324 | return nil, errors.New("ssh: Stderr already set") 325 | } 326 | var b singleWriter 327 | s.Stdout = &b 328 | s.Stderr = &b 329 | err := s.Run(cmd) 330 | return b.b.Bytes(), err 331 | } 332 | 333 | // Shell starts a login shell on the remote host. A Session only 334 | // accepts one call to Run, Start, Shell, Output, or CombinedOutput. 335 | func (s *Session) Shell() error { 336 | if s.started { 337 | return errors.New("ssh: session already started") 338 | } 339 | 340 | ok, err := s.ch.SendRequest("shell", true, nil) 341 | if err == nil && !ok { 342 | return fmt.Errorf("ssh: cound not start shell") 343 | } 344 | if err != nil { 345 | return err 346 | } 347 | return s.start() 348 | } 349 | 350 | func (s *Session) start() error { 351 | s.started = true 352 | 353 | type F func(*Session) 354 | for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} { 355 | setupFd(s) 356 | } 357 | 358 | s.errors = make(chan error, len(s.copyFuncs)) 359 | for _, fn := range s.copyFuncs { 360 | go func(fn func() error) { 361 | s.errors <- fn() 362 | }(fn) 363 | } 364 | return nil 365 | } 366 | 367 | // Wait waits for the remote command to exit. 368 | // 369 | // The returned error is nil if the command runs, has no problems 370 | // copying stdin, stdout, and stderr, and exits with a zero exit 371 | // status. 372 | // 373 | // If the command fails to run or doesn't complete successfully, the 374 | // error is of type *ExitError. Other error types may be 375 | // returned for I/O problems. 376 | func (s *Session) Wait() error { 377 | if !s.started { 378 | return errors.New("ssh: session not started") 379 | } 380 | waitErr := <-s.exitStatus 381 | 382 | if s.stdinPipeWriter != nil { 383 | s.stdinPipeWriter.Close() 384 | } 385 | var copyError error 386 | for _ = range s.copyFuncs { 387 | if err := <-s.errors; err != nil && copyError == nil { 388 | copyError = err 389 | } 390 | } 391 | if waitErr != nil { 392 | return waitErr 393 | } 394 | return copyError 395 | } 396 | 397 | func (s *Session) wait(reqs <-chan *Request) error { 398 | wm := Waitmsg{status: -1} 399 | // Wait for msg channel to be closed before returning. 400 | for msg := range reqs { 401 | switch msg.Type { 402 | case "exit-status": 403 | d := msg.Payload 404 | wm.status = int(d[0])<<24 | int(d[1])<<16 | int(d[2])<<8 | int(d[3]) 405 | case "exit-signal": 406 | var sigval struct { 407 | Signal string 408 | CoreDumped bool 409 | Error string 410 | Lang string 411 | } 412 | if err := Unmarshal(msg.Payload, &sigval); err != nil { 413 | return err 414 | } 415 | 416 | // Must sanitize strings? 417 | wm.signal = sigval.Signal 418 | wm.msg = sigval.Error 419 | wm.lang = sigval.Lang 420 | default: 421 | // This handles keepalives and matches 422 | // OpenSSH's behaviour. 423 | if msg.WantReply { 424 | msg.Reply(false, nil) 425 | } 426 | } 427 | } 428 | if wm.status == 0 { 429 | return nil 430 | } 431 | if wm.status == -1 { 432 | // exit-status was never sent from server 433 | if wm.signal == "" { 434 | return errors.New("wait: remote command exited without exit status or exit signal") 435 | } 436 | wm.status = 128 437 | if _, ok := signals[Signal(wm.signal)]; ok { 438 | wm.status += signals[Signal(wm.signal)] 439 | } 440 | } 441 | return &ExitError{wm} 442 | } 443 | 444 | func (s *Session) stdin() { 445 | if s.stdinpipe { 446 | return 447 | } 448 | var stdin io.Reader 449 | if s.Stdin == nil { 450 | stdin = new(bytes.Buffer) 451 | } else { 452 | r, w := io.Pipe() 453 | go func() { 454 | _, err := io.Copy(w, s.Stdin) 455 | w.CloseWithError(err) 456 | }() 457 | stdin, s.stdinPipeWriter = r, w 458 | } 459 | s.copyFuncs = append(s.copyFuncs, func() error { 460 | _, err := io.Copy(s.ch, stdin) 461 | if err1 := s.ch.CloseWrite(); err == nil && err1 != io.EOF { 462 | err = err1 463 | } 464 | return err 465 | }) 466 | } 467 | 468 | func (s *Session) stdout() { 469 | if s.stdoutpipe { 470 | return 471 | } 472 | if s.Stdout == nil { 473 | s.Stdout = ioutil.Discard 474 | } 475 | s.copyFuncs = append(s.copyFuncs, func() error { 476 | _, err := io.Copy(s.Stdout, s.ch) 477 | return err 478 | }) 479 | } 480 | 481 | func (s *Session) stderr() { 482 | if s.stderrpipe { 483 | return 484 | } 485 | if s.Stderr == nil { 486 | s.Stderr = ioutil.Discard 487 | } 488 | s.copyFuncs = append(s.copyFuncs, func() error { 489 | _, err := io.Copy(s.Stderr, s.ch.Stderr()) 490 | return err 491 | }) 492 | } 493 | 494 | // sessionStdin reroutes Close to CloseWrite. 495 | type sessionStdin struct { 496 | io.Writer 497 | ch Channel 498 | } 499 | 500 | func (s *sessionStdin) Close() error { 501 | return s.ch.CloseWrite() 502 | } 503 | 504 | // StdinPipe returns a pipe that will be connected to the 505 | // remote command's standard input when the command starts. 506 | func (s *Session) StdinPipe() (io.WriteCloser, error) { 507 | if s.Stdin != nil { 508 | return nil, errors.New("ssh: Stdin already set") 509 | } 510 | if s.started { 511 | return nil, errors.New("ssh: StdinPipe after process started") 512 | } 513 | s.stdinpipe = true 514 | return &sessionStdin{s.ch, s.ch}, nil 515 | } 516 | 517 | // StdoutPipe returns a pipe that will be connected to the 518 | // remote command's standard output when the command starts. 519 | // There is a fixed amount of buffering that is shared between 520 | // stdout and stderr streams. If the StdoutPipe reader is 521 | // not serviced fast enough it may eventually cause the 522 | // remote command to block. 523 | func (s *Session) StdoutPipe() (io.Reader, error) { 524 | if s.Stdout != nil { 525 | return nil, errors.New("ssh: Stdout already set") 526 | } 527 | if s.started { 528 | return nil, errors.New("ssh: StdoutPipe after process started") 529 | } 530 | s.stdoutpipe = true 531 | return s.ch, nil 532 | } 533 | 534 | // StderrPipe returns a pipe that will be connected to the 535 | // remote command's standard error when the command starts. 536 | // There is a fixed amount of buffering that is shared between 537 | // stdout and stderr streams. If the StderrPipe reader is 538 | // not serviced fast enough it may eventually cause the 539 | // remote command to block. 540 | func (s *Session) StderrPipe() (io.Reader, error) { 541 | if s.Stderr != nil { 542 | return nil, errors.New("ssh: Stderr already set") 543 | } 544 | if s.started { 545 | return nil, errors.New("ssh: StderrPipe after process started") 546 | } 547 | s.stderrpipe = true 548 | return s.ch.Stderr(), nil 549 | } 550 | 551 | // newSession returns a new interactive session on the remote host. 552 | func newSession(ch Channel, reqs <-chan *Request) (*Session, error) { 553 | s := &Session{ 554 | ch: ch, 555 | } 556 | s.exitStatus = make(chan error, 1) 557 | go func() { 558 | s.exitStatus <- s.wait(reqs) 559 | }() 560 | 561 | return s, nil 562 | } 563 | 564 | // An ExitError reports unsuccessful completion of a remote command. 565 | type ExitError struct { 566 | Waitmsg 567 | } 568 | 569 | func (e *ExitError) Error() string { 570 | return e.Waitmsg.String() 571 | } 572 | 573 | // Waitmsg stores the information about an exited remote command 574 | // as reported by Wait. 575 | type Waitmsg struct { 576 | status int 577 | signal string 578 | msg string 579 | lang string 580 | } 581 | 582 | // ExitStatus returns the exit status of the remote command. 583 | func (w Waitmsg) ExitStatus() int { 584 | return w.status 585 | } 586 | 587 | // Signal returns the exit signal of the remote command if 588 | // it was terminated violently. 589 | func (w Waitmsg) Signal() string { 590 | return w.signal 591 | } 592 | 593 | // Msg returns the exit message given by the remote command 594 | func (w Waitmsg) Msg() string { 595 | return w.msg 596 | } 597 | 598 | // Lang returns the language tag. See RFC 3066 599 | func (w Waitmsg) Lang() string { 600 | return w.lang 601 | } 602 | 603 | func (w Waitmsg) String() string { 604 | return fmt.Sprintf("Process exited with: %v. Reason was: %v (%v)", w.status, w.msg, w.signal) 605 | } 606 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/tcpip.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "io" 11 | "math/rand" 12 | "net" 13 | "strconv" 14 | "strings" 15 | "sync" 16 | "time" 17 | ) 18 | 19 | // Listen requests the remote peer open a listening socket on 20 | // addr. Incoming connections will be available by calling Accept on 21 | // the returned net.Listener. The listener must be serviced, or the 22 | // SSH connection may hang. 23 | func (c *Client) Listen(n, addr string) (net.Listener, error) { 24 | laddr, err := net.ResolveTCPAddr(n, addr) 25 | if err != nil { 26 | return nil, err 27 | } 28 | return c.ListenTCP(laddr) 29 | } 30 | 31 | // Automatic port allocation is broken with OpenSSH before 6.0. See 32 | // also https://bugzilla.mindrot.org/show_bug.cgi?id=2017. In 33 | // particular, OpenSSH 5.9 sends a channelOpenMsg with port number 0, 34 | // rather than the actual port number. This means you can never open 35 | // two different listeners with auto allocated ports. We work around 36 | // this by trying explicit ports until we succeed. 37 | 38 | const openSSHPrefix = "OpenSSH_" 39 | 40 | var portRandomizer = rand.New(rand.NewSource(time.Now().UnixNano())) 41 | 42 | // isBrokenOpenSSHVersion returns true if the given version string 43 | // specifies a version of OpenSSH that is known to have a bug in port 44 | // forwarding. 45 | func isBrokenOpenSSHVersion(versionStr string) bool { 46 | i := strings.Index(versionStr, openSSHPrefix) 47 | if i < 0 { 48 | return false 49 | } 50 | i += len(openSSHPrefix) 51 | j := i 52 | for ; j < len(versionStr); j++ { 53 | if versionStr[j] < '0' || versionStr[j] > '9' { 54 | break 55 | } 56 | } 57 | version, _ := strconv.Atoi(versionStr[i:j]) 58 | return version < 6 59 | } 60 | 61 | // autoPortListenWorkaround simulates automatic port allocation by 62 | // trying random ports repeatedly. 63 | func (c *Client) autoPortListenWorkaround(laddr *net.TCPAddr) (net.Listener, error) { 64 | var sshListener net.Listener 65 | var err error 66 | const tries = 10 67 | for i := 0; i < tries; i++ { 68 | addr := *laddr 69 | addr.Port = 1024 + portRandomizer.Intn(60000) 70 | sshListener, err = c.ListenTCP(&addr) 71 | if err == nil { 72 | laddr.Port = addr.Port 73 | return sshListener, err 74 | } 75 | } 76 | return nil, fmt.Errorf("ssh: listen on random port failed after %d tries: %v", tries, err) 77 | } 78 | 79 | // RFC 4254 7.1 80 | type channelForwardMsg struct { 81 | addr string 82 | rport uint32 83 | } 84 | 85 | // ListenTCP requests the remote peer open a listening socket 86 | // on laddr. Incoming connections will be available by calling 87 | // Accept on the returned net.Listener. 88 | func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) { 89 | if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) { 90 | return c.autoPortListenWorkaround(laddr) 91 | } 92 | 93 | m := channelForwardMsg{ 94 | laddr.IP.String(), 95 | uint32(laddr.Port), 96 | } 97 | // send message 98 | ok, resp, err := c.SendRequest("tcpip-forward", true, Marshal(&m)) 99 | if err != nil { 100 | return nil, err 101 | } 102 | if !ok { 103 | return nil, errors.New("ssh: tcpip-forward request denied by peer") 104 | } 105 | 106 | // If the original port was 0, then the remote side will 107 | // supply a real port number in the response. 108 | if laddr.Port == 0 { 109 | var p struct { 110 | Port uint32 111 | } 112 | if err := Unmarshal(resp, &p); err != nil { 113 | return nil, err 114 | } 115 | laddr.Port = int(p.Port) 116 | } 117 | 118 | // Register this forward, using the port number we obtained. 119 | ch := c.forwards.add(*laddr) 120 | 121 | return &tcpListener{laddr, c, ch}, nil 122 | } 123 | 124 | // forwardList stores a mapping between remote 125 | // forward requests and the tcpListeners. 126 | type forwardList struct { 127 | sync.Mutex 128 | entries []forwardEntry 129 | } 130 | 131 | // forwardEntry represents an established mapping of a laddr on a 132 | // remote ssh server to a channel connected to a tcpListener. 133 | type forwardEntry struct { 134 | laddr net.TCPAddr 135 | c chan forward 136 | } 137 | 138 | // forward represents an incoming forwarded tcpip connection. The 139 | // arguments to add/remove/lookup should be address as specified in 140 | // the original forward-request. 141 | type forward struct { 142 | newCh NewChannel // the ssh client channel underlying this forward 143 | raddr *net.TCPAddr // the raddr of the incoming connection 144 | } 145 | 146 | func (l *forwardList) add(addr net.TCPAddr) chan forward { 147 | l.Lock() 148 | defer l.Unlock() 149 | f := forwardEntry{ 150 | addr, 151 | make(chan forward, 1), 152 | } 153 | l.entries = append(l.entries, f) 154 | return f.c 155 | } 156 | 157 | // See RFC 4254, section 7.2 158 | type forwardedTCPPayload struct { 159 | Addr string 160 | Port uint32 161 | OriginAddr string 162 | OriginPort uint32 163 | } 164 | 165 | // parseTCPAddr parses the originating address from the remote into a *net.TCPAddr. 166 | func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) { 167 | if port == 0 || port > 65535 { 168 | return nil, fmt.Errorf("ssh: port number out of range: %d", port) 169 | } 170 | ip := net.ParseIP(string(addr)) 171 | if ip == nil { 172 | return nil, fmt.Errorf("ssh: cannot parse IP address %q", addr) 173 | } 174 | return &net.TCPAddr{IP: ip, Port: int(port)}, nil 175 | } 176 | 177 | func (l *forwardList) handleChannels(in <-chan NewChannel) { 178 | for ch := range in { 179 | var payload forwardedTCPPayload 180 | if err := Unmarshal(ch.ExtraData(), &payload); err != nil { 181 | ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error()) 182 | continue 183 | } 184 | 185 | // RFC 4254 section 7.2 specifies that incoming 186 | // addresses should list the address, in string 187 | // format. It is implied that this should be an IP 188 | // address, as it would be impossible to connect to it 189 | // otherwise. 190 | laddr, err := parseTCPAddr(payload.Addr, payload.Port) 191 | if err != nil { 192 | ch.Reject(ConnectionFailed, err.Error()) 193 | continue 194 | } 195 | raddr, err := parseTCPAddr(payload.OriginAddr, payload.OriginPort) 196 | if err != nil { 197 | ch.Reject(ConnectionFailed, err.Error()) 198 | continue 199 | } 200 | 201 | if ok := l.forward(*laddr, *raddr, ch); !ok { 202 | // Section 7.2, implementations MUST reject spurious incoming 203 | // connections. 204 | ch.Reject(Prohibited, "no forward for address") 205 | continue 206 | } 207 | } 208 | } 209 | 210 | // remove removes the forward entry, and the channel feeding its 211 | // listener. 212 | func (l *forwardList) remove(addr net.TCPAddr) { 213 | l.Lock() 214 | defer l.Unlock() 215 | for i, f := range l.entries { 216 | if addr.IP.Equal(f.laddr.IP) && addr.Port == f.laddr.Port { 217 | l.entries = append(l.entries[:i], l.entries[i+1:]...) 218 | close(f.c) 219 | return 220 | } 221 | } 222 | } 223 | 224 | // closeAll closes and clears all forwards. 225 | func (l *forwardList) closeAll() { 226 | l.Lock() 227 | defer l.Unlock() 228 | for _, f := range l.entries { 229 | close(f.c) 230 | } 231 | l.entries = nil 232 | } 233 | 234 | func (l *forwardList) forward(laddr, raddr net.TCPAddr, ch NewChannel) bool { 235 | l.Lock() 236 | defer l.Unlock() 237 | for _, f := range l.entries { 238 | if laddr.IP.Equal(f.laddr.IP) && laddr.Port == f.laddr.Port { 239 | f.c <- forward{ch, &raddr} 240 | return true 241 | } 242 | } 243 | return false 244 | } 245 | 246 | type tcpListener struct { 247 | laddr *net.TCPAddr 248 | 249 | conn *Client 250 | in <-chan forward 251 | } 252 | 253 | // Accept waits for and returns the next connection to the listener. 254 | func (l *tcpListener) Accept() (net.Conn, error) { 255 | s, ok := <-l.in 256 | if !ok { 257 | return nil, io.EOF 258 | } 259 | ch, incoming, err := s.newCh.Accept() 260 | if err != nil { 261 | return nil, err 262 | } 263 | go DiscardRequests(incoming) 264 | 265 | return &tcpChanConn{ 266 | Channel: ch, 267 | laddr: l.laddr, 268 | raddr: s.raddr, 269 | }, nil 270 | } 271 | 272 | // Close closes the listener. 273 | func (l *tcpListener) Close() error { 274 | m := channelForwardMsg{ 275 | l.laddr.IP.String(), 276 | uint32(l.laddr.Port), 277 | } 278 | 279 | // this also closes the listener. 280 | l.conn.forwards.remove(*l.laddr) 281 | ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m)) 282 | if err == nil && !ok { 283 | err = errors.New("ssh: cancel-tcpip-forward failed") 284 | } 285 | return err 286 | } 287 | 288 | // Addr returns the listener's network address. 289 | func (l *tcpListener) Addr() net.Addr { 290 | return l.laddr 291 | } 292 | 293 | // Dial initiates a connection to the addr from the remote host. 294 | // The resulting connection has a zero LocalAddr() and RemoteAddr(). 295 | func (c *Client) Dial(n, addr string) (net.Conn, error) { 296 | // Parse the address into host and numeric port. 297 | host, portString, err := net.SplitHostPort(addr) 298 | if err != nil { 299 | return nil, err 300 | } 301 | port, err := strconv.ParseUint(portString, 10, 16) 302 | if err != nil { 303 | return nil, err 304 | } 305 | // Use a zero address for local and remote address. 306 | zeroAddr := &net.TCPAddr{ 307 | IP: net.IPv4zero, 308 | Port: 0, 309 | } 310 | ch, err := c.dial(net.IPv4zero.String(), 0, host, int(port)) 311 | if err != nil { 312 | return nil, err 313 | } 314 | return &tcpChanConn{ 315 | Channel: ch, 316 | laddr: zeroAddr, 317 | raddr: zeroAddr, 318 | }, nil 319 | } 320 | 321 | // DialTCP connects to the remote address raddr on the network net, 322 | // which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used 323 | // as the local address for the connection. 324 | func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) { 325 | if laddr == nil { 326 | laddr = &net.TCPAddr{ 327 | IP: net.IPv4zero, 328 | Port: 0, 329 | } 330 | } 331 | ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port) 332 | if err != nil { 333 | return nil, err 334 | } 335 | return &tcpChanConn{ 336 | Channel: ch, 337 | laddr: laddr, 338 | raddr: raddr, 339 | }, nil 340 | } 341 | 342 | // RFC 4254 7.2 343 | type channelOpenDirectMsg struct { 344 | raddr string 345 | rport uint32 346 | laddr string 347 | lport uint32 348 | } 349 | 350 | func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel, error) { 351 | msg := channelOpenDirectMsg{ 352 | raddr: raddr, 353 | rport: uint32(rport), 354 | laddr: laddr, 355 | lport: uint32(lport), 356 | } 357 | ch, in, err := c.OpenChannel("direct-tcpip", Marshal(&msg)) 358 | if err != nil { 359 | return nil, err 360 | } 361 | go DiscardRequests(in) 362 | return ch, err 363 | } 364 | 365 | type tcpChan struct { 366 | Channel // the backing channel 367 | } 368 | 369 | // tcpChanConn fulfills the net.Conn interface without 370 | // the tcpChan having to hold laddr or raddr directly. 371 | type tcpChanConn struct { 372 | Channel 373 | laddr, raddr net.Addr 374 | } 375 | 376 | // LocalAddr returns the local network address. 377 | func (t *tcpChanConn) LocalAddr() net.Addr { 378 | return t.laddr 379 | } 380 | 381 | // RemoteAddr returns the remote network address. 382 | func (t *tcpChanConn) RemoteAddr() net.Addr { 383 | return t.raddr 384 | } 385 | 386 | // SetDeadline sets the read and write deadlines associated 387 | // with the connection. 388 | func (t *tcpChanConn) SetDeadline(deadline time.Time) error { 389 | if err := t.SetReadDeadline(deadline); err != nil { 390 | return err 391 | } 392 | return t.SetWriteDeadline(deadline) 393 | } 394 | 395 | // SetReadDeadline sets the read deadline. 396 | // A zero value for t means Read will not time out. 397 | // After the deadline, the error from Read will implement net.Error 398 | // with Timeout() == true. 399 | func (t *tcpChanConn) SetReadDeadline(deadline time.Time) error { 400 | return errors.New("ssh: tcpChan: deadline not supported") 401 | } 402 | 403 | // SetWriteDeadline exists to satisfy the net.Conn interface 404 | // but is not implemented by this type. It always returns an error. 405 | func (t *tcpChanConn) SetWriteDeadline(deadline time.Time) error { 406 | return errors.New("ssh: tcpChan: deadline not supported") 407 | } 408 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/terminal/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin dragonfly freebsd linux,!appengine netbsd openbsd 6 | 7 | // Package terminal provides support functions for dealing with terminals, as 8 | // commonly found on UNIX systems. 9 | // 10 | // Putting a terminal into raw mode is the most common requirement: 11 | // 12 | // oldState, err := terminal.MakeRaw(0) 13 | // if err != nil { 14 | // panic(err) 15 | // } 16 | // defer terminal.Restore(0, oldState) 17 | package terminal 18 | 19 | import ( 20 | "io" 21 | "syscall" 22 | "unsafe" 23 | ) 24 | 25 | // State contains the state of a terminal. 26 | type State struct { 27 | termios syscall.Termios 28 | } 29 | 30 | // IsTerminal returns true if the given file descriptor is a terminal. 31 | func IsTerminal(fd int) bool { 32 | var termios syscall.Termios 33 | _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) 34 | return err == 0 35 | } 36 | 37 | // MakeRaw put the terminal connected to the given file descriptor into raw 38 | // mode and returns the previous state of the terminal so that it can be 39 | // restored. 40 | func MakeRaw(fd int) (*State, error) { 41 | var oldState State 42 | if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { 43 | return nil, err 44 | } 45 | 46 | newState := oldState.termios 47 | newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF 48 | newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG 49 | if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { 50 | return nil, err 51 | } 52 | 53 | return &oldState, nil 54 | } 55 | 56 | // GetState returns the current state of a terminal which may be useful to 57 | // restore the terminal after a signal. 58 | func GetState(fd int) (*State, error) { 59 | var oldState State 60 | if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { 61 | return nil, err 62 | } 63 | 64 | return &oldState, nil 65 | } 66 | 67 | // Restore restores the terminal connected to the given file descriptor to a 68 | // previous state. 69 | func Restore(fd int, state *State) error { 70 | _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0) 71 | return err 72 | } 73 | 74 | // GetSize returns the dimensions of the given terminal. 75 | func GetSize(fd int) (width, height int, err error) { 76 | var dimensions [4]uint16 77 | 78 | if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 { 79 | return -1, -1, err 80 | } 81 | return int(dimensions[1]), int(dimensions[0]), nil 82 | } 83 | 84 | // ReadPassword reads a line of input from a terminal without local echo. This 85 | // is commonly used for inputting passwords and other sensitive data. The slice 86 | // returned does not include the \n. 87 | func ReadPassword(fd int) ([]byte, error) { 88 | var oldState syscall.Termios 89 | if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 { 90 | return nil, err 91 | } 92 | 93 | newState := oldState 94 | newState.Lflag &^= syscall.ECHO 95 | newState.Lflag |= syscall.ICANON | syscall.ISIG 96 | newState.Iflag |= syscall.ICRNL 97 | if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { 98 | return nil, err 99 | } 100 | 101 | defer func() { 102 | syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0) 103 | }() 104 | 105 | var buf [16]byte 106 | var ret []byte 107 | for { 108 | n, err := syscall.Read(fd, buf[:]) 109 | if err != nil { 110 | return nil, err 111 | } 112 | if n == 0 { 113 | if len(ret) == 0 { 114 | return nil, io.EOF 115 | } 116 | break 117 | } 118 | if buf[n-1] == '\n' { 119 | n-- 120 | } 121 | ret = append(ret, buf[:n]...) 122 | if n < len(buf) { 123 | break 124 | } 125 | } 126 | 127 | return ret, nil 128 | } 129 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin dragonfly freebsd netbsd openbsd 6 | 7 | package terminal 8 | 9 | import "syscall" 10 | 11 | const ioctlReadTermios = syscall.TIOCGETA 12 | const ioctlWriteTermios = syscall.TIOCSETA 13 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/terminal/util_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package terminal 6 | 7 | // These constants are declared here, rather than importing 8 | // them from the syscall package as some syscall packages, even 9 | // on linux, for example gccgo, do not declare them. 10 | const ioctlReadTermios = 0x5401 // syscall.TCGETS 11 | const ioctlWriteTermios = 0x5402 // syscall.TCSETS 12 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/terminal/util_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build windows 6 | 7 | // Package terminal provides support functions for dealing with terminals, as 8 | // commonly found on UNIX systems. 9 | // 10 | // Putting a terminal into raw mode is the most common requirement: 11 | // 12 | // oldState, err := terminal.MakeRaw(0) 13 | // if err != nil { 14 | // panic(err) 15 | // } 16 | // defer terminal.Restore(0, oldState) 17 | package terminal 18 | 19 | import ( 20 | "io" 21 | "syscall" 22 | "unsafe" 23 | ) 24 | 25 | const ( 26 | enableLineInput = 2 27 | enableEchoInput = 4 28 | enableProcessedInput = 1 29 | enableWindowInput = 8 30 | enableMouseInput = 16 31 | enableInsertMode = 32 32 | enableQuickEditMode = 64 33 | enableExtendedFlags = 128 34 | enableAutoPosition = 256 35 | enableProcessedOutput = 1 36 | enableWrapAtEolOutput = 2 37 | ) 38 | 39 | var kernel32 = syscall.NewLazyDLL("kernel32.dll") 40 | 41 | var ( 42 | procGetConsoleMode = kernel32.NewProc("GetConsoleMode") 43 | procSetConsoleMode = kernel32.NewProc("SetConsoleMode") 44 | procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") 45 | ) 46 | 47 | type ( 48 | short int16 49 | word uint16 50 | 51 | coord struct { 52 | x short 53 | y short 54 | } 55 | smallRect struct { 56 | left short 57 | top short 58 | right short 59 | bottom short 60 | } 61 | consoleScreenBufferInfo struct { 62 | size coord 63 | cursorPosition coord 64 | attributes word 65 | window smallRect 66 | maximumWindowSize coord 67 | } 68 | ) 69 | 70 | type State struct { 71 | mode uint32 72 | } 73 | 74 | // IsTerminal returns true if the given file descriptor is a terminal. 75 | func IsTerminal(fd int) bool { 76 | var st uint32 77 | r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) 78 | return r != 0 && e == 0 79 | } 80 | 81 | // MakeRaw put the terminal connected to the given file descriptor into raw 82 | // mode and returns the previous state of the terminal so that it can be 83 | // restored. 84 | func MakeRaw(fd int) (*State, error) { 85 | var st uint32 86 | _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) 87 | if e != 0 { 88 | return nil, error(e) 89 | } 90 | st &^= (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput) 91 | _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0) 92 | if e != 0 { 93 | return nil, error(e) 94 | } 95 | return &State{st}, nil 96 | } 97 | 98 | // GetState returns the current state of a terminal which may be useful to 99 | // restore the terminal after a signal. 100 | func GetState(fd int) (*State, error) { 101 | var st uint32 102 | _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) 103 | if e != 0 { 104 | return nil, error(e) 105 | } 106 | return &State{st}, nil 107 | } 108 | 109 | // Restore restores the terminal connected to the given file descriptor to a 110 | // previous state. 111 | func Restore(fd int, state *State) error { 112 | _, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0) 113 | return err 114 | } 115 | 116 | // GetSize returns the dimensions of the given terminal. 117 | func GetSize(fd int) (width, height int, err error) { 118 | var info consoleScreenBufferInfo 119 | _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0) 120 | if e != 0 { 121 | return 0, 0, error(e) 122 | } 123 | return int(info.size.x), int(info.size.y), nil 124 | } 125 | 126 | // ReadPassword reads a line of input from a terminal without local echo. This 127 | // is commonly used for inputting passwords and other sensitive data. The slice 128 | // returned does not include the \n. 129 | func ReadPassword(fd int) ([]byte, error) { 130 | var st uint32 131 | _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) 132 | if e != 0 { 133 | return nil, error(e) 134 | } 135 | old := st 136 | 137 | st &^= (enableEchoInput) 138 | st |= (enableProcessedInput | enableLineInput | enableProcessedOutput) 139 | _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0) 140 | if e != 0 { 141 | return nil, error(e) 142 | } 143 | 144 | defer func() { 145 | syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0) 146 | }() 147 | 148 | var buf [16]byte 149 | var ret []byte 150 | for { 151 | n, err := syscall.Read(syscall.Handle(fd), buf[:]) 152 | if err != nil { 153 | return nil, err 154 | } 155 | if n == 0 { 156 | if len(ret) == 0 { 157 | return nil, io.EOF 158 | } 159 | break 160 | } 161 | if buf[n-1] == '\n' { 162 | n-- 163 | } 164 | if n > 0 && buf[n-1] == '\r' { 165 | n-- 166 | } 167 | ret = append(ret, buf[:n]...) 168 | if n < len(buf) { 169 | break 170 | } 171 | } 172 | 173 | return ret, nil 174 | } 175 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/test/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This package contains integration tests for the 6 | // golang.org/x/crypto/ssh package. 7 | package test 8 | -------------------------------------------------------------------------------- /vendor/golang.org/x/crypto/ssh/transport.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssh 6 | 7 | import ( 8 | "bufio" 9 | "errors" 10 | "io" 11 | ) 12 | 13 | const ( 14 | gcmCipherID = "aes128-gcm@openssh.com" 15 | aes128cbcID = "aes128-cbc" 16 | ) 17 | 18 | // packetConn represents a transport that implements packet based 19 | // operations. 20 | type packetConn interface { 21 | // Encrypt and send a packet of data to the remote peer. 22 | writePacket(packet []byte) error 23 | 24 | // Read a packet from the connection 25 | readPacket() ([]byte, error) 26 | 27 | // Close closes the write-side of the connection. 28 | Close() error 29 | } 30 | 31 | // transport is the keyingTransport that implements the SSH packet 32 | // protocol. 33 | type transport struct { 34 | reader connectionState 35 | writer connectionState 36 | 37 | bufReader *bufio.Reader 38 | bufWriter *bufio.Writer 39 | rand io.Reader 40 | 41 | io.Closer 42 | 43 | // Initial H used for the session ID. Once assigned this does 44 | // not change, even during subsequent key exchanges. 45 | sessionID []byte 46 | } 47 | 48 | // getSessionID returns the ID of the SSH connection. The return value 49 | // should not be modified. 50 | func (t *transport) getSessionID() []byte { 51 | if t.sessionID == nil { 52 | panic("session ID not set yet") 53 | } 54 | return t.sessionID 55 | } 56 | 57 | // packetCipher represents a combination of SSH encryption/MAC 58 | // protocol. A single instance should be used for one direction only. 59 | type packetCipher interface { 60 | // writePacket encrypts the packet and writes it to w. The 61 | // contents of the packet are generally scrambled. 62 | writePacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error 63 | 64 | // readPacket reads and decrypts a packet of data. The 65 | // returned packet may be overwritten by future calls of 66 | // readPacket. 67 | readPacket(seqnum uint32, r io.Reader) ([]byte, error) 68 | } 69 | 70 | // connectionState represents one side (read or write) of the 71 | // connection. This is necessary because each direction has its own 72 | // keys, and can even have its own algorithms 73 | type connectionState struct { 74 | packetCipher 75 | seqNum uint32 76 | dir direction 77 | pendingKeyChange chan packetCipher 78 | } 79 | 80 | // prepareKeyChange sets up key material for a keychange. The key changes in 81 | // both directions are triggered by reading and writing a msgNewKey packet 82 | // respectively. 83 | func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) error { 84 | if t.sessionID == nil { 85 | t.sessionID = kexResult.H 86 | } 87 | 88 | kexResult.SessionID = t.sessionID 89 | 90 | if ciph, err := newPacketCipher(t.reader.dir, algs.r, kexResult); err != nil { 91 | return err 92 | } else { 93 | t.reader.pendingKeyChange <- ciph 94 | } 95 | 96 | if ciph, err := newPacketCipher(t.writer.dir, algs.w, kexResult); err != nil { 97 | return err 98 | } else { 99 | t.writer.pendingKeyChange <- ciph 100 | } 101 | 102 | return nil 103 | } 104 | 105 | // Read and decrypt next packet. 106 | func (t *transport) readPacket() ([]byte, error) { 107 | return t.reader.readPacket(t.bufReader) 108 | } 109 | 110 | func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { 111 | packet, err := s.packetCipher.readPacket(s.seqNum, r) 112 | s.seqNum++ 113 | if err == nil && len(packet) == 0 { 114 | err = errors.New("ssh: zero length packet") 115 | } 116 | 117 | if len(packet) > 0 && packet[0] == msgNewKeys { 118 | select { 119 | case cipher := <-s.pendingKeyChange: 120 | s.packetCipher = cipher 121 | default: 122 | return nil, errors.New("ssh: got bogus newkeys message.") 123 | } 124 | } 125 | 126 | // The packet may point to an internal buffer, so copy the 127 | // packet out here. 128 | fresh := make([]byte, len(packet)) 129 | copy(fresh, packet) 130 | 131 | return fresh, err 132 | } 133 | 134 | func (t *transport) writePacket(packet []byte) error { 135 | return t.writer.writePacket(t.bufWriter, t.rand, packet) 136 | } 137 | 138 | func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error { 139 | changeKeys := len(packet) > 0 && packet[0] == msgNewKeys 140 | 141 | err := s.packetCipher.writePacket(s.seqNum, w, rand, packet) 142 | if err != nil { 143 | return err 144 | } 145 | if err = w.Flush(); err != nil { 146 | return err 147 | } 148 | s.seqNum++ 149 | if changeKeys { 150 | select { 151 | case cipher := <-s.pendingKeyChange: 152 | s.packetCipher = cipher 153 | default: 154 | panic("ssh: no key material for msgNewKeys") 155 | } 156 | } 157 | return err 158 | } 159 | 160 | func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transport { 161 | t := &transport{ 162 | bufReader: bufio.NewReader(rwc), 163 | bufWriter: bufio.NewWriter(rwc), 164 | rand: rand, 165 | reader: connectionState{ 166 | packetCipher: &streamPacketCipher{cipher: noneCipher{}}, 167 | pendingKeyChange: make(chan packetCipher, 1), 168 | }, 169 | writer: connectionState{ 170 | packetCipher: &streamPacketCipher{cipher: noneCipher{}}, 171 | pendingKeyChange: make(chan packetCipher, 1), 172 | }, 173 | Closer: rwc, 174 | } 175 | if isClient { 176 | t.reader.dir = serverKeys 177 | t.writer.dir = clientKeys 178 | } else { 179 | t.reader.dir = clientKeys 180 | t.writer.dir = serverKeys 181 | } 182 | 183 | return t 184 | } 185 | 186 | type direction struct { 187 | ivTag []byte 188 | keyTag []byte 189 | macKeyTag []byte 190 | } 191 | 192 | var ( 193 | serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}} 194 | clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}} 195 | ) 196 | 197 | // generateKeys generates key material for IV, MAC and encryption. 198 | func generateKeys(d direction, algs directionAlgorithms, kex *kexResult) (iv, key, macKey []byte) { 199 | cipherMode := cipherModes[algs.Cipher] 200 | macMode := macModes[algs.MAC] 201 | 202 | iv = make([]byte, cipherMode.ivSize) 203 | key = make([]byte, cipherMode.keySize) 204 | macKey = make([]byte, macMode.keySize) 205 | 206 | generateKeyMaterial(iv, d.ivTag, kex) 207 | generateKeyMaterial(key, d.keyTag, kex) 208 | generateKeyMaterial(macKey, d.macKeyTag, kex) 209 | return 210 | } 211 | 212 | // setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as 213 | // described in RFC 4253, section 6.4. direction should either be serverKeys 214 | // (to setup server->client keys) or clientKeys (for client->server keys). 215 | func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) { 216 | iv, key, macKey := generateKeys(d, algs, kex) 217 | 218 | if algs.Cipher == gcmCipherID { 219 | return newGCMCipher(iv, key, macKey) 220 | } 221 | 222 | if algs.Cipher == aes128cbcID { 223 | return newAESCBCCipher(iv, key, macKey, algs) 224 | } 225 | 226 | c := &streamPacketCipher{ 227 | mac: macModes[algs.MAC].new(macKey), 228 | } 229 | c.macResult = make([]byte, c.mac.Size()) 230 | 231 | var err error 232 | c.cipher, err = cipherModes[algs.Cipher].createStream(key, iv) 233 | if err != nil { 234 | return nil, err 235 | } 236 | 237 | return c, nil 238 | } 239 | 240 | // generateKeyMaterial fills out with key material generated from tag, K, H 241 | // and sessionId, as specified in RFC 4253, section 7.2. 242 | func generateKeyMaterial(out, tag []byte, r *kexResult) { 243 | var digestsSoFar []byte 244 | 245 | h := r.Hash.New() 246 | for len(out) > 0 { 247 | h.Reset() 248 | h.Write(r.K) 249 | h.Write(r.H) 250 | 251 | if len(digestsSoFar) == 0 { 252 | h.Write(tag) 253 | h.Write(r.SessionID) 254 | } else { 255 | h.Write(digestsSoFar) 256 | } 257 | 258 | digest := h.Sum(nil) 259 | n := copy(out, digest) 260 | out = out[n:] 261 | if len(out) > 0 { 262 | digestsSoFar = append(digestsSoFar, digest...) 263 | } 264 | } 265 | } 266 | 267 | const packageVersion = "SSH-2.0-Go" 268 | 269 | // Sends and receives a version line. The versionLine string should 270 | // be US ASCII, start with "SSH-2.0-", and should not include a 271 | // newline. exchangeVersions returns the other side's version line. 272 | func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err error) { 273 | // Contrary to the RFC, we do not ignore lines that don't 274 | // start with "SSH-2.0-" to make the library usable with 275 | // nonconforming servers. 276 | for _, c := range versionLine { 277 | // The spec disallows non US-ASCII chars, and 278 | // specifically forbids null chars. 279 | if c < 32 { 280 | return nil, errors.New("ssh: junk character in version line") 281 | } 282 | } 283 | if _, err = rw.Write(append(versionLine, '\r', '\n')); err != nil { 284 | return 285 | } 286 | 287 | them, err = readVersion(rw) 288 | return them, err 289 | } 290 | 291 | // maxVersionStringBytes is the maximum number of bytes that we'll 292 | // accept as a version string. RFC 4253 section 4.2 limits this at 255 293 | // chars 294 | const maxVersionStringBytes = 255 295 | 296 | // Read version string as specified by RFC 4253, section 4.2. 297 | func readVersion(r io.Reader) ([]byte, error) { 298 | versionString := make([]byte, 0, 64) 299 | var ok bool 300 | var buf [1]byte 301 | 302 | for len(versionString) < maxVersionStringBytes { 303 | _, err := io.ReadFull(r, buf[:]) 304 | if err != nil { 305 | return nil, err 306 | } 307 | // The RFC says that the version should be terminated with \r\n 308 | // but several SSH servers actually only send a \n. 309 | if buf[0] == '\n' { 310 | ok = true 311 | break 312 | } 313 | 314 | // non ASCII chars are disallowed, but we are lenient, 315 | // since Go doesn't use null-terminated strings. 316 | 317 | // The RFC allows a comment after a space, however, 318 | // all of it (version and comments) goes into the 319 | // session hash. 320 | versionString = append(versionString, buf[0]) 321 | } 322 | 323 | if !ok { 324 | return nil, errors.New("ssh: overflow reading version string") 325 | } 326 | 327 | // There might be a '\r' on the end which we should remove. 328 | if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' { 329 | versionString = versionString[:len(versionString)-1] 330 | } 331 | return versionString, nil 332 | } 333 | -------------------------------------------------------------------------------- /vscale.go: -------------------------------------------------------------------------------- 1 | package vscale 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "time" 7 | 8 | "github.com/docker/machine/libmachine/drivers" 9 | "github.com/docker/machine/libmachine/log" 10 | "github.com/docker/machine/libmachine/mcnflag" 11 | "github.com/docker/machine/libmachine/state" 12 | api "github.com/evrone/vscale_api" 13 | ) 14 | 15 | type Driver struct { 16 | *drivers.BaseDriver 17 | AccessToken string 18 | ScaletID int 19 | ScaletName string 20 | Rplan string 21 | MadeFrom string 22 | Location string 23 | SSHKeyID int 24 | } 25 | 26 | const ( 27 | defaultRplan = "small" 28 | defaultLocation = "spb0" 29 | defaultMadeFrom = "ubuntu_14.04_64_002_master" 30 | ) 31 | 32 | func (d *Driver) GetCreateFlags() []mcnflag.Flag { 33 | return []mcnflag.Flag{ 34 | mcnflag.StringFlag{ 35 | EnvVar: "VSCALE_ACCESS_TOKEN", 36 | Name: "vscale-access-token", 37 | Usage: "Vscale access token", 38 | }, 39 | mcnflag.StringFlag{ 40 | EnvVar: "VSCALE_LOCATION", 41 | Name: "vscale-location", 42 | Usage: "Vscale location", 43 | Value: defaultLocation, 44 | }, 45 | mcnflag.StringFlag{ 46 | EnvVar: "VSCALE_RPLAN", 47 | Name: "vscale-rplan", 48 | Usage: "Vscale rplan", 49 | Value: defaultRplan, 50 | }, 51 | mcnflag.StringFlag{ 52 | EnvVar: "VSCALE_MADE_FROM", 53 | Name: "vscale-made-from", 54 | Usage: "Vscale made from", 55 | Value: defaultMadeFrom, 56 | }, 57 | } 58 | } 59 | 60 | func NewDriver(hostName, storePath string) *Driver { 61 | return &Driver{ 62 | Rplan: defaultRplan, 63 | Location: defaultLocation, 64 | MadeFrom: defaultMadeFrom, 65 | BaseDriver: &drivers.BaseDriver{ 66 | MachineName: hostName, 67 | StorePath: storePath, 68 | }, 69 | } 70 | } 71 | 72 | func (d *Driver) GetSSHHostname() (string, error) { 73 | return d.GetIP() 74 | } 75 | 76 | // DriverName returns the name of the driver 77 | func (d *Driver) DriverName() string { 78 | return "vscale" 79 | } 80 | 81 | func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { 82 | d.AccessToken = flags.String("vscale-access-token") 83 | d.Location = flags.String("vscale-location") 84 | d.Rplan = flags.String("vscale-rplan") 85 | d.MadeFrom = flags.String("vscale-made-from") 86 | 87 | d.SwarmMaster = flags.Bool("swarm-master") 88 | d.SwarmHost = flags.String("swarm-host") 89 | d.SwarmDiscovery = flags.String("swarm-discovery") 90 | d.SSHPort = 22 91 | 92 | if d.AccessToken == "" { 93 | return fmt.Errorf("vscale driver requres the --vscale-access-token option") 94 | } 95 | 96 | return nil 97 | } 98 | 99 | func (d *Driver) getClient() *api.Client { 100 | return api.New(d.AccessToken) 101 | } 102 | 103 | func (d *Driver) PreCreateCheck() error { 104 | client := d.getClient() 105 | if client == nil { 106 | return fmt.Errorf("Cannot create Vscale client. Check --vscale-access-token option") 107 | } 108 | 109 | return nil 110 | } 111 | 112 | func (d *Driver) Create() error { 113 | log.Infof("Creating SSH key...") 114 | key, err := d.createSSHKey() 115 | if err != nil { 116 | return err 117 | } 118 | d.SSHKeyID = key.ID 119 | 120 | log.Infof("Creating Vscale scalet...") 121 | 122 | client := d.getClient() 123 | createRequest := &api.ScaletCreateRequest{ 124 | MakeFrom: d.MadeFrom, 125 | Rplan: d.Rplan, 126 | DoStart: true, 127 | Name: d.MachineName, 128 | Keys: []int{d.SSHKeyID}, 129 | Location: d.Location, 130 | } 131 | 132 | newScalet, _, err := client.Scalet.Create(createRequest) 133 | if err != nil { 134 | return err 135 | } 136 | 137 | d.ScaletID = newScalet.CTID 138 | 139 | log.Info("Waiting for IP address to be assigned to the Scalet...") 140 | 141 | for { 142 | newScalet, _, err = client.Scalet.GetByID(d.ScaletID) 143 | if err != nil { 144 | return err 145 | } 146 | 147 | if newScalet.PublicAddress != nil { 148 | d.IPAddress = newScalet.PublicAddress.Address 149 | } 150 | 151 | if d.IPAddress != "" { 152 | break 153 | } 154 | 155 | time.Sleep(1 * time.Second) 156 | } 157 | 158 | log.Debugf("Created scalet with ID: %v, IPAddress: %v", d.ScaletID, d.IPAddress) 159 | return nil 160 | } 161 | 162 | func (d *Driver) GetURL() (string, error) { 163 | ip, err := d.GetIP() 164 | if err != nil { 165 | return "", err 166 | } 167 | return fmt.Sprintf("tcp://%s", net.JoinHostPort(ip, "2376")), nil 168 | } 169 | 170 | func (d *Driver) GetState() (state.State, error) { 171 | scalet, _, err := d.getClient().Scalet.GetByID(d.ScaletID) 172 | if err != nil { 173 | return state.Error, err 174 | } 175 | 176 | switch scalet.Status { 177 | case "started": 178 | return state.Running, nil 179 | case "stopped": 180 | return state.Stopped, nil 181 | case "defined": 182 | return state.Starting, nil 183 | } 184 | return state.None, nil 185 | } 186 | 187 | func (d *Driver) Start() error { 188 | _, _, err := d.getClient().Scalet.Start(d.ScaletID) 189 | return err 190 | } 191 | 192 | func (d *Driver) Stop() error { 193 | _, _, err := d.getClient().Scalet.Halt(d.ScaletID) 194 | return err 195 | } 196 | 197 | func (d *Driver) Remove() error { 198 | client := d.getClient() 199 | _, _, err := client.Scalet.Delete(d.ScaletID) 200 | if err != nil { 201 | return err 202 | } 203 | 204 | _, err = client.SSHKey.Delete(d.SSHKeyID) 205 | if err != nil { 206 | return err 207 | } 208 | 209 | return nil 210 | } 211 | 212 | func (d *Driver) Restart() error { 213 | _, _, err := d.getClient().Scalet.Restart(d.ScaletID) 214 | return err 215 | } 216 | 217 | func (d *Driver) Kill() error { 218 | _, _, err := d.getClient().Scalet.Halt(d.ScaletID) 219 | return err 220 | } 221 | -------------------------------------------------------------------------------- /vscale_test.go: -------------------------------------------------------------------------------- 1 | package vscale 2 | 3 | import ( 4 | "github.com/docker/machine/libmachine/drivers" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | func TestSetConfigFromFlags(t *testing.T) { 10 | driver := NewDriver("default", "path") 11 | 12 | checkFlags := &drivers.CheckDriverOptions{ 13 | FlagsValues: map[string]interface{}{ 14 | "vscale-access-token": "TOKEN", 15 | }, 16 | CreateFlags: driver.GetCreateFlags(), 17 | } 18 | 19 | err := driver.SetConfigFromFlags(checkFlags) 20 | 21 | assert.NoError(t, err) 22 | assert.Empty(t, checkFlags.InvalidFlags) 23 | } 24 | --------------------------------------------------------------------------------