Repository: netty/netty
File: handler/src/main/java/io/netty/handler/ssl/EnhancingX509ExtendedTrustManager.java (Java)

Code before:
            if (message.charAt(message.length() - 1) != '.') {
                sb.append('.');
            }
            sb.append(" Chain of ").append(chain.length).append(" certificate(s):");
            for (int i = 0; i < chain.length; i++) {
                X509Certificate cert = chain[i];
                Collection<List<?>> collection = cert.getSubjectAlternativeNames();
                sb.append(' ').append(i + 1).append(". subjectAlternativeNames=[");
                if (collection != null) {
                    boolean hasNames = false;
                    for (List<?> altNames : collection) {
                        final int nameType = ((Integer) altNames.get(0)).intValue();
                        if (nameType == ALTNAME_DNS) {
                            sb.append("DNS");
                        } else if (nameType == ALTNAME_IP) {
                            sb.append("IP");
                        } else if (nameType == ALTNAME_URI) {
                            // URI names are common in some environments with gRPC services that use SPIFFEs.
                            // Though the hostname matcher won't be looking at them, having them there can help
                            // debugging cases where hostname verification was enabled when it shouldn't be.
                            sb.append("URI");
                        } else {
                            continue;
                        }
                        sb.append(':').append((String) altNames.get(1)).append(SEPARATOR);
                        hasNames = true;
                    }
                    if (hasNames) {
                        // Strip of the last separator
                        sb.setLength(sb.length() - SEPARATOR.length());
                    }
                }
                sb.append("], CN=").append(getCommonName(cert)).append('.');
            }
            throw new CertificateException(sb.toString(), e);
        }
        throw e;
    }

    private static String getCommonName(X509Certificate cert) {
        try {
            // 1. Get the X500Principal (better than getSubjectDN which is implementation dependent and deprecated)
            X500Principal principal = cert.getSubjectX500Principal();
            // 2. Parse the DN using LdapName
            LdapName ldapName = new LdapName(principal.getName());
            // 3. Iterate over the Relative Distinguished Names (RDNs) to find CN
            for (Rdn rdn : ldapName.getRdns()) {
                if (rdn.getType().equalsIgnoreCase("CN")) {
                    return rdn.getValue().toString();
                }
            }

Review comment (suggestion):
is it guaranteed that `altNames` is not empty ? Maybe consider adding a check just to be safe... 


```suggestion
                        if (altNames.isEmpty()) {
                            continue;
                        }
                        final int nameType = ((Integer) altNames.get(0)).intValue();
```

Code after:
        String message = e.getMessage();
        if (message != null &&
                (message.startsWith("No subject alternative") || message.startsWith("No name matching"))) {
            StringBuilder sb = new StringBuilder(128);
            sb.append(message);
            // Some exception messages from sun.security.util.HostnameChecker may end with a dot that we don't need
            if (message.charAt(message.length() - 1) == '.') {
                sb.setLength(sb.length() - 1);
            }
            if (session != null) {
                sb.append(" for SNIHostName=").append(getSNIHostName(session))
                        .append(" and peerHost=").append(session.getPeerHost());
            }
            sb.append(" in the chain of ").append(chain.length).append(" certificate(s):");
            for (int i = 0; i < chain.length; i++) {
                X509Certificate cert = chain[i];
                Collection<List<?>> collection = cert.getSubjectAlternativeNames();
                sb.append(' ').append(i + 1).append(". subjectAlternativeNames=[");
                if (collection != null) {
                    boolean hasNames = false;
                    for (List<?> altNames : collection) {
                        if (altNames.size() < 2) {
                            // We expect at least a pair of 'nameType:value' in that list.
                            continue;
                        }
                        final int nameType = ((Integer) altNames.get(0)).intValue();
                        if (nameType == ALTNAME_DNS) {
                            sb.append("DNS");
                        } else if (nameType == ALTNAME_IP) {
                            sb.append("IP");
                        } else if (nameType == ALTNAME_URI) {
                            // URI names are common in some environments with gRPC services that use SPIFFEs.
                            // Though the hostname matcher won't be looking at them, having them there can help
                            // debugging cases where hostname verification was enabled when it shouldn't be.
                            sb.append("URI");
                        } else {
                            continue;
                        }
                        sb.append(':').append((String) altNames.get(1)).append(SEPARATOR);
                        hasNames = true;
                    }
                    if (hasNames) {
                        // Strip of the last separator
                        sb.setLength(sb.length() - SEPARATOR.length());
                    }
                }
                sb.append("], CN=").append(getCommonName(cert)).append('.');
            }
            throw new CertificateException(sb.toString(), e);
        }
        throw e;