684 lines
28 KiB
Java
684 lines
28 KiB
Java
/* WolfSSLInternalVerifyCb.java
|
|
*
|
|
* Copyright (C) 2006-2026 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfSSL.
|
|
*
|
|
* wolfSSL is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfSSL is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
package com.wolfssl.provider.jsse;
|
|
|
|
import com.wolfssl.WolfSSL;
|
|
import com.wolfssl.WolfSSLDebug;
|
|
import com.wolfssl.WolfSSLVerifyCallback;
|
|
import com.wolfssl.WolfSSLException;
|
|
import com.wolfssl.WolfSSLJNIException;
|
|
import com.wolfssl.WolfSSLCertificate;
|
|
import com.wolfssl.WolfSSLX509StoreCtx;
|
|
import com.wolfssl.provider.jsse.WolfSSLInternalVerifyCb;
|
|
import java.security.cert.X509Certificate;
|
|
import java.security.cert.CertificateException;
|
|
import javax.net.ssl.SSLSocket;
|
|
import javax.net.ssl.SSLEngine;
|
|
import javax.net.ssl.SSLSession;
|
|
import javax.net.ssl.X509TrustManager;
|
|
import javax.net.ssl.X509ExtendedTrustManager;
|
|
import java.io.IOException;
|
|
import java.lang.ref.WeakReference;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Internal verify callback.
|
|
* This is used when a user registers a TrustManager which is NOT
|
|
* com.wolfssl.provider.jsse.WolfSSLTrustManager. It is used to call
|
|
* TrustManager checkClientTrusted() or checkServerTrusted().
|
|
* If wolfJSSE TrustManager is used, native wolfSSL does certificate
|
|
* verification internally. Used by WolfSSLEngineHelper.
|
|
*/
|
|
public class WolfSSLInternalVerifyCb implements WolfSSLVerifyCallback {
|
|
|
|
private X509TrustManager tm = null;
|
|
private boolean clientMode;
|
|
private WolfSSLParameters params = null;
|
|
|
|
/* Use WeakReference for SSLSocket and SSLEngine to avoid
|
|
* holding back garbage collection of WolfSSLSocket/WolfSSLEngine
|
|
* objects */
|
|
private WeakReference<SSLSocket> callingSocket = null;
|
|
private WeakReference<SSLEngine> callingEngine = null;
|
|
|
|
/* TrustManager exception for SSLHandshakeException cause chain */
|
|
private Exception verifyException = null;
|
|
|
|
/**
|
|
* Create new WolfSSLInternalVerifyCb
|
|
*
|
|
* @param xtm X509TrustManager to use with this object
|
|
* @param client boolean representing if this is client side
|
|
* @param socket SSLSocket associated with this callback, or null
|
|
* @param engine SSLEngine associated with this callback, or null
|
|
* @param params WolfSSLParameters associated with this callback
|
|
*/
|
|
public WolfSSLInternalVerifyCb(X509TrustManager xtm, boolean client,
|
|
SSLSocket socket, SSLEngine engine, WolfSSLParameters params) {
|
|
this.tm = xtm;
|
|
this.clientMode = client;
|
|
this.params = params;
|
|
|
|
if (socket != null) {
|
|
this.callingSocket = new WeakReference<>(socket);
|
|
} else {
|
|
this.callingSocket = null;
|
|
}
|
|
|
|
if (engine != null) {
|
|
this.callingEngine = new WeakReference<>(engine);
|
|
} else {
|
|
this.callingEngine = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset internal variables back to null/default.
|
|
*/
|
|
protected void clearInternalVars() {
|
|
this.callingSocket = null;
|
|
this.callingEngine = null;
|
|
this.params = null;
|
|
this.tm = null;
|
|
this.verifyException = null;
|
|
}
|
|
|
|
/**
|
|
* Get the last exception thrown by the TrustManager during
|
|
* certificate verification. Returns null if verification succeeded
|
|
* or no verification has occurred.
|
|
*
|
|
* @return Exception from last failed verification, or null
|
|
*/
|
|
public Exception getVerifyException() {
|
|
return this.verifyException;
|
|
}
|
|
|
|
/**
|
|
* Verify hostname of provided peer certificate using
|
|
* Endpoint Identification Algorithm if set in SSLParameters.
|
|
*
|
|
* Used by verifyCallback() only for case where internal native wolfSSL
|
|
* peer verification is done. Otherwise, hostname is verified as part
|
|
* of full cert validation later in verifyCallback().
|
|
*
|
|
* @param peer peer certificate to use for hostname verification
|
|
*
|
|
* @return 1 if hostname verification was successful (allows verify
|
|
* callback to proceed, otherwise 0 if verification was not
|
|
* successful (or not able to do it since Endpoitn Identification
|
|
* Algorithm has not been set).
|
|
*/
|
|
private int verifyHostnameOnly(X509Certificate peer) {
|
|
|
|
WolfSSLTrustX509 wolfTM = (WolfSSLTrustX509)tm;
|
|
|
|
try {
|
|
SSLSocket sock = (this.callingSocket != null) ?
|
|
this.callingSocket.get() : null;
|
|
SSLEngine eng = (this.callingEngine != null) ?
|
|
this.callingEngine.get() : null;
|
|
|
|
if (sock != null) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "checking hostname verification using SSLSocket");
|
|
|
|
/* Throws CertificateException when verify fails */
|
|
wolfTM.verifyHostname(peer, sock, null, clientMode);
|
|
}
|
|
else if (eng != null) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "checking hostname verification using SSLEngine");
|
|
|
|
/* Throws CertificateException when verify fails */
|
|
wolfTM.verifyHostname(peer, null, eng, clientMode);
|
|
}
|
|
else {
|
|
/* SSLSocket/SSLEngine null. Fail if endpoint ID
|
|
* is set, otherwise skip hostname verification. */
|
|
String eia = null;
|
|
if (this.params != null) {
|
|
eia = this.params.getEndpointIdentificationAlgorithm();
|
|
}
|
|
if (eia != null && !eia.isEmpty()) {
|
|
throw new CertificateException(
|
|
"Both SSLSocket and SSLEngine null, cannot " +
|
|
"perform hostname verification for " +
|
|
"endpoint identification algorithm: " + eia);
|
|
}
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Both SSLSocket and SSLEngine null, skipping " +
|
|
"hostname verification (native verify already " +
|
|
"passed, no endpoint identification configured)");
|
|
}
|
|
} catch (CertificateException e) {
|
|
this.verifyException = e;
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "X509ExtendedTrustManager hostname verification " +
|
|
"failed: " + e.getMessage());
|
|
return 0;
|
|
}
|
|
|
|
/* Hostname verification successful */
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Verify hostname for basic X509TrustManager when Endpoint
|
|
* Identification Algorithm is set. Matches SunJSSE behavior.
|
|
*
|
|
* @param peer peer certificate to verify hostname against
|
|
*
|
|
* @return 1 if passed or not needed, 0 if failed
|
|
*/
|
|
private int verifyHostnameForExternalTM(X509Certificate peer) {
|
|
|
|
String endpointIdAlgo = null;
|
|
String peerHost = null;
|
|
SSLSession session = null;
|
|
|
|
/* Get endpoint identification algorithm from params */
|
|
if (this.params != null) {
|
|
endpointIdAlgo = this.params.getEndpointIdentificationAlgorithm();
|
|
}
|
|
|
|
/* If no endpoint identification algorithm set, skip hostname
|
|
* verification - it has not been requested */
|
|
if (endpointIdAlgo == null || endpointIdAlgo.isEmpty()) {
|
|
return 1;
|
|
}
|
|
|
|
/* Only HTTPS and LDAPS are supported. Fail if endpoint ID was
|
|
* explicitly set to something else (typo or unsupported algo). */
|
|
if (!endpointIdAlgo.equals("HTTPS") &&
|
|
!endpointIdAlgo.equals("LDAPS")) {
|
|
final String tmpAlgoUnsup = endpointIdAlgo;
|
|
this.verifyException = new CertificateException(
|
|
"Unsupported endpoint identification algorithm: " +
|
|
endpointIdAlgo);
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Unsupported endpoint identification algorithm: "
|
|
+ tmpAlgoUnsup);
|
|
return 0;
|
|
}
|
|
|
|
final String tmpAlgo = endpointIdAlgo;
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Provider-level hostname verification, algorithm: " +
|
|
tmpAlgo);
|
|
|
|
/* Get peer host from SSLEngine or SSLSocket handshake session */
|
|
try {
|
|
SSLEngine eng = (this.callingEngine != null) ?
|
|
this.callingEngine.get() : null;
|
|
SSLSocket sock = (this.callingSocket != null) ?
|
|
this.callingSocket.get() : null;
|
|
|
|
if (eng != null) {
|
|
session = eng.getHandshakeSession();
|
|
}
|
|
else if (sock != null) {
|
|
session = sock.getHandshakeSession();
|
|
}
|
|
} catch (UnsupportedOperationException e) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "getHandshakeSession() not supported: " + e.getMessage());
|
|
CertificateException ce = new CertificateException(
|
|
"getHandshakeSession() not supported: " + e.getMessage());
|
|
ce.initCause(e);
|
|
this.verifyException = ce;
|
|
return 0;
|
|
}
|
|
|
|
/* Prefer SNI hostname from SSLParameters over session peer host.
|
|
* session.getPeerHost() returns the IP address (e.g. 127.0.0.1),
|
|
* but for SNI verification we need the logical hostname the client
|
|
* requested (e.g. "something.netty.io"). */
|
|
if (this.params != null) {
|
|
List<WolfSSLSNIServerName> sniNames =
|
|
this.params.getWolfSSLServerNames();
|
|
if (sniNames != null && !sniNames.isEmpty()) {
|
|
for (WolfSSLSNIServerName sni : sniNames) {
|
|
/* Type 0 = host_name (RFC 6066) */
|
|
if (sni.getType() == 0) {
|
|
byte[] encoded = sni.getEncoded();
|
|
if (encoded != null && encoded.length > 0) {
|
|
peerHost = new String(encoded,
|
|
StandardCharsets.US_ASCII);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Fall back to session peer host if no SNI hostname */
|
|
if (peerHost == null || peerHost.isEmpty()) {
|
|
if (session != null) {
|
|
peerHost = session.getPeerHost();
|
|
}
|
|
}
|
|
|
|
if (peerHost == null || peerHost.isEmpty()) {
|
|
this.verifyException = new CertificateException(
|
|
"No peer host available for hostname verification");
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "No peer host available for hostname verification");
|
|
/* No peer host to verify against, fail verification since
|
|
* endpoint identification was explicitly requested */
|
|
return 0;
|
|
}
|
|
|
|
/* Verify hostname against certificate SAN/CN using native
|
|
* wolfSSL X509_check_host() */
|
|
final String tmpHost = peerHost;
|
|
WolfSSLCertificate wCert = null;
|
|
try {
|
|
wCert = new WolfSSLCertificate(peer.getEncoded());
|
|
int ret = wCert.checkHost(peerHost);
|
|
if (ret == WolfSSL.SSL_SUCCESS) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Provider-level hostname verification " +
|
|
"passed for: " + tmpHost);
|
|
return 1;
|
|
} else {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Provider-level hostname verification " +
|
|
"FAILED for: " + tmpHost);
|
|
this.verifyException = new CertificateException(
|
|
"Hostname verification failed for: " + tmpHost);
|
|
return 0;
|
|
}
|
|
} catch (Exception e) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Hostname verification error: " + e.getMessage());
|
|
this.verifyException = e;
|
|
return 0;
|
|
} finally {
|
|
if (wCert != null) {
|
|
wCert.free();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calls registered X509TrustManager / X509ExtendedTrustManager to
|
|
* verify certificate chain.
|
|
*
|
|
* @param certs Peer certificate chain to validate
|
|
* @param authType Authentication type
|
|
*
|
|
* @return true on successful validation, otherwise false on failure
|
|
*/
|
|
private boolean VerifyCertChainWithTrustManager(X509Certificate[] certs,
|
|
String authType) {
|
|
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Verifying peer with X509TrustManager: " + this.tm);
|
|
if (this.tm instanceof X509ExtendedTrustManager) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "X509TrustManager of type X509ExtendedTrustManager");
|
|
}
|
|
else {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "X509TrustManager of type X509TrustManager");
|
|
}
|
|
|
|
try {
|
|
/* Call TrustManager to do cert verification, should throw
|
|
* CertificateException if verification fails */
|
|
SSLSocket sock = (this.callingSocket != null) ?
|
|
this.callingSocket.get() : null;
|
|
SSLEngine eng = (this.callingEngine != null) ?
|
|
this.callingEngine.get() : null;
|
|
|
|
if (this.clientMode) {
|
|
if (this.tm instanceof X509ExtendedTrustManager) {
|
|
X509ExtendedTrustManager xtm =
|
|
(X509ExtendedTrustManager)this.tm;
|
|
|
|
if (sock != null) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Calling TrustManager.checkServerTrusted(" +
|
|
"SSLSocket)");
|
|
|
|
xtm.checkServerTrusted(certs, authType, sock);
|
|
}
|
|
else if (eng != null) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Calling TrustManager.checkServerTrusted(" +
|
|
"SSLEngine)");
|
|
|
|
xtm.checkServerTrusted(certs, authType, eng);
|
|
}
|
|
else {
|
|
/* If we do have access to X509ExtendedTrustManager,
|
|
* but don't have SSLSocket/Engine, error out instead
|
|
* of falling back to verify without hostname. */
|
|
throw new Exception(
|
|
"SSLSocket/SSLEngine null during server peer " +
|
|
"verification, failed to verify");
|
|
}
|
|
}
|
|
else {
|
|
/* Basic X509TrustManager does not support HTTPS
|
|
* hostname verification, no SSLSocket/Engine needed */
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Calling TrustManager.checkServerTrusted()");
|
|
this.tm.checkServerTrusted(certs, authType);
|
|
}
|
|
|
|
} else {
|
|
if (this.tm instanceof X509ExtendedTrustManager) {
|
|
X509ExtendedTrustManager xtm =
|
|
(X509ExtendedTrustManager)this.tm;
|
|
|
|
if (sock != null) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Calling TrustManager.checkClientTrusted(" +
|
|
"SSLSocket)");
|
|
|
|
xtm.checkClientTrusted(certs, authType, sock);
|
|
}
|
|
else if (eng != null) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Calling TrustManager.checkClientTrusted(" +
|
|
"SSLEngine)");
|
|
|
|
xtm.checkClientTrusted(certs, authType, eng);
|
|
}
|
|
else {
|
|
/* If we do have access to X509ExtendedTrustManager,
|
|
* but don't have SSLSocket/Engine, error out instead
|
|
* of falling back to verify without hostname. */
|
|
throw new Exception(
|
|
"SSLSocket/SSLEngine null during client peer " +
|
|
"verification, failed to verify");
|
|
}
|
|
}
|
|
else {
|
|
/* Basic X509TrustManager does not support HTTPS
|
|
* hostname verification, no SSLSocket/Engine needed */
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Calling TrustManager.checkClientTrusted()");
|
|
this.tm.checkClientTrusted(certs, authType);
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
/* Store for SSLHandshakeException cause chain */
|
|
this.verifyException = e;
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "TrustManager rejected certificates, " +
|
|
"verification failed: " + e.getMessage());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Derive the authType String passed to X509TrustManager
|
|
* checkClientTrusted() / checkServerTrusted() from the peer's leaf
|
|
* certificate.
|
|
*
|
|
* Derived from the certificate public key algorithm, matching the JDK
|
|
* convention of using chain[0].getPublicKey().getAlgorithm(). Values map
|
|
* to the authType strings wolfJSSE has historically passed to
|
|
* TrustManagers ("RSA", "ECDSA", "DSA", "ED25519", "ED448", "ML-DSA").
|
|
*
|
|
* Falls back to deriving from the certificate signature type for key
|
|
* types the native public-key-type API does not report, and to keep
|
|
* reporting the historical "ED25519" / "ED448" values for EdDSA keys.
|
|
*
|
|
* @param cert peer leaf certificate
|
|
*
|
|
* @return authType String, or null if it cannot be determined
|
|
*/
|
|
public static String getAuthTypeFromPeerCert(WolfSSLCertificate cert) {
|
|
|
|
String keyType = null;
|
|
String authType = null;
|
|
|
|
try {
|
|
keyType = cert.getPubkeyType();
|
|
} catch (Exception e) {
|
|
/* Key type unknown to native pubkey-type API, fall back to
|
|
* signature-type derivation below */
|
|
}
|
|
|
|
if (keyType != null) {
|
|
if (keyType.equals("RSA") || keyType.equals("RSASSA-PSS")) {
|
|
/* RSASSA-PSS keys map to "RSA", matching the authType
|
|
* String wolfJSSE has historically used for PSS certs */
|
|
authType = "RSA";
|
|
} else if (keyType.equals("ECC")) {
|
|
authType = "ECDSA";
|
|
} else if (keyType.equals("DSA")) {
|
|
authType = "DSA";
|
|
} else if (keyType.equals("ML-DSA")) {
|
|
authType = "ML-DSA";
|
|
}
|
|
}
|
|
|
|
if (authType == null) {
|
|
/* Fall back to certificate signature type. Order matters:
|
|
* check "ML-DSA" before "DSA" since the latter is a substring
|
|
* of the former. */
|
|
String sigType = null;
|
|
try {
|
|
sigType = cert.getSignatureType();
|
|
} catch (Exception e) {
|
|
return null;
|
|
}
|
|
if (sigType == null) {
|
|
return null;
|
|
}
|
|
if (sigType.contains("ML-DSA")) {
|
|
authType = "ML-DSA";
|
|
} else if (sigType.contains("RSA")) {
|
|
authType = "RSA";
|
|
} else if (sigType.contains("ECDSA")) {
|
|
authType = "ECDSA";
|
|
} else if (sigType.contains("DSA")) {
|
|
authType = "DSA";
|
|
} else if (sigType.contains("ED25519")) {
|
|
authType = "ED25519";
|
|
} else if (sigType.contains("ED448")) {
|
|
authType = "ED448";
|
|
}
|
|
}
|
|
|
|
return authType;
|
|
}
|
|
|
|
/**
|
|
* Native wolfSSL verify callback.
|
|
*
|
|
* @param preverify_ok Will be 1 if native wolfSSL verification
|
|
* procedures have passed, otherwise 0.
|
|
* @param x509StorePtr Native pointer to WOLFSSL_X509_STORE structure
|
|
*
|
|
* @return 1 if verification should be considered successful and
|
|
* SSL/TLS handshake should continue. Otherwise return 0
|
|
* to mark verification failure and stop/abort handshake.
|
|
*/
|
|
@SuppressWarnings("deprecation")
|
|
public int verifyCallback(int preverify_ok, long x509StorePtr) {
|
|
|
|
WolfSSLCertificate[] certs = null;
|
|
String authType = null;
|
|
X509Certificate[] x509certs = new X509Certificate[0];
|
|
|
|
/* Clear any prior callback failure so callers don't see stale causes
|
|
* if this callback instance is reused across handshakes. */
|
|
this.verifyException = null;
|
|
|
|
if (preverify_ok == 1) {
|
|
/* When using WolfSSLTrustX509 implementation of
|
|
* X509TrustManager, we use internal wolfSSL verification logic
|
|
* but register this verify callback (always called) so that
|
|
* we can do additional hostname verification if user has set
|
|
* the Endpoint Identification Algorithm in SSLParameters.
|
|
* Note that certificate verification has already been done and
|
|
* passed if preverify_ok == 1, so we skip doing it again here
|
|
* later on for this case */
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Native wolfSSL peer verification passed (clientMode: " +
|
|
this.clientMode + ")");
|
|
} else {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "NOTE: Native wolfSSL peer verification failed " +
|
|
"(clientMode: " + this.clientMode + ")");
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> " Continuing with X509TrustManager verification");
|
|
}
|
|
|
|
try {
|
|
/* Get WolfSSLCertificate[] from x509StorePtr, certs from
|
|
* store.getCerts() should be listed in order of peer to root */
|
|
WolfSSLX509StoreCtx store = new WolfSSLX509StoreCtx(x509StorePtr);
|
|
certs = store.getCerts();
|
|
|
|
} catch (WolfSSLException e) {
|
|
/* failed to get certs from native, give app null array */
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Failed to get certs from x509StorePtr, certs = null: " +
|
|
e.getMessage());
|
|
certs = null;
|
|
}
|
|
|
|
if (certs != null && certs.length > 0) {
|
|
try {
|
|
/* Convert WolfSSLCertificate[] to X509Certificate[] */
|
|
x509certs = new X509Certificate[certs.length];
|
|
for (int i = 0; i < certs.length; i++) {
|
|
x509certs[i] = certs[i].getX509Certificate();
|
|
final String tmpName =
|
|
x509certs[i].getSubjectDN().getName();
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Peer cert: " + tmpName);
|
|
}
|
|
} catch (CertificateException | IOException |
|
|
WolfSSLJNIException ce) {
|
|
/* failed to get cert array, give app empty array */
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Failed to get X509Certificate[] array, set to " +
|
|
"empty array: " + ce.getMessage());
|
|
x509certs = new X509Certificate[0];
|
|
}
|
|
|
|
/* get authType from the peer's leaf cert */
|
|
authType = getAuthTypeFromPeerCert(certs[0]);
|
|
final String tmpAuthType = authType;
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Auth type: " + tmpAuthType);
|
|
|
|
/* Free native WolfSSLCertificate memory. At this
|
|
* point x509certs[] is all Java managed memory now. */
|
|
for (int i = 0; i < certs.length; i++) {
|
|
certs[i].free();
|
|
}
|
|
}
|
|
|
|
/* Case where native wolfSSL verification was already done and passed
|
|
* and we only want to do hostname verification if needed additionally.
|
|
* We do that here and return before going on to additional
|
|
* checkServerTrusted/checkClientTrusted() so that we do not
|
|
* duplicate verification. */
|
|
if ((preverify_ok == 1) && (x509certs.length > 0) &&
|
|
(tm instanceof WolfSSLTrustX509)) {
|
|
return verifyHostnameOnly(x509certs[0]);
|
|
}
|
|
|
|
/* If server-side application has explicitly disabled client
|
|
* authentication (neither needClientAuth nor wantClientAuth set),
|
|
* return as success and skip X509TrustManager verification. */
|
|
if ((!this.clientMode) && (this.params != null) &&
|
|
(!this.params.getNeedClientAuth()) &&
|
|
(!this.params.getWantClientAuth())) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Application has disabled client verification " +
|
|
"(needClientAuth=false, wantClientAuth=false), " +
|
|
"skipping verification");
|
|
return 1;
|
|
}
|
|
else if ((x509certs.length == 0) &&
|
|
(!this.clientMode) && (this.params != null) &&
|
|
this.params.getWantClientAuth() &&
|
|
(!this.params.getNeedClientAuth())) {
|
|
/* No peer certificates sent and client authentication is
|
|
* optional (wantClientAuth == true, needClientAuth == false).
|
|
* Don't call TrustManager with empty certificate chain,
|
|
* just consider verification successful. Don't require
|
|
* preverify_ok == 1 here since native wolfSSL may report
|
|
* failure when no CAs are loaded (foreign TrustManager). */
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "No client cert sent and client auth marked optional, " +
|
|
"not calling TrustManager for hostname verification");
|
|
}
|
|
else if ((!this.clientMode) && (this.params != null) &&
|
|
this.params.getWantClientAuth() &&
|
|
(!this.params.getNeedClientAuth())) {
|
|
/* wantClientAuth only makes an absent client cert non-fatal.
|
|
* A cert that is presented must still validate, matching SunJSSE,
|
|
* so abort the handshake if the TrustManager rejects it. */
|
|
if (VerifyCertChainWithTrustManager(x509certs, authType) == false) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "wantClientAuth: client cert verification failed, " +
|
|
"aborting handshake");
|
|
return 0;
|
|
}
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "wantClientAuth: client cert verified successfully");
|
|
}
|
|
else {
|
|
/* Poll X509TrustManager / X509ExtendedTrustManager for certificate
|
|
* verification status. Returns 0 if certificates are rejected,
|
|
* otherwise 1 on successful verification */
|
|
if (VerifyCertChainWithTrustManager(x509certs, authType) == false) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "TrustManager verification failed");
|
|
/* Abort handshake, verification failed */
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Provider-level hostname verify for basic X509TrustManager
|
|
* (X509ExtendedTrustManager handles it internally) */
|
|
if (!(tm instanceof WolfSSLTrustX509) &&
|
|
!(tm instanceof X509ExtendedTrustManager) &&
|
|
this.clientMode && x509certs.length > 0) {
|
|
if (verifyHostnameForExternalTM(x509certs[0]) == 0) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "Provider-level hostname verification failed");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
() -> "TrustManager verification successful");
|
|
|
|
/* Continue handshake, verification succeeded */
|
|
return 1;
|
|
}
|
|
}
|