1/* 2 * Adapted from: 3 * 4 * client.c 5 * 6 * Copyright (C) 2006-2015 wolfSSL Inc. 7 * 8 * This file is part of wolfSSL. (formerly known as CyaSSL) 9 * 10 * wolfSSL is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * wolfSSL is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 23 */ 24#include <stdlib.h> 25#include <unistd.h> 26#include <stdarg.h> 27#include <string.h> 28#include <errno.h> 29#include <fcntl.h> 30#include <stdio.h> 31#include <time.h> 32#include <poll.h> 33#include <sys/socket.h> 34 35#include <wolfssl/wolfcrypt/types.h> 36#include <wolfssl/ssl.h> 37 38#if 0 39# define dbg(...) say(__VA_ARGS__) 40#else 41# define dbg(...) ((void)0) 42#endif 43 44static ssize_t safe_write(int fd, const void *buf, size_t count) 45{ 46 ssize_t n; 47 48 do { 49 n = write(fd, buf, count); 50 } while (n < 0 && errno == EINTR); 51 52 return n; 53} 54 55static ssize_t full_write(int fd, const void *buf, size_t len) 56{ 57 ssize_t cc; 58 ssize_t total; 59 60 total = 0; 61 62 while (len) { 63 cc = safe_write(fd, buf, len); 64 65 if (cc < 0) { 66 if (total) { 67 /* we already wrote some! */ 68 /* user can do another write to know the error code */ 69 return total; 70 } 71 return cc; /* write() returns -1 on failure. */ 72 } 73 74 total += cc; 75 buf = ((const char *)buf) + cc; 76 len -= cc; 77 } 78 79 return total; 80} 81 82static void say(const char *s, ...) 83{ 84 char buf[256]; 85 va_list p; 86 int sz; 87 88 va_start(p, s); 89 sz = vsnprintf(buf, sizeof(buf), s, p); 90 full_write(STDERR_FILENO, buf, sz >= 0 && sz < sizeof(buf) ? sz : strlen(buf)); 91 va_end(p); 92} 93 94static void die(const char *s, ...) 95{ 96 char buf[256]; 97 va_list p; 98 int sz; 99 100 va_start(p, s); 101 sz = vsnprintf(buf, sizeof(buf), s, p); 102 full_write(STDERR_FILENO, buf, sz >= 0 && sz < sizeof(buf) ? sz : strlen(buf)); 103 exit(1); 104 va_end(p); 105} 106 107static void err_sys(const char *msg) 108{ 109 die("%s\n", msg); 110} 111 112/* ==== */ 113 114#if 0 115static void showPeer(WOLFSSL* ssl) 116{ 117 WOLFSSL_CIPHER* cipher; 118 WOLFSSL_X509* peer = wolfSSL_get_peer_certificate(ssl); 119 if (peer) 120 ShowX509(peer, "peer's cert info:"); 121 else 122 say("peer has no cert!\n"); 123 say("SSL version is %s\n", wolfSSL_get_version(ssl)); 124 125 cipher = wolfSSL_get_current_cipher(ssl); 126 say("SSL cipher suite is %s\n", wolfSSL_CIPHER_get_name(cipher)); 127 128 { 129 WOLFSSL_X509_CHAIN* chain = wolfSSL_get_peer_chain(ssl); 130 int count = wolfSSL_get_chain_count(chain); 131 int i; 132 133 for (i = 0; i < count; i++) { 134 int length; 135 unsigned char buffer[3072]; 136 WOLFSSL_X509* chainX509; 137 138 wolfSSL_get_chain_cert_pem(chain, i, buffer, sizeof(buffer), &length); 139 buffer[length] = 0; 140 say("cert %d has length %d data = \n%s\n", i, length, buffer); 141 142 chainX509 = wolfSSL_get_chain_X509(chain, i); 143 if (chainX509) 144 ShowX509(chainX509, "session cert info:"); 145 else 146 say("get_chain_X509 failed\n"); 147 wolfSSL_FreeX509(chainX509); 148 } 149 } 150} 151#endif 152 153WOLFSSL *prepare(int sockfd) 154{ 155 WOLFSSL_METHOD* method; 156 WOLFSSL_CTX* ctx; 157 WOLFSSL* ssl; 158 159 wolfSSL_Init(); 160 161 method = wolfTLSv1_1_client_method(); 162 if (method == NULL) 163 err_sys("out of memory"); 164 ctx = wolfSSL_CTX_new(method); 165 if (ctx == NULL) 166 err_sys("out of memory"); 167// if (cipherList) 168// if (wolfSSL_CTX_set_cipher_list(ctx, cipherList) != SSL_SUCCESS) 169// err_sys("client can't set cipher list 1"); 170 171// if (fewerPackets) 172// wolfSSL_CTX_set_group_messages(ctx); 173 174//#ifndef NO_DH 175// wolfSSL_CTX_SetMinDhKey_Sz(ctx, (word16)minDhKeyBits); 176//#endif 177 178// if (usePsk) { 179// wolfSSL_CTX_set_psk_client_callback(ctx, my_psk_client_cb); 180// if (cipherList == NULL) { 181// const char *defaultCipherList; 182//#if defined(HAVE_AESGCM) && !defined(NO_DH) 183// defaultCipherList = "DHE-PSK-AES128-GCM-SHA256"; 184//#elif defined(HAVE_NULL_CIPHER) 185// defaultCipherList = "PSK-NULL-SHA256"; 186//#else 187// defaultCipherList = "PSK-AES128-CBC-SHA256"; 188//#endif 189// if (wolfSSL_CTX_set_cipher_list(ctx,defaultCipherList) != SSL_SUCCESS) 190// err_sys("client can't set cipher list 2"); 191// } 192// useClientCert = 0; 193// } 194 195// if (useAnon) { 196// if (cipherList == NULL) { 197// wolfSSL_CTX_allow_anon_cipher(ctx); 198// if (wolfSSL_CTX_set_cipher_list(ctx,"ADH-AES128-SHA") != SSL_SUCCESS) 199// err_sys("client can't set cipher list 4"); 200// } 201// useClientCert = 0; 202// } 203 204//#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) 205// wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack); 206//#endif 207 208// if (useOcsp) { 209// if (ocspUrl != NULL) { 210// wolfSSL_CTX_SetOCSP_OverrideURL(ctx, ocspUrl); 211// wolfSSL_CTX_EnableOCSP(ctx, WOLFSSL_OCSP_NO_NONCE 212// | WOLFSSL_OCSP_URL_OVERRIDE); 213// } 214// else 215// wolfSSL_CTX_EnableOCSP(ctx, WOLFSSL_OCSP_NO_NONCE); 216// } 217// 218//#ifdef USER_CA_CB 219// wolfSSL_CTX_SetCACb(ctx, CaCb); 220//#endif 221// 222//#ifdef VERIFY_CALLBACK 223// wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, myVerify); 224//#endif 225//#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) 226// if (useClientCert) { 227// if (wolfSSL_CTX_use_certificate_chain_file(ctx, ourCert) != SSL_SUCCESS) 228// err_sys("can't load client cert file, check file and run from" 229// " wolfSSL home dir"); 230// if (wolfSSL_CTX_use_PrivateKey_file(ctx, ourKey, SSL_FILETYPE_PEM) != SSL_SUCCESS) 231// err_sys("can't load client private key file, check file and run " 232// "from wolfSSL home dir"); 233// } 234// 235// if (!usePsk && !useAnon) { 236// if (wolfSSL_CTX_load_verify_locations(ctx, verifyCert,0) != SSL_SUCCESS) 237// err_sys("can't load ca file, Please run from wolfSSL home dir"); 238//#ifdef HAVE_ECC 239// /* load ecc verify too, echoserver uses it by default w/ ecc */ 240// if (wolfSSL_CTX_load_verify_locations(ctx, eccCert, 0) != SSL_SUCCESS) 241// err_sys("can't load ecc ca file, Please run from wolfSSL home dir"); 242//#endif 243// } 244//#endif /* !NO_FILESYSTEM && !NO_CERTS */ 245 246//#if !defined(NO_CERTS) 247// if (!usePsk && !useAnon && doPeerCheck == 0) 248// wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0); 249// if (!usePsk && !useAnon && overrideDateErrors == 1) 250// wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, myDateCb); 251//#endif 252 253 wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0); 254 255//#ifdef HAVE_SNI 256// if (sniHostName) 257// if (wolfSSL_CTX_UseSNI(ctx, 0, sniHostName, XSTRLEN(sniHostName)) != SSL_SUCCESS) 258// err_sys("UseSNI failed"); 259//#endif 260 261//#ifdef HAVE_MAX_FRAGMENT 262// if (maxFragment) 263// if (wolfSSL_CTX_UseMaxFragment(ctx, maxFragment) != SSL_SUCCESS) 264// err_sys("UseMaxFragment failed"); 265//#endif 266//#ifdef HAVE_TRUNCATED_HMAC 267// if (truncatedHMAC) 268// if (wolfSSL_CTX_UseTruncatedHMAC(ctx) != SSL_SUCCESS) 269// err_sys("UseTruncatedHMAC failed"); 270//#endif 271//#ifdef HAVE_SESSION_TICKET 272// if (wolfSSL_CTX_UseSessionTicket(ctx) != SSL_SUCCESS) 273// err_sys("UseSessionTicket failed"); 274//#endif 275 276//#if defined(WOLFSSL_MDK_ARM) 277// wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0); 278//#endif 279 280 ssl = wolfSSL_new(ctx); 281 if (ssl == NULL) 282 err_sys("out of memory"); 283 284//#ifdef HAVE_SESSION_TICKET 285// wolfSSL_set_SessionTicket_cb(ssl, sessionTicketCB, (void*)"initial session"); 286//#endif 287 288// if (doDTLS) { 289// SOCKADDR_IN_T addr; 290// build_addr(&addr, host, port, 1); 291// wolfSSL_dtls_set_peer(ssl, &addr, sizeof(addr)); 292// tcp_socket(&sockfd, 1); 293// } wlse { 294// tcp_connect(&sockfd, host, port, 0); 295// } 296 297//#ifdef HAVE_POLY1305 298// /* use old poly to connect with google server */ 299// if (!XSTRNCMP(domain, "www.google.com", 14)) { 300// if (wolfSSL_use_old_poly(ssl, 1) != 0) 301// err_sys("unable to set to old poly"); 302// } 303//#endif 304 305 wolfSSL_set_fd(ssl, sockfd); 306 307//#ifdef HAVE_CRL 308// if (disableCRL == 0) { 309// if (wolfSSL_EnableCRL(ssl, WOLFSSL_CRL_CHECKALL) != SSL_SUCCESS) 310// err_sys("can't enable crl check"); 311// if (wolfSSL_LoadCRL(ssl, crlPemDir, SSL_FILETYPE_PEM, 0) != SSL_SUCCESS) 312// err_sys("can't load crl, check crlfile and date validity"); 313// if (wolfSSL_SetCRL_Cb(ssl, CRL_CallBack) != SSL_SUCCESS) 314// err_sys("can't set crl callback"); 315// } 316//#endif 317//#ifdef HAVE_SECURE_RENEGOTIATION 318// if (scr) { 319// if (wolfSSL_UseSecureRenegotiation(ssl) != SSL_SUCCESS) 320// err_sys("can't enable secure renegotiation"); 321// } 322//#endif 323//#ifdef ATOMIC_USER 324// if (atomicUser) 325// SetupAtomicUser(ctx, ssl); 326//#endif 327//#ifdef HAVE_PK_CALLBACKS 328// if (pkCallbacks) 329// SetupPkCallbacks(ctx, ssl); 330//#endif 331// if (matchName && doPeerCheck) 332// wolfSSL_check_domain_name(ssl, domain); 333 334 if (wolfSSL_connect(ssl) != SSL_SUCCESS) { 335// /* see note at top of README */ 336// int err = wolfSSL_get_error(ssl, 0); 337// char buffer[WOLFSSL_MAX_ERROR_SZ]; 338// say("err = %d, %s\n", err, 339// wolfSSL_ERR_error_string(err, buffer)); 340 err_sys("SSL_connect failed"); 341 } 342// showPeer(ssl); 343 344//#ifdef HAVE_SECURE_RENEGOTIATION 345// if (scr && forceScr) { 346// if (wolfSSL_Rehandshake(ssl) != SSL_SUCCESS) { 347// int err = wolfSSL_get_error(ssl, 0); 348// char buffer[WOLFSSL_MAX_ERROR_SZ]; 349// say("err = %d, %s\n", err, 350// wolfSSL_ERR_error_string(err, buffer)); 351// err_sys("wolfSSL_Rehandshake failed"); 352// } 353// } 354//#endif 355 356 return ssl; 357} 358 359static struct pollfd pfd[2] = { 360 { -1, POLLIN|POLLERR|POLLHUP, 0 }, 361 { -1, POLLIN|POLLERR|POLLHUP, 0 }, 362}; 363#define STDIN pfd[0] 364#define NETWORK pfd[1] 365#define STDIN_READY() (pfd[0].revents & (POLLIN|POLLERR|POLLHUP)) 366#define NETWORK_READY() (pfd[1].revents & (POLLIN|POLLERR|POLLHUP)) 367 368static void wait_for_input(void) 369{ 370 if (STDIN.fd == NETWORK.fd) /* means both are -1 */ 371 exit(0); 372 dbg("polling\n"); 373 STDIN.revents = NETWORK.revents = 0; 374 while (poll(pfd, 2, -1) < 0 && errno == EINTR) 375 continue; 376} 377 378static void do_io_until_eof_and_exit(WOLFSSL *ssl, int fd) 379{ 380 int len; 381 char ibuf[4 * 1024]; 382 383 NETWORK.fd = fd; 384 STDIN.fd = 0; 385 386 len = 0; /* only to suppress compiler warning */ 387 for (;;) { 388 wait_for_input(); 389 390 if (STDIN_READY()) { 391 dbg("reading stdin\n"); 392 len = read(STDIN_FILENO, ibuf, sizeof(ibuf)); 393 if (len < 0) 394 die("read error on stdin\n"); 395 if (len == 0) { 396 dbg("read len = 0, stdin not polled anymore\n"); 397 STDIN.fd = -1; 398 } else { 399 int n = wolfSSL_write(ssl, ibuf, len); 400 if (n != len) 401 die("SSL_write(%d) failed (returned %d)\n", len, n); 402 } 403 } 404 405 if (NETWORK_READY()) { 406 dbg("%s%s%s\n", 407 (pfd[1].revents & POLLIN) ? "POLLIN" : "", 408 (pfd[1].revents & POLLERR) ? "|POLLERR" : "", 409 (pfd[1].revents & POLLHUP) ? "|POLLHUP" : "" 410 ); 411/* We are using blocking socket here. 412 * (Nonblocking socket would complicate writing to it). 413 * Therefore, SSL_read _can block_ here. 414 * This is not what wget expects (it wants to see short reads). 415 * Therefore, we use smallish buffer here, to approximate that. 416 */ 417 len = wolfSSL_read(ssl, ibuf, 418 sizeof(ibuf) < 1024 ? sizeof(ibuf) : 1024 419 ); 420 if (len < 0) 421 die("SSL_read error on network (%d)\n", len); 422 if (len > 0) { 423 int n; 424 n = full_write(STDOUT_FILENO, ibuf, len); 425 if (n != len) 426 die("write(%d) to stdout returned %d\n", len, n); 427 continue; 428 } 429/* Blocking reads are easier wtr EOF detection (no EAGAIN error to check for) */ 430 dbg("read len = 0, network not polled anymore\n"); 431 NETWORK.fd = -1; 432 /* saw EOF on network, and we processed 433 * and wrote out all ssl data. Signal it: 434 */ 435 close(STDOUT_FILENO); 436 } 437 } 438} 439 440int main(int argc, char **argv) 441{ 442 WOLFSSL *ssl; 443 int fd; 444 char *fd_str; 445 446 if (!argv[1]) 447 die("Syntax error\n"); 448 if (argv[1][0] != '-') 449 die("Syntax error\n"); 450 if (argv[1][1] != 'd') 451 die("Syntax error\n"); 452 fd_str = argv[1] + 2; 453 if (!fd_str[0]) 454 fd_str = argv[2]; 455 if (!fd_str || fd_str[0] < '0' || fd_str[0] > '9') 456 die("Syntax error\n"); 457 458 fd = atoi(fd_str); 459 if (fd < 3) 460 die("Syntax error\n"); 461 462 ssl = prepare(fd); 463 do_io_until_eof_and_exit(ssl, fd); 464 /* does not return */ 465 466// if (doDTLS == 0) { /* don't send alert after "break" command */ 467// ret = wolfSSL_shutdown(ssl); 468// if (wc_shutdown && ret == SSL_SHUTDOWN_NOT_DONE) 469// wolfSSL_shutdown(ssl); /* bidirectional shutdown */ 470// } 471//#ifdef ATOMIC_USER 472// if (atomicUser) 473// FreeAtomicUser(ssl); 474//#endif 475// wolfSSL_free(ssl); 476// CloseSocket(sockfd); 477// wolfSSL_CTX_free(ctx); 478 479 return 0; 480} 481