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

Code before:
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        try {
            wrapped.checkServerTrusted(chain, authType);
        } catch (CertificateException e) {
            throwEnhancedCertificateException(chain, e);
        }
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return wrapped.getAcceptedIssuers();
    }

    private static void throwEnhancedCertificateException(X509Certificate[] chain, CertificateException e)
            throws CertificateException {
        // Matching the message is the best we can do sadly.
        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 do not end witha dot.
            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 || nameType == ALTNAME_IP) {
                            sb.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);

Review comment (security):
```suggestion
            // Some exception messages from sun.security.util.HostnameChecker do not end with a dot.
```

Code after:
        }
    }

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        wrapped.checkClientTrusted(chain, authType);
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        try {
            wrapped.checkServerTrusted(chain, authType);
        } catch (CertificateException e) {
            throwEnhancedCertificateException(e, chain, null);
        }
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return wrapped.getAcceptedIssuers();
    }

    private static void throwEnhancedCertificateException(CertificateException e, X509Certificate[] chain,
                                                          SSLSession session) throws CertificateException {
        // Matching the message is the best we can do sadly.
        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;