3
0

ssl_helper.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /*
  2. * Copyright (c) 2013 INSIDE Secure Corporation
  3. * Copyright (c) PeerSec Networks, 2002-2011
  4. * All Rights Reserved
  5. *
  6. * The latest version of this code is available at http://www.matrixssl.org
  7. *
  8. * This software is open source; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. * See the 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. * http://www.gnu.org/copyleft/gpl.html
  21. */
  22. #include <errno.h>
  23. #include <stdlib.h>
  24. #include <unistd.h>
  25. #include <stdarg.h>
  26. #include <fcntl.h>
  27. #include <stdio.h>
  28. #include <time.h>
  29. #include <poll.h>
  30. #include <sys/socket.h>
  31. #include "matrixssl/matrixsslApi.h"
  32. //#warning "DO NOT USE THESE DEFAULT KEYS IN PRODUCTION ENVIRONMENTS."
  33. /*
  34. * If supporting client authentication, pick ONE identity to auto select a
  35. * certificate and private key that support desired algorithms.
  36. */
  37. #define ID_RSA /* RSA Certificate and Key */
  38. #define USE_HEADER_KEYS
  39. /* If the algorithm type is supported, load a CA for it */
  40. #ifdef USE_HEADER_KEYS
  41. /* CAs */
  42. # include "sampleCerts/RSA/ALL_RSA_CAS.h"
  43. /* Identity Certs and Keys for use with Client Authentication */
  44. # ifdef ID_RSA
  45. # define EXAMPLE_RSA_KEYS
  46. # include "sampleCerts/RSA/2048_RSA.h"
  47. # include "sampleCerts/RSA/2048_RSA_KEY.h"
  48. # endif
  49. #endif
  50. static ssize_t safe_write(int fd, const void *buf, size_t count)
  51. {
  52. ssize_t n;
  53. do {
  54. n = write(fd, buf, count);
  55. } while (n < 0 && errno == EINTR);
  56. return n;
  57. }
  58. static ssize_t full_write(int fd, const void *buf, size_t len)
  59. {
  60. ssize_t cc;
  61. ssize_t total;
  62. total = 0;
  63. while (len) {
  64. cc = safe_write(fd, buf, len);
  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. total += cc;
  74. buf = ((const char *)buf) + cc;
  75. len -= cc;
  76. }
  77. return total;
  78. }
  79. static void say(const char *s, ...)
  80. {
  81. char buf[256];
  82. va_list p;
  83. int sz;
  84. va_start(p, s);
  85. sz = vsnprintf(buf, sizeof(buf), s, p);
  86. full_write(STDERR_FILENO, buf, sz >= 0 && sz < sizeof(buf) ? sz : strlen(buf));
  87. va_end(p);
  88. }
  89. static void die(const char *s, ...)
  90. {
  91. char buf[256];
  92. va_list p;
  93. int sz;
  94. va_start(p, s);
  95. sz = vsnprintf(buf, sizeof(buf), s, p);
  96. full_write(STDERR_FILENO, buf, sz >= 0 && sz < sizeof(buf) ? sz : strlen(buf));
  97. exit(1);
  98. va_end(p);
  99. }
  100. #if 0
  101. # define dbg(...) say(__VA_ARGS__)
  102. #else
  103. # define dbg(...) ((void)0)
  104. #endif
  105. static struct pollfd pfd[2] = {
  106. { -1, POLLIN|POLLERR|POLLHUP, 0 },
  107. { -1, POLLIN|POLLERR|POLLHUP, 0 },
  108. };
  109. #define STDIN pfd[0]
  110. #define NETWORK pfd[1]
  111. #define STDIN_READY() (pfd[0].revents & (POLLIN|POLLERR|POLLHUP))
  112. #define NETWORK_READY() (pfd[1].revents & (POLLIN|POLLERR|POLLHUP))
  113. static int wait_for_input(void)
  114. {
  115. if (STDIN.fd == NETWORK.fd) /* means both are -1 */
  116. exit(0);
  117. dbg("polling\n");
  118. STDIN.revents = NETWORK.revents = 0;
  119. return poll(pfd, 2, -1);
  120. }
  121. static int32 certCb(ssl_t *ssl, psX509Cert_t *cert, int32 alert)
  122. {
  123. /* Example to allow anonymous connections based on a define */
  124. if (alert > 0) {
  125. return SSL_ALLOW_ANON_CONNECTION; // = 254
  126. }
  127. #if 0
  128. /* Validate the 'not before' and 'not after' dates, etc */
  129. return PS_FAILURE; /* if we don't like this cert */
  130. #endif
  131. return PS_SUCCESS;
  132. }
  133. static void close_conn_and_exit(ssl_t *ssl, int fd)
  134. {
  135. unsigned char *buf;
  136. int len;
  137. fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
  138. /* Quick attempt to send a closure alert, don't worry about failure */
  139. if (matrixSslEncodeClosureAlert(ssl) >= 0) {
  140. len = matrixSslGetOutdata(ssl, &buf);
  141. if (len > 0) {
  142. len = safe_write(fd, buf, len);
  143. //if (len > 0) {
  144. // matrixSslSentData(ssl, len);
  145. //}
  146. }
  147. }
  148. //matrixSslDeleteSession(ssl);
  149. shutdown(fd, SHUT_WR);
  150. exit(0);
  151. }
  152. static int encode_data(ssl_t *ssl, const void *data, int len)
  153. {
  154. unsigned char *buf;
  155. int available;
  156. available = matrixSslGetWritebuf(ssl, &buf, len);
  157. if (available < 0)
  158. die("matrixSslGetWritebuf\n");
  159. if (len > available)
  160. die("len > available\n");
  161. memcpy(buf, data, len);
  162. if (matrixSslEncodeWritebuf(ssl, len) < 0)
  163. die("matrixSslEncodeWritebuf\n");
  164. return len;
  165. }
  166. static void flush_to_net(ssl_t *ssl, int fd)
  167. {
  168. int rc;
  169. int len;
  170. unsigned char *buf;
  171. while ((len = matrixSslGetOutdata(ssl, &buf)) > 0) {
  172. dbg("writing net %d bytes\n", len);
  173. if (full_write(fd, buf, len) != len)
  174. die("write to network\n");
  175. rc = matrixSslSentData(ssl, len);
  176. if (rc < 0)
  177. die("matrixSslSentData\n");
  178. }
  179. }
  180. static void do_io_until_eof_and_exit(int fd, sslKeys_t *keys)
  181. {
  182. int rc;
  183. int len;
  184. uint32_t len32u;
  185. sslSessionId_t *sid;
  186. ssl_t *ssl;
  187. unsigned char *buf;
  188. NETWORK.fd = fd;
  189. /* Note! STDIN.fd is disabled (-1) until SSL handshake is over:
  190. * we do not attempt to feed any user data to MatrixSSL
  191. * before it is ready.
  192. */
  193. matrixSslNewSessionId(&sid);
  194. rc = matrixSslNewClientSession(&ssl, keys, sid, 0, certCb, NULL, NULL, 0);
  195. dbg("matrixSslNewClientSession:rc=%d\n", rc);
  196. if (rc != MATRIXSSL_REQUEST_SEND)
  197. die("matrixSslNewClientSession\n");
  198. len = 0; /* only to suppress compiler warning */
  199. again:
  200. switch (rc) {
  201. case MATRIXSSL_REQUEST_SEND:
  202. dbg("MATRIXSSL_REQUEST_SEND\n");
  203. flush_to_net(ssl, fd);
  204. goto poll_input;
  205. case 0:
  206. dbg("rc==0\n");
  207. flush_to_net(ssl, fd);
  208. goto poll_input;
  209. case MATRIXSSL_REQUEST_CLOSE:
  210. /* what does this mean if we are here? */
  211. dbg("MATRIXSSL_REQUEST_CLOSE\n");
  212. close_conn_and_exit(ssl, fd);
  213. case MATRIXSSL_HANDSHAKE_COMPLETE:
  214. dbg("MATRIXSSL_HANDSHAKE_COMPLETE\n");
  215. /* Init complete, can start reading local user's data: */
  216. STDIN.fd = STDIN_FILENO;
  217. poll_input:
  218. wait_for_input();
  219. if (STDIN_READY()) {
  220. char ibuf[4 * 1024];
  221. dbg("reading stdin\n");
  222. len = read(STDIN_FILENO, ibuf, sizeof(ibuf));
  223. if (len < 0)
  224. die("read error on stdin\n");
  225. if (len == 0)
  226. STDIN.fd = -1;
  227. else {
  228. len = encode_data(ssl, ibuf, len);
  229. if (len) {
  230. rc = MATRIXSSL_REQUEST_SEND;
  231. dbg("rc=%d\n", rc);
  232. goto again;
  233. }
  234. }
  235. }
  236. read_network:
  237. if (NETWORK_READY()) {
  238. dbg("%s%s%s\n",
  239. (pfd[1].revents & POLLIN) ? "POLLIN" : "",
  240. (pfd[1].revents & POLLERR) ? "|POLLERR" : "",
  241. (pfd[1].revents & POLLHUP) ? "|POLLHUP" : ""
  242. );
  243. len = matrixSslGetReadbuf(ssl, &buf);
  244. if (len <= 0)
  245. die("matrixSslGetReadbuf\n");
  246. dbg("reading net up to %d\n", len);
  247. len = read(fd, buf, len);
  248. dbg("reading net:%d\n", len);
  249. if (len < 0)
  250. die("read error on network\n");
  251. if (len == 0) /*eof*/
  252. NETWORK.fd = -1;
  253. len32u = len;
  254. rc = matrixSslReceivedData(ssl, len, &buf, &len32u);
  255. dbg("matrixSslReceivedData:rc=%d\n", rc);
  256. len = len32u;
  257. if (rc < 0)
  258. die("matrixSslReceivedData\n");
  259. }
  260. goto again;
  261. case MATRIXSSL_APP_DATA:
  262. dbg("MATRIXSSL_APP_DATA: writing stdout\n");
  263. do {
  264. if (full_write(STDOUT_FILENO, buf, len) != len)
  265. die("write to stdout\n");
  266. len32u = len;
  267. rc = matrixSslProcessedData(ssl, &buf, &len32u);
  268. //this was seen returning rc=0:
  269. dbg("matrixSslProcessedData:rc=%d\n", rc);
  270. len = len32u;
  271. } while (rc == MATRIXSSL_APP_DATA);
  272. if (pfd[1].fd == -1) {
  273. /* Already saw EOF on network, and we processed
  274. * and wrote out all ssl data. Signal it:
  275. */
  276. close(STDOUT_FILENO);
  277. }
  278. goto again;
  279. case MATRIXSSL_REQUEST_RECV:
  280. dbg("MATRIXSSL_REQUEST_RECV\n");
  281. wait_for_input();
  282. goto read_network;
  283. case MATRIXSSL_RECEIVED_ALERT:
  284. dbg("MATRIXSSL_RECEIVED_ALERT\n");
  285. /* The first byte of the buffer is the level */
  286. /* The second byte is the description */
  287. if (buf[0] == SSL_ALERT_LEVEL_FATAL)
  288. die("Fatal alert\n");
  289. /* Closure alert is normal (and best) way to close */
  290. if (buf[1] == SSL_ALERT_CLOSE_NOTIFY)
  291. close_conn_and_exit(ssl, fd);
  292. die("Warning alert\n");
  293. len32u = len;
  294. rc = matrixSslProcessedData(ssl, &buf, &len32u);
  295. dbg("matrixSslProcessedData:rc=%d\n", rc);
  296. len = len32u;
  297. goto again;
  298. default:
  299. /* If rc < 0 it is an error */
  300. die("bad rc:%d\n", rc);
  301. }
  302. }
  303. static sslKeys_t* make_keys(void)
  304. {
  305. int rc, CAstreamLen;
  306. char *CAstream;
  307. sslKeys_t *keys;
  308. if (matrixSslNewKeys(&keys) < 0)
  309. die("matrixSslNewKeys\n");
  310. #ifdef USE_HEADER_KEYS
  311. /*
  312. * In-memory based keys
  313. * Build the CA list first for potential client auth usage
  314. */
  315. CAstream = NULL;
  316. CAstreamLen = sizeof(RSACAS);
  317. if (CAstreamLen > 0) {
  318. CAstream = psMalloc(NULL, CAstreamLen);
  319. memcpy(CAstream, RSACAS, sizeof(RSACAS));
  320. }
  321. #ifdef ID_RSA
  322. rc = matrixSslLoadRsaKeysMem(keys, RSA2048, sizeof(RSA2048),
  323. RSA2048KEY, sizeof(RSA2048KEY), (unsigned char*)CAstream,
  324. CAstreamLen);
  325. if (rc < 0)
  326. die("matrixSslLoadRsaKeysMem\n");
  327. #endif
  328. if (CAstream)
  329. psFree(CAstream);
  330. #endif /* USE_HEADER_KEYS */
  331. return keys;
  332. }
  333. int main(int argc, char **argv)
  334. {
  335. int fd;
  336. char *fd_str;
  337. if (!argv[1])
  338. die("Syntax error\n");
  339. if (argv[1][0] != '-')
  340. die("Syntax error\n");
  341. if (argv[1][1] != 'd')
  342. die("Syntax error\n");
  343. fd_str = argv[1] + 2;
  344. if (!fd_str[0])
  345. fd_str = argv[2];
  346. if (!fd_str || fd_str[0] < '0' || fd_str[0] > '9')
  347. die("Syntax error\n");
  348. fd = atoi(fd_str);
  349. if (fd < 3)
  350. die("Syntax error\n");
  351. if (matrixSslOpen() < 0)
  352. die("matrixSslOpen\n");
  353. do_io_until_eof_and_exit(fd, make_keys());
  354. /* does not return */
  355. return 0;
  356. }