├── .gitignore ├── .godir ├── Godeps ├── Godeps.json └── Readme ├── LICENSE ├── README.md ├── aux.go ├── handlers.go ├── keyboards.go ├── main.go ├── user.go └── vendor ├── github.com ├── braintree │ └── manners │ │ ├── LICENSE │ │ ├── README.md │ │ ├── interfaces.go │ │ ├── server.go │ │ └── static.go ├── go-telegram-bot-api │ └── telegram-bot-api │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE.txt │ │ ├── README.md │ │ ├── bot.go │ │ ├── configs.go │ │ ├── helpers.go │ │ └── types.go └── technoweenie │ └── multipartstreamer │ ├── LICENSE │ ├── README.md │ └── multipartstreamer.go └── 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 ├── 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 └── transport.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 | -------------------------------------------------------------------------------- /.godir: -------------------------------------------------------------------------------- 1 | github.com/rafadev7/sshclient -------------------------------------------------------------------------------- /Godeps/Godeps.json: -------------------------------------------------------------------------------- 1 | { 2 | "ImportPath": "github.com/rafadev7/sshclient", 3 | "GoVersion": "go1.6", 4 | "GodepVersion": "v63", 5 | "Deps": [ 6 | { 7 | "ImportPath": "github.com/braintree/manners", 8 | "Comment": "0.4.0-13-g213a497", 9 | "Rev": "213a497c0285defc24f640dbdb8a30f7d7080310" 10 | }, 11 | { 12 | "ImportPath": "github.com/go-telegram-bot-api/telegram-bot-api", 13 | "Comment": "v4.2.1", 14 | "Rev": "bf6e165e92e6da5dd62b859f8397f7c8864e4b04" 15 | }, 16 | { 17 | "ImportPath": "github.com/technoweenie/multipartstreamer", 18 | "Comment": "v1.0.1", 19 | "Rev": "a90a01d73ae432e2611d178c18367fbaa13e0154" 20 | }, 21 | { 22 | "ImportPath": "golang.org/x/crypto/curve25519", 23 | "Rev": "2f6fccd33b9b1fc23ebb73ad4890698820f7174d" 24 | }, 25 | { 26 | "ImportPath": "golang.org/x/crypto/ssh", 27 | "Rev": "2f6fccd33b9b1fc23ebb73ad4890698820f7174d" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /Godeps/Readme: -------------------------------------------------------------------------------- 1 | This directory tree is generated automatically by godep. 2 | 3 | Please do not edit. 4 | 5 | See https://github.com/tools/godep for more information. 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Roman Buldygin 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Telegram SSH Client Bot 2 | It's a secure ssh client for telegram. 3 | 4 | [@sshclientbot](https://telegram.me/sshclientbot) 5 | 6 | It's an open-source project, we don't store any information you send through the very secure Telegram cryptography system. 7 | 8 | If you got interested then access our github pages and get involved with the project. 9 | 10 | Please [click here to rate us five Stars](https://telegram.me/storebot?start=sshclientbot). 11 | 12 | It's free and open by MIT License. -------------------------------------------------------------------------------- /aux.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "log" 7 | "net/http" 8 | "os" 9 | "os/signal" 10 | "strconv" 11 | "syscall" 12 | 13 | "github.com/braintree/manners" 14 | "github.com/go-telegram-bot-api/telegram-bot-api" 15 | 16 | "golang.org/x/crypto/ssh" 17 | ) 18 | 19 | func GetUser(update tgbotapi.Update) *User { 20 | 21 | u, ok := users[GetUserID(update)] 22 | if !ok { 23 | return nil 24 | } 25 | return u 26 | } 27 | 28 | func GetUserID(update tgbotapi.Update) int { 29 | 30 | if update.Message != nil { 31 | return update.Message.From.ID 32 | } 33 | if update.CallbackQuery != nil { 34 | return update.CallbackQuery.From.ID 35 | } 36 | return 0 37 | } 38 | 39 | func GetChatID(update tgbotapi.Update) int64 { 40 | 41 | if update.Message != nil { 42 | return update.Message.Chat.ID 43 | } 44 | if update.CallbackQuery != nil { 45 | return update.CallbackQuery.Message.Chat.ID 46 | } 47 | return 0 48 | } 49 | 50 | func EditMessage(u *User, msg tgbotapi.Message, text string) (tgbotapi.Message, error) { 51 | 52 | edit := tgbotapi.EditMessageTextConfig{ 53 | BaseEdit: tgbotapi.BaseEdit{ 54 | ChatID: u.ChatID, 55 | MessageID: msg.MessageID, 56 | }, 57 | Text: text, 58 | } 59 | 60 | return u.Bot.Send(edit) 61 | } 62 | 63 | func Run(u *User, cmd string) error { 64 | 65 | sshConfig := &ssh.ClientConfig{ 66 | User: u.User, 67 | Auth: []ssh.AuthMethod{ 68 | ssh.Password(u.Pass), 69 | }, 70 | } 71 | 72 | client, err := ssh.Dial("tcp", u.Host+":"+strconv.Itoa(u.Port), sshConfig) 73 | if err != nil { 74 | return err 75 | } 76 | 77 | session, err := client.NewSession() 78 | if err != nil { 79 | return err 80 | } 81 | defer session.Close() 82 | 83 | outPipe, err := session.StdoutPipe() 84 | if err != nil { 85 | u.Println("Error getting outPipe: " + err.Error()) 86 | } 87 | 88 | errPipe, err := session.StderrPipe() 89 | if err != nil { 90 | u.Println("Error getting errPipe: " + err.Error()) 91 | } 92 | 93 | err = session.Run(cmd) 94 | if err != nil { 95 | u.Println(err.Error()) 96 | } 97 | 98 | stdOut, err := ioutil.ReadAll(outPipe) 99 | if err != nil { 100 | u.Println("Error reading stdOut: " + err.Error()) 101 | } 102 | 103 | u.Println(string(stdOut)) 104 | 105 | stdErr, err := ioutil.ReadAll(errPipe) 106 | if err != nil { 107 | u.Println("Error reading stdErr: " + err.Error()) 108 | } 109 | 110 | u.Println(string(stdErr)) 111 | 112 | return nil 113 | } 114 | 115 | func StartWebServer() { 116 | 117 | ip := os.Getenv(ipEnv) 118 | if ip == "" { 119 | log.Panic("PORT ENV NOT FOUND!") 120 | } 121 | 122 | port := os.Getenv(portEnv) 123 | if port == "" { 124 | log.Panic("PORT ENV NOT FOUND!") 125 | } 126 | // WebServer Workaround 127 | // These routes are pingged for services just to never idles this instance 128 | mux := http.NewServeMux() 129 | // Starting a Web Server never idles our instance 130 | mux.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) { 131 | w.Header().Set("Content-Type", "text/plain; charset=utf-8") 132 | w.WriteHeader(http.StatusOK) 133 | w.Write([]byte("pong")) 134 | }) 135 | mux.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) { 136 | w.Header().Set("Content-Type", "text/html; charset=utf-8") 137 | w.WriteHeader(http.StatusOK) 138 | w.Write([]byte("\"Website")) 139 | }) 140 | // Shut the server down gracefully 141 | processStopedBySignal() 142 | // Manners allows you to shut your Go webserver down gracefully, without dropping any requests 143 | err := manners.ListenAndServe(ip+":"+port, mux) 144 | if err != nil { 145 | log.Panic(err) 146 | return 147 | } else { 148 | log.Println("Server listening at " + ip + ":" + port) 149 | } 150 | defer manners.Close() 151 | // END of WebServer Workaround 152 | } 153 | 154 | // Shut the server down gracefully if receive a interrupt signal 155 | func processStopedBySignal() { 156 | // Stop server if someone kills the process 157 | c := make(chan os.Signal, 1) 158 | signal.Notify(c, os.Interrupt) 159 | //signal.Notify(c, syscall.SIGSTOP) 160 | signal.Notify(c, syscall.SIGABRT) // ABORT 161 | signal.Notify(c, syscall.SIGKILL) // KILL 162 | signal.Notify(c, syscall.SIGTERM) // TERMINATION 163 | signal.Notify(c, syscall.SIGINT) // TERMINAL INTERRUPT (Ctrl+C) 164 | signal.Notify(c, syscall.SIGSTOP) // STOP 165 | signal.Notify(c, syscall.SIGTSTP) // TERMINAL STOP (Ctrl+Z) 166 | signal.Notify(c, syscall.SIGQUIT) // QUIT (Ctrl+\) 167 | go func() { 168 | fmt.Println("THIS PROCESS IS WAITING SIGNAL TO STOP GRACEFULLY") 169 | for sig := range c { 170 | fmt.Println("\n\nSTOPED BY SIGNAL:", sig.String()) 171 | fmt.Println("SHUTTING DOWN GRACEFULLY!") 172 | fmt.Println("\nGod bye!") 173 | manners.Close() 174 | os.Exit(1) 175 | } 176 | }() 177 | } 178 | -------------------------------------------------------------------------------- /handlers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/go-telegram-bot-api/telegram-bot-api" 7 | ) 8 | 9 | func Handle(u *User, update tgbotapi.Update) { 10 | switch u.State { 11 | case InitState: 12 | InitHandler(u, update) 13 | case ConfigState: 14 | ConfigHandler(u, update) 15 | case ReadyState: 16 | ReadyHandler(u, update) 17 | } 18 | 19 | // Insert instructions for next command 20 | PostProcess(u) 21 | } 22 | 23 | func PostProcess(u *User) { 24 | switch u.State { 25 | case InitState: 26 | InitHeader(u) 27 | case ConfigState: 28 | ConfigHeader(u) 29 | case ReadyState: 30 | ReadyHeader(u) 31 | } 32 | 33 | } 34 | 35 | func InitHeader(u *User) { 36 | } 37 | 38 | func InitHandler(u *User, update tgbotapi.Update) { 39 | 40 | switch update.Message.Text { 41 | case "/start", "Start": 42 | u.Println("OK, let's configure the SSH Client") 43 | u.Println("Keep calm, we don't store any data inserted by you") 44 | u.HideKeyboard("Type /back if you wanna go back") 45 | u.State = ConfigState 46 | 47 | case "/help", "Help": 48 | u.Println("Type /start to start the SSH Client") 49 | u.Println("Or /about to know more about this project") 50 | SendKeyboard(u, "Or you can just use the keyboard bellow") 51 | 52 | case "/about", "About": 53 | u.Println("This is the first SSH Client for Telegram to rapidly connect to your remote server with all messages encrypted by Telegram") 54 | u.Println("It's an open-source project found in github.com/rafadev7/sshclient") 55 | u.Println("We don't store any information you send through the very secure Telegram cryptography system") 56 | u.Println("If you got interested then access our github pages and get involved with the project") 57 | SendKeyboard(u, "Chose one of the options in the keyboard bellow") 58 | 59 | case "/rate", "Please give us five Stars!": 60 | SendRateInline(u) 61 | SendKeyboard(u, "Then you can choose any options below") 62 | 63 | default: 64 | SendKeyboard(u, "Welcome to the SSH Client for Telegram") 65 | } 66 | 67 | } 68 | 69 | func ConfigHeader(u *User) { 70 | if u.Host == "" { 71 | u.HideKeyboard("Insert your Host address:") 72 | return 73 | } 74 | 75 | if u.Port == 0 { 76 | u.HideKeyboard("Insert the Host Port:") 77 | return 78 | } 79 | 80 | if u.User == "" { 81 | u.HideKeyboard("Insert your User:") 82 | return 83 | } 84 | 85 | if u.Pass == "" { 86 | u.HideKeyboard("Insert your Password:") 87 | return 88 | } 89 | 90 | SendKeyboard(u, "Seems everything is configured") 91 | } 92 | 93 | func ConfigHandler(u *User, update tgbotapi.Update) { 94 | 95 | if update.Message.Text == "/back" { 96 | u.State = InitState 97 | SendKeyboard(u, "Welcome to the SSH Client for Telegram") 98 | return 99 | } 100 | 101 | if u.Host == "" { 102 | u.Host = update.Message.Text 103 | return 104 | } 105 | 106 | if u.Port == 0 { 107 | port, err := strconv.Atoi(update.Message.Text) 108 | if err != nil || port > 65535 { 109 | u.Println("Ops, your port should be a number and < 65535") 110 | } 111 | u.Port = port 112 | return 113 | } 114 | 115 | if u.User == "" { 116 | u.User = update.Message.Text 117 | return 118 | } 119 | 120 | if u.Pass == "" { 121 | u.Pass = update.Message.Text 122 | return 123 | } 124 | 125 | switch update.Message.Text { 126 | case "/host", "Host": 127 | u.Host = "" 128 | 129 | case "/port", "Port": 130 | u.Port = 0 131 | 132 | case "/user", "User": 133 | u.User = "" 134 | 135 | case "/pass", "Pass": 136 | u.Pass = "" 137 | 138 | case "/run", "Start sending commands!": 139 | u.HideKeyboard("Just type the commands you need to send...") 140 | u.HideKeyboard("Or type /back if you wanna go back") 141 | u.State = ReadyState 142 | 143 | } 144 | } 145 | 146 | func ReadyHeader(u *User) { 147 | } 148 | 149 | func ReadyHandler(u *User, update tgbotapi.Update) { 150 | 151 | if update.Message.Text == "/back" { 152 | u.State = ConfigState 153 | return 154 | } 155 | 156 | err := Run(u, update.Message.Text) 157 | if err != nil { 158 | u.Println("Fail:" + err.Error()) 159 | u.Println("Something goes wrong connecting to the server") 160 | u.Println("You have to reconfigure the access data") 161 | u.State = ConfigState 162 | return 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /keyboards.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api" 4 | 5 | func SendKeyboard(u *User, text string) { 6 | 7 | message := tgbotapi.NewMessage(u.ChatID, text) 8 | 9 | switch u.State { 10 | case InitState: 11 | 12 | btnStart := tgbotapi.NewKeyboardButton("Start") 13 | btnAbout := tgbotapi.NewKeyboardButton("About") 14 | btnRow1 := tgbotapi.NewKeyboardButtonRow(btnStart, btnAbout) 15 | btnRate := tgbotapi.NewKeyboardButton("Please give us five Stars!") 16 | btnRow2 := tgbotapi.NewKeyboardButtonRow(btnRate) 17 | keyboard := tgbotapi.NewReplyKeyboard(btnRow1, btnRow2) 18 | 19 | keyboard.OneTimeKeyboard = true 20 | 21 | message.ReplyMarkup = keyboard 22 | _, err := u.Send(message) 23 | if err != nil { 24 | u.Println("Error sending Init keyboard:" + err.Error()) 25 | } 26 | 27 | case ConfigState: 28 | 29 | btnHost := tgbotapi.NewKeyboardButton("Host") 30 | btnPort := tgbotapi.NewKeyboardButton("Port") 31 | btnRow1 := tgbotapi.NewKeyboardButtonRow(btnHost, btnPort) 32 | btnUser := tgbotapi.NewKeyboardButton("User") 33 | btnPass := tgbotapi.NewKeyboardButton("Pass") 34 | btnRow2 := tgbotapi.NewKeyboardButtonRow(btnUser, btnPass) 35 | btnReady := tgbotapi.NewKeyboardButton("Start sending commands!") 36 | btnRow3 := tgbotapi.NewKeyboardButtonRow(btnReady) 37 | keyboard := tgbotapi.NewReplyKeyboard(btnRow1, btnRow2, btnRow3) 38 | 39 | keyboard.OneTimeKeyboard = true 40 | 41 | message.ReplyMarkup = keyboard 42 | _, err := u.Send(message) 43 | if err != nil { 44 | u.Println("Error sending Config keyboard:" + err.Error()) 45 | } 46 | 47 | case ReadyState: 48 | } 49 | } 50 | 51 | func SendRateInline(u *User) { 52 | 53 | u.Println("It's an opensource project, help us!") 54 | 55 | u.Println("Please access the link below and give us five Stars!") 56 | 57 | message := tgbotapi.NewMessage(u.ChatID, "https://telegram.me/storebot?start=sshclientbot") 58 | message.DisableWebPagePreview = true 59 | 60 | _, err := u.Send(message) 61 | if err != nil { 62 | u.Println("Error sending Rate keyboard: " + err.Error()) 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | 7 | "github.com/go-telegram-bot-api/telegram-bot-api" 8 | ) 9 | 10 | const tokenEnv string = "TOKEN" 11 | const ipEnv string = "OPENSHIFT_GO_IP" 12 | const portEnv string = "OPENSHIFT_GO_PORT" 13 | 14 | type State uint 15 | 16 | const ( 17 | InitState = 0 18 | ConfigState = 1 19 | ReadyState = 2 20 | ) 21 | 22 | func main() { 23 | 24 | token := os.Getenv(tokenEnv) 25 | if token == "" { 26 | log.Panic("TOKEN ENV NOT FOUND!") 27 | } 28 | 29 | bot, err := tgbotapi.NewBotAPI(token) 30 | if err != nil { 31 | log.Panic(err) 32 | } 33 | 34 | // Start this webserver just to never puts this instance idle 35 | go StartWebServer() 36 | 37 | bot.Debug = false 38 | 39 | log.Printf("Authorized on account %s\n", bot.Self.UserName) 40 | 41 | news := tgbotapi.NewUpdate(0) 42 | news.Timeout = 60 43 | 44 | updates, err := bot.GetUpdatesChan(news) 45 | 46 | for update := range updates { 47 | 48 | //log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text) 49 | 50 | // This bot doesn't answare for inline queries 51 | if update.InlineQuery != nil { 52 | continue 53 | } 54 | 55 | u := GetUser(update) 56 | 57 | // Block if user not in session 58 | if u == nil { 59 | u = NewUser(bot, update) 60 | u.State = InitState 61 | } 62 | 63 | // Handle the actual command 64 | go Handle(u, update) 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /user.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api" 4 | 5 | type User struct { 6 | ChatID int64 7 | Host string 8 | Port int 9 | User string 10 | Pass string 11 | Bot *tgbotapi.BotAPI 12 | State State // What interface user is using 13 | } 14 | 15 | // int = User.ID 16 | var users = map[int]*User{} 17 | 18 | func NewUser(bot *tgbotapi.BotAPI, update tgbotapi.Update) *User { 19 | u := &User{Bot: bot, ChatID: GetChatID(update), Port: 22} 20 | users[GetUserID(update)] = u 21 | return u 22 | } 23 | 24 | func (u *User) Println(line string) (tgbotapi.Message, error) { 25 | m := tgbotapi.NewMessage(u.ChatID, line) 26 | m.DisableWebPagePreview = true 27 | return u.Bot.Send(m) 28 | } 29 | 30 | func (u *User) Send(msg tgbotapi.MessageConfig) (tgbotapi.Message, error) { 31 | return u.Bot.Send(msg) 32 | } 33 | 34 | func (u *User) HideKeyboard(text string) (tgbotapi.Message, error) { 35 | 36 | m := tgbotapi.NewMessage(u.ChatID, text) 37 | m.ReplyMarkup = tgbotapi.NewHideKeyboard(true) 38 | 39 | return u.Send(m) 40 | } 41 | 42 | func (u *User) IsReady() bool { 43 | if u.Host != "" && u.Port != 0 && u.User != "" && u.Pass != "" { 44 | return true 45 | } 46 | return false 47 | } 48 | -------------------------------------------------------------------------------- /vendor/github.com/braintree/manners/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Braintree, a division of PayPal, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/github.com/braintree/manners/README.md: -------------------------------------------------------------------------------- 1 | # Manners 2 | 3 | A *polite* webserver for Go. 4 | 5 | Manners allows you to shut your Go webserver down gracefully, without dropping any requests. It can act as a drop-in replacement for the standard library's http.ListenAndServe function: 6 | 7 | ```go 8 | func main() { 9 | handler := MyHTTPHandler() 10 | manners.ListenAndServe(":7000", handler) 11 | } 12 | ``` 13 | 14 | Then, when you want to shut the server down: 15 | 16 | ```go 17 | manners.Close() 18 | ``` 19 | 20 | (Note that this does not block until all the requests are finished. Rather, the call to manners.ListenAndServe will stop blocking when all the requests are finished.) 21 | 22 | Manners ensures that all requests are served by incrementing a WaitGroup when a request comes in and decrementing it when the request finishes. 23 | 24 | If your request handler spawns Goroutines that are not guaranteed to finish with the request, you can ensure they are also completed with the `StartRoutine` and `FinishRoutine` functions on the server. 25 | 26 | ### Known Issues 27 | 28 | Manners does not correctly shut down long-lived keepalive connections when issued a shutdown command. Clients on an idle keepalive connection may see a connection reset error rather than a close. See https://github.com/braintree/manners/issues/13 for details. 29 | 30 | ### Compatability 31 | 32 | Manners 0.3.0 and above uses standard library functionality introduced in Go 1.3. 33 | 34 | ### Installation 35 | 36 | `go get github.com/braintree/manners` 37 | -------------------------------------------------------------------------------- /vendor/github.com/braintree/manners/interfaces.go: -------------------------------------------------------------------------------- 1 | package manners 2 | 3 | type waitGroup interface { 4 | Add(int) 5 | Done() 6 | Wait() 7 | } 8 | -------------------------------------------------------------------------------- /vendor/github.com/braintree/manners/server.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package manners provides a wrapper for a standard net/http server that 3 | ensures all active HTTP client have completed their current request 4 | before the server shuts down. 5 | 6 | It can be used a drop-in replacement for the standard http package, 7 | or can wrap a pre-configured Server. 8 | 9 | eg. 10 | 11 | http.Handle("/hello", func(w http.ResponseWriter, r *http.Request) { 12 | w.Write([]byte("Hello\n")) 13 | }) 14 | 15 | log.Fatal(manners.ListenAndServe(":8080", nil)) 16 | 17 | or for a customized server: 18 | 19 | s := manners.NewWithServer(&http.Server{ 20 | Addr: ":8080", 21 | Handler: myHandler, 22 | ReadTimeout: 10 * time.Second, 23 | WriteTimeout: 10 * time.Second, 24 | MaxHeaderBytes: 1 << 20, 25 | }) 26 | log.Fatal(s.ListenAndServe()) 27 | 28 | The server will shut down cleanly when the Close() method is called: 29 | 30 | go func() { 31 | sigchan := make(chan os.Signal, 1) 32 | signal.Notify(sigchan, os.Interrupt, os.Kill) 33 | <-sigchan 34 | log.Info("Shutting down...") 35 | manners.Close() 36 | }() 37 | 38 | http.Handle("/hello", myHandler) 39 | log.Fatal(manners.ListenAndServe(":8080", nil)) 40 | */ 41 | package manners 42 | 43 | import ( 44 | "crypto/tls" 45 | "net" 46 | "net/http" 47 | "sync" 48 | "sync/atomic" 49 | ) 50 | 51 | // A GracefulServer maintains a WaitGroup that counts how many in-flight 52 | // requests the server is handling. When it receives a shutdown signal, 53 | // it stops accepting new requests but does not actually shut down until 54 | // all in-flight requests terminate. 55 | // 56 | // GracefulServer embeds the underlying net/http.Server making its non-override 57 | // methods and properties avaiable. 58 | // 59 | // It must be initialized by calling NewWithServer. 60 | type GracefulServer struct { 61 | *http.Server 62 | 63 | shutdown chan bool 64 | shutdownFinished chan bool 65 | wg waitGroup 66 | routinesCount int 67 | 68 | lcsmu sync.RWMutex 69 | connections map[net.Conn]bool 70 | 71 | up chan net.Listener // Only used by test code. 72 | } 73 | 74 | // NewServer creates a new GracefulServer. 75 | func NewServer() *GracefulServer { 76 | return NewWithServer(new(http.Server)) 77 | } 78 | 79 | // NewWithServer wraps an existing http.Server object and returns a 80 | // GracefulServer that supports all of the original Server operations. 81 | func NewWithServer(s *http.Server) *GracefulServer { 82 | return &GracefulServer{ 83 | Server: s, 84 | shutdown: make(chan bool), 85 | shutdownFinished: make(chan bool, 1), 86 | wg: new(sync.WaitGroup), 87 | routinesCount: 0, 88 | connections: make(map[net.Conn]bool), 89 | } 90 | } 91 | 92 | // Close stops the server from accepting new requets and begins shutting down. 93 | // It returns true if it's the first time Close is called. 94 | func (s *GracefulServer) Close() bool { 95 | return <-s.shutdown 96 | } 97 | 98 | // BlockingClose is similar to Close, except that it blocks until the last 99 | // connection has been closed. 100 | func (s *GracefulServer) BlockingClose() bool { 101 | result := s.Close() 102 | <-s.shutdownFinished 103 | return result 104 | } 105 | 106 | // ListenAndServe provides a graceful equivalent of net/http.Serve.ListenAndServe. 107 | func (s *GracefulServer) ListenAndServe() error { 108 | addr := s.Addr 109 | if addr == "" { 110 | addr = ":http" 111 | } 112 | listener, err := net.Listen("tcp", addr) 113 | if err != nil { 114 | return err 115 | } 116 | 117 | return s.Serve(listener) 118 | } 119 | 120 | // ListenAndServeTLS provides a graceful equivalent of net/http.Serve.ListenAndServeTLS. 121 | func (s *GracefulServer) ListenAndServeTLS(certFile, keyFile string) error { 122 | // direct lift from net/http/server.go 123 | addr := s.Addr 124 | if addr == "" { 125 | addr = ":https" 126 | } 127 | config := &tls.Config{} 128 | if s.TLSConfig != nil { 129 | *config = *s.TLSConfig 130 | } 131 | if config.NextProtos == nil { 132 | config.NextProtos = []string{"http/1.1"} 133 | } 134 | 135 | var err error 136 | config.Certificates = make([]tls.Certificate, 1) 137 | config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) 138 | if err != nil { 139 | return err 140 | } 141 | 142 | ln, err := net.Listen("tcp", addr) 143 | if err != nil { 144 | return err 145 | } 146 | 147 | return s.Serve(tls.NewListener(ln, config)) 148 | } 149 | 150 | // Serve provides a graceful equivalent net/http.Server.Serve. 151 | func (s *GracefulServer) Serve(listener net.Listener) error { 152 | // Wrap the server HTTP handler into graceful one, that will close kept 153 | // alive connections if a new request is received after shutdown. 154 | gracefulHandler := newGracefulHandler(s.Server.Handler) 155 | s.Server.Handler = gracefulHandler 156 | 157 | // Start a goroutine that waits for a shutdown signal and will stop the 158 | // listener when it receives the signal. That in turn will result in 159 | // unblocking of the http.Serve call. 160 | go func() { 161 | s.shutdown <- true 162 | close(s.shutdown) 163 | gracefulHandler.Close() 164 | s.Server.SetKeepAlivesEnabled(false) 165 | listener.Close() 166 | }() 167 | 168 | originalConnState := s.Server.ConnState 169 | 170 | // s.ConnState is invoked by the net/http.Server every time a connection 171 | // changes state. It keeps track of each connection's state over time, 172 | // enabling manners to handle persisted connections correctly. 173 | s.ConnState = func(conn net.Conn, newState http.ConnState) { 174 | s.lcsmu.RLock() 175 | protected := s.connections[conn] 176 | s.lcsmu.RUnlock() 177 | 178 | switch newState { 179 | 180 | case http.StateNew: 181 | // New connection -> StateNew 182 | protected = true 183 | s.StartRoutine() 184 | 185 | case http.StateActive: 186 | // (StateNew, StateIdle) -> StateActive 187 | if gracefulHandler.IsClosed() { 188 | conn.Close() 189 | break 190 | } 191 | 192 | if !protected { 193 | protected = true 194 | s.StartRoutine() 195 | } 196 | 197 | default: 198 | // (StateNew, StateActive) -> (StateIdle, StateClosed, StateHiJacked) 199 | if protected { 200 | s.FinishRoutine() 201 | protected = false 202 | } 203 | } 204 | 205 | s.lcsmu.Lock() 206 | if newState == http.StateClosed || newState == http.StateHijacked { 207 | delete(s.connections, conn) 208 | } else { 209 | s.connections[conn] = protected 210 | } 211 | s.lcsmu.Unlock() 212 | 213 | if originalConnState != nil { 214 | originalConnState(conn, newState) 215 | } 216 | } 217 | 218 | // A hook to allow the server to notify others when it is ready to receive 219 | // requests; only used by tests. 220 | if s.up != nil { 221 | s.up <- listener 222 | } 223 | 224 | err := s.Server.Serve(listener) 225 | // An error returned on shutdown is not worth reporting. 226 | if err != nil && gracefulHandler.IsClosed() { 227 | err = nil 228 | } 229 | 230 | // Wait for pending requests to complete regardless the Serve result. 231 | s.wg.Wait() 232 | s.shutdownFinished <- true 233 | return err 234 | } 235 | 236 | // StartRoutine increments the server's WaitGroup. Use this if a web request 237 | // starts more goroutines and these goroutines are not guaranteed to finish 238 | // before the request. 239 | func (s *GracefulServer) StartRoutine() { 240 | s.lcsmu.Lock() 241 | defer s.lcsmu.Unlock() 242 | s.wg.Add(1) 243 | s.routinesCount++ 244 | } 245 | 246 | // FinishRoutine decrements the server's WaitGroup. Use this to complement 247 | // StartRoutine(). 248 | func (s *GracefulServer) FinishRoutine() { 249 | s.lcsmu.Lock() 250 | defer s.lcsmu.Unlock() 251 | s.wg.Done() 252 | s.routinesCount-- 253 | } 254 | 255 | // RoutinesCount returns the number of currently running routines 256 | func (s *GracefulServer) RoutinesCount() int { 257 | s.lcsmu.RLock() 258 | defer s.lcsmu.RUnlock() 259 | return s.routinesCount 260 | } 261 | 262 | // gracefulHandler is used by GracefulServer to prevent calling ServeHTTP on 263 | // to be closed kept-alive connections during the server shutdown. 264 | type gracefulHandler struct { 265 | closed int32 // accessed atomically. 266 | wrapped http.Handler 267 | } 268 | 269 | func newGracefulHandler(wrapped http.Handler) *gracefulHandler { 270 | return &gracefulHandler{ 271 | wrapped: wrapped, 272 | } 273 | } 274 | 275 | func (gh *gracefulHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 276 | if atomic.LoadInt32(&gh.closed) == 0 { 277 | gh.wrapped.ServeHTTP(w, r) 278 | return 279 | } 280 | r.Body.Close() 281 | // Server is shutting down at this moment, and the connection that this 282 | // handler is being called on is about to be closed. So we do not need to 283 | // actually execute the handler logic. 284 | } 285 | 286 | func (gh *gracefulHandler) Close() { 287 | atomic.StoreInt32(&gh.closed, 1) 288 | } 289 | 290 | func (gh *gracefulHandler) IsClosed() bool { 291 | return atomic.LoadInt32(&gh.closed) == 1 292 | } 293 | -------------------------------------------------------------------------------- /vendor/github.com/braintree/manners/static.go: -------------------------------------------------------------------------------- 1 | package manners 2 | 3 | import ( 4 | "net" 5 | "net/http" 6 | ) 7 | 8 | var defaultServer *GracefulServer 9 | 10 | // ListenAndServe provides a graceful version of the function provided by the 11 | // net/http package. Call Close() to stop the server. 12 | func ListenAndServe(addr string, handler http.Handler) error { 13 | defaultServer = NewWithServer(&http.Server{Addr: addr, Handler: handler}) 14 | return defaultServer.ListenAndServe() 15 | } 16 | 17 | // ListenAndServeTLS provides a graceful version of the function provided by the 18 | // net/http package. Call Close() to stop the server. 19 | func ListenAndServeTLS(addr string, certFile string, keyFile string, handler http.Handler) error { 20 | defaultServer = NewWithServer(&http.Server{Addr: addr, Handler: handler}) 21 | return defaultServer.ListenAndServeTLS(certFile, keyFile) 22 | } 23 | 24 | // Serve provides a graceful version of the function provided by the net/http 25 | // package. Call Close() to stop the server. 26 | func Serve(l net.Listener, handler http.Handler) error { 27 | defaultServer = NewWithServer(&http.Server{Handler: handler}) 28 | return defaultServer.Serve(l) 29 | } 30 | 31 | // Shuts down the default server used by ListenAndServe, ListenAndServeTLS and 32 | // Serve. It returns true if it's the first time Close is called. 33 | func Close() bool { 34 | return defaultServer.Close() 35 | } 36 | -------------------------------------------------------------------------------- /vendor/github.com/go-telegram-bot-api/telegram-bot-api/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | coverage.out 3 | -------------------------------------------------------------------------------- /vendor/github.com/go-telegram-bot-api/telegram-bot-api/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.4 5 | - tip -------------------------------------------------------------------------------- /vendor/github.com/go-telegram-bot-api/telegram-bot-api/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Syfaro 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 | -------------------------------------------------------------------------------- /vendor/github.com/go-telegram-bot-api/telegram-bot-api/README.md: -------------------------------------------------------------------------------- 1 | # Golang bindings for the Telegram Bot API 2 | 3 | [![GoDoc](https://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api?status.svg)](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api) 4 | [![Travis](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api.svg)](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api) 5 | 6 | All methods have been added, and all features should be available. 7 | If you want a feature that hasn't been added yet or something is broken, 8 | open an issue and I'll see what I can do. 9 | 10 | All methods are fairly self explanatory, and reading the godoc page should 11 | explain everything. If something isn't clear, open an issue or submit 12 | a pull request. 13 | 14 | The scope of this project is just to provide a wrapper around the API 15 | without any additional features. There are other projects for creating 16 | something with plugins and command handlers without having to design 17 | all that yourself. 18 | 19 | Use `github.com/go-telegram-bot-api/telegram-bot-api` for the latest 20 | version, or use `gopkg.in/telegram-bot-api.v4` for the stable build. 21 | 22 | Join [the development group](https://telegram.me/go_telegram_bot_api) if 23 | you want to ask questions or discuss development. 24 | 25 | ## Example 26 | 27 | This is a very simple bot that just displays any gotten updates, 28 | then replies it to that chat. 29 | 30 | ```go 31 | package main 32 | 33 | import ( 34 | "log" 35 | "gopkg.in/telegram-bot-api.v4" 36 | ) 37 | 38 | func main() { 39 | bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken") 40 | if err != nil { 41 | log.Panic(err) 42 | } 43 | 44 | bot.Debug = true 45 | 46 | log.Printf("Authorized on account %s", bot.Self.UserName) 47 | 48 | u := tgbotapi.NewUpdate(0) 49 | u.Timeout = 60 50 | 51 | updates, err := bot.GetUpdatesChan(u) 52 | 53 | for update := range updates { 54 | log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text) 55 | 56 | msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text) 57 | msg.ReplyToMessageID = update.Message.MessageID 58 | 59 | bot.Send(msg) 60 | } 61 | } 62 | ``` 63 | 64 | If you need to use webhooks (if you wish to run on Google App Engine), 65 | you may use a slightly different method. 66 | 67 | ```go 68 | package main 69 | 70 | import ( 71 | "gopkg.in/telegram-bot-api.v4" 72 | "log" 73 | "net/http" 74 | ) 75 | 76 | func main() { 77 | bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken") 78 | if err != nil { 79 | log.Fatal(err) 80 | } 81 | 82 | bot.Debug = true 83 | 84 | log.Printf("Authorized on account %s", bot.Self.UserName) 85 | 86 | _, err = bot.SetWebhook(tgbotapi.NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem")) 87 | if err != nil { 88 | log.Fatal(err) 89 | } 90 | 91 | updates := bot.ListenForWebhook("/" + bot.Token) 92 | go http.ListenAndServeTLS("0.0.0.0:8443", "cert.pem", "key.pem", nil) 93 | 94 | for update := range updates { 95 | log.Printf("%+v\n", update) 96 | } 97 | } 98 | ``` 99 | 100 | If you need, you may generate a self signed certficate, as this requires 101 | HTTPS / TLS. The above example tells Telegram that this is your 102 | certificate and that it should be trusted, even though it is not 103 | properly signed. 104 | 105 | openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 3560 -subj "//O=Org\CN=Test" -nodes 106 | 107 | Now that [Let's Encrypt](https://letsencrypt.org) has entered public beta, 108 | you may wish to generate your free TLS certificate there. 109 | -------------------------------------------------------------------------------- /vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go: -------------------------------------------------------------------------------- 1 | // Package tgbotapi has functions and types used for interacting with 2 | // the Telegram Bot API. 3 | package tgbotapi 4 | 5 | import ( 6 | "bytes" 7 | "encoding/json" 8 | "errors" 9 | "fmt" 10 | "github.com/technoweenie/multipartstreamer" 11 | "io/ioutil" 12 | "log" 13 | "net/http" 14 | "net/url" 15 | "os" 16 | "strconv" 17 | "strings" 18 | "time" 19 | ) 20 | 21 | // BotAPI allows you to interact with the Telegram Bot API. 22 | type BotAPI struct { 23 | Token string `json:"token"` 24 | Debug bool `json:"debug"` 25 | Self User `json:"-"` 26 | Client *http.Client `json:"-"` 27 | } 28 | 29 | // NewBotAPI creates a new BotAPI instance. 30 | // 31 | // It requires a token, provided by @BotFather on Telegram. 32 | func NewBotAPI(token string) (*BotAPI, error) { 33 | return NewBotAPIWithClient(token, &http.Client{}) 34 | } 35 | 36 | // NewBotAPIWithClient creates a new BotAPI instance 37 | // and allows you to pass a http.Client. 38 | // 39 | // It requires a token, provided by @BotFather on Telegram. 40 | func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) { 41 | bot := &BotAPI{ 42 | Token: token, 43 | Client: client, 44 | } 45 | 46 | self, err := bot.GetMe() 47 | if err != nil { 48 | return &BotAPI{}, err 49 | } 50 | 51 | bot.Self = self 52 | 53 | return bot, nil 54 | } 55 | 56 | // MakeRequest makes a request to a specific endpoint with our token. 57 | func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse, error) { 58 | method := fmt.Sprintf(APIEndpoint, bot.Token, endpoint) 59 | 60 | resp, err := bot.Client.PostForm(method, params) 61 | if err != nil { 62 | return APIResponse{}, err 63 | } 64 | defer resp.Body.Close() 65 | 66 | if resp.StatusCode == http.StatusForbidden { 67 | return APIResponse{}, errors.New(ErrAPIForbidden) 68 | } 69 | 70 | bytes, err := ioutil.ReadAll(resp.Body) 71 | if err != nil { 72 | return APIResponse{}, err 73 | } 74 | 75 | if bot.Debug { 76 | log.Println(endpoint, string(bytes)) 77 | } 78 | 79 | var apiResp APIResponse 80 | json.Unmarshal(bytes, &apiResp) 81 | 82 | if !apiResp.Ok { 83 | return APIResponse{}, errors.New(apiResp.Description) 84 | } 85 | 86 | return apiResp, nil 87 | } 88 | 89 | // makeMessageRequest makes a request to a method that returns a Message. 90 | func (bot *BotAPI) makeMessageRequest(endpoint string, params url.Values) (Message, error) { 91 | resp, err := bot.MakeRequest(endpoint, params) 92 | if err != nil { 93 | return Message{}, err 94 | } 95 | 96 | var message Message 97 | json.Unmarshal(resp.Result, &message) 98 | 99 | bot.debugLog(endpoint, params, message) 100 | 101 | return message, nil 102 | } 103 | 104 | // UploadFile makes a request to the API with a file. 105 | // 106 | // Requires the parameter to hold the file not be in the params. 107 | // File should be a string to a file path, a FileBytes struct, 108 | // or a FileReader struct. 109 | // 110 | // Note that if your FileReader has a size set to -1, it will read 111 | // the file into memory to calculate a size. 112 | func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldname string, file interface{}) (APIResponse, error) { 113 | ms := multipartstreamer.New() 114 | ms.WriteFields(params) 115 | 116 | switch f := file.(type) { 117 | case string: 118 | fileHandle, err := os.Open(f) 119 | if err != nil { 120 | return APIResponse{}, err 121 | } 122 | defer fileHandle.Close() 123 | 124 | fi, err := os.Stat(f) 125 | if err != nil { 126 | return APIResponse{}, err 127 | } 128 | 129 | ms.WriteReader(fieldname, fileHandle.Name(), fi.Size(), fileHandle) 130 | case FileBytes: 131 | buf := bytes.NewBuffer(f.Bytes) 132 | ms.WriteReader(fieldname, f.Name, int64(len(f.Bytes)), buf) 133 | case FileReader: 134 | if f.Size != -1 { 135 | ms.WriteReader(fieldname, f.Name, f.Size, f.Reader) 136 | 137 | break 138 | } 139 | 140 | data, err := ioutil.ReadAll(f.Reader) 141 | if err != nil { 142 | return APIResponse{}, err 143 | } 144 | 145 | buf := bytes.NewBuffer(data) 146 | 147 | ms.WriteReader(fieldname, f.Name, int64(len(data)), buf) 148 | default: 149 | return APIResponse{}, errors.New(ErrBadFileType) 150 | } 151 | 152 | method := fmt.Sprintf(APIEndpoint, bot.Token, endpoint) 153 | 154 | req, err := http.NewRequest("POST", method, nil) 155 | if err != nil { 156 | return APIResponse{}, err 157 | } 158 | 159 | ms.SetupRequest(req) 160 | 161 | res, err := bot.Client.Do(req) 162 | if err != nil { 163 | return APIResponse{}, err 164 | } 165 | defer res.Body.Close() 166 | 167 | bytes, err := ioutil.ReadAll(res.Body) 168 | if err != nil { 169 | return APIResponse{}, err 170 | } 171 | 172 | if bot.Debug { 173 | log.Println(string(bytes)) 174 | } 175 | 176 | var apiResp APIResponse 177 | json.Unmarshal(bytes, &apiResp) 178 | 179 | if !apiResp.Ok { 180 | return APIResponse{}, errors.New(apiResp.Description) 181 | } 182 | 183 | return apiResp, nil 184 | } 185 | 186 | // GetFileDirectURL returns direct URL to file 187 | // 188 | // It requires the FileID. 189 | func (bot *BotAPI) GetFileDirectURL(fileID string) (string, error) { 190 | file, err := bot.GetFile(FileConfig{fileID}) 191 | 192 | if err != nil { 193 | return "", err 194 | } 195 | 196 | return file.Link(bot.Token), nil 197 | } 198 | 199 | // GetMe fetches the currently authenticated bot. 200 | // 201 | // This method is called upon creation to validate the token, 202 | // and so you may get this data from BotAPI.Self without the need for 203 | // another request. 204 | func (bot *BotAPI) GetMe() (User, error) { 205 | resp, err := bot.MakeRequest("getMe", nil) 206 | if err != nil { 207 | return User{}, err 208 | } 209 | 210 | var user User 211 | json.Unmarshal(resp.Result, &user) 212 | 213 | bot.debugLog("getMe", nil, user) 214 | 215 | return user, nil 216 | } 217 | 218 | // IsMessageToMe returns true if message directed to this bot. 219 | // 220 | // It requires the Message. 221 | func (bot *BotAPI) IsMessageToMe(message Message) bool { 222 | return strings.Contains(message.Text, "@"+bot.Self.UserName) 223 | } 224 | 225 | // Send will send a Chattable item to Telegram. 226 | // 227 | // It requires the Chattable to send. 228 | func (bot *BotAPI) Send(c Chattable) (Message, error) { 229 | switch c.(type) { 230 | case Fileable: 231 | return bot.sendFile(c.(Fileable)) 232 | default: 233 | return bot.sendChattable(c) 234 | } 235 | } 236 | 237 | // debugLog checks if the bot is currently running in debug mode, and if 238 | // so will display information about the request and response in the 239 | // debug log. 240 | func (bot *BotAPI) debugLog(context string, v url.Values, message interface{}) { 241 | if bot.Debug { 242 | log.Printf("%s req : %+v\n", context, v) 243 | log.Printf("%s resp: %+v\n", context, message) 244 | } 245 | } 246 | 247 | // sendExisting will send a Message with an existing file to Telegram. 248 | func (bot *BotAPI) sendExisting(method string, config Fileable) (Message, error) { 249 | v, err := config.values() 250 | 251 | if err != nil { 252 | return Message{}, err 253 | } 254 | 255 | message, err := bot.makeMessageRequest(method, v) 256 | if err != nil { 257 | return Message{}, err 258 | } 259 | 260 | return message, nil 261 | } 262 | 263 | // uploadAndSend will send a Message with a new file to Telegram. 264 | func (bot *BotAPI) uploadAndSend(method string, config Fileable) (Message, error) { 265 | params, err := config.params() 266 | if err != nil { 267 | return Message{}, err 268 | } 269 | 270 | file := config.getFile() 271 | 272 | resp, err := bot.UploadFile(method, params, config.name(), file) 273 | if err != nil { 274 | return Message{}, err 275 | } 276 | 277 | var message Message 278 | json.Unmarshal(resp.Result, &message) 279 | 280 | bot.debugLog(method, nil, message) 281 | 282 | return message, nil 283 | } 284 | 285 | // sendFile determines if the file is using an existing file or uploading 286 | // a new file, then sends it as needed. 287 | func (bot *BotAPI) sendFile(config Fileable) (Message, error) { 288 | if config.useExistingFile() { 289 | return bot.sendExisting(config.method(), config) 290 | } 291 | 292 | return bot.uploadAndSend(config.method(), config) 293 | } 294 | 295 | // sendChattable sends a Chattable. 296 | func (bot *BotAPI) sendChattable(config Chattable) (Message, error) { 297 | v, err := config.values() 298 | if err != nil { 299 | return Message{}, err 300 | } 301 | 302 | message, err := bot.makeMessageRequest(config.method(), v) 303 | 304 | if err != nil { 305 | return Message{}, err 306 | } 307 | 308 | return message, nil 309 | } 310 | 311 | // GetUserProfilePhotos gets a user's profile photos. 312 | // 313 | // It requires UserID. 314 | // Offset and Limit are optional. 315 | func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) { 316 | v := url.Values{} 317 | v.Add("user_id", strconv.Itoa(config.UserID)) 318 | if config.Offset != 0 { 319 | v.Add("offset", strconv.Itoa(config.Offset)) 320 | } 321 | if config.Limit != 0 { 322 | v.Add("limit", strconv.Itoa(config.Limit)) 323 | } 324 | 325 | resp, err := bot.MakeRequest("getUserProfilePhotos", v) 326 | if err != nil { 327 | return UserProfilePhotos{}, err 328 | } 329 | 330 | var profilePhotos UserProfilePhotos 331 | json.Unmarshal(resp.Result, &profilePhotos) 332 | 333 | bot.debugLog("GetUserProfilePhoto", v, profilePhotos) 334 | 335 | return profilePhotos, nil 336 | } 337 | 338 | // GetFile returns a File which can download a file from Telegram. 339 | // 340 | // Requires FileID. 341 | func (bot *BotAPI) GetFile(config FileConfig) (File, error) { 342 | v := url.Values{} 343 | v.Add("file_id", config.FileID) 344 | 345 | resp, err := bot.MakeRequest("getFile", v) 346 | if err != nil { 347 | return File{}, err 348 | } 349 | 350 | var file File 351 | json.Unmarshal(resp.Result, &file) 352 | 353 | bot.debugLog("GetFile", v, file) 354 | 355 | return file, nil 356 | } 357 | 358 | // GetUpdates fetches updates. 359 | // If a WebHook is set, this will not return any data! 360 | // 361 | // Offset, Limit, and Timeout are optional. 362 | // To avoid stale items, set Offset to one higher than the previous item. 363 | // Set Timeout to a large number to reduce requests so you can get updates 364 | // instantly instead of having to wait between requests. 365 | func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) { 366 | v := url.Values{} 367 | if config.Offset > 0 { 368 | v.Add("offset", strconv.Itoa(config.Offset)) 369 | } 370 | if config.Limit > 0 { 371 | v.Add("limit", strconv.Itoa(config.Limit)) 372 | } 373 | if config.Timeout > 0 { 374 | v.Add("timeout", strconv.Itoa(config.Timeout)) 375 | } 376 | 377 | resp, err := bot.MakeRequest("getUpdates", v) 378 | if err != nil { 379 | return []Update{}, err 380 | } 381 | 382 | var updates []Update 383 | json.Unmarshal(resp.Result, &updates) 384 | 385 | bot.debugLog("getUpdates", v, updates) 386 | 387 | return updates, nil 388 | } 389 | 390 | // RemoveWebhook unsets the webhook. 391 | func (bot *BotAPI) RemoveWebhook() (APIResponse, error) { 392 | return bot.MakeRequest("setWebhook", url.Values{}) 393 | } 394 | 395 | // SetWebhook sets a webhook. 396 | // 397 | // If this is set, GetUpdates will not get any data! 398 | // 399 | // If you do not have a legitmate TLS certificate, you need to include 400 | // your self signed certificate with the config. 401 | func (bot *BotAPI) SetWebhook(config WebhookConfig) (APIResponse, error) { 402 | if config.Certificate == nil { 403 | v := url.Values{} 404 | v.Add("url", config.URL.String()) 405 | 406 | return bot.MakeRequest("setWebhook", v) 407 | } 408 | 409 | params := make(map[string]string) 410 | params["url"] = config.URL.String() 411 | 412 | resp, err := bot.UploadFile("setWebhook", params, "certificate", config.Certificate) 413 | if err != nil { 414 | return APIResponse{}, err 415 | } 416 | 417 | var apiResp APIResponse 418 | json.Unmarshal(resp.Result, &apiResp) 419 | 420 | if bot.Debug { 421 | log.Printf("setWebhook resp: %+v\n", apiResp) 422 | } 423 | 424 | return apiResp, nil 425 | } 426 | 427 | // GetUpdatesChan starts and returns a channel for getting updates. 428 | func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (<-chan Update, error) { 429 | updatesChan := make(chan Update, 100) 430 | 431 | go func() { 432 | for { 433 | updates, err := bot.GetUpdates(config) 434 | if err != nil { 435 | log.Println(err) 436 | log.Println("Failed to get updates, retrying in 3 seconds...") 437 | time.Sleep(time.Second * 3) 438 | 439 | continue 440 | } 441 | 442 | for _, update := range updates { 443 | if update.UpdateID >= config.Offset { 444 | config.Offset = update.UpdateID + 1 445 | updatesChan <- update 446 | } 447 | } 448 | } 449 | }() 450 | 451 | return updatesChan, nil 452 | } 453 | 454 | // ListenForWebhook registers a http handler for a webhook. 455 | func (bot *BotAPI) ListenForWebhook(pattern string) <-chan Update { 456 | updatesChan := make(chan Update, 100) 457 | 458 | http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) { 459 | bytes, _ := ioutil.ReadAll(r.Body) 460 | 461 | var update Update 462 | json.Unmarshal(bytes, &update) 463 | 464 | updatesChan <- update 465 | }) 466 | 467 | return updatesChan 468 | } 469 | 470 | // AnswerInlineQuery sends a response to an inline query. 471 | // 472 | // Note that you must respond to an inline query within 30 seconds. 473 | func (bot *BotAPI) AnswerInlineQuery(config InlineConfig) (APIResponse, error) { 474 | v := url.Values{} 475 | 476 | v.Add("inline_query_id", config.InlineQueryID) 477 | v.Add("cache_time", strconv.Itoa(config.CacheTime)) 478 | v.Add("is_personal", strconv.FormatBool(config.IsPersonal)) 479 | v.Add("next_offset", config.NextOffset) 480 | data, err := json.Marshal(config.Results) 481 | if err != nil { 482 | return APIResponse{}, err 483 | } 484 | v.Add("results", string(data)) 485 | v.Add("switch_pm_text", config.SwitchPMText) 486 | v.Add("switch_pm_parameter", config.SwitchPMParameter) 487 | 488 | bot.debugLog("answerInlineQuery", v, nil) 489 | 490 | return bot.MakeRequest("answerInlineQuery", v) 491 | } 492 | 493 | // AnswerCallbackQuery sends a response to an inline query callback. 494 | func (bot *BotAPI) AnswerCallbackQuery(config CallbackConfig) (APIResponse, error) { 495 | v := url.Values{} 496 | 497 | v.Add("callback_query_id", config.CallbackQueryID) 498 | v.Add("text", config.Text) 499 | v.Add("show_alert", strconv.FormatBool(config.ShowAlert)) 500 | 501 | bot.debugLog("answerCallbackQuery", v, nil) 502 | 503 | return bot.MakeRequest("answerCallbackQuery", v) 504 | } 505 | 506 | // KickChatMember kicks a user from a chat. Note that this only will work 507 | // in supergroups, and requires the bot to be an admin. Also note they 508 | // will be unable to rejoin until they are unbanned. 509 | func (bot *BotAPI) KickChatMember(config ChatMemberConfig) (APIResponse, error) { 510 | v := url.Values{} 511 | 512 | if config.SuperGroupUsername == "" { 513 | v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) 514 | } else { 515 | v.Add("chat_id", config.SuperGroupUsername) 516 | } 517 | v.Add("user_id", strconv.Itoa(config.UserID)) 518 | 519 | bot.debugLog("kickChatMember", v, nil) 520 | 521 | return bot.MakeRequest("kickChatMember", v) 522 | } 523 | 524 | // UnbanChatMember unbans a user from a chat. Note that this only will work 525 | // in supergroups, and requires the bot to be an admin. 526 | func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error) { 527 | v := url.Values{} 528 | 529 | if config.SuperGroupUsername == "" { 530 | v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) 531 | } else { 532 | v.Add("chat_id", config.SuperGroupUsername) 533 | } 534 | v.Add("user_id", strconv.Itoa(config.UserID)) 535 | 536 | bot.debugLog("unbanChatMember", v, nil) 537 | 538 | return bot.MakeRequest("unbanChatMember", v) 539 | } 540 | -------------------------------------------------------------------------------- /vendor/github.com/technoweenie/multipartstreamer/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-* rick olson 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /vendor/github.com/technoweenie/multipartstreamer/README.md: -------------------------------------------------------------------------------- 1 | # multipartstreamer 2 | 3 | Package multipartstreamer helps you encode large files in MIME multipart format 4 | without reading the entire content into memory. It uses io.MultiReader to 5 | combine an inner multipart.Reader with a file handle. 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "github.com/technoweenie/multipartstreamer.go" 12 | "net/http" 13 | ) 14 | 15 | func main() { 16 | ms := multipartstreamer.New() 17 | 18 | ms.WriteFields(map[string]string{ 19 | "key": "some-key", 20 | "AWSAccessKeyId": "ABCDEF", 21 | "acl": "some-acl", 22 | }) 23 | 24 | // Add any io.Reader to the multipart.Reader. 25 | ms.WriteReader("file", "filename", some_ioReader, size) 26 | 27 | // Shortcut for adding local file. 28 | ms.WriteFile("file", "path/to/file") 29 | 30 | req, _ := http.NewRequest("POST", "someurl", nil) 31 | ms.SetupRequest(req) 32 | 33 | res, _ := http.DefaultClient.Do(req) 34 | } 35 | ``` 36 | 37 | One limitation: You can only write a single file. 38 | 39 | ## TODO 40 | 41 | * Multiple files? 42 | 43 | ## Credits 44 | 45 | Heavily inspired by James 46 | 47 | https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/Zjg5l4nKcQ0 48 | -------------------------------------------------------------------------------- /vendor/github.com/technoweenie/multipartstreamer/multipartstreamer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package multipartstreamer helps you encode large files in MIME multipart format 3 | without reading the entire content into memory. It uses io.MultiReader to 4 | combine an inner multipart.Reader with a file handle. 5 | */ 6 | package multipartstreamer 7 | 8 | import ( 9 | "bytes" 10 | "fmt" 11 | "io" 12 | "io/ioutil" 13 | "mime/multipart" 14 | "net/http" 15 | "os" 16 | "path/filepath" 17 | ) 18 | 19 | type MultipartStreamer struct { 20 | ContentType string 21 | bodyBuffer *bytes.Buffer 22 | bodyWriter *multipart.Writer 23 | closeBuffer *bytes.Buffer 24 | reader io.Reader 25 | contentLength int64 26 | } 27 | 28 | // New initializes a new MultipartStreamer. 29 | func New() (m *MultipartStreamer) { 30 | m = &MultipartStreamer{bodyBuffer: new(bytes.Buffer)} 31 | 32 | m.bodyWriter = multipart.NewWriter(m.bodyBuffer) 33 | boundary := m.bodyWriter.Boundary() 34 | m.ContentType = "multipart/form-data; boundary=" + boundary 35 | 36 | closeBoundary := fmt.Sprintf("\r\n--%s--\r\n", boundary) 37 | m.closeBuffer = bytes.NewBufferString(closeBoundary) 38 | 39 | return 40 | } 41 | 42 | // WriteFields writes multiple form fields to the multipart.Writer. 43 | func (m *MultipartStreamer) WriteFields(fields map[string]string) error { 44 | var err error 45 | 46 | for key, value := range fields { 47 | err = m.bodyWriter.WriteField(key, value) 48 | if err != nil { 49 | return err 50 | } 51 | } 52 | 53 | return nil 54 | } 55 | 56 | // WriteReader adds an io.Reader to get the content of a file. The reader is 57 | // not accessed until the multipart.Reader is copied to some output writer. 58 | func (m *MultipartStreamer) WriteReader(key, filename string, size int64, reader io.Reader) (err error) { 59 | m.reader = reader 60 | m.contentLength = size 61 | 62 | _, err = m.bodyWriter.CreateFormFile(key, filename) 63 | return 64 | } 65 | 66 | // WriteFile is a shortcut for adding a local file as an io.Reader. 67 | func (m *MultipartStreamer) WriteFile(key, filename string) error { 68 | fh, err := os.Open(filename) 69 | if err != nil { 70 | return err 71 | } 72 | 73 | stat, err := fh.Stat() 74 | if err != nil { 75 | return err 76 | } 77 | 78 | return m.WriteReader(key, filepath.Base(filename), stat.Size(), fh) 79 | } 80 | 81 | // SetupRequest sets up the http.Request body, and some crucial HTTP headers. 82 | func (m *MultipartStreamer) SetupRequest(req *http.Request) { 83 | req.Body = m.GetReader() 84 | req.Header.Add("Content-Type", m.ContentType) 85 | req.ContentLength = m.Len() 86 | } 87 | 88 | func (m *MultipartStreamer) Boundary() string { 89 | return m.bodyWriter.Boundary() 90 | } 91 | 92 | // Len calculates the byte size of the multipart content. 93 | func (m *MultipartStreamer) Len() int64 { 94 | return m.contentLength + int64(m.bodyBuffer.Len()) + int64(m.closeBuffer.Len()) 95 | } 96 | 97 | // GetReader gets an io.ReadCloser for passing to an http.Request. 98 | func (m *MultipartStreamer) GetReader() io.ReadCloser { 99 | reader := io.MultiReader(m.bodyBuffer, m.reader, m.closeBuffer) 100 | return ioutil.NopCloser(reader) 101 | } 102 | -------------------------------------------------------------------------------- /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/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/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 | "time" 13 | ) 14 | 15 | // Client implements a traditional SSH client that supports shells, 16 | // subprocesses, port forwarding and tunneled dialing. 17 | type Client struct { 18 | Conn 19 | 20 | forwards forwardList // forwarded tcpip connections from the remote side 21 | mu sync.Mutex 22 | channelHandlers map[string]chan NewChannel 23 | } 24 | 25 | // HandleChannelOpen returns a channel on which NewChannel requests 26 | // for the given type are sent. If the type already is being handled, 27 | // nil is returned. The channel is closed when the connection is closed. 28 | func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel { 29 | c.mu.Lock() 30 | defer c.mu.Unlock() 31 | if c.channelHandlers == nil { 32 | // The SSH channel has been closed. 33 | c := make(chan NewChannel) 34 | close(c) 35 | return c 36 | } 37 | 38 | ch := c.channelHandlers[channelType] 39 | if ch != nil { 40 | return nil 41 | } 42 | 43 | ch = make(chan NewChannel, 16) 44 | c.channelHandlers[channelType] = ch 45 | return ch 46 | } 47 | 48 | // NewClient creates a Client on top of the given connection. 49 | func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client { 50 | conn := &Client{ 51 | Conn: c, 52 | channelHandlers: make(map[string]chan NewChannel, 1), 53 | } 54 | 55 | go conn.handleGlobalRequests(reqs) 56 | go conn.handleChannelOpens(chans) 57 | go func() { 58 | conn.Wait() 59 | conn.forwards.closeAll() 60 | }() 61 | go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip")) 62 | return conn 63 | } 64 | 65 | // NewClientConn establishes an authenticated SSH connection using c 66 | // as the underlying transport. The Request and NewChannel channels 67 | // must be serviced or the connection will hang. 68 | func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) { 69 | fullConf := *config 70 | fullConf.SetDefaults() 71 | conn := &connection{ 72 | sshConn: sshConn{conn: c}, 73 | } 74 | 75 | if err := conn.clientHandshake(addr, &fullConf); err != nil { 76 | c.Close() 77 | return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err) 78 | } 79 | conn.mux = newMux(conn.transport) 80 | return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil 81 | } 82 | 83 | // clientHandshake performs the client side key exchange. See RFC 4253 Section 84 | // 7. 85 | func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error { 86 | if config.ClientVersion != "" { 87 | c.clientVersion = []byte(config.ClientVersion) 88 | } else { 89 | c.clientVersion = []byte(packageVersion) 90 | } 91 | var err error 92 | c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion) 93 | if err != nil { 94 | return err 95 | } 96 | 97 | c.transport = newClientTransport( 98 | newTransport(c.sshConn.conn, config.Rand, true /* is client */), 99 | c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr()) 100 | if err := c.transport.requestInitialKeyChange(); err != nil { 101 | return err 102 | } 103 | 104 | if packet, err := c.transport.readPacket(); err != nil { 105 | return err 106 | } else if packet[0] != msgNewKeys { 107 | return unexpectedMessageError(msgNewKeys, packet[0]) 108 | } 109 | 110 | // We just did the key change, so the session ID is established. 111 | c.sessionID = c.transport.getSessionID() 112 | 113 | return c.clientAuthenticate(config) 114 | } 115 | 116 | // verifyHostKeySignature verifies the host key obtained in the key 117 | // exchange. 118 | func verifyHostKeySignature(hostKey PublicKey, result *kexResult) error { 119 | sig, rest, ok := parseSignatureBody(result.Signature) 120 | if len(rest) > 0 || !ok { 121 | return errors.New("ssh: signature parse error") 122 | } 123 | 124 | return hostKey.Verify(result.H, sig) 125 | } 126 | 127 | // NewSession opens a new Session for this client. (A session is a remote 128 | // execution of a program.) 129 | func (c *Client) NewSession() (*Session, error) { 130 | ch, in, err := c.OpenChannel("session", nil) 131 | if err != nil { 132 | return nil, err 133 | } 134 | return newSession(ch, in) 135 | } 136 | 137 | func (c *Client) handleGlobalRequests(incoming <-chan *Request) { 138 | for r := range incoming { 139 | // This handles keepalive messages and matches 140 | // the behaviour of OpenSSH. 141 | r.Reply(false, nil) 142 | } 143 | } 144 | 145 | // handleChannelOpens channel open messages from the remote side. 146 | func (c *Client) handleChannelOpens(in <-chan NewChannel) { 147 | for ch := range in { 148 | c.mu.Lock() 149 | handler := c.channelHandlers[ch.ChannelType()] 150 | c.mu.Unlock() 151 | 152 | if handler != nil { 153 | handler <- ch 154 | } else { 155 | ch.Reject(UnknownChannelType, fmt.Sprintf("unknown channel type: %v", ch.ChannelType())) 156 | } 157 | } 158 | 159 | c.mu.Lock() 160 | for _, ch := range c.channelHandlers { 161 | close(ch) 162 | } 163 | c.channelHandlers = nil 164 | c.mu.Unlock() 165 | } 166 | 167 | // Dial starts a client connection to the given SSH server. It is a 168 | // convenience function that connects to the given network address, 169 | // initiates the SSH handshake, and then sets up a Client. For access 170 | // to incoming channels and requests, use net.Dial with NewClientConn 171 | // instead. 172 | func Dial(network, addr string, config *ClientConfig) (*Client, error) { 173 | conn, err := net.DialTimeout(network, addr, config.Timeout) 174 | if err != nil { 175 | return nil, err 176 | } 177 | c, chans, reqs, err := NewClientConn(conn, addr, config) 178 | if err != nil { 179 | return nil, err 180 | } 181 | return NewClient(c, chans, reqs), nil 182 | } 183 | 184 | // A ClientConfig structure is used to configure a Client. It must not be 185 | // modified after having been passed to an SSH function. 186 | type ClientConfig struct { 187 | // Config contains configuration that is shared between clients and 188 | // servers. 189 | Config 190 | 191 | // User contains the username to authenticate as. 192 | User string 193 | 194 | // Auth contains possible authentication methods to use with the 195 | // server. Only the first instance of a particular RFC 4252 method will 196 | // be used during authentication. 197 | Auth []AuthMethod 198 | 199 | // HostKeyCallback, if not nil, is called during the cryptographic 200 | // handshake to validate the server's host key. A nil HostKeyCallback 201 | // implies that all host keys are accepted. 202 | HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error 203 | 204 | // ClientVersion contains the version identification string that will 205 | // be used for the connection. If empty, a reasonable default is used. 206 | ClientVersion string 207 | 208 | // HostKeyAlgorithms lists the key types that the client will 209 | // accept from the server as host key, in order of 210 | // preference. If empty, a reasonable default is used. Any 211 | // string returned from PublicKey.Type method may be used, or 212 | // any of the CertAlgoXxxx and KeyAlgoXxxx constants. 213 | HostKeyAlgorithms []string 214 | 215 | // Timeout is the maximum amount of time for the TCP connection to establish. 216 | // 217 | // A Timeout of zero means no timeout. 218 | Timeout time.Duration 219 | } 220 | -------------------------------------------------------------------------------- /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 | default: 325 | return false, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0]) 326 | } 327 | } 328 | } 329 | 330 | // KeyboardInteractiveChallenge should print questions, optionally 331 | // disabling echoing (e.g. for passwords), and return all the answers. 332 | // Challenge may be called multiple times in a single session. After 333 | // successful authentication, the server may send a challenge with no 334 | // questions, for which the user and instruction messages should be 335 | // printed. RFC 4256 section 3.3 details how the UI should behave for 336 | // both CLI and GUI environments. 337 | type KeyboardInteractiveChallenge func(user, instruction string, questions []string, echos []bool) (answers []string, err error) 338 | 339 | // KeyboardInteractive returns a AuthMethod using a prompt/response 340 | // sequence controlled by the server. 341 | func KeyboardInteractive(challenge KeyboardInteractiveChallenge) AuthMethod { 342 | return challenge 343 | } 344 | 345 | func (cb KeyboardInteractiveChallenge) method() string { 346 | return "keyboard-interactive" 347 | } 348 | 349 | func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { 350 | type initiateMsg struct { 351 | User string `sshtype:"50"` 352 | Service string 353 | Method string 354 | Language string 355 | Submethods string 356 | } 357 | 358 | if err := c.writePacket(Marshal(&initiateMsg{ 359 | User: user, 360 | Service: serviceSSH, 361 | Method: "keyboard-interactive", 362 | })); err != nil { 363 | return false, nil, err 364 | } 365 | 366 | for { 367 | packet, err := c.readPacket() 368 | if err != nil { 369 | return false, nil, err 370 | } 371 | 372 | // like handleAuthResponse, but with less options. 373 | switch packet[0] { 374 | case msgUserAuthBanner: 375 | // TODO: Print banners during userauth. 376 | continue 377 | case msgUserAuthInfoRequest: 378 | // OK 379 | case msgUserAuthFailure: 380 | var msg userAuthFailureMsg 381 | if err := Unmarshal(packet, &msg); err != nil { 382 | return false, nil, err 383 | } 384 | return false, msg.Methods, nil 385 | case msgUserAuthSuccess: 386 | return true, nil, nil 387 | default: 388 | return false, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0]) 389 | } 390 | 391 | var msg userAuthInfoRequestMsg 392 | if err := Unmarshal(packet, &msg); err != nil { 393 | return false, nil, err 394 | } 395 | 396 | // Manually unpack the prompt/echo pairs. 397 | rest := msg.Prompts 398 | var prompts []string 399 | var echos []bool 400 | for i := 0; i < int(msg.NumPrompts); i++ { 401 | prompt, r, ok := parseString(rest) 402 | if !ok || len(r) == 0 { 403 | return false, nil, errors.New("ssh: prompt format error") 404 | } 405 | prompts = append(prompts, string(prompt)) 406 | echos = append(echos, r[0] != 0) 407 | rest = r[1:] 408 | } 409 | 410 | if len(rest) != 0 { 411 | return false, nil, errors.New("ssh: extra data following keyboard-interactive pairs") 412 | } 413 | 414 | answers, err := cb(msg.User, msg.Instruction, prompts, echos) 415 | if err != nil { 416 | return false, nil, err 417 | } 418 | 419 | if len(answers) != len(prompts) { 420 | return false, nil, errors.New("ssh: not enough answers from keyboard-interactive callback") 421 | } 422 | responseLength := 1 + 4 423 | for _, a := range answers { 424 | responseLength += stringLength(len(a)) 425 | } 426 | serialized := make([]byte, responseLength) 427 | p := serialized 428 | p[0] = msgUserAuthInfoResponse 429 | p = p[1:] 430 | p = marshalUint32(p, uint32(len(answers))) 431 | for _, a := range answers { 432 | p = marshalString(p, []byte(a)) 433 | } 434 | 435 | if err := c.writePacket(serialized); err != nil { 436 | return false, nil, err 437 | } 438 | } 439 | } 440 | -------------------------------------------------------------------------------- /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 | 34 | // handshakeTransport implements rekeying on top of a keyingTransport 35 | // and offers a thread-safe writePacket() interface. 36 | type handshakeTransport struct { 37 | conn keyingTransport 38 | config *Config 39 | 40 | serverVersion []byte 41 | clientVersion []byte 42 | 43 | // hostKeys is non-empty if we are the server. In that case, 44 | // it contains all host keys that can be used to sign the 45 | // connection. 46 | hostKeys []Signer 47 | 48 | // hostKeyAlgorithms is non-empty if we are the client. In that case, 49 | // we accept these key types from the server as host key. 50 | hostKeyAlgorithms []string 51 | 52 | // On read error, incoming is closed, and readError is set. 53 | incoming chan []byte 54 | readError error 55 | 56 | // data for host key checking 57 | hostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error 58 | dialAddress string 59 | remoteAddr net.Addr 60 | 61 | readSinceKex uint64 62 | 63 | // Protects the writing side of the connection 64 | mu sync.Mutex 65 | cond *sync.Cond 66 | sentInitPacket []byte 67 | sentInitMsg *kexInitMsg 68 | writtenSinceKex uint64 69 | writeError error 70 | 71 | // The session ID or nil if first kex did not complete yet. 72 | sessionID []byte 73 | } 74 | 75 | func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport { 76 | t := &handshakeTransport{ 77 | conn: conn, 78 | serverVersion: serverVersion, 79 | clientVersion: clientVersion, 80 | incoming: make(chan []byte, 16), 81 | config: config, 82 | } 83 | t.cond = sync.NewCond(&t.mu) 84 | return t 85 | } 86 | 87 | func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ClientConfig, dialAddr string, addr net.Addr) *handshakeTransport { 88 | t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) 89 | t.dialAddress = dialAddr 90 | t.remoteAddr = addr 91 | t.hostKeyCallback = config.HostKeyCallback 92 | if config.HostKeyAlgorithms != nil { 93 | t.hostKeyAlgorithms = config.HostKeyAlgorithms 94 | } else { 95 | t.hostKeyAlgorithms = supportedHostKeyAlgos 96 | } 97 | go t.readLoop() 98 | return t 99 | } 100 | 101 | func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport { 102 | t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) 103 | t.hostKeys = config.hostKeys 104 | go t.readLoop() 105 | return t 106 | } 107 | 108 | func (t *handshakeTransport) getSessionID() []byte { 109 | return t.sessionID 110 | } 111 | 112 | func (t *handshakeTransport) id() string { 113 | if len(t.hostKeys) > 0 { 114 | return "server" 115 | } 116 | return "client" 117 | } 118 | 119 | func (t *handshakeTransport) readPacket() ([]byte, error) { 120 | p, ok := <-t.incoming 121 | if !ok { 122 | return nil, t.readError 123 | } 124 | return p, nil 125 | } 126 | 127 | func (t *handshakeTransport) readLoop() { 128 | for { 129 | p, err := t.readOnePacket() 130 | if err != nil { 131 | t.readError = err 132 | close(t.incoming) 133 | break 134 | } 135 | if p[0] == msgIgnore || p[0] == msgDebug { 136 | continue 137 | } 138 | t.incoming <- p 139 | } 140 | 141 | // If we can't read, declare the writing part dead too. 142 | t.mu.Lock() 143 | defer t.mu.Unlock() 144 | if t.writeError == nil { 145 | t.writeError = t.readError 146 | } 147 | t.cond.Broadcast() 148 | } 149 | 150 | func (t *handshakeTransport) readOnePacket() ([]byte, error) { 151 | if t.readSinceKex > t.config.RekeyThreshold { 152 | if err := t.requestKeyChange(); err != nil { 153 | return nil, err 154 | } 155 | } 156 | 157 | p, err := t.conn.readPacket() 158 | if err != nil { 159 | return nil, err 160 | } 161 | 162 | t.readSinceKex += uint64(len(p)) 163 | if debugHandshake { 164 | msg, err := decode(p) 165 | log.Printf("%s got %T %v (%v)", t.id(), msg, msg, err) 166 | } 167 | if p[0] != msgKexInit { 168 | return p, nil 169 | } 170 | 171 | t.mu.Lock() 172 | err = t.enterKeyExchangeLocked(p) 173 | if err != nil { 174 | // drop connection 175 | t.conn.Close() 176 | t.writeError = err 177 | } 178 | 179 | if debugHandshake { 180 | log.Printf("%s exited key exchange, err %v", t.id(), err) 181 | } 182 | 183 | // Unblock writers. 184 | t.sentInitMsg = nil 185 | t.sentInitPacket = nil 186 | t.cond.Broadcast() 187 | t.writtenSinceKex = 0 188 | t.mu.Unlock() 189 | 190 | if err != nil { 191 | return nil, err 192 | } 193 | 194 | t.readSinceKex = 0 195 | return []byte{msgNewKeys}, nil 196 | } 197 | 198 | // keyChangeCategory describes whether a key exchange is the first on a 199 | // connection, or a subsequent one. 200 | type keyChangeCategory bool 201 | 202 | const ( 203 | firstKeyExchange keyChangeCategory = true 204 | subsequentKeyExchange keyChangeCategory = false 205 | ) 206 | 207 | // sendKexInit sends a key change message, and returns the message 208 | // that was sent. After initiating the key change, all writes will be 209 | // blocked until the change is done, and a failed key change will 210 | // close the underlying transport. This function is safe for 211 | // concurrent use by multiple goroutines. 212 | func (t *handshakeTransport) sendKexInit(isFirst keyChangeCategory) (*kexInitMsg, []byte, error) { 213 | t.mu.Lock() 214 | defer t.mu.Unlock() 215 | return t.sendKexInitLocked(isFirst) 216 | } 217 | 218 | func (t *handshakeTransport) requestInitialKeyChange() error { 219 | _, _, err := t.sendKexInit(firstKeyExchange) 220 | return err 221 | } 222 | 223 | func (t *handshakeTransport) requestKeyChange() error { 224 | _, _, err := t.sendKexInit(subsequentKeyExchange) 225 | return err 226 | } 227 | 228 | // sendKexInitLocked sends a key change message. t.mu must be locked 229 | // while this happens. 230 | func (t *handshakeTransport) sendKexInitLocked(isFirst keyChangeCategory) (*kexInitMsg, []byte, error) { 231 | // kexInits may be sent either in response to the other side, 232 | // or because our side wants to initiate a key change, so we 233 | // may have already sent a kexInit. In that case, don't send a 234 | // second kexInit. 235 | if t.sentInitMsg != nil { 236 | return t.sentInitMsg, t.sentInitPacket, nil 237 | } 238 | 239 | // If this is the initial key change, but we already have a sessionID, 240 | // then do nothing because the key exchange has already completed 241 | // asynchronously. 242 | if isFirst && t.sessionID != nil { 243 | return nil, nil, nil 244 | } 245 | 246 | msg := &kexInitMsg{ 247 | KexAlgos: t.config.KeyExchanges, 248 | CiphersClientServer: t.config.Ciphers, 249 | CiphersServerClient: t.config.Ciphers, 250 | MACsClientServer: t.config.MACs, 251 | MACsServerClient: t.config.MACs, 252 | CompressionClientServer: supportedCompressions, 253 | CompressionServerClient: supportedCompressions, 254 | } 255 | io.ReadFull(rand.Reader, msg.Cookie[:]) 256 | 257 | if len(t.hostKeys) > 0 { 258 | for _, k := range t.hostKeys { 259 | msg.ServerHostKeyAlgos = append( 260 | msg.ServerHostKeyAlgos, k.PublicKey().Type()) 261 | } 262 | } else { 263 | msg.ServerHostKeyAlgos = t.hostKeyAlgorithms 264 | } 265 | packet := Marshal(msg) 266 | 267 | // writePacket destroys the contents, so save a copy. 268 | packetCopy := make([]byte, len(packet)) 269 | copy(packetCopy, packet) 270 | 271 | if err := t.conn.writePacket(packetCopy); err != nil { 272 | return nil, nil, err 273 | } 274 | 275 | t.sentInitMsg = msg 276 | t.sentInitPacket = packet 277 | return msg, packet, nil 278 | } 279 | 280 | func (t *handshakeTransport) writePacket(p []byte) error { 281 | t.mu.Lock() 282 | defer t.mu.Unlock() 283 | 284 | if t.writtenSinceKex > t.config.RekeyThreshold { 285 | t.sendKexInitLocked(subsequentKeyExchange) 286 | } 287 | for t.sentInitMsg != nil && t.writeError == nil { 288 | t.cond.Wait() 289 | } 290 | if t.writeError != nil { 291 | return t.writeError 292 | } 293 | t.writtenSinceKex += uint64(len(p)) 294 | 295 | switch p[0] { 296 | case msgKexInit: 297 | return errors.New("ssh: only handshakeTransport can send kexInit") 298 | case msgNewKeys: 299 | return errors.New("ssh: only handshakeTransport can send newKeys") 300 | default: 301 | return t.conn.writePacket(p) 302 | } 303 | } 304 | 305 | func (t *handshakeTransport) Close() error { 306 | return t.conn.Close() 307 | } 308 | 309 | // enterKeyExchange runs the key exchange. t.mu must be held while running this. 310 | func (t *handshakeTransport) enterKeyExchangeLocked(otherInitPacket []byte) error { 311 | if debugHandshake { 312 | log.Printf("%s entered key exchange", t.id()) 313 | } 314 | myInit, myInitPacket, err := t.sendKexInitLocked(subsequentKeyExchange) 315 | if err != nil { 316 | return err 317 | } 318 | 319 | otherInit := &kexInitMsg{} 320 | if err := Unmarshal(otherInitPacket, otherInit); err != nil { 321 | return err 322 | } 323 | 324 | magics := handshakeMagics{ 325 | clientVersion: t.clientVersion, 326 | serverVersion: t.serverVersion, 327 | clientKexInit: otherInitPacket, 328 | serverKexInit: myInitPacket, 329 | } 330 | 331 | clientInit := otherInit 332 | serverInit := myInit 333 | if len(t.hostKeys) == 0 { 334 | clientInit = myInit 335 | serverInit = otherInit 336 | 337 | magics.clientKexInit = myInitPacket 338 | magics.serverKexInit = otherInitPacket 339 | } 340 | 341 | algs, err := findAgreedAlgorithms(clientInit, serverInit) 342 | if err != nil { 343 | return err 344 | } 345 | 346 | // We don't send FirstKexFollows, but we handle receiving it. 347 | if otherInit.FirstKexFollows && algs.kex != otherInit.KexAlgos[0] { 348 | // other side sent a kex message for the wrong algorithm, 349 | // which we have to ignore. 350 | if _, err := t.conn.readPacket(); err != nil { 351 | return err 352 | } 353 | } 354 | 355 | kex, ok := kexAlgoMap[algs.kex] 356 | if !ok { 357 | return fmt.Errorf("ssh: unexpected key exchange algorithm %v", algs.kex) 358 | } 359 | 360 | var result *kexResult 361 | if len(t.hostKeys) > 0 { 362 | result, err = t.server(kex, algs, &magics) 363 | } else { 364 | result, err = t.client(kex, algs, &magics) 365 | } 366 | 367 | if err != nil { 368 | return err 369 | } 370 | 371 | if t.sessionID == nil { 372 | t.sessionID = result.H 373 | result.SessionID = result.H 374 | } 375 | 376 | t.conn.prepareKeyChange(algs, result) 377 | if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil { 378 | return err 379 | } 380 | if packet, err := t.conn.readPacket(); err != nil { 381 | return err 382 | } else if packet[0] != msgNewKeys { 383 | return unexpectedMessageError(msgNewKeys, packet[0]) 384 | } 385 | 386 | return nil 387 | } 388 | 389 | func (t *handshakeTransport) server(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { 390 | var hostKey Signer 391 | for _, k := range t.hostKeys { 392 | if algs.hostKey == k.PublicKey().Type() { 393 | hostKey = k 394 | } 395 | } 396 | 397 | r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey) 398 | return r, err 399 | } 400 | 401 | func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { 402 | result, err := kex.Client(t.conn, t.config.Rand, magics) 403 | if err != nil { 404 | return nil, err 405 | } 406 | 407 | hostKey, err := ParsePublicKey(result.HostKey) 408 | if err != nil { 409 | return nil, err 410 | } 411 | 412 | if err := verifyHostKeySignature(hostKey, result); err != nil { 413 | return nil, err 414 | } 415 | 416 | if t.hostKeyCallback != nil { 417 | err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey) 418 | if err != nil { 419 | return nil, err 420 | } 421 | } 422 | 423 | return result, nil 424 | } 425 | -------------------------------------------------------------------------------- /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/rand" 12 | "crypto/subtle" 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 derive key material inside the 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 | func (m *mux) Close() error { 179 | return m.conn.Close() 180 | } 181 | 182 | // loop runs the connection machine. It will process packets until an 183 | // error is encountered. To synchronize on loop exit, use mux.Wait. 184 | func (m *mux) loop() { 185 | var err error 186 | for err == nil { 187 | err = m.onePacket() 188 | } 189 | 190 | for _, ch := range m.chanList.dropAll() { 191 | ch.close() 192 | } 193 | 194 | close(m.incomingChannels) 195 | close(m.incomingRequests) 196 | close(m.globalResponses) 197 | 198 | m.conn.Close() 199 | 200 | m.errCond.L.Lock() 201 | m.err = err 202 | m.errCond.Broadcast() 203 | m.errCond.L.Unlock() 204 | 205 | if debugMux { 206 | log.Println("loop exit", err) 207 | } 208 | } 209 | 210 | // onePacket reads and processes one packet. 211 | func (m *mux) onePacket() error { 212 | packet, err := m.conn.readPacket() 213 | if err != nil { 214 | return err 215 | } 216 | 217 | if debugMux { 218 | if packet[0] == msgChannelData || packet[0] == msgChannelExtendedData { 219 | log.Printf("decoding(%d): data packet - %d bytes", m.chanList.offset, len(packet)) 220 | } else { 221 | p, _ := decode(packet) 222 | log.Printf("decoding(%d): %d %#v - %d bytes", m.chanList.offset, packet[0], p, len(packet)) 223 | } 224 | } 225 | 226 | switch packet[0] { 227 | case msgNewKeys: 228 | // Ignore notification of key change. 229 | return nil 230 | case msgChannelOpen: 231 | return m.handleChannelOpen(packet) 232 | case msgGlobalRequest, msgRequestSuccess, msgRequestFailure: 233 | return m.handleGlobalPacket(packet) 234 | } 235 | 236 | // assume a channel packet. 237 | if len(packet) < 5 { 238 | return parseError(packet[0]) 239 | } 240 | id := binary.BigEndian.Uint32(packet[1:]) 241 | ch := m.chanList.getChan(id) 242 | if ch == nil { 243 | return fmt.Errorf("ssh: invalid channel %d", id) 244 | } 245 | 246 | return ch.handlePacket(packet) 247 | } 248 | 249 | func (m *mux) handleGlobalPacket(packet []byte) error { 250 | msg, err := decode(packet) 251 | if err != nil { 252 | return err 253 | } 254 | 255 | switch msg := msg.(type) { 256 | case *globalRequestMsg: 257 | m.incomingRequests <- &Request{ 258 | Type: msg.Type, 259 | WantReply: msg.WantReply, 260 | Payload: msg.Data, 261 | mux: m, 262 | } 263 | case *globalRequestSuccessMsg, *globalRequestFailureMsg: 264 | m.globalResponses <- msg 265 | default: 266 | panic(fmt.Sprintf("not a global message %#v", msg)) 267 | } 268 | 269 | return nil 270 | } 271 | 272 | // handleChannelOpen schedules a channel to be Accept()ed. 273 | func (m *mux) handleChannelOpen(packet []byte) error { 274 | var msg channelOpenMsg 275 | if err := Unmarshal(packet, &msg); err != nil { 276 | return err 277 | } 278 | 279 | if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { 280 | failMsg := channelOpenFailureMsg{ 281 | PeersId: msg.PeersId, 282 | Reason: ConnectionFailed, 283 | Message: "invalid request", 284 | Language: "en_US.UTF-8", 285 | } 286 | return m.sendMessage(failMsg) 287 | } 288 | 289 | c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData) 290 | c.remoteId = msg.PeersId 291 | c.maxRemotePayload = msg.MaxPacketSize 292 | c.remoteWin.add(msg.PeersWindow) 293 | m.incomingChannels <- c 294 | return nil 295 | } 296 | 297 | func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Request, error) { 298 | ch, err := m.openChannel(chanType, extra) 299 | if err != nil { 300 | return nil, nil, err 301 | } 302 | 303 | return ch, ch.incomingRequests, nil 304 | } 305 | 306 | func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) { 307 | ch := m.newChannel(chanType, channelOutbound, extra) 308 | 309 | ch.maxIncomingPayload = channelMaxPacket 310 | 311 | open := channelOpenMsg{ 312 | ChanType: chanType, 313 | PeersWindow: ch.myWindow, 314 | MaxPacketSize: ch.maxIncomingPayload, 315 | TypeSpecificData: extra, 316 | PeersId: ch.localId, 317 | } 318 | if err := m.sendMessage(open); err != nil { 319 | return nil, err 320 | } 321 | 322 | switch msg := (<-ch.msg).(type) { 323 | case *channelOpenConfirmMsg: 324 | return ch, nil 325 | case *channelOpenFailureMsg: 326 | return nil, &OpenChannelError{msg.Reason, msg.Message} 327 | default: 328 | return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg) 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /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.requestInitialKeyChange(); 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/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/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 | 44 | // packetCipher represents a combination of SSH encryption/MAC 45 | // protocol. A single instance should be used for one direction only. 46 | type packetCipher interface { 47 | // writePacket encrypts the packet and writes it to w. The 48 | // contents of the packet are generally scrambled. 49 | writePacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error 50 | 51 | // readPacket reads and decrypts a packet of data. The 52 | // returned packet may be overwritten by future calls of 53 | // readPacket. 54 | readPacket(seqnum uint32, r io.Reader) ([]byte, error) 55 | } 56 | 57 | // connectionState represents one side (read or write) of the 58 | // connection. This is necessary because each direction has its own 59 | // keys, and can even have its own algorithms 60 | type connectionState struct { 61 | packetCipher 62 | seqNum uint32 63 | dir direction 64 | pendingKeyChange chan packetCipher 65 | } 66 | 67 | // prepareKeyChange sets up key material for a keychange. The key changes in 68 | // both directions are triggered by reading and writing a msgNewKey packet 69 | // respectively. 70 | func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) error { 71 | if ciph, err := newPacketCipher(t.reader.dir, algs.r, kexResult); err != nil { 72 | return err 73 | } else { 74 | t.reader.pendingKeyChange <- ciph 75 | } 76 | 77 | if ciph, err := newPacketCipher(t.writer.dir, algs.w, kexResult); err != nil { 78 | return err 79 | } else { 80 | t.writer.pendingKeyChange <- ciph 81 | } 82 | 83 | return nil 84 | } 85 | 86 | // Read and decrypt next packet. 87 | func (t *transport) readPacket() ([]byte, error) { 88 | return t.reader.readPacket(t.bufReader) 89 | } 90 | 91 | func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { 92 | packet, err := s.packetCipher.readPacket(s.seqNum, r) 93 | s.seqNum++ 94 | if err == nil && len(packet) == 0 { 95 | err = errors.New("ssh: zero length packet") 96 | } 97 | 98 | if len(packet) > 0 { 99 | switch packet[0] { 100 | case msgNewKeys: 101 | select { 102 | case cipher := <-s.pendingKeyChange: 103 | s.packetCipher = cipher 104 | default: 105 | return nil, errors.New("ssh: got bogus newkeys message.") 106 | } 107 | 108 | case msgDisconnect: 109 | // Transform a disconnect message into an 110 | // error. Since this is lowest level at which 111 | // we interpret message types, doing it here 112 | // ensures that we don't have to handle it 113 | // elsewhere. 114 | var msg disconnectMsg 115 | if err := Unmarshal(packet, &msg); err != nil { 116 | return nil, err 117 | } 118 | return nil, &msg 119 | } 120 | } 121 | 122 | // The packet may point to an internal buffer, so copy the 123 | // packet out here. 124 | fresh := make([]byte, len(packet)) 125 | copy(fresh, packet) 126 | 127 | return fresh, err 128 | } 129 | 130 | func (t *transport) writePacket(packet []byte) error { 131 | return t.writer.writePacket(t.bufWriter, t.rand, packet) 132 | } 133 | 134 | func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error { 135 | changeKeys := len(packet) > 0 && packet[0] == msgNewKeys 136 | 137 | err := s.packetCipher.writePacket(s.seqNum, w, rand, packet) 138 | if err != nil { 139 | return err 140 | } 141 | if err = w.Flush(); err != nil { 142 | return err 143 | } 144 | s.seqNum++ 145 | if changeKeys { 146 | select { 147 | case cipher := <-s.pendingKeyChange: 148 | s.packetCipher = cipher 149 | default: 150 | panic("ssh: no key material for msgNewKeys") 151 | } 152 | } 153 | return err 154 | } 155 | 156 | func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transport { 157 | t := &transport{ 158 | bufReader: bufio.NewReader(rwc), 159 | bufWriter: bufio.NewWriter(rwc), 160 | rand: rand, 161 | reader: connectionState{ 162 | packetCipher: &streamPacketCipher{cipher: noneCipher{}}, 163 | pendingKeyChange: make(chan packetCipher, 1), 164 | }, 165 | writer: connectionState{ 166 | packetCipher: &streamPacketCipher{cipher: noneCipher{}}, 167 | pendingKeyChange: make(chan packetCipher, 1), 168 | }, 169 | Closer: rwc, 170 | } 171 | if isClient { 172 | t.reader.dir = serverKeys 173 | t.writer.dir = clientKeys 174 | } else { 175 | t.reader.dir = clientKeys 176 | t.writer.dir = serverKeys 177 | } 178 | 179 | return t 180 | } 181 | 182 | type direction struct { 183 | ivTag []byte 184 | keyTag []byte 185 | macKeyTag []byte 186 | } 187 | 188 | var ( 189 | serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}} 190 | clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}} 191 | ) 192 | 193 | // generateKeys generates key material for IV, MAC and encryption. 194 | func generateKeys(d direction, algs directionAlgorithms, kex *kexResult) (iv, key, macKey []byte) { 195 | cipherMode := cipherModes[algs.Cipher] 196 | macMode := macModes[algs.MAC] 197 | 198 | iv = make([]byte, cipherMode.ivSize) 199 | key = make([]byte, cipherMode.keySize) 200 | macKey = make([]byte, macMode.keySize) 201 | 202 | generateKeyMaterial(iv, d.ivTag, kex) 203 | generateKeyMaterial(key, d.keyTag, kex) 204 | generateKeyMaterial(macKey, d.macKeyTag, kex) 205 | return 206 | } 207 | 208 | // setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as 209 | // described in RFC 4253, section 6.4. direction should either be serverKeys 210 | // (to setup server->client keys) or clientKeys (for client->server keys). 211 | func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) { 212 | iv, key, macKey := generateKeys(d, algs, kex) 213 | 214 | if algs.Cipher == gcmCipherID { 215 | return newGCMCipher(iv, key, macKey) 216 | } 217 | 218 | if algs.Cipher == aes128cbcID { 219 | return newAESCBCCipher(iv, key, macKey, algs) 220 | } 221 | 222 | c := &streamPacketCipher{ 223 | mac: macModes[algs.MAC].new(macKey), 224 | } 225 | c.macResult = make([]byte, c.mac.Size()) 226 | 227 | var err error 228 | c.cipher, err = cipherModes[algs.Cipher].createStream(key, iv) 229 | if err != nil { 230 | return nil, err 231 | } 232 | 233 | return c, nil 234 | } 235 | 236 | // generateKeyMaterial fills out with key material generated from tag, K, H 237 | // and sessionId, as specified in RFC 4253, section 7.2. 238 | func generateKeyMaterial(out, tag []byte, r *kexResult) { 239 | var digestsSoFar []byte 240 | 241 | h := r.Hash.New() 242 | for len(out) > 0 { 243 | h.Reset() 244 | h.Write(r.K) 245 | h.Write(r.H) 246 | 247 | if len(digestsSoFar) == 0 { 248 | h.Write(tag) 249 | h.Write(r.SessionID) 250 | } else { 251 | h.Write(digestsSoFar) 252 | } 253 | 254 | digest := h.Sum(nil) 255 | n := copy(out, digest) 256 | out = out[n:] 257 | if len(out) > 0 { 258 | digestsSoFar = append(digestsSoFar, digest...) 259 | } 260 | } 261 | } 262 | 263 | const packageVersion = "SSH-2.0-Go" 264 | 265 | // Sends and receives a version line. The versionLine string should 266 | // be US ASCII, start with "SSH-2.0-", and should not include a 267 | // newline. exchangeVersions returns the other side's version line. 268 | func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err error) { 269 | // Contrary to the RFC, we do not ignore lines that don't 270 | // start with "SSH-2.0-" to make the library usable with 271 | // nonconforming servers. 272 | for _, c := range versionLine { 273 | // The spec disallows non US-ASCII chars, and 274 | // specifically forbids null chars. 275 | if c < 32 { 276 | return nil, errors.New("ssh: junk character in version line") 277 | } 278 | } 279 | if _, err = rw.Write(append(versionLine, '\r', '\n')); err != nil { 280 | return 281 | } 282 | 283 | them, err = readVersion(rw) 284 | return them, err 285 | } 286 | 287 | // maxVersionStringBytes is the maximum number of bytes that we'll 288 | // accept as a version string. RFC 4253 section 4.2 limits this at 255 289 | // chars 290 | const maxVersionStringBytes = 255 291 | 292 | // Read version string as specified by RFC 4253, section 4.2. 293 | func readVersion(r io.Reader) ([]byte, error) { 294 | versionString := make([]byte, 0, 64) 295 | var ok bool 296 | var buf [1]byte 297 | 298 | for len(versionString) < maxVersionStringBytes { 299 | _, err := io.ReadFull(r, buf[:]) 300 | if err != nil { 301 | return nil, err 302 | } 303 | // The RFC says that the version should be terminated with \r\n 304 | // but several SSH servers actually only send a \n. 305 | if buf[0] == '\n' { 306 | ok = true 307 | break 308 | } 309 | 310 | // non ASCII chars are disallowed, but we are lenient, 311 | // since Go doesn't use null-terminated strings. 312 | 313 | // The RFC allows a comment after a space, however, 314 | // all of it (version and comments) goes into the 315 | // session hash. 316 | versionString = append(versionString, buf[0]) 317 | } 318 | 319 | if !ok { 320 | return nil, errors.New("ssh: overflow reading version string") 321 | } 322 | 323 | // There might be a '\r' on the end which we should remove. 324 | if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' { 325 | versionString = versionString[:len(versionString)-1] 326 | } 327 | return versionString, nil 328 | } 329 | --------------------------------------------------------------------------------