<commit_before>/*
 *  SSLv3/TLSv1 client-side functions
 *
 *  Copyright (C) 2006-2013, Brainspark B.V.
 *
 *  This file is part of PolarSSL (http://www.polarssl.org)
 *  Lead Maintainer: <NAME> <polarssl_maintainer at polarssl.org>
 *
 *  All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "polarssl/config.h"

#if defined(POLARSSL_SSL_CLI_C)

#include "polarssl/debug.h"
#include "polarssl/ssl.h"

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#if defined(POLARSSL_SHA4_C)
#include "polarssl/sha4.h"
#endif

static int ssl_write_client_hello( ssl_context *ssl )
{
    int ret;
    size_t i, n, ext_len = 0;
    unsigned char *buf;
    unsigned char *p;
    time_t t;
    unsigned char sig_alg_list[20];
    size_t sig_alg_len = 0;
#if defined(POLARSSL_ECDH_C)
    unsigned char elliptic_curve_list[20];
    size_t elliptic_curve_len = 0;
#endif

    SSL_DEBUG_MSG( 2, ( "=> write client hello" ) );

    if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE )
    {
        ssl->major_ver = ssl->min_major_ver;
        ssl->minor_ver = ssl->min_minor_ver;
    }

    if( ssl->max_major_ver == 0 && ssl->max_minor_ver == 0 )
    {
        ssl->max_major_ver = SSL_MAJOR_VERSION_3;
        ssl->max_minor_ver = SSL_MINOR_VERSION_3;
    }

    /*
     *     0  .   0   handshake type
     *     1  .   3   handshake length
     *     4  .   5   highest version supported
     *     6  .   9   current UNIX time
     *    10  .  37   random bytes
     */
    buf = ssl->out_msg;
    p = buf + 4;

    *p++ = (unsigned char) ssl->max_major_ver;
    *p++ = (unsigned char) ssl->max_minor_ver;

    SSL_DEBUG_MSG( 3, ( "client hello, max version: [%d:%d]",
                   buf[4], buf[5] ) );

    t = time( NULL );
    *p++ = (unsigned char)( t >> 24 );
    *p++ = (unsigned char)( t >> 16 );
    *p++ = (unsigned char)( t >>  8 );
    *p++ = (unsigned char)( t       );

    SSL_DEBUG_MSG( 3, ( "client hello, current time: %lu", t ) );

    if( ( ret = ssl->f_rng( ssl->p_rng, p, 28 ) ) != 0 )
        return( ret );

    p += 28;

    memcpy( ssl->handshake->randbytes, buf + 6, 32 );

    SSL_DEBUG_BUF( 3, "client hello, random bytes", buf + 6, 32 );

    /*
     *    38  .  38   session id length
     *    39  . 39+n  session id
     *   40+n . 41+n  ciphersuitelist length
     *   42+n . ..    ciphersuitelist
     *   ..   . ..    compression methods length
     *   ..   . ..    compression methods
     *   ..   . ..    extensions length
     *   ..   . ..    extensions
     */
    n = ssl->session_negotiate->length;

    if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE || n < 16 || n > 32 ||
        ssl->handshake->resume == 0 )
        n = 0;

    *p++ = (unsigned char) n;

    for( i = 0; i < n; i++ )
        *p++ = ssl->session_negotiate->id[i];

    SSL_DEBUG_MSG( 3, ( "client hello, session id len.: %d", n ) );
    SSL_DEBUG_BUF( 3,   "client hello, session id", buf + 39, n );

    for( n = 0; ssl->ciphersuites[n] != 0; n++ );
    if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) n++;
    *p++ = (unsigned char)( n >> 7 );
    *p++ = (unsigned char)( n << 1 );

    /*
     * Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV
     */
    if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE )
    {
        *p++ = (unsigned char)( SSL_EMPTY_RENEGOTIATION_INFO >> 8 );
        *p++ = (unsigned char)( SSL_EMPTY_RENEGOTIATION_INFO      );
        n--;
    }

    SSL_DEBUG_MSG( 3, ( "client hello, got %d ciphersuites", n ) );

    for( i = 0; i < n; i++ )
    {
        SSL_DEBUG_MSG( 3, ( "client hello, add ciphersuite: %2d",
                       ssl->ciphersuites[i] ) );

        *p++ = (unsigned char)( ssl->ciphersuites[i] >> 8 );
        *p++ = (unsigned char)( ssl->ciphersuites[i]      );
    }

#if defined(POLARSSL_ZLIB_SUPPORT)
    SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 2 ) );
    SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d %d",
                        SSL_COMPRESS_DEFLATE, SSL_COMPRESS_NULL ) );

    *p++ = 2;
    *p++ = SSL_COMPRESS_DEFLATE;
    *p++ = SSL_COMPRESS_NULL;
#else
    SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 1 ) );
    SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d", SSL_COMPRESS_NULL ) );

    *p++ = 1;
    *p++ = SSL_COMPRESS_NULL;
#endif

    if ( ssl->hostname != NULL )
    {
        SSL_DEBUG_MSG( 3, ( "client hello, prepping for server name extension: %s",
                       ssl->hostname ) );

        ext_len += ssl->hostname_len + 9;
    }

    if( ssl->renegotiation == SSL_RENEGOTIATION )
    {
        SSL_DEBUG_MSG( 3, ( "client hello, prepping for renegotiation extension" ) );
        ext_len += 5 + ssl->verify_data_len;
    }

    /*
     * Prepare signature_algorithms extension (TLS 1.2)
     */
    if( ssl->max_minor_ver == SSL_MINOR_VERSION_3 )
    {
#if defined(POLARSSL_SHA4_C)
        sig_alg_list[sig_alg_len++] = SSL_HASH_SHA512;
        sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
        sig_alg_list[sig_alg_len++] = SSL_HASH_SHA384;
        sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
#endif
#if defined(POLARSSL_SHA2_C)
        sig_alg_list[sig_alg_len++] = SSL_HASH_SHA256;
        sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
        sig_alg_list[sig_alg_len++] = SSL_HASH_SHA224;
        sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
#endif
#if defined(POLARSSL_SHA1_C)
        sig_alg_list[sig_alg_len++] = SSL_HASH_SHA1;
        sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
#endif
#if defined(POLARSSL_MD5_C)
        sig_alg_list[sig_alg_len++] = SSL_HASH_MD5;
        sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
#endif
        ext_len += 6 + sig_alg_len;
    }

#if defined(POLARSSL_ECDH_C)
    SSL_DEBUG_MSG( 3, ( "client hello, prepping for supported elliptic curves extension" ) );

    elliptic_curve_list[elliptic_curve_len++] = 0x00;
    elliptic_curve_list[elliptic_curve_len++] = POLARSSL_ECP_DP_SECP521R1;
    elliptic_curve_list[elliptic_curve_len++] = 0x00;
    elliptic_curve_list[elliptic_curve_len++] = POLARSSL_ECP_DP_SECP384R1;
    elliptic_curve_list[elliptic_curve_len++] = 0x00;
    elliptic_curve_list[elliptic_curve_len++] = POLARSSL_ECP_DP_SECP256R1;
    elliptic_curve_list[elliptic_curve_len++] = 0x00;
    elliptic_curve_list[elliptic_curve_len++] = POLARSSL_ECP_DP_SECP224R1;
    elliptic_curve_list[elliptic_curve_len++] = 0x00;
    elliptic_curve_list[elliptic_curve_len++] = POLARSSL_ECP_DP_SECP192R1;

    ext_len += 6 + elliptic_curve_len;

    SSL_DEBUG_MSG( 3, ( "client hello, prepping for supported point formats extension" ) );
    ext_len += 7;
#endif

    SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d",
                   ext_len ) );

    *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( ext_len      ) & 0xFF );

    if ( ssl->hostname != NULL )
    {
        /*
         * struct {
         *     NameType name_type;
         *     select (name_type) {
         *         case host_name: HostName;
         *     } name;
         * } ServerName;
         *
         * enum {
         *     host_name(0), (255)
         * } NameType;
         *
         * opaque HostName<1..2^16-1>;
         *
         * struct {
         *     ServerName server_name_list<1..2^16-1>
         * } ServerNameList;
         */
        SSL_DEBUG_MSG( 3, ( "client hello, adding server name extension: %s",
                       ssl->hostname ) );

        *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME >> 8 ) & 0xFF );
        *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME      ) & 0xFF );

        *p++ = (unsigned char)( ( (ssl->hostname_len + 5) >> 8 ) & 0xFF );
        *p++ = (unsigned char)( ( (ssl->hostname_len + 5)      ) & 0xFF );

        *p++ = (unsigned char)( ( (ssl->hostname_len + 3) >> 8 ) & 0xFF );
        *p++ = (unsigned char)( ( (ssl->hostname_len + 3)      ) & 0xFF );

        *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME_HOSTNAME ) & 0xFF );
        *p++ = (unsigned char)( ( ssl->hostname_len >> 8 ) & 0xFF );
        *p++ = (unsigned char)( ( ssl->hostname_len      ) & 0xFF );

        memcpy( p, ssl->hostname, ssl->hostname_len );
        p += ssl->hostname_len;
    }

    if( ssl->renegotiation == SSL_RENEGOTIATION )
    {
        /*
         * Secure renegotiation
         */
        SSL_DEBUG_MSG( 3, ( "client hello, renegotiation info extension" ) );

        *p++ = (unsigned char)( ( TLS_EXT_RENEGOTIATION_INFO >> 8 ) & 0xFF );
        *p++ = (unsigned char)( ( TLS_EXT_RENEGOTIATION_INFO      ) & 0xFF );

        *p++ = 0x00;
        *p++ = ( ssl->verify_data_len + 1 ) & 0xFF;
        *p++ = ssl->verify_data_len & 0xFF;

        memcpy( p, ssl->own_verify_data, ssl->verify_data_len );
        p += ssl->verify_data_len;
    }

    if( ssl->max_minor_ver == SSL_MINOR_VERSION_3 )
    {
        /*
         * enum {
         *     none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
         *     sha512(6), (255)
         * } HashAlgorithm;
         *
         * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) }
         *   SignatureAlgorithm;
         *
         * struct {
         *     HashAlgorithm hash;
         *     SignatureAlgorithm signature;
         * } SignatureAndHashAlgorithm;
         *
         * SignatureAndHashAlgorithm
         *   supported_signature_algorithms<2..2^16-2>;
         */
        SSL_DEBUG_MSG( 3, ( "client hello, adding signature_algorithms extension" ) );

        *p++ = (unsigned char)( ( TLS_EXT_SIG_ALG >> 8 ) & 0xFF );
        *p++ = (unsigned char)( ( TLS_EXT_SIG_ALG      ) & 0xFF );

        *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) >> 8 ) & 0xFF );
        *p++ = (unsigned char)( ( ( sig_alg_len + 2 )      ) & 0xFF );

        *p++ = (unsigned char)( ( sig_alg_len >> 8 ) & 0xFF );
        *p++ = (unsigned char)( ( sig_alg_len      ) & 0xFF );

        memcpy( p, sig_alg_list, sig_alg_len );

        p += sig_alg_len;
    }

#if defined(POLARSSL_ECDH_C)
    SSL_DEBUG_MSG( 3, ( "client hello, adding supported_elliptic_curves extension" ) );

    *p++ = (unsigned char)( ( TLS_EXT_SUPPORTED_ELLIPTIC_CURVES >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( TLS_EXT_SUPPORTED_ELLIPTIC_CURVES      ) & 0xFF );

    *p++ = (unsigned char)( ( ( elliptic_curve_len + 2 ) >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( ( elliptic_curve_len + 2 )      ) & 0xFF );

    *p++ = (unsigned char)( ( ( elliptic_curve_len     ) >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( ( elliptic_curve_len     )      ) & 0xFF );

    memcpy( p, elliptic_curve_list, elliptic_curve_len );

    p+= elliptic_curve_len;

    SSL_DEBUG_MSG( 3, ( "client hello, adding supported_point_formats extension" ) );

    *p++ = (unsigned char)( ( TLS_EXT_SUPPORTED_POINT_FORMATS >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( TLS_EXT_SUPPORTED_POINT_FORMATS      ) & 0xFF );

    *p++ = 0x00;
    *p++ = 3;

    *p++ = 2;
    *p++ = POLARSSL_ECP_PF_COMPRESSED;
    *p++ = POLARSSL_ECP_PF_UNCOMPRESSED;
#endif

    ssl->out_msglen  = p - buf;
    ssl->out_msgtype = SSL_MSG_HANDSHAKE;
    ssl->out_msg[0]  = SSL_HS_CLIENT_HELLO;

    ssl->state++;

    if( ( ret = ssl_write_record( ssl ) ) != 0 )
    {
        SSL_DEBUG_RET( 1, "ssl_write_record", ret );<commit_msg>Moved writing of client extensions to separate functions in ssl_cli.c<commit_after>/*
 *  SSLv3/TLSv1 client-side functions
 *
 *  Copyright (C) 2006-2013, Brainspark B.V.
 *
 *  This file is part of PolarSSL (http://www.polarssl.org)
 *  Lead Maintainer: <NAME> <polarssl_maintainer at polarssl.org>
 *
 *  All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "polarssl/config.h"

#if defined(POLARSSL_SSL_CLI_C)

#include "polarssl/debug.h"
#include "polarssl/ssl.h"

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#if defined(POLARSSL_SHA4_C)
#include "polarssl/sha4.h"
#endif

static void ssl_write_hostname_ext( ssl_context *ssl,
                                    unsigned char *buf,
                                    size_t *olen )
{
    unsigned char *p = buf;

    *olen = 0;

    if ( ssl->hostname == NULL )
        return;

    SSL_DEBUG_MSG( 3, ( "client hello, adding server name extension: %s",
                   ssl->hostname ) );

    /*
     * struct {
     *     NameType name_type;
     *     select (name_type) {
     *         case host_name: HostName;
     *     } name;
     * } ServerName;
     *
     * enum {
     *     host_name(0), (255)
     * } NameType;
     *
     * opaque HostName<1..2^16-1>;
     *
     * struct {
     *     ServerName server_name_list<1..2^16-1>
     * } ServerNameList;
     */
    *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME      ) & 0xFF );

    *p++ = (unsigned char)( ( (ssl->hostname_len + 5) >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( (ssl->hostname_len + 5)      ) & 0xFF );

    *p++ = (unsigned char)( ( (ssl->hostname_len + 3) >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( (ssl->hostname_len + 3)      ) & 0xFF );

    *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME_HOSTNAME ) & 0xFF );
    *p++ = (unsigned char)( ( ssl->hostname_len >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( ssl->hostname_len      ) & 0xFF );

    memcpy( p, ssl->hostname, ssl->hostname_len );

    *olen = ssl->hostname_len + 9;
}

static void ssl_write_renegotiation_ext( ssl_context *ssl,
                                         unsigned char *buf,
                                         size_t *olen )
{
    unsigned char *p = buf;

    *olen = 0;

    if( ssl->renegotiation != SSL_RENEGOTIATION )
        return;

    SSL_DEBUG_MSG( 3, ( "client hello, adding renegotiation extension" ) );

    /*
     * Secure renegotiation
     */
    *p++ = (unsigned char)( ( TLS_EXT_RENEGOTIATION_INFO >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( TLS_EXT_RENEGOTIATION_INFO      ) & 0xFF );

    *p++ = 0x00;
    *p++ = ( ssl->verify_data_len + 1 ) & 0xFF;
    *p++ = ssl->verify_data_len & 0xFF;

    memcpy( p, ssl->own_verify_data, ssl->verify_data_len );

    *olen = 5 + ssl->verify_data_len;
}

static void ssl_write_signature_algorithms_ext( ssl_context *ssl,
                                                unsigned char *buf,
                                                size_t *olen )
{
    unsigned char *p = buf;
    unsigned char sig_alg_list[20];
    size_t sig_alg_len = 0;

    *olen = 0;

    if( ssl->max_minor_ver != SSL_MINOR_VERSION_3 )
        return;

    SSL_DEBUG_MSG( 3, ( "client hello, adding signature_algorithms extension" ) );

    /*
     * Prepare signature_algorithms extension (TLS 1.2)
     */
#if defined(POLARSSL_SHA4_C)
    sig_alg_list[sig_alg_len++] = SSL_HASH_SHA512;
    sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
    sig_alg_list[sig_alg_len++] = SSL_HASH_SHA384;
    sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
#endif
#if defined(POLARSSL_SHA2_C)
    sig_alg_list[sig_alg_len++] = SSL_HASH_SHA256;
    sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
    sig_alg_list[sig_alg_len++] = SSL_HASH_SHA224;
    sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
#endif
#if defined(POLARSSL_SHA1_C)
    sig_alg_list[sig_alg_len++] = SSL_HASH_SHA1;
    sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
#endif
#if defined(POLARSSL_MD5_C)
    sig_alg_list[sig_alg_len++] = SSL_HASH_MD5;
    sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
#endif

    /*
     * enum {
     *     none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
     *     sha512(6), (255)
     * } HashAlgorithm;
     *
     * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) }
     *   SignatureAlgorithm;
     *
     * struct {
     *     HashAlgorithm hash;
     *     SignatureAlgorithm signature;
     * } SignatureAndHashAlgorithm;
     *
     * SignatureAndHashAlgorithm
     *   supported_signature_algorithms<2..2^16-2>;
     */
    *p++ = (unsigned char)( ( TLS_EXT_SIG_ALG >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( TLS_EXT_SIG_ALG      ) & 0xFF );

    *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( ( sig_alg_len + 2 )      ) & 0xFF );

    *p++ = (unsigned char)( ( sig_alg_len >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( sig_alg_len      ) & 0xFF );

    memcpy( p, sig_alg_list, sig_alg_len );

    *olen = 6 + sig_alg_len;
}

#if defined(POLARSSL_ECDH_C)
static void ssl_write_supported_elliptic_curves_ext( ssl_context *ssl,
                                                     unsigned char *buf,
                                                     size_t *olen )
{
    unsigned char *p = buf;
    unsigned char elliptic_curve_list[20];
    size_t elliptic_curve_len = 0;

    *olen = 0;

    SSL_DEBUG_MSG( 3, ( "client hello, adding supported_elliptic_curves extension" ) );

    elliptic_curve_list[elliptic_curve_len++] = 0x00;
    elliptic_curve_list[elliptic_curve_len++] = POLARSSL_ECP_DP_SECP521R1;
    elliptic_curve_list[elliptic_curve_len++] = 0x00;
    elliptic_curve_list[elliptic_curve_len++] = POLARSSL_ECP_DP_SECP384R1;
    elliptic_curve_list[elliptic_curve_len++] = 0x00;
    elliptic_curve_list[elliptic_curve_len++] = POLARSSL_ECP_DP_SECP256R1;
    elliptic_curve_list[elliptic_curve_len++] = 0x00;
    elliptic_curve_list[elliptic_curve_len++] = POLARSSL_ECP_DP_SECP224R1;
    elliptic_curve_list[elliptic_curve_len++] = 0x00;
    elliptic_curve_list[elliptic_curve_len++] = POLARSSL_ECP_DP_SECP192R1;

    *p++ = (unsigned char)( ( TLS_EXT_SUPPORTED_ELLIPTIC_CURVES >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( TLS_EXT_SUPPORTED_ELLIPTIC_CURVES      ) & 0xFF );

    *p++ = (unsigned char)( ( ( elliptic_curve_len + 2 ) >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( ( elliptic_curve_len + 2 )      ) & 0xFF );

    *p++ = (unsigned char)( ( ( elliptic_curve_len     ) >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( ( elliptic_curve_len     )      ) & 0xFF );

    memcpy( p, elliptic_curve_list, elliptic_curve_len );

    *olen = 6 + elliptic_curve_len;
}

static void ssl_write_supported_point_formats_ext( ssl_context *ssl,
                                                   unsigned char *buf,
                                                   size_t *olen )
{
    unsigned char *p = buf;

    *olen = 0;

    SSL_DEBUG_MSG( 3, ( "client hello, adding supported_point_formats extension" ) );

    *p++ = (unsigned char)( ( TLS_EXT_SUPPORTED_POINT_FORMATS >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( TLS_EXT_SUPPORTED_POINT_FORMATS      ) & 0xFF );

    *p++ = 0x00;
    *p++ = 3;

    *p++ = 2;
    *p++ = POLARSSL_ECP_PF_COMPRESSED;
    *p++ = POLARSSL_ECP_PF_UNCOMPRESSED;

    *olen = 7;
}
#endif

static int ssl_write_client_hello( ssl_context *ssl )
{
    int ret;
    size_t i, n, olen, ext_len = 0;
    unsigned char *buf;
    unsigned char *p;
    time_t t;

    SSL_DEBUG_MSG( 2, ( "=> write client hello" ) );

    if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE )
    {
        ssl->major_ver = ssl->min_major_ver;
        ssl->minor_ver = ssl->min_minor_ver;
    }

    if( ssl->max_major_ver == 0 && ssl->max_minor_ver == 0 )
    {
        ssl->max_major_ver = SSL_MAJOR_VERSION_3;
        ssl->max_minor_ver = SSL_MINOR_VERSION_3;
    }

    /*
     *     0  .   0   handshake type
     *     1  .   3   handshake length
     *     4  .   5   highest version supported
     *     6  .   9   current UNIX time
     *    10  .  37   random bytes
     */
    buf = ssl->out_msg;
    p = buf + 4;

    *p++ = (unsigned char) ssl->max_major_ver;
    *p++ = (unsigned char) ssl->max_minor_ver;

    SSL_DEBUG_MSG( 3, ( "client hello, max version: [%d:%d]",
                   buf[4], buf[5] ) );

    t = time( NULL );
    *p++ = (unsigned char)( t >> 24 );
    *p++ = (unsigned char)( t >> 16 );
    *p++ = (unsigned char)( t >>  8 );
    *p++ = (unsigned char)( t       );

    SSL_DEBUG_MSG( 3, ( "client hello, current time: %lu", t ) );

    if( ( ret = ssl->f_rng( ssl->p_rng, p, 28 ) ) != 0 )
        return( ret );

    p += 28;

    memcpy( ssl->handshake->randbytes, buf + 6, 32 );

    SSL_DEBUG_BUF( 3, "client hello, random bytes", buf + 6, 32 );

    /*
     *    38  .  38   session id length
     *    39  . 39+n  session id
     *   40+n . 41+n  ciphersuitelist length
     *   42+n . ..    ciphersuitelist
     *   ..   . ..    compression methods length
     *   ..   . ..    compression methods
     *   ..   . ..    extensions length
     *   ..   . ..    extensions
     */
    n = ssl->session_negotiate->length;

    if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE || n < 16 || n > 32 ||
        ssl->handshake->resume == 0 )
        n = 0;

    *p++ = (unsigned char) n;

    for( i = 0; i < n; i++ )
        *p++ = ssl->session_negotiate->id[i];

    SSL_DEBUG_MSG( 3, ( "client hello, session id len.: %d", n ) );
    SSL_DEBUG_BUF( 3,   "client hello, session id", buf + 39, n );

    for( n = 0; ssl->ciphersuites[n] != 0; n++ );
    if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) n++;
    *p++ = (unsigned char)( n >> 7 );
    *p++ = (unsigned char)( n << 1 );

    /*
     * Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV
     */
    if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE )
    {
        *p++ = (unsigned char)( SSL_EMPTY_RENEGOTIATION_INFO >> 8 );
        *p++ = (unsigned char)( SSL_EMPTY_RENEGOTIATION_INFO      );
        n--;
    }

    SSL_DEBUG_MSG( 3, ( "client hello, got %d ciphersuites", n ) );

    for( i = 0; i < n; i++ )
    {
        SSL_DEBUG_MSG( 3, ( "client hello, add ciphersuite: %2d",
                       ssl->ciphersuites[i] ) );

        *p++ = (unsigned char)( ssl->ciphersuites[i] >> 8 );
        *p++ = (unsigned char)( ssl->ciphersuites[i]      );
    }

#if defined(POLARSSL_ZLIB_SUPPORT)
    SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 2 ) );
    SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d %d",
                        SSL_COMPRESS_DEFLATE, SSL_COMPRESS_NULL ) );

    *p++ = 2;
    *p++ = SSL_COMPRESS_DEFLATE;
    *p++ = SSL_COMPRESS_NULL;
#else
    SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 1 ) );
    SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d", SSL_COMPRESS_NULL ) );

    *p++ = 1;
    *p++ = SSL_COMPRESS_NULL;
#endif

    // First write extensions, then the total length
    //
    ssl_write_hostname_ext( ssl, p + 2 + ext_len, &olen );
    ext_len += olen;

    ssl_write_renegotiation_ext( ssl, p + 2 + ext_len, &olen );
    ext_len += olen;

    ssl_write_signature_algorithms_ext( ssl, p + 2 + ext_len, &olen );
    ext_len += olen;

#if defined(POLARSSL_ECDH_C)
    ssl_write_supported_elliptic_curves_ext( ssl, p + 2 + ext_len, &olen );
    ext_len += olen;

    ssl_write_supported_point_formats_ext( ssl, p + 2 + ext_len, &olen );
    ext_len += olen;
#endif

    SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d",
                   ext_len ) );

    *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF );
    *p++ = (unsigned char)( ( ext_len      ) & 0xFF );
    p += ext_len;

    ssl->out_msglen  = p - buf;
    ssl->out_msgtype = SSL_MSG_HANDSHAKE;
    ssl->out_msg[0]  = SSL_HS_CLIENT_HELLO;

    ssl->state++;

    if( ( ret = ssl_write_record( ssl ) ) != 0 )
    {
        SSL_DEBUG_RET( 1, "ssl_write_record", ret );
{'fraction_non_alphanumeric': 0.14028923931693765, 'fraction_numerical': 0.024470953509273634, 'mean_word_length': 2.384349509193972, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 207, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4693464', 'n_tokens_mistral': 9627, 'n_tokens_neox': 8863, 'n_words': 1963}