Commit a77699ce authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

Chain order was inverted and added option to disable parts of the validation.

git-svn-id: http://svn.igniterealtime.org/svn/repos/wildfire/trunk@3273 b35dd754-fafc-0310-a699-88a17e54d16e
parent 2e318eb6
...@@ -50,6 +50,26 @@ class ServerTrustManager implements X509TrustManager { ...@@ -50,6 +50,26 @@ class ServerTrustManager implements X509TrustManager {
// when the remote server requests to do EXTERNAL SASL // when the remote server requests to do EXTERNAL SASL
} }
/**
* Given the partial or complete certificate chain provided by the peer, build a certificate
* path to a trusted root and return if it can be validated and is trusted for server SSL
* authentication based on the authentication type. The authentication type is the key
* exchange algorithm portion of the cipher suites represented as a String, such as "RSA",
* "DHE_DSS". Note: for some exportable cipher suites, the key exchange algorithm is
* determined at run time during the handshake. For instance, for
* TLS_RSA_EXPORT_WITH_RC4_40_MD5, the authType should be RSA_EXPORT when an ephemeral
* RSA key is used for the key exchange, and RSA when the key from the server certificate
* is used. Checking is case-sensitive.<p>
*
* By default certificates are going to be verified. This includes verifying the certificate
* chain, the root certificate and the certificates validity. However, it is possible to
* disable certificates validation as a whole or each specific validation.
*
* @param x509Certificates an ordered array of peer X.509 certificates with the peer's own
* certificate listed first and followed by any certificate authorities.
* @param string the key exchange algorithm used.
* @throws CertificateException if the certificate chain is not trusted by this TrustManager.
*/
public void checkServerTrusted(X509Certificate[] x509Certificates, String string) public void checkServerTrusted(X509Certificate[] x509Certificates, String string)
throws CertificateException { throws CertificateException {
...@@ -59,69 +79,86 @@ class ServerTrustManager implements X509TrustManager { ...@@ -59,69 +79,86 @@ class ServerTrustManager implements X509TrustManager {
if (verify) { if (verify) {
int nSize = x509Certificates.length; int nSize = x509Certificates.length;
String peerIdentity = getPeerIdentity(x509Certificates[nSize - 1]); String peerIdentity = getPeerIdentity(x509Certificates[0]);
// Working down the chain, for every certificate in the chain, if (JiveGlobals.getBooleanProperty("xmpp.server.certificate.verify.chain", true)) {
// verify that the subject of the certificate is the issuer of the // Working down the chain, for every certificate in the chain,
// next certificate in the chain. // verify that the subject of the certificate is the issuer of the
Principal principalLast = null; // next certificate in the chain.
for (int i = 0; i < nSize; i++) { Principal principalLast = null;
X509Certificate x509certificate = x509Certificates[i]; for (int i = nSize -1; i >= 0 ; i--) {
Principal principalIssuer = x509certificate.getIssuerDN(); X509Certificate x509certificate = x509Certificates[i];
Principal principalSubject = x509certificate.getSubjectDN(); Principal principalIssuer = x509certificate.getIssuerDN();
if (principalLast != null) { Principal principalSubject = x509certificate.getSubjectDN();
if (principalIssuer.equals(principalLast)) { if (principalLast != null) {
try { if (principalIssuer.equals(principalLast)) {
PublicKey publickey = try {
x509Certificates[i - 1].getPublicKey(); PublicKey publickey =
x509Certificates[i].verify(publickey); x509Certificates[i + 1].getPublicKey();
x509Certificates[i].verify(publickey);
}
catch (GeneralSecurityException generalsecurityexception) {
throw new CertificateException(
"signature verification failed of " + peerIdentity);
}
} }
catch (GeneralSecurityException generalsecurityexception) { else {
throw new CertificateException( throw new CertificateException(
"signature verification failed of " + peerIdentity); "subject/issuer verification failed of " + peerIdentity);
} }
} }
else { principalLast = principalSubject;
throw new CertificateException(
"subject/issuer verification failed of " + peerIdentity);
}
} }
principalLast = principalSubject;
} }
// Verify that the the first certificate in the chain was issued if (JiveGlobals.getBooleanProperty("xmpp.server.certificate.verify.root", true)) {
// by a third-party that the client trusts. // Verify that the the last certificate in the chain was issued
boolean trusted = false; // by a third-party that the client trusts.
try { boolean trusted = false;
trusted = trustStore.getCertificateAlias(x509Certificates[0]) != null; try {
if (!trusted && nSize == 1 && JiveGlobals trusted = trustStore.getCertificateAlias(x509Certificates[nSize - 1]) != null;
.getBooleanProperty("xmpp.server.certificate.accept-selfsigned", false)) { if (!trusted && nSize == 1 && JiveGlobals
Log.warn("Accepting self-signed certificate of remote server: " + peerIdentity); .getBooleanProperty("xmpp.server.certificate.accept-selfsigned", false))
trusted = true; {
Log.warn("Accepting self-signed certificate of remote server: " +
peerIdentity);
trusted = true;
}
}
catch (KeyStoreException e) {
Log.error(e);
}
if (!trusted) {
throw new CertificateException("root certificate not trusted of " + peerIdentity);
} }
}
catch (KeyStoreException e) {
Log.error(e);
}
if (!trusted) {
throw new CertificateException("root certificate not trusted of " + peerIdentity);
} }
// Verify that the last certificate in the chain corresponds to // Verify that the first certificate in the chain corresponds to
// the server we desire to authenticate. // the server we desire to authenticate.
if (!server.equals(peerIdentity)) { // Check if the certificate uses a wildcard indicating that subdomains are valid
if (peerIdentity.startsWith("*.")) {
// Remove the wildcard
peerIdentity = peerIdentity.replace("*.", "");
// Check if the requested subdomain matches the certified domain
if (!server.endsWith(peerIdentity)) {
throw new CertificateException("target verification failed of " + peerIdentity);
}
}
else if (!server.equals(peerIdentity)) {
throw new CertificateException("target verification failed of " + peerIdentity); throw new CertificateException("target verification failed of " + peerIdentity);
} }
// For every certificate in the chain, verify that the certificate if (JiveGlobals.getBooleanProperty("xmpp.server.certificate.verify.validity", true)) {
// is valid at the current time. // For every certificate in the chain, verify that the certificate
Date date = new Date(); // is valid at the current time.
for (int i = 0; i < nSize; i++) { Date date = new Date();
try { for (int i = 0; i < nSize; i++) {
x509Certificates[i].checkValidity(date); try {
} x509Certificates[i].checkValidity(date);
catch (GeneralSecurityException generalsecurityexception) { }
throw new CertificateException("invalid date of " + peerIdentity); catch (GeneralSecurityException generalsecurityexception) {
throw new CertificateException("invalid date of " + peerIdentity);
}
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment