Fix CVE-2017-6891 in minitasn1 code
[platform/upstream/gnutls.git] / doc / examples / ex-client-x509.c
1 /* This example code is placed in the public domain. */
2
3 #ifdef HAVE_CONFIG_H
4 #include <config.h>
5 #endif
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <gnutls/gnutls.h>
11 #include <gnutls/x509.h>
12 #include "examples.h"
13
14 /* A very basic TLS client, with X.509 authentication and server certificate
15  * verification. Note that error checking for missing files etc. is omitted
16  * for simplicity.
17  */
18
19 #define MAX_BUF 1024
20 #define CAFILE "/etc/ssl/certs/ca-certificates.crt"
21 #define MSG "GET / HTTP/1.0\r\n\r\n"
22
23 extern int tcp_connect(void);
24 extern void tcp_close(int sd);
25 static int _verify_certificate_callback(gnutls_session_t session);
26
27 int main(void)
28 {
29         int ret, sd, ii;
30         gnutls_session_t session;
31         char buffer[MAX_BUF + 1];
32         const char *err;
33         gnutls_certificate_credentials_t xcred;
34
35         if (gnutls_check_version("3.1.4") == NULL) {
36                 fprintf(stderr, "GnuTLS 3.1.4 or later is required for this example\n");
37                 exit(1);
38         }
39
40         /* for backwards compatibility with gnutls < 3.3.0 */
41         gnutls_global_init();
42
43         /* X509 stuff */
44         gnutls_certificate_allocate_credentials(&xcred);
45
46         /* sets the trusted cas file
47          */
48         gnutls_certificate_set_x509_trust_file(xcred, CAFILE,
49                                                GNUTLS_X509_FMT_PEM);
50         gnutls_certificate_set_verify_function(xcred,
51                                                _verify_certificate_callback);
52
53         /* If client holds a certificate it can be set using the following:
54          *
55          gnutls_certificate_set_x509_key_file (xcred, 
56          "cert.pem", "key.pem", 
57          GNUTLS_X509_FMT_PEM); 
58          */
59
60         /* Initialize TLS session 
61          */
62         gnutls_init(&session, GNUTLS_CLIENT);
63
64         gnutls_session_set_ptr(session, (void *) "my_host_name");
65
66         gnutls_server_name_set(session, GNUTLS_NAME_DNS, "my_host_name",
67                                strlen("my_host_name"));
68
69         /* use default priorities */
70         gnutls_set_default_priority(session);
71 #if 0
72         /* if more fine-graned control is required */
73         ret = gnutls_priority_set_direct(session, 
74                                          "NORMAL", &err);
75         if (ret < 0) {
76                 if (ret == GNUTLS_E_INVALID_REQUEST) {
77                         fprintf(stderr, "Syntax error at: %s\n", err);
78                 }
79                 exit(1);
80         }
81 #endif
82
83         /* put the x509 credentials to the current session
84          */
85         gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
86
87         /* connect to the peer
88          */
89         sd = tcp_connect();
90
91         gnutls_transport_set_int(session, sd);
92         gnutls_handshake_set_timeout(session,
93                                      GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
94
95         /* Perform the TLS handshake
96          */
97         do {
98                 ret = gnutls_handshake(session);
99         }
100         while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
101
102         if (ret < 0) {
103                 fprintf(stderr, "*** Handshake failed\n");
104                 gnutls_perror(ret);
105                 goto end;
106         } else {
107                 char *desc;
108
109                 desc = gnutls_session_get_desc(session);
110                 printf("- Session info: %s\n", desc);
111                 gnutls_free(desc);
112         }
113
114         gnutls_record_send(session, MSG, strlen(MSG));
115
116         ret = gnutls_record_recv(session, buffer, MAX_BUF);
117         if (ret == 0) {
118                 printf("- Peer has closed the TLS connection\n");
119                 goto end;
120         } else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) {
121                 fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret));
122         } else if (ret < 0) {
123                 fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret));
124                 goto end;
125         }
126
127         if (ret > 0) {
128                 printf("- Received %d bytes: ", ret);
129                 for (ii = 0; ii < ret; ii++) {
130                         fputc(buffer[ii], stdout);
131                 }
132                 fputs("\n", stdout);
133         }
134
135         gnutls_bye(session, GNUTLS_SHUT_RDWR);
136
137       end:
138
139         tcp_close(sd);
140
141         gnutls_deinit(session);
142
143         gnutls_certificate_free_credentials(xcred);
144
145         gnutls_global_deinit();
146
147         return 0;
148 }
149
150 /* This function will verify the peer's certificate, and check
151  * if the hostname matches, as well as the activation, expiration dates.
152  */
153 static int _verify_certificate_callback(gnutls_session_t session)
154 {
155         unsigned int status;
156         int ret, type;
157         const char *hostname;
158         gnutls_datum_t out;
159
160         /* read hostname */
161         hostname = gnutls_session_get_ptr(session);
162
163         /* This verification function uses the trusted CAs in the credentials
164          * structure. So you must have installed one or more CA certificates.
165          */
166
167          /* The following demonstrate two different verification functions,
168           * the more flexible gnutls_certificate_verify_peers(), as well
169           * as the old gnutls_certificate_verify_peers3(). */
170 #if 1
171         {
172         gnutls_typed_vdata_st data[2];
173
174         memset(data, 0, sizeof(data));
175
176         data[0].type = GNUTLS_DT_DNS_HOSTNAME;
177         data[0].data = (void*)hostname;
178
179         data[1].type = GNUTLS_DT_KEY_PURPOSE_OID;
180         data[1].data = (void*)GNUTLS_KP_TLS_WWW_SERVER;
181
182         ret = gnutls_certificate_verify_peers(session, data, 2,
183                                               &status);
184         }
185 #else
186         ret = gnutls_certificate_verify_peers3(session, hostname,
187                                                &status);
188 #endif
189         if (ret < 0) {
190                 printf("Error\n");
191                 return GNUTLS_E_CERTIFICATE_ERROR;
192         }
193
194         type = gnutls_certificate_type_get(session);
195
196         ret =
197             gnutls_certificate_verification_status_print(status, type,
198                                                          &out, 0);
199         if (ret < 0) {
200                 printf("Error\n");
201                 return GNUTLS_E_CERTIFICATE_ERROR;
202         }
203
204         printf("%s", out.data);
205
206         gnutls_free(out.data);
207
208         if (status != 0)        /* Certificate is not trusted */
209                 return GNUTLS_E_CERTIFICATE_ERROR;
210
211         /* notify gnutls to continue handshake normally */
212         return 0;
213 }