Ignore manual entered SIP proxy data when autodetect is selected

Replace the CertificateVerificationService with CertificateService to correctly validate the hostname of servers
cusax-fix
Ingo Bauersachs 15 years ago
parent 27197bb56b
commit 60385be26e

@ -2366,7 +2366,9 @@ javax.swing.event, javax.swing.border"/>
<manifest>
<attribute name="Export-Package" value="org.bouncycastle.asn1,
org.bouncycastle.asn1.nist,
org.bouncycastle.asn1.pkcs,
org.bouncycastle.asn1.sec,
org.bouncycastle.asn1.x509,
org.bouncycastle.asn1.x9,
org.bouncycastle.crypto,
org.bouncycastle.crypto.agreement,

@ -504,7 +504,14 @@ service.gui.DECEMBER=Dec
service.gui.ALWAYS_TRUST=Always trust this certificate
service.gui.CERT_DIALOG_TITLE=Verify Certificate
service.gui.CERT_DIALOG_DESCRIPTION_TXT=<html>{0} can''t verify the identity \
of the server when connecting <br>to {1}:{2}.<br><br> \
of the server when connecting to<br>\
<b>{1}</b>.<br><br> \
The certificate is not trusted, which means that the server''s \
identity cannot be automatically verified.<br><br> \
Do you want to continue connecting?<br> \
For more information, click "Show Certificate".</html>
service.gui.CERT_DIALOG_DESCRIPTION_TXT_NOHOST=<html>{0} can''t verify the \
identity of the server''s certificate.<br><br> \
The certificate is not trusted, which means that the server''s \
identity cannot<br> be automatically verified. \
Do you want to continue connecting?<br><br> \
@ -515,12 +522,13 @@ The certificate is not trusted, which means that the client''s \
identity cannot<br> be automatically verified. \
Do you want to accept the connection?<br><br> \
For more information, click "Show Certificate".</html>
service.gui.CERT_DIALOG_PEER_DESCRIPTION_TXT=<html>The identity \
of the peer {0} could not be verified.<br><br> \
service.gui.CERT_DIALOG_PEER_DESCRIPTION_TXT=<html>{0} can''t verify the identity \
of the peer {0}.<br><br> \
The certificate is not trusted, which means that the peer''s \
identity cannot<br> be automatically verified. \
Do you want to continue connecting?<br><br> \
For more information, click "Show Certificate".</html>
service.gui.CONTINUE_ANYWAY=Continue anyway
service.gui.CERT_INFO_ISSUED_TO=<html><b>Issued To</b></html>
service.gui.CERT_INFO_CN=Common Name:
service.gui.CERT_INFO_O=Organization:
@ -1266,7 +1274,6 @@ plugin.loggingutils.ARCHIVE_MESSAGE_NOTOK=Error archiving logs \n{0}
# dns config plugin
plugin.dnsconfig.TITLE=Parallel DNS
plugin.dnsconfig.border.TITLE=Backup resolver
plugin.dnsconfig.ICON=
plugin.dnsconfig.chkBackupDnsEnabled.text=Enable parallel DNS resolving
plugin.dnsconfig.lblBackupResolver.text=Hostname
plugin.dnsconfig.lblBackupResolverFallbackIP.text=Fallback IP

