Test server-side renegotiation.
This change adds support to the Go code for renegotiation as a client,
meaning that we can test BoringSSL's renegotiation as a server.
Change-Id: Iaa9fb1a6022c51023bce36c47d4ef7abee74344b
Reviewed-on: https://boringssl-review.googlesource.com/2082
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index 3ce6c76..897175e 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -50,6 +50,10 @@
clientProtocolFallback bool
usedALPN bool
+ // verify_data values for the renegotiation extension.
+ clientVerify []byte
+ serverVerify []byte
+
channelID *ecdsa.PublicKey
// input/output
@@ -129,9 +133,10 @@
}
func (hc *halfConn) error() error {
- hc.Lock()
+ // This should be locked, but I've removed it for the renegotiation
+ // tests since we don't concurrently read and write the same tls.Conn
+ // in any case during testing.
err := hc.err
- hc.Unlock()
return err
}
@@ -651,7 +656,7 @@
func (c *Conn) readRecord(want recordType) error {
// Caller must be in sync with connection:
// handshake data if handshake not yet completed,
- // else application data. (We don't support renegotiation.)
+ // else application data.
switch want {
default:
c.sendAlert(alertInternalError)
@@ -725,7 +730,12 @@
case recordTypeHandshake:
// TODO(rsc): Should at least pick off connection close.
if typ != want {
- return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation))
+ // A client might need to process a HelloRequest from
+ // the server, thus receiving a handshake message when
+ // application data is expected is ok.
+ if !c.isClient {
+ return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation))
+ }
}
c.hand.Write(data)
}
@@ -908,6 +918,8 @@
var m handshakeMessage
switch data[0] {
+ case typeHelloRequest:
+ m = new(helloRequestMsg)
case typeClientHello:
m = &clientHelloMsg{
isDTLS: c.isDTLS,
@@ -1000,6 +1012,25 @@
return n + m, c.out.setErrorLocked(err)
}
+func (c *Conn) handleRenegotiation() error {
+ c.handshakeComplete = false
+ if !c.isClient {
+ panic("renegotiation should only happen for a client")
+ }
+
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ _, ok := msg.(*helloRequestMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return alertUnexpectedMessage
+ }
+
+ return c.Handshake()
+}
+
// Read can be made to time out and return a net.Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetReadDeadline.
func (c *Conn) Read(b []byte) (n int, err error) {
@@ -1019,6 +1050,14 @@
// Soft error, like EAGAIN
return 0, err
}
+ if c.hand.Len() > 0 {
+ // We received handshake bytes, indicating the
+ // start of a renegotiation.
+ if err := c.handleRenegotiation(); err != nil {
+ return 0, err
+ }
+ continue
+ }
}
if err := c.in.err; err != nil {
return 0, err