static int s_do_server_side_negotiation_step_2()

in source/windows/secure_channel_tls_handler.c [604:761]


static int s_do_server_side_negotiation_step_2(struct aws_channel_handler *handler) {
    struct secure_channel_handler *sc_handler = handler->impl;

    AWS_LOGF_TRACE(
        AWS_LS_IO_TLS, "id=%p: running step 2 of negotiation (cipher change, key exchange etc...)", (void *)handler);
    SecBuffer input_buffers[] = {
        [0] =
            {
                .pvBuffer = sc_handler->buffered_read_in_data_buf.buffer,
                .cbBuffer = (unsigned long)sc_handler->buffered_read_in_data_buf.len,
                .BufferType = SECBUFFER_TOKEN,
            },
        [1] =
            {
                .pvBuffer = NULL,
                .cbBuffer = 0,
                .BufferType = SECBUFFER_EMPTY,
            },
    };

    SecBufferDesc input_buffers_desc = {
        .ulVersion = SECBUFFER_VERSION,
        .cBuffers = 2,
        .pBuffers = input_buffers,
    };

    SecBuffer output_buffers[3];
    AWS_ZERO_ARRAY(output_buffers);
    output_buffers[0].BufferType = SECBUFFER_TOKEN;
    output_buffers[1].BufferType = SECBUFFER_ALERT;

    SecBufferDesc output_buffers_desc = {
        .ulVersion = SECBUFFER_VERSION,
        .cBuffers = 3,
        .pBuffers = output_buffers,
    };

    sc_handler->read_extra = 0;
    sc_handler->estimated_incomplete_size = 0;

    SECURITY_STATUS status = AcceptSecurityContext(
        &sc_handler->creds,
        &sc_handler->sec_handle,
        &input_buffers_desc,
        sc_handler->ctx_req,
        0,
        NULL,
        &output_buffers_desc,
        &sc_handler->ctx_ret_flags,
        &sc_handler->sspi_timestamp);

    if (status != SEC_E_INCOMPLETE_MESSAGE && status != SEC_I_CONTINUE_NEEDED && status != SEC_E_OK) {
        AWS_LOGF_ERROR(
            AWS_LS_IO_TLS, "id=%p: Error during negotiation. SECURITY_STATUS is %d", (void *)handler, (int)status);
        int aws_error = s_determine_sspi_error(status);
        aws_raise_error(aws_error);
        s_invoke_negotiation_error(handler, aws_error);
        return AWS_OP_ERR;
    }

    if (status == SEC_E_INCOMPLETE_MESSAGE) {
        AWS_LOGF_TRACE(
            AWS_LS_IO_TLS, "id=%p: Last processed buffer was incomplete, waiting on more data.", (void *)handler);
        sc_handler->estimated_incomplete_size = input_buffers[1].cbBuffer;
        return aws_raise_error(AWS_IO_READ_WOULD_BLOCK);
    };
    /* any output buffers that were filled in with SECBUFFER_TOKEN need to be sent,
       SECBUFFER_EXTRA means we need to account for extra data and shift everything for the next run. */
    if (status == SEC_I_CONTINUE_NEEDED || status == SEC_E_OK) {
        for (size_t i = 0; i < output_buffers_desc.cBuffers; ++i) {
            SecBuffer *buf_ptr = &output_buffers[i];

            if (buf_ptr->BufferType == SECBUFFER_TOKEN && buf_ptr->cbBuffer) {
                struct aws_io_message *outgoing_message = aws_channel_acquire_message_from_pool(
                    sc_handler->slot->channel, AWS_IO_MESSAGE_APPLICATION_DATA, buf_ptr->cbBuffer);

                if (!outgoing_message) {
                    FreeContextBuffer(buf_ptr->pvBuffer);
                    s_invoke_negotiation_error(handler, aws_last_error());
                    return AWS_OP_ERR;
                }

                memcpy(outgoing_message->message_data.buffer, buf_ptr->pvBuffer, buf_ptr->cbBuffer);
                outgoing_message->message_data.len = buf_ptr->cbBuffer;
                FreeContextBuffer(buf_ptr->pvBuffer);

                if (aws_channel_slot_send_message(sc_handler->slot, outgoing_message, AWS_CHANNEL_DIR_WRITE)) {
                    aws_mem_release(outgoing_message->allocator, outgoing_message);
                    s_invoke_negotiation_error(handler, aws_last_error());
                    return AWS_OP_ERR;
                }
            }
        }

        if (input_buffers[1].BufferType == SECBUFFER_EXTRA && input_buffers[1].cbBuffer > 0) {
            AWS_LOGF_TRACE(
                AWS_LS_IO_TLS,
                "id=%p: Extra data recieved. Extra size is %lu",
                (void *)handler,
                input_buffers[1].cbBuffer);
            sc_handler->read_extra = input_buffers[1].cbBuffer;
        }
    }

    if (status == SEC_E_OK) {
        AWS_LOGF_TRACE(AWS_LS_IO_TLS, "id=%p: handshake completed", (void *)handler);
        /* if a custom CA store was configured, we have to do the verification ourselves. */
        if (sc_handler->custom_ca_store) {
            AWS_LOGF_TRACE(
                AWS_LS_IO_TLS,
                "id=%p: Custom CA was configured, evaluating trust before completing connection",
                (void *)handler);

            if (s_manually_verify_peer_cert(handler)) {
                aws_raise_error(AWS_IO_TLS_ERROR_NEGOTIATION_FAILURE);
                s_invoke_negotiation_error(handler, AWS_IO_TLS_ERROR_NEGOTIATION_FAILURE);
                return AWS_OP_ERR;
            }
        }
        sc_handler->negotiation_finished = true;

        /* force query of the sizes so future calls to encrypt will be loaded. */
        s_message_overhead(handler);

        /*
           grab the negotiated protocol out of the session.
        */
#ifdef SECBUFFER_APPLICATION_PROTOCOLS
        if (sc_handler->alpn_list && aws_tls_is_alpn_available()) {
            SecPkgContext_ApplicationProtocol alpn_result;
            status = QueryContextAttributes(&sc_handler->sec_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
            AWS_LOGF_TRACE(AWS_LS_IO_TLS, "id=%p: ALPN is configured. Checking for negotiated protocol", handler);

            if (status == SEC_E_OK && alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) {
                aws_byte_buf_init(&sc_handler->protocol, handler->alloc, alpn_result.ProtocolIdSize + 1);
                memset(sc_handler->protocol.buffer, 0, alpn_result.ProtocolIdSize + 1);
                memcpy(sc_handler->protocol.buffer, alpn_result.ProtocolId, alpn_result.ProtocolIdSize);
                sc_handler->protocol.len = alpn_result.ProtocolIdSize;
                AWS_LOGF_DEBUG(
                    AWS_LS_IO_TLS, "id=%p: negotiated protocol %s", handler, (char *)sc_handler->protocol.buffer);
            } else {
                AWS_LOGF_WARN(
                    AWS_LS_IO_TLS,
                    "id=%p: Error retrieving negotiated protocol. SECURITY_STATUS is %d",
                    handler,
                    (int)status);
                int aws_error = s_determine_sspi_error(status);
                aws_raise_error(aws_error);
            }
        }
#endif
        sc_handler->s_connection_state_fn = s_do_application_data_decrypt;
        AWS_LOGF_DEBUG(AWS_LS_IO_TLS, "id=%p: TLS handshake completed successfully.", (void *)handler);
        s_on_negotiation_success(handler);
    }

    return AWS_OP_SUCCESS;
}