@ -0,0 +1,692 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.certificate;
import java.io.*;
import java.net.*;
import java.security.*;
import java.security.cert.*;
import java.security.cert.Certificate;
import java.util.*;
import javax.net.ssl.*;
import javax.swing.*;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.asn1.x509.X509Extension;
import net.java.sip.communicator.service.certificate.*;
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.httputil.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
/**
* Implementation of the CertificateService. It asks the user to trust a
* certificate when the automatic verification fails.
*
* @author Ingo Bauersachs
*/
public class CertificateServiceImpl
implements CertificateService
{
// services
private static final Logger logger =
Logger.getLogger(CertificateServiceImpl.class);
private final ResourceManagementService R =
CertificateVerificationActivator.getResources();
private final ConfigurationService config =
CertificateVerificationActivator.getConfigurationService();
// properties
/**
* Base property name for the storage of certificate user preferences.
*/
private final static String PNAME_CERT_TRUST_PREFIX =
"net.java.sip.communicator.impl.certservice";
/** Hash algorithm for the cert thumbprint*/
private final static String THUMBPRINT_HASH_ALGORITHM = "SHA1";
// variables
/**
* Stores the certificates that are trusted as long as this service lives.
*/
private Map<String, String> sessionAllowedCertificates =
new HashMap<String, String>();
/*
* (non-Javadoc)
*
* @see net.java.sip.communicator.service.certificate.CertificateService#
* addCertificateToTrust(java.security.cert.Certificate, java.lang.String,
* int)
*/
public void addCertificateToTrust(Certificate cert, String trustFor,
int trustMode)
throws CertificateException
{
switch (trustMode)
{
case DO_NOT_TRUST:
throw new IllegalArgumentException(
"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));
break;
case TRUST_THIS_SESSION_ONLY:
sessionAllowedCertificates.put(PNAME_CERT_TRUST_PREFIX + ".param."
+ trustFor, getThumbprint(cert, THUMBPRINT_HASH_ALGORITHM));
break;
}
}
/*
* (non-Javadoc)
*
* @see net.java.sip.communicator.service.certificate.CertificateService#
* getSSLContext()
*/
public SSLContext getSSLContext() throws GeneralSecurityException
{
return getSSLContext(getTrustManager((Iterable<String>)null));
}
/*
* (non-Javadoc)
*
* @see net.java.sip.communicator.service.certificate.CertificateService#
* getSSLContext(javax.net.ssl.X509TrustManager)
*/
public SSLContext getSSLContext(X509TrustManager trustManager)
throws GeneralSecurityException
{
try
{
KeyStore ks =
KeyStore.getInstance(System.getProperty(
"javax.net.ssl.keyStoreType", KeyStore.getDefaultType()));
KeyManagerFactory kmFactory =
KeyManagerFactory.getInstance(KeyManagerFactory
.getDefaultAlgorithm());
String keyStorePassword =
System.getProperty("javax.net.ssl.keyStorePassword");
if (System.getProperty("javax.net.ssl.keyStore") != null)
{
ks.load(
new FileInputStream(System
.getProperty("javax.net.ssl.keyStore")), null);
}
else
{
ks.load(null, null);
}
kmFactory.init(ks, keyStorePassword == null ? null
: keyStorePassword.toCharArray());
//TODO: inject our own socket factory to use our own DNS stuff
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmFactory.getKeyManagers(), new TrustManager[]
{ trustManager }, null);
return sslContext;
}
catch (Exception e)
{
throw new GeneralSecurityException("Cannot init SSLContext: "
+ e.getMessage());
}
}
/*
* (non-Javadoc)
*
* @see
* net.java.sip.communicator.service.certificate
* .CertificateService#getTrustManager(java.lang.Iterable)
*/
public X509TrustManager getTrustManager(Iterable<String> identitiesToTest)
throws GeneralSecurityException
{
return getTrustManager(
identitiesToTest,
new EMailAddressMatcher(),
new BrowserLikeHostnameMatcher()
);
}
/*
* (non-Javadoc)
*
* @see
* net.java.sip.communicator.service.certificate.CertificateService
* #getTrustManager(java.lang.String)
*/
public X509TrustManager getTrustManager(String identityToTest)
throws GeneralSecurityException
{
return getTrustManager(
Arrays.asList(new String[]{identityToTest}),
new EMailAddressMatcher(),
new BrowserLikeHostnameMatcher()
);
}
/*
* (non-Javadoc)
*
* @see
* net.java.sip.communicator.service.certificate.CertificateService
* #getTrustManager(java.lang.String,
* net.java.sip.communicator.service.certificate.CertificateMatcher,
* net.java.sip.communicator.service.certificate.CertificateMatcher)
*/
public X509TrustManager getTrustManager(
String identityToTest,
CertificateMatcher clientVerifier,
CertificateMatcher serverVerifier)
throws GeneralSecurityException
{
return getTrustManager(
Arrays.asList(new String[]{identityToTest}),
clientVerifier,
serverVerifier
);
}
/*
* (non-Javadoc)
*
* @see
* net.java.sip.communicator.service.certificate.CertificateService
* #getTrustManager(java.lang.Iterable,
* net.java.sip.communicator.service.certificate.CertificateMatcher,
* net.java.sip.communicator.service.certificate.CertificateMatcher)
*/
public X509TrustManager getTrustManager(
final Iterable<String> identitiesToTest,
final CertificateMatcher clientVerifier,
final CertificateMatcher serverVerifier)
throws GeneralSecurityException
{
// obtain the default X509 trust manager
X509TrustManager defaultTm = null;
TrustManagerFactory tmFactory =
TrustManagerFactory.getInstance(TrustManagerFactory
.getDefaultAlgorithm());
tmFactory.init((KeyStore) null);
for (TrustManager m : tmFactory.getTrustManagers())
{
if (m instanceof X509TrustManager)
{
defaultTm = (X509TrustManager) m;
break;
}
}
if (defaultTm == null)
throw new GeneralSecurityException(
"No default X509 trust manager found");
final X509TrustManager tm = defaultTm;
return new X509TrustManager()
{
private boolean serverCheck;
public X509Certificate[] getAcceptedIssuers()
{
return tm.getAcceptedIssuers();
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException
{
serverCheck = true;
checkCertTrusted(chain, authType);
}
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException
{
serverCheck = false;
checkCertTrusted(chain, authType);
}
private void checkCertTrusted(X509Certificate[] chain,
String authType) throws CertificateException
{
if(config.getBoolean(PNAME_ALWAYS_TRUST, false))
return;
try
{
// check the certificate itself (issuer, validity)
try
{
chain = tryBuildChain(chain);
}
catch (Exception e)
{} // don't care and take the chain as is
if(serverCheck)
tm.checkServerTrusted(chain, authType);
else
tm.checkClientTrusted(chain, authType);
if(identitiesToTest == null
|| !identitiesToTest.iterator().hasNext())
return;
else if(serverCheck)
serverVerifier.verify(identitiesToTest, chain[0]);
else
clientVerifier.verify(identitiesToTest, chain[0]);
// ok, globally valid cert
}
catch (CertificateException e)
{
String thumbprint = getThumbprint(
chain[0], THUMBPRINT_HASH_ALGORITHM);
String propName = null;
String message = null;
String storedCert = null;
String appName =
R.getSettingsString("service.gui.APPLICATION_NAME");
if (identitiesToTest == null
|| !identitiesToTest.iterator().hasNext())
{
propName =
PNAME_CERT_TRUST_PREFIX + ".server." + thumbprint;
message =
R.getI18NString("service.gui."
+ "CERT_DIALOG_DESCRIPTION_TXT_NOHOST",
new String[] {
appName
}
);
// get the thumbprint from the permanent allowances
storedCert = config.getString(propName);
// not found? check the session allowances
if (storedCert == null)
storedCert =
sessionAllowedCertificates.get(propName);
}
else
{
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;
}
}
if (!thumbprint.equals(storedCert))
{
switch (verify(chain, message))
{
case DO_NOT_TRUST:
throw new CertificateException(
"The peer provided certificate with Subject <"
+ chain[0].getSubjectDN()
+ "> is not trusted");
case TRUST_ALWAYS:
config.setProperty(propName, thumbprint);
break;
case TRUST_THIS_SESSION_ONLY:
sessionAllowedCertificates
.put(propName, thumbprint);
break;
}
}
// ok, we've seen this certificate before
}
}
private X509Certificate[] tryBuildChain(X509Certificate[] chain)
throws IOException,
URISyntaxException,
CertificateException
{
// Only try to build chains for servers that send only their
// own cert, but no issuer. This also matches self signed (will
// be ignored later) and Root-CA signed certs. In this case we
// throw the Root-CA away after the lookup
if (chain.length != 1)
return chain;
// ignore self signed certs
if (chain[0].getIssuerDN().equals(chain[0].getSubjectDN()))
return chain;
// prepare for the newly created chain
List<X509Certificate> newChain =
new ArrayList<X509Certificate>(chain.length + 4);
for (X509Certificate cert : chain)
{
newChain.add(cert);
}
// search from the topmost certificate upwards
CertificateFactory certFactory =
CertificateFactory.getInstance("X.509");
X509Certificate current = chain[chain.length - 1];
boolean foundParent;
int chainLookupCount = 0;
do
{
foundParent = false;
// extract the url(s) where the parent certificate can be
// found
byte[] aiaBytes =
current.getExtensionValue(
X509Extension.authorityInfoAccess.getId());
if (aiaBytes == null)
break;
DEROctetString octs =
(DEROctetString) ASN1Object.fromByteArray(aiaBytes);
ASN1InputStream as = new ASN1InputStream(octs.getOctets());
AuthorityInformationAccess aia =
AuthorityInformationAccess
.getInstance(as.readObject());
// the AIA may contain different URLs and types, try all
// of them
for (AccessDescription ad : aia.getAccessDescriptions())
{
// we are only interested in the issuer certificate,
// not in OCSP urls the like
if (!ad.getAccessMethod().equals(
AccessDescription.id_ad_caIssuers))
continue;
GeneralName gn = ad.getAccessLocation();
if (!(gn.getTagNo() ==
GeneralName.uniformResourceIdentifier
&& gn.getName() instanceof DERIA5String))
continue;
URI uri =
new URI(((DERIA5String) gn.getName()).getString());
// only http(s) urls; LDAP is taken care of in the
// default implementation
if (!(uri.getScheme().equalsIgnoreCase("http") || uri
.getScheme().equals("https")))
continue;
if (logger.isDebugEnabled())
logger
.debug("Downloading parent certificate for <"
+ current.getSubjectDN()
+ "> from <"
+ uri
+ ">");
try
{
InputStream is =
HttpUtils.openURLConnection(uri.toString())
.getContent();
X509Certificate cert =
(X509Certificate) certFactory
.generateCertificate(is);
if(!cert.getIssuerDN().equals(cert.getSubjectDN()))
{
newChain.add(cert);
foundParent = true;
current = cert;
break; // an AD was valid, ignore others
}
else
logger.debug("Parent is self-signed, ignoring");
}
catch (Exception e)
{
logger.debug("Could not download from <" + uri
+ ">");
}
}
chainLookupCount++;
}
while (foundParent && chainLookupCount < 10);
chain = newChain.toArray(chain);
return chain;
}
};
}
protected class BrowserLikeHostnameMatcher
implements CertificateMatcher
{
public void verify(Iterable<String> identitiesToTest,
X509Certificate cert) throws CertificateException
{
// check whether one of the hostname is present in the
// certificate
boolean oneMatched = false;
for(String identity : identitiesToTest)
{
try
{
org.apache.http.conn.ssl.SSLSocketFactory
.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
.verify(identity, cert);
oneMatched = true;
break;
}
catch (SSLException e)
{}
}
if (!oneMatched)
throw new CertificateException("None of <"
+ identitiesToTest
+ "> matched the cert with CN="
+ cert.getSubjectDN());
}
}
protected class EMailAddressMatcher
implements CertificateMatcher
{
public void verify(Iterable<String> identitiesToTest,
X509Certificate cert) throws CertificateException
{
// check if the certificate contains the E-Mail address(es)
// in the SAN(s)
//TODO: extract address from DN (E-field) too?
boolean oneMatched = false;
Iterable<String> emails = getSubjectAltNames(cert, 6);
for(String identity : identitiesToTest)
{
for(String email : emails)
{
if(identity.equalsIgnoreCase(email))
{
oneMatched = true;
break;
}
}
}
if(!oneMatched)
throw new CertificateException(
"The peer provided certificate with Subject <"
+ cert.getSubjectDN()
+ "> contains no SAN for <"
+ identitiesToTest + ">");
}
}
/**
* Asks the user whether he trusts the supplied chain of certificates.
*
* @param chain The chain of the certificates to check with user.
* @param message A text that describes why the verification failed.
* @return The result of the user interaction. One of
* {@link CertificateService#DO_NOT_TRUST},
* {@link CertificateService#TRUST_THIS_SESSION_ONLY},
* {@link CertificateService#TRUST_ALWAYS}
*/
protected int verify(final X509Certificate[] chain, final String message)
{
if(config.getBoolean(PNAME_NO_USER_INTERACTION, false))
return DO_NOT_TRUST;
final VerifyCertificateDialog dialog =
new VerifyCertificateDialog(chain, null, message);
try
{
// show the dialog in the swing thread and wait for the user
// choice
SwingUtilities.invokeAndWait(new Runnable()
{
public void run()
{
dialog.setVisible(true);
}
});
}
catch (Exception e)
{
logger.error("Cannot show certificate verification dialog", e);
return DO_NOT_TRUST;
}
if(!dialog.isTrusted)
return DO_NOT_TRUST;
else if(dialog.alwaysTrustCheckBox.isSelected())
return TRUST_ALWAYS;
else
return TRUST_THIS_SESSION_ONLY;
}
/**
* Calculates the hash of the certificate known as the "thumbprint"
* and returns it as a string representation.
*
* @param cert The certificate to hash.
* @param algorithm The hash algorithm to use.
* @return The SHA-1 hash of the certificate.
* @throws CertificateException
*/
static String getThumbprint(Certificate cert, String algorithm)
throws CertificateException
{
MessageDigest digest;
try
{
digest = MessageDigest.getInstance(algorithm);
}
catch (NoSuchAlgorithmException e)
{
throw new CertificateException(e);
}
byte[] encodedCert = cert.getEncoded();
StringBuilder sb = new StringBuilder(encodedCert.length * 2);
Formatter f = new Formatter(sb);
for (byte b : digest.digest(encodedCert))
{
f.format("%02x", b);
}
return sb.toString();
}
/**
* Gets the SAN (Subject Alternative Name) of the specified type.
*
* @param cert the certificate to extract from
* @param altNameType The type to be returned
* @return SAN of the type
*
* <PRE>
* GeneralName ::= CHOICE {
* otherName [0] OtherName,
* rfc822Name [1] IA5String,
* dNSName [2] IA5String,
* x400Address [3] ORAddress,
* directoryName [4] Name,
* ediPartyName [5] EDIPartyName,
* uniformResourceIdentifier [6] IA5String,
* iPAddress [7] OCTET STRING,
* registeredID [8] OBJECT IDENTIFIER
* }
* <PRE>
*/
private static Iterable<String> getSubjectAltNames(X509Certificate cert,
int altNameType)
{
Collection<List<?>> altNames = null;
try
{
altNames = cert.getSubjectAlternativeNames();
}
catch (CertificateParsingException e)
{
return Collections.emptyList();
}
List<String> matchedAltNames = new LinkedList<String>();
for (List<?> item : altNames)
{
if (item.contains(altNameType))
{
Integer type = (Integer) item.get(0);
if (type.intValue() == altNameType)
matchedAltNames.add((String) item.get(1));
}
}
return matchedAltNames;
}
}

