Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(3471)

Side by Side Diff: ssh/server.go

Issue 9853050: code review 9853050: go.crypto/ssh: implement challenge/response auth (RFC 4... (Closed)
Patch Set: diff -r 273987d8ccbc https://code.google.com/p/go.crypto Created 10 years, 9 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« ssh/client_auth.go ('K') | « ssh/messages.go ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 The Go Authors. All rights reserved. 1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package ssh 5 package ssh
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "crypto" 9 "crypto"
10 "crypto/rand" 10 "crypto/rand"
(...skipping 24 matching lines...) Expand all
35 // PasswordCallback, if non-nil, is called when a user attempts to 35 // PasswordCallback, if non-nil, is called when a user attempts to
36 // authenticate using a password. It may be called concurrently from 36 // authenticate using a password. It may be called concurrently from
37 // several goroutines. 37 // several goroutines.
38 PasswordCallback func(conn *ServerConn, user, password string) bool 38 PasswordCallback func(conn *ServerConn, user, password string) bool
39 39
40 // PublicKeyCallback, if non-nil, is called when a client attempts publi c 40 // PublicKeyCallback, if non-nil, is called when a client attempts publi c
41 // key authentication. It must return true iff the given public key is 41 // key authentication. It must return true iff the given public key is
42 // valid for the given user. 42 // valid for the given user.
43 PublicKeyCallback func(conn *ServerConn, user, algo string, pubkey []byt e) bool 43 PublicKeyCallback func(conn *ServerConn, user, algo string, pubkey []byt e) bool
44 44
45 // ChallengeResponseCallback, if non-nil, is called when
46 // keyboard-interactive authentication is selected (RFC
47 // 4256). The client object's Challenge function should be
48 // used to query the user. The callback may offer multiple
49 // Challenge rounds. To avoid information leaks, the client
agl1 2013/06/06 14:22:13 only a single space after a period. (several cases
hanwen-google 2013/06/06 14:37:17 Done.
50 // should be presented a challenge even if the user is
51 // unknown.
52 ChallengeResponseCallback func(conn *ServerConn, user string, client Cli entChallengeResponse) bool
53
45 // Cryptographic-related configuration. 54 // Cryptographic-related configuration.
46 Crypto CryptoConfig 55 Crypto CryptoConfig
47 } 56 }
48 57
49 func (c *ServerConfig) rand() io.Reader { 58 func (c *ServerConfig) rand() io.Reader {
50 if c.Rand == nil { 59 if c.Rand == nil {
51 return rand.Reader 60 return rand.Reader
52 } 61 }
53 return c.Rand 62 return c.Rand
54 } 63 }
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 payload = payload[1:] 417 payload = payload[1:]
409 password, payload, ok := parseString(payload) 418 password, payload, ok := parseString(payload)
410 if !ok || len(payload) > 0 { 419 if !ok || len(payload) > 0 {
411 return ParseError{msgUserAuthRequest} 420 return ParseError{msgUserAuthRequest}
412 } 421 }
413 422
414 s.User = userAuthReq.User 423 s.User = userAuthReq.User
415 if s.config.PasswordCallback(s, userAuthReq.User, string (password)) { 424 if s.config.PasswordCallback(s, userAuthReq.User, string (password)) {
416 break userAuthLoop 425 break userAuthLoop
417 } 426 }
427 case "keyboard-interactive":
428 if s.config.ChallengeResponseCallback == nil {
429 break
430 }
431
432 s.User = userAuthReq.User
433 ok := s.config.ChallengeResponseCallback(s, s.User, &ssh ClientChallengeResponse{s})
agl1 2013/06/06 14:22:13 merge this with following conditional.
hanwen-google 2013/06/06 14:37:17 Done.
434 if ok {
435 break userAuthLoop
436 }
418 case "publickey": 437 case "publickey":
419 if s.config.PublicKeyCallback == nil { 438 if s.config.PublicKeyCallback == nil {
420 break 439 break
421 } 440 }
422 payload := userAuthReq.Payload 441 payload := userAuthReq.Payload
423 if len(payload) < 1 { 442 if len(payload) < 1 {
424 return ParseError{msgUserAuthRequest} 443 return ParseError{msgUserAuthRequest}
425 } 444 }
426 isQuery := payload[0] == 0 445 isQuery := payload[0] == 0
427 payload = payload[1:] 446 payload = payload[1:]
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 } 510 }
492 } 511 }
493 512
494 var failureMsg userAuthFailureMsg 513 var failureMsg userAuthFailureMsg
495 if s.config.PasswordCallback != nil { 514 if s.config.PasswordCallback != nil {
496 failureMsg.Methods = append(failureMsg.Methods, "passwor d") 515 failureMsg.Methods = append(failureMsg.Methods, "passwor d")
497 } 516 }
498 if s.config.PublicKeyCallback != nil { 517 if s.config.PublicKeyCallback != nil {
499 failureMsg.Methods = append(failureMsg.Methods, "publick ey") 518 failureMsg.Methods = append(failureMsg.Methods, "publick ey")
500 } 519 }
520 if s.config.ChallengeResponseCallback != nil {
521 failureMsg.Methods = append(failureMsg.Methods, "keyboar d-interactive")
522 }
501 523
502 if len(failureMsg.Methods) == 0 { 524 if len(failureMsg.Methods) == 0 {
503 return errors.New("ssh: no authentication methods config ured but NoClientAuth is also false") 525 return errors.New("ssh: no authentication methods config ured but NoClientAuth is also false")
504 } 526 }
505 527
506 if err = s.writePacket(marshal(msgUserAuthFailure, failureMsg)); err != nil { 528 if err = s.writePacket(marshal(msgUserAuthFailure, failureMsg)); err != nil {
507 return err 529 return err
508 } 530 }
509 } 531 }
510 532
511 packet = []byte{msgUserAuthSuccess} 533 packet = []byte{msgUserAuthSuccess}
512 if err = s.writePacket(packet); err != nil { 534 if err = s.writePacket(packet); err != nil {
513 return err 535 return err
514 } 536 }
515 537
516 return nil 538 return nil
517 } 539 }
518 540
541 // sshClientChallengeResponse implements a ClientChallengeResponse by
542 // asking the client on the other side of a ServerConn.
543 type sshClientChallengeResponse struct {
544 *ServerConn
545 }
546
547 func (c *sshClientChallengeResponse) Challenge(user, instruction string, questio ns []string, echos []bool) (answers []string, err error) {
548 if len(questions) != len(echos) {
549 return nil, errors.New("ssh: echos and questions must have equal length")
550 }
551
552 var prompts []byte
553 for i := range questions {
554 prompts = appendString(prompts, questions[i])
555 prompts = appendBool(prompts, echos[i])
556 }
557
558 if err := c.writePacket(marshal(msgUserAuthInfoRequest, userAuthInfoRequ estMsg{
559 Instruction: instruction,
560 NumPrompts: uint32(len(questions)),
561 Prompts: prompts,
562 })); err != nil {
563 return nil, err
564 }
565
566 packet, err := c.readPacket()
567 if err != nil {
568 return nil, err
569 }
570 if packet[0] != msgUserAuthInfoResponse {
571 return nil, UnexpectedMessageError{msgUserAuthInfoResponse, pack et[0]}
572 }
573 packet = packet[1:]
574
575 var n uint32
agl1 2013/06/06 14:22:13 it seems that these two var lines can be eliminate
hanwen-google 2013/06/06 14:37:17 Done.
576 var ok bool
577 n, packet, ok = parseUint32(packet)
578 if !ok || int(n) != len(questions) {
579 return nil, &ParseError{msgUserAuthInfoResponse}
580 }
581
582 for i := uint32(0); i < n; i++ {
583 ans, rest, ok := parseString(packet)
584 if !ok {
585 return nil, &ParseError{msgUserAuthInfoResponse}
586 }
587
588 answers = append(answers, string(ans))
589 packet = rest
590 }
591 if len(packet) != 0 {
592 return nil, errors.New("ssh: junk at end of message")
593 }
594
595 return answers, nil
596 }
597
519 const defaultWindowSize = 32768 598 const defaultWindowSize = 32768
520 599
521 // Accept reads and processes messages on a ServerConn. It must be called 600 // Accept reads and processes messages on a ServerConn. It must be called
522 // in order to demultiplex messages to any resulting Channels. 601 // in order to demultiplex messages to any resulting Channels.
523 func (s *ServerConn) Accept() (Channel, error) { 602 func (s *ServerConn) Accept() (Channel, error) {
524 // TODO(dfc) s.lock is not held here so visibility of s.err is not guara nteed. 603 // TODO(dfc) s.lock is not held here so visibility of s.err is not guara nteed.
525 if s.err != nil { 604 if s.err != nil {
526 return nil, s.err 605 return nil, s.err
527 } 606 }
528 607
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
689 func Listen(network, addr string, config *ServerConfig) (*Listener, error) { 768 func Listen(network, addr string, config *ServerConfig) (*Listener, error) {
690 l, err := net.Listen(network, addr) 769 l, err := net.Listen(network, addr)
691 if err != nil { 770 if err != nil {
692 return nil, err 771 return nil, err
693 } 772 }
694 return &Listener{ 773 return &Listener{
695 l, 774 l,
696 config, 775 config,
697 }, nil 776 }, nil
698 } 777 }
OLDNEW
« ssh/client_auth.go ('K') | « ssh/messages.go ('k') | no next file » | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b