END_TEST START_TEST(cache_fkcrt_04) { X509 *c1, *c2; c1 = ssl_x509_load(TESTCERT); fail_unless(!!c1, "loading certificate failed"); fail_unless(c1->references == 1, "refcount != 1"); cachemgr_fkcrt_set(c1, c1); fail_unless(c1->references == 2, "refcount != 2"); c2 = cachemgr_fkcrt_get(c1); fail_unless(c1->references == 3, "refcount != 3"); cachemgr_fkcrt_set(c1, c1); fail_unless(c1->references == 3, "refcount != 3"); cachemgr_fkcrt_del(c1); fail_unless(c1->references == 2, "refcount != 2"); cachemgr_fkcrt_set(c1, c1); fail_unless(c1->references == 3, "refcount != 3"); X509_free(c1); fail_unless(c1->references == 2, "refcount != 2"); cachemgr_fini(); fail_unless(c1->references == 1, "refcount != 1"); X509_free(c2); /* deliberate access of free'd X509* */ fail_unless(c1->references == 0, "refcount != 0"); fail_unless(cachemgr_preinit() != -1, "reinit"); }
END_TEST START_TEST(ssl_x509_names_01) { X509 *c; char **names, **p; c = ssl_x509_load(TESTCERT); fail_unless(!!c, "loading certificate failed"); names = ssl_x509_names(c); fail_unless(!!names, "parsing names failed"); fail_unless(!!names[0], "first name"); fail_unless(!strcmp(names[0], "daniel.roe.ch"), "first name"); fail_unless(!!names[1], "second name"); fail_unless(!strcmp(names[1], "daniel.roe.ch"), "second name"); fail_unless(!!names[2], "third name"); fail_unless(!strcmp(names[2], "www.roe.ch"), "third name"); fail_unless(!!names[3], "fourth name"); fail_unless(!strcmp(names[3], "*.roe.ch"), "fourth name"); fail_unless(!names[4], "too many names"); p = names; while (*p) free(*p++); free(names); X509_free(c); }
END_TEST START_TEST(ssl_key_identifier_sha1_01) { X509 *c; EVP_PKEY *k; unsigned char keyid[SSL_KEY_IDSZ]; c = ssl_x509_load(TESTCERT); fail_unless(!!c, "loading certificate failed"); k = ssl_key_load(TESTKEY); fail_unless(!!k, "loading key failed"); fail_unless(ssl_key_identifier_sha1(k, keyid) == 0, "ssl_key_identifier_sha1() failed"); int loc = X509_get_ext_by_NID(c, NID_subject_key_identifier, -1); X509_EXTENSION *ext = X509_get_ext(c, loc); fail_unless(!!ext, "loading ext failed"); ASN1_STRING *value = X509_EXTENSION_get_data(ext); fail_unless(ASN1_STRING_length(value) - 2 == SSL_KEY_IDSZ, "extension length mismatch"); fail_unless(!memcmp(ASN1_STRING_get0_data(value) + 2, keyid, SSL_KEY_IDSZ), "key id mismatch"); EVP_PKEY_free(k); X509_free(c); }
END_TEST START_TEST(cache_fkcrt_02) { X509 *c1, *c2; c1 = ssl_x509_load(TESTCERT); fail_unless(!!c1, "loading certificate failed"); c2 = cachemgr_fkcrt_get(c1); fail_unless(c2 == NULL, "certificate was already in empty cache"); X509_free(c1); }
END_TEST START_TEST(ssl_x509_ocsps_02) { X509 *c; char **ocsps; c = ssl_x509_load(TESTCERT2); fail_unless(!!c, "loading certificate failed"); ocsps = ssl_x509_ocsps(c); fail_unless(!ocsps, "unexpected OCSP extensions"); X509_free(c); }
END_TEST START_TEST(cache_fkcrt_03) { X509 *c1, *c2; c1 = ssl_x509_load(TESTCERT); fail_unless(!!c1, "loading certificate failed"); cachemgr_fkcrt_set(c1, c1); cachemgr_fkcrt_del(c1); c2 = cachemgr_fkcrt_get(c1); fail_unless(c2 == NULL, "cache returned deleted certificate"); X509_free(c1); }
END_TEST START_TEST(ssl_x509_names_to_str_02) { X509 *c; char *names; c = ssl_x509_load(TESTCERT2); fail_unless(!!c, "loading certificate failed"); names = ssl_x509_names_to_str(c); fail_unless(!!names, "no string"); fail_unless(!strcmp(names, "SSLsplit Root CA"), "wrong name string"); X509_free(c); }
END_TEST START_TEST(ssl_x509_subject_01) { X509 *c; char *subject; c = ssl_x509_load(TESTCERT); fail_unless(!!c, "loading certificate failed"); subject = ssl_x509_subject(c); fail_unless(!!subject, "no string"); fail_unless(!strcmp(subject, "/C=CH/O=SSLsplit Test Certificate/" "CN=daniel.roe.ch"), "wrong subject string"); X509_free(c); }
END_TEST START_TEST(ssl_x509_names_to_str_01) { X509 *c; char *names; c = ssl_x509_load(TESTCERT); fail_unless(!!c, "loading certificate failed"); names = ssl_x509_names_to_str(c); fail_unless(!!names, "no string"); fail_unless(!strcmp(names, "daniel.roe.ch/daniel.roe.ch/www.roe.ch/*.roe.ch"), "wrong name string"); X509_free(c); }
END_TEST START_TEST(ssl_x509_refcount_inc_01) { X509 *crt; crt = ssl_x509_load(TESTCERT); fail_unless(!!crt, "loading certificate failed"); ssl_x509_refcount_inc(crt); ssl_x509_refcount_inc(crt); ssl_x509_refcount_inc(crt); X509_free(crt); /* these must not crash */ X509_free(crt); X509_free(crt); X509_free(crt); }
END_TEST START_TEST(ssl_x509_ocsps_01) { X509 *c; char **ocsps, **p; c = ssl_x509_load(TESTCERT); fail_unless(!!c, "loading certificate failed"); ocsps = ssl_x509_ocsps(c); fail_unless(!!ocsps, "parsing OCSP extensions failed"); fail_unless(!!ocsps[0], "first OCSP"); fail_unless(!strcmp(ocsps[0], "http://daniel.roe.ch/test/ocsp"), "first OCSP"); fail_unless(!ocsps[1], "too many OCSPs"); p = ocsps; while (*p) free(*p++); free(ocsps); X509_free(c); }
END_TEST START_TEST(ssl_x509_subject_cn_01) { X509 *c; char *cn; size_t sz; size_t expsz = strlen("daniel.roe.ch") + 1; c = ssl_x509_load(TESTCERT); fail_unless(!!c, "loading certificate failed"); cn = ssl_x509_subject_cn(c, &sz); fail_unless(!!cn, "no string"); fail_unless(sz >= expsz, "subject CN size too small"); fail_unless(!strcmp(cn, "daniel.roe.ch"), "wrong subject CN string"); #if 0 for (unsigned int i = expsz; i < sz; i++) { fail_unless(cn[i] == '\0', "extra byte != 0"); } #endif X509_free(c); }
/* * Main entry point. */ int main(int argc, char *argv[]) { const char *argv0; int ch; opts_t *opts; char *natengine; int pidfd = -1; int rv = EXIT_FAILURE; argv0 = argv[0]; opts = opts_new(); natengine = strdup(nat_getdefaultname()); while ((ch = getopt(argc, argv, OPT_g OPT_G OPT_Z "k:c:C:K:t:OPs:e:Eu:j:p:l:L:S:dDVh")) != -1) { switch (ch) { case 'c': if (opts->cacrt) X509_free(opts->cacrt); opts->cacrt = ssl_x509_load(optarg); if (!opts->cacrt) { fprintf(stderr, "%s: error loading CA " "cert from '%s':\n", argv0, optarg); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); } else { ERR_print_errors_fp(stderr); } exit(EXIT_FAILURE); } ssl_x509_refcount_inc(opts->cacrt); sk_X509_insert(opts->chain, opts->cacrt, 0); if (!opts->cakey) { opts->cakey = ssl_key_load(optarg); } #ifndef OPENSSL_NO_DH if (!opts->dh) { opts->dh = ssl_dh_load(optarg); } #endif /* !OPENSSL_NO_DH */ break; case 'k': if (opts->cakey) EVP_PKEY_free(opts->cakey); opts->cakey = ssl_key_load(optarg); if (!opts->cakey) { fprintf(stderr, "%s: error loading CA " "key from '%s':\n", argv0, optarg); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); } else { ERR_print_errors_fp(stderr); } exit(EXIT_FAILURE); } if (!opts->cacrt) { opts->cacrt = ssl_x509_load(optarg); if (opts->cacrt) { ssl_x509_refcount_inc( opts->cacrt); sk_X509_insert(opts->chain, opts->cacrt, 0); } } #ifndef OPENSSL_NO_DH if (!opts->dh) { opts->dh = ssl_dh_load(optarg); } #endif /* !OPENSSL_NO_DH */ break; case 'C': if (ssl_x509chain_load(NULL, &opts->chain, optarg) == -1) { fprintf(stderr, "%s: error loading " "chain from '%s':\n", argv0, optarg); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); } else { ERR_print_errors_fp(stderr); } exit(EXIT_FAILURE); } break; case 'K': if (opts->key) EVP_PKEY_free(opts->key); opts->key = ssl_key_load(optarg); if (!opts->key) { fprintf(stderr, "%s: error loading lea" "f key from '%s':\n", argv0, optarg); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); } else { ERR_print_errors_fp(stderr); } exit(EXIT_FAILURE); } #ifndef OPENSSL_NO_DH if (!opts->dh) { opts->dh = ssl_dh_load(optarg); } #endif /* !OPENSSL_NO_DH */ break; case 't': if (!sys_isdir(optarg)) { fprintf(stderr, "%s: '%s' is not a " "directory\n", argv0, optarg); exit(EXIT_FAILURE); } if (opts->tgcrtdir) free(opts->tgcrtdir); opts->tgcrtdir = strdup(optarg); break; case 'O': opts->deny_ocsp = 1; break; case 'P': opts->passthrough = 1; break; #ifndef OPENSSL_NO_DH case 'g': if (opts->dh) DH_free(opts->dh); opts->dh = ssl_dh_load(optarg); if (!opts->dh) { fprintf(stderr, "%s: error loading DH " "params from '%s':\n", argv0, optarg); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); } else { ERR_print_errors_fp(stderr); } exit(EXIT_FAILURE); } break; #endif /* !OPENSSL_NO_DH */ #ifndef OPENSSL_NO_ECDH case 'G': { EC_KEY *ec; if (opts->ecdhcurve) free(opts->ecdhcurve); if (!(ec = ssl_ec_by_name(optarg))) { fprintf(stderr, "%s: unknown curve " "'%s'\n", argv0, optarg); exit(EXIT_FAILURE); } EC_KEY_free(ec); opts->ecdhcurve = strdup(optarg); break; } #endif /* !OPENSSL_NO_ECDH */ #ifdef SSL_OP_NO_COMPRESSION case 'Z': opts->sslcomp = 0; break; #endif /* SSL_OP_NO_COMPRESSION */ case 's': if (opts->ciphers) free(opts->ciphers); opts->ciphers = strdup(optarg); break; case 'e': free(natengine); natengine = strdup(optarg); break; case 'E': nat_list_engines(); exit(EXIT_SUCCESS); break; case 'u': if (opts->dropuser) free(opts->dropuser); opts->dropuser = strdup(optarg); break; case 'p': if (opts->pidfile) free(opts->pidfile); opts->pidfile = strdup(optarg); break; case 'j': if (opts->jaildir) free(opts->jaildir); opts->jaildir = strdup(optarg); break; case 'l': if (opts->connectlog) free(opts->connectlog); opts->connectlog = strdup(optarg); break; case 'L': if (opts->contentlog) free(opts->contentlog); opts->contentlog = strdup(optarg); opts->contentlogdir = 0; break; case 'S': if (opts->contentlog) free(opts->contentlog); opts->contentlog = strdup(optarg); opts->contentlogdir = 1; break; case 'd': opts->detach = 1; break; case 'D': log_dbg_mode(LOG_DBG_MODE_ERRLOG); opts->debug = 1; break; case 'V': main_version(); exit(EXIT_SUCCESS); case 'h': main_usage(); exit(EXIT_SUCCESS); case '?': exit(EXIT_FAILURE); default: main_usage(); exit(EXIT_FAILURE); } } argc -= optind; argv += optind; opts->spec = proxyspec_parse(&argc, &argv, natengine); /* usage checks */ if (opts->detach && OPTS_DEBUG(opts)) { fprintf(stderr, "%s: -d and -D are mutually exclusive.\n", argv0); exit(EXIT_FAILURE); } if (!opts->spec) { fprintf(stderr, "%s: no proxyspec specified.\n", argv0); exit(EXIT_FAILURE); } for (proxyspec_t *spec = opts->spec; spec; spec = spec->next) { if (spec->connect_addrlen || spec->sni_port) continue; if (!spec->natengine) { fprintf(stderr, "%s: no supported NAT engines " "on this platform.\n" "Only static addr and SNI proxyspecs " "supported.\n", argv0); exit(EXIT_FAILURE); } if (spec->listen_addr.ss_family == AF_INET6 && !nat_ipv6ready(spec->natengine)) { fprintf(stderr, "%s: IPv6 not supported by '%s'\n", argv0, spec->natengine); exit(EXIT_FAILURE); } spec->natlookup = nat_getlookupcb(spec->natengine); spec->natsocket = nat_getsocketcb(spec->natengine); } if (opts_has_ssl_spec(opts)) { if ((opts->cacrt || !opts->tgcrtdir) && !opts->cakey) { fprintf(stderr, "%s: no CA key specified (-k).\n", argv0); exit(EXIT_FAILURE); } if (opts->cakey && !opts->cacrt) { fprintf(stderr, "%s: no CA cert specified (-c).\n", argv0); exit(EXIT_FAILURE); } if (opts->cakey && opts->cacrt && (X509_check_private_key(opts->cacrt, opts->cakey) != 1)) { fprintf(stderr, "%s: CA cert does not match key.\n", argv0); ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } } /* prevent multiple instances running */ if (opts->pidfile) { pidfd = sys_pidf_open(opts->pidfile); if (pidfd == -1) { fprintf(stderr, "%s: cannot open PID file '%s' " "- process already running?\n", argv0, opts->pidfile); exit(EXIT_FAILURE); } } /* dynamic defaults */ if (!opts->ciphers) { opts->ciphers = strdup("ALL:-aNULL"); if (!opts->ciphers) { fprintf(stderr, "%s: out of memory.\n", argv0); exit(EXIT_FAILURE); } } if (!opts->jaildir && (geteuid() == 0) && !opts->contentlogdir) { opts->jaildir = strdup("/var/empty"); } if (!opts->dropuser && !geteuid() && !getuid() && !opts->contentlogdir) { opts->dropuser = strdup("nobody"); } if (opts_has_ssl_spec(opts) && !opts->key) { opts->key = ssl_key_genrsa(1024); if (!opts->key) { fprintf(stderr, "%s: error generating RSA key:\n", argv0); ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } if (OPTS_DEBUG(opts)) { log_dbg_printf("Generated RSA key for leaf certs.\n"); } } /* debugging */ if (OPTS_DEBUG(opts)) { main_version(); log_dbg_printf("proxyspecs:\n"); for (proxyspec_t *spec = opts->spec; spec; spec = spec->next) { char *lbuf, *cbuf = NULL; lbuf = sys_sockaddr_str((struct sockaddr *) &spec->listen_addr, spec->listen_addrlen); if (spec->connect_addrlen) { cbuf = sys_sockaddr_str((struct sockaddr *) &spec->connect_addr, spec->connect_addrlen); } if (spec->sni_port) { asprintf(&cbuf, "sni %i", spec->sni_port); } log_dbg_printf("- %s %s %s %s\n", lbuf, (spec->ssl ? "ssl" : "tcp"), (spec->http ? "http" : "plain"), (spec->natengine ? spec->natengine : cbuf)); if (lbuf) free(lbuf); if (cbuf) free(cbuf); } if (opts->cacrt) { char *subj = ssl_x509_subject(opts->cacrt); log_dbg_printf("Loaded CA: '%s'\n", subj); free(subj); #ifdef DEBUG_CERTIFICATE log_dbg_print_free(ssl_x509_to_str(opts->cacrt)); log_dbg_print_free(ssl_x509_to_pem(opts->cacrt)); #endif /* DEBUG_CERTIFICATE */ } else { log_dbg_printf("No CA loaded.\n"); } } /* * Initialize as much as possible before daemon() in order to be * able to provide direct feedback to the user when failing. */ if (cachemgr_preinit() == -1) { fprintf(stderr, "%s: failed to preinit cachemgr.\n", argv0); exit(EXIT_FAILURE); } if (log_preinit(opts) == -1) { fprintf(stderr, "%s: failed to preinit logging.\n", argv0); exit(EXIT_FAILURE); } if (nat_preinit() == -1) { fprintf(stderr, "%s: failed to preinit NAT lookup.\n", argv0); exit(EXIT_FAILURE); } /* Bind listeners before dropping privileges */ proxy_ctx_t *proxy = proxy_new(opts); if (!proxy) { fprintf(stderr, "%s: failed to initialize proxy.\n", argv0); exit(EXIT_FAILURE); } /* Drop privs, chroot, detach from TTY */ if (sys_privdrop(opts->dropuser, opts->jaildir) == -1) { fprintf(stderr, "%s: failed to drop privileges: %s\n", argv0, strerror(errno)); exit(EXIT_FAILURE); } if (opts->detach) { if (OPTS_DEBUG(opts)) { log_dbg_printf("Detaching from TTY, see syslog for " "errors after this point\n"); } if (daemon(1, 0) == -1) { fprintf(stderr, "%s: failed to detach from TTY: %s\n", argv0, strerror(errno)); exit(EXIT_FAILURE); } log_err_mode(LOG_ERR_MODE_SYSLOG); ssl_reinit(); } /* Post-privdrop/chroot/detach initialization, thread spawning */ if (log_init(opts) == -1) { fprintf(stderr, "%s: failed to init log facility.\n", argv0); goto out_log_failed; } if (opts->pidfile && (sys_pidf_write(pidfd) == -1)) { log_err_printf("Failed to write PID to PID file '%s': %s\n", opts->pidfile, strerror(errno)); goto out_pidwrite_failed; } if (cachemgr_init() == -1) { log_err_printf("Failed to init cache manager.\n"); goto out_cachemgr_failed; } if (nat_init() == -1) { log_err_printf("Failed to init NAT state table lookup.\n"); goto out_nat_failed; } if (opts->tgcrtdir) { sys_dir_eachfile(opts->tgcrtdir, main_loadtgcrt, opts); } rv = EXIT_SUCCESS; proxy_run(proxy); proxy_free(proxy); nat_fini(); out_nat_failed: cachemgr_fini(); out_cachemgr_failed: if (opts->pidfile) { sys_pidf_close(pidfd, opts->pidfile); } out_pidwrite_failed: log_fini(); out_log_failed: opts_free(opts); ssl_fini(); return rv; }
int load_config() { string tmp; vector<string> splited; int tmpSize, tmpPort; if(configFilePath[0] == '\0') { strcpy(configFilePath, DEFAULT_CONFIG_FILE_PATH); } if(!options.read_options_file(configFilePath)) { log_message(ERROR_LOG, "Couldn't read configuration file %s.", configFilePath); return 1; } tmp = options["logLevel"]; config.logLevel = atoi(tmp.c_str()); tmp = options["maxClients"]; config.maxClients = atoi(tmp.c_str()); config.logFilePath = options["logFilePath"]; tmp = options["bindPort"]; config.bindPort = atoi(tmp.c_str()); tmp = options["sslPorts"]; splited = split(tmp, ','); tmpSize = splited.size(); for(int i=0; i<tmpSize; i++) { tmpPort = atoi(splited.at(i).c_str()); if((tmpPort >= 0) && (tmpPort <= 65535)) { config.sslPorts.push_back(tmpPort); } } /* load certificate */ tmp = options["cacrt"]; config.cacrt = ssl_x509_load(tmp.c_str()); if(!config.cacrt) { log_message(ERROR_LOG, "Could not loading ca crt %s.", tmp.c_str()); return 1; } config.chain = sk_X509_new_null(); ssl_x509_refcount_inc(config.cacrt); sk_X509_insert(config.chain, config.cacrt, 0); tmp = options["cakey"]; config.cakey = ssl_key_load(tmp.c_str()); if (!config.cakey) { log_message(ERROR_LOG, "Could not loading ca key %s.", tmp.c_str()); return 1; } tmp = options["leafkey"]; config.key = ssl_key_load(tmp.c_str()); if (!config.key) { log_message(ERROR_LOG, "Could not loading leaf key %s.", tmp.c_str()); return 1; } config.ciphers = strdup("ALL:-aNULL"); if (!config.ciphers) { log_message(ERROR_LOG, "Could not malloc ciphers."); return 1; } tmp = options["contentLogDir"]; config.contentLogDir = strdup(tmp.c_str()); if (!config.contentLogDir) { log_message(ERROR_LOG, "Could not malloc contentLogDir."); return 1; } if (!sys_isdir(config.contentLogDir)) { log_message(ERROR_LOG, "%s is not a directory.", config.contentLogDir); return 1; } return 0; }