spacemonkeygo / openssl

OpenSSL bindings for Go
http://godoc.org/github.com/spacemonkeygo/openssl
Apache License 2.0
472 stars 237 forks source link

Issue with fips mode set and Openssl version 1.0.2o #96

Open ajaynalawade opened 6 years ago

ajaynalawade commented 6 years ago

Hi,

I am using spacemonkeygo openssl for openssl binding. I have tcp server running with fips mode set. When I use Openssl version 1.0.2o, read request at server fails with following error under load (500 requests per second). "Errored while reading request. Error: %vSSL errors: SSL routines:SSL3_GET_RECORD:decryption failed or bad record mac"

Above error is not seen if fips mode is off. Also above error is not seen with 1.0.1 version (with or without fips mode).

Find attached sample server code using which I am able to reproduce issue.

Thanks, Ajay

ajaynalawade commented 6 years ago

package main

import ( "log" "net" "net/http" "fmt" "os" "bufio" "io" "strconv" "github.com/spacemonkeygo/openssl" )

func init_fips() { err := openssl.FIPSModeSet(true) if err != nil { panic(fmt.Errorf("%v Error:%v\n", "openssl failed to set fips mode.", err)) } log.Print("OpenSSL FIPS mode is set to: True\n") }

func main() { init_fips()

laddr := "0.0.0.0:443"
var ln net.Listener
var err error

// Init SSL shared context used across connections
ctx, err := openssl.NewCtxFromFiles("/etc/certs/sslcert.crt", "/etc/certs/sslcert.key")
if err != nil {
    log.Fatalf("Failed to read ssl certificate. Error: %v", err)
}

// Set options and do not allow SSLv2 and SSLv3 communication
_ = ctx.SetOptions(openssl.CipherServerPreference |
    openssl.NoSSLv2 | openssl.NoSSLv3)

// Read certificate
// Listen on bind address
ln, err = openssl.Listen("tcp", laddr, ctx)

if err != nil {
    log.Fatalf("Failed to start server. Error: %v",
        err)
    os.Exit(1)
} else {
        log.Println("Started secure server")
}
if err != nil {
    log.Fatalf("server: listen: %s", err)
}
log.Print("server: listening")
for {
    accepted, err := ln.Accept()

    if err != nil {
        log.Println("Got errored while accepting connection. %v", err)
        return
    }

    go handleClient(accepted)
}

}

func handleClient(conn net.Conn) { defer conn.Close() reader := bufio.NewReader(conn) for { //log.Print("server: conn: waiting") var err error httpreq, err := http.ReadRequest(reader) if err != nil { log.Print("Errored while reading request. Error: %v", err) break } buf := make([]byte, httpreq.ContentLength) toread := int(httpreq.ContentLength) rbytes := 0 n := 0 for toread > 0 { n, err = httpreq.Body.Read(buf[rbytes:]) if err != nil && err != io.EOF { log.Print("Errored while reading request body. Error: %v", err) break } rbytes += n toread = toread - n }

    resp := append([]byte("HTTP/1.1 200 OK\r\n"+"Content-Length: "+
            strconv.Itoa(len(buf))+"\r\n\r\n"), buf...)
    _, err = conn.Write(resp)
    if err != nil {
            log.Print("Errored while writing response. Error: %v", err)
            break
    }

    log.Printf("server: conn: wrote %d bytes", n)

}
log.Println("server: conn: closed")

}

ajaynalawade commented 6 years ago

Here are some more observations

  1. It did not take much load to cause this error(Creating even 2 connections in parallel gives this issue).
  2. While a client is sending data, another client connecting does not error. The error seems to be only when two clients try to handshake together. If we serialise ssl wrap even thousands of clients do not give this issue.
  3. There comes a time(after 40 iterations in case of 3 parallel handshaking clients) after which the server kind of gives up and keeps on giving the same error no matter how much we slow down the clients(I stopped my client script for 5 minutes before trying again).