MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt)
{
    int i;
    MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR;
    X509 *x = NULL;
    unsigned long l;
    const unsigned char *certstart, *certbytes;
    STACK_OF(X509) *sk = NULL;
    PACKET spkt, context;
    size_t chainidx;
    SSL_SESSION *new_sess = NULL;

    if ((sk = sk_X509_new_null()) == NULL) {
        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
                 ERR_R_MALLOC_FAILURE);
        goto err;
    }

    if (SSL_IS_TLS13(s) && (!PACKET_get_length_prefixed_1(pkt, &context)
                            || (s->pha_context == NULL && PACKET_remaining(&context) != 0)
                            || (s->pha_context != NULL &&
                                !PACKET_equal(&context, s->pha_context, s->pha_context_len)))) {
        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
                 SSL_R_INVALID_CONTEXT);
        goto err;
    }

    if (!PACKET_get_length_prefixed_3(pkt, &spkt)
            || PACKET_remaining(pkt) != 0) {
        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
                 SSL_R_LENGTH_MISMATCH);
        goto err;
    }

    for (chainidx = 0; PACKET_remaining(&spkt) > 0; chainidx++) {
        if (!PACKET_get_net_3(&spkt, &l)
            || !PACKET_get_bytes(&spkt, &certbytes, l)) {
            SSLfatal(s, SSL_AD_DECODE_ERROR,
                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
                     SSL_R_CERT_LENGTH_MISMATCH);
            goto err;
        }

        certstart = certbytes;
        x = d2i_X509(NULL, (const unsigned char **)&certbytes, l);
        if (x == NULL) {
            SSLfatal(s, SSL_AD_DECODE_ERROR,
                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_ASN1_LIB);
            goto err;
        }
        if (certbytes != (certstart + l)) {
            SSLfatal(s, SSL_AD_DECODE_ERROR,
                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
                     SSL_R_CERT_LENGTH_MISMATCH);
            goto err;
        }

        if (SSL_IS_TLS13(s)) {
            RAW_EXTENSION *rawexts = NULL;
            PACKET extensions;

            if (!PACKET_get_length_prefixed_2(&spkt, &extensions)) {
                SSLfatal(s, SSL_AD_DECODE_ERROR,
                         SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
                         SSL_R_BAD_LENGTH);
                goto err;
            }
            if (!tls_collect_extensions(s, &extensions,
                                        SSL_EXT_TLS1_3_CERTIFICATE, &rawexts,
                                        NULL, chainidx == 0)
                || !tls_parse_all_extensions(s, SSL_EXT_TLS1_3_CERTIFICATE,
                                             rawexts, x, chainidx,
                                             PACKET_remaining(&spkt) == 0)) {
                OPENSSL_free(rawexts);
                goto err;
            }
            OPENSSL_free(rawexts);
        }

        if (!sk_X509_push(sk, x)) {
            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
                     ERR_R_MALLOC_FAILURE);
            goto err;
        }
        x = NULL;
    }

    if (sk_X509_num(sk) <= 0) {
        /* TLS does not mind 0 certs returned */
        if (s->version == SSL3_VERSION) {
            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
                     SSL_R_NO_CERTIFICATES_RETURNED);
            goto err;
        }
        /* Fail for TLS only if we required a certificate */
        else if ((s->verify_mode & SSL_VERIFY_PEER) &&
                 (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
            SSLfatal(s, SSL_AD_CERTIFICATE_REQUIRED,
                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
                     SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
            goto err;
        }
        /* No client certificate so digest cached records */
        if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, 0)) {
            /* SSLfatal() already called */
            goto err;
        }
    } else {
        EVP_PKEY *pkey;
        i = ssl_verify_cert_chain(s, sk);
        if (i <= 0) {
            SSLfatal(s, ssl_verify_alarm_type(s->verify_result),
                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
                     SSL_R_CERTIFICATE_VERIFY_FAILED);
            goto err;
        }
        if (i > 1) {
            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, i);
            goto err;
        }
        pkey = X509_get0_pubkey(sk_X509_value(sk, 0));
        if (pkey == NULL) {
            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
                     SSL_R_UNKNOWN_CERTIFICATE_TYPE);
            goto err;
        }
    }

    /*
     * Sessions must be immutable once they go into the session cache. Otherwise
     * we can get multi-thread problems. Therefore we don't "update" sessions,
     * we replace them with a duplicate. Here, we need to do this every time
     * a new certificate is received via post-handshake authentication, as the
     * session may have already gone into the session cache.
     */

    if (s->post_handshake_auth == SSL_PHA_REQUESTED) {
        int m = s->session_ctx->session_cache_mode;

        if ((new_sess = ssl_session_dup(s->session, 0)) == 0) {
            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
                     SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
                     ERR_R_MALLOC_FAILURE);
            goto err;
        }

        if (m & SSL_SESS_CACHE_SERVER) {
            /*
             * Remove the old session from the cache. We carry on if this fails
             */
            SSL_CTX_remove_session(s->session_ctx, s->session);
        }

        SSL_SESSION_free(s->session);
        s->session = new_sess;
    }

    X509_free(s->session->peer);
    s->session->peer = sk_X509_shift(sk);
    s->session->verify_result = s->verify_result;

    sk_X509_pop_free(s->session->peer_chain, X509_free);
    s->session->peer_chain = sk;

    if (new_sess != NULL)
        ssl_update_cache(s, SSL_SESS_CACHE_SERVER);

    /*
     * Freeze the handshake buffer. For <TLS1.3 we do this after the CKE
     * message
     */
    if (SSL_IS_TLS13(s) && !ssl3_digest_cached_records(s, 1)) {
        /* SSLfatal() already called */
        goto err;
    }

    /*
     * Inconsistency alert: cert_chain does *not* include the peer's own
     * certificate, while we do include it in statem_clnt.c
     */
    sk = NULL;

    /* Save the current hash state for when we receive the CertificateVerify */
    if (SSL_IS_TLS13(s)
            && !ssl_handshake_hash(s, s->cert_verify_hash,
                                   sizeof(s->cert_verify_hash),
                                   &s->cert_verify_hash_len)) {
        /* SSLfatal() already called */
        goto err;
    }

    ret = MSG_PROCESS_CONTINUE_READING;

 err:
    X509_free(x);
    sk_X509_pop_free(sk, X509_free);
    return ret;
}