背景,荣耀9x,混淆才会出这个问题。
[ERROR:ssl_client_socket_impl.cc(981)] handshake failed; returned -1, SSL error code 1, net_error -2
NetError.java
int SSLClientSocketImpl::DoHandshake() {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
int rv = SSL_do_handshake(ssl_.get());
int net_error = OK;
if (rv <= 0) {
int ssl_error = SSL_get_error(ssl_.get(), rv);
if (ssl_error == SSL_ERROR_WANT_X509_LOOKUP && !send_client_cert_) {
return ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
}
if (ssl_error == SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
DCHECK(client_private_key_);
DCHECK_NE(kSSLClientSocketNoPendingResult, signature_result_);
next_handshake_state_ = STATE_HANDSHAKE;
return ERR_IO_PENDING;
}
if (ssl_error == SSL_ERROR_WANT_CERTIFICATE_VERIFY) {
DCHECK(cert_verifier_request_);
next_handshake_state_ = STATE_HANDSHAKE;
return ERR_IO_PENDING;
}
OpenSSLErrorInfo error_info;
net_error = MapLastOpenSSLError(ssl_error, err_tracer, &error_info);
if (net_error == ERR_IO_PENDING) {
// If not done, stay in this state
next_handshake_state_ = STATE_HANDSHAKE;
return ERR_IO_PENDING;
}
LOG(ERROR) << "handshake failed; returned " << rv << ", SSL error code "
<< ssl_error << ", net_error " << net_error;
NetLogOpenSSLError(net_log_, NetLogEventType::SSL_HANDSHAKE_ERROR,
net_error, ssl_error, error_info);
}
next_handshake_state_ = STATE_HANDSHAKE_COMPLETE;
return net_error;
}
int SSLClientSocketImpl::MapLastOpenSSLError(
int ssl_error,
const crypto::OpenSSLErrStackTracer& tracer,
OpenSSLErrorInfo* info) {
int net_error = MapOpenSSLErrorWithDetails(ssl_error, tracer, info);
if (ssl_error == SSL_ERROR_SSL &&
ERR_GET_LIB(info->error_code) == ERR_LIB_SSL) {
// TLS does not provide an alert for missing client certificates, so most
// servers send a generic handshake_failure alert. Detect this case by
// checking if we have received a CertificateRequest but sent no
// certificate. See https://crbug.com/646567.
if (ERR_GET_REASON(info->error_code) ==
SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE &&
certificate_requested_ && send_client_cert_ && !client_cert_) {
net_error = ERR_BAD_SSL_CLIENT_AUTH_CERT;
}
// Per spec, access_denied is only for client-certificate-based access
// control, but some buggy firewalls use it when blocking a page. To avoid a
// confusing error, map it to a generic protocol error if no
// CertificateRequest was sent. See https://crbug.com/630883.
if (ERR_GET_REASON(info->error_code) == SSL_R_TLSV1_ALERT_ACCESS_DENIED &&
!certificate_requested_) {
net_error = ERR_SSL_PROTOCOL_ERROR;
}
// This error is specific to the client, so map it here.
if (ERR_GET_REASON(info->error_code) ==
SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS) {
net_error = ERR_SSL_CLIENT_AUTH_NO_COMMON_ALGORITHMS;
}
}
return net_error;
}
int MapOpenSSLErrorWithDetails(int err,
const crypto::OpenSSLErrStackTracer& tracer,
OpenSSLErrorInfo* out_error_info) {
*out_error_info = OpenSSLErrorInfo();
switch (err) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
return ERR_IO_PENDING;
case SSL_ERROR_EARLY_DATA_REJECTED:
return ERR_EARLY_DATA_REJECTED;
case SSL_ERROR_SYSCALL:
PLOG(ERROR) << "OpenSSL SYSCALL error, earliest error code in "
"error queue: "
<< ERR_peek_error();
return ERR_FAILED;
case SSL_ERROR_SSL:
// Walk down the error stack to find an SSL or net error.
while (true) {
OpenSSLErrorInfo error_info;
error_info.error_code =
ERR_get_error_line(&error_info.file, &error_info.line);
if (error_info.error_code == 0) {
// Map errors to ERR_SSL_PROTOCOL_ERROR by default, reporting the most
// recent error in |*out_error_info|.
return ERR_SSL_PROTOCOL_ERROR;
}
*out_error_info = error_info;
if (ERR_GET_LIB(error_info.error_code) == ERR_LIB_SSL) {
return MapOpenSSLErrorSSL(error_info.error_code);
}
if (ERR_GET_LIB(error_info.error_code) == OpenSSLNetErrorLib()) {
// Net error codes are negative but encoded in OpenSSL as positive
// numbers.
return -ERR_GET_REASON(error_info.error_code);
}
}
default:
// TODO(joth): Implement full mapping.
LOG(WARNING) << "Unknown OpenSSL error " << err;
return ERR_SSL_PROTOCOL_ERROR;
}
}
只有MapOpenSSLErrorWithDetails能返回-2,所以是openssl返回的错误。
抓包对比报文的差异:
似乎是客户端不识别证书。
没有思路,使用二分试错法。
结果:keep bouncycastle库可以解决问题,之前没有keep这个库却移除了系统实现。
问题代码:
//set up the security provider
private fun setupBouncyCastle() {
// Web3j will set up a provider when it's used for the first time.
val provider = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) ?: return
if (provider.javaClass == BouncyCastleProvider::class.java) {
return
}
//There is a possibility the bouncy castle registered by android may not have all ciphers
//so we substitute with the one bundled in the app.
Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME)
Security.insertProviderAt(BouncyCastleProvider(), 1)
}