summaryrefslogtreecommitdiff
path: root/lib/gnutls_alert.c
blob: 1aa4bd6e2e9764bce1172b63635706ee683a7b02 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 *      Copyright (C) 2000,2001 Nikos Mavroyanopoulos
 *
 * This file is part of GNUTLS.
 *
 * GNUTLS 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.
 *
 * GNUTLS 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

#include <gnutls_int.h>
#include <gnutls_errors.h>
#include <gnutls_alert.h>
#include <gnutls_record.h>
#include <debug.h>

/**
  * gnutls_alert_send - This function sends an alert message to the peer
  * @state: is a &GNUTLS_STATE structure.
  * @level: is the level of the alert
  * @desc: is the alert description
  *
  * This function will send an alert to the peer in order to inform
  * him of something important (eg. his Certificate could not be verified).
  * If the alert level is Fatal then the peer is expected to close the
  * connection, otherwise he may ignore the alert and continue.
  * Returns 0 on success.
  *
  **/
int gnutls_alert_send( GNUTLS_STATE state, GNUTLS_AlertLevel level, GNUTLS_AlertDescription desc)
{
	uint8 data[2];
	int ret;
	
	data[0] = (uint8) level;
	data[1] = (uint8) desc;

	_gnutls_record_log( "REC: Sending Alert[%d|%d] - %s\n", data[0], data[1], _gnutls_alert2str((int)data[1]));

	if ( (ret = gnutls_send_int( state, GNUTLS_ALERT, -1, data, 2)) >= 0)
		return 0;
	else
		return ret;
}

/* Sends the appropriate alert, depending
 * on the error message.
 */
/**
  * gnutls_alert_send_appropriate - This function sends an alert to the peer depending on the error code
  * @state: is a &GNUTLS_STATE structure.
  * @err: is an integer
  *
  * Sends an alert to the peer depending on the error code returned by a gnutls
  * function. All alerts sent by this function are fatal, so connection should
  * be considered terminated after calling this function. The only exception
  * is when err == GNUTLS_E_REHANDSHAKE, then a warning alert is sent to
  * the peer indicating the no renegotiation will be performed.
  *
  * This function may also return GNUTLS_E_AGAIN, or GNUTLS_E_INTERRUPTED.
  *
  * If the return value is GNUTLS_E_UNIMPLEMENTED_FEATURE, then no alert has
  * been sent to the peer.
  *
  **/
int gnutls_alert_send_appropriate( GNUTLS_STATE state, int err) {
int ret = GNUTLS_E_UNIMPLEMENTED_FEATURE;
	switch (err) { /* send appropriate alert */
		case GNUTLS_E_DECRYPTION_FAILED:
			/* GNUTLS_A_DECRYPTION_FAILED is not sent, because
			 * it is not defined in SSL3.
			 */
			ret = gnutls_alert_send( state, GNUTLS_AL_FATAL, GNUTLS_A_BAD_RECORD_MAC);
			break;
		case GNUTLS_E_DECOMPRESSION_FAILED:
			ret = gnutls_alert_send( state, GNUTLS_AL_FATAL, GNUTLS_A_DECOMPRESSION_FAILURE);
			break;
		case GNUTLS_E_ILLEGAL_PARAMETER:
                        ret = gnutls_alert_send( state, GNUTLS_AL_FATAL, GNUTLS_A_ILLEGAL_PARAMETER);
                        break;
		case GNUTLS_E_ASN1_PARSING_ERROR:
		case GNUTLS_E_NO_CERTIFICATE_FOUND:
                        ret = gnutls_alert_send( state, GNUTLS_AL_FATAL, GNUTLS_A_BAD_CERTIFICATE);
                        break;
		case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
                        ret = gnutls_alert_send( state, GNUTLS_AL_FATAL, GNUTLS_A_HANDSHAKE_FAILURE);
                        break;
		case GNUTLS_E_UNEXPECTED_PACKET:
                        ret = gnutls_alert_send( state, GNUTLS_AL_FATAL, GNUTLS_A_UNEXPECTED_MESSAGE);
                        break;
		case GNUTLS_E_REHANDSHAKE:
                        ret = gnutls_alert_send( state, GNUTLS_AL_WARNING, GNUTLS_A_NO_RENEGOTIATION);
                        break;
		case GNUTLS_E_UNSUPPORTED_VERSION_PACKET:
                        ret = gnutls_alert_send( state, GNUTLS_AL_WARNING, GNUTLS_A_PROTOCOL_VERSION);
			break;
		case GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE:
                        ret = gnutls_alert_send( state, GNUTLS_AL_WARNING, GNUTLS_A_UNSUPPORTED_CERTIFICATE);
			break;
		case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
			ret = gnutls_alert_send( state, GNUTLS_AL_FATAL, GNUTLS_A_RECORD_OVERFLOW);
			break;
	}
	return ret;
}

/**
  * gnutls_alert_get_last - Returns the last alert number received.
  * @state: is a &GNUTLS_STATE structure.
  *
  * Returns the last alert number received. This function
  * should be called if GNUTLS_E_WARNING_ALERT_RECEIVED or
  * GNUTLS_E_FATAL_ALERT_RECEIVED has been returned by a gnutls function.
  * The peer may send alerts if he thinks some things were not 
  * right. Check gnutls.h for the available alert descriptions.
  **/
GNUTLS_AlertDescription gnutls_alert_get_last( GNUTLS_STATE state) {
	return state->gnutls_internals.last_alert;
}