Skip to content

Instantly share code, notes, and snippets.

@coreequip
Last active April 26, 2025 12:57
Show Gist options
  • Save coreequip/8788fd21a677aa8e6fb3e5222ec0c1ef to your computer and use it in GitHub Desktop.
Save coreequip/8788fd21a677aa8e6fb3e5222ec0c1ef to your computer and use it in GitHub Desktop.
Simple certificate pinning in groovy.
package dev.coreequip.security
import javax.net.ssl.HttpsURLConnection
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
import java.security.MessageDigest
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
/**
* A TrustManager that only allows certificates thats pinned.
* All others are rejected.<br>
* <br>
* Usage: <tt>PinningTrustManager.init(certificatePublicKeyHash)</tt>
*/
class PinningTrustManager {
static pins = [] as Set
/**
* Init TrustManager with no pins.
*/
static void init() {
def pinningManager = [
getAcceptedIssuers: {},
checkClientTrusted: { a, b -> },
checkServerTrusted: { X509Certificate[] chain, String authType ->
for (X509Certificate cert : chain) {
def hash = new BigInteger(1,
MessageDigest.getInstance('SHA-256').digest(cert.encoded)
).toString(16).padLeft(64, '0').toLowerCase()
if (pins.contains(hash)) return
}
throw new CertificateException('None of these certificates are pinned.')
}
] as X509TrustManager
def sslContext = SSLContext.getInstance('TLS')
sslContext.init(null, [pinningManager] as TrustManager[], null)
SSLContext.setDefault(sslContext)
}
/**
* Init TrustManager with a pin.
*
* @param pin Hexadecimal representation of pinned certificate's public key
*/
static void init(String pin) {
pins.add(pin.toLowerCase())
init()
}
/**
* Add a pin the TrustManager.
*
* @param pin Hexadecimal representation of pinned certificate's public key
*/
static void addPin(String pin) {
pins.add(pin)
}
static void main(String[] args) {
init('451335746aa70c5b022570531e4cb5eaf8b5a1b3a50a01459ffc8e848ff2fa1a')
try {
def con = 'https://github.com'.toURL().openConnection() as HttpsURLConnection
con.connect()
} catch (Exception e) {
e.printStackTrace()
}
println 'Done.'
}
}
@coreequip
Copy link
Author

coreequip commented Feb 12, 2025

Java-Version:

package dev.coreequip.security;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.math.BigInteger;
import java.net.URL;
import java.security.MessageDigest;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashSet;
import java.util.Set;
import java.util.Arrays;

public class PinningTrustManager {

    private static final Set<String> pins = new HashSet<>();

    public static void init(String pin) throws Exception {
        pins.add(pin.toLowerCase());
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, new TrustManager[]{new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
            public void checkClientTrusted(X509Certificate[] chain, String authType) {}
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                if (Arrays.stream(chain).anyMatch(cert -> {
                    try {
                        String hash = String.format("%064x", new BigInteger(1,
                            MessageDigest.getInstance("SHA-256").digest(cert.getEncoded()))).toLowerCase();
                        return pins.contains(hash);
                    } catch (Exception ex) {
                        return false;
                    }
                })) return;
                throw new CertificateException("None of the certificates are pinned.");
            }
        }}, null);
        SSLContext.setDefault(context);

        // only for accepting self-signed certificates
        // HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
    }

    public static void addPin(String pin) {
        pins.add(pin.toLowerCase());
    }

    public static void main(String[] args) {
        try {
            init("451335746aa70c5b022570531e4cb5eaf8b5a1b3a50a01459ffc8e848ff2fa1a");
            HttpsURLConnection connection = (HttpsURLConnection) new URL("https://github.com").openConnection();
            connection.connect();
            System.out.println("Done.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment