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 } 381