aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
authorBrian P. Hinz <bphinz@users.sf.net>2015-09-13 10:39:54 -0400
committerBrian P. Hinz <bphinz@users.sf.net>2015-09-13 10:44:40 -0400
commit95f39a5685bbf389200e0c7abea5d7db50755572 (patch)
tree6e1048a656c1f6a33efa28dd4abf5505bd2f60c9 /java
parent47963ba8d56d5219ff2804872e17bed52f67954c (diff)
downloadtigervnc-95f39a5685bbf389200e0c7abea5d7db50755572.tar.gz
tigervnc-95f39a5685bbf389200e0c7abea5d7db50755572.zip
Improve handling of x509 authentication
Fixes #193 and also adds automatic certificate saving feature like the Fltk viewer. Also pulls in CA certificates from all trusted authorities known to the JRE for the case when the server is using a certificate from a top-level authority.
Diffstat (limited to 'java')
-rw-r--r--java/com/tigervnc/rfb/CSecurityTLS.java125
1 files changed, 101 insertions, 24 deletions
diff --git a/java/com/tigervnc/rfb/CSecurityTLS.java b/java/com/tigervnc/rfb/CSecurityTLS.java
index 6f799bb4..a3246c5f 100644
--- a/java/com/tigervnc/rfb/CSecurityTLS.java
+++ b/java/com/tigervnc/rfb/CSecurityTLS.java
@@ -24,16 +24,21 @@
package com.tigervnc.rfb;
import javax.net.ssl.*;
-import java.security.*;
-import java.security.cert.*;
+import java.security.KeyManagementException;
import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.MessageDigest;
+import java.security.cert.*;
import java.io.File;
-import java.io.InputStream;
import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import javax.swing.JOptionPane;
+import javax.xml.bind.DatatypeConverter;
import com.tigervnc.rdr.*;
import com.tigervnc.network.*;
@@ -129,7 +134,7 @@ public class CSecurityTLS extends CSecurity {
manager = new SSLEngineManager(engine, is, os);
manager.doHandshake();
} catch(java.lang.Exception e) {
- throw new Exception(e.toString());
+ throw new Exception(e.getMessage());
}
//checkSession();
@@ -200,19 +205,38 @@ public class CSecurityTLS extends CSecurity {
MyX509TrustManager() throws java.security.GeneralSecurityException
{
- TrustManagerFactory tmf =
- TrustManagerFactory.getInstance("PKIX");
KeyStore ks = KeyStore.getInstance("JKS");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
try {
ks.load(null, null);
+ String a = TrustManagerFactory.getDefaultAlgorithm();
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(a);
+ tmf.init((KeyStore)null);
+ for (TrustManager m : tmf.getTrustManagers())
+ if (m instanceof X509TrustManager)
+ for (X509Certificate c : ((X509TrustManager)m).getAcceptedIssuers())
+ ks.setCertificateEntry(c.getSubjectX500Principal().getName(), c);
+ File castore = new File(FileUtils.getVncHomeDir()+"x509_savedcerts.pem");
+ if (castore.exists() && castore.canRead()) {
+ InputStream caStream = new FileInputStream(castore);
+ Collection<? extends Certificate> cacerts =
+ cf.generateCertificates(caStream);
+ for (Certificate cert : cacerts) {
+ String dn =
+ ((X509Certificate)cert).getSubjectX500Principal().getName();
+ ks.setCertificateEntry(dn, (X509Certificate)cert);
+ }
+ }
File cacert = new File(cafile);
- if (!cacert.exists() || !cacert.canRead())
- return;
- InputStream caStream = new FileInputStream(cafile);
- X509Certificate ca = (X509Certificate)cf.generateCertificate(caStream);
- ks.setCertificateEntry("CA", ca);
- PKIXBuilderParameters params = new PKIXBuilderParameters(ks, new X509CertSelector());
+ if (cacert.exists() && cacert.canRead()) {
+ InputStream caStream = new FileInputStream(cafile);
+ Certificate cert = cf.generateCertificate(caStream);
+ String dn =
+ ((X509Certificate)cert).getSubjectX500Principal().getName();
+ ks.setCertificateEntry(dn, (X509Certificate)cert);
+ }
+ PKIXBuilderParameters params =
+ new PKIXBuilderParameters(ks, new X509CertSelector());
File crlcert = new File(crlfile);
if (!crlcert.exists() || !crlcert.canRead()) {
params.setRevocationEnabled(false);
@@ -224,13 +248,14 @@ public class CSecurityTLS extends CSecurity {
params.addCertStore(store);
params.setRevocationEnabled(true);
}
+ tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(new CertPathTrustManagerParameters(params));
+ tm = (X509TrustManager)tmf.getTrustManagers()[0];
} catch (java.io.FileNotFoundException e) {
vlog.error(e.toString());
} catch (java.io.IOException e) {
vlog.error(e.toString());
}
- tm = (X509TrustManager)tmf.getTrustManagers()[0];
}
public void checkClientTrusted(X509Certificate[] chain, String authType)
@@ -242,20 +267,71 @@ public class CSecurityTLS extends CSecurity {
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
+ MessageDigest md = null;
try {
- tm.checkServerTrusted(chain, authType);
+ md = MessageDigest.getInstance("SHA-1");
+ tm.checkServerTrusted(chain, authType);
} catch (CertificateException e) {
- Object[] answer = {"Proceed", "Exit"};
- int ret = JOptionPane.showOptionDialog(null,
- e.getCause().getLocalizedMessage()+"\n"+
- "Continue connecting to this host?",
- "Confirm certificate exception?",
- JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
- null, answer, answer[0]);
- if (ret == JOptionPane.NO_OPTION)
- System.exit(1);
+ if (e.getCause() instanceof CertPathBuilderException) {
+ Object[] answer = {"YES", "NO"};
+ X509Certificate cert = chain[0];
+ md.update(cert.getEncoded());
+ String thumbprint =
+ DatatypeConverter.printHexBinary(md.digest());
+ thumbprint = thumbprint.replaceAll("..(?!$)", "$0 ");
+ int ret = JOptionPane.showOptionDialog(null,
+ "This certificate has been signed by an unknown authority\n"+
+ "\n"+
+ " Subject: "+cert.getSubjectX500Principal().getName()+"\n"+
+ " Issuer: "+cert.getIssuerX500Principal().getName()+"\n"+
+ " Serial Number: "+cert.getSerialNumber()+"\n"+
+ " Version: "+cert.getVersion()+"\n"+
+ " Signature Algorithm: "+cert.getPublicKey().getAlgorithm()+"\n"+
+ " Not Valid Before: "+cert.getNotBefore()+"\n"+
+ " Not Valid After: "+cert.getNotAfter()+"\n"+
+ " SHA1 Fingerprint: "+thumbprint+"\n"+
+ "\n"+
+ "Do you want to save it and continue?",
+ "Certificate Issuer Unknown",
+ JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
+ null, answer, answer[0]);
+ if (ret == JOptionPane.YES_OPTION) {
+ File vncDir = new File(FileUtils.getVncHomeDir());
+ if (!vncDir.exists() && !vncDir.mkdir()) {
+ vlog.info("Certificate save failed, unable to create ~/.vnc");
+ return;
+ }
+ for (int i = 0; i < chain.length; i++) {
+ byte[] der = chain[i].getEncoded();
+ String pem = DatatypeConverter.printBase64Binary(der);
+ pem = pem.replaceAll("(.{64})", "$1\n");
+ FileWriter fw = null;
+ try {
+ String castore =
+ FileUtils.getVncHomeDir()+"x509_savedcerts.pem";
+ fw = new FileWriter(castore, true);
+ fw.write("-----BEGIN CERTIFICATE-----\n");
+ fw.write(pem+"\n");
+ fw.write("-----END CERTIFICATE-----\n");
+ } catch (IOException ioe) {
+ throw new Exception(ioe.getCause().getMessage());
+ } finally {
+ try {
+ if (fw != null)
+ fw.close();
+ } catch(IOException ioe2) {
+ throw new Exception(ioe2.getCause().getMessage());
+ }
+ }
+ }
+ } else {
+ System.exit(1);
+ }
+ } else {
+ throw new Exception(e.getCause().getMessage());
+ }
} catch (java.lang.Exception e) {
- throw new Exception(e.toString());
+ throw new Exception(e.getCause().getMessage());
}
}
@@ -263,6 +339,7 @@ public class CSecurityTLS extends CSecurity {
{
return tm.getAcceptedIssuers();
}
+
}
public final int getType() { return anon ? Security.secTypeTLSNone : Security.secTypeX509None; }