picoquic/tls_api.c
int picoquic_initialize_tls_stream(picoquic_cnx_t* cnx, uint64_t current_time)
{
    int ret = 0;
    struct st_ptls_buffer_t sendbuf;
    picoquic_tls_ctx_t* ctx = (picoquic_tls_ctx_t*)cnx->tls_ctx;
    size_t epoch_offsets[PICOQUIC_NUMBER_OF_EPOCH_OFFSETS] = { 0, 0, 0, 0, 0 };

    if (cnx->sni != NULL) {
        ptls_set_server_name(ctx->tls, cnx->sni, strlen(cnx->sni));
    }

    if (cnx->alpn != NULL) {
        ctx->alpn_vec[0].base = (uint8_t*)cnx->alpn;
        ctx->alpn_vec[0].len = strlen(cnx->alpn);
        ctx->handshake_properties.client.negotiated_protocols.count = 1;
        ctx->handshake_properties.client.negotiated_protocols.list = ctx->alpn_vec;
    }
    else if (cnx->callback_fn != NULL) {
        /* Get the default ALPN list for the callback function */
        ret = cnx->callback_fn(cnx, 0, (uint8_t*)ctx, 0, picoquic_callback_request_alpn_list, cnx->callback_ctx, NULL);

        ctx->handshake_properties.client.negotiated_protocols.count = ctx->alpn_count;
        ctx->handshake_properties.client.negotiated_protocols.list = ctx->alpn_vec;

        if (ret != 0) {
            DBG_PRINTF("ALPN list callback returns 0x%x", ret);
        }
    }

    /* ALPN is mandatory, there should be at least one */
    if (ret == 0 && ctx->handshake_properties.client.negotiated_protocols.count == 0) {
        ret = PICOQUIC_ERROR_NO_ALPN_PROVIDED;
        DBG_PRINTF("No ALPN provided, error 0x%x", ret);
    }

    if (cnx->quic->F_log != NULL) {
        picoquic_log_negotiated_alpn(cnx->quic->F_log, cnx, 0, 1, ctx->handshake_properties.client.negotiated_protocols.list, ctx->handshake_properties.client.negotiated_protocols.count);
    }
    if (cnx->f_binlog != NULL) {
        binlog_transport_extension(cnx,
            1, (const uint8_t *)cnx->sni, (cnx->sni == NULL)?0:strlen(cnx->sni), NULL, 0,
            ctx->handshake_properties.client.negotiated_protocols.list, 
            ctx->handshake_properties.client.negotiated_protocols.count,
            0, NULL);
    }

    /* No resumption if no alpn specified upfront, because it would make the negotiation and
     * the handling of 0-RTT way too messy */
    if (cnx->sni != NULL && cnx->alpn != NULL && !cnx->quic->client_zero_share) {
        uint8_t* ticket = NULL;
        uint16_t ticket_length = 0;

        if (picoquic_get_ticket(cnx->quic->p_first_ticket, current_time,
            cnx->sni, (uint16_t)strlen(cnx->sni), cnx->alpn, (uint16_t)strlen(cnx->alpn),
            &ticket, &ticket_length, &cnx->remote_parameters, 1)
            == 0) {
            ctx->handshake_properties.client.session_ticket.base = ticket;
            ctx->handshake_properties.client.session_ticket.len = ticket_length;

            ctx->handshake_properties.client.max_early_data_size = &cnx->max_early_data_size;

            cnx->psk_cipher_suite_id = PICOPARSE_16(ticket + 8);
        }
    }

    if (cnx->quic->client_zero_share &&
        cnx->cnx_state == picoquic_state_client_init)
    {
        ctx->handshake_properties.client.negotiate_before_key_exchange = 1;
    }
    else
    {
        ctx->handshake_properties.client.negotiate_before_key_exchange = 0;
    }

    if (ret != 0) {
        DBG_PRINTF("Could not set up TLS parameters, error 0x%x, abandoning connection", ret);
        cnx->cnx_state = picoquic_state_disconnected;
    } else {
        picoquic_tls_set_extensions(cnx, ctx);

        ptls_buffer_init(&sendbuf, "", 0);

        /* Clearing the global error state of openssl before calling handle message.
         * This allows detection of errors during processing. */
        ERR_clear_error();
        ret = ptls_handle_message(ctx->tls, &sendbuf, epoch_offsets, 0, NULL, 0, &ctx->handshake_properties);

        /* assume that all the data goes to epoch 0, initial */
        if ((ret == 0 || ret == PTLS_ERROR_IN_PROGRESS)) {
#ifdef PTLS_ESNI_NONCE_SIZE
            /* Find the ESNI secret if any, and copy key values to picoquic tls context */
            struct st_ptls_esni_secret_t* esni = ptls_get_esni_secret(ctx->tls);
            if (esni != NULL) {
                ctx->esni_version = esni->version;
                memcpy(ctx->esni_nonce, esni->nonce, PTLS_ESNI_NONCE_SIZE);
            }
#endif
            if (sendbuf.off > 0) {
                ret = picoquic_add_to_tls_stream(cnx, sendbuf.base, sendbuf.off, 0);
            }
            else {
                ret = 0;
            }
        }
        else {
            picoquic_log_openssl_errors(cnx, ret);
            ret = -1;
        }
        ptls_buffer_dispose(&sendbuf);
    }

    return ret;
}
/* Prepare the initial message when starting a connection.
 */
Prepare the initial message when starting a connection.
Prepare the initial message when starting a connection .
int picoquic_initialize_tls_stream(picoquic_cnx_t* cnx, uint64_t current_time)
{
    int ret = 0;
    struct st_ptls_buffer_t sendbuf;
    picoquic_tls_ctx_t* ctx = (picoquic_tls_ctx_t*)cnx->tls_ctx;
    size_t epoch_offsets[PICOQUIC_NUMBER_OF_EPOCH_OFFSETS] = { 0, 0, 0, 0, 0 };
    if (cnx->sni != NULL) {
        ptls_set_server_name(ctx->tls, cnx->sni, strlen(cnx->sni));
    }
    if (cnx->alpn != NULL) {
        ctx->alpn_vec[0].base = (uint8_t*)cnx->alpn;
        ctx->alpn_vec[0].len = strlen(cnx->alpn);
        ctx->handshake_properties.client.negotiated_protocols.count = 1;
        ctx->handshake_properties.client.negotiated_protocols.list = ctx->alpn_vec;
    }
    else if (cnx->callback_fn != NULL) {
        ret = cnx->callback_fn(cnx, 0, (uint8_t*)ctx, 0, picoquic_callback_request_alpn_list, cnx->callback_ctx, NULL);
        ctx->handshake_properties.client.negotiated_protocols.count = ctx->alpn_count;
        ctx->handshake_properties.client.negotiated_protocols.list = ctx->alpn_vec;
        if (ret != 0) {
            DBG_PRINTF("ALPN list callback returns 0x%x", ret);
        }
    }
    if (ret == 0 && ctx->handshake_properties.client.negotiated_protocols.count == 0) {
        ret = PICOQUIC_ERROR_NO_ALPN_PROVIDED;
        DBG_PRINTF("No ALPN provided, error 0x%x", ret);
    }
    if (cnx->quic->F_log != NULL) {
        picoquic_log_negotiated_alpn(cnx->quic->F_log, cnx, 0, 1, ctx->handshake_properties.client.negotiated_protocols.list, ctx->handshake_properties.client.negotiated_protocols.count);
    }
    if (cnx->f_binlog != NULL) {
        binlog_transport_extension(cnx,
            1, (const uint8_t *)cnx->sni, (cnx->sni == NULL)?0:strlen(cnx->sni), NULL, 0,
            ctx->handshake_properties.client.negotiated_protocols.list, 
            ctx->handshake_properties.client.negotiated_protocols.count,
            0, NULL);
    }
    if (cnx->sni != NULL && cnx->alpn != NULL && !cnx->quic->client_zero_share) {
        uint8_t* ticket = NULL;
        uint16_t ticket_length = 0;
        if (picoquic_get_ticket(cnx->quic->p_first_ticket, current_time,
            cnx->sni, (uint16_t)strlen(cnx->sni), cnx->alpn, (uint16_t)strlen(cnx->alpn),
            &ticket, &ticket_length, &cnx->remote_parameters, 1)
            == 0) {
            ctx->handshake_properties.client.session_ticket.base = ticket;
            ctx->handshake_properties.client.session_ticket.len = ticket_length;
            ctx->handshake_properties.client.max_early_data_size = &cnx->max_early_data_size;
            cnx->psk_cipher_suite_id = PICOPARSE_16(ticket + 8);
        }
    }
    if (cnx->quic->client_zero_share &&
        cnx->cnx_state == picoquic_state_client_init)
    {
        ctx->handshake_properties.client.negotiate_before_key_exchange = 1;
    }
    else
    {
        ctx->handshake_properties.client.negotiate_before_key_exchange = 0;
    }
    if (ret != 0) {
        DBG_PRINTF("Could not set up TLS parameters, error 0x%x, abandoning connection", ret);
        cnx->cnx_state = picoquic_state_disconnected;
    } else {
        picoquic_tls_set_extensions(cnx, ctx);
        ptls_buffer_init(&sendbuf, "", 0);
        ERR_clear_error();
        ret = ptls_handle_message(ctx->tls, &sendbuf, epoch_offsets, 0, NULL, 0, &ctx->handshake_properties);
        if ((ret == 0 || ret == PTLS_ERROR_IN_PROGRESS)) {
#ifdef PTLS_ESNI_NONCE_SIZE
            struct st_ptls_esni_secret_t* esni = ptls_get_esni_secret(ctx->tls);
            if (esni != NULL) {
                ctx->esni_version = esni->version;
                memcpy(ctx->esni_nonce, esni->nonce, PTLS_ESNI_NONCE_SIZE);
            }
#endif
            if (sendbuf.off > 0) {
                ret = picoquic_add_to_tls_stream(cnx, sendbuf.base, sendbuf.off, 0);
            }
            else {
                ret = 0;
            }
        }
        else {
            picoquic_log_openssl_errors(cnx, ret);
            ret = -1;
        }
        ptls_buffer_dispose(&sendbuf);
    }
    return ret;
}
int picoquic_initialize_tls_stream ( picoquic_cnx_t * cnx , uint64_t current_time ) { int ret = 0 ; struct st_ptls_buffer_t sendbuf ; picoquic_tls_ctx_t * ctx = ( picoquic_tls_ctx_t * ) cnx -> tls_ctx ; size_t epoch_offsets [ PICOQUIC_NUMBER_OF_EPOCH_OFFSETS ] = { 0 , 0 , 0 , 0 , 0 } ; if ( cnx -> sni != NULL ) { ptls_set_server_name ( ctx -> tls , cnx -> sni , strlen ( cnx -> sni ) ) ; } if ( cnx -> alpn != NULL ) { ctx -> alpn_vec [ 0 ] . base = ( uint8_t * ) cnx -> alpn ; ctx -> alpn_vec [ 0 ] . len = strlen ( cnx -> alpn ) ; ctx -> handshake_properties . client . negotiated_protocols . count = 1 ; ctx -> handshake_properties . client . negotiated_protocols . list = ctx -> alpn_vec ; } else if ( cnx -> callback_fn != NULL ) { ret = cnx -> callback_fn ( cnx , 0 , ( uint8_t * ) ctx , 0 , picoquic_callback_request_alpn_list , cnx -> callback_ctx , NULL ) ; ctx -> handshake_properties . client . negotiated_protocols . count = ctx -> alpn_count ; ctx -> handshake_properties . client . negotiated_protocols . list = ctx -> alpn_vec ; if ( ret != 0 ) { DBG_PRINTF ( " " , ret ) ; } } if ( ret == 0 && ctx -> handshake_properties . client . negotiated_protocols . count == 0 ) { ret = PICOQUIC_ERROR_NO_ALPN_PROVIDED ; DBG_PRINTF ( " " , ret ) ; } if ( cnx -> quic -> F_log != NULL ) { picoquic_log_negotiated_alpn ( cnx -> quic -> F_log , cnx , 0 , 1 , ctx -> handshake_properties . client . negotiated_protocols . list , ctx -> handshake_properties . client . negotiated_protocols . count ) ; } if ( cnx -> f_binlog != NULL ) { binlog_transport_extension ( cnx , 1 , ( const uint8_t * ) cnx -> sni , ( cnx -> sni == NULL ) ? 0 : strlen ( cnx -> sni ) , NULL , 0 , ctx -> handshake_properties . client . negotiated_protocols . list , ctx -> handshake_properties . client . negotiated_protocols . count , 0 , NULL ) ; } if ( cnx -> sni != NULL && cnx -> alpn != NULL && ! cnx -> quic -> client_zero_share ) { uint8_t * ticket = NULL ; uint16_t ticket_length = 0 ; if ( picoquic_get_ticket ( cnx -> quic -> p_first_ticket , current_time , cnx -> sni , ( uint16_t ) strlen ( cnx -> sni ) , cnx -> alpn , ( uint16_t ) strlen ( cnx -> alpn ) , & ticket , & ticket_length , & cnx -> remote_parameters , 1 ) == 0 ) { ctx -> handshake_properties . client . session_ticket . base = ticket ; ctx -> handshake_properties . client . session_ticket . len = ticket_length ; ctx -> handshake_properties . client . max_early_data_size = & cnx -> max_early_data_size ; cnx -> psk_cipher_suite_id = PICOPARSE_16 ( ticket + 8 ) ; } } if ( cnx -> quic -> client_zero_share && cnx -> cnx_state == picoquic_state_client_init ) { ctx -> handshake_properties . client . negotiate_before_key_exchange = 1 ; } else { ctx -> handshake_properties . client . negotiate_before_key_exchange = 0 ; } if ( ret != 0 ) { DBG_PRINTF ( " " , ret ) ; cnx -> cnx_state = picoquic_state_disconnected ; } else { picoquic_tls_set_extensions ( cnx , ctx ) ; ptls_buffer_init ( & sendbuf , " " , 0 ) ; ERR_clear_error ( ) ; ret = ptls_handle_message ( ctx -> tls , & sendbuf , epoch_offsets , 0 , NULL , 0 , & ctx -> handshake_properties ) ; if ( ( ret == 0 || ret == PTLS_ERROR_IN_PROGRESS ) ) { #ifdef PTLS_ESNI_NONCE_SIZE struct st_ptls_esni_secret_t * esni = ptls_get_esni_secret ( ctx -> tls ) ; if ( esni != NULL ) { ctx -> esni_version = esni -> version ; memcpy ( ctx -> esni_nonce , esni -> nonce , PTLS_ESNI_NONCE_SIZE ) ; } #endif if ( sendbuf . off > 0 ) { ret = picoquic_add_to_tls_stream ( cnx , sendbuf . base , sendbuf . off , 0 ) ; } else { ret = 0 ; } } else { picoquic_log_openssl_errors ( cnx , ret ) ; ret = -1 ; } ptls_buffer_dispose ( & sendbuf ) ; } return ret ; }
Prepare the initial message when starting a connection.
Prepare the initial message when starting a connection .
/* Get the default ALPN list for the callback function */ /* ALPN is mandatory, there should be at least one */ /* No resumption if no alpn specified upfront, because it would make the negotiation and
     * the handling of 0-RTT way too messy */ /* Clearing the global error state of openssl before calling handle message.
         * This allows detection of errors during processing. */ /* assume that all the data goes to epoch 0, initial */ /* Find the ESNI secret if any, and copy key values to picoquic tls context */