@ -53,8 +53,8 @@ public void start(BundleContext bc) throws Exception
bundleContext = bc;
bundleContext.registerService(
CertificateVerificationService.class.getName(),
new CertificateVerificationServiceImpl(),
CertificateService.class.getName(),
new CertificateServiceImpl(),
null);
}

@ -32,9 +32,11 @@
* Asks the user for permission for the
* certificates which are for some reason not valid and not globally trusted.
*
* @deprecated Use the new {@link CertificateService}
* @author Damian Minkov
* @author Yana Stamcheva
*/
@Deprecated
public class CertificateVerificationServiceImpl
implements CertificateVerificationService
{

@ -0,0 +1,659 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.certificate;
import java.awt.*;
import java.awt.event.*;
import java.security.cert.*;
import java.security.interfaces.*;
import java.text.*;
import java.util.Formatter;
import javax.naming.*;
import javax.naming.ldap.*;
import javax.security.auth.x500.*;
import javax.swing.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.swing.*;
/**
* Dialog that is shown to the user when a certificate verification failed.
*/
class VerifyCertificateDialog
extends SIPCommDialog
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
private ResourceManagementService R = CertificateVerificationActivator
.getResources();
/**
* Date formatter.
*/
private DateFormat dateFormatter = DateFormat
.getDateInstance(DateFormat.MEDIUM);
/**
* The maximum width that we allow message dialogs to have.
*/
private static final int MAX_MSG_PANE_WIDTH = 600;
/**
* The maximum height that we allow message dialogs to have.
*/
private static final int MAX_MSG_PANE_HEIGHT = 800;
/**
* The certificate to show.
*/
Certificate cert;
/**
* A text that describes why the verification failed.
*/
String message;
/**
* The certificate panel.
*/
TransparentPanel certPanel;
/**
* This dialog content pane.
*/
TransparentPanel contentPane;
/**
* Whether certificate description is shown.
*/
boolean certOpened = false;
/**
* The button to show certificate description.
*/
JButton certButton;
/**
* The check box if checked permanently stored the certificate
* which will be always trusted.
*/
SIPCommCheckBox alwaysTrustCheckBox = new SIPCommCheckBox(
R.getI18NString("service.gui.ALWAYS_TRUST"),
false);
/**
* Whether the user trusts this certificate.
*/
boolean isTrusted = false;
/**
* Creates the dialog.
*
* @param certs the certificates list
* @param title The title of the dialog; when null the resource
* <tt>service.gui.CERT_DIALOG_TITLE</tt> is loaded.
* @param message A text that describes why the verification failed.
*/
public VerifyCertificateDialog( Certificate[] certs,
String title, String message)
{
super(false);
setTitle(title != null ? title :
R.getI18NString("service.gui.CERT_DIALOG_TITLE"));
setModal(true);
// for now shows only the first certificate from the chain
this.cert = certs[0];
this.message = message;
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
init();
setLocationRelativeTo(getParent());
}
/**
* Inits the dialog initial display.
*/
private void init()
{
this.getContentPane().setLayout(new BorderLayout());
contentPane =
new TransparentPanel(new BorderLayout(5, 5));
TransparentPanel northPanel =
new TransparentPanel(new BorderLayout(5, 5));
northPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 5));
JLabel imgLabel = new JLabel(
R.getImage("service.gui.icons.WARNING_ICON"));
imgLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
northPanel.add(imgLabel, BorderLayout.WEST);
StyledHTMLEditorPane descriptionPane = new StyledHTMLEditorPane();
descriptionPane.setOpaque(false);
descriptionPane.setEditable(false);
descriptionPane.setContentType("text/html");
descriptionPane.setText(message);
descriptionPane.setSize(
new Dimension(MAX_MSG_PANE_WIDTH, MAX_MSG_PANE_HEIGHT));
int height = descriptionPane.getPreferredSize().height;
descriptionPane.setPreferredSize(
new Dimension(MAX_MSG_PANE_WIDTH, height));
northPanel.add(descriptionPane, BorderLayout.CENTER);
contentPane.add(northPanel, BorderLayout.NORTH);
certPanel = new TransparentPanel();
contentPane.add(certPanel, BorderLayout.CENTER);
TransparentPanel southPanel =
new TransparentPanel(new BorderLayout());
contentPane.add(southPanel, BorderLayout.SOUTH);
certButton = new JButton();
certButton.setText(R.getI18NString("service.gui.SHOW_CERT"));
certButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
actionShowCertificate();
}
});
TransparentPanel firstButonPanel =
new TransparentPanel(new FlowLayout(FlowLayout.LEFT));
firstButonPanel.add(certButton);
southPanel.add(firstButonPanel, BorderLayout.WEST);
TransparentPanel secondButonPanel =
new TransparentPanel(new FlowLayout(FlowLayout.RIGHT));
JButton cancelButton = new JButton(
R.getI18NString("service.gui.CANCEL"));
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
actionCancel();
}
});
JButton continueButton = new JButton(
R.getI18NString("service.gui.CONTINUE_ANYWAY"));
continueButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
actionContinue();
}
});
secondButonPanel.add(continueButton);
secondButonPanel.add(cancelButton);
southPanel.add(secondButonPanel, BorderLayout.EAST);
this.getContentPane().add(contentPane, BorderLayout.CENTER);
pack();
}
/**
* Action when shoe certificate button is clicked.
*/
private void actionShowCertificate()
{
if(certOpened)
{
certPanel.removeAll();
certButton.setText(R.getI18NString("service.gui.SHOW_CERT"));
certPanel.revalidate();
certPanel.repaint();
pack();
certOpened = false;
setLocationRelativeTo(getParent());
return;
}
certPanel.setLayout(new BorderLayout());
certPanel.add(alwaysTrustCheckBox, BorderLayout.NORTH);
Component certInfoPane = null;
if(cert instanceof X509Certificate)
{
certInfoPane = getX509DisplayComponent((X509Certificate)cert);
}
else
{
JTextArea textArea = new JTextArea();
textArea.setOpaque(false);
textArea.setEditable(false);
textArea.setText(cert.toString());
certInfoPane = textArea;
}
final JScrollPane certScroll = new JScrollPane(certInfoPane);
certScroll.setPreferredSize(new Dimension(300, 300));
certPanel.add(certScroll, BorderLayout.CENTER);
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
certScroll.getVerticalScrollBar().setValue(0);
}
});
certButton.setText(R.getI18NString("service.gui.HIDE_CERT"));
certPanel.revalidate();
certPanel.repaint();
// restore default values for prefered size,
// as we have resized its components let it calculate
// that size
setPreferredSize(null);
pack();
certOpened = true;
setLocationRelativeTo(getParent());
}
/**
* Action when cancel button is clicked.
*/
private void actionCancel()
{
isTrusted = false;
dispose();
}
/**
* Action when continue is clicked.
*/
private void actionContinue()
{
isTrusted = true;
dispose();
}
/**
* Called when dialog closed or escape pressed.
* @param isEscaped is escape button pressed.
*/
protected void close(boolean isEscaped)
{
actionCancel();
}
/**
* Returns the display component for X509 certificate.
*
* @param certificate the certificate to show
* @return the created component
*/
private Component getX509DisplayComponent(
X509Certificate certificate)
{
Insets valueInsets = new Insets(2,10,0,0);
Insets titleInsets = new Insets(10,5,0,0);
TransparentPanel certDisplayPanel
= new TransparentPanel(new GridBagLayout());
int currentRow = 0;
GridBagConstraints constraints = new GridBagConstraints();
constraints.anchor = GridBagConstraints.WEST;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.insets = new Insets(2,5,0,0);
constraints.gridx = 0;
constraints.weightx = 0;
constraints.weighty = 0;
constraints.gridy = currentRow++;
X500Principal issuer = certificate.getIssuerX500Principal();
X500Principal subject = certificate.getSubjectX500Principal();
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_ISSUED_TO")),
constraints);
// subject
constraints.insets = valueInsets;
try
{
for(Rdn name : new LdapName(subject.getName()).getRdns())
{
constraints.gridy = currentRow++;
constraints.gridx = 0;
String lbl =
R.getI18NString("service.gui.CERT_INFO_" + name.getType());
if (lbl
.equals("!service.gui.CERT_INFO_" + name.getType() + "!"))
lbl = name.getType();
certDisplayPanel.add(new JLabel(lbl), constraints);
constraints.gridx = 1;
certDisplayPanel.add(
new JLabel(
name.getValue() instanceof byte[] ?
getHex((byte[])name.getValue()) + " ("
+ new String((byte[]) name.getValue()) + ")"
: name.getValue().toString()),
constraints);
}
}
catch (InvalidNameException e1)
{
constraints.gridy = currentRow++;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_CN")),
constraints);
constraints.gridx = 1;
certDisplayPanel.add(
new JLabel(subject.getName()),
constraints);
}
// issuer
constraints.gridy = currentRow++;
constraints.gridx = 0;
constraints.insets = titleInsets;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_ISSUED_BY")),
constraints);
constraints.insets = valueInsets;
try
{
for(Rdn name : new LdapName(issuer.getName()).getRdns())
{
constraints.gridy = currentRow++;
constraints.gridx = 0;
constraints.gridx = 0;
String lbl =
R.getI18NString("service.gui.CERT_INFO_" + name.getType());
if (lbl
.equals("!service.gui.CERT_INFO_" + name.getType() + "!"))
lbl = name.getType();
certDisplayPanel.add(new JLabel(lbl), constraints);
constraints.gridx = 1;
certDisplayPanel.add(
new JLabel(
name.getValue() instanceof byte[] ?
getHex((byte[])name.getValue()) + " ("
+ new String((byte[]) name.getValue()) + ")"
: name.getValue().toString()),
constraints);
}
}
catch (InvalidNameException e1)
{
constraints.gridy = currentRow++;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_CN")),
constraints);
constraints.gridx = 1;
certDisplayPanel.add(
new JLabel(issuer.getName()),
constraints);
}
// validity
constraints.gridy = currentRow++;
constraints.gridx = 0;
constraints.insets = titleInsets;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_VALIDITY")),
constraints);
constraints.insets = valueInsets;
constraints.gridy = currentRow++;
constraints.gridx = 0;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_ISSUED_ON")),
constraints);
constraints.gridx = 1;
certDisplayPanel.add(
new JLabel(dateFormatter.format(certificate.getNotBefore())),
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_EXPIRES_ON")),
constraints);
constraints.gridx = 1;
certDisplayPanel.add(
new JLabel(dateFormatter.format(certificate.getNotAfter())),
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
constraints.insets = titleInsets;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_FINGERPRINTS")),
constraints);
constraints.insets = valueInsets;
try
{
String sha1String = CertificateServiceImpl.getThumbprint(certificate, "SHA1");
String md5String = CertificateServiceImpl.getThumbprint(certificate, "MD5");
JTextArea sha1Area = new JTextArea(sha1String);
sha1Area.setLineWrap(false);
sha1Area.setOpaque(false);
sha1Area.setWrapStyleWord(true);
sha1Area.setEditable(false);
constraints.gridy = currentRow++;
constraints.gridx = 0;
certDisplayPanel.add(new JLabel("SHA1:"),
constraints);
constraints.gridx = 1;
certDisplayPanel.add(
sha1Area,
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
certDisplayPanel.add(new JLabel("MD5:"),
constraints);
JTextArea md5Area = new JTextArea(md5String);
md5Area.setLineWrap(false);
md5Area.setOpaque(false);
md5Area.setWrapStyleWord(true);
md5Area.setEditable(false);
constraints.gridx = 1;
certDisplayPanel.add(
md5Area,
constraints);
}
catch (Exception e)
{
// do nothing as we cannot show this value
}
constraints.gridy = currentRow++;
constraints.gridx = 0;
constraints.insets = titleInsets;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_CERT_DETAILS")),
constraints);
constraints.insets = valueInsets;
constraints.gridy = currentRow++;
constraints.gridx = 0;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_SER_NUM")),
constraints);
constraints.gridx = 1;
certDisplayPanel.add(
new JLabel(certificate.getSerialNumber().toString()),
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_VER")),
constraints);
constraints.gridx = 1;
certDisplayPanel.add(
new JLabel(String.valueOf(certificate.getVersion())),
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_SIGN_ALG")),
constraints);
constraints.gridx = 1;
certDisplayPanel.add(
new JLabel(String.valueOf(certificate.getSigAlgName())),
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
constraints.insets = titleInsets;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_PUB_KEY_INFO")),
constraints);
constraints.insets = valueInsets;
constraints.gridy = currentRow++;
constraints.gridx = 0;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_ALG")),
constraints);
constraints.gridx = 1;
certDisplayPanel.add(
new JLabel(certificate.getPublicKey().getAlgorithm()),
constraints);
if(certificate.getPublicKey().getAlgorithm().equals("RSA"))
{
RSAPublicKey key = (RSAPublicKey)certificate.getPublicKey();
constraints.gridy = currentRow++;
constraints.gridx = 0;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_PUB_KEY")),
constraints);
JTextArea pubkeyArea = new JTextArea(
R.getI18NString(
"service.gui.CERT_INFO_KEY_BYTES_PRINT",
new String[]{
String.valueOf(key.getModulus().toByteArray().length - 1),
key.getModulus().toString(16)
}));
pubkeyArea.setLineWrap(false);
pubkeyArea.setOpaque(false);
pubkeyArea.setWrapStyleWord(true);
pubkeyArea.setEditable(false);
constraints.gridx = 1;
certDisplayPanel.add(
pubkeyArea,
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_EXP")),
constraints);
constraints.gridx = 1;
certDisplayPanel.add(
new JLabel(key.getPublicExponent().toString()),
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_KEY_SIZE")),
constraints);
constraints.gridx = 1;
certDisplayPanel.add(
new JLabel(R.getI18NString(
"service.gui.CERT_INFO_KEY_BITS_PRINT",
new String[]{
String.valueOf(key.getModulus().bitLength())})),
constraints);
}
else if(certificate.getPublicKey().getAlgorithm().equals("DSA"))
{
DSAPublicKey key =
(DSAPublicKey)certificate.getPublicKey();
constraints.gridy = currentRow++;
constraints.gridx = 0;
certDisplayPanel.add(new JLabel("Y:"), constraints);
JTextArea yArea = new JTextArea(key.getY().toString(16));
yArea.setLineWrap(false);
yArea.setOpaque(false);
yArea.setWrapStyleWord(true);
yArea.setEditable(false);
constraints.gridx = 1;
certDisplayPanel.add(
yArea,
constraints);
}
constraints.gridy = currentRow++;
constraints.gridx = 0;
certDisplayPanel.add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_SIGN")),
constraints);
JTextArea signArea = new JTextArea(
R.getI18NString(
"service.gui.CERT_INFO_KEY_BYTES_PRINT",
new String[]{
String.valueOf(certificate.getSignature().length),
getHex(certificate.getSignature())
}));
signArea.setLineWrap(false);
signArea.setOpaque(false);
signArea.setWrapStyleWord(true);
signArea.setEditable(false);
constraints.gridx = 1;
certDisplayPanel.add(
signArea,
constraints);
return certDisplayPanel;
}
/**
* Converts the byte array to hex string.
* @param raw the data.
* @return the hex string.
*/
public String getHex( byte [] raw )
{
if (raw == null)
return null;
StringBuilder hex = new StringBuilder(2 * raw.length);
Formatter f = new Formatter(hex);
for (byte b : raw)
{
f.format("%02x", b);
}
return hex.toString();
}
}

@ -11,8 +11,12 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.fileaccess,
net.java.sip.communicator.service.configuration,
net.java.sip.communicator.util.swing,
net.java.sip.communicator.service.httputil,
javax.net.ssl,
javax.security.auth.x500,
javax.naming,
javax.naming.ldap,
javax.swing
javax.swing,
org.apache.http.conn.ssl,
org.bouncycastle.asn1,
org.bouncycastle.asn1.x509

@ -231,7 +231,7 @@ public class ProtocolProviderServiceJabberImpl
/**
* The service we use to interact with user.
*/
private CertificateVerificationService guiVerification;
private CertificateService guiVerification;
/**
* Used with tls connecting when certificates are not trusted
@ -241,12 +241,6 @@ public class ProtocolProviderServiceJabberImpl
*/
private boolean abortConnecting = false;
/**
* Shows whether we have already checked the certificate for current server.
* In case we use TLS.
*/
private boolean certChecked = false;
/**
* Flag indicating are we currently executing connectAndLogin method.
*/
@ -333,15 +327,15 @@ else if(connection.isConnected() && connection.isAuthenticated())
* Return the certificate verification service impl.
* @return the CertificateVerification service.
*/
private CertificateVerificationService getCertificateVerificationService()
private CertificateService getCertificateVerificationService()
{
if(guiVerification == null)
{
ServiceReference guiVerifyReference
= JabberActivator.getBundleContext().getServiceReference(
CertificateVerificationService.class.getName());
CertificateService.class.getName());
if(guiVerifyReference != null)
guiVerification = (CertificateVerificationService)
guiVerification = (CertificateService)
JabberActivator.getBundleContext().getService(
guiVerifyReference);
}
@ -844,22 +838,20 @@ private ConnectState connectAndLogin(
try
{
CertificateVerificationService gvs =
CertificateService cvs =
getCertificateVerificationService();
if(gvs != null)
if(cvs != null)
{
connection.setCustomTrustManager(
new HostTrustManager(gvs.getTrustManager(
JabberActivator.getResources().getI18NString(
"service.gui.CERT_DIALOG_DESCRIPTION_TXT",
new String[]{ JabberActivator.getResources().
getSettingsString(
"service.gui.APPLICATION_NAME"),
address, Integer.toString(serverPort)
}
new HostTrustManager(
cvs.getTrustManager(
Arrays.asList(new String[]{
serviceName,
"_xmpp-client._tcp." + serviceName
})
)
)
));
);
}
}
catch(GeneralSecurityException e)
@ -870,7 +862,7 @@ private ConnectState connectAndLogin(
if(debugger == null)
debugger = new SmackPacketDebugger();
// setts the debugger
// sets the debugger
debugger.setConnection(connection);
connection.addPacketListener(debugger, null);
connection.addPacketInterceptor(debugger, null);
@ -1901,13 +1893,9 @@ public void checkClientTrusted(X509Certificate[] chain, String authType)
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
if(certChecked)
return;
abortConnecting = true;
try
{
certChecked = true;
tm.checkServerTrusted(chain, authType);
}
catch(CertificateException e)

@ -68,7 +68,7 @@ public class ProtocolProviderServiceSipImpl
/**
* The AddressFactory used to create URLs ans Address objects.
*/
private AddressFactory addressFactory;
private AddressFactoryEx addressFactory;
/**
* The HeaderFactory used to create SIP message headers.
@ -1258,8 +1258,8 @@ public ArrayList<ViaHeader> getLocalViaHeaders(SipURI intendedDestination)
int localPort = srcListeningPoint.getPort();
String transport = srcListeningPoint.getTransport();
if (ListeningPoint.TCP.equalsIgnoreCase(transport))
//|| ListeningPoint.TLS.equalsIgnoreCase(transport)
if (ListeningPoint.TCP.equalsIgnoreCase(transport)
|| ListeningPoint.TLS.equalsIgnoreCase(transport))
{
InetSocketAddress localSockAddr
= sipStackSharing.getLocalAddressForDestination(
@ -1488,7 +1488,7 @@ public String getContactAddressCustomParamValue()
*
* @return the AddressFactory used to create URLs ans Address objects.
*/
public AddressFactory getAddressFactory()
public AddressFactoryEx getAddressFactory()
{
return addressFactory;
}
@ -1886,6 +1886,22 @@ public InetSocketAddress getOutboundProxy()
return this.outboundProxySocketAddress;
}
/**
* Compares an InetAddress against the active outbound proxy. The comparison
* is by reference, not equals.
*
* @param addressToTest The addres to test.
* @return True when the InetAddress is the same as the outbound proxy.
*/
public boolean matchesInetAddress(InetAddress addressToTest)
{
// if the proxy is not yet initialized then this is not the provider that
// caused this comparison
if(outboundProxySocketAddress == null)
return false;
return addressToTest == outboundProxySocketAddress.getAddress();
}
/**
* In case we are using an outbound proxy this method returns the transport
* we are using to connect to it. The method returns <tt>null</tt>
@ -1915,7 +1931,9 @@ void initOutboundProxy(SipAccountID accountID, int ix)
PROXY_ADDRESS);
boolean proxyAddressAndPortEntered = false;
if(proxyAddressStr == null || proxyAddressStr.trim().length() == 0)
if(proxyAddressStr == null || proxyAddressStr.trim().length() == 0
|| accountID.getAccountPropertyBoolean(
ProtocolProviderFactory.PROXY_AUTO_CONFIG, false))
{
String userID = accountID.getAccountPropertyString(
ProtocolProviderFactory.USER_ID);
@ -2907,6 +2925,7 @@ public void resolveSipAddress(
// resulting InetSocketAddress because its constructor
// suppresses UnknownHostException-s and we want to know if
// something goes wrong.
@SuppressWarnings("unused")
InetAddress addressObj = InetAddress.getByName(address);
}
}

@ -11,7 +11,9 @@
import net.java.sip.communicator.service.packetlogging.*;
import org.osgi.framework.*;
import net.java.sip.communicator.service.certificate.*;
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.fileaccess.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.hid.*;
@ -38,8 +40,10 @@ public class SipActivator
private static MediaService mediaService = null;
private static VersionService versionService = null;
private static UIService uiService = null;
private static HIDService hidService = null;
private static HIDService hidService = null;
private static PacketLoggingService packetLoggingService = null;
private static CertificateService certService = null;
private static FileAccessService fileService = null;
/**
* The resource service. Used for checking for default values
@ -68,7 +72,7 @@ public void start(BundleContext context) throws Exception
SipActivator.bundleContext = context;
sipProviderFactory = new ProtocolProviderFactorySipImpl();
sipProviderFactory = createProtocolProviderFactory();
/*
* Install the UriHandler prior to registering the factory service in
@ -88,6 +92,34 @@ public void start(BundleContext context) throws Exception
if (logger.isDebugEnabled())
logger.debug("SIP Protocol Provider Factory ... [REGISTERED]");
}
/**
* Creates the ProtocolProviderFactory for this protocol.
* @return The created factory.
*/
protected ProtocolProviderFactorySipImpl createProtocolProviderFactory()
{
return new ProtocolProviderFactorySipImpl();
}
/**
* Return the certificate verification service impl.
* @return the CertificateVerification service.
*/
public static CertificateService getCertificateVerificationService()
{
if(certService == null)
{
ServiceReference guiVerifyReference
= bundleContext.getServiceReference(
CertificateService.class.getName());
if(guiVerifyReference != null)
certService = (CertificateService)
bundleContext.getService(guiVerifyReference);
}
return certService;
}
/**
* Returns a reference to a ConfigurationService implementation currently
@ -269,6 +301,21 @@ public static PacketLoggingService getPacketLogging()
}
return packetLoggingService;
}
/**
* Return the file access service impl.
* @return the FileAccess Service.
*/
public static FileAccessService getFileAccessService()
{
if(fileService == null)
{
fileService = ServiceUtils.getService(
bundleContext, FileAccessService.class);
}
return fileService;
}
/**
* Called when this bundle is stopped so the Framework can perform the

@ -8,9 +8,11 @@
import java.io.*;
import java.net.*;
import java.security.cert.*;
import java.text.*;
import java.util.*;
import javax.net.ssl.*;
import javax.sip.*;
import javax.sip.address.*;
import javax.sip.header.*;
@ -250,8 +252,16 @@ void register()
catch (Exception exc)
{
if(exc.getCause() instanceof SocketException
|| exc.getCause() instanceof IOException)
|| exc.getCause() instanceof IOException
|| exc.getCause() instanceof SSLHandshakeException)
{
if(exc.getCause().getCause() instanceof CertificateException)
{
setRegistrationState(RegistrationState.UNREGISTERED
, RegistrationStateChangeEvent.REASON_USER_REQUEST
, exc.getMessage());
return;
}
if(sipProvider.registerUsingNextAddress())
return;
}

@ -7,8 +7,9 @@
package net.java.sip.communicator.impl.protocol.sip;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.*;
import net.java.sip.communicator.impl.protocol.sip.net.*;
/**
* The properties used at the creation of the JAIN-SIP stack.
@ -291,6 +292,6 @@ else if (logLevel.equals(Level.OFF.getName()))
this.setProperty(NSPNAME_SERVER_LOGGER, NSPVALUE_SERVER_LOGGER);
this.setProperty("gov.nist.javax.sip.NETWORK_LAYER",
"net.java.sip.communicator.impl.protocol.sip.net.SslNetworkLayer");
SslNetworkLayer.class.getName());
}
}

@ -0,0 +1,214 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.sip.net;
import java.security.cert.*;
import java.text.*;
import java.util.*;
import java.util.regex.*;
import javax.sip.address.*;
import net.java.sip.communicator.impl.protocol.sip.*;
import net.java.sip.communicator.service.certificate.*;
import net.java.sip.communicator.util.*;
/**
* Matcher that extracts certificate identities according to <a
* href="http://tools.ietf.org/html/rfc5922#section-7.1">RFC5922, Section
* 7.1</a> and compares them with the rules from Section 7.2 and 7.3.
* @see #PNAME_STRICT_RFC5922 for wildcard handling; the default is false
*
* @author Ingo Bauersachs
*/
public class RFC5922Matcher
implements CertificateMatcher
{
/**
* When set to true, enables strict validation of the hostname according to
* <a href="http://tools.ietf.org/html/rfc5922#section-7.2">RFC5922 Section
* 7.2</a>
*/
public final static String PNAME_STRICT_RFC5922 =
"net.java.sip.communicator.sip.tls.STRICT_RFC5922";
private ProtocolProviderServiceSipImpl provider;
/**
* Creates a new instance of this class.
* @param provider The SIP Provider to which this matcher belongs.
*/
public RFC5922Matcher(ProtocolProviderServiceSipImpl provider)
{
this.provider = provider;
}
/** Our class logger. */
private static final Logger logger = Logger
.getLogger(CertificateMatcher.class);
/*
* (non-Javadoc)
*
* @see
* net.java.sip.communicator.service.certificate.CertificateMatcher#verify
* (java.lang.Iterable, java.security.cert.X509Certificate)
*/
public void verify(Iterable<String> identitiesToTest, X509Certificate cert)
throws CertificateException
{
boolean strict = SipActivator.getConfigurationService()
.getBoolean(PNAME_STRICT_RFC5922, false);
// if any of the identities is contained in the certificate we're good
boolean oneMatched = false;
Iterable<String> certIdentities = extractCertIdentities(cert);
for (String identity : identitiesToTest)
{
// check if the intended hostname is contained in one of the
// hostnames of the certificate according to
// http://tools.ietf.org/html/rfc5922#section-7.2
for(String dnsName : certIdentities)
{
try
{
if(NetworkUtils.compareDnsNames(dnsName, identity) == 0)
{
// one of the hostnames matched, we're good to go
return;
}
if(!strict
// is a wildcard name
&& dnsName.startsWith("*.")
// contains at least two dots (*.example.com)
&& identity.indexOf(".") < identity.lastIndexOf(".")
// compare *.example.com stripped to example.com with
// - foo.example.com stripped to example.com
// - foo.bar.example.com to bar.example.com
&& NetworkUtils.compareDnsNames(
dnsName.substring(2),
identity.substring(identity.indexOf(".")+1)) == 0)
{
// the wildcard matched, we're good to go
return;
}
}
catch (ParseException e)
{} // we don't care - this hostname did not match
}
}
if (!oneMatched)
throw new CertificateException("None of <" + identitiesToTest
+ "> matched by the rules of RFC5922 to the cert with CN="
+ cert.getSubjectDN());
}
private Iterable<String> extractCertIdentities(X509Certificate cert)
{
List<String> certIdentities = new ArrayList<String>();
Collection<List<?>> subjAltNames = null;
try
{
subjAltNames = cert.getSubjectAlternativeNames();
}
catch (CertificateParsingException ex)
{
logger.error("Error parsing TLS certificate", ex);
}
// subjAltName types are defined in rfc2459
final Integer dnsNameType = 2;
final Integer uriNameType = 6;
if (subjAltNames != null)
{
if (logger.isDebugEnabled())
logger.debug("found subjAltNames: " + subjAltNames);
// First look for a URI in the subjectAltName field
for (List<?> altName : subjAltNames)
{
// 0th position is the alt name type
// 1st position is the alt name data
if (altName.get(0).equals(uriNameType))
{
SipURI altNameUri;
try
{
altNameUri =
provider.getAddressFactory().createSipURI(
(String) altName.get(1));
// only sip URIs are allowed
if (!"sip".equals(altNameUri.getScheme()))
continue;
// user certificates are not allowed
if (altNameUri.getUser() != null)
continue;
String altHostName = altNameUri.getHost();
if (logger.isDebugEnabled())
{
logger.debug("found uri " + altName.get(1)
+ ", hostName " + altHostName);
}
certIdentities.add(altHostName);
}
catch (ParseException e)
{
logger.error("certificate contains invalid uri: "
+ altName.get(1));
}
}
}
// DNS An implementation MUST accept a domain name system
// identifier as a SIP domain identity if and only if no other
// identity is found that matches the "sip" URI type described
// above.
if (certIdentities.isEmpty())
{
for (List<?> altName : subjAltNames)
{
if (altName.get(0).equals(dnsNameType))
{
if (logger.isDebugEnabled())
logger.debug("found dns " + altName.get(1));
certIdentities.add(altName.get(1).toString());
}
}
}
}
else
{
// If and only if the subjectAltName does not appear in the
// certificate, the implementation MAY examine the CN field of the
// certificate. If a valid DNS name is found there, the
// implementation MAY accept this value as a SIP domain identity.
String dname = cert.getSubjectDN().getName();
String cname = "";
try
{
Pattern EXTRACT_CN =
Pattern.compile(".*CN\\s*=\\s*([\\w*\\.]+).*");
Matcher matcher = EXTRACT_CN.matcher(dname);
if (matcher.matches())
{
cname = matcher.group(1);
if (logger.isDebugEnabled())
{
logger.debug("found CN: " + cname + " from DN: "
+ dname);
}
certIdentities.add(cname);
}
}
catch (Exception ex)
{
logger.error("exception while extracting CN", ex);
}
}
return certIdentities;
}
}

@ -9,6 +9,7 @@
import java.io.*;
import java.net.*;
import java.security.*;
import java.util.*;
import javax.net.ssl.*;
@ -16,58 +17,51 @@
import net.java.sip.communicator.impl.protocol.sip.*;
import net.java.sip.communicator.service.certificate.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.Logger;
import org.osgi.framework.*;
/**
* Manages jain-sip socket creating. When dealing with ssl sockets we interact
* Manages jain-sip socket creation. When dealing with ssl sockets we interact
* with the user when the certificate for some reason is not trusted.
*
*
* @author Damian Minkov
* @author Ingo Bauersachs
*/
public class SslNetworkLayer
implements NetworkLayer,
ServiceListener
implements NetworkLayer
{
/**
/**
* Our class logger.
*/
private static final Logger logger =
Logger.getLogger(SslNetworkLayer.class);
private static final Logger logger =
Logger.getLogger(SslNetworkLayer.class);
/**
* The service we use to interact with user.
*/
private CertificateVerificationService certificateVerification;
private CertificateService certificateVerification;
/**
* Creates the network layer.
*
* @throws GeneralSecurityException
* @throws FileNotFoundException
* @throws IOException
*/
public SslNetworkLayer()
throws GeneralSecurityException,
FileNotFoundException,
IOException
{
SipActivator.getBundleContext().addServiceListener(this);
ServiceReference guiVerifyReference =
SipActivator.getBundleContext().getServiceReference(
CertificateService.class.getName());
ServiceReference guiVerifyReference
= SipActivator.getBundleContext().getServiceReference(
CertificateVerificationService.class.getName());
if(guiVerifyReference != null)
certificateVerification
= (CertificateVerificationService)SipActivator.getBundleContext()
.getService(guiVerifyReference);
if (guiVerifyReference != null)
certificateVerification =
(CertificateService) SipActivator.getBundleContext().getService(
guiVerifyReference);
}
/**
* Creates a server with the specified port, listen backlog,
* and local IP address to bind to.
* Comparable to "new java.net.ServerSocket(port,backlog,bindAddress);"
* Creates a server with the specified port, listen backlog, and local IP
* address to bind to. Comparable to
* "new java.net.ServerSocket(port,backlog,bindAddress);"
*
* @param port the port
* @param backlog backlog
@ -83,12 +77,12 @@ public ServerSocket createServerSocket(int port, int backlog,
}
/**
* Creates a stream socket and connects it to the specified
* port number at the specified IP address.
*
* Creates a stream socket and connects it to the specified port number at
* the specified IP address.
*
* @param address the address to connect.
* @param port the port to connect.
* @return the socket
* @return the socket
* @throws IOException problem creating socket.
*/
public Socket createSocket(InetAddress address, int port)
@ -99,9 +93,8 @@ public Socket createSocket(InetAddress address, int port)
/**
* Constructs a datagram socket and binds it to any available port on the
* local host machine.
* Comparable to "new java.net.DatagramSocket();"
*
* local host machine. Comparable to "new java.net.DatagramSocket();"
*
* @return the datagram socket
* @throws SocketException problem creating socket.
*/
@ -112,12 +105,12 @@ public DatagramSocket createDatagramSocket()
}
/**
* Creates a datagram socket, bound to the specified local address.
* Creates a datagram socket, bound to the specified local address.
* Comparable to "new java.net.DatagramSocket(port,laddr);"
*
*
* @param port local port to use
* @param laddr local address to bind
* @return the datagram socket
* @return the datagram socket
* @throws SocketException problem creating socket.
*/
public DatagramSocket createDatagramSocket(int port, InetAddress laddr)
@ -127,8 +120,8 @@ public DatagramSocket createDatagramSocket(int port, InetAddress laddr)
}
/**
* Creates an SSL server with the specified port, listen backlog,
* and local IP address to bind to.
* Creates an SSL server with the specified port, listen backlog, and local
* IP address to bind to.
*
* @param port the port to listen to
* @param backlog backlog
@ -140,111 +133,99 @@ public SSLServerSocket createSSLServerSocket(int port, int backlog,
InetAddress bindAddress)
throws IOException
{
return (SSLServerSocket) getSSLServerSocketFactory(
bindAddress.getHostName(), port).createServerSocket(
port, backlog, bindAddress);
return (SSLServerSocket) getSSLServerSocketFactory()
.createServerSocket(port, backlog, bindAddress);
}
/**
* Creates a ssl server socket factory.
* @param address the address.
* @param port the port
*
* @return the server socket factory.
* @throws IOException problem creating factory.
*/
private SSLServerSocketFactory getSSLServerSocketFactory(
String address, int port)
private SSLServerSocketFactory getSSLServerSocketFactory()
throws IOException
{
return getSSLContext(SipActivator.getResources().
getI18NString(
"service.gui.CERT_DIALOG_CLIENT_DESCRIPTION_TXT",
new String[]
{
SipActivator.getResources()
.getSettingsString("service.gui.APPLICATION_NAME")
})
).getServerSocketFactory();
try
{
return certificateVerification.getSSLContext()
.getServerSocketFactory();
}
catch (GeneralSecurityException e)
{
throw new IOException(e.getMessage());
}
}
/**
* Creates the ssl context used to create ssl socket factories. Used
* to install our custom trust manager which knows the address
* we are connecting to.
* @param address the address we are connecting to.
* @param port the port
* @return the ssl context.
* @throws IOException problem creating ssl context.
* Creates ssl socket factory.
*
* @return the socket factory.
* @throws IOException problem creating ssl socket factory.
*/
private SSLContext getSSLContext(String address, int port)
private SSLSocketFactory getSSLSocketFactory(InetAddress address)
throws IOException
{
if(certificateVerification != null)
return certificateVerification.getSSLContext(address, port);
else
ProtocolProviderServiceSipImpl provider = null;
for (ProtocolProviderServiceSipImpl pps : ProtocolProviderServiceSipImpl
.getAllInstances())
{
try
if (pps.matchesInetAddress(address))
{
SSLContext sslContext;
sslContext = SSLContext.getInstance("TLS");
String algorithm = KeyManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmFactory =
TrustManagerFactory.getInstance(algorithm);
KeyManagerFactory kmFactory =
KeyManagerFactory.getInstance(algorithm);
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextInt();
tmFactory.init((KeyStore)null);
kmFactory.init(null, null);
sslContext.init(kmFactory.getKeyManagers(),
tmFactory.getTrustManagers(), secureRandom);
return sslContext;
provider = pps;
break;
}
catch (Throwable e)
}
if (provider == null)
throw new IOException(
"The provider that requested "
+ "the SSL Socket could not be found");
try
{
ArrayList<String> identities = new ArrayList<String>(2);
SipAccountID id = (SipAccountID) provider.getAccountID();
// if the proxy is configured manually, the entered name is valid
// for the X.509 certificate
if(!id.getAccountPropertyBoolean(
ProtocolProviderFactory.PROXY_AUTO_CONFIG, false))
{
String proxy = id.getAccountPropertyString(
ProtocolProviderFactory.PROXY_ADDRESS);
if(proxy != null)
identities.add(proxy);
if (logger.isDebugEnabled())
logger.debug("Added <" + proxy
+ "> to list of valid SIP TLS server identities.");
}
// the domain part of the user id is always valid
String userID =
id.getAccountPropertyString(ProtocolProviderFactory.USER_ID);
int index = userID.indexOf('@');
if (index > -1)
{
throw new IOException("Cannot init SSLContext: " +
e.getMessage());
identities.add(userID.substring(index + 1));
if (logger.isDebugEnabled())
logger.debug("Added <" + userID.substring(index + 1)
+ "> to list of valid SIP TLS server identities.");
}
return certificateVerification.getSSLContext(
certificateVerification.getTrustManager(
identities,
null,
new RFC5922Matcher(provider)
)).getSocketFactory();
}
}
/**
* Creates the ssl context used to create ssl socket factories. Used
* to install our custom trust manager which knows the address
* we are connecting to.
* @param message the message to show on the verification GUI
* @return the ssl context.
* @throws IOException problem creating ssl context.
*/
private SSLContext getSSLContext(String message)
throws IOException
{
if(certificateVerification != null)
return certificateVerification.getSSLContext(message);
else
catch (GeneralSecurityException e)
{
//goes to the non-service case which doesn't use the a message/port
return getSSLContext(null, 0);
throw new IOException(e.getMessage());
}
}
/**
* Creates ssl socket factory.
* @param address the address we are connecting to.
* @param port the port we use.
* @return the socket factory.
* @throws IOException problem creating ssl socket factory.
*/
private SSLSocketFactory getSSLSocketFactory(String address, int port)
throws IOException
{
return getSSLContext(address, port).getSocketFactory();
}
/**
* Creates a stream SSL socket and connects it to the specified
* port number at the specified IP address.
* Creates a stream SSL socket and connects it to the specified port number
* at the specified IP address.
*
* @param address the address we are connecting to.
* @param port the port we use.
* @return the socket.
@ -253,13 +234,14 @@ private SSLSocketFactory getSSLSocketFactory(String address, int port)
public SSLSocket createSSLSocket(InetAddress address, int port)
throws IOException
{
return (SSLSocket) getSSLSocketFactory(
address.getCanonicalHostName(), port).createSocket(address, port);
return (SSLSocket) getSSLSocketFactory(address).createSocket(address,
port);
}
/**
* Creates a stream SSL socket and connects it to the specified
* port number at the specified IP address.
* Creates a stream SSL socket and connects it to the specified port number
* at the specified IP address.
*
* @param address the address we are connecting to.
* @param port the port we use.
* @param myAddress the local address to use
@ -270,15 +252,15 @@ public SSLSocket createSSLSocket(InetAddress address, int port,
InetAddress myAddress)
throws IOException
{
return (SSLSocket) getSSLSocketFactory(
address.getCanonicalHostName(), port).createSocket(address, port,
myAddress, 0);
return (SSLSocket) getSSLSocketFactory(address).createSocket(address,
port, myAddress, 0);
}
/**
* Creates a stream socket and connects it to the specified port number at
* the specified IP address.
* Comparable to "new java.net.Socket(address, port,localaddress);"
* the specified IP address. Comparable to
* "new java.net.Socket(address, port,localaddress);"
*
* @param address the address to connect to.
* @param port the port we use.
* @param myAddress the local address to use.
@ -298,18 +280,18 @@ public Socket createSocket(InetAddress address, int port,
/**
* Creates a new Socket, binds it to myAddress:myPort and connects it to
* address:port.
*
*
* @param address the InetAddress that we'd like to connect to.
* @param port the port that we'd like to connect to
* @param myAddress the address that we are supposed to bind on or null
* for the "any" address.
* @param myAddress the address that we are supposed to bind on or null for
* the "any" address.
* @param myPort the port that we are supposed to bind on or 0 for a random
* one.
*
* one.
*
* @return a new Socket, bound on myAddress:myPort and connected to
* address:port.
* address:port.
* @throws IOException if binding or connecting the socket fail for a reason
* (exception relayed from the corresponding Socket methods)
* (exception relayed from the corresponding Socket methods)
*/
public Socket createSocket(InetAddress address, int port,
InetAddress myAddress, int myPort)
@ -319,7 +301,7 @@ public Socket createSocket(InetAddress address, int port,
return new Socket(address, port, myAddress, myPort);
else if (port != 0)
{
//myAddress is null (i.e. any) but we have a port number
// myAddress is null (i.e. any) but we have a port number
Socket sock = new Socket();
sock.bind(new InetSocketAddress(port));
sock.connect(new InetSocketAddress(address, port));
@ -328,27 +310,4 @@ else if (port != 0)
else
return new Socket(address, port);
}
/**
* Listens for newly registered services. Looking for
* CertificateVerificationService.
*
* @param event the new event.
*/
public void serviceChanged(ServiceEvent event)
{
Object sService = SipActivator.getBundleContext().getService(
event.getServiceReference());
// we don't care if the source service is not a plugin component
if (! (sService instanceof CertificateVerificationService))
{
return;
}
if(event.getType() == ServiceEvent.REGISTERED)
certificateVerification = (CertificateVerificationService)sService;
else if(event.getType() == ServiceEvent.UNREGISTERING)
certificateVerification = null;
}
}

@ -17,8 +17,9 @@
import org.apache.http.client.methods.*;
import org.apache.http.conn.*;
import org.apache.http.conn.scheme.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.*;
import org.apache.http.impl.client.*;
import org.apache.http.params.*;
import org.osgi.framework.*;
@ -102,7 +103,7 @@ public abstract class BaseHttpXCapClient implements HttpXCapClient
/**
* The service we use to interact with user regarding certificates.
*/
private CertificateVerificationService certificateVerification;
private CertificateService certificateVerification;
/**
* Creates an instance of this XCAP client.
@ -113,11 +114,11 @@ public BaseHttpXCapClient()
ServiceReference guiVerifyReference
= SipActivator.getBundleContext().getServiceReference(
CertificateVerificationService.class.getName());
CertificateService.class.getName());
if(guiVerifyReference != null)
certificateVerification
= (CertificateVerificationService)SipActivator.getBundleContext()
= (CertificateService)SipActivator.getBundleContext()
.getService(guiVerifyReference);
}
@ -413,6 +414,7 @@ protected URI getResourceURI(XCapResourceId resourceId)
*/
private DefaultHttpClient createHttpClient()
{
//TODO: move to HttpUtil
DefaultHttpClient httpClient = new DefaultHttpClient();
try
{
@ -421,14 +423,13 @@ private DefaultHttpClient createHttpClient()
// for approval
ClientConnectionManager ccm = httpClient.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
SSLContext ctx = certificateVerification.getSSLContext(
uri.getHost(), uri.getPort() == -1 ? 443 : uri.getPort());
org.apache.http.conn.ssl.SSLSocketFactory ssf
= new org.apache.http.conn.ssl.SSLSocketFactory(
ctx, new HostNameResolverImpl());
ssf.setHostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory
.ALLOW_ALL_HOSTNAME_VERIFIER);
sr.register(new Scheme("https", ssf, 443));
SSLContext ctx =
certificateVerification.getSSLContext(
certificateVerification.getTrustManager(uri.getHost()));
org.apache.http.conn.ssl.SSLSocketFactory ssf =
new org.apache.http.conn.ssl.SSLSocketFactory(ctx,
SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
sr.register(new Scheme("https", 443, ssf));
}
catch(Throwable e)
{
@ -442,7 +443,7 @@ private DefaultHttpClient createHttpClient()
/**
* Creates XCAP response from HTTP response.
* If HTTP code is 200, 201 or 409 the HTTP content would be readed.
* If HTTP code is 200, 201 or 409 the HTTP content would be read.
*
* @param response the HTTP response.
* @return the XCAP response.
@ -540,42 +541,4 @@ protected String getXCapErrorMessage(XCapHttpResponse response)
return null;
}
}
/**
* Using deprecated HostNameResolver as quick fix,
* Make apache http client lib to use our resolver when connecting to hosts.
*/
private class HostNameResolverImpl
implements HostNameResolver
{
/**
* Resolves given hostname to its IP address
*
* @param hostname the hostname.
* @return IP address.
* @throws java.io.IOException
*/
public InetAddress resolve(String hostname)
throws IOException
{
try
{
InetSocketAddress addr = null;
// use port 80 as we need only the address
if(ProtocolProviderServiceSipImpl.checkPreferIPv6Addresses())
addr = NetworkUtils.getAAAARecord(hostname, 80);
else
addr = NetworkUtils.getARecord(hostname, 80);
if(addr != null)
return addr.getAddress();
else
return null;
}
catch(java.text.ParseException e)
{
throw new IOException(e.getMessage());
}
}
}
}

@ -0,0 +1,24 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.certificate;
import java.security.cert.*;
public interface CertificateMatcher
{
/**
* Implementations check whether one of the supplied identities is
* contained in the certificate.
*
* @param identitiesToTest The that are compared against the certificate.
* @param cert The X.509 certificate that was supplied by the server or
* client.
* @throws CertificateException When any certificate parsing fails.
*/
public void verify(Iterable<String> identitiesToTest, X509Certificate cert)
throws CertificateException;
}

@ -0,0 +1,152 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.certificate;
import java.security.GeneralSecurityException;
import java.security.cert.*;
import javax.net.ssl.*;
/**
* A service which implementors will ask the user for permission for the
* certificates which are for some reason not valid and not globally trusted.
*
* @author Damian Minkov
* @author Ingo Bauersachs
*/
public interface CertificateService
{
/**
* Property for always trust mode. When enabled certificate check is
* skipped.
*/
public final static String PNAME_ALWAYS_TRUST =
"net.java.sip.communicator.service.gui.ALWAYS_TRUST_MODE_ENABLED";
/**
* When set to true, the certificate check is performed. If the check fails
* the user is not asked and the error is directly reported to the calling
* service.
*/
public final static String PNAME_NO_USER_INTERACTION =
"net.java.sip.communicator.service.tls.NO_USER_INTERACTION";
/**
* Result of user interaction. User does not trust this certificate.
*/
public final static int DO_NOT_TRUST = 0;
/**
* Result of user interaction. User will always trust this certificate.
*/
public final static int TRUST_ALWAYS = 1;
/**
* Result of user interaction. User will trust this certificate
* only for the current session.
*/
public final static int TRUST_THIS_SESSION_ONLY = 2;
/**
* Get an SSL Context that validates certificates based on the JRE default
* check and asks the user when the JRE check fails.
*
* CAUTION: Only the certificate itself is validated, no check is performed
* whether it is valid for a specific server or client.
*
* @return An SSL context based on a user confirming trust manager.
* @throws GeneralSecurityException
*/
public SSLContext getSSLContext() throws GeneralSecurityException;
/**
* Get an SSL Context with the specified trustmanager.
*
* @param trustManager The trustmanager that will be used by the created
* SSLContext
* @return An SSL context based on the supplied trust manager.
* @throws GeneralSecurityException
*/
public SSLContext getSSLContext(X509TrustManager trustManager)
throws GeneralSecurityException;
/**
* Creates a trustmanager that validates the certificate based on the JRE
* default check and asks the user when the JRE check fails. When
* <tt>null</tt> is passed as the <tt>identityToTest</tt> then no check is
* performed whether the certificate is valid for a specific server or
* client. The passed identities are checked by applying a behavior similar
* to the on regular browsers use.
*
* @param identitiesToTest when not <tt>null</tt>, the values are assumed
* to be hostnames for invocations of checkServerTrusted and
* e-mail addresses for invocations of checkClientTrusted
* @return TrustManager to use in an SSLContext
* @throws GeneralSecurityException
*/
public X509TrustManager getTrustManager(Iterable<String> identitiesToTest)
throws GeneralSecurityException;
/**
* @see #getTrustManager(Iterable)
*
* @param identityToTest when not <tt>null</tt>, the value is assumed to
* be a hostname for invocations of checkServerTrusted and an
* e-mail address for invocations of checkClientTrusted
* @return TrustManager to use in an SSLContext
* @throws GeneralSecurityException
*/
public X509TrustManager getTrustManager(String identityToTest)
throws GeneralSecurityException;
/**
* @see #getTrustManager(Iterable, CertificateMatcher, CertificateMatcher)
*
* @param identityToTest The identity to match against the supplied
* verifiers.
* @param clientVerifier The verifier to use in calls to checkClientTrusted
* @param serverVerifier The verifier to use in calls to checkServerTrusted
* @return TrustManager to use in an SSLContext
* @throws GeneralSecurityException
*/
public X509TrustManager getTrustManager(
final String identityToTest,
final CertificateMatcher clientVerifier,
final CertificateMatcher serverVerifier)
throws GeneralSecurityException;
/**
* Creates a trustmanager that validates the certificate based on the JRE
* default check and asks the user when the JRE check fails. When
* <tt>null</tt> is passed as the <tt>identityToTest</tt> then no check is
* performed whether the certificate is valid for a specific server or
* client.
*
* @param identitiesToTest The identities to match against the supplied
* verifiers.
* @param clientVerifier The verifier to use in calls to checkClientTrusted
* @param serverVerifier The verifier to use in calls to checkServerTrusted
* @return TrustManager to use in an SSLContext
* @throws GeneralSecurityException
*/
public X509TrustManager getTrustManager(
final Iterable<String> identitiesToTest,
final CertificateMatcher clientVerifier,
final CertificateMatcher serverVerifier)
throws GeneralSecurityException;
/**
* Adds a certificate to the local trust store.
*
* @param cert The certificate to add to the trust store.
* @param trustMode Whether to trust the certificate permanently or only
* for the current session.
* @throws CertificateException when the thumbprint could not be calculated
*/
public void addCertificateToTrust(Certificate cert, String trustFor,
int trustMode) throws CertificateException;
}

@ -15,8 +15,11 @@
* A service which implementors will ask the user for permission for the
* certificates which are for some reason not valid and not globally trusted.
*
* @deprecated Use the new {@link CertificateService}
*
* @author Damian Minkov
*/
@Deprecated
public interface CertificateVerificationService
{
/**

@ -19,7 +19,7 @@ public class HttpUtilActivator
/**
* The service we use to interact with user regarding certificates.
*/
private static CertificateVerificationService guiCertificateVerification;
private static CertificateService guiCertificateVerification;
/**
* Reference to the credentials service
@ -46,16 +46,16 @@ public class HttpUtilActivator
* Return the certificate verification service impl.
* @return the CertificateVerification service.
*/
public static CertificateVerificationService
public static CertificateService
getCertificateVerificationService()
{
if(guiCertificateVerification == null)
{
ServiceReference guiVerifyReference
= bundleContext.getServiceReference(
CertificateVerificationService.class.getName());
CertificateService.class.getName());
if(guiVerifyReference != null)
guiCertificateVerification = (CertificateVerificationService)
guiCertificateVerification = (CertificateService)
bundleContext.getService(guiVerifyReference);
}

@ -30,6 +30,7 @@
import javax.net.ssl.*;
import java.io.*;
import java.net.*;
import java.security.*;
import java.util.*;
/**
@ -519,7 +520,7 @@ else if(i == passwordParamIx && creds != null)
private static DefaultHttpClient getHttpClient(
String usernamePropertyName,
String passwordPropertyName,
String address)
final String address)
throws IOException
{
HttpParams params = new BasicHttpParams();
@ -534,23 +535,25 @@ private static DefaultHttpClient getHttpClient(
+ "/"
+ System.getProperty("sip-communicator.version"));
SSLContext sslCtx = HttpUtilActivator
.getCertificateVerificationService().getSSLContext(
HttpUtilActivator.getResources().
getI18NString(
"service.gui.CERT_DIALOG_DESCRIPTION_TXT",
new String[]{
HttpUtilActivator.getResources().getSettingsString(
"service.gui.APPLICATION_NAME"),
address,
Integer.toString(443)
}
));
SSLContext sslCtx;
try
{
sslCtx = HttpUtilActivator.getCertificateVerificationService()
.getSSLContext(
HttpUtilActivator.getCertificateVerificationService()
.getTrustManager(address));
}
catch (GeneralSecurityException e)
{
throw new IOException(e.getMessage());
}
Scheme sch = new Scheme("https", 443,
new SSLSocketFactory(
sslCtx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER));
Scheme sch =
new Scheme("https", 443, new SSLSocketFactory(sslCtx,
SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER));
httpClient.getConnectionManager().getSchemeRegistry().register(sch);
//TODO: wrap the SSLSocketFactory to use our own DNS resolution
//TODO: register socketfactory for http to use our own DNS resolution
// set proxy from default jre settings
ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner(

@ -1190,4 +1190,28 @@ public static void reloadDnsResolverConfig()
}
}
}
/**
* Compares two DNS names against each other. Helper method to avoid the
* export of DNSJava.
* @param dns1 The first DNS name
* @param dns2 The DNS name that is compared against dns1
* @return The value 0 if dns2 is a name equivalent to dns1;
* a value less than 0 if dns2 is less than dns1 in the canonical ordering,
* and a value greater than 0 if dns2 is greater than dns1 in the canonical
* ordering.
* @throws ParseException if the dns1 or dns2 is not a DNS Name
*/
public static int compareDnsNames(String dns1, String dns2)
throws ParseException
{
try
{
return Name.fromString(dns1).compareTo(Name.fromString(dns2));
}
catch(TextParseException e)
{
throw new ParseException(e.getMessage(), 0);
}
}
}

@ -82,7 +82,7 @@ public void testInstallAccount()
bc.getService(confReference);
configurationService.setProperty(
CertificateVerificationService.ALWAYS_TRUST_MODE_ENABLED_PROP_NAME,
CertificateService.PNAME_ALWAYS_TRUST,
Boolean.TRUE);
//Keep the reference for later usage.

Loading…
Cancel
Save