/* * ==================================================================== * Copyright (c) 2004-2012 TMate Software Ltd. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://svnkit.com/license.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * ==================================================================== */ package org.tmatesoft.svn.core.internal.util; import java.security.MessageDigest; import java.security.cert.CertificateException; import java.security.cert.CertificateParsingException; import java.security.cert.X509Certificate; import java.util.Collection; import java.util.Date; import java.util.Iterator; /** * @version 1.0 * @author TMate Software Ltd. */ public class SVNSSLUtil { public static StringBuffer getServerCertificatePrompt(X509Certificate cert, String realm, String hostName) { int failures = getServerCertificateFailures(cert, hostName); StringBuffer prompt = new StringBuffer(); prompt.append("Error validating server certificate for '"); prompt.append(realm); prompt.append("':\n"); if ((failures & 8) != 0) { prompt.append(" - The certificate is not issued by a trusted authority. Use the\n" + " fingerprint to validate the certificate manually!\n"); } if ((failures & 4) != 0) { prompt.append(" - The certificate hostname does not match.\n"); } if ((failures & 2) != 0) { prompt.append(" - The certificate has expired.\n"); } if ((failures & 1) != 0) { prompt.append(" - The certificate is not yet valid.\n"); } getServerCertificateInfo(cert, prompt); return prompt; } private static String getFingerprint(X509Certificate cert) { try { return getFingerprint(cert.getEncoded(), "SHA1"); } catch (Exception e) { } return null; } public static String getFingerprint(byte[] key, String digestAlgorithm) { StringBuffer s = new StringBuffer(); try { MessageDigest md = MessageDigest.getInstance(digestAlgorithm != null ? digestAlgorithm : "SHA1"); md.update(key); byte[] digest = md.digest(); for (int i= 0; i < digest.length; i++) { if (i != 0) { s.append(':'); } int b = digest[i] & 0xFF; String hex = Integer.toHexString(b); if (hex.length() == 1) { s.append('0'); } s.append(hex.toLowerCase()); } } catch (Exception e) { } return s.toString(); } private static void getServerCertificateInfo(X509Certificate cert, StringBuffer info) { info.append("Certificate information:"); info.append('\n'); info.append(" - Subject: "); info.append(cert.getSubjectDN().getName()); info.append('\n'); info.append(" - Valid: "); info.append("from " + cert.getNotBefore() + " until " + cert.getNotAfter()); info.append('\n'); info.append(" - Issuer: "); info.append(cert.getIssuerDN().getName()); info.append('\n'); info.append(" - Fingerprint: "); info.append(getFingerprint(cert)); } public static int getServerCertificateFailures(X509Certificate cert, String realHostName) { int mask = 8; Date time = new Date(System.currentTimeMillis()); if (time.before(cert.getNotBefore())) { mask |= 1; } if (time.after(cert.getNotAfter())) { mask |= 2; } String certHostName = cert.getSubjectDN().getName(); int index = certHostName.indexOf("CN="); if (index >= 0) { index += 3; certHostName = certHostName.substring(index); if (certHostName.indexOf(' ') >= 0) { certHostName = certHostName.substring(0, certHostName.indexOf(' ')); } if (certHostName.indexOf(',') >= 0) { certHostName = certHostName.substring(0, certHostName.indexOf(',')); } } if (!realHostName.equals(certHostName)) { try { Collection altNames = cert.getSubjectAlternativeNames(); if(altNames != null) { for (Iterator names = altNames.iterator(); names.hasNext();) { Object nameList = names.next(); if (nameList instanceof Collection && ((Collection) nameList).size() >= 2) { Object[] name = ((Collection) nameList).toArray(); Object type = name[0]; Object host = name[1]; if (type instanceof Integer && host instanceof String) { if (((Integer) type).intValue() == 2 && host.equals(realHostName)) { return mask; } } } } } } catch (CertificateParsingException e) { } mask |= 4; } return mask; } public static class CertificateNotTrustedException extends CertificateException { private static final long serialVersionUID = 4845L; public CertificateNotTrustedException() { super(); } public CertificateNotTrustedException(String msg) { super(msg); } } @SuppressWarnings("serial") public static class CertificateDoesNotConformConstraints extends CertificateException { public CertificateDoesNotConformConstraints(String msg, Exception source) { super(msg, source); } } }