apple / swift-nio-ssl

TLS Support for SwiftNIO, based on BoringSSL.
https://swiftpackageindex.com/apple/swift-nio-ssl/main/documentation/niossl
Apache License 2.0
385 stars 139 forks source link

BorringSSL Handshake Failure #420

Open WiseNN opened 1 year ago

WiseNN commented 1 year ago

I am consistently getting an SSL Handshake Failure, and am having issues troubleshooting this. Any help would be much appreciated.

 handshakeFailed(NIOSSL.BoringSSLError.sslError([Error: 268436496 error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE at /Users/norriswise/Library/Developer/Xcode/DerivedData/ios-dc-bocetydygnmhxsdxqxaivnvasghk/SourcePackages/checkouts/swift-nio-ssl/Sources/CNIOBoringSSL/ssl/tls_record.cc:592])) file:[<unknown>] line:[0]]

tls_record.cc

 if (alert_level == SSL3_AL_FATAL) {
    OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr);
    ERR_add_error_dataf("SSL alert number %d", alert_descr);
    *out_alert = 0;  // No alert to send back to the peer.
    return ssl_open_record_error;
  }

Swift Code:

 var tlsConfig = TLSConfiguration.makeClientConfiguration()
        tlsConfig.maximumTLSVersion = .tlsv12
        tlsConfig.minimumTLSVersion = .tlsv11
        tlsConfig.cipherSuiteValues = NIOTLSCipher.allCases
        tlsConfig.certificateVerification = .noHostnameVerification
        tlsConfig.certificateChain = [.certificate(nioCert!)]
        let privateKeyNIO = try? NIOSSLPrivateKey.init(bytes: privateKeyByteAry, format: .der)
        tlsConfig.privateKey = NIOSSLPrivateKeySource.privateKey(privateKeyNIO!)

        let clientConfig = GRPCTLSConfiguration.makeClientConfigurationBackedByNIOSSL(configuration: tlsConfig, hostnameOverride: config.sniName)

        var gRPCLogger = Logger.init(label: "[[GRPC-LOGG]]", factory: StreamLogHandler.standardOutput(label:))
        gRPCLogger.logLevel = .debug

        if config.enableTLS {
            clientConnection = ClientConnection.usingTLS(with: clientConfig, on: eventLoopGroup)
                .withTLSCustomVerificationCallback({ certAry, verificationEventLoop in

                                      verificationEventLoop.succeed(.certificateVerified) //forcing success for testing purposes

                                  }                    
                             })
                .withBackgroundActivityLogger(gRPCLogger)
                .withErrorDelegate(self)
            clientConnection.withConnectionBackoff(retries: .upTo(3))
Lukasa commented 1 year ago

This error is the result of us receiving a handshake failure alert message. That usually means the other side has rejected the connection. Do you have logs from that side? If not, can you get a wireshark capture?

WiseNN commented 1 year ago

@Lukasa I have been told from the backend guys that the client certificates are not being seen; which I do think is correct from reviewing Charles. I see 3 server side certificates and 0 client side certificates.

Wireshark Logs:

Screenshot 1 - Wireshark

Screenshot 1



Screenshot 2 - Wireshark

Screenshot 2



Screenshot 3 From Server Guy Wireshark basically saying we are missing a client certificate Screenshot from Server Guy Wireshark (6)

Lukasa commented 1 year ago

Hmm, can you show me the Certificate messages coming from the client to the server? In the handshake you can see that the server requests a client cert using a Certificate Request message (same packet as the Server Key Exchange message in both cases), and then the client sends back a Certificate and Certificate Verify message in its next flight. That's where the client cert should be. Can you confirm the client cert is right, and that the server doesn't have any logs indicating that it's failing to verify it? It's notable that in your first screenshot the Certificate message is extremely short (78 bytes), which seems likely to be wrong as it's barely enough space for the key.