/ samples / client_basic.c
client_basic.c
  1  /*
  2   * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
  3   *
  4   * Permission is hereby granted, free of charge, to any person obtaining 
  5   * a copy of this software and associated documentation files (the
  6   * "Software"), to deal in the Software without restriction, including
  7   * without limitation the rights to use, copy, modify, merge, publish,
  8   * distribute, sublicense, and/or sell copies of the Software, and to
  9   * permit persons to whom the Software is furnished to do so, subject to
 10   * the following conditions:
 11   *
 12   * The above copyright notice and this permission notice shall be 
 13   * included in all copies or substantial portions of the Software.
 14   *
 15   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
 16   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 17   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 18   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 19   * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 20   * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 21   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 22   * SOFTWARE.
 23   */
 24  
 25  #include <stdio.h>
 26  #include <stdlib.h>
 27  #include <string.h>
 28  #include <stdint.h>
 29  #include <errno.h>
 30  #include <signal.h>
 31  
 32  #include <sys/types.h>
 33  #include <sys/socket.h>
 34  #include <netdb.h>
 35  #include <netinet/in.h>
 36  #include <arpa/inet.h>
 37  #include <unistd.h>
 38  
 39  #include "bearssl.h"
 40  
 41  /*
 42   * Connect to the specified host and port. The connected socket is
 43   * returned, or -1 on error.
 44   */
 45  static int
 46  host_connect(const char *host, const char *port)
 47  {
 48  	struct addrinfo hints, *si, *p;
 49  	int fd;
 50  	int err;
 51  
 52  	memset(&hints, 0, sizeof hints);
 53  	hints.ai_family = PF_UNSPEC;
 54  	hints.ai_socktype = SOCK_STREAM;
 55  	err = getaddrinfo(host, port, &hints, &si);
 56  	if (err != 0) {
 57  		fprintf(stderr, "ERROR: getaddrinfo(): %s\n",
 58  			gai_strerror(err));
 59  		return -1;
 60  	}
 61  	fd = -1;
 62  	for (p = si; p != NULL; p = p->ai_next) {
 63  		struct sockaddr *sa;
 64  		void *addr;
 65  		char tmp[INET6_ADDRSTRLEN + 50];
 66  
 67  		sa = (struct sockaddr *)p->ai_addr;
 68  		if (sa->sa_family == AF_INET) {
 69  			addr = &((struct sockaddr_in *)sa)->sin_addr;
 70  		} else if (sa->sa_family == AF_INET6) {
 71  			addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
 72  		} else {
 73  			addr = NULL;
 74  		}
 75  		if (addr != NULL) {
 76  			inet_ntop(p->ai_family, addr, tmp, sizeof tmp);
 77  		} else {
 78  			sprintf(tmp, "<unknown family: %d>",
 79  				(int)sa->sa_family);
 80  		}
 81  		fprintf(stderr, "connecting to: %s\n", tmp);
 82  		fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
 83  		if (fd < 0) {
 84  			perror("socket()");
 85  			continue;
 86  		}
 87  		if (connect(fd, p->ai_addr, p->ai_addrlen) < 0) {
 88  			perror("connect()");
 89  			close(fd);
 90  			continue;
 91  		}
 92  		break;
 93  	}
 94  	if (p == NULL) {
 95  		freeaddrinfo(si);
 96  		fprintf(stderr, "ERROR: failed to connect\n");
 97  		return -1;
 98  	}
 99  	freeaddrinfo(si);
100  	fprintf(stderr, "connected.\n");
101  	return fd;
102  }
103  
104  /*
105   * Low-level data read callback for the simplified SSL I/O API.
106   */
107  static int
108  sock_read(void *ctx, unsigned char *buf, size_t len)
109  {
110  	for (;;) {
111  		ssize_t rlen;
112  
113  		rlen = read(*(int *)ctx, buf, len);
114  		if (rlen <= 0) {
115  			if (rlen < 0 && errno == EINTR) {
116  				continue;
117  			}
118  			return -1;
119  		}
120  		return (int)rlen;
121  	}
122  }
123  
124  /*
125   * Low-level data write callback for the simplified SSL I/O API.
126   */
127  static int
128  sock_write(void *ctx, const unsigned char *buf, size_t len)
129  {
130  	for (;;) {
131  		ssize_t wlen;
132  
133  		wlen = write(*(int *)ctx, buf, len);
134  		if (wlen <= 0) {
135  			if (wlen < 0 && errno == EINTR) {
136  				continue;
137  			}
138  			return -1;
139  		}
140  		return (int)wlen;
141  	}
142  }
143  
144  /*
145   * The hardcoded trust anchors. These are the two DN + public key that
146   * correspond to the self-signed certificates cert-root-rsa.pem and
147   * cert-root-ec.pem.
148   *
149   * C code for hardcoded trust anchors can be generated with the "brssl"
150   * command-line tool (with the "ta" command).
151   */
152  
153  static const unsigned char TA0_DN[] = {
154  	0x30, 0x1C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
155  	0x02, 0x43, 0x41, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03,
156  	0x13, 0x04, 0x52, 0x6F, 0x6F, 0x74
157  };
158  
159  static const unsigned char TA0_RSA_N[] = {
160  	0xB6, 0xD9, 0x34, 0xD4, 0x50, 0xFD, 0xB3, 0xAF, 0x7A, 0x73, 0xF1, 0xCE,
161  	0x38, 0xBF, 0x5D, 0x6F, 0x45, 0xE1, 0xFD, 0x4E, 0xB1, 0x98, 0xC6, 0x60,
162  	0x83, 0x26, 0xD2, 0x17, 0xD1, 0xC5, 0xB7, 0x9A, 0xA3, 0xC1, 0xDE, 0x63,
163  	0x39, 0x97, 0x9C, 0xF0, 0x5E, 0x5C, 0xC8, 0x1C, 0x17, 0xB9, 0x88, 0x19,
164  	0x6D, 0xF0, 0xB6, 0x2E, 0x30, 0x50, 0xA1, 0x54, 0x6E, 0x93, 0xC0, 0xDB,
165  	0xCF, 0x30, 0xCB, 0x9F, 0x1E, 0x27, 0x79, 0xF1, 0xC3, 0x99, 0x52, 0x35,
166  	0xAA, 0x3D, 0xB6, 0xDF, 0xB0, 0xAD, 0x7C, 0xCB, 0x49, 0xCD, 0xC0, 0xED,
167  	0xE7, 0x66, 0x10, 0x2A, 0xE9, 0xCE, 0x28, 0x1F, 0x21, 0x50, 0xFA, 0x77,
168  	0x4C, 0x2D, 0xDA, 0xEF, 0x3C, 0x58, 0xEB, 0x4E, 0xBF, 0xCE, 0xE9, 0xFB,
169  	0x1A, 0xDA, 0xA3, 0x83, 0xA3, 0xCD, 0xA3, 0xCA, 0x93, 0x80, 0xDC, 0xDA,
170  	0xF3, 0x17, 0xCC, 0x7A, 0xAB, 0x33, 0x80, 0x9C, 0xB2, 0xD4, 0x7F, 0x46,
171  	0x3F, 0xC5, 0x3C, 0xDC, 0x61, 0x94, 0xB7, 0x27, 0x29, 0x6E, 0x2A, 0xBC,
172  	0x5B, 0x09, 0x36, 0xD4, 0xC6, 0x3B, 0x0D, 0xEB, 0xBE, 0xCE, 0xDB, 0x1D,
173  	0x1C, 0xBC, 0x10, 0x6A, 0x71, 0x71, 0xB3, 0xF2, 0xCA, 0x28, 0x9A, 0x77,
174  	0xF2, 0x8A, 0xEC, 0x42, 0xEF, 0xB1, 0x4A, 0x8E, 0xE2, 0xF2, 0x1A, 0x32,
175  	0x2A, 0xCD, 0xC0, 0xA6, 0x46, 0x2C, 0x9A, 0xC2, 0x85, 0x37, 0x91, 0x7F,
176  	0x46, 0xA1, 0x93, 0x81, 0xA1, 0x74, 0x66, 0xDF, 0xBA, 0xB3, 0x39, 0x20,
177  	0x91, 0x93, 0xFA, 0x1D, 0xA1, 0xA8, 0x85, 0xE7, 0xE4, 0xF9, 0x07, 0xF6,
178  	0x10, 0xF6, 0xA8, 0x27, 0x01, 0xB6, 0x7F, 0x12, 0xC3, 0x40, 0xC3, 0xC9,
179  	0xE2, 0xB0, 0xAB, 0x49, 0x18, 0x3A, 0x64, 0xB6, 0x59, 0xB7, 0x95, 0xB5,
180  	0x96, 0x36, 0xDF, 0x22, 0x69, 0xAA, 0x72, 0x6A, 0x54, 0x4E, 0x27, 0x29,
181  	0xA3, 0x0E, 0x97, 0x15
182  };
183  
184  static const unsigned char TA0_RSA_E[] = {
185  	0x01, 0x00, 0x01
186  };
187  
188  static const unsigned char TA1_DN[] = {
189  	0x30, 0x1C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
190  	0x02, 0x43, 0x41, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03,
191  	0x13, 0x04, 0x52, 0x6F, 0x6F, 0x74
192  };
193  
194  static const unsigned char TA1_EC_Q[] = {
195  	0x04, 0x71, 0x74, 0xBA, 0xAB, 0xB9, 0x30, 0x2E, 0x81, 0xD5, 0xE5, 0x57,
196  	0xF9, 0xF3, 0x20, 0x68, 0x0C, 0x9C, 0xF9, 0x64, 0xDB, 0xB4, 0x20, 0x0D,
197  	0x6D, 0xEA, 0x40, 0xD0, 0x4A, 0x6E, 0x42, 0xFD, 0xB6, 0x9A, 0x68, 0x25,
198  	0x44, 0xF6, 0xDF, 0x7B, 0xC4, 0xFC, 0xDE, 0xDD, 0x7B, 0xBB, 0xC5, 0xDB,
199  	0x7C, 0x76, 0x3F, 0x41, 0x66, 0x40, 0x6E, 0xDB, 0xA7, 0x87, 0xC2, 0xE5,
200  	0xD8, 0xC5, 0xF3, 0x7F, 0x8D
201  };
202  
203  static const br_x509_trust_anchor TAs[2] = {
204  	{
205  		{ (unsigned char *)TA0_DN, sizeof TA0_DN },
206  		BR_X509_TA_CA,
207  		{
208  			BR_KEYTYPE_RSA,
209  			{ .rsa = {
210  				(unsigned char *)TA0_RSA_N, sizeof TA0_RSA_N,
211  				(unsigned char *)TA0_RSA_E, sizeof TA0_RSA_E,
212  			} }
213  		}
214  	},
215  	{
216  		{ (unsigned char *)TA1_DN, sizeof TA1_DN },
217  		BR_X509_TA_CA,
218  		{
219  			BR_KEYTYPE_EC,
220  			{ .ec = {
221  				BR_EC_secp256r1,
222  				(unsigned char *)TA1_EC_Q, sizeof TA1_EC_Q,
223  			} }
224  		}
225  	}
226  };
227  
228  #define TAs_NUM   2
229  
230  /*
231   * Main program: this is a simple program that expects 2 or 3 arguments.
232   * The first two arguments are a hostname and a port; the program will
233   * open a SSL connection with that server and port. It will then send
234   * a simple HTTP GET request, using the third argument as target path
235   * ("/" is used as path if no third argument was provided). The HTTP
236   * response, complete with header and contents, is received and written
237   * on stdout.
238   */
239  int
240  main(int argc, char *argv[])
241  {
242  	const char *host, *port, *path;
243  	int fd;
244  	br_ssl_client_context sc;
245  	br_x509_minimal_context xc;
246  	unsigned char iobuf[BR_SSL_BUFSIZE_BIDI];
247  	br_sslio_context ioc;
248  
249  	/*
250  	 * Parse command-line argument: host, port, and path. The path
251  	 * is optional; if absent, "/" is used.
252  	 */
253  	if (argc < 3 || argc > 4) {
254  		return EXIT_FAILURE;
255  	}
256  	host = argv[1];
257  	port = argv[2];
258  	if (argc == 4) {
259  		path = argv[3];
260  	} else {
261  		path = "/";
262  	}
263  
264  	/*
265  	 * Ignore SIGPIPE to avoid crashing in case of abrupt socket close.
266  	 */
267  	signal(SIGPIPE, SIG_IGN);
268  
269  	/*
270  	 * Open the socket to the target server.
271  	 */
272  	fd = host_connect(host, port);
273  	if (fd < 0) {
274  		return EXIT_FAILURE;
275  	}
276  
277  	/*
278  	 * Initialise the client context:
279  	 * -- Use the "full" profile (all supported algorithms).
280  	 * -- The provided X.509 validation engine is initialised, with
281  	 *    the hardcoded trust anchor.
282  	 */
283  	br_ssl_client_init_full(&sc, &xc, TAs, TAs_NUM);
284  
285  	/*
286  	 * Set the I/O buffer to the provided array. We allocated a
287  	 * buffer large enough for full-duplex behaviour with all
288  	 * allowed sizes of SSL records, hence we set the last argument
289  	 * to 1 (which means "split the buffer into separate input and
290  	 * output areas").
291  	 */
292  	br_ssl_engine_set_buffer(&sc.eng, iobuf, sizeof iobuf, 1);
293  
294  	/*
295  	 * Reset the client context, for a new handshake. We provide the
296  	 * target host name: it will be used for the SNI extension. The
297  	 * last parameter is 0: we are not trying to resume a session.
298  	 */
299  	br_ssl_client_reset(&sc, host, 0);
300  
301  	/*
302  	 * Initialise the simplified I/O wrapper context, to use our
303  	 * SSL client context, and the two callbacks for socket I/O.
304  	 */
305  	br_sslio_init(&ioc, &sc.eng, sock_read, &fd, sock_write, &fd);
306  
307  	/*
308  	 * Note that while the context has, at that point, already
309  	 * assembled the ClientHello to send, nothing happened on the
310  	 * network yet. Real I/O will occur only with the next call.
311  	 *
312  	 * We write our simple HTTP request. We could test each call
313  	 * for an error (-1), but this is not strictly necessary, since
314  	 * the error state "sticks": if the context fails for any reason
315  	 * (e.g. bad server certificate), then it will remain in failed
316  	 * state and all subsequent calls will return -1 as well.
317  	 */
318  	br_sslio_write_all(&ioc, "GET ", 4);
319  	br_sslio_write_all(&ioc, path, strlen(path));
320  	br_sslio_write_all(&ioc, " HTTP/1.0\r\nHost: ", 17);
321  	br_sslio_write_all(&ioc, host, strlen(host));
322  	br_sslio_write_all(&ioc, "\r\n\r\n", 4);
323  
324  	/*
325  	 * SSL is a buffered protocol: we make sure that all our request
326  	 * bytes are sent onto the wire.
327  	 */
328  	br_sslio_flush(&ioc);
329  
330  	/*
331  	 * Read the server's response. We use here a small 512-byte buffer,
332  	 * but most of the buffering occurs in the client context: the
333  	 * server will send full records (up to 16384 bytes worth of data
334  	 * each), and the client context buffers one full record at a time.
335  	 */
336  	for (;;) {
337  		int rlen;
338  		unsigned char tmp[512];
339  
340  		rlen = br_sslio_read(&ioc, tmp, sizeof tmp);
341  		if (rlen < 0) {
342  			break;
343  		}
344  		fwrite(tmp, 1, rlen, stdout);
345  	}
346  
347  	/*
348  	 * Close the socket.
349  	 */
350  	close(fd);
351  
352  	/*
353  	 * Check whether we closed properly or not. If the engine is
354  	 * closed, then its error status allows to distinguish between
355  	 * a normal closure and a SSL error.
356  	 *
357  	 * If the engine is NOT closed, then this means that the
358  	 * underlying network socket was closed or failed in some way.
359  	 * Note that many Web servers out there do not properly close
360  	 * their SSL connections (they don't send a close_notify alert),
361  	 * which will be reported here as "socket closed without proper
362  	 * SSL termination".
363  	 */
364  	if (br_ssl_engine_current_state(&sc.eng) == BR_SSL_CLOSED) {
365  		int err;
366  
367  		err = br_ssl_engine_last_error(&sc.eng);
368  		if (err == 0) {
369  			fprintf(stderr, "closed.\n");
370  			return EXIT_SUCCESS;
371  		} else {
372  			fprintf(stderr, "SSL error %d\n", err);
373  			return EXIT_FAILURE;
374  		}
375  	} else {
376  		fprintf(stderr,
377  			"socket closed without proper SSL termination\n");
378  		return EXIT_FAILURE;
379  	}
380  }