goahead-mbedtls.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. /*
  2. goahead-mbedtls.c - MbedTLS interface to GoAhead
  3. Copyright (c) All Rights Reserved. See details at the end of the file.
  4. */
  5. /************************************ Include *********************************/
  6. #include "goahead.h"
  7. #if ME_COM_MBEDTLS
  8. /*
  9. Indent to bypass MakeMe dependencies
  10. */
  11. #include "mbedtls.h"
  12. /************************************* Defines ********************************/
  13. typedef struct MbedConfig {
  14. mbedtls_x509_crt ca; /* Certificate authority bundle to verify peer */
  15. mbedtls_ssl_cache_context cache; /* Session cache context */
  16. mbedtls_ssl_config conf; /* SSL configuration */
  17. mbedtls_x509_crt cert; /* Certificate (own) */
  18. mbedtls_ctr_drbg_context ctr; /* Counter random generator state */
  19. mbedtls_ssl_ticket_context tickets; /* Session tickets */
  20. mbedtls_entropy_context entropy; /* Entropy context */
  21. mbedtls_x509_crl revoke; /* Certificate authority bundle to verify peer */
  22. mbedtls_pk_context pkey; /* Private key */
  23. int *ciphers; /* Set of acceptable ciphers - null terminated */
  24. } MbedConfig;
  25. /*
  26. Per socket state
  27. */
  28. typedef struct MbedSocket {
  29. mbedtls_ssl_context ctx; /* SSL state */
  30. mbedtls_ssl_session session; /* SSL sessions */
  31. } MbedSocket;
  32. static MbedConfig cfg;
  33. /*
  34. GoAhead Log level to start SSL tracing
  35. */
  36. static int mbedLogLevel = ME_GOAHEAD_SSL_LOG_LEVEL;
  37. /************************************ Forwards ********************************/
  38. static int *getCipherSuite(char *ciphers, int *len);
  39. static int mbedHandshake(Webs *wp);
  40. static int parseCert(mbedtls_x509_crt *cert, char *file);
  41. static int parseCrl(mbedtls_x509_crl *crl, char *path);
  42. static int parseKey(mbedtls_pk_context *key, char *path);
  43. static void merror(int rc, char *fmt, ...);
  44. static char *replaceHyphen(char *cipher, char from, char to);
  45. static void traceMbed(void *context, int level, cchar *file, int line, cchar *str);
  46. /************************************** Code **********************************/
  47. PUBLIC int sslOpen()
  48. {
  49. mbedtls_ssl_config *conf;
  50. int rc;
  51. trace(7, "Initializing MbedTLS SSL");
  52. mbedtls_entropy_init(&cfg.entropy);
  53. conf = &cfg.conf;
  54. mbedtls_ssl_config_init(conf);
  55. mbedtls_ssl_conf_dbg(conf, traceMbed, NULL);
  56. if (websGetLogLevel() >= mbedLogLevel) {
  57. mbedtls_debug_set_threshold(websGetLogLevel() - mbedLogLevel);
  58. }
  59. mbedtls_pk_init(&cfg.pkey);
  60. mbedtls_ssl_cache_init(&cfg.cache);
  61. mbedtls_ctr_drbg_init(&cfg.ctr);
  62. mbedtls_x509_crt_init(&cfg.cert);
  63. mbedtls_ssl_ticket_init(&cfg.tickets);
  64. if ((rc = mbedtls_ctr_drbg_seed(&cfg.ctr, mbedtls_entropy_func, &cfg.entropy, (cuchar*) ME_NAME, slen(ME_NAME))) < 0) {
  65. merror(rc, "Cannot seed rng");
  66. return -1;
  67. }
  68. /*
  69. Set the server certificate and key files
  70. */
  71. if (*ME_GOAHEAD_SSL_KEY) {
  72. /*
  73. Load a decrypted PEM format private key. The last arg is the private key.
  74. */
  75. if (parseKey(&cfg.pkey, ME_GOAHEAD_SSL_KEY) < 0) {
  76. return -1;
  77. }
  78. }
  79. if (*ME_GOAHEAD_SSL_CERTIFICATE) {
  80. /*
  81. Load a PEM format certificate file
  82. */
  83. if (parseCert(&cfg.cert, ME_GOAHEAD_SSL_CERTIFICATE) < 0) {
  84. return -1;
  85. }
  86. }
  87. if (*ME_GOAHEAD_SSL_AUTHORITY) {
  88. if (parseCert(&cfg.ca, ME_GOAHEAD_SSL_AUTHORITY) != 0) {
  89. return -1;
  90. }
  91. }
  92. if (*ME_GOAHEAD_SSL_REVOKE) {
  93. /*
  94. Load a PEM format certificate file
  95. */
  96. if (parseCrl(&cfg.revoke, (char*) ME_GOAHEAD_SSL_REVOKE) != 0) {
  97. return -1;
  98. }
  99. }
  100. if (ME_GOAHEAD_SSL_CIPHERS && *ME_GOAHEAD_SSL_CIPHERS) {
  101. cfg.ciphers = getCipherSuite(ME_GOAHEAD_SSL_CIPHERS, NULL);
  102. }
  103. if ((rc = mbedtls_ssl_config_defaults(conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM,
  104. MBEDTLS_SSL_PRESET_DEFAULT)) < 0) {
  105. merror(rc, "Cannot set mbedtls defaults");
  106. return -1;
  107. }
  108. mbedtls_ssl_conf_rng(conf, mbedtls_ctr_drbg_random, &cfg.ctr);
  109. /*
  110. Configure larger DH parameters
  111. */
  112. if ((rc = mbedtls_ssl_conf_dh_param(conf, MBEDTLS_DHM_RFC5114_MODP_2048_P, MBEDTLS_DHM_RFC5114_MODP_2048_G)) < 0) {
  113. merror(rc, "Cannot set DH params");
  114. return -1;
  115. }
  116. /*
  117. Set auth mode if peer cert should be verified
  118. */
  119. mbedtls_ssl_conf_authmode(conf, ME_GOAHEAD_SSL_VERIFY_PEER ? MBEDTLS_SSL_VERIFY_OPTIONAL : MBEDTLS_SSL_VERIFY_NONE);
  120. /*
  121. Configure ticket-based sessions
  122. */
  123. if (ME_GOAHEAD_SSL_TICKET) {
  124. if ((rc = mbedtls_ssl_ticket_setup(&cfg.tickets, mbedtls_ctr_drbg_random, &cfg.ctr,
  125. MBEDTLS_CIPHER_AES_256_GCM, ME_GOAHEAD_SSL_TIMEOUT)) < 0) {
  126. merror(rc, "Cannot setup ticketing sessions");
  127. return -1;
  128. }
  129. mbedtls_ssl_conf_session_tickets_cb(conf, mbedtls_ssl_ticket_write, mbedtls_ssl_ticket_parse, &cfg.tickets);
  130. }
  131. /*
  132. Configure server-side session cache
  133. */
  134. if (ME_GOAHEAD_SSL_CACHE) {
  135. mbedtls_ssl_conf_session_cache(conf, &cfg.cache, mbedtls_ssl_cache_get, mbedtls_ssl_cache_set);
  136. mbedtls_ssl_cache_set_max_entries(&cfg.cache, ME_GOAHEAD_SSL_CACHE);
  137. mbedtls_ssl_cache_set_timeout(&cfg.cache, ME_GOAHEAD_SSL_TIMEOUT);
  138. }
  139. /*
  140. Configure explicit cipher suite selection
  141. */
  142. if (cfg.ciphers) {
  143. mbedtls_ssl_conf_ciphersuites(conf, cfg.ciphers);
  144. }
  145. /*
  146. Configure CA certificate bundle and revocation list
  147. */
  148. mbedtls_ssl_conf_ca_chain(conf, *ME_GOAHEAD_SSL_AUTHORITY ? &cfg.ca : NULL, *ME_GOAHEAD_SSL_REVOKE ? &cfg.revoke : NULL);
  149. /*
  150. Configure server cert and key
  151. */
  152. if (ME_GOAHEAD_SSL_KEY[0] != '\0' && ME_GOAHEAD_SSL_CERTIFICATE[0] != '\0') {
  153. if ((rc = mbedtls_ssl_conf_own_cert(conf, &cfg.cert, &cfg.pkey)) < 0) {
  154. merror(rc, "Cannot define certificate and private key");
  155. return -1;
  156. }
  157. }
  158. if (websGetLogLevel() >= 5) {
  159. char cipher[80];
  160. cint *cp;
  161. trace(5, "mbedtls: Supported Ciphers");
  162. for (cp = mbedtls_ssl_list_ciphersuites(); *cp; cp++) {
  163. scopy(cipher, sizeof(cipher), (char*) mbedtls_ssl_get_ciphersuite_name(*cp));
  164. replaceHyphen(cipher, '-', '_');
  165. trace(5, "mbedtls: %s (0x%04X)", cipher, *cp);
  166. }
  167. }
  168. return 0;
  169. }
  170. PUBLIC void sslClose()
  171. {
  172. mbedtls_ctr_drbg_free(&cfg.ctr);
  173. mbedtls_pk_free(&cfg.pkey);
  174. mbedtls_x509_crt_free(&cfg.cert);
  175. mbedtls_x509_crt_free(&cfg.ca);
  176. mbedtls_x509_crl_free(&cfg.revoke);
  177. mbedtls_ssl_cache_free(&cfg.cache);
  178. mbedtls_ssl_ticket_free(&cfg.tickets);
  179. mbedtls_ssl_config_free(&cfg.conf);
  180. mbedtls_entropy_free(&cfg.entropy);
  181. wfree(cfg.ciphers);
  182. }
  183. PUBLIC int sslUpgrade(Webs *wp)
  184. {
  185. MbedSocket *mb;
  186. WebsSocket *sp;
  187. mbedtls_ssl_context *ctx;
  188. assert(wp);
  189. if ((mb = walloc(sizeof(MbedSocket))) == 0) {
  190. return -1;
  191. }
  192. memset(mb, 0, sizeof(MbedSocket));
  193. wp->ssl = mb;
  194. sp = socketPtr(wp->sid);
  195. ctx = &mb->ctx;
  196. mbedtls_ssl_init(ctx);
  197. mbedtls_ssl_setup(ctx, &cfg.conf);
  198. mbedtls_ssl_set_bio(ctx, &sp->sock, mbedtls_net_send, mbedtls_net_recv, 0);
  199. if (mbedHandshake(wp) < 0) {
  200. return -1;
  201. }
  202. return 0;
  203. }
  204. PUBLIC void sslFree(Webs *wp)
  205. {
  206. MbedSocket *mb;
  207. WebsSocket *sp;
  208. mb = wp->ssl;
  209. sp = socketPtr(wp->sid);
  210. if (mb) {
  211. if (!(sp->flags & SOCKET_EOF)) {
  212. mbedtls_ssl_close_notify(&mb->ctx);
  213. }
  214. mbedtls_ssl_free(&mb->ctx);
  215. wfree(mb);
  216. wp->ssl = 0;
  217. }
  218. }
  219. /*
  220. Initiate or continue SSL handshaking with the peer. This routine does not block.
  221. Return -1 on errors, 0 incomplete and awaiting I/O, 1 if successful
  222. */
  223. static int mbedHandshake(Webs *wp)
  224. {
  225. WebsSocket *sp;
  226. MbedSocket *mb;
  227. int rc, vrc;
  228. mb = (MbedSocket*) wp->ssl;
  229. rc = 0;
  230. sp = socketPtr(wp->sid);
  231. sp->flags |= SOCKET_HANDSHAKING;
  232. while (mb->ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER && ((rc = mbedtls_ssl_handshake(&mb->ctx)) != 0)) {
  233. if (rc == MBEDTLS_ERR_SSL_WANT_READ || rc == MBEDTLS_ERR_SSL_WANT_WRITE) {
  234. return 0;
  235. }
  236. break;
  237. }
  238. sp->flags &= ~SOCKET_HANDSHAKING;
  239. /*
  240. Analyze the handshake result
  241. */
  242. if (rc < 0) {
  243. if (rc == MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED &&
  244. (ME_GOAHEAD_SSL_KEY[0] == '\0' || ME_GOAHEAD_SSL_CERTIFICATE[0] == '\0')) {
  245. error("Missing required certificate and key");
  246. } else {
  247. char ebuf[256];
  248. mbedtls_strerror(-rc, ebuf, sizeof(ebuf));
  249. error("%s: error -0x%x", ebuf, -rc);
  250. }
  251. sp->flags |= SOCKET_EOF;
  252. errno = EPROTO;
  253. return -1;
  254. } else if ((vrc = mbedtls_ssl_get_verify_result(&mb->ctx)) != 0) {
  255. if (vrc & MBEDTLS_X509_BADCERT_MISSING) {
  256. logmsg(2, "Certificate missing");
  257. } else if (vrc & MBEDTLS_X509_BADCERT_EXPIRED) {
  258. logmsg(2, "Certificate expired");
  259. } else if (vrc & MBEDTLS_X509_BADCERT_REVOKED) {
  260. logmsg(2, "Certificate revoked");
  261. } else if (vrc & MBEDTLS_X509_BADCERT_CN_MISMATCH) {
  262. logmsg(2, "Certificate common name mismatch");
  263. } else if (vrc & MBEDTLS_X509_BADCERT_KEY_USAGE || vrc & MBEDTLS_X509_BADCERT_EXT_KEY_USAGE) {
  264. logmsg(2, "Unauthorized key use in certificate");
  265. } else if (vrc & MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
  266. logmsg(2, "Certificate not trusted");
  267. if (!ME_GOAHEAD_SSL_VERIFY_ISSUER) {
  268. vrc = 0;
  269. }
  270. } else if (vrc & MBEDTLS_X509_BADCERT_SKIP_VERIFY) {
  271. /*
  272. MBEDTLS_SSL_VERIFY_NONE requested, so ignore error
  273. */
  274. vrc = 0;
  275. } else {
  276. if (mb->ctx.client_auth && !*ME_GOAHEAD_SSL_CERTIFICATE) {
  277. logmsg(2, "Server requires a client certificate");
  278. } else if (rc == MBEDTLS_ERR_NET_CONN_RESET) {
  279. logmsg(2, "Peer disconnected");
  280. } else {
  281. logmsg(2, "Cannot handshake: error -0x%x", -rc);
  282. }
  283. }
  284. if (vrc != 0 && ME_GOAHEAD_SSL_VERIFY_PEER) {
  285. if (mbedtls_ssl_get_peer_cert(&mb->ctx) == 0) {
  286. logmsg(2, "Peer did not provide a certificate");
  287. }
  288. sp->flags |= SOCKET_EOF;
  289. errno = EPROTO;
  290. return -1;
  291. }
  292. }
  293. return 1;
  294. }
  295. PUBLIC ssize sslRead(Webs *wp, void *buf, ssize len)
  296. {
  297. WebsSocket *sp;
  298. MbedSocket *mb;
  299. int rc;
  300. if (!wp->ssl) {
  301. assert(0);
  302. return -1;
  303. }
  304. mb = (MbedSocket*) wp->ssl;
  305. assert(mb);
  306. sp = socketPtr(wp->sid);
  307. if (mb->ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER) {
  308. if ((rc = mbedHandshake(wp)) <= 0) {
  309. return rc;
  310. }
  311. }
  312. while (1) {
  313. rc = mbedtls_ssl_read(&mb->ctx, buf, (int) len);
  314. trace(5, "mbedtls: mbedtls_ssl_read %d", rc);
  315. if (rc < 0) {
  316. if (rc == MBEDTLS_ERR_SSL_WANT_READ || rc == MBEDTLS_ERR_SSL_WANT_WRITE) {
  317. continue;
  318. } else if (rc == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
  319. trace(5, "mbedtls: connection was closed gracefully");
  320. sp->flags |= SOCKET_EOF;
  321. return -1;
  322. } else if (rc == MBEDTLS_ERR_NET_CONN_RESET) {
  323. trace(5, "mbedtls: connection reset");
  324. sp->flags |= SOCKET_EOF;
  325. return -1;
  326. } else {
  327. trace(4, "mbedtls: read error -0x%", -rc);
  328. sp->flags |= SOCKET_EOF;
  329. return -1;
  330. }
  331. } else if (rc == 0) {
  332. sp->flags |= SOCKET_EOF;
  333. return -1;
  334. }
  335. break;
  336. }
  337. socketHiddenData(sp, mbedtls_ssl_get_bytes_avail(&mb->ctx), SOCKET_READABLE);
  338. return rc;
  339. }
  340. PUBLIC ssize sslWrite(Webs *wp, void *buf, ssize len)
  341. {
  342. MbedSocket *mb;
  343. ssize totalWritten;
  344. int rc;
  345. if (wp->ssl == 0 || len <= 0) {
  346. assert(0);
  347. return -1;
  348. }
  349. mb = (MbedSocket*) wp->ssl;
  350. if (mb->ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER) {
  351. if ((rc = mbedHandshake(wp)) <= 0) {
  352. return rc;
  353. }
  354. }
  355. totalWritten = 0;
  356. do {
  357. rc = mbedtls_ssl_write(&mb->ctx, (uchar*) buf, (int) len);
  358. trace(7, "mbedtls write: wrote %d of %zd", rc, len);
  359. if (rc <= 0) {
  360. if (rc == MBEDTLS_ERR_SSL_WANT_READ || rc == MBEDTLS_ERR_SSL_WANT_WRITE) {
  361. socketSetError(EAGAIN);
  362. return -1;
  363. }
  364. if (rc == MBEDTLS_ERR_NET_CONN_RESET) {
  365. trace(4, "mbedtls_ssl_write peer closed");
  366. return -1;
  367. } else {
  368. trace(4, "mbedtls_ssl_write failed rc %d", rc);
  369. return -1;
  370. }
  371. } else {
  372. totalWritten += rc;
  373. buf = (void*) ((char*) buf + rc);
  374. len -= rc;
  375. }
  376. } while (len > 0);
  377. socketHiddenData(socketPtr(wp->sid), mb->ctx.in_left, SOCKET_WRITABLE);
  378. return totalWritten;
  379. }
  380. /*
  381. Convert string of IANA ciphers into a list of cipher codes
  382. */
  383. static int *getCipherSuite(char *ciphers, int *len)
  384. {
  385. char *cipher, *next;
  386. cint *cp;
  387. int nciphers, i, *result, code;
  388. if (!ciphers || *ciphers == 0) {
  389. return 0;
  390. }
  391. for (nciphers = 0, cp = mbedtls_ssl_list_ciphersuites(); cp && *cp; cp++, nciphers++) { }
  392. result = walloc((nciphers + 1) * sizeof(int));
  393. next = sclone(ciphers);
  394. for (i = 0; (cipher = stok(next, ":, \t", &next)) != 0; ) {
  395. replaceHyphen(cipher, '_', '-');
  396. if ((code = mbedtls_ssl_get_ciphersuite_id(cipher)) <= 0) {
  397. error("Unsupported cipher \"%s\"", cipher);
  398. continue;
  399. }
  400. result[i++] = code;
  401. }
  402. result[i] = 0;
  403. if (len) {
  404. *len = i;
  405. }
  406. return result;
  407. }
  408. static int parseCert(mbedtls_x509_crt *cert, char *path)
  409. {
  410. char *buf;
  411. ssize len;
  412. if ((buf = websReadWholeFile(path)) == 0) {
  413. error("Unable to read certificate %s", path);
  414. return -1;
  415. }
  416. len = slen(buf);
  417. if (strstr(buf, "-----BEGIN ")) {
  418. /* Looks PEM encoded so count the null in the length */
  419. len++;
  420. }
  421. if (mbedtls_x509_crt_parse(cert, (uchar*) buf, len) != 0) {
  422. memset(buf, 0, len);
  423. error("Unable to parse certificate %s", path);
  424. return -1;
  425. }
  426. memset(buf, 0, len);
  427. wfree(buf);
  428. return 0;
  429. }
  430. static int parseKey(mbedtls_pk_context *key, char *path)
  431. {
  432. char *buf;
  433. ssize len;
  434. if ((buf = websReadWholeFile(path)) == 0) {
  435. error("Unable to read key %s", path);
  436. return -1;
  437. }
  438. len = slen(buf);
  439. if (strstr(buf, "-----BEGIN ")) {
  440. len++;
  441. }
  442. if (mbedtls_pk_parse_key(key, (uchar*) buf, len, NULL, 0) != 0) {
  443. memset(buf, 0, len);
  444. error("Unable to parse key %s", path);
  445. return -1;
  446. }
  447. memset(buf, 0, len);
  448. wfree(buf);
  449. return 0;
  450. }
  451. static int parseCrl(mbedtls_x509_crl *crl, char *path)
  452. {
  453. char *buf;
  454. ssize len;
  455. if ((buf = websReadWholeFile(path)) == 0) {
  456. error("Unable to read crl %s", path);
  457. return -1;
  458. }
  459. len = slen(buf);
  460. if (strstr(buf, "-----BEGIN ")) {
  461. len++;
  462. }
  463. if (mbedtls_x509_crl_parse(crl, (uchar*) buf, len) != 0) {
  464. memset(buf, 0, len);
  465. error("Unable to parse crl %s", path);
  466. return -1;
  467. }
  468. memset(buf, 0, len);
  469. wfree(buf);
  470. return 0;
  471. }
  472. static void traceMbed(void *context, int level, cchar *file, int line, cchar *str)
  473. {
  474. char *buf;
  475. level += mbedLogLevel;
  476. if (level <= websGetLogLevel()) {
  477. buf = sclone((char*) str);
  478. buf[slen(buf) - 1] = '\0';
  479. trace(level, "%s", buf);
  480. wfree(buf);
  481. }
  482. }
  483. static void merror(int rc, char *fmt, ...)
  484. {
  485. va_list ap;
  486. char ebuf[ME_MAX_BUFFER];
  487. va_start(ap, fmt);
  488. mbedtls_strerror(-rc, ebuf, sizeof(ebuf));
  489. error("mbedtls", "mbedtls error: 0x%x %s %s", rc, sfmtv(fmt, ap), ebuf);
  490. va_end(ap);
  491. }
  492. static char *replaceHyphen(char *cipher, char from, char to)
  493. {
  494. char *cp;
  495. for (cp = cipher; *cp; cp++) {
  496. if (*cp == from) {
  497. *cp = to;
  498. }
  499. }
  500. return cipher;
  501. }
  502. #else
  503. void mbedDummy() {}
  504. #endif /* ME_COM_MBEDTLS */
  505. /*
  506. Copyright (c) Embedthis Software. All Rights Reserved.
  507. This software is distributed under commercial and open source licenses.
  508. You may use the Embedthis GoAhead open source license or you may acquire
  509. a commercial license from Embedthis Software. You agree to be fully bound
  510. by the terms of either license. Consult the LICENSE.md distributed with
  511. this software for full details and other copyrights.
  512. */