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