PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/examples/client/client.c

https://github.com/andersmalm/cyassl
C | 591 lines | 463 code | 100 blank | 28 comment | 104 complexity | 673c80b5cb1998355be9a47f5a827942 MD5 | raw file
Possible License(s): GPL-2.0
  1. /* client.c
  2. *
  3. * Copyright (C) 2006-2012 Sawtooth Consulting Ltd.
  4. *
  5. * This file is part of CyaSSL.
  6. *
  7. * CyaSSL is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * CyaSSL is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  20. */
  21. #ifdef HAVE_CONFIG_H
  22. #include <config.h>
  23. #endif
  24. #include <cyassl/ssl.h>
  25. #include <cyassl/test.h>
  26. #include "examples/client/client.h"
  27. #ifdef CYASSL_CALLBACKS
  28. int handShakeCB(HandShakeInfo*);
  29. int timeoutCB(TimeoutInfo*);
  30. Timeval timeout;
  31. #endif
  32. static void NonBlockingSSL_Connect(CYASSL* ssl)
  33. {
  34. #ifndef CYASSL_CALLBACKS
  35. int ret = CyaSSL_connect(ssl);
  36. #else
  37. int ret = CyaSSL_connect_ex(ssl, handShakeCB, timeoutCB, timeout);
  38. #endif
  39. int error = CyaSSL_get_error(ssl, 0);
  40. SOCKET_T sockfd = (SOCKET_T)CyaSSL_get_fd(ssl);
  41. int select_ret;
  42. while (ret != SSL_SUCCESS && (error == SSL_ERROR_WANT_READ ||
  43. error == SSL_ERROR_WANT_WRITE)) {
  44. if (error == SSL_ERROR_WANT_READ)
  45. printf("... client would read block\n");
  46. else
  47. printf("... client would write block\n");
  48. if (CyaSSL_dtls(ssl))
  49. select_ret = tcp_select(sockfd,
  50. CyaSSL_dtls_get_current_timeout(ssl));
  51. else
  52. select_ret = tcp_select(sockfd, 1);
  53. if ((select_ret == TEST_RECV_READY) ||
  54. (select_ret == TEST_ERROR_READY)) {
  55. #ifndef CYASSL_CALLBACKS
  56. ret = CyaSSL_connect(ssl);
  57. #else
  58. ret = CyaSSL_connect_ex(ssl,handShakeCB,timeoutCB,timeout);
  59. #endif
  60. error = CyaSSL_get_error(ssl, 0);
  61. }
  62. else if (select_ret == TEST_TIMEOUT &&
  63. (!CyaSSL_dtls(ssl) ||
  64. (CyaSSL_dtls_got_timeout(ssl) >= 0))) {
  65. error = SSL_ERROR_WANT_READ;
  66. }
  67. else {
  68. error = SSL_FATAL_ERROR;
  69. }
  70. }
  71. if (ret != SSL_SUCCESS)
  72. err_sys("SSL_connect failed");
  73. }
  74. static void Usage(void)
  75. {
  76. printf("client " LIBCYASSL_VERSION_STRING
  77. " NOTE: All files relative to CyaSSL home dir\n");
  78. printf("-? Help, print this usage\n");
  79. printf("-h <host> Host to connect to, default %s\n", yasslIP);
  80. printf("-p <num> Port to connect on, default %d\n", yasslPort);
  81. printf("-v <num> SSL version [0-3], SSLv3(0) - TLS1.2(3)), default %d\n",
  82. CLIENT_DEFAULT_VERSION);
  83. printf("-l <str> Cipher list\n");
  84. printf("-c <file> Certificate file, default %s\n", cliCert);
  85. printf("-k <file> Key file, default %s\n", cliKey);
  86. printf("-A <file> Certificate Authority file, default %s\n", caCert);
  87. printf("-b <num> Benchmark <num> connections and print stats\n");
  88. printf("-s Use pre Shared keys\n");
  89. printf("-d Disable peer checks\n");
  90. printf("-g Send server HTTP GET\n");
  91. printf("-u Use UDP DTLS\n");
  92. printf("-m Match domain name in cert\n");
  93. printf("-N Use Non-blocking sockets\n");
  94. printf("-r Resume session\n");
  95. }
  96. void client_test(void* args)
  97. {
  98. SOCKET_T sockfd = 0;
  99. CYASSL_METHOD* method = 0;
  100. CYASSL_CTX* ctx = 0;
  101. CYASSL* ssl = 0;
  102. CYASSL* sslResume = 0;
  103. CYASSL_SESSION* session = 0;
  104. char resumeMsg[] = "resuming cyassl!";
  105. int resumeSz = sizeof(resumeMsg);
  106. char msg[64] = "hello cyassl!";
  107. char reply[1024];
  108. int input;
  109. int msgSz = (int)strlen(msg);
  110. int port = yasslPort;
  111. char* host = (char*)yasslIP;
  112. char* domain = (char*)"www.yassl.com";
  113. int ch;
  114. int version = CLIENT_DEFAULT_VERSION;
  115. int usePsk = 0;
  116. int sendGET = 0;
  117. int benchmark = 0;
  118. int doDTLS = 0;
  119. int matchName = 0;
  120. int doPeerCheck = 1;
  121. int nonBlocking = 0;
  122. int resumeSession = 0;
  123. char* cipherList = NULL;
  124. char* verifyCert = (char*)caCert;
  125. char* ourCert = (char*)cliCert;
  126. char* ourKey = (char*)cliKey;
  127. int argc = ((func_args*)args)->argc;
  128. char** argv = ((func_args*)args)->argv;
  129. ((func_args*)args)->return_code = -1; /* error state */
  130. while ((ch = mygetopt(argc, argv, "?gdusmNrh:p:v:l:A:c:k:b:")) != -1) {
  131. switch (ch) {
  132. case '?' :
  133. Usage();
  134. exit(EXIT_SUCCESS);
  135. case 'g' :
  136. sendGET = 1;
  137. break;
  138. case 'd' :
  139. doPeerCheck = 0;
  140. break;
  141. case 'u' :
  142. doDTLS = 1;
  143. version = -1; /* DTLS flag */
  144. break;
  145. case 's' :
  146. usePsk = 1;
  147. break;
  148. case 'm' :
  149. matchName = 1;
  150. break;
  151. case 'h' :
  152. host = myoptarg;
  153. domain = myoptarg;
  154. break;
  155. case 'p' :
  156. port = atoi(myoptarg);
  157. break;
  158. case 'v' :
  159. version = atoi(myoptarg);
  160. if (version < 0 || version > 3) {
  161. Usage();
  162. exit(MY_EX_USAGE);
  163. }
  164. if (doDTLS)
  165. version = -1; /* DTLS flag */
  166. break;
  167. case 'l' :
  168. cipherList = myoptarg;
  169. break;
  170. case 'A' :
  171. verifyCert = myoptarg;
  172. break;
  173. case 'c' :
  174. ourCert = myoptarg;
  175. break;
  176. case 'k' :
  177. ourKey = myoptarg;
  178. break;
  179. case 'b' :
  180. benchmark = atoi(myoptarg);
  181. if (benchmark < 0 || benchmark > 1000000) {
  182. Usage();
  183. exit(MY_EX_USAGE);
  184. }
  185. break;
  186. case 'N' :
  187. nonBlocking = 1;
  188. break;
  189. case 'r' :
  190. resumeSession = 1;
  191. break;
  192. default:
  193. Usage();
  194. exit(MY_EX_USAGE);
  195. }
  196. }
  197. myoptind = 0; /* reset for test cases */
  198. switch (version) {
  199. #ifndef NO_OLD_TLS
  200. case 0:
  201. method = CyaSSLv3_client_method();
  202. break;
  203. case 1:
  204. method = CyaTLSv1_client_method();
  205. break;
  206. case 2:
  207. method = CyaTLSv1_1_client_method();
  208. break;
  209. #endif
  210. case 3:
  211. method = CyaTLSv1_2_client_method();
  212. break;
  213. #ifdef CYASSL_DTLS
  214. case -1:
  215. method = CyaDTLSv1_client_method();
  216. break;
  217. #endif
  218. default:
  219. err_sys("Bad SSL version");
  220. }
  221. if (method == NULL)
  222. err_sys("unable to get method");
  223. ctx = CyaSSL_CTX_new(method);
  224. if (ctx == NULL)
  225. err_sys("unable to get ctx");
  226. if (cipherList)
  227. if (CyaSSL_CTX_set_cipher_list(ctx, cipherList) != SSL_SUCCESS)
  228. err_sys("client can't set cipher list 1");
  229. #ifdef CYASSL_LEANPSK
  230. usePsk = 1;
  231. #endif
  232. if (usePsk) {
  233. #ifndef NO_PSK
  234. CyaSSL_CTX_set_psk_client_callback(ctx, my_psk_client_cb);
  235. if (cipherList == NULL) {
  236. const char *defaultCipherList;
  237. #ifdef HAVE_NULL_CIPHER
  238. defaultCipherList = "PSK-NULL-SHA";
  239. #else
  240. defaultCipherList = "PSK-AES256-CBC-SHA";
  241. #endif
  242. if (CyaSSL_CTX_set_cipher_list(ctx,defaultCipherList) !=SSL_SUCCESS)
  243. err_sys("client can't set cipher list 2");
  244. }
  245. #endif
  246. }
  247. #ifdef OPENSSL_EXTRA
  248. CyaSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
  249. #endif
  250. #if defined(CYASSL_SNIFFER) && !defined(HAVE_NTRU) && !defined(HAVE_ECC)
  251. if (cipherList == NULL) {
  252. /* don't use EDH, can't sniff tmp keys */
  253. if (CyaSSL_CTX_set_cipher_list(ctx, "AES256-SHA") != SSL_SUCCESS) {
  254. err_sys("client can't set cipher list 3");
  255. }
  256. }
  257. #endif
  258. #ifdef USER_CA_CB
  259. CyaSSL_CTX_SetCACb(ctx, CaCb);
  260. #endif
  261. #ifdef VERIFY_CALLBACK
  262. CyaSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, myVerify);
  263. #endif
  264. #ifndef NO_FILESYSTEM
  265. if (!usePsk){
  266. if (CyaSSL_CTX_use_certificate_file(ctx, ourCert, SSL_FILETYPE_PEM)
  267. != SSL_SUCCESS)
  268. err_sys("can't load client cert file, check file and run from"
  269. " CyaSSL home dir");
  270. if (CyaSSL_CTX_use_PrivateKey_file(ctx, ourKey, SSL_FILETYPE_PEM)
  271. != SSL_SUCCESS)
  272. err_sys("can't load client cert file, check file and run from"
  273. " CyaSSL home dir");
  274. if (CyaSSL_CTX_load_verify_locations(ctx, verifyCert, 0) != SSL_SUCCESS)
  275. err_sys("can't load ca file, Please run from CyaSSL home dir");
  276. }
  277. #endif
  278. if (!usePsk && doPeerCheck == 0)
  279. CyaSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);
  280. #ifdef HAVE_CAVIUM
  281. CyaSSL_CTX_UseCavium(ctx, CAVIUM_DEV_ID);
  282. #endif
  283. if (benchmark) {
  284. /* time passed in number of connects give average */
  285. int times = benchmark;
  286. int i = 0;
  287. double start = current_time(), avg;
  288. for (i = 0; i < times; i++) {
  289. tcp_connect(&sockfd, host, port, doDTLS);
  290. ssl = CyaSSL_new(ctx);
  291. CyaSSL_set_fd(ssl, sockfd);
  292. if (CyaSSL_connect(ssl) != SSL_SUCCESS)
  293. err_sys("SSL_connect failed");
  294. CyaSSL_shutdown(ssl);
  295. CyaSSL_free(ssl);
  296. CloseSocket(sockfd);
  297. }
  298. avg = current_time() - start;
  299. avg /= times;
  300. avg *= 1000; /* milliseconds */
  301. printf("CyaSSL_connect avg took: %8.3f milliseconds\n", avg);
  302. CyaSSL_CTX_free(ctx);
  303. ((func_args*)args)->return_code = 0;
  304. exit(EXIT_SUCCESS);
  305. }
  306. ssl = CyaSSL_new(ctx);
  307. if (ssl == NULL)
  308. err_sys("unable to get SSL object");
  309. if (doDTLS) {
  310. SOCKADDR_IN_T addr;
  311. build_addr(&addr, host, port);
  312. CyaSSL_dtls_set_peer(ssl, &addr, sizeof(addr));
  313. tcp_socket(&sockfd, 1);
  314. }
  315. else {
  316. tcp_connect(&sockfd, host, port, 0);
  317. }
  318. CyaSSL_set_fd(ssl, sockfd);
  319. #ifdef HAVE_CRL
  320. if (CyaSSL_EnableCRL(ssl, CYASSL_CRL_CHECKALL) != SSL_SUCCESS)
  321. err_sys("can't enable crl check");
  322. if (CyaSSL_LoadCRL(ssl, crlPemDir, SSL_FILETYPE_PEM, 0) != SSL_SUCCESS)
  323. err_sys("can't load crl, check crlfile and date validity");
  324. if (CyaSSL_SetCRL_Cb(ssl, CRL_CallBack) != SSL_SUCCESS)
  325. err_sys("can't set crl callback");
  326. #endif
  327. if (matchName && doPeerCheck)
  328. CyaSSL_check_domain_name(ssl, domain);
  329. #ifndef CYASSL_CALLBACKS
  330. if (nonBlocking) {
  331. CyaSSL_set_using_nonblock(ssl, 1);
  332. tcp_set_nonblocking(&sockfd);
  333. NonBlockingSSL_Connect(ssl);
  334. }
  335. else if (CyaSSL_connect(ssl) != SSL_SUCCESS) {
  336. /* see note at top of README */
  337. int err = CyaSSL_get_error(ssl, 0);
  338. char buffer[80];
  339. printf("err = %d, %s\n", err,
  340. CyaSSL_ERR_error_string(err, buffer));
  341. err_sys("SSL_connect failed");
  342. /* if you're getting an error here */
  343. }
  344. #else
  345. timeout.tv_sec = 2;
  346. timeout.tv_usec = 0;
  347. NonBlockingSSL_Connect(ssl); /* will keep retrying on timeout */
  348. #endif
  349. showPeer(ssl);
  350. if (sendGET) {
  351. printf("SSL connect ok, sending GET...\n");
  352. msgSz = 28;
  353. strncpy(msg, "GET /index.html HTTP/1.0\r\n\r\n", msgSz);
  354. }
  355. if (CyaSSL_write(ssl, msg, msgSz) != msgSz)
  356. err_sys("SSL_write failed");
  357. input = CyaSSL_read(ssl, reply, sizeof(reply));
  358. if (input > 0) {
  359. reply[input] = 0;
  360. printf("Server response: %s\n", reply);
  361. if (sendGET) { /* get html */
  362. while (1) {
  363. input = CyaSSL_read(ssl, reply, sizeof(reply));
  364. if (input > 0) {
  365. reply[input] = 0;
  366. printf("%s\n", reply);
  367. }
  368. else
  369. break;
  370. }
  371. }
  372. }
  373. else if (input < 0) {
  374. int readErr = CyaSSL_get_error(ssl, 0);
  375. if (readErr != SSL_ERROR_WANT_READ)
  376. err_sys("CyaSSL_read failed");
  377. }
  378. if (resumeSession) {
  379. if (doDTLS) {
  380. strncpy(msg, "break", 6);
  381. msgSz = (int)strlen(msg);
  382. /* try to send session close */
  383. CyaSSL_write(ssl, msg, msgSz);
  384. }
  385. session = CyaSSL_get_session(ssl);
  386. sslResume = CyaSSL_new(ctx);
  387. }
  388. if (doDTLS == 0) /* don't send alert after "break" command */
  389. CyaSSL_shutdown(ssl); /* echoserver will interpret as new conn */
  390. CyaSSL_free(ssl);
  391. CloseSocket(sockfd);
  392. if (resumeSession) {
  393. if (doDTLS) {
  394. SOCKADDR_IN_T addr;
  395. #ifdef USE_WINDOWS_API
  396. Sleep(500);
  397. #else
  398. sleep(1);
  399. #endif
  400. build_addr(&addr, host, port);
  401. CyaSSL_dtls_set_peer(sslResume, &addr, sizeof(addr));
  402. tcp_socket(&sockfd, 1);
  403. }
  404. else {
  405. tcp_connect(&sockfd, host, port, 0);
  406. }
  407. CyaSSL_set_fd(sslResume, sockfd);
  408. CyaSSL_set_session(sslResume, session);
  409. showPeer(sslResume);
  410. #ifndef CYASSL_CALLBACKS
  411. if (nonBlocking) {
  412. CyaSSL_set_using_nonblock(sslResume, 1);
  413. tcp_set_nonblocking(&sockfd);
  414. NonBlockingSSL_Connect(sslResume);
  415. }
  416. else if (CyaSSL_connect(sslResume) != SSL_SUCCESS)
  417. err_sys("SSL resume failed");
  418. #else
  419. timeout.tv_sec = 2;
  420. timeout.tv_usec = 0;
  421. NonBlockingSSL_Connect(ssl); /* will keep retrying on timeout */
  422. #endif
  423. #ifdef OPENSSL_EXTRA
  424. if (CyaSSL_session_reused(sslResume))
  425. printf("reused session id\n");
  426. else
  427. printf("didn't reuse session id!!!\n");
  428. #endif
  429. if (CyaSSL_write(sslResume, resumeMsg, resumeSz) != resumeSz)
  430. err_sys("SSL_write failed");
  431. if (nonBlocking) {
  432. /* give server a chance to bounce a message back to client */
  433. #ifdef USE_WINDOWS_API
  434. Sleep(500);
  435. #else
  436. sleep(1);
  437. #endif
  438. }
  439. input = CyaSSL_read(sslResume, reply, sizeof(reply));
  440. if (input > 0) {
  441. reply[input] = 0;
  442. printf("Server resume response: %s\n", reply);
  443. }
  444. /* try to send session break */
  445. CyaSSL_write(sslResume, msg, msgSz);
  446. CyaSSL_shutdown(sslResume);
  447. CyaSSL_free(sslResume);
  448. }
  449. CyaSSL_CTX_free(ctx);
  450. CloseSocket(sockfd);
  451. ((func_args*)args)->return_code = 0;
  452. }
  453. /* so overall tests can pull in test function */
  454. #ifndef NO_MAIN_DRIVER
  455. int main(int argc, char** argv)
  456. {
  457. func_args args;
  458. #ifdef HAVE_CAVIUM
  459. int ret = OpenNitroxDevice(CAVIUM_DIRECT, CAVIUM_DEV_ID);
  460. if (ret != 0)
  461. err_sys("Cavium OpenNitroxDevice failed");
  462. #endif /* HAVE_CAVIUM */
  463. StartTCP();
  464. args.argc = argc;
  465. args.argv = argv;
  466. CyaSSL_Init();
  467. #ifdef DEBUG_CYASSL
  468. CyaSSL_Debugging_ON();
  469. #endif
  470. if (CurrentDir("client") || CurrentDir("build"))
  471. ChangeDirBack(2);
  472. client_test(&args);
  473. CyaSSL_Cleanup();
  474. #ifdef HAVE_CAVIUM
  475. CspShutdown(CAVIUM_DEV_ID);
  476. #endif
  477. return args.return_code;
  478. }
  479. int myoptind = 0;
  480. char* myoptarg = NULL;
  481. #endif /* NO_MAIN_DRIVER */
  482. #ifdef CYASSL_CALLBACKS
  483. int handShakeCB(HandShakeInfo* info)
  484. {
  485. return 0;
  486. }
  487. int timeoutCB(TimeoutInfo* info)
  488. {
  489. return 0;
  490. }
  491. #endif