diff --git a/java-pinning-core/src/main/java/eu/geekplace/javapinning/PinningTrustManager.java b/java-pinning-core/src/main/java/eu/geekplace/javapinning/PinningTrustManager.java index bfddca8..fa62c4f 100644 --- a/java-pinning-core/src/main/java/eu/geekplace/javapinning/PinningTrustManager.java +++ b/java-pinning-core/src/main/java/eu/geekplace/javapinning/PinningTrustManager.java @@ -43,10 +43,12 @@ public void checkClientTrusted(X509Certificate[] chain, String authType) @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + final X509Certificate leafCertificate = chain[0]; - if (isPinned(leafCertificate)) { - return; - } + + for (X509Certificate cert : chain) + if (isPinned(cert)) return; + // Throw a CertificateException with a meaningful message. Note that we // use CERTPLAIN, which tends to be long, so colons as separator are of // no use and most other software UIs show the "public key" without diff --git a/java-pinning-core/src/test/java/eu/geekplace/javapinning/integrationtest/IntegrationTest.java b/java-pinning-core/src/test/java/eu/geekplace/javapinning/integrationtest/IntegrationTest.java index 005e06d..ed162ad 100644 --- a/java-pinning-core/src/test/java/eu/geekplace/javapinning/integrationtest/IntegrationTest.java +++ b/java-pinning-core/src/test/java/eu/geekplace/javapinning/integrationtest/IntegrationTest.java @@ -31,10 +31,21 @@ public class IntegrationTest { + private static final String PIN_GITHUB_DIGICERT = "SHA256:451335746aa70c5b022570531e4cb5eaf8b5a1b3a50a01459ffc8e848ff2fa1a"; + private static final String PIN_GITHUB_LEAF = "SHA256:a39a1ae45e0b6d911f799d245c3826694d8adec20f62d6d0a53dc440b259aae3"; + + @Test + public void testGithubDigiCert() throws NoSuchAlgorithmException, KeyManagementException, IOException { + connect(JavaPinning.forPin(PIN_GITHUB_DIGICERT)); + } + @Test - public void main() throws NoSuchAlgorithmException, KeyManagementException, IOException { - SSLContext sc = JavaPinning.forPin("SHA256:a4bd7ea9bf474cc459266b82fdb07f648f5ddf4d8162baea895b91c96f831ab5"); + public void testGithubLeaf() throws NoSuchAlgorithmException, KeyManagementException, IOException { + connect(JavaPinning.forPin(PIN_GITHUB_LEAF)); + } + + private void connect(SSLContext sc) throws NoSuchAlgorithmException, KeyManagementException, IOException { Socket socket = new Socket("github.com", 443); SSLSocket sslSocket = (SSLSocket) sc.getSocketFactory().createSocket(socket, "github.com", 443, true); sslSocket.startHandshake(); diff --git a/tools/pin.groovy b/tools/pin.groovy new file mode 100644 index 0000000..5875522 --- /dev/null +++ b/tools/pin.groovy @@ -0,0 +1,33 @@ +import javax.net.ssl.HttpsURLConnection +import java.security.MessageDigest +import java.security.cert.Certificate +import java.security.cert.X509Certificate + +def domain = args.size() ? args[0] : null +if (!domain) { + println 'Usage: pin.groovy ' + System.exit(0) +} + +def con = "https://$domain".toURL().openConnection() as HttpsURLConnection +con.connect() + +con.getServerCertificates().eachWithIndex { Certificate cert, int i -> + + println "Certificate Nr. ${i + 1}" + if (!cert instanceof X509Certificate) return + + def xc = cert as X509Certificate + + println "Subject: ${xc.subjectDN.name}" + println "Valid from ${xc.notBefore} to ${xc.notAfter}" + + if (xc.subjectAlternativeNames?.size()) + println "Alternate DNS: ${xc.subjectAlternativeNames*.last().join(', ')}" + + def sha = new BigInteger(1, MessageDigest.getInstance('SHA-256').digest(cert.publicKey.encoded)) + .toString(16).padLeft(64, '0').toLowerCase() + + println "Pin string: SHA256:$sha\n" +} +con.disconnect() \ No newline at end of file diff --git a/version.gradle b/version.gradle index 0f0b6a7..38d0b7e 100644 --- a/version.gradle +++ b/version.gradle @@ -1,10 +1,10 @@ allprojects { ext { - shortVersion = '1.2.1' + shortVersion = '1.2.2' // increase versionCode with every release // versionCode format: // - versionCode = 01020100 + versionCode = 01020200 isSnapshot = true } }