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

Code before:
            }
            return new X509ExtendedWrapTrustManager((X509ExtendedTrustManager) tm, confirmedValidations);
        }
        return tm;
    }

    public void remove(SSLEngine engine) {
        if (resumableTm.get() != null) {
            confirmedValidations.remove(unwrapEngine(engine));
        }
    }

    public boolean validateResumeIfNeeded(SSLEngine engine)
            throws CertificateException, SSLPeerUnverifiedException {
        ResumableX509ExtendedTrustManager tm;
        SSLSession session = engine.getSession();
        boolean valid = session.isValid();
        if (valid && (engine.getUseClientMode() || engine.getNeedClientAuth() || engine.getWantClientAuth()) &&
                (tm = resumableTm.get()) != null) {
            // Unwrap JdkSslEngines because they add their inner JDK SSLEngine objects to the set.
            engine = unwrapEngine(engine);

            if (!confirmedValidations.remove(engine)) {
                Certificate[] peerCertificates;
                try {
                    peerCertificates = session.getPeerCertificates();
                } catch (SSLPeerUnverifiedException e) {
                    if (engine.getUseClientMode() || engine.getNeedClientAuth()) {
                        throw e;
                    }
                    return false;
                }

                // This is a resumed session.
                if (engine.getUseClientMode()) {
                    // We are the client, resuming a session trusting the server
                    tm.resumeServerTrusted(chainOf(peerCertificates), engine);
                } else {
                    // We are the server, resuming a session trusting the client
                    tm.resumeClientTrusted(chainOf(peerCertificates), engine);
                }
                return true;
            }
        }
        return false;
    }

    private static SSLEngine unwrapEngine(SSLEngine engine) {
        if (engine instanceof JdkSslEngine) {
            return ((JdkSslEngine) engine).getWrappedEngine();
        }

Review comment (security):
can you add a comment clarifying the goal of this conditional?

`getUseClientMode` -> I assume this is to cover the case of "always do this on the client"

`getNeedClientAuth || getWantClientAuth` -> isn't the default treated by some engines as "want"? for example iirc openssl flavors will have the server request the client's certificate but if they don't return one it will succeed. so I'm just trying to understand if client/server need to be consistent and if not, why.

Code after:
            }
            return new X509ExtendedWrapTrustManager((X509ExtendedTrustManager) tm, confirmedValidations);
        }
        return tm;
    }

    public void remove(SSLEngine engine) {
        if (resumableTm.get() != null) {
            confirmedValidations.remove(unwrapEngine(engine));
        }
    }

    public boolean validateResumeIfNeeded(SSLEngine engine)
            throws CertificateException, SSLPeerUnverifiedException {
        ResumableX509ExtendedTrustManager tm;
        SSLSession session = engine.getSession();
        boolean valid = session.isValid();

        // Look for resumption if the session is valid, and we expect to authenticate our peer:
        //   1.   Clients always authenticate the server.
        //   2.a. Servers only authenticate the client if they need auth,
        //   2.b. or if they requested auth and the client provided.
        //
        // If a server only "want" but don't "need" auth (ClientAuth.OPTIONAL) and the client didn't provide
        // any certificates, then `session.getPeerCertificates()` will throw `SSLPeerUnverifiedException`.
        if (valid && (engine.getUseClientMode() || engine.getNeedClientAuth() || engine.getWantClientAuth()) &&
                (tm = resumableTm.get()) != null) {
            // Unwrap JdkSslEngines because they add their inner JDK SSLEngine objects to the set.
            engine = unwrapEngine(engine);

            if (!confirmedValidations.remove(engine)) {
                Certificate[] peerCertificates;
                try {
                    peerCertificates = session.getPeerCertificates();
                } catch (SSLPeerUnverifiedException e) {
                    if (engine.getUseClientMode() || engine.getNeedClientAuth()) {
                        // Auth is required, and we got none.
                        throw e;
                    }
                    // Auth is optional, and none were provided. Skip out; session resumed but nothing to authenticate.
                    return false;
                }

                // This is a resumed session.
                if (engine.getUseClientMode()) {
                    // We are the client, resuming a session trusting the server
                    tm.resumeServerTrusted(chainOf(peerCertificates), engine);
                } else {
                    // We are the server, resuming a session trusting the client
                    tm.resumeClientTrusted(chainOf(peerCertificates), engine);
                }