static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
{
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    size_t signature_len = 0;
#if defined(MBEDTLS_KEY_EXCHANGE_SOME_NON_PFS_ENABLED)
    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
                            ssl->handshake->ciphersuite_info;
#endif /* MBEDTLS_KEY_EXCHANGE_SOME_NON_PFS_ENABLED */

    MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) );

#if defined(MBEDTLS_KEY_EXCHANGE_SOME_NON_PFS_ENABLED)
    /* Extract static ECDH parameters and abort if ServerKeyExchange
     * is not needed. */
    if( mbedtls_ssl_ciphersuite_no_pfs( ciphersuite_info ) )
    {
        /* For suites involving ECDH, extract DH parameters
         * from certificate at this point. */
#if defined(MBEDTLS_KEY_EXCHANGE_SOME_ECDH_ENABLED)
        if( mbedtls_ssl_ciphersuite_uses_ecdh( ciphersuite_info ) )
        {
            ssl_get_ecdh_params_from_cert( ssl );
        }
#endif /* MBEDTLS_KEY_EXCHANGE_SOME_ECDH_ENABLED */

        /* Key exchanges not involving ephemeral keys don't use
         * ServerKeyExchange, so end here. */
        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) );
        ssl->state++;
        return( 0 );
    }
#endif /* MBEDTLS_KEY_EXCHANGE_SOME_NON_PFS_ENABLED */

#if defined(MBEDTLS_KEY_EXCHANGE_WITH_SERVER_SIGNATURE_ENABLED) && \
    defined(MBEDTLS_SSL_ASYNC_PRIVATE)
    /* If we have already prepared the message and there is an ongoing
     * signature operation, resume signing. */
    if( ssl->handshake->async_in_progress != 0 )
    {
        MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming signature operation" ) );
        ret = ssl_resume_server_key_exchange( ssl, &signature_len );
    }
    else
#endif /* defined(MBEDTLS_KEY_EXCHANGE_WITH_SERVER_SIGNATURE_ENABLED) &&
          defined(MBEDTLS_SSL_ASYNC_PRIVATE) */
    {
        /* ServerKeyExchange is needed. Prepare the message. */
        ret = ssl_prepare_server_key_exchange( ssl, &signature_len );
    }

    if( ret != 0 )
    {
        /* If we're starting to write a new message, set ssl->out_msglen
         * to 0. But if we're resuming after an asynchronous message,
         * out_msglen is the amount of data written so far and mst be
         * preserved. */
        if( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS )
            MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange (pending)" ) );
        else
            ssl->out_msglen = 0;
        return( ret );
    }

    /* If there is a signature, write its length.
     * ssl_prepare_server_key_exchange already wrote the signature
     * itself at its proper place in the output buffer. */
#if defined(MBEDTLS_KEY_EXCHANGE_WITH_SERVER_SIGNATURE_ENABLED)
    if( signature_len != 0 )
    {
        ssl->out_msg[ssl->out_msglen++] = MBEDTLS_BYTE_1( signature_len );
        ssl->out_msg[ssl->out_msglen++] = MBEDTLS_BYTE_0( signature_len );

        MBEDTLS_SSL_DEBUG_BUF( 3, "my signature",
                               ssl->out_msg + ssl->out_msglen,
                               signature_len );

        /* Skip over the already-written signature */
        ssl->out_msglen += signature_len;
    }
#endif /* MBEDTLS_KEY_EXCHANGE_WITH_SERVER_SIGNATURE_ENABLED */

    /* Add header and send. */
    ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE;
    ssl->out_msg[0]  = MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE;

    ssl->state++;

    if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
    {
        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
        return( ret );
    }

    MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange" ) );
    return( 0 );
}