struct tls_config * https_init(void) { struct tls_config *tls_config; char *str; int depth; uint32_t http_tls_protocols; const char *errstr; if (tls_init() != 0) errx(1, "tls init failed"); if ((tls_config = tls_config_new()) == NULL) errx(1, "tls config_new failed"); tls_config_set_protocols(tls_config, TLS_PROTOCOLS_ALL); if (tls_config_set_ciphers(tls_config, "compat") != 0) errx(1, "tls set ciphers failed"); if (tls_options == NULL) return tls_config; while (*tls_options) { switch (getsubopt(&tls_options, tls_verify_opts, &str)) { case HTTP_TLS_CAFILE: if (str == NULL) errx(1, "missing CA file"); if (tls_config_set_ca_file(tls_config, str) != 0) errx(1, "tls ca file failed"); break; case HTTP_TLS_CAPATH: if (str == NULL) errx(1, "missing ca path"); if (tls_config_set_ca_path(tls_config, str) != 0) errx(1, "tls ca path failed"); break; case HTTP_TLS_CIPHERS: if (str == NULL) errx(1, "missing cipher list"); if (tls_config_set_ciphers(tls_config, str) != 0) errx(1, "tls set ciphers failed"); break; case HTTP_TLS_DONTVERIFY: tls_config_insecure_noverifycert(tls_config); tls_config_insecure_noverifyname(tls_config); break; case HTTP_TLS_PROTOCOLS: if (tls_config_parse_protocols(&http_tls_protocols, str) != 0) errx(1, "tls parsing protocols failed"); tls_config_set_protocols(tls_config, http_tls_protocols); break; case HTTP_TLS_VERIFYDEPTH: if (str == NULL) errx(1, "missing depth"); depth = strtonum(str, 0, INT_MAX, &errstr); if (errstr) errx(1, "Cert validation depth is %s", errstr); tls_config_set_verify_depth(tls_config, depth); break; default: errx(1, "Unknown -S suboption `%s'", suboptarg ? suboptarg : ""); } } return tls_config; }
int main(int argc, char *argv[], char *envp[]) { struct tls *tls = NULL; int ch; environ = envp; /* pipes to communicate with the front end */ int in = -1; int out = -1; bool no_name_verification = false; bool no_cert_verification = false; bool no_time_verification = false; char *host = getenv("TCPREMOTEHOST"); struct tls_config *tls_config; if (getenv("TLSC_NO_VERIFICATION") != NULL) { no_name_verification = true; no_cert_verification = true; no_time_verification = true; } if (getenv("TLSC_NO_HOST_VERIFICATION") != NULL) no_name_verification = true; if (getenv("TLSC_NO_CERT_VERIFICATION") != NULL) no_cert_verification = true; if (getenv("TLSC_NO_TIME_VERIFICATION") != NULL) no_time_verification = true; if ((tls_config = tls_config_new()) == NULL) err(EXIT_FAILURE, "tls_config_new"); char *str = NULL; if ((str = getenv("TLSC_CERT_FILE")) != NULL) if (tls_config_set_cert_file(tls_config, str) == -1) err(EXIT_FAILURE, "tls_config_set_cert_file"); if ((str = getenv("TLSC_KEY_FILE")) != NULL) if (tls_config_set_key_file(tls_config, str) == -1) err(EXIT_FAILURE, "tls_config_set_key_file"); if ((str = getenv("TLSC_CA_FILE")) != NULL) if (tls_config_set_ca_file(tls_config, str) == -1) err(EXIT_FAILURE, "tls_config_set_ca_file"); if ((str = getenv("TLSC_CA_PATH")) != NULL) if (tls_config_set_ca_path(tls_config, str) == -1) err(EXIT_FAILURE, "tls_config_set_ca_path"); while ((ch = getopt(argc, argv, "c:k:f:p:n:HCTVh")) != -1) { switch (ch) { case 'c': if (tls_config_set_cert_file(tls_config, optarg) == -1) err(EXIT_FAILURE, "tls_config_set_cert_file"); break; case 'k': if (tls_config_set_key_file(tls_config, optarg) == -1) err(EXIT_FAILURE, "tls_config_set_key_file"); break; case 'f': if (tls_config_set_ca_file(tls_config, optarg) == -1) err(EXIT_FAILURE, "tls_config_set_ca_file"); break; case 'p': if (tls_config_set_ca_path(tls_config, optarg) == -1) err(EXIT_FAILURE, "tls_config_set_ca_path"); break; case 'n': if ((host = strdup(optarg)) == NULL) goto err; break; case 'H': no_name_verification = true; break; case 'C': no_cert_verification = true; break; case 'T': no_time_verification = true; break; case 'V': no_name_verification = true; no_cert_verification = true; no_time_verification = true; break; case 'h': default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc < 1) usage(); /* verification settings */ if (no_cert_verification) tls_config_insecure_noverifycert(tls_config); if (no_name_verification) tls_config_insecure_noverifyname(tls_config); if (no_time_verification) tls_config_insecure_noverifytime(tls_config); /* libtls setup */ if (tls_init() != 0) err(EXIT_FAILURE, "tls_init"); if ((tls = tls_client()) == NULL) err(EXIT_FAILURE, "tls_client"); if (tls_configure(tls, tls_config) != 0) err(EXIT_FAILURE, "tls_configure"); if (tls_connect_fds(tls, READ_FD, WRITE_FD, host) == -1) goto err; if (tls_handshake(tls) == -1) goto err; /* overide PROTO to signal the application layer that the communication * channel is save. */ if (setenv("PROTO", "SSL", 1) == -1) err(EXIT_FAILURE, "setenv"); /* fork front end program */ char *prog = argv[0]; # define PIPE_READ 0 # define PIPE_WRITE 1 int pi[2]; /* input pipe */ int po[2]; /* output pipe */ if (pipe(pi) == -1) err(EXIT_FAILURE, "pipe"); if (pipe(po) == -1) err(EXIT_FAILURE, "pipe"); switch (fork()) { case -1: err(EXIT_FAILURE, "fork"); case 0: /* client program */ /* close non-using ends of pipes */ if (close(pi[PIPE_READ]) == -1) err(EXIT_FAILURE, "close"); if (close(po[PIPE_WRITE]) == -1) err(EXIT_FAILURE, "close"); /* * We have to move one descriptor cause po[] may * overlaps with descriptor 6 and 7. */ int po_read = 0; if ((po_read = dup(po[PIPE_READ])) == -1) err(EXIT_FAILURE, "dup"); if (close(po[PIPE_READ]) < 0) err(EXIT_FAILURE, "close"); if (dup2(pi[PIPE_WRITE], WRITE_FD) < 0) err(EXIT_FAILURE, "dup2"); if (dup2(po_read, READ_FD) < 0) err(EXIT_FAILURE, "dup2"); if (close(pi[PIPE_WRITE]) < 0) err(EXIT_FAILURE, "close"); if (close(po_read) < 0) err(EXIT_FAILURE, "close"); execvpe(prog, argv, environ); err(EXIT_FAILURE, "execvpe"); default: break; /* parent */ } /* close non-using ends of pipes */ if (close(pi[PIPE_WRITE]) == -1) err(EXIT_FAILURE, "close"); if (close(po[PIPE_READ]) == -1) err(EXIT_FAILURE, "close"); in = pi[PIPE_READ]; out = po[PIPE_WRITE]; /* communication loop */ for (;;) { int ret; char buf[BUFSIZ]; ssize_t sn = 0; fd_set readfds; FD_ZERO(&readfds); FD_SET(in, &readfds); FD_SET(READ_FD, &readfds); int max_fd = MAX(in, READ_FD); ret = select(max_fd+1, &readfds, NULL, NULL, NULL); if (ret == -1) err(EXIT_FAILURE, "select"); if (FD_ISSET(READ_FD, &readfds)) { do { again: sn = tls_read(tls, buf, sizeof buf); if (sn == TLS_WANT_POLLIN || sn == TLS_WANT_POLLOUT) goto again; if (sn == -1) goto err; if (sn == 0) return EXIT_SUCCESS; if (write(out, buf, sn) == -1) err(EXIT_FAILURE, "write()"); } while (sn == sizeof buf); } else if (FD_ISSET(in, &readfds)) { if ((sn = read(in, buf, sizeof buf)) == -1) err(EXIT_FAILURE, "read()"); if (sn == 0) goto out; if ((sn = tls_write(tls, buf, sn)) == -1) goto out; } } out: tls_close(tls); return EXIT_SUCCESS; err: errx(EXIT_FAILURE, "tls_error: %s", tls_error(tls)); }
int main(int argc, char *argv[]) { struct tls *tls = NULL; struct tls *cctx = NULL; struct tls_config *tls_config = NULL; char buf[BUFSIZ]; int ch; int e; if ((tls_config = tls_config_new()) == NULL) err(EXIT_FAILURE, "tls_config_new"); while ((ch = getopt(argc, argv, "Cc:k:p:f:")) != -1) { switch (ch) { case 'C': tls_config_verify_client(tls_config); break; case 'c': if (tls_config_set_cert_file(tls_config, optarg) == -1) err(EXIT_FAILURE, "tls_config_set_cert_file"); break; case 'k': if (tls_config_set_key_file(tls_config, optarg) == -1) err(EXIT_FAILURE, "tls_config_set_key_file"); break; case 'f': if (tls_config_set_ca_file(tls_config, optarg) == -1) err(EXIT_FAILURE, "tls_config_set_ca_file"); break; case 'p': if (tls_config_set_ca_path(tls_config, optarg) == -1) err(EXIT_FAILURE, "tls_config_set_ca_path"); break; default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; /* prepare libtls */ if (tls_init() == -1) err(EXIT_FAILURE, "tls_init"); if ((tls = tls_server()) == NULL) err(EXIT_FAILURE, "tls_server"); if (tls_configure(tls, tls_config) == -1) goto err; if (tls_accept_fds(tls, &cctx, STDIN_FILENO, STDOUT_FILENO) == -1) goto err; if (tls_handshake(cctx) == -1) goto err; if (setenv("PROTO", "SSL", 1) == -1) err(EXIT_FAILURE, "setenv"); /* fork front end program */ char *prog = argv[0]; # define PIPE_READ 0 # define PIPE_WRITE 1 int pi[2]; /* input pipe */ int po[2]; /* output pipe */ if (pipe(pi) == -1) err(EXIT_FAILURE, "pipe"); if (pipe(po) == -1) err(EXIT_FAILURE, "pipe"); switch (fork()) { case -1: err(EXIT_FAILURE, "fork"); case 0: /* client program */ /* close non-using ends of pipes */ if (close(pi[PIPE_READ]) == -1) err(EXIT_FAILURE, "close"); if (close(po[PIPE_WRITE]) == -1) err(EXIT_FAILURE, "close"); /* move pipe end to ucspi defined fd numbers */ if (dup2(po[PIPE_READ], READ_FD) == -1) err(EXIT_FAILURE, "dup2"); if (dup2(pi[PIPE_WRITE], WRITE_FD) == -1) err(EXIT_FAILURE, "dup2"); if (close(po[PIPE_READ]) == -1) err(EXIT_FAILURE, "close"); if (close(pi[PIPE_WRITE]) == -1) err(EXIT_FAILURE, "close"); execv(prog, argv); err(EXIT_FAILURE, "execve"); default: break; /* parent */ } /* close non-using ends of pipes */ if (close(pi[PIPE_WRITE]) == -1) err(EXIT_FAILURE, "close"); if (close(po[PIPE_READ]) == -1) err(EXIT_FAILURE, "close"); int in = pi[PIPE_READ]; int out = po[PIPE_WRITE]; /* communication loop */ for (;;) { int ret; char buf[BUFSIZ]; ssize_t sn = 0; fd_set readfds; FD_ZERO(&readfds); FD_SET(in, &readfds); FD_SET(READ_FD, &readfds); int max_fd = MAX(in, READ_FD); ret = select(max_fd+1, &readfds, NULL, NULL, NULL); if (ret == -1) err(EXIT_FAILURE, "select"); if (FD_ISSET(READ_FD, &readfds)) { do { again: sn = tls_read(cctx, buf, sizeof buf); if (sn == TLS_WANT_POLLIN || sn == TLS_WANT_POLLOUT) goto again; if (sn == -1) goto err; if (sn == 0) return EXIT_SUCCESS; if (write(out, buf, sn) == -1) err(EXIT_FAILURE, "write()"); } while (sn == sizeof buf); } else if (FD_ISSET(in, &readfds)) { if ((sn = read(in, buf, sizeof buf)) == -1) err(EXIT_FAILURE, "read()"); if (sn == 0) /* EOF from inside */ goto out; /* XXX: unable to detect disconnect here */ if (tls_write(cctx, buf, sn) == -1) goto err; } } out: tls_close(cctx); return EXIT_SUCCESS; err: while ((e = ERR_get_error())) { ERR_error_string(e, buf); fprintf(stderr, " %s\n", buf); } errx(EXIT_FAILURE, "tls_error: %s", tls_error(cctx)); errx(EXIT_FAILURE, "tls_error: %s", tls_error(tls)); }