1*0957b409SSimon J. Gerraty /* 2*0957b409SSimon J. Gerraty * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> 3*0957b409SSimon J. Gerraty * 4*0957b409SSimon J. Gerraty * Permission is hereby granted, free of charge, to any person obtaining 5*0957b409SSimon J. Gerraty * a copy of this software and associated documentation files (the 6*0957b409SSimon J. Gerraty * "Software"), to deal in the Software without restriction, including 7*0957b409SSimon J. Gerraty * without limitation the rights to use, copy, modify, merge, publish, 8*0957b409SSimon J. Gerraty * distribute, sublicense, and/or sell copies of the Software, and to 9*0957b409SSimon J. Gerraty * permit persons to whom the Software is furnished to do so, subject to 10*0957b409SSimon J. Gerraty * the following conditions: 11*0957b409SSimon J. Gerraty * 12*0957b409SSimon J. Gerraty * The above copyright notice and this permission notice shall be 13*0957b409SSimon J. Gerraty * included in all copies or substantial portions of the Software. 14*0957b409SSimon J. Gerraty * 15*0957b409SSimon J. Gerraty * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16*0957b409SSimon J. Gerraty * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17*0957b409SSimon J. Gerraty * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18*0957b409SSimon J. Gerraty * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19*0957b409SSimon J. Gerraty * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20*0957b409SSimon J. Gerraty * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21*0957b409SSimon J. Gerraty * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22*0957b409SSimon J. Gerraty * SOFTWARE. 23*0957b409SSimon J. Gerraty */ 24*0957b409SSimon J. Gerraty 25*0957b409SSimon J. Gerraty #include <stdio.h> 26*0957b409SSimon J. Gerraty #include <stdlib.h> 27*0957b409SSimon J. Gerraty #include <string.h> 28*0957b409SSimon J. Gerraty #include <stdint.h> 29*0957b409SSimon J. Gerraty #include <errno.h> 30*0957b409SSimon J. Gerraty #include <signal.h> 31*0957b409SSimon J. Gerraty 32*0957b409SSimon J. Gerraty #ifdef _WIN32 33*0957b409SSimon J. Gerraty #include <winsock2.h> 34*0957b409SSimon J. Gerraty #include <ws2tcpip.h> 35*0957b409SSimon J. Gerraty #else 36*0957b409SSimon J. Gerraty #include <sys/types.h> 37*0957b409SSimon J. Gerraty #include <sys/socket.h> 38*0957b409SSimon J. Gerraty #include <netdb.h> 39*0957b409SSimon J. Gerraty #include <netinet/in.h> 40*0957b409SSimon J. Gerraty #include <arpa/inet.h> 41*0957b409SSimon J. Gerraty #include <unistd.h> 42*0957b409SSimon J. Gerraty #include <fcntl.h> 43*0957b409SSimon J. Gerraty 44*0957b409SSimon J. Gerraty #define SOCKET int 45*0957b409SSimon J. Gerraty #define INVALID_SOCKET (-1) 46*0957b409SSimon J. Gerraty #endif 47*0957b409SSimon J. Gerraty 48*0957b409SSimon J. Gerraty #include "brssl.h" 49*0957b409SSimon J. Gerraty 50*0957b409SSimon J. Gerraty static int 51*0957b409SSimon J. Gerraty host_connect(const char *host, const char *port, int verbose) 52*0957b409SSimon J. Gerraty { 53*0957b409SSimon J. Gerraty struct addrinfo hints, *si, *p; 54*0957b409SSimon J. Gerraty SOCKET fd; 55*0957b409SSimon J. Gerraty int err; 56*0957b409SSimon J. Gerraty 57*0957b409SSimon J. Gerraty memset(&hints, 0, sizeof hints); 58*0957b409SSimon J. Gerraty hints.ai_family = PF_UNSPEC; 59*0957b409SSimon J. Gerraty hints.ai_socktype = SOCK_STREAM; 60*0957b409SSimon J. Gerraty err = getaddrinfo(host, port, &hints, &si); 61*0957b409SSimon J. Gerraty if (err != 0) { 62*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: getaddrinfo(): %s\n", 63*0957b409SSimon J. Gerraty gai_strerror(err)); 64*0957b409SSimon J. Gerraty return INVALID_SOCKET; 65*0957b409SSimon J. Gerraty } 66*0957b409SSimon J. Gerraty fd = INVALID_SOCKET; 67*0957b409SSimon J. Gerraty for (p = si; p != NULL; p = p->ai_next) { 68*0957b409SSimon J. Gerraty if (verbose) { 69*0957b409SSimon J. Gerraty struct sockaddr *sa; 70*0957b409SSimon J. Gerraty void *addr; 71*0957b409SSimon J. Gerraty char tmp[INET6_ADDRSTRLEN + 50]; 72*0957b409SSimon J. Gerraty 73*0957b409SSimon J. Gerraty sa = (struct sockaddr *)p->ai_addr; 74*0957b409SSimon J. Gerraty if (sa->sa_family == AF_INET) { 75*0957b409SSimon J. Gerraty addr = &((struct sockaddr_in *) 76*0957b409SSimon J. Gerraty (void *)sa)->sin_addr; 77*0957b409SSimon J. Gerraty } else if (sa->sa_family == AF_INET6) { 78*0957b409SSimon J. Gerraty addr = &((struct sockaddr_in6 *) 79*0957b409SSimon J. Gerraty (void *)sa)->sin6_addr; 80*0957b409SSimon J. Gerraty } else { 81*0957b409SSimon J. Gerraty addr = NULL; 82*0957b409SSimon J. Gerraty } 83*0957b409SSimon J. Gerraty if (addr != NULL) { 84*0957b409SSimon J. Gerraty if (!inet_ntop(p->ai_family, addr, 85*0957b409SSimon J. Gerraty tmp, sizeof tmp)) 86*0957b409SSimon J. Gerraty { 87*0957b409SSimon J. Gerraty strcpy(tmp, "<invalid>"); 88*0957b409SSimon J. Gerraty } 89*0957b409SSimon J. Gerraty } else { 90*0957b409SSimon J. Gerraty sprintf(tmp, "<unknown family: %d>", 91*0957b409SSimon J. Gerraty (int)sa->sa_family); 92*0957b409SSimon J. Gerraty } 93*0957b409SSimon J. Gerraty fprintf(stderr, "connecting to: %s\n", tmp); 94*0957b409SSimon J. Gerraty } 95*0957b409SSimon J. Gerraty fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); 96*0957b409SSimon J. Gerraty if (fd == INVALID_SOCKET) { 97*0957b409SSimon J. Gerraty if (verbose) { 98*0957b409SSimon J. Gerraty perror("socket()"); 99*0957b409SSimon J. Gerraty } 100*0957b409SSimon J. Gerraty continue; 101*0957b409SSimon J. Gerraty } 102*0957b409SSimon J. Gerraty if (connect(fd, p->ai_addr, p->ai_addrlen) == INVALID_SOCKET) { 103*0957b409SSimon J. Gerraty if (verbose) { 104*0957b409SSimon J. Gerraty perror("connect()"); 105*0957b409SSimon J. Gerraty } 106*0957b409SSimon J. Gerraty #ifdef _WIN32 107*0957b409SSimon J. Gerraty closesocket(fd); 108*0957b409SSimon J. Gerraty #else 109*0957b409SSimon J. Gerraty close(fd); 110*0957b409SSimon J. Gerraty #endif 111*0957b409SSimon J. Gerraty continue; 112*0957b409SSimon J. Gerraty } 113*0957b409SSimon J. Gerraty break; 114*0957b409SSimon J. Gerraty } 115*0957b409SSimon J. Gerraty if (p == NULL) { 116*0957b409SSimon J. Gerraty freeaddrinfo(si); 117*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: failed to connect\n"); 118*0957b409SSimon J. Gerraty return INVALID_SOCKET; 119*0957b409SSimon J. Gerraty } 120*0957b409SSimon J. Gerraty freeaddrinfo(si); 121*0957b409SSimon J. Gerraty if (verbose) { 122*0957b409SSimon J. Gerraty fprintf(stderr, "connected.\n"); 123*0957b409SSimon J. Gerraty } 124*0957b409SSimon J. Gerraty 125*0957b409SSimon J. Gerraty /* 126*0957b409SSimon J. Gerraty * We make the socket non-blocking, since we are going to use 127*0957b409SSimon J. Gerraty * poll() or select() to organise I/O. 128*0957b409SSimon J. Gerraty */ 129*0957b409SSimon J. Gerraty #ifdef _WIN32 130*0957b409SSimon J. Gerraty { 131*0957b409SSimon J. Gerraty u_long arg; 132*0957b409SSimon J. Gerraty 133*0957b409SSimon J. Gerraty arg = 1; 134*0957b409SSimon J. Gerraty ioctlsocket(fd, FIONBIO, &arg); 135*0957b409SSimon J. Gerraty } 136*0957b409SSimon J. Gerraty #else 137*0957b409SSimon J. Gerraty fcntl(fd, F_SETFL, O_NONBLOCK); 138*0957b409SSimon J. Gerraty #endif 139*0957b409SSimon J. Gerraty return fd; 140*0957b409SSimon J. Gerraty } 141*0957b409SSimon J. Gerraty 142*0957b409SSimon J. Gerraty typedef struct { 143*0957b409SSimon J. Gerraty const br_ssl_client_certificate_class *vtable; 144*0957b409SSimon J. Gerraty int verbose; 145*0957b409SSimon J. Gerraty br_x509_certificate *chain; 146*0957b409SSimon J. Gerraty size_t chain_len; 147*0957b409SSimon J. Gerraty private_key *sk; 148*0957b409SSimon J. Gerraty int issuer_key_type; 149*0957b409SSimon J. Gerraty } ccert_context; 150*0957b409SSimon J. Gerraty 151*0957b409SSimon J. Gerraty static void 152*0957b409SSimon J. Gerraty cc_start_name_list(const br_ssl_client_certificate_class **pctx) 153*0957b409SSimon J. Gerraty { 154*0957b409SSimon J. Gerraty ccert_context *zc; 155*0957b409SSimon J. Gerraty 156*0957b409SSimon J. Gerraty zc = (ccert_context *)pctx; 157*0957b409SSimon J. Gerraty if (zc->verbose) { 158*0957b409SSimon J. Gerraty fprintf(stderr, "Server requests a client certificate.\n"); 159*0957b409SSimon J. Gerraty fprintf(stderr, "--- anchor DN list start ---\n"); 160*0957b409SSimon J. Gerraty } 161*0957b409SSimon J. Gerraty } 162*0957b409SSimon J. Gerraty 163*0957b409SSimon J. Gerraty static void 164*0957b409SSimon J. Gerraty cc_start_name(const br_ssl_client_certificate_class **pctx, size_t len) 165*0957b409SSimon J. Gerraty { 166*0957b409SSimon J. Gerraty ccert_context *zc; 167*0957b409SSimon J. Gerraty 168*0957b409SSimon J. Gerraty zc = (ccert_context *)pctx; 169*0957b409SSimon J. Gerraty if (zc->verbose) { 170*0957b409SSimon J. Gerraty fprintf(stderr, "new anchor name, length = %u\n", 171*0957b409SSimon J. Gerraty (unsigned)len); 172*0957b409SSimon J. Gerraty } 173*0957b409SSimon J. Gerraty } 174*0957b409SSimon J. Gerraty 175*0957b409SSimon J. Gerraty static void 176*0957b409SSimon J. Gerraty cc_append_name(const br_ssl_client_certificate_class **pctx, 177*0957b409SSimon J. Gerraty const unsigned char *data, size_t len) 178*0957b409SSimon J. Gerraty { 179*0957b409SSimon J. Gerraty ccert_context *zc; 180*0957b409SSimon J. Gerraty 181*0957b409SSimon J. Gerraty zc = (ccert_context *)pctx; 182*0957b409SSimon J. Gerraty if (zc->verbose) { 183*0957b409SSimon J. Gerraty size_t u; 184*0957b409SSimon J. Gerraty 185*0957b409SSimon J. Gerraty for (u = 0; u < len; u ++) { 186*0957b409SSimon J. Gerraty if (u == 0) { 187*0957b409SSimon J. Gerraty fprintf(stderr, " "); 188*0957b409SSimon J. Gerraty } else if (u > 0 && u % 16 == 0) { 189*0957b409SSimon J. Gerraty fprintf(stderr, "\n "); 190*0957b409SSimon J. Gerraty } 191*0957b409SSimon J. Gerraty fprintf(stderr, " %02x", data[u]); 192*0957b409SSimon J. Gerraty } 193*0957b409SSimon J. Gerraty if (len > 0) { 194*0957b409SSimon J. Gerraty fprintf(stderr, "\n"); 195*0957b409SSimon J. Gerraty } 196*0957b409SSimon J. Gerraty } 197*0957b409SSimon J. Gerraty } 198*0957b409SSimon J. Gerraty 199*0957b409SSimon J. Gerraty static void 200*0957b409SSimon J. Gerraty cc_end_name(const br_ssl_client_certificate_class **pctx) 201*0957b409SSimon J. Gerraty { 202*0957b409SSimon J. Gerraty (void)pctx; 203*0957b409SSimon J. Gerraty } 204*0957b409SSimon J. Gerraty 205*0957b409SSimon J. Gerraty static void 206*0957b409SSimon J. Gerraty cc_end_name_list(const br_ssl_client_certificate_class **pctx) 207*0957b409SSimon J. Gerraty { 208*0957b409SSimon J. Gerraty ccert_context *zc; 209*0957b409SSimon J. Gerraty 210*0957b409SSimon J. Gerraty zc = (ccert_context *)pctx; 211*0957b409SSimon J. Gerraty if (zc->verbose) { 212*0957b409SSimon J. Gerraty fprintf(stderr, "--- anchor DN list end ---\n"); 213*0957b409SSimon J. Gerraty } 214*0957b409SSimon J. Gerraty } 215*0957b409SSimon J. Gerraty 216*0957b409SSimon J. Gerraty static void 217*0957b409SSimon J. Gerraty print_hashes(unsigned hh, unsigned hh2) 218*0957b409SSimon J. Gerraty { 219*0957b409SSimon J. Gerraty int i; 220*0957b409SSimon J. Gerraty 221*0957b409SSimon J. Gerraty for (i = 0; i < 8; i ++) { 222*0957b409SSimon J. Gerraty const char *name; 223*0957b409SSimon J. Gerraty 224*0957b409SSimon J. Gerraty name = hash_function_name(i); 225*0957b409SSimon J. Gerraty if (((hh >> i) & 1) != 0) { 226*0957b409SSimon J. Gerraty fprintf(stderr, " %s", name); 227*0957b409SSimon J. Gerraty } else if (((hh2 >> i) & 1) != 0) { 228*0957b409SSimon J. Gerraty fprintf(stderr, " (%s)", name); 229*0957b409SSimon J. Gerraty } 230*0957b409SSimon J. Gerraty } 231*0957b409SSimon J. Gerraty } 232*0957b409SSimon J. Gerraty 233*0957b409SSimon J. Gerraty static int 234*0957b409SSimon J. Gerraty choose_hash(unsigned hh) 235*0957b409SSimon J. Gerraty { 236*0957b409SSimon J. Gerraty static const int f[] = { 237*0957b409SSimon J. Gerraty br_sha256_ID, br_sha224_ID, br_sha384_ID, br_sha512_ID, 238*0957b409SSimon J. Gerraty br_sha1_ID, br_md5sha1_ID, -1 239*0957b409SSimon J. Gerraty }; 240*0957b409SSimon J. Gerraty 241*0957b409SSimon J. Gerraty size_t u; 242*0957b409SSimon J. Gerraty 243*0957b409SSimon J. Gerraty for (u = 0; f[u] >= 0; u ++) { 244*0957b409SSimon J. Gerraty if (((hh >> f[u]) & 1) != 0) { 245*0957b409SSimon J. Gerraty return f[u]; 246*0957b409SSimon J. Gerraty } 247*0957b409SSimon J. Gerraty } 248*0957b409SSimon J. Gerraty return -1; 249*0957b409SSimon J. Gerraty } 250*0957b409SSimon J. Gerraty 251*0957b409SSimon J. Gerraty static void 252*0957b409SSimon J. Gerraty cc_choose(const br_ssl_client_certificate_class **pctx, 253*0957b409SSimon J. Gerraty const br_ssl_client_context *cc, uint32_t auth_types, 254*0957b409SSimon J. Gerraty br_ssl_client_certificate *choices) 255*0957b409SSimon J. Gerraty { 256*0957b409SSimon J. Gerraty ccert_context *zc; 257*0957b409SSimon J. Gerraty int scurve; 258*0957b409SSimon J. Gerraty 259*0957b409SSimon J. Gerraty zc = (ccert_context *)pctx; 260*0957b409SSimon J. Gerraty scurve = br_ssl_client_get_server_curve(cc); 261*0957b409SSimon J. Gerraty if (zc->verbose) { 262*0957b409SSimon J. Gerraty unsigned hashes; 263*0957b409SSimon J. Gerraty 264*0957b409SSimon J. Gerraty hashes = br_ssl_client_get_server_hashes(cc); 265*0957b409SSimon J. Gerraty if ((auth_types & 0x00FF) != 0) { 266*0957b409SSimon J. Gerraty fprintf(stderr, "supported: RSA signatures:"); 267*0957b409SSimon J. Gerraty print_hashes(auth_types, hashes); 268*0957b409SSimon J. Gerraty fprintf(stderr, "\n"); 269*0957b409SSimon J. Gerraty } 270*0957b409SSimon J. Gerraty if ((auth_types & 0xFF00) != 0) { 271*0957b409SSimon J. Gerraty fprintf(stderr, "supported: ECDSA signatures:"); 272*0957b409SSimon J. Gerraty print_hashes(auth_types >> 8, hashes >> 8); 273*0957b409SSimon J. Gerraty fprintf(stderr, "\n"); 274*0957b409SSimon J. Gerraty } 275*0957b409SSimon J. Gerraty if ((auth_types & 0x010000) != 0) { 276*0957b409SSimon J. Gerraty fprintf(stderr, "supported:" 277*0957b409SSimon J. Gerraty " fixed ECDH (cert signed with RSA)\n"); 278*0957b409SSimon J. Gerraty } 279*0957b409SSimon J. Gerraty if ((auth_types & 0x020000) != 0) { 280*0957b409SSimon J. Gerraty fprintf(stderr, "supported:" 281*0957b409SSimon J. Gerraty " fixed ECDH (cert signed with ECDSA)\n"); 282*0957b409SSimon J. Gerraty } 283*0957b409SSimon J. Gerraty if (scurve) { 284*0957b409SSimon J. Gerraty fprintf(stderr, "server key curve: %s (%d)\n", 285*0957b409SSimon J. Gerraty ec_curve_name(scurve), scurve); 286*0957b409SSimon J. Gerraty } else { 287*0957b409SSimon J. Gerraty fprintf(stderr, "server key is not EC\n"); 288*0957b409SSimon J. Gerraty } 289*0957b409SSimon J. Gerraty } 290*0957b409SSimon J. Gerraty switch (zc->sk->key_type) { 291*0957b409SSimon J. Gerraty case BR_KEYTYPE_RSA: 292*0957b409SSimon J. Gerraty if ((choices->hash_id = choose_hash(auth_types)) >= 0) { 293*0957b409SSimon J. Gerraty if (zc->verbose) { 294*0957b409SSimon J. Gerraty fprintf(stderr, "using RSA, hash = %d (%s)\n", 295*0957b409SSimon J. Gerraty choices->hash_id, 296*0957b409SSimon J. Gerraty hash_function_name(choices->hash_id)); 297*0957b409SSimon J. Gerraty } 298*0957b409SSimon J. Gerraty choices->auth_type = BR_AUTH_RSA; 299*0957b409SSimon J. Gerraty choices->chain = zc->chain; 300*0957b409SSimon J. Gerraty choices->chain_len = zc->chain_len; 301*0957b409SSimon J. Gerraty return; 302*0957b409SSimon J. Gerraty } 303*0957b409SSimon J. Gerraty break; 304*0957b409SSimon J. Gerraty case BR_KEYTYPE_EC: 305*0957b409SSimon J. Gerraty if (zc->issuer_key_type != 0 306*0957b409SSimon J. Gerraty && scurve == zc->sk->key.ec.curve) 307*0957b409SSimon J. Gerraty { 308*0957b409SSimon J. Gerraty int x; 309*0957b409SSimon J. Gerraty 310*0957b409SSimon J. Gerraty x = (zc->issuer_key_type == BR_KEYTYPE_RSA) ? 16 : 17; 311*0957b409SSimon J. Gerraty if (((auth_types >> x) & 1) != 0) { 312*0957b409SSimon J. Gerraty if (zc->verbose) { 313*0957b409SSimon J. Gerraty fprintf(stderr, "using static ECDH\n"); 314*0957b409SSimon J. Gerraty } 315*0957b409SSimon J. Gerraty choices->auth_type = BR_AUTH_ECDH; 316*0957b409SSimon J. Gerraty choices->hash_id = -1; 317*0957b409SSimon J. Gerraty choices->chain = zc->chain; 318*0957b409SSimon J. Gerraty choices->chain_len = zc->chain_len; 319*0957b409SSimon J. Gerraty return; 320*0957b409SSimon J. Gerraty } 321*0957b409SSimon J. Gerraty } 322*0957b409SSimon J. Gerraty if ((choices->hash_id = choose_hash(auth_types >> 8)) >= 0) { 323*0957b409SSimon J. Gerraty if (zc->verbose) { 324*0957b409SSimon J. Gerraty fprintf(stderr, "using ECDSA, hash = %d (%s)\n", 325*0957b409SSimon J. Gerraty choices->hash_id, 326*0957b409SSimon J. Gerraty hash_function_name(choices->hash_id)); 327*0957b409SSimon J. Gerraty } 328*0957b409SSimon J. Gerraty choices->auth_type = BR_AUTH_ECDSA; 329*0957b409SSimon J. Gerraty choices->chain = zc->chain; 330*0957b409SSimon J. Gerraty choices->chain_len = zc->chain_len; 331*0957b409SSimon J. Gerraty return; 332*0957b409SSimon J. Gerraty } 333*0957b409SSimon J. Gerraty break; 334*0957b409SSimon J. Gerraty } 335*0957b409SSimon J. Gerraty if (zc->verbose) { 336*0957b409SSimon J. Gerraty fprintf(stderr, "no matching client certificate\n"); 337*0957b409SSimon J. Gerraty } 338*0957b409SSimon J. Gerraty choices->chain = NULL; 339*0957b409SSimon J. Gerraty choices->chain_len = 0; 340*0957b409SSimon J. Gerraty } 341*0957b409SSimon J. Gerraty 342*0957b409SSimon J. Gerraty static uint32_t 343*0957b409SSimon J. Gerraty cc_do_keyx(const br_ssl_client_certificate_class **pctx, 344*0957b409SSimon J. Gerraty unsigned char *data, size_t *len) 345*0957b409SSimon J. Gerraty { 346*0957b409SSimon J. Gerraty const br_ec_impl *iec; 347*0957b409SSimon J. Gerraty ccert_context *zc; 348*0957b409SSimon J. Gerraty size_t xoff, xlen; 349*0957b409SSimon J. Gerraty uint32_t r; 350*0957b409SSimon J. Gerraty 351*0957b409SSimon J. Gerraty zc = (ccert_context *)pctx; 352*0957b409SSimon J. Gerraty iec = br_ec_get_default(); 353*0957b409SSimon J. Gerraty r = iec->mul(data, *len, zc->sk->key.ec.x, 354*0957b409SSimon J. Gerraty zc->sk->key.ec.xlen, zc->sk->key.ec.curve); 355*0957b409SSimon J. Gerraty xoff = iec->xoff(zc->sk->key.ec.curve, &xlen); 356*0957b409SSimon J. Gerraty memmove(data, data + xoff, xlen); 357*0957b409SSimon J. Gerraty *len = xlen; 358*0957b409SSimon J. Gerraty return r; 359*0957b409SSimon J. Gerraty } 360*0957b409SSimon J. Gerraty 361*0957b409SSimon J. Gerraty static size_t 362*0957b409SSimon J. Gerraty cc_do_sign(const br_ssl_client_certificate_class **pctx, 363*0957b409SSimon J. Gerraty int hash_id, size_t hv_len, unsigned char *data, size_t len) 364*0957b409SSimon J. Gerraty { 365*0957b409SSimon J. Gerraty ccert_context *zc; 366*0957b409SSimon J. Gerraty unsigned char hv[64]; 367*0957b409SSimon J. Gerraty 368*0957b409SSimon J. Gerraty zc = (ccert_context *)pctx; 369*0957b409SSimon J. Gerraty memcpy(hv, data, hv_len); 370*0957b409SSimon J. Gerraty switch (zc->sk->key_type) { 371*0957b409SSimon J. Gerraty const br_hash_class *hc; 372*0957b409SSimon J. Gerraty const unsigned char *hash_oid; 373*0957b409SSimon J. Gerraty uint32_t x; 374*0957b409SSimon J. Gerraty size_t sig_len; 375*0957b409SSimon J. Gerraty 376*0957b409SSimon J. Gerraty case BR_KEYTYPE_RSA: 377*0957b409SSimon J. Gerraty hash_oid = get_hash_oid(hash_id); 378*0957b409SSimon J. Gerraty if (hash_oid == NULL && hash_id != 0) { 379*0957b409SSimon J. Gerraty if (zc->verbose) { 380*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: cannot RSA-sign with" 381*0957b409SSimon J. Gerraty " unknown hash function: %d\n", 382*0957b409SSimon J. Gerraty hash_id); 383*0957b409SSimon J. Gerraty } 384*0957b409SSimon J. Gerraty return 0; 385*0957b409SSimon J. Gerraty } 386*0957b409SSimon J. Gerraty sig_len = (zc->sk->key.rsa.n_bitlen + 7) >> 3; 387*0957b409SSimon J. Gerraty if (len < sig_len) { 388*0957b409SSimon J. Gerraty if (zc->verbose) { 389*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: cannot RSA-sign," 390*0957b409SSimon J. Gerraty " buffer is too small" 391*0957b409SSimon J. Gerraty " (sig=%lu, buf=%lu)\n", 392*0957b409SSimon J. Gerraty (unsigned long)sig_len, 393*0957b409SSimon J. Gerraty (unsigned long)len); 394*0957b409SSimon J. Gerraty } 395*0957b409SSimon J. Gerraty return 0; 396*0957b409SSimon J. Gerraty } 397*0957b409SSimon J. Gerraty x = br_rsa_pkcs1_sign_get_default()( 398*0957b409SSimon J. Gerraty hash_oid, hv, hv_len, &zc->sk->key.rsa, data); 399*0957b409SSimon J. Gerraty if (!x) { 400*0957b409SSimon J. Gerraty if (zc->verbose) { 401*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: RSA-sign failure\n"); 402*0957b409SSimon J. Gerraty } 403*0957b409SSimon J. Gerraty return 0; 404*0957b409SSimon J. Gerraty } 405*0957b409SSimon J. Gerraty return sig_len; 406*0957b409SSimon J. Gerraty 407*0957b409SSimon J. Gerraty case BR_KEYTYPE_EC: 408*0957b409SSimon J. Gerraty hc = get_hash_impl(hash_id); 409*0957b409SSimon J. Gerraty if (hc == NULL) { 410*0957b409SSimon J. Gerraty if (zc->verbose) { 411*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: cannot ECDSA-sign with" 412*0957b409SSimon J. Gerraty " unknown hash function: %d\n", 413*0957b409SSimon J. Gerraty hash_id); 414*0957b409SSimon J. Gerraty } 415*0957b409SSimon J. Gerraty return 0; 416*0957b409SSimon J. Gerraty } 417*0957b409SSimon J. Gerraty if (len < 139) { 418*0957b409SSimon J. Gerraty if (zc->verbose) { 419*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: cannot ECDSA-sign" 420*0957b409SSimon J. Gerraty " (output buffer = %lu)\n", 421*0957b409SSimon J. Gerraty (unsigned long)len); 422*0957b409SSimon J. Gerraty } 423*0957b409SSimon J. Gerraty return 0; 424*0957b409SSimon J. Gerraty } 425*0957b409SSimon J. Gerraty sig_len = br_ecdsa_sign_asn1_get_default()( 426*0957b409SSimon J. Gerraty br_ec_get_default(), hc, hv, &zc->sk->key.ec, data); 427*0957b409SSimon J. Gerraty if (sig_len == 0) { 428*0957b409SSimon J. Gerraty if (zc->verbose) { 429*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: ECDSA-sign failure\n"); 430*0957b409SSimon J. Gerraty } 431*0957b409SSimon J. Gerraty return 0; 432*0957b409SSimon J. Gerraty } 433*0957b409SSimon J. Gerraty return sig_len; 434*0957b409SSimon J. Gerraty 435*0957b409SSimon J. Gerraty default: 436*0957b409SSimon J. Gerraty return 0; 437*0957b409SSimon J. Gerraty } 438*0957b409SSimon J. Gerraty } 439*0957b409SSimon J. Gerraty 440*0957b409SSimon J. Gerraty static const br_ssl_client_certificate_class ccert_vtable = { 441*0957b409SSimon J. Gerraty sizeof(ccert_context), 442*0957b409SSimon J. Gerraty cc_start_name_list, 443*0957b409SSimon J. Gerraty cc_start_name, 444*0957b409SSimon J. Gerraty cc_append_name, 445*0957b409SSimon J. Gerraty cc_end_name, 446*0957b409SSimon J. Gerraty cc_end_name_list, 447*0957b409SSimon J. Gerraty cc_choose, 448*0957b409SSimon J. Gerraty cc_do_keyx, 449*0957b409SSimon J. Gerraty cc_do_sign 450*0957b409SSimon J. Gerraty }; 451*0957b409SSimon J. Gerraty 452*0957b409SSimon J. Gerraty static void 453*0957b409SSimon J. Gerraty free_alpn(void *alpn) 454*0957b409SSimon J. Gerraty { 455*0957b409SSimon J. Gerraty xfree(*(char **)alpn); 456*0957b409SSimon J. Gerraty } 457*0957b409SSimon J. Gerraty 458*0957b409SSimon J. Gerraty static void 459*0957b409SSimon J. Gerraty usage_client(void) 460*0957b409SSimon J. Gerraty { 461*0957b409SSimon J. Gerraty fprintf(stderr, 462*0957b409SSimon J. Gerraty "usage: brssl client server[:port] [ options ]\n"); 463*0957b409SSimon J. Gerraty fprintf(stderr, 464*0957b409SSimon J. Gerraty "options:\n"); 465*0957b409SSimon J. Gerraty fprintf(stderr, 466*0957b409SSimon J. Gerraty " -q suppress verbose messages\n"); 467*0957b409SSimon J. Gerraty fprintf(stderr, 468*0957b409SSimon J. Gerraty " -trace activate extra debug messages (dump of all packets)\n"); 469*0957b409SSimon J. Gerraty fprintf(stderr, 470*0957b409SSimon J. Gerraty " -sni name use this specific name for SNI\n"); 471*0957b409SSimon J. Gerraty fprintf(stderr, 472*0957b409SSimon J. Gerraty " -nosni do not send any SNI\n"); 473*0957b409SSimon J. Gerraty fprintf(stderr, 474*0957b409SSimon J. Gerraty " -mono use monodirectional buffering\n"); 475*0957b409SSimon J. Gerraty fprintf(stderr, 476*0957b409SSimon J. Gerraty " -buf length set the I/O buffer length (in bytes)\n"); 477*0957b409SSimon J. Gerraty fprintf(stderr, 478*0957b409SSimon J. Gerraty " -CA file add certificates in 'file' to trust anchors\n"); 479*0957b409SSimon J. Gerraty fprintf(stderr, 480*0957b409SSimon J. Gerraty " -cert file set client certificate chain\n"); 481*0957b409SSimon J. Gerraty fprintf(stderr, 482*0957b409SSimon J. Gerraty " -key file set client private key (for certificate authentication)\n"); 483*0957b409SSimon J. Gerraty fprintf(stderr, 484*0957b409SSimon J. Gerraty " -nostaticecdh prohibit full-static ECDH (client certificate)\n"); 485*0957b409SSimon J. Gerraty fprintf(stderr, 486*0957b409SSimon J. Gerraty " -list list supported names (protocols, algorithms...)\n"); 487*0957b409SSimon J. Gerraty fprintf(stderr, 488*0957b409SSimon J. Gerraty " -vmin name set minimum supported version (default: TLS-1.0)\n"); 489*0957b409SSimon J. Gerraty fprintf(stderr, 490*0957b409SSimon J. Gerraty " -vmax name set maximum supported version (default: TLS-1.2)\n"); 491*0957b409SSimon J. Gerraty fprintf(stderr, 492*0957b409SSimon J. Gerraty " -cs names set list of supported cipher suites (comma-separated)\n"); 493*0957b409SSimon J. Gerraty fprintf(stderr, 494*0957b409SSimon J. Gerraty " -hf names add support for some hash functions (comma-separated)\n"); 495*0957b409SSimon J. Gerraty fprintf(stderr, 496*0957b409SSimon J. Gerraty " -minhello len set minimum ClientHello length (in bytes)\n"); 497*0957b409SSimon J. Gerraty fprintf(stderr, 498*0957b409SSimon J. Gerraty " -fallback send the TLS_FALLBACK_SCSV (i.e. claim a downgrade)\n"); 499*0957b409SSimon J. Gerraty fprintf(stderr, 500*0957b409SSimon J. Gerraty " -noreneg prohibit renegotiations\n"); 501*0957b409SSimon J. Gerraty fprintf(stderr, 502*0957b409SSimon J. Gerraty " -alpn name add protocol name to list of protocols (ALPN extension)\n"); 503*0957b409SSimon J. Gerraty fprintf(stderr, 504*0957b409SSimon J. Gerraty " -strictalpn fail on ALPN mismatch\n"); 505*0957b409SSimon J. Gerraty } 506*0957b409SSimon J. Gerraty 507*0957b409SSimon J. Gerraty /* see brssl.h */ 508*0957b409SSimon J. Gerraty int 509*0957b409SSimon J. Gerraty do_client(int argc, char *argv[]) 510*0957b409SSimon J. Gerraty { 511*0957b409SSimon J. Gerraty int retcode; 512*0957b409SSimon J. Gerraty int verbose; 513*0957b409SSimon J. Gerraty int trace; 514*0957b409SSimon J. Gerraty int i, bidi; 515*0957b409SSimon J. Gerraty const char *server_name; 516*0957b409SSimon J. Gerraty char *host; 517*0957b409SSimon J. Gerraty char *port; 518*0957b409SSimon J. Gerraty const char *sni; 519*0957b409SSimon J. Gerraty anchor_list anchors = VEC_INIT; 520*0957b409SSimon J. Gerraty unsigned vmin, vmax; 521*0957b409SSimon J. Gerraty VECTOR(char *) alpn_names = VEC_INIT; 522*0957b409SSimon J. Gerraty cipher_suite *suites; 523*0957b409SSimon J. Gerraty size_t num_suites; 524*0957b409SSimon J. Gerraty uint16_t *suite_ids; 525*0957b409SSimon J. Gerraty unsigned hfuns; 526*0957b409SSimon J. Gerraty size_t u; 527*0957b409SSimon J. Gerraty br_ssl_client_context cc; 528*0957b409SSimon J. Gerraty br_x509_minimal_context xc; 529*0957b409SSimon J. Gerraty x509_noanchor_context xwc; 530*0957b409SSimon J. Gerraty const br_hash_class *dnhash; 531*0957b409SSimon J. Gerraty ccert_context zc; 532*0957b409SSimon J. Gerraty br_x509_certificate *chain; 533*0957b409SSimon J. Gerraty size_t chain_len; 534*0957b409SSimon J. Gerraty private_key *sk; 535*0957b409SSimon J. Gerraty int nostaticecdh; 536*0957b409SSimon J. Gerraty unsigned char *iobuf; 537*0957b409SSimon J. Gerraty size_t iobuf_len; 538*0957b409SSimon J. Gerraty size_t minhello_len; 539*0957b409SSimon J. Gerraty int fallback; 540*0957b409SSimon J. Gerraty uint32_t flags; 541*0957b409SSimon J. Gerraty SOCKET fd; 542*0957b409SSimon J. Gerraty 543*0957b409SSimon J. Gerraty retcode = 0; 544*0957b409SSimon J. Gerraty verbose = 1; 545*0957b409SSimon J. Gerraty trace = 0; 546*0957b409SSimon J. Gerraty server_name = NULL; 547*0957b409SSimon J. Gerraty host = NULL; 548*0957b409SSimon J. Gerraty port = NULL; 549*0957b409SSimon J. Gerraty sni = NULL; 550*0957b409SSimon J. Gerraty bidi = 1; 551*0957b409SSimon J. Gerraty vmin = 0; 552*0957b409SSimon J. Gerraty vmax = 0; 553*0957b409SSimon J. Gerraty suites = NULL; 554*0957b409SSimon J. Gerraty num_suites = 0; 555*0957b409SSimon J. Gerraty hfuns = 0; 556*0957b409SSimon J. Gerraty suite_ids = NULL; 557*0957b409SSimon J. Gerraty chain = NULL; 558*0957b409SSimon J. Gerraty chain_len = 0; 559*0957b409SSimon J. Gerraty sk = NULL; 560*0957b409SSimon J. Gerraty nostaticecdh = 0; 561*0957b409SSimon J. Gerraty iobuf = NULL; 562*0957b409SSimon J. Gerraty iobuf_len = 0; 563*0957b409SSimon J. Gerraty minhello_len = (size_t)-1; 564*0957b409SSimon J. Gerraty fallback = 0; 565*0957b409SSimon J. Gerraty flags = 0; 566*0957b409SSimon J. Gerraty fd = INVALID_SOCKET; 567*0957b409SSimon J. Gerraty for (i = 0; i < argc; i ++) { 568*0957b409SSimon J. Gerraty const char *arg; 569*0957b409SSimon J. Gerraty 570*0957b409SSimon J. Gerraty arg = argv[i]; 571*0957b409SSimon J. Gerraty if (arg[0] != '-') { 572*0957b409SSimon J. Gerraty if (server_name != NULL) { 573*0957b409SSimon J. Gerraty fprintf(stderr, 574*0957b409SSimon J. Gerraty "ERROR: duplicate server name\n"); 575*0957b409SSimon J. Gerraty usage_client(); 576*0957b409SSimon J. Gerraty goto client_exit_error; 577*0957b409SSimon J. Gerraty } 578*0957b409SSimon J. Gerraty server_name = arg; 579*0957b409SSimon J. Gerraty continue; 580*0957b409SSimon J. Gerraty } 581*0957b409SSimon J. Gerraty if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) { 582*0957b409SSimon J. Gerraty verbose = 1; 583*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) { 584*0957b409SSimon J. Gerraty verbose = 0; 585*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-trace")) { 586*0957b409SSimon J. Gerraty trace = 1; 587*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-sni")) { 588*0957b409SSimon J. Gerraty if (++ i >= argc) { 589*0957b409SSimon J. Gerraty fprintf(stderr, 590*0957b409SSimon J. Gerraty "ERROR: no argument for '-sni'\n"); 591*0957b409SSimon J. Gerraty usage_client(); 592*0957b409SSimon J. Gerraty goto client_exit_error; 593*0957b409SSimon J. Gerraty } 594*0957b409SSimon J. Gerraty if (sni != NULL) { 595*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: duplicate SNI\n"); 596*0957b409SSimon J. Gerraty usage_client(); 597*0957b409SSimon J. Gerraty goto client_exit_error; 598*0957b409SSimon J. Gerraty } 599*0957b409SSimon J. Gerraty sni = argv[i]; 600*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-nosni")) { 601*0957b409SSimon J. Gerraty if (sni != NULL) { 602*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: duplicate SNI\n"); 603*0957b409SSimon J. Gerraty usage_client(); 604*0957b409SSimon J. Gerraty goto client_exit_error; 605*0957b409SSimon J. Gerraty } 606*0957b409SSimon J. Gerraty sni = ""; 607*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-mono")) { 608*0957b409SSimon J. Gerraty bidi = 0; 609*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-buf")) { 610*0957b409SSimon J. Gerraty if (++ i >= argc) { 611*0957b409SSimon J. Gerraty fprintf(stderr, 612*0957b409SSimon J. Gerraty "ERROR: no argument for '-buf'\n"); 613*0957b409SSimon J. Gerraty usage_client(); 614*0957b409SSimon J. Gerraty goto client_exit_error; 615*0957b409SSimon J. Gerraty } 616*0957b409SSimon J. Gerraty arg = argv[i]; 617*0957b409SSimon J. Gerraty if (iobuf_len != 0) { 618*0957b409SSimon J. Gerraty fprintf(stderr, 619*0957b409SSimon J. Gerraty "ERROR: duplicate I/O buffer length\n"); 620*0957b409SSimon J. Gerraty usage_client(); 621*0957b409SSimon J. Gerraty goto client_exit_error; 622*0957b409SSimon J. Gerraty } 623*0957b409SSimon J. Gerraty iobuf_len = parse_size(arg); 624*0957b409SSimon J. Gerraty if (iobuf_len == (size_t)-1) { 625*0957b409SSimon J. Gerraty usage_client(); 626*0957b409SSimon J. Gerraty goto client_exit_error; 627*0957b409SSimon J. Gerraty } 628*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-CA")) { 629*0957b409SSimon J. Gerraty if (++ i >= argc) { 630*0957b409SSimon J. Gerraty fprintf(stderr, 631*0957b409SSimon J. Gerraty "ERROR: no argument for '-CA'\n"); 632*0957b409SSimon J. Gerraty usage_client(); 633*0957b409SSimon J. Gerraty goto client_exit_error; 634*0957b409SSimon J. Gerraty } 635*0957b409SSimon J. Gerraty arg = argv[i]; 636*0957b409SSimon J. Gerraty if (read_trust_anchors(&anchors, arg) == 0) { 637*0957b409SSimon J. Gerraty usage_client(); 638*0957b409SSimon J. Gerraty goto client_exit_error; 639*0957b409SSimon J. Gerraty } 640*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-cert")) { 641*0957b409SSimon J. Gerraty if (++ i >= argc) { 642*0957b409SSimon J. Gerraty fprintf(stderr, 643*0957b409SSimon J. Gerraty "ERROR: no argument for '-cert'\n"); 644*0957b409SSimon J. Gerraty usage_client(); 645*0957b409SSimon J. Gerraty goto client_exit_error; 646*0957b409SSimon J. Gerraty } 647*0957b409SSimon J. Gerraty if (chain != NULL) { 648*0957b409SSimon J. Gerraty fprintf(stderr, 649*0957b409SSimon J. Gerraty "ERROR: duplicate certificate chain\n"); 650*0957b409SSimon J. Gerraty usage_client(); 651*0957b409SSimon J. Gerraty goto client_exit_error; 652*0957b409SSimon J. Gerraty } 653*0957b409SSimon J. Gerraty arg = argv[i]; 654*0957b409SSimon J. Gerraty chain = read_certificates(arg, &chain_len); 655*0957b409SSimon J. Gerraty if (chain == NULL || chain_len == 0) { 656*0957b409SSimon J. Gerraty goto client_exit_error; 657*0957b409SSimon J. Gerraty } 658*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-key")) { 659*0957b409SSimon J. Gerraty if (++ i >= argc) { 660*0957b409SSimon J. Gerraty fprintf(stderr, 661*0957b409SSimon J. Gerraty "ERROR: no argument for '-key'\n"); 662*0957b409SSimon J. Gerraty usage_client(); 663*0957b409SSimon J. Gerraty goto client_exit_error; 664*0957b409SSimon J. Gerraty } 665*0957b409SSimon J. Gerraty if (sk != NULL) { 666*0957b409SSimon J. Gerraty fprintf(stderr, 667*0957b409SSimon J. Gerraty "ERROR: duplicate private key\n"); 668*0957b409SSimon J. Gerraty usage_client(); 669*0957b409SSimon J. Gerraty goto client_exit_error; 670*0957b409SSimon J. Gerraty } 671*0957b409SSimon J. Gerraty arg = argv[i]; 672*0957b409SSimon J. Gerraty sk = read_private_key(arg); 673*0957b409SSimon J. Gerraty if (sk == NULL) { 674*0957b409SSimon J. Gerraty goto client_exit_error; 675*0957b409SSimon J. Gerraty } 676*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-nostaticecdh")) { 677*0957b409SSimon J. Gerraty nostaticecdh = 1; 678*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-list")) { 679*0957b409SSimon J. Gerraty list_names(); 680*0957b409SSimon J. Gerraty goto client_exit; 681*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-vmin")) { 682*0957b409SSimon J. Gerraty if (++ i >= argc) { 683*0957b409SSimon J. Gerraty fprintf(stderr, 684*0957b409SSimon J. Gerraty "ERROR: no argument for '-vmin'\n"); 685*0957b409SSimon J. Gerraty usage_client(); 686*0957b409SSimon J. Gerraty goto client_exit_error; 687*0957b409SSimon J. Gerraty } 688*0957b409SSimon J. Gerraty arg = argv[i]; 689*0957b409SSimon J. Gerraty if (vmin != 0) { 690*0957b409SSimon J. Gerraty fprintf(stderr, 691*0957b409SSimon J. Gerraty "ERROR: duplicate minimum version\n"); 692*0957b409SSimon J. Gerraty usage_client(); 693*0957b409SSimon J. Gerraty goto client_exit_error; 694*0957b409SSimon J. Gerraty } 695*0957b409SSimon J. Gerraty vmin = parse_version(arg, strlen(arg)); 696*0957b409SSimon J. Gerraty if (vmin == 0) { 697*0957b409SSimon J. Gerraty fprintf(stderr, 698*0957b409SSimon J. Gerraty "ERROR: unrecognised version '%s'\n", 699*0957b409SSimon J. Gerraty arg); 700*0957b409SSimon J. Gerraty usage_client(); 701*0957b409SSimon J. Gerraty goto client_exit_error; 702*0957b409SSimon J. Gerraty } 703*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-vmax")) { 704*0957b409SSimon J. Gerraty if (++ i >= argc) { 705*0957b409SSimon J. Gerraty fprintf(stderr, 706*0957b409SSimon J. Gerraty "ERROR: no argument for '-vmax'\n"); 707*0957b409SSimon J. Gerraty usage_client(); 708*0957b409SSimon J. Gerraty goto client_exit_error; 709*0957b409SSimon J. Gerraty } 710*0957b409SSimon J. Gerraty arg = argv[i]; 711*0957b409SSimon J. Gerraty if (vmax != 0) { 712*0957b409SSimon J. Gerraty fprintf(stderr, 713*0957b409SSimon J. Gerraty "ERROR: duplicate maximum version\n"); 714*0957b409SSimon J. Gerraty usage_client(); 715*0957b409SSimon J. Gerraty goto client_exit_error; 716*0957b409SSimon J. Gerraty } 717*0957b409SSimon J. Gerraty vmax = parse_version(arg, strlen(arg)); 718*0957b409SSimon J. Gerraty if (vmax == 0) { 719*0957b409SSimon J. Gerraty fprintf(stderr, 720*0957b409SSimon J. Gerraty "ERROR: unrecognised version '%s'\n", 721*0957b409SSimon J. Gerraty arg); 722*0957b409SSimon J. Gerraty usage_client(); 723*0957b409SSimon J. Gerraty goto client_exit_error; 724*0957b409SSimon J. Gerraty } 725*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-cs")) { 726*0957b409SSimon J. Gerraty if (++ i >= argc) { 727*0957b409SSimon J. Gerraty fprintf(stderr, 728*0957b409SSimon J. Gerraty "ERROR: no argument for '-cs'\n"); 729*0957b409SSimon J. Gerraty usage_client(); 730*0957b409SSimon J. Gerraty goto client_exit_error; 731*0957b409SSimon J. Gerraty } 732*0957b409SSimon J. Gerraty arg = argv[i]; 733*0957b409SSimon J. Gerraty if (suites != NULL) { 734*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: duplicate list" 735*0957b409SSimon J. Gerraty " of cipher suites\n"); 736*0957b409SSimon J. Gerraty usage_client(); 737*0957b409SSimon J. Gerraty goto client_exit_error; 738*0957b409SSimon J. Gerraty } 739*0957b409SSimon J. Gerraty suites = parse_suites(arg, &num_suites); 740*0957b409SSimon J. Gerraty if (suites == NULL) { 741*0957b409SSimon J. Gerraty usage_client(); 742*0957b409SSimon J. Gerraty goto client_exit_error; 743*0957b409SSimon J. Gerraty } 744*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-hf")) { 745*0957b409SSimon J. Gerraty unsigned x; 746*0957b409SSimon J. Gerraty 747*0957b409SSimon J. Gerraty if (++ i >= argc) { 748*0957b409SSimon J. Gerraty fprintf(stderr, 749*0957b409SSimon J. Gerraty "ERROR: no argument for '-hf'\n"); 750*0957b409SSimon J. Gerraty usage_client(); 751*0957b409SSimon J. Gerraty goto client_exit_error; 752*0957b409SSimon J. Gerraty } 753*0957b409SSimon J. Gerraty arg = argv[i]; 754*0957b409SSimon J. Gerraty x = parse_hash_functions(arg); 755*0957b409SSimon J. Gerraty if (x == 0) { 756*0957b409SSimon J. Gerraty usage_client(); 757*0957b409SSimon J. Gerraty goto client_exit_error; 758*0957b409SSimon J. Gerraty } 759*0957b409SSimon J. Gerraty hfuns |= x; 760*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-minhello")) { 761*0957b409SSimon J. Gerraty if (++ i >= argc) { 762*0957b409SSimon J. Gerraty fprintf(stderr, 763*0957b409SSimon J. Gerraty "ERROR: no argument for '-minhello'\n"); 764*0957b409SSimon J. Gerraty usage_client(); 765*0957b409SSimon J. Gerraty goto client_exit_error; 766*0957b409SSimon J. Gerraty } 767*0957b409SSimon J. Gerraty arg = argv[i]; 768*0957b409SSimon J. Gerraty if (minhello_len != (size_t)-1) { 769*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: duplicate minimum" 770*0957b409SSimon J. Gerraty " ClientHello length\n"); 771*0957b409SSimon J. Gerraty usage_client(); 772*0957b409SSimon J. Gerraty goto client_exit_error; 773*0957b409SSimon J. Gerraty } 774*0957b409SSimon J. Gerraty minhello_len = parse_size(arg); 775*0957b409SSimon J. Gerraty /* 776*0957b409SSimon J. Gerraty * Minimum ClientHello length must fit on 16 bits. 777*0957b409SSimon J. Gerraty */ 778*0957b409SSimon J. Gerraty if (minhello_len == (size_t)-1 779*0957b409SSimon J. Gerraty || (((minhello_len >> 12) >> 4) != 0)) 780*0957b409SSimon J. Gerraty { 781*0957b409SSimon J. Gerraty usage_client(); 782*0957b409SSimon J. Gerraty goto client_exit_error; 783*0957b409SSimon J. Gerraty } 784*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-fallback")) { 785*0957b409SSimon J. Gerraty fallback = 1; 786*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-noreneg")) { 787*0957b409SSimon J. Gerraty flags |= BR_OPT_NO_RENEGOTIATION; 788*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-alpn")) { 789*0957b409SSimon J. Gerraty if (++ i >= argc) { 790*0957b409SSimon J. Gerraty fprintf(stderr, 791*0957b409SSimon J. Gerraty "ERROR: no argument for '-alpn'\n"); 792*0957b409SSimon J. Gerraty usage_client(); 793*0957b409SSimon J. Gerraty goto client_exit_error; 794*0957b409SSimon J. Gerraty } 795*0957b409SSimon J. Gerraty VEC_ADD(alpn_names, xstrdup(argv[i])); 796*0957b409SSimon J. Gerraty } else if (eqstr(arg, "-strictalpn")) { 797*0957b409SSimon J. Gerraty flags |= BR_OPT_FAIL_ON_ALPN_MISMATCH; 798*0957b409SSimon J. Gerraty } else { 799*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: unknown option: '%s'\n", arg); 800*0957b409SSimon J. Gerraty usage_client(); 801*0957b409SSimon J. Gerraty goto client_exit_error; 802*0957b409SSimon J. Gerraty } 803*0957b409SSimon J. Gerraty } 804*0957b409SSimon J. Gerraty if (server_name == NULL) { 805*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: no server name/address provided\n"); 806*0957b409SSimon J. Gerraty usage_client(); 807*0957b409SSimon J. Gerraty goto client_exit_error; 808*0957b409SSimon J. Gerraty } 809*0957b409SSimon J. Gerraty for (u = strlen(server_name); u > 0; u --) { 810*0957b409SSimon J. Gerraty int c = server_name[u - 1]; 811*0957b409SSimon J. Gerraty if (c == ':') { 812*0957b409SSimon J. Gerraty break; 813*0957b409SSimon J. Gerraty } 814*0957b409SSimon J. Gerraty if (c < '0' || c > '9') { 815*0957b409SSimon J. Gerraty u = 0; 816*0957b409SSimon J. Gerraty break; 817*0957b409SSimon J. Gerraty } 818*0957b409SSimon J. Gerraty } 819*0957b409SSimon J. Gerraty if (u == 0) { 820*0957b409SSimon J. Gerraty host = xstrdup(server_name); 821*0957b409SSimon J. Gerraty port = xstrdup("443"); 822*0957b409SSimon J. Gerraty } else { 823*0957b409SSimon J. Gerraty port = xstrdup(server_name + u); 824*0957b409SSimon J. Gerraty host = xmalloc(u); 825*0957b409SSimon J. Gerraty memcpy(host, server_name, u - 1); 826*0957b409SSimon J. Gerraty host[u - 1] = 0; 827*0957b409SSimon J. Gerraty } 828*0957b409SSimon J. Gerraty if (sni == NULL) { 829*0957b409SSimon J. Gerraty sni = host; 830*0957b409SSimon J. Gerraty } 831*0957b409SSimon J. Gerraty 832*0957b409SSimon J. Gerraty if (chain == NULL && sk != NULL) { 833*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: private key specified, but" 834*0957b409SSimon J. Gerraty " no certificate chain\n"); 835*0957b409SSimon J. Gerraty usage_client(); 836*0957b409SSimon J. Gerraty goto client_exit_error; 837*0957b409SSimon J. Gerraty } 838*0957b409SSimon J. Gerraty if (chain != NULL && sk == NULL) { 839*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: certificate chain specified, but" 840*0957b409SSimon J. Gerraty " no private key\n"); 841*0957b409SSimon J. Gerraty usage_client(); 842*0957b409SSimon J. Gerraty goto client_exit_error; 843*0957b409SSimon J. Gerraty } 844*0957b409SSimon J. Gerraty 845*0957b409SSimon J. Gerraty if (vmin == 0) { 846*0957b409SSimon J. Gerraty vmin = BR_TLS10; 847*0957b409SSimon J. Gerraty } 848*0957b409SSimon J. Gerraty if (vmax == 0) { 849*0957b409SSimon J. Gerraty vmax = BR_TLS12; 850*0957b409SSimon J. Gerraty } 851*0957b409SSimon J. Gerraty if (vmax < vmin) { 852*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: impossible minimum/maximum protocol" 853*0957b409SSimon J. Gerraty " version combination\n"); 854*0957b409SSimon J. Gerraty usage_client(); 855*0957b409SSimon J. Gerraty goto client_exit_error; 856*0957b409SSimon J. Gerraty } 857*0957b409SSimon J. Gerraty if (suites == NULL) { 858*0957b409SSimon J. Gerraty num_suites = 0; 859*0957b409SSimon J. Gerraty 860*0957b409SSimon J. Gerraty for (u = 0; cipher_suites[u].name; u ++) { 861*0957b409SSimon J. Gerraty if ((cipher_suites[u].req & REQ_TLS12) == 0 862*0957b409SSimon J. Gerraty || vmax >= BR_TLS12) 863*0957b409SSimon J. Gerraty { 864*0957b409SSimon J. Gerraty num_suites ++; 865*0957b409SSimon J. Gerraty } 866*0957b409SSimon J. Gerraty } 867*0957b409SSimon J. Gerraty suites = xmalloc(num_suites * sizeof *suites); 868*0957b409SSimon J. Gerraty num_suites = 0; 869*0957b409SSimon J. Gerraty for (u = 0; cipher_suites[u].name; u ++) { 870*0957b409SSimon J. Gerraty if ((cipher_suites[u].req & REQ_TLS12) == 0 871*0957b409SSimon J. Gerraty || vmax >= BR_TLS12) 872*0957b409SSimon J. Gerraty { 873*0957b409SSimon J. Gerraty suites[num_suites ++] = cipher_suites[u]; 874*0957b409SSimon J. Gerraty } 875*0957b409SSimon J. Gerraty } 876*0957b409SSimon J. Gerraty } 877*0957b409SSimon J. Gerraty if (hfuns == 0) { 878*0957b409SSimon J. Gerraty hfuns = (unsigned)-1; 879*0957b409SSimon J. Gerraty } 880*0957b409SSimon J. Gerraty if (iobuf_len == 0) { 881*0957b409SSimon J. Gerraty if (bidi) { 882*0957b409SSimon J. Gerraty iobuf_len = BR_SSL_BUFSIZE_BIDI; 883*0957b409SSimon J. Gerraty } else { 884*0957b409SSimon J. Gerraty iobuf_len = BR_SSL_BUFSIZE_MONO; 885*0957b409SSimon J. Gerraty } 886*0957b409SSimon J. Gerraty } 887*0957b409SSimon J. Gerraty iobuf = xmalloc(iobuf_len); 888*0957b409SSimon J. Gerraty 889*0957b409SSimon J. Gerraty /* 890*0957b409SSimon J. Gerraty * Compute implementation requirements and inject implementations. 891*0957b409SSimon J. Gerraty */ 892*0957b409SSimon J. Gerraty suite_ids = xmalloc((num_suites + 1) * sizeof *suite_ids); 893*0957b409SSimon J. Gerraty br_ssl_client_zero(&cc); 894*0957b409SSimon J. Gerraty br_ssl_engine_set_versions(&cc.eng, vmin, vmax); 895*0957b409SSimon J. Gerraty dnhash = NULL; 896*0957b409SSimon J. Gerraty for (u = 0; hash_functions[u].name; u ++) { 897*0957b409SSimon J. Gerraty const br_hash_class *hc; 898*0957b409SSimon J. Gerraty int id; 899*0957b409SSimon J. Gerraty 900*0957b409SSimon J. Gerraty hc = hash_functions[u].hclass; 901*0957b409SSimon J. Gerraty id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK; 902*0957b409SSimon J. Gerraty if ((hfuns & ((unsigned)1 << id)) != 0) { 903*0957b409SSimon J. Gerraty dnhash = hc; 904*0957b409SSimon J. Gerraty } 905*0957b409SSimon J. Gerraty } 906*0957b409SSimon J. Gerraty if (dnhash == NULL) { 907*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: no supported hash function\n"); 908*0957b409SSimon J. Gerraty goto client_exit_error; 909*0957b409SSimon J. Gerraty } 910*0957b409SSimon J. Gerraty br_x509_minimal_init(&xc, dnhash, 911*0957b409SSimon J. Gerraty &VEC_ELT(anchors, 0), VEC_LEN(anchors)); 912*0957b409SSimon J. Gerraty if (vmin <= BR_TLS11) { 913*0957b409SSimon J. Gerraty if (!(hfuns & (1 << br_md5_ID))) { 914*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need MD5\n"); 915*0957b409SSimon J. Gerraty goto client_exit_error; 916*0957b409SSimon J. Gerraty } 917*0957b409SSimon J. Gerraty if (!(hfuns & (1 << br_sha1_ID))) { 918*0957b409SSimon J. Gerraty fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need SHA-1\n"); 919*0957b409SSimon J. Gerraty goto client_exit_error; 920*0957b409SSimon J. Gerraty } 921*0957b409SSimon J. Gerraty } 922*0957b409SSimon J. Gerraty for (u = 0; u < num_suites; u ++) { 923*0957b409SSimon J. Gerraty unsigned req; 924*0957b409SSimon J. Gerraty 925*0957b409SSimon J. Gerraty req = suites[u].req; 926*0957b409SSimon J. Gerraty suite_ids[u] = suites[u].suite; 927*0957b409SSimon J. Gerraty if ((req & REQ_TLS12) != 0 && vmax < BR_TLS12) { 928*0957b409SSimon J. Gerraty fprintf(stderr, 929*0957b409SSimon J. Gerraty "ERROR: cipher suite %s requires TLS 1.2\n", 930*0957b409SSimon J. Gerraty suites[u].name); 931*0957b409SSimon J. Gerraty goto client_exit_error; 932*0957b409SSimon J. Gerraty } 933*0957b409SSimon J. Gerraty if ((req & REQ_SHA1) != 0 && !(hfuns & (1 << br_sha1_ID))) { 934*0957b409SSimon J. Gerraty fprintf(stderr, 935*0957b409SSimon J. Gerraty "ERROR: cipher suite %s requires SHA-1\n", 936*0957b409SSimon J. Gerraty suites[u].name); 937*0957b409SSimon J. Gerraty goto client_exit_error; 938*0957b409SSimon J. Gerraty } 939*0957b409SSimon J. Gerraty if ((req & REQ_SHA256) != 0 && !(hfuns & (1 << br_sha256_ID))) { 940*0957b409SSimon J. Gerraty fprintf(stderr, 941*0957b409SSimon J. Gerraty "ERROR: cipher suite %s requires SHA-256\n", 942*0957b409SSimon J. Gerraty suites[u].name); 943*0957b409SSimon J. Gerraty goto client_exit_error; 944*0957b409SSimon J. Gerraty } 945*0957b409SSimon J. Gerraty if ((req & REQ_SHA384) != 0 && !(hfuns & (1 << br_sha384_ID))) { 946*0957b409SSimon J. Gerraty fprintf(stderr, 947*0957b409SSimon J. Gerraty "ERROR: cipher suite %s requires SHA-384\n", 948*0957b409SSimon J. Gerraty suites[u].name); 949*0957b409SSimon J. Gerraty goto client_exit_error; 950*0957b409SSimon J. Gerraty } 951*0957b409SSimon J. Gerraty /* TODO: algorithm implementation selection */ 952*0957b409SSimon J. Gerraty if ((req & REQ_AESCBC) != 0) { 953*0957b409SSimon J. Gerraty br_ssl_engine_set_default_aes_cbc(&cc.eng); 954*0957b409SSimon J. Gerraty } 955*0957b409SSimon J. Gerraty if ((req & REQ_AESCCM) != 0) { 956*0957b409SSimon J. Gerraty br_ssl_engine_set_default_aes_ccm(&cc.eng); 957*0957b409SSimon J. Gerraty } 958*0957b409SSimon J. Gerraty if ((req & REQ_AESGCM) != 0) { 959*0957b409SSimon J. Gerraty br_ssl_engine_set_default_aes_gcm(&cc.eng); 960*0957b409SSimon J. Gerraty } 961*0957b409SSimon J. Gerraty if ((req & REQ_CHAPOL) != 0) { 962*0957b409SSimon J. Gerraty br_ssl_engine_set_default_chapol(&cc.eng); 963*0957b409SSimon J. Gerraty } 964*0957b409SSimon J. Gerraty if ((req & REQ_3DESCBC) != 0) { 965*0957b409SSimon J. Gerraty br_ssl_engine_set_default_des_cbc(&cc.eng); 966*0957b409SSimon J. Gerraty } 967*0957b409SSimon J. Gerraty if ((req & REQ_RSAKEYX) != 0) { 968*0957b409SSimon J. Gerraty br_ssl_client_set_default_rsapub(&cc); 969*0957b409SSimon J. Gerraty } 970*0957b409SSimon J. Gerraty if ((req & REQ_ECDHE_RSA) != 0) { 971*0957b409SSimon J. Gerraty br_ssl_engine_set_default_ec(&cc.eng); 972*0957b409SSimon J. Gerraty br_ssl_engine_set_default_rsavrfy(&cc.eng); 973*0957b409SSimon J. Gerraty } 974*0957b409SSimon J. Gerraty if ((req & REQ_ECDHE_ECDSA) != 0) { 975*0957b409SSimon J. Gerraty br_ssl_engine_set_default_ecdsa(&cc.eng); 976*0957b409SSimon J. Gerraty } 977*0957b409SSimon J. Gerraty if ((req & REQ_ECDH) != 0) { 978*0957b409SSimon J. Gerraty br_ssl_engine_set_default_ec(&cc.eng); 979*0957b409SSimon J. Gerraty } 980*0957b409SSimon J. Gerraty } 981*0957b409SSimon J. Gerraty if (fallback) { 982*0957b409SSimon J. Gerraty suite_ids[num_suites ++] = 0x5600; 983*0957b409SSimon J. Gerraty } 984*0957b409SSimon J. Gerraty br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites); 985*0957b409SSimon J. Gerraty 986*0957b409SSimon J. Gerraty for (u = 0; hash_functions[u].name; u ++) { 987*0957b409SSimon J. Gerraty const br_hash_class *hc; 988*0957b409SSimon J. Gerraty int id; 989*0957b409SSimon J. Gerraty 990*0957b409SSimon J. Gerraty hc = hash_functions[u].hclass; 991*0957b409SSimon J. Gerraty id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK; 992*0957b409SSimon J. Gerraty if ((hfuns & ((unsigned)1 << id)) != 0) { 993*0957b409SSimon J. Gerraty br_ssl_engine_set_hash(&cc.eng, id, hc); 994*0957b409SSimon J. Gerraty br_x509_minimal_set_hash(&xc, id, hc); 995*0957b409SSimon J. Gerraty } 996*0957b409SSimon J. Gerraty } 997*0957b409SSimon J. Gerraty if (vmin <= BR_TLS11) { 998*0957b409SSimon J. Gerraty br_ssl_engine_set_prf10(&cc.eng, &br_tls10_prf); 999*0957b409SSimon J. Gerraty } 1000*0957b409SSimon J. Gerraty if (vmax >= BR_TLS12) { 1001*0957b409SSimon J. Gerraty if ((hfuns & ((unsigned)1 << br_sha256_ID)) != 0) { 1002*0957b409SSimon J. Gerraty br_ssl_engine_set_prf_sha256(&cc.eng, 1003*0957b409SSimon J. Gerraty &br_tls12_sha256_prf); 1004*0957b409SSimon J. Gerraty } 1005*0957b409SSimon J. Gerraty if ((hfuns & ((unsigned)1 << br_sha384_ID)) != 0) { 1006*0957b409SSimon J. Gerraty br_ssl_engine_set_prf_sha384(&cc.eng, 1007*0957b409SSimon J. Gerraty &br_tls12_sha384_prf); 1008*0957b409SSimon J. Gerraty } 1009*0957b409SSimon J. Gerraty } 1010*0957b409SSimon J. Gerraty br_x509_minimal_set_rsa(&xc, br_rsa_pkcs1_vrfy_get_default()); 1011*0957b409SSimon J. Gerraty br_x509_minimal_set_ecdsa(&xc, 1012*0957b409SSimon J. Gerraty br_ec_get_default(), br_ecdsa_vrfy_asn1_get_default()); 1013*0957b409SSimon J. Gerraty 1014*0957b409SSimon J. Gerraty /* 1015*0957b409SSimon J. Gerraty * If there is no provided trust anchor, then certificate validation 1016*0957b409SSimon J. Gerraty * will always fail. In that situation, we use our custom wrapper 1017*0957b409SSimon J. Gerraty * that tolerates unknown anchors. 1018*0957b409SSimon J. Gerraty */ 1019*0957b409SSimon J. Gerraty if (VEC_LEN(anchors) == 0) { 1020*0957b409SSimon J. Gerraty if (verbose) { 1021*0957b409SSimon J. Gerraty fprintf(stderr, 1022*0957b409SSimon J. Gerraty "WARNING: no configured trust anchor\n"); 1023*0957b409SSimon J. Gerraty } 1024*0957b409SSimon J. Gerraty x509_noanchor_init(&xwc, &xc.vtable); 1025*0957b409SSimon J. Gerraty br_ssl_engine_set_x509(&cc.eng, &xwc.vtable); 1026*0957b409SSimon J. Gerraty } else { 1027*0957b409SSimon J. Gerraty br_ssl_engine_set_x509(&cc.eng, &xc.vtable); 1028*0957b409SSimon J. Gerraty } 1029*0957b409SSimon J. Gerraty 1030*0957b409SSimon J. Gerraty if (minhello_len != (size_t)-1) { 1031*0957b409SSimon J. Gerraty br_ssl_client_set_min_clienthello_len(&cc, minhello_len); 1032*0957b409SSimon J. Gerraty } 1033*0957b409SSimon J. Gerraty br_ssl_engine_set_all_flags(&cc.eng, flags); 1034*0957b409SSimon J. Gerraty if (VEC_LEN(alpn_names) != 0) { 1035*0957b409SSimon J. Gerraty br_ssl_engine_set_protocol_names(&cc.eng, 1036*0957b409SSimon J. Gerraty (const char **)&VEC_ELT(alpn_names, 0), 1037*0957b409SSimon J. Gerraty VEC_LEN(alpn_names)); 1038*0957b409SSimon J. Gerraty } 1039*0957b409SSimon J. Gerraty 1040*0957b409SSimon J. Gerraty if (chain != NULL) { 1041*0957b409SSimon J. Gerraty zc.vtable = &ccert_vtable; 1042*0957b409SSimon J. Gerraty zc.verbose = verbose; 1043*0957b409SSimon J. Gerraty zc.chain = chain; 1044*0957b409SSimon J. Gerraty zc.chain_len = chain_len; 1045*0957b409SSimon J. Gerraty zc.sk = sk; 1046*0957b409SSimon J. Gerraty if (nostaticecdh || sk->key_type != BR_KEYTYPE_EC) { 1047*0957b409SSimon J. Gerraty zc.issuer_key_type = 0; 1048*0957b409SSimon J. Gerraty } else { 1049*0957b409SSimon J. Gerraty zc.issuer_key_type = get_cert_signer_algo(&chain[0]); 1050*0957b409SSimon J. Gerraty if (zc.issuer_key_type == 0) { 1051*0957b409SSimon J. Gerraty goto client_exit_error; 1052*0957b409SSimon J. Gerraty } 1053*0957b409SSimon J. Gerraty } 1054*0957b409SSimon J. Gerraty br_ssl_client_set_client_certificate(&cc, &zc.vtable); 1055*0957b409SSimon J. Gerraty } 1056*0957b409SSimon J. Gerraty 1057*0957b409SSimon J. Gerraty br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi); 1058*0957b409SSimon J. Gerraty br_ssl_client_reset(&cc, sni, 0); 1059*0957b409SSimon J. Gerraty 1060*0957b409SSimon J. Gerraty /* 1061*0957b409SSimon J. Gerraty * On Unix systems, we need to avoid SIGPIPE. 1062*0957b409SSimon J. Gerraty */ 1063*0957b409SSimon J. Gerraty #ifndef _WIN32 1064*0957b409SSimon J. Gerraty signal(SIGPIPE, SIG_IGN); 1065*0957b409SSimon J. Gerraty #endif 1066*0957b409SSimon J. Gerraty 1067*0957b409SSimon J. Gerraty /* 1068*0957b409SSimon J. Gerraty * Connect to the peer. 1069*0957b409SSimon J. Gerraty */ 1070*0957b409SSimon J. Gerraty fd = host_connect(host, port, verbose); 1071*0957b409SSimon J. Gerraty if (fd == INVALID_SOCKET) { 1072*0957b409SSimon J. Gerraty goto client_exit_error; 1073*0957b409SSimon J. Gerraty } 1074*0957b409SSimon J. Gerraty 1075*0957b409SSimon J. Gerraty /* 1076*0957b409SSimon J. Gerraty * Run the engine until completion. 1077*0957b409SSimon J. Gerraty */ 1078*0957b409SSimon J. Gerraty if (run_ssl_engine(&cc.eng, fd, 1079*0957b409SSimon J. Gerraty (verbose ? RUN_ENGINE_VERBOSE : 0) 1080*0957b409SSimon J. Gerraty | (trace ? RUN_ENGINE_TRACE : 0)) != 0) 1081*0957b409SSimon J. Gerraty { 1082*0957b409SSimon J. Gerraty goto client_exit_error; 1083*0957b409SSimon J. Gerraty } else { 1084*0957b409SSimon J. Gerraty goto client_exit; 1085*0957b409SSimon J. Gerraty } 1086*0957b409SSimon J. Gerraty 1087*0957b409SSimon J. Gerraty /* 1088*0957b409SSimon J. Gerraty * Release allocated structures. 1089*0957b409SSimon J. Gerraty */ 1090*0957b409SSimon J. Gerraty client_exit: 1091*0957b409SSimon J. Gerraty xfree(host); 1092*0957b409SSimon J. Gerraty xfree(port); 1093*0957b409SSimon J. Gerraty xfree(suites); 1094*0957b409SSimon J. Gerraty xfree(suite_ids); 1095*0957b409SSimon J. Gerraty VEC_CLEAREXT(anchors, &free_ta_contents); 1096*0957b409SSimon J. Gerraty VEC_CLEAREXT(alpn_names, &free_alpn); 1097*0957b409SSimon J. Gerraty free_certificates(chain, chain_len); 1098*0957b409SSimon J. Gerraty free_private_key(sk); 1099*0957b409SSimon J. Gerraty xfree(iobuf); 1100*0957b409SSimon J. Gerraty if (fd != INVALID_SOCKET) { 1101*0957b409SSimon J. Gerraty #ifdef _WIN32 1102*0957b409SSimon J. Gerraty closesocket(fd); 1103*0957b409SSimon J. Gerraty #else 1104*0957b409SSimon J. Gerraty close(fd); 1105*0957b409SSimon J. Gerraty #endif 1106*0957b409SSimon J. Gerraty } 1107*0957b409SSimon J. Gerraty return retcode; 1108*0957b409SSimon J. Gerraty 1109*0957b409SSimon J. Gerraty client_exit_error: 1110*0957b409SSimon J. Gerraty retcode = -1; 1111*0957b409SSimon J. Gerraty goto client_exit; 1112*0957b409SSimon J. Gerraty } 1113