diff --git a/examples/jce/TLCPClient.java b/examples/jce/TLCPClient.java index a02cd19b0..62d2ed19a 100644 --- a/examples/jce/TLCPClient.java +++ b/examples/jce/TLCPClient.java @@ -20,34 +20,138 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; -import java.security.KeyStore; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import net.tongsuo.TongsuoProvider; import net.tongsuo.TongsuoX509Certificate; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import javax.net.ssl.TrustManagerFactory; +import java.util.Collection; +import java.util.List; +import java.util.ArrayList; +import javax.naming.ldap.LdapName; +import javax.naming.ldap.Rdn; +import javax.security.auth.x500.X500Principal; +import java.security.cert.CertificateParsingException; public class TLCPClient { public static void main(String[] args) throws Exception { - String[] ciphers = {"ECC-SM2-SM4-GCM-SM3"}; + String[] ciphers = { "ECC-SM2-SM4-GCM-SM3" }; int port = 4433; String caCertFile = "ca.crt"; String subCaCertFile = "subca.crt"; - X509Certificate caCert = TongsuoX509Certificate.fromX509PemInputStream(new FileInputStream(new File(caCertFile))); - X509Certificate subCaCert = TongsuoX509Certificate.fromX509PemInputStream(new FileInputStream(new File(subCaCertFile))); + X509Certificate caCert = TongsuoX509Certificate + .fromX509PemInputStream(new FileInputStream(new File(caCertFile))); + X509Certificate subCaCert = TongsuoX509Certificate + .fromX509PemInputStream(new FileInputStream(new File(subCaCertFile))); - KeyStore ks = KeyStore.getInstance("PKCS12", new BouncyCastleProvider()); - ks.load(null); - ks.setCertificateEntry("CA", caCert); - ks.setCertificateEntry("SUB_CA", subCaCert); + TrustManager[] tms = new TrustManager[] { + new X509TrustManager() { + public void checkClientTrusted(X509Certificate[] certs, String authType) + throws CertificateException { + } - TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - tmf.init(ks); - TrustManager[] clientTrustManager = tmf.getTrustManagers(); + public void checkServerTrusted(X509Certificate[] certs, String authType) + throws CertificateException { + if (subCaCert != null) { + for (X509Certificate cert : certs) { + try { + cert.checkValidity(); + if (cert.getIssuerX500Principal().equals(subCaCert.getSubjectX500Principal())) { + // verifyHostname(cert, "localhost"); + cert.verify(subCaCert.getPublicKey()); + } else if (cert.getIssuerX500Principal().equals(caCert.getSubjectX500Principal())) { + cert.verify(caCert.getPublicKey()); + } else { + throw new CertificateException("Certificate issuer does not match CA or SubCA"); + } + } catch (Exception e) { + e.printStackTrace(); + throw new CertificateException(e); + } + } + } + } + + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + + void verifyHostname(X509Certificate cert, String hostname) throws CertificateException { + if (hostname == null || hostname.isEmpty()) { + throw new CertificateException("Hostname is empty"); + } + + List possibleNames = getAllPossibleHostnames(cert); + + for (String name : possibleNames) { + if (matchHostname(name, hostname)) { + return; + } + } + + throw new CertificateException( + "No matching hostname found in certificate. Expected: " + hostname); + } + + List getAllPossibleHostnames(X509Certificate cert) throws CertificateException { + List result = new ArrayList<>(); + + try { + X500Principal principal = cert.getSubjectX500Principal(); + LdapName ldapName = new LdapName(principal.getName()); + + for (Rdn rdn : ldapName.getRdns()) { + if ("CN".equalsIgnoreCase(rdn.getType())) { + result.add(rdn.getValue().toString()); + } + } + } catch (Exception e) { + throw new CertificateException("Error extracting CN: " + e.getMessage()); + } + + try { + Collection> subjectAltNames = cert.getSubjectAlternativeNames(); + if (subjectAltNames != null) { + for (List san : subjectAltNames) { + if (san.size() >= 2) { + Integer type = (Integer) san.get(0); + if (type == 2) { + String name = (String) san.get(1); + result.add(name); + } + } + } + } + } catch (CertificateParsingException e) { + throw new CertificateException("Error extracting SAN: " + e.getMessage()); + } + + return result; + } + + boolean matchHostname(String pattern, String hostname) { + if (pattern.equals(hostname)) { + return true; + } + + if (pattern.startsWith("*.")) { + String suffix = pattern.substring(1); + + if (hostname.length() > suffix.length()) { + if (hostname.endsWith(suffix)) { + String prefix = hostname.substring(0, hostname.length() - suffix.length()); + return !prefix.contains("."); + } + } + } + + return false; + } + + } + }; SSLContext sslContext = SSLContext.getInstance("TLCP", new TongsuoProvider()); - sslContext.init(null, clientTrustManager, new SecureRandom()); + sslContext.init(null, tms, new SecureRandom()); SSLSocketFactory sslCntFactory = sslContext.getSocketFactory(); SSLSocket sslSocket = (SSLSocket) sslCntFactory.createSocket("localhost", port); if (ciphers != null) { @@ -63,7 +167,7 @@ public static void main(String[] args) throws Exception { BufferedInputStream streamReader = new BufferedInputStream(sslSocket.getInputStream()); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(streamReader, "utf-8")); String line = null; - while((line = bufferedReader.readLine())!= null){ + while ((line = bufferedReader.readLine()) != null) { System.out.println("client receive server data:" + line); }