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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
/* This example code is placed in the public domain. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <gnutls/gnutls.h>
extern void check_alert(gnutls_session_t session, int ret);
extern int tcp_connect(void);
extern void tcp_close(int sd);
/* A very basic TLS client, with X.509 authentication and server certificate
* verification as well as session resumption.
*
* Note that error recovery is minimal for simplicity.
*/
#define CHECK(x) assert((x)>=0)
#define LOOP_CHECK(rval, cmd) \
do { \
rval = cmd; \
} while(rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED); \
assert(rval >= 0)
#define MAX_BUF 1024
#define MSG "GET / HTTP/1.0\r\n\r\n"
int main(void)
{
int ret;
int sd, ii;
gnutls_session_t session;
char buffer[MAX_BUF + 1];
gnutls_certificate_credentials_t xcred;
/* variables used in session resuming
*/
int t;
gnutls_datum_t sdata;
/* for backwards compatibility with gnutls < 3.3.0 */
CHECK(gnutls_global_init());
CHECK(gnutls_certificate_allocate_credentials(&xcred));
CHECK(gnutls_certificate_set_x509_system_trust(xcred));
for (t = 0; t < 2; t++) { /* connect 2 times to the server */
sd = tcp_connect();
CHECK(gnutls_init(&session, GNUTLS_CLIENT));
CHECK(gnutls_server_name_set(session, GNUTLS_NAME_DNS,
"www.example.com",
strlen("www.example.com")));
gnutls_session_set_verify_cert(session, "www.example.com", 0);
CHECK(gnutls_set_default_priority(session));
gnutls_transport_set_int(session, sd);
gnutls_handshake_set_timeout(session,
GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
xcred);
if (t > 0) {
/* if this is not the first time we connect */
CHECK(gnutls_session_set_data(session, sdata.data,
sdata.size));
gnutls_free(sdata.data);
}
/* Perform the TLS handshake
*/
do {
ret = gnutls_handshake(session);
}
while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
if (ret < 0) {
fprintf(stderr, "*** Handshake failed\n");
gnutls_perror(ret);
goto end;
} else {
printf("- Handshake was completed\n");
}
if (t == 0) { /* the first time we connect */
/* get the session data */
CHECK(gnutls_session_get_data2(session, &sdata));
} else { /* the second time we connect */
/* check if we actually resumed the previous session */
if (gnutls_session_is_resumed(session) != 0) {
printf("- Previous session was resumed\n");
} else {
fprintf(stderr,
"*** Previous session was NOT resumed\n");
}
}
LOOP_CHECK(ret, gnutls_record_send(session, MSG, strlen(MSG)));
LOOP_CHECK(ret, gnutls_record_recv(session, buffer, MAX_BUF));
if (ret == 0) {
printf("- Peer has closed the TLS connection\n");
goto end;
} else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) {
fprintf(stderr, "*** Warning: %s\n",
gnutls_strerror(ret));
} else if (ret < 0) {
fprintf(stderr, "*** Error: %s\n",
gnutls_strerror(ret));
goto end;
}
if (ret > 0) {
printf("- Received %d bytes: ", ret);
for (ii = 0; ii < ret; ii++) {
fputc(buffer[ii], stdout);
}
fputs("\n", stdout);
}
gnutls_bye(session, GNUTLS_SHUT_RDWR);
end:
tcp_close(sd);
gnutls_deinit(session);
} /* for() */
gnutls_certificate_free_credentials(xcred);
gnutls_global_deinit();
return 0;
}
|