/* This is a temporary function to be used before the generate_*
   internal API is changed to use mbuffers. For now we don't avoid the
   extra alloc + memcpy. */
static inline int
send_handshake (gnutls_session_t session, opaque * data, size_t size,
                gnutls_handshake_description_t type)
{
  mbuffer_st *bufel;

  if (data == NULL && size == 0)
    return _gnutls_send_handshake (session, NULL, type);

  if (data == NULL && size > 0)
    {
      gnutls_assert ();
      return GNUTLS_E_INVALID_REQUEST;
    }

  bufel = _gnutls_handshake_alloc(session, size, size);
  if (bufel == NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_MEMORY_ERROR;
    }

  _mbuffer_set_udata (bufel, data, size);

  return _gnutls_send_handshake (session, bufel, type);
}
Beispiel #2
0
/* This is the function for the client to send the certificate
 * verify message
 */
int
_gnutls_send_client_certificate_verify (gnutls_session_t session, int again)
{
    uint8_t *data;
    int ret = 0;
    int data_size;

    /* This is a packet that is only sent by the client
     */
    if (session->security_parameters.entity == GNUTLS_SERVER)
        return 0;

    /* if certificate verify is not needed just exit
     */
    if (session->key->certificate_requested == 0)
        return 0;

    if (session->internals.auth_struct->gnutls_generate_client_cert_vrfy ==
            NULL)
    {
        gnutls_assert ();
        return 0;			/* this algorithm does not support cli_cert_vrfy
				 */
    }

    data = NULL;
    data_size = 0;

    if (again == 0)
    {
        data_size =
            session->internals.
            auth_struct->gnutls_generate_client_cert_vrfy (session, &data);
        if (data_size < 0)
        {
            gnutls_assert ();
            return data_size;
        }
        if (data_size == 0)
            return 0;

    }
    ret =
        _gnutls_send_handshake (session, data,
                                data_size, GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY);
    gnutls_free (data);

    return ret;
}
Beispiel #3
0
/* This is called when we want to receive the key exchange message of the
 * server. It does nothing if this type of message is not required
 * by the selected ciphersuite.
 */
int
_gnutls_send_server_kx_message (gnutls_session_t session, int again)
{
    uint8_t *data = NULL;
    int data_size = 0;
    int ret = 0;

    if (session->internals.auth_struct->gnutls_generate_server_kx == NULL)
        return 0;

    data = NULL;
    data_size = 0;

    if (again == 0)
    {
        data_size =
            session->internals.auth_struct->gnutls_generate_server_kx (session,
                    &data);

        if (data_size == GNUTLS_E_INT_RET_0)
        {
            gnutls_assert ();
            return 0;
        }

        if (data_size < 0)
        {
            gnutls_assert ();
            return data_size;
        }
    }

    ret =
        _gnutls_send_handshake (session, data, data_size,
                                GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE);
    gnutls_free (data);

    if (ret < 0)
    {
        gnutls_assert ();
        return ret;
    }
    return data_size;
}
Beispiel #4
0
/* This function sends a certificate request message to the
 * client.
 */
int
_gnutls_send_server_certificate_request (gnutls_session_t session, int again)
{
    uint8_t *data = NULL;
    int data_size = 0;
    int ret = 0;

    if (session->internals.
            auth_struct->gnutls_generate_server_certificate_request == NULL)
        return 0;

    if (session->internals.send_cert_req <= 0)
        return 0;

    data = NULL;
    data_size = 0;

    if (again == 0)
    {
        data_size =
            session->internals.
            auth_struct->gnutls_generate_server_certificate_request (session,
                    &data);

        if (data_size < 0)
        {
            gnutls_assert ();
            return data_size;
        }
    }
    ret =
        _gnutls_send_handshake (session, data, data_size,
                                GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST);
    gnutls_free (data);

    if (ret < 0)
    {
        gnutls_assert ();
        return ret;
    }
    return data_size;
}
Beispiel #5
0
int
_gnutls_send_server_certificate_status(gnutls_session_t session, int again)
{
	mbuffer_st *bufel = NULL;
	uint8_t *data;
	int data_size = 0;
	int ret;
	status_request_ext_st *priv = NULL;
	extension_priv_data_t epriv;
	if (again == 0) {
		ret =
		    _gnutls_ext_get_session_data(session,
						 GNUTLS_EXTENSION_STATUS_REQUEST,
						 &epriv);
		if (ret < 0)
			return 0;
		priv = epriv.ptr;

		if (!priv->response.size)
			return 0;

		data_size = priv->response.size + 4;
		bufel =
		    _gnutls_handshake_alloc(session, data_size, data_size);
		if (!bufel)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		data = _mbuffer_get_udata_ptr(bufel);

		data[0] = 0x01;
		_gnutls_write_uint24(priv->response.size, &data[1]);
		memcpy(&data[4], priv->response.data, priv->response.size);

		_gnutls_free_datum(&priv->response);
	}
	return _gnutls_send_handshake(session, data_size ? bufel : NULL,
				      GNUTLS_HANDSHAKE_CERTIFICATE_STATUS);
}
Beispiel #6
0
int _gnutls13_send_key_update(gnutls_session_t session, unsigned again, unsigned flags /* GNUTLS_KU_* */)
{
	int ret;
	mbuffer_st *bufel = NULL;
	uint8_t val;

	if (again == 0) {
		if (flags & GNUTLS_KU_PEER) {
			/* mark that we asked a key update to prevent an
			 * infinite ping pong when receiving the reply */
			session->internals.hsk_flags |= HSK_KEY_UPDATE_ASKED;
			val = 0x01;
		} else {
			val = 0x00;
		}

		_gnutls_handshake_log("HSK[%p]: sending key update (%u)\n", session, (unsigned)val);

		bufel = _gnutls_handshake_alloc(session, 1);
		if (bufel == NULL)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		_mbuffer_set_udata_size(bufel, 0);
		ret = _mbuffer_append_data(bufel, &val, 1);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

	}

	return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_KEY_UPDATE);

cleanup:
	_mbuffer_xfree(&bufel);
	return ret;
}
Beispiel #7
0
/* This is called when we want send our certificate
 */
int
_gnutls_send_client_certificate (gnutls_session_t session, int again)
{
    uint8_t *data = NULL;
    int data_size = 0;
    int ret = 0;


    if (session->key->certificate_requested == 0)
        return 0;

    if (session->internals.auth_struct->gnutls_generate_client_certificate ==
            NULL)
        return 0;

    data = NULL;
    data_size = 0;

    if (again == 0)
    {
        if (gnutls_protocol_get_version (session) != GNUTLS_SSL3 ||
                session->internals.selected_cert_list_length > 0)
        {
            /* TLS 1.0 or SSL 3.0 with a valid certificate
             */
            data_size =
                session->internals.
                auth_struct->gnutls_generate_client_certificate (session, &data);

            if (data_size < 0)
            {
                gnutls_assert ();
                return data_size;
            }
        }
    }

    /* In the SSL 3.0 protocol we need to send a
     * no certificate alert instead of an
     * empty certificate.
     */
    if (gnutls_protocol_get_version (session) == GNUTLS_SSL3 &&
            session->internals.selected_cert_list_length == 0)
    {
        ret =
            gnutls_alert_send (session, GNUTLS_AL_WARNING,
                               GNUTLS_A_SSL3_NO_CERTIFICATE);

    }
    else
    {   /* TLS 1.0 or SSL 3.0 with a valid certificate
        */
        ret =
            _gnutls_send_handshake (session, data, data_size,
                                    GNUTLS_HANDSHAKE_CERTIFICATE_PKT);
        gnutls_free (data);
    }

    if (ret < 0)
    {
        gnutls_assert ();
        return ret;
    }

    return data_size;
}
Beispiel #8
0
int _gnutls13_send_certificate(gnutls_session_t session, unsigned again)
{
	int ret;
	gnutls_pcert_st *apr_cert_list = NULL;
	gnutls_privkey_t apr_pkey = NULL;
	int apr_cert_list_length = 0;
	mbuffer_st *bufel = NULL;
	gnutls_buffer_st buf;
	unsigned pos_mark, ext_pos_mark;
	unsigned i;
	struct ocsp_req_ctx_st ctx;
	gnutls_certificate_credentials_t cred;

	if (again == 0) {
		if (!session->internals.initial_negotiation_completed &&
		    session->internals.hsk_flags & HSK_PSK_SELECTED)
			return 0;

		if (session->security_parameters.entity == GNUTLS_SERVER &&
		    session->internals.resumed)
			return 0;

		cred = (gnutls_certificate_credentials_t)
		    _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
		if (cred == NULL) {
			gnutls_assert();
			return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
		}

		if (session->security_parameters.entity == GNUTLS_CLIENT &&
		    !(session->internals.hsk_flags & HSK_CRT_ASKED)) {
			return 0;
		}

		ret = _gnutls_get_selected_cert(session, &apr_cert_list,
						&apr_cert_list_length, &apr_pkey);
		if (ret < 0)
			return gnutls_assert_val(ret);

		ret = _gnutls_buffer_init_handshake_mbuffer(&buf);
		if (ret < 0)
			return gnutls_assert_val(ret);

		if (session->security_parameters.entity == GNUTLS_CLIENT) {
			ret = _gnutls_buffer_append_data_prefix(&buf, 8,
								session->internals.post_handshake_cr_context.data,
								session->internals.post_handshake_cr_context.size);
			if (ret < 0) {
				gnutls_assert();
				goto cleanup;
			}

		} else {
			ret = _gnutls_buffer_append_prefix(&buf, 8, 0);
			if (ret < 0) {
				gnutls_assert();
				goto cleanup;
			}
		}

		/* mark total size */
		pos_mark = buf.length;
		ret = _gnutls_buffer_append_prefix(&buf, 24, 0);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		for (i=0;i<(unsigned)apr_cert_list_length;i++) {
			ret = _gnutls_buffer_append_data_prefix(&buf, 24,
								apr_cert_list[i].cert.data,
								apr_cert_list[i].cert.size);
			if (ret < 0) {
				gnutls_assert();
				goto cleanup;
			}

#ifdef ENABLE_OCSP
			if ((session->internals.selected_ocsp_length > 0 ||
			     session->internals.selected_ocsp_func) &&
			    _gnutls_hello_ext_is_present(session, GNUTLS_EXTENSION_STATUS_REQUEST)) {
				/* append status response if available */
				ret = _gnutls_extv_append_init(&buf);
				if (ret < 0) {
					gnutls_assert();
					goto cleanup;
				}
				ext_pos_mark = ret;

				ctx.pcert = &apr_cert_list[i];
				ctx.cert_index = i;
				ctx.session = session;
				ctx.cred = cred;
				ret = _gnutls_extv_append(&buf, STATUS_REQUEST_TLS_ID,
							  &ctx, append_status_request);
				if (ret < 0) {
					gnutls_assert();
					goto cleanup;
				}

				ret = _gnutls_extv_append_final(&buf, ext_pos_mark, 0);
				if (ret < 0) {
					gnutls_assert();
					goto cleanup;
				}
			} else
#endif
			{
				ret = _gnutls_buffer_append_prefix(&buf, 16, 0);
				if (ret < 0) {
					gnutls_assert();
					goto cleanup;
				}
			}
		}

		_gnutls_write_uint24(buf.length-pos_mark-3, &buf.data[pos_mark]);

		bufel = _gnutls_buffer_to_mbuffer(&buf);
	}

	return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_CERTIFICATE_PKT);

 cleanup:
	_gnutls_buffer_clear(&buf);
	return ret;
}
Beispiel #9
0
/*
 * Return zero if session tickets haven't been enabled.
 */
int _gnutls_send_new_session_ticket(gnutls_session_t session, int again)
{
	mbuffer_st *bufel = NULL;
	uint8_t *data = NULL, *p;
	int data_size = 0;
	int ret;
	gnutls_datum_t state = { NULL, 0 };
	uint16_t epoch_saved = session->security_parameters.epoch_write;
	gnutls_datum_t ticket_data;

	if (again == 0) {
		if (session->internals.flags & GNUTLS_NO_TICKETS)
			return 0;
		if (!session->internals.session_ticket_renew)
			return 0;

		_gnutls_handshake_log
		    ("HSK[%p]: sending session ticket\n", session);

		/* XXX: Temporarily set write algorithms to be used.
		   _gnutls_write_connection_state_init() does this job, but it also
		   triggers encryption, while NewSessionTicket should not be
		   encrypted in the record layer. */
		ret =
		    _gnutls_epoch_set_keys(session,
					   session->security_parameters.
					   epoch_next, 0);
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}

		/* Under TLS1.2 with session tickets, the session ID is used for different
		 * purposes than the TLS1.0 session ID. Ensure that there is an internally
		 * set value which the server will see on the original and resumed sessions */
		if (session->internals.resumed != RESUME_TRUE) {
			ret = _gnutls_generate_session_id(session->security_parameters.
							  session_id,
							  &session->security_parameters.
							  session_id_size);
			if (ret < 0) {
				gnutls_assert();
				return ret;
			}
		}

		session->security_parameters.epoch_write =
		    session->security_parameters.epoch_next;

		/* Pack security parameters. */
		ret = _gnutls_session_pack(session, &state);
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}

		/* Generate an encrypted ticket */
		ret = _gnutls_encrypt_session_ticket(session, &state, &ticket_data);
		session->security_parameters.epoch_write = epoch_saved;
		_gnutls_free_datum(&state);
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}

		bufel =
		    _gnutls_handshake_alloc(session, 
					    4 + 2 + ticket_data.size);
		if (!bufel) {
			gnutls_assert();
			_gnutls_free_datum(&ticket_data);
			return GNUTLS_E_MEMORY_ERROR;
		}

		data = _mbuffer_get_udata_ptr(bufel);
		p = data;

		_gnutls_write_uint32(session->internals.expire_time, p);
		p += 4;

		_gnutls_write_uint16(ticket_data.size, p);
		p += 2;

		memcpy(p, ticket_data.data, ticket_data.size);
		p += ticket_data.size;

		_gnutls_free_datum(&ticket_data);

		data_size = p - data;

		session->internals.hsk_flags |= HSK_TLS12_TICKET_SENT;
	}
	return _gnutls_send_handshake(session, data_size ? bufel : NULL,
				      GNUTLS_HANDSHAKE_NEW_SESSION_TICKET);
}
Beispiel #10
0
int _gnutls_send_new_session_ticket(gnutls_session_t session, int again)
{
    mbuffer_st *bufel = NULL;
    uint8_t *data = NULL, *p;
    int data_size = 0;
    int ret;
    struct ticket_st ticket;
    uint16_t ticket_len;
    session_ticket_ext_st *priv = NULL;
    extension_priv_data_t epriv;
    uint16_t epoch_saved = session->security_parameters.epoch_write;

    if (again == 0) {
        ret =
            _gnutls_ext_get_session_data(session,
                                         GNUTLS_EXTENSION_SESSION_TICKET,
                                         &epriv);
        if (ret < 0)
            return 0;
        priv = epriv;

        if (!priv->session_ticket_renew)
            return 0;

        /* XXX: Temporarily set write algorithms to be used.
           _gnutls_write_connection_state_init() does this job, but it also
           triggers encryption, while NewSessionTicket should not be
           encrypted in the record layer. */
        ret =
            _gnutls_epoch_set_keys(session,
                                   session->security_parameters.
                                   epoch_next);
        if (ret < 0) {
            gnutls_assert();
            return ret;
        }

        session->security_parameters.epoch_write =
            session->security_parameters.epoch_next;

        ret = encrypt_ticket(session, priv, &ticket);
        session->security_parameters.epoch_write = epoch_saved;
        if (ret < 0) {
            gnutls_assert();
            return ret;
        }

        ticket_len =
            KEY_NAME_SIZE + IV_SIZE + 2 +
            ticket.encrypted_state_len + MAC_SIZE;

        bufel =
            _gnutls_handshake_alloc(session,
                                    4 + 2 + ticket_len);
        if (!bufel) {
            gnutls_assert();
            gnutls_free(ticket.encrypted_state);
            return GNUTLS_E_MEMORY_ERROR;
        }

        data = _mbuffer_get_udata_ptr(bufel);
        p = data;

        _gnutls_write_uint32(session->internals.expire_time, p);
        p += 4;

        _gnutls_write_uint16(ticket_len, p);
        p += 2;

        memcpy(p, ticket.key_name, KEY_NAME_SIZE);
        p += KEY_NAME_SIZE;

        memcpy(p, ticket.IV, IV_SIZE);
        p += IV_SIZE;

        _gnutls_write_uint16(ticket.encrypted_state_len, p);
        p += 2;

        memcpy(p, ticket.encrypted_state, ticket.encrypted_state_len);
        gnutls_free(ticket.encrypted_state);
        p += ticket.encrypted_state_len;

        memcpy(p, ticket.mac, MAC_SIZE);
        p += MAC_SIZE;

        data_size = p - data;

        session->internals.ticket_sent = 1;
    }
    return _gnutls_send_handshake(session, data_size ? bufel : NULL,
                                  GNUTLS_HANDSHAKE_NEW_SESSION_TICKET);
}