From a5f2f134dc8f266f09bcd1981a8b184782fc0587 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Thu, 25 Aug 2011 02:36:40 +0000 Subject: [PATCH] Allow multiple cert hashes for a single hostname. Drop the protocol from XMPP SRVName construction for the cert validation. --- .../certificate/CertificateServiceImpl.java | 156 +++++++++++------- .../ProtocolProviderServiceJabberImpl.java | 2 +- 2 files changed, 96 insertions(+), 62 deletions(-) diff --git a/src/net/java/sip/communicator/impl/certificate/CertificateServiceImpl.java b/src/net/java/sip/communicator/impl/certificate/CertificateServiceImpl.java index 38d2641c8..921d9c63c 100644 --- a/src/net/java/sip/communicator/impl/certificate/CertificateServiceImpl.java +++ b/src/net/java/sip/communicator/impl/certificate/CertificateServiceImpl.java @@ -59,8 +59,27 @@ public class CertificateServiceImpl /** * Stores the certificates that are trusted as long as this service lives. */ - private Map sessionAllowedCertificates = - new HashMap(); + private Map> sessionAllowedCertificates = + new HashMap>(); + + /** + * Helper method to avoid accessing null-lists in the session allowed + * certificate map + * + * @param propName the key to access + * @return the list for the given list or a new, empty list put in place for + * the key + */ + private List getSessionCertEntry(String propName) + { + List entry = sessionAllowedCertificates.get(propName); + if (entry == null) + { + entry = new LinkedList(); + sessionAllowedCertificates.put(propName, entry); + } + return entry; + } /* * (non-Javadoc) @@ -73,6 +92,8 @@ public void addCertificateToTrust(Certificate cert, String trustFor, int trustMode) throws CertificateException { + String propName = PNAME_CERT_TRUST_PREFIX + ".param." + trustFor; + String thumbprint = getThumbprint(cert, THUMBPRINT_HASH_ALGORITHM); switch (trustMode) { case DO_NOT_TRUST: @@ -80,12 +101,14 @@ public void addCertificateToTrust(Certificate cert, String trustFor, "Cannot add a certificate to trust when " + "no trust is requested."); case TRUST_ALWAYS: - config.setProperty(PNAME_CERT_TRUST_PREFIX + ".param." + trustFor, - getThumbprint(cert, THUMBPRINT_HASH_ALGORITHM)); + String current = config.getString(propName); + String newValue = thumbprint; + if(current != null) + newValue += "," + thumbprint; + config.setProperty(propName, newValue); break; case TRUST_THIS_SESSION_ONLY: - sessionAllowedCertificates.put(PNAME_CERT_TRUST_PREFIX + ".param." - + trustFor, getThumbprint(cert, THUMBPRINT_HASH_ALGORITHM)); + getSessionCertEntry(propName).add(thumbprint); break; } } @@ -306,17 +329,19 @@ else if(serverCheck) { String thumbprint = getThumbprint( chain[0], THUMBPRINT_HASH_ALGORITHM); - String propName = null; String message = null; - String storedCert = null; + List propNames = new LinkedList(); + List storedCerts = new LinkedList(); String appName = R.getSettingsString("service.gui.APPLICATION_NAME"); if (identitiesToTest == null || !identitiesToTest.iterator().hasNext()) { - propName = + String propName = PNAME_CERT_TRUST_PREFIX + ".server." + thumbprint; + propNames.add(propName); + message = R.getI18NString("service.gui." + "CERT_DIALOG_DESCRIPTION_TXT_NOHOST", @@ -325,63 +350,65 @@ else if(serverCheck) } ); - // get the thumbprint from the permanent allowances - storedCert = config.getString(propName); - // not found? check the session allowances - if (storedCert == null) - storedCert = - sessionAllowedCertificates.get(propName); + // get the thumbprints from the permanent allowances + String hashes = config.getString(propName); + if (hashes != null) + for(String h : hashes.split(",")) + storedCerts.add(h); + + // get the thumbprints from the session allowances + List sessionCerts = + sessionAllowedCertificates.get(propName); + if (sessionCerts != null) + storedCerts.addAll(sessionCerts); } else { + if (serverCheck) + { + message = + R.getI18NString( + "service.gui." + + "CERT_DIALOG_DESCRIPTION_TXT", + new String[] { + appName, + identitiesToTest.toString() + } + ); + } + else + { + message = + R.getI18NString( + "service.gui." + + "CERT_DIALOG_PEER_DESCRIPTION_TXT", + new String[] { + appName, + identitiesToTest.toString() + } + ); + } for (String identity : identitiesToTest) { - if (serverCheck) - { - message = - R.getI18NString( - "service.gui." - + "CERT_DIALOG_DESCRIPTION_TXT", - new String[] { - appName, - identitiesToTest.toString() - } - ); - propName = - PNAME_CERT_TRUST_PREFIX + ".param." - + identity; - } - else - { - message = - R.getI18NString( - "service.gui." - + "CERT_DIALOG_PEER_DESCRIPTION_TXT", - new String[] { - appName, - identitiesToTest.toString() - } - ); - propName = - PNAME_CERT_TRUST_PREFIX + ".param." - + identity; - } - - // get the thumbprint from the permanent allowances - storedCert = config.getString(propName); - // not found? check the session allowances - if (storedCert == null) - storedCert = - sessionAllowedCertificates.get(propName); - - // stop search for further saved allowances if we - // found a match - if (storedCert != null) - break; + String propName = + PNAME_CERT_TRUST_PREFIX + ".param." + identity; + propNames.add(propName); + + // get the thumbprints from the permanent allowances + String hashes = config.getString(propName); + if (hashes != null) + for(String h : hashes.split(",")) + storedCerts.add(h); + + // get the thumbprints from the session allowances + List sessionCerts = + sessionAllowedCertificates.get(propName); + if (sessionCerts != null) + storedCerts.addAll(sessionCerts); } } - if (!thumbprint.equals(storedCert)) + if (!storedCerts.contains(thumbprint)) { switch (verify(chain, message)) { @@ -391,11 +418,18 @@ else if(serverCheck) + chain[0].getSubjectDN() + "> is not trusted"); case TRUST_ALWAYS: - config.setProperty(propName, thumbprint); + for (String propName : propNames) + { + String current = config.getString(propName); + String newValue = thumbprint; + if (current != null) + newValue += "," + current; + config.setProperty(propName, newValue); + } break; case TRUST_THIS_SESSION_ONLY: - sessionAllowedCertificates - .put(propName, thumbprint); + for(String propName : propNames) + getSessionCertEntry(propName).add(thumbprint); break; } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java index ca817a71e..684c036d1 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java @@ -847,7 +847,7 @@ private ConnectState connectAndLogin( cvs.getTrustManager( Arrays.asList(new String[]{ serviceName, - "_xmpp-client._tcp." + serviceName + "_xmpp-client." + serviceName }) ) )