// Executes the server side authentication and returns either the agreed secret // session key or the a failure reason. func (l *Listener) serverAuth(strm *stream.Stream, req *authRequest) ([]byte, error) { // Create a new STS session stsSess, err := sts.New(rand.Reader, config.StsGroup, config.StsGenerator, config.StsCipher, config.StsCipherBits, config.StsSigHash) if err != nil { return nil, fmt.Errorf("failed to create STS session: %v", err) } // Accept the incoming key exchange request and send back own exp + auth token exp, token, err := stsSess.Accept(rand.Reader, l.key, req.Exp) if err != nil { return nil, fmt.Errorf("failed to accept incoming exchange: %v", err) } if err = strm.Send(authChallenge{exp, token}); err != nil { return nil, fmt.Errorf("failed to encode auth challenge: %v", err) } if err = strm.Flush(); err != nil { return nil, fmt.Errorf("failed to flush auth challenge: %v", err) } // Receive the foreign auth token and if verifies conclude session resp := new(authResponse) if err = strm.Recv(resp); err != nil { return nil, fmt.Errorf("failed to decode auth response: %v", err) } if err = stsSess.Finalize(&l.key.PublicKey, resp.Token); err != nil { return nil, fmt.Errorf("failed to finalize exchange: %v", err) } return stsSess.Secret() }
// Client side of the STS session negotiation. func clientAuth(strm *stream.Stream, key *rsa.PrivateKey) ([]byte, error) { // Set an overall time limit for the handshake to complete strm.Sock().SetDeadline(time.Now().Add(config.SessionShakeTimeout)) defer strm.Sock().SetDeadline(time.Time{}) // Create a new empty session stsSess, err := sts.New(rand.Reader, config.StsGroup, config.StsGenerator, config.StsCipher, config.StsCipherBits, config.StsSigHash) if err != nil { return nil, fmt.Errorf("failed to create new session: %v", err) } // Initiate a key exchange, send the exponential exp, err := stsSess.Initiate() if err != nil { return nil, fmt.Errorf("failed to initiate key exchange: %v", err) } req := &initRequest{ Auth: &authRequest{exp}, } if err = strm.Send(req); err != nil { return nil, fmt.Errorf("failed to send auth request: %v", err) } if err = strm.Flush(); err != nil { return nil, fmt.Errorf("failed to flush auth request: %v", err) } // Receive the foreign exponential and auth token and if verifies, send own auth chall := new(authChallenge) if err = strm.Recv(chall); err != nil { return nil, fmt.Errorf("failed to receive auth challenge: %v", err) } token, err := stsSess.Verify(rand.Reader, key, &key.PublicKey, chall.Exp, chall.Token) if err != nil { return nil, fmt.Errorf("failed to verify acceptor auth token: %v", err) } if err = strm.Send(authResponse{token}); err != nil { return nil, fmt.Errorf("failed to send auth response: %v", err) } if err = strm.Flush(); err != nil { return nil, fmt.Errorf("failed to flush auth response: %v", err) } return stsSess.Secret() }
// STS initiator: creates a new session, initiates a key exchange, verifies the other side and authenticates itself. func initiator(group, generator *big.Int, cipher func([]byte) (cipher.Block, error), bits int, hash crypto.Hash, skey *rsa.PrivateKey, pkey *rsa.PublicKey, trans, out chan []byte) { // Create a new empty session session, err := sts.New(rand.Reader, group, generator, cipher, bits, hash) if err != nil { fmt.Printf("failed to create new session: %v\n", err) close(out) return } // Initiate a key exchange, send the exponential exp, err := session.Initiate() if err != nil { fmt.Printf("failed to initiate key exchange: %v\n", err) close(out) return } trans <- exp.Bytes() // Receive the foreign exponential and auth token and if verifies, send own auth bytes, token := <-trans, <-trans exp = new(big.Int).SetBytes(bytes) token, err = session.Verify(rand.Reader, skey, pkey, exp, token) if err != nil { fmt.Printf("failed to verify acceptor auth token: %v\n", err) close(out) return } trans <- token // Protocol done, other side should finalize if all is correct secret, err := session.Secret() if err != nil { fmt.Printf("failed to retrieve exchanged secret: %v\n", err) close(out) return } out <- secret return }
// STS acceptor: creates a new session, accepts an exchange request, authenticates itself and verifies the other side. func acceptor(group, generator *big.Int, cipher func([]byte) (cipher.Block, error), bits int, hash crypto.Hash, skey *rsa.PrivateKey, pkey *rsa.PublicKey, trans, out chan []byte) { // Create a new empty session session, err := sts.New(rand.Reader, group, generator, cipher, bits, hash) if err != nil { fmt.Printf("failed to create new session: %v\n", err) close(out) return } // Receive foreign exponential, accept the incoming key exchange request and send back own exp + auth token bytes := <-trans exp := new(big.Int).SetBytes(bytes) exp, token, err := session.Accept(rand.Reader, skey, exp) if err != nil { fmt.Printf("failed to accept incoming exchange: %v\n", err) close(out) return } trans <- exp.Bytes() trans <- token // Receive the foreign auth token and if verifies conclude session token = <-trans err = session.Finalize(pkey, token) if err != nil { fmt.Printf("failed to finalize exchange: %v\n", err) close(out) return } // Protocol done secret, err := session.Secret() if err != nil { fmt.Printf("failed to retrieve exchanged secret: %v\n", err) close(out) return } out <- secret return }