goahead-mbedtls.c 17 KB

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