client_auth.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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. package ssh
  5. import (
  6. "fmt"
  7. "io"
  8. )
  9. // authenticate authenticates with the remote server. See RFC 4252.
  10. func (c *ClientConn) authenticate(session []byte) error {
  11. // initiate user auth session
  12. if err := c.writePacket(marshal(msgServiceRequest, serviceRequestMsg{serviceUserAuth})); err != nil {
  13. return err
  14. }
  15. packet, err := c.readPacket()
  16. if err != nil {
  17. return err
  18. }
  19. var serviceAccept serviceAcceptMsg
  20. if err := unmarshal(&serviceAccept, packet, msgServiceAccept); err != nil {
  21. return err
  22. }
  23. // during the authentication phase the client first attempts the "none" method
  24. // then any untried methods suggested by the server.
  25. tried, remain := make(map[string]bool), make(map[string]bool)
  26. for auth := ClientAuth(new(noneAuth)); auth != nil; {
  27. ok, methods, err := auth.auth(session, c.config.User, c.transport, c.config.rand())
  28. if err != nil {
  29. return err
  30. }
  31. if ok {
  32. // success
  33. return nil
  34. }
  35. tried[auth.method()] = true
  36. delete(remain, auth.method())
  37. for _, meth := range methods {
  38. if tried[meth] {
  39. // if we've tried meth already, skip it.
  40. continue
  41. }
  42. remain[meth] = true
  43. }
  44. auth = nil
  45. for _, a := range c.config.Auth {
  46. if remain[a.method()] {
  47. auth = a
  48. break
  49. }
  50. }
  51. }
  52. return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", keys(tried))
  53. }
  54. func keys(m map[string]bool) (s []string) {
  55. for k, _ := range m {
  56. s = append(s, k)
  57. }
  58. return
  59. }
  60. // A ClientAuth represents an instance of an RFC 4252 authentication method.
  61. type ClientAuth interface {
  62. // auth authenticates user over transport t.
  63. // Returns true if authentication is successful.
  64. // If authentication is not successful, a []string of alternative
  65. // method names is returned.
  66. auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error)
  67. // method returns the RFC 4252 method name.
  68. method() string
  69. }
  70. // "none" authentication, RFC 4252 section 5.2.
  71. type noneAuth int
  72. func (n *noneAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) {
  73. if err := t.writePacket(marshal(msgUserAuthRequest, userAuthRequestMsg{
  74. User: user,
  75. Service: serviceSSH,
  76. Method: "none",
  77. })); err != nil {
  78. return false, nil, err
  79. }
  80. return handleAuthResponse(t)
  81. }
  82. func (n *noneAuth) method() string {
  83. return "none"
  84. }
  85. // "password" authentication, RFC 4252 Section 8.
  86. type passwordAuth struct {
  87. ClientPassword
  88. }
  89. func (p *passwordAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) {
  90. type passwordAuthMsg struct {
  91. User string
  92. Service string
  93. Method string
  94. Reply bool
  95. Password string
  96. }
  97. pw, err := p.Password(user)
  98. if err != nil {
  99. return false, nil, err
  100. }
  101. if err := t.writePacket(marshal(msgUserAuthRequest, passwordAuthMsg{
  102. User: user,
  103. Service: serviceSSH,
  104. Method: "password",
  105. Reply: false,
  106. Password: pw,
  107. })); err != nil {
  108. return false, nil, err
  109. }
  110. return handleAuthResponse(t)
  111. }
  112. func (p *passwordAuth) method() string {
  113. return "password"
  114. }
  115. // A ClientPassword implements access to a client's passwords.
  116. type ClientPassword interface {
  117. // Password returns the password to use for user.
  118. Password(user string) (password string, err error)
  119. }
  120. // ClientAuthPassword returns a ClientAuth using password authentication.
  121. func ClientAuthPassword(impl ClientPassword) ClientAuth {
  122. return &passwordAuth{impl}
  123. }
  124. // ClientKeyring implements access to a client key ring.
  125. type ClientKeyring interface {
  126. // Key returns the i'th *rsa.Publickey or *dsa.Publickey, or nil if
  127. // no key exists at i.
  128. Key(i int) (key interface{}, err error)
  129. // Sign returns a signature of the given data using the i'th key
  130. // and the supplied random source.
  131. Sign(i int, rand io.Reader, data []byte) (sig []byte, err error)
  132. }
  133. // "publickey" authentication, RFC 4252 Section 7.
  134. type publickeyAuth struct {
  135. ClientKeyring
  136. }
  137. type publickeyAuthMsg struct {
  138. User string
  139. Service string
  140. Method string
  141. // HasSig indicates to the reciver packet that the auth request is signed and
  142. // should be used for authentication of the request.
  143. HasSig bool
  144. Algoname string
  145. Pubkey string
  146. // Sig is defined as []byte so marshal will exclude it during validateKey
  147. Sig []byte `ssh:"rest"`
  148. }
  149. func (p *publickeyAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) {
  150. // Authentication is performed in two stages. The first stage sends an
  151. // enquiry to test if each key is acceptable to the remote. The second
  152. // stage attempts to authenticate with the valid keys obtained in the
  153. // first stage.
  154. var index int
  155. // a map of public keys to their index in the keyring
  156. validKeys := make(map[int]interface{})
  157. for {
  158. key, err := p.Key(index)
  159. if err != nil {
  160. return false, nil, err
  161. }
  162. if key == nil {
  163. // no more keys in the keyring
  164. break
  165. }
  166. if ok, err := p.validateKey(key, user, t); ok {
  167. validKeys[index] = key
  168. } else {
  169. if err != nil {
  170. return false, nil, err
  171. }
  172. }
  173. index++
  174. }
  175. // methods that may continue if this auth is not successful.
  176. var methods []string
  177. for i, key := range validKeys {
  178. pubkey := serializePublickey(key)
  179. algoname := algoName(key)
  180. sign, err := p.Sign(i, rand, buildDataSignedForAuth(session, userAuthRequestMsg{
  181. User: user,
  182. Service: serviceSSH,
  183. Method: p.method(),
  184. }, []byte(algoname), pubkey))
  185. if err != nil {
  186. return false, nil, err
  187. }
  188. // manually wrap the serialized signature in a string
  189. s := serializeSignature(algoname, sign)
  190. sig := make([]byte, stringLength(s))
  191. marshalString(sig, s)
  192. msg := publickeyAuthMsg{
  193. User: user,
  194. Service: serviceSSH,
  195. Method: p.method(),
  196. HasSig: true,
  197. Algoname: algoname,
  198. Pubkey: string(pubkey),
  199. Sig: sig,
  200. }
  201. p := marshal(msgUserAuthRequest, msg)
  202. if err := t.writePacket(p); err != nil {
  203. return false, nil, err
  204. }
  205. success, methods, err := handleAuthResponse(t)
  206. if err != nil {
  207. return false, nil, err
  208. }
  209. if success {
  210. return success, methods, err
  211. }
  212. }
  213. return false, methods, nil
  214. }
  215. // validateKey validates the key provided it is acceptable to the server.
  216. func (p *publickeyAuth) validateKey(key interface{}, user string, t *transport) (bool, error) {
  217. pubkey := serializePublickey(key)
  218. algoname := algoName(key)
  219. msg := publickeyAuthMsg{
  220. User: user,
  221. Service: serviceSSH,
  222. Method: p.method(),
  223. HasSig: false,
  224. Algoname: algoname,
  225. Pubkey: string(pubkey),
  226. }
  227. if err := t.writePacket(marshal(msgUserAuthRequest, msg)); err != nil {
  228. return false, err
  229. }
  230. return p.confirmKeyAck(key, t)
  231. }
  232. func (p *publickeyAuth) confirmKeyAck(key interface{}, t *transport) (bool, error) {
  233. pubkey := serializePublickey(key)
  234. algoname := algoName(key)
  235. for {
  236. packet, err := t.readPacket()
  237. if err != nil {
  238. return false, err
  239. }
  240. switch packet[0] {
  241. case msgUserAuthBanner:
  242. // TODO(gpaul): add callback to present the banner to the user
  243. case msgUserAuthPubKeyOk:
  244. msg := decode(packet).(*userAuthPubKeyOkMsg)
  245. if msg.Algo != algoname || msg.PubKey != string(pubkey) {
  246. return false, nil
  247. }
  248. return true, nil
  249. case msgUserAuthFailure:
  250. return false, nil
  251. default:
  252. return false, UnexpectedMessageError{msgUserAuthSuccess, packet[0]}
  253. }
  254. }
  255. panic("unreachable")
  256. }
  257. func (p *publickeyAuth) method() string {
  258. return "publickey"
  259. }
  260. // ClientAuthKeyring returns a ClientAuth using public key authentication.
  261. func ClientAuthKeyring(impl ClientKeyring) ClientAuth {
  262. return &publickeyAuth{impl}
  263. }
  264. // handleAuthResponse returns whether the preceding authentication request succeeded
  265. // along with a list of remaining authentication methods to try next and
  266. // an error if an unexpected response was received.
  267. func handleAuthResponse(t *transport) (bool, []string, error) {
  268. for {
  269. packet, err := t.readPacket()
  270. if err != nil {
  271. return false, nil, err
  272. }
  273. switch packet[0] {
  274. case msgUserAuthBanner:
  275. // TODO: add callback to present the banner to the user
  276. case msgUserAuthFailure:
  277. msg := decode(packet).(*userAuthFailureMsg)
  278. return false, msg.Methods, nil
  279. case msgUserAuthSuccess:
  280. return true, nil, nil
  281. case msgDisconnect:
  282. return false, nil, io.EOF
  283. default:
  284. return false, nil, UnexpectedMessageError{msgUserAuthSuccess, packet[0]}
  285. }
  286. }
  287. panic("unreachable")
  288. }