int tls_server_certificate_verify(int preverify_ok, X509_STORE_CTX *pX509CTX){ // preverify_ok // 0 ==> Fail // 1 ==> Pass int verification_return = 0; //last certificate(depth = 0) is the one provided by the Server if((X509_STORE_CTX_get_error_depth(pX509CTX) == 0) && (preverify_ok == 1)){ X509 *pX509Cert; HostnameValidationResult result; pX509Cert = X509_STORE_CTX_get_current_cert(pX509CTX); result = validate_hostname(pDestinationURL, pX509Cert); if(MatchFound == result){ verification_return = 1; } } else{ verification_return = preverify_ok; } return verification_return; }
/* See http://archives.seul.org/libevent/users/Jan-2013/msg00039.html */ static int cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg) { char cert_str[256]; const char *host = (const char *) arg; const char *res_str = "X509_verify_cert failed"; HostnameValidationResult res = Error; /* This is the function that OpenSSL would call if we hadn't called * SSL_CTX_set_cert_verify_callback(). Therefore, we are "wrapping" * the default functionality, rather than replacing it. */ int ok_so_far = 0; X509 *server_cert = NULL; if (ignore_cert) { return 1; } ok_so_far = X509_verify_cert(x509_ctx); server_cert = X509_STORE_CTX_get_current_cert(x509_ctx); if (ok_so_far) { res = validate_hostname(host, server_cert); switch (res) { case MatchFound: res_str = "MatchFound"; break; case MatchNotFound: res_str = "MatchNotFound"; break; case NoSANPresent: res_str = "NoSANPresent"; break; case MalformedCertificate: res_str = "MalformedCertificate"; break; case Error: res_str = "Error"; break; default: res_str = "WTF!"; break; } } X509_NAME_oneline(X509_get_subject_name (server_cert), cert_str, sizeof (cert_str)); if (res == MatchFound) { printf("https server '%s' has this certificate, " "which looks good to me:\n%s\n", host, cert_str); return 1; } else { printf("Got '%s' for hostname '%s' and certificate:\n%s\n", res_str, host, cert_str); return 0; } }
static void remote_send_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w; remote_t *remote = remote_send_ctx->remote; server_t *server = remote->server; ev_timer_stop(EV_A_ & remote_send_ctx->watcher); if (!remote_send_ctx->connected) { int r = 0; if (remote->addr == NULL) { struct sockaddr_storage addr; memset(&addr, 0, sizeof(struct sockaddr_storage)); socklen_t len = sizeof addr; r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); } if (r == 0) { remote_send_ctx->connected = 1; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_stop(EV_A_ & server->recv_ctx->io); ev_io_start(EV_A_ & remote->recv_ctx->io); ev_timer_start(EV_A_ & remote->recv_ctx->watcher); // send destaddr buffer_t ss_addr_to_send; buffer_t *abuf = &ss_addr_to_send; balloc(abuf, BUF_SIZE); if (server->hostname_len > 0 && validate_hostname(server->hostname, server->hostname_len)) { // HTTP/SNI uint16_t port; if (AF_INET6 == server->destaddr.ss_family) { // IPv6 port = (((struct sockaddr_in6 *)&(server->destaddr))->sin6_port); } else { // IPv4 port = (((struct sockaddr_in *)&(server->destaddr))->sin_port); } abuf->data[abuf->len++] = 3; // Type 3 is hostname abuf->data[abuf->len++] = server->hostname_len; memcpy(abuf->data + abuf->len, server->hostname, server->hostname_len); abuf->len += server->hostname_len; memcpy(abuf->data + abuf->len, &port, 2); } else if (AF_INET6 == server->destaddr.ss_family) { // IPv6 abuf->data[abuf->len++] = 4; // Type 4 is IPv6 address size_t in6_addr_len = sizeof(struct in6_addr); memcpy(abuf->data + abuf->len, &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_addr), in6_addr_len); abuf->len += in6_addr_len; memcpy(abuf->data + abuf->len, &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_port), 2); } else { // IPv4 abuf->data[abuf->len++] = 1; // Type 1 is IPv4 address size_t in_addr_len = sizeof(struct in_addr); memcpy(abuf->data + abuf->len, &((struct sockaddr_in *)&(server->destaddr))->sin_addr, in_addr_len); abuf->len += in_addr_len; memcpy(abuf->data + abuf->len, &((struct sockaddr_in *)&(server->destaddr))->sin_port, 2); } abuf->len += 2; int err = crypto->encrypt(abuf, server->e_ctx, BUF_SIZE); if (err) { LOGE("invalid password or cipher"); bfree(abuf); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } err = crypto->encrypt(remote->buf, server->e_ctx, BUF_SIZE); if (err) { LOGE("invalid password or cipher"); bfree(abuf); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } bprepend(remote->buf, abuf, BUF_SIZE); bfree(abuf); } else { ERROR("getpeername"); // not connected close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } if (remote->buf->len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s; if (remote->addr != NULL) { s = sendto(remote->fd, remote->buf->data + remote->buf->idx, remote->buf->len, MSG_FASTOPEN, remote->addr, get_sockaddr_len(remote->addr)); if (s == -1 && (errno == EOPNOTSUPP || errno == EPROTONOSUPPORT || errno == ENOPROTOOPT)) { fast_open = 0; LOGE("fast open is not supported on this platform"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } remote->addr = NULL; if (s == -1) { if (errno == CONNECT_IN_PROGRESS || errno == EAGAIN || errno == EWOULDBLOCK) { ev_io_start(EV_A_ & remote_send_ctx->io); ev_timer_start(EV_A_ & remote_send_ctx->watcher); } else { ERROR("connect"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } } else { s = send(remote->fd, remote->buf->data + remote->buf->idx, remote->buf->len, 0); } if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("send"); // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < remote->buf->len) { // partly sent, move memory, wait for the next time to send remote->buf->len -= s; remote->buf->idx += s; ev_io_start(EV_A_ & remote_send_ctx->io); return; } else { // all sent out, wait for reading remote->buf->len = 0; remote->buf->idx = 0; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_start(EV_A_ & server->recv_ctx->io); } } }
static void proceed_handshake(h2o_socket_t *sock, const char *err) { h2o_iovec_t first_input = {NULL}; int ret; sock->_cb.write = NULL; if (err != NULL) { goto Complete; } if (sock->ssl->handshake.server.async_resumption.state == ASYNC_RESUMPTION_STATE_RECORD) { if (sock->ssl->input.encrypted->size <= 1024) { /* retain a copy of input if performing async resumption */ first_input = h2o_iovec_init(alloca(sock->ssl->input.encrypted->size), sock->ssl->input.encrypted->size); memcpy(first_input.base, sock->ssl->input.encrypted->bytes, first_input.len); } else { sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE; } } Redo: if (SSL_is_server(sock->ssl->ssl)) { ret = SSL_accept(sock->ssl->ssl); } else { ret = SSL_connect(sock->ssl->ssl); } switch (sock->ssl->handshake.server.async_resumption.state) { case ASYNC_RESUMPTION_STATE_RECORD: /* async resumption has not been triggered; proceed the state to complete */ sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE; break; case ASYNC_RESUMPTION_STATE_REQUEST_SENT: { /* sent async request, reset the ssl state, and wait for async response */ assert(ret < 0); SSL_CTX *ssl_ctx = SSL_get_SSL_CTX(sock->ssl->ssl); SSL_free(sock->ssl->ssl); create_ssl(sock, ssl_ctx); clear_output_buffer(sock->ssl); h2o_buffer_consume(&sock->ssl->input.encrypted, sock->ssl->input.encrypted->size); h2o_buffer_reserve(&sock->ssl->input.encrypted, first_input.len); memcpy(sock->ssl->input.encrypted->bytes, first_input.base, first_input.len); sock->ssl->input.encrypted->size = first_input.len; h2o_socket_read_stop(sock); return; } default: break; } if (ret == 0 || (ret < 0 && SSL_get_error(sock->ssl->ssl, ret) != SSL_ERROR_WANT_READ)) { /* failed */ long verify_result = SSL_get_verify_result(sock->ssl->ssl); if (verify_result != X509_V_OK) { err = X509_verify_cert_error_string(verify_result); } else { err = "ssl handshake failure"; } goto Complete; } if (sock->ssl->output.bufs.size != 0) { h2o_socket_read_stop(sock); flush_pending_ssl(sock, ret == 1 ? on_handshake_complete : proceed_handshake); } else { if (ret == 1) { if (!SSL_is_server(sock->ssl->ssl)) { X509 *cert = SSL_get_peer_certificate(sock->ssl->ssl); if (cert != NULL) { switch (validate_hostname(sock->ssl->handshake.client.server_name, cert)) { case MatchFound: /* ok */ break; case MatchNotFound: err = h2o_socket_error_ssl_cert_name_mismatch; break; default: err = h2o_socket_error_ssl_cert_invalid; break; } X509_free(cert); } else { err = h2o_socket_error_ssl_no_cert; } } goto Complete; } if (sock->ssl->input.encrypted->size != 0) goto Redo; h2o_socket_read_start(sock, proceed_handshake); } return; Complete: h2o_socket_read_stop(sock); on_handshake_complete(sock, err); }
int main(int argc, char *argv[]) { BIO *sbio; SSL_CTX *ssl_ctx; SSL *ssl; X509 *server_cert; // Initialize OpenSSL OpenSSL_add_all_algorithms(); SSL_library_init(); SSL_load_error_strings(); // Check OpenSSL PRNG if(RAND_status() != 1) { fprintf(stderr, "OpenSSL PRNG not seeded with enough data."); goto error_1; } ssl_ctx = SSL_CTX_new(TLSv1_client_method()); // Enable certificate validation SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); // Configure the CA trust store to be used if (SSL_CTX_load_verify_locations(ssl_ctx, TRUSTED_CA_PATHNAME, NULL) != 1) { fprintf(stderr, "Couldn't load certificate trust store.\n"); goto error_2; } // Only support secure cipher suites if (SSL_CTX_set_cipher_list(ssl_ctx, SECURE_CIPHER_LIST) != 1) goto error_2; // Create the SSL connection sbio = BIO_new_ssl_connect(ssl_ctx); BIO_get_ssl(sbio, &ssl); if(!ssl) { fprintf(stderr, "Can't locate SSL pointer\n"); goto error_3; } // Do the SSL handshake BIO_set_conn_hostname(sbio, TARGET_SERVER); if(SSL_do_handshake(ssl) <= 0) { // SSL Handshake failed long verify_err = SSL_get_verify_result(ssl); if (verify_err != X509_V_OK) { // It failed because the certificate chain validation failed fprintf(stderr, "Certificate chain validation failed: %s\n", X509_verify_cert_error_string(verify_err)); } else { // It failed for another reason ERR_print_errors_fp(stderr); } goto error_3; } // Recover the server's certificate server_cert = SSL_get_peer_certificate(ssl); if (server_cert == NULL) { // The handshake was successful although the server did not provide a certificate // Most likely using an insecure anonymous cipher suite... get out! goto error_4; } // Validate the hostname if (validate_hostname(TARGET_HOST, server_cert) != MatchFound) { fprintf(stderr, "Hostname validation failed.\n"); goto error_5; } // Hostname validation succeeded; we can start sending data send_http_get_and_print(sbio); error_5: X509_free(server_cert); error_4: BIO_ssl_shutdown(sbio); error_3: BIO_free_all(sbio); error_2: SSL_CTX_free(ssl_ctx); error_1: // OpenSSL cleanup EVP_cleanup(); ERR_free_strings(); return 0; }
static lcb_error_t setup_bootstrap_hosts(lcb_t ret, const char *host) { const char *ptr = host; lcb_size_t num = 0; int ii; while ((ptr = strchr(ptr, ';')) != NULL) { ++ptr; ++num; } /* Let's allocate the buffer space and copy the pointers * (the +2 and not +1 is because of the way we count the number of * bootstrap hosts (num == 0 means that we've got a single host etc) */ if ((ret->backup_nodes = calloc(num + 2, sizeof(char *))) == NULL) { return LCB_CLIENT_ENOMEM; } ret->should_free_backup_nodes = 1; ptr = host; ii = 0; do { char nm[NI_MAXHOST + NI_MAXSERV + 2]; const char *start = ptr; lcb_error_t error; ptr = strchr(ptr, ';'); ret->backup_nodes[ii] = NULL; if (ptr == NULL) { /* this is the last part */ error = validate_hostname(start, &ret->backup_nodes[ii]); ptr = NULL; } else { /* copy everything up to ';' */ unsigned long size = (unsigned long)ptr - (unsigned long)start; /* skip the entry if it's too long */ if (size < sizeof(nm)) { memcpy(nm, start, (lcb_size_t)(ptr - start)); *(nm + size) = '\0'; } ++ptr; error = validate_hostname(nm, &ret->backup_nodes[ii]); } if (error != LCB_SUCCESS) { while (ii > 0) { free(ret->backup_nodes[ii--]); } return error; } ++ii; } while (ptr != NULL); if (ret->randomize_bootstrap_nodes) { ii = 1; while (ret->backup_nodes[ii] != NULL) { lcb_size_t nidx = (lcb_size_t)(gethrtime() >> 10) % ii; char *other = ret->backup_nodes[nidx]; ret->backup_nodes[nidx] = ret->backup_nodes[ii]; ret->backup_nodes[ii] = other; ++ii; } }
gfarm_error_t add_line(char *line, int lineno) { gfarm_error_t e; long port, ncpu, flags; int len, nhostaliases; char *s, *hostname, *architecture; char *hostaliases[MAX_HOSTALIASES + 1]; /* parse architecture */ line += strspn(line, space); /* skip space */ len = strcspn(line, space); if (len == 0 || line[len] == '\0') return (invalid_input(lineno)); line[len] = '\0'; architecture = line; line += len + 1; s = validate_architecture(architecture); if (s != NULL) { fprintf(stderr, "line %d: invalid character '%c' in architecture \"%s\"\n", lineno, *s, architecture); return (GFARM_ERR_INVALID_ARGUMENT); } e = parse_string_long(&line, lineno, "ncpu", &ncpu); if (e != GFARM_ERR_NO_ERROR) return (e); /* parse hostname */ line += strspn(line, space); /* skip space */ len = strcspn(line, space); if (len == 0) return (invalid_input(lineno)); hostname = line; if (line[len] == '\0') { line += len; } else { line[len] = '\0'; line += len + 1; } s = validate_hostname(hostname); if (s != NULL) { fprintf(stderr, "line %d: invalid character '%c' in hostname \"%s\"\n", lineno, *s, hostname); return (GFARM_ERR_INVALID_ARGUMENT); } e = parse_string_long(&line, lineno, "port", &port); if (e != GFARM_ERR_NO_ERROR) return (e); e = parse_string_long(&line, lineno, "flags", &flags); if (e != GFARM_ERR_NO_ERROR) return (e); /* parse hostaliases */ for (nhostaliases = 0;; nhostaliases++) { line += strspn(line, space); /* skip space */ if (*line == '\0') break; len = strcspn(line, space); /* assert(len > 0); */ if (nhostaliases >= MAX_HOSTALIASES) { fprintf(stderr, "line %d: " "number of hostaliases exceeds %d\n", lineno, nhostaliases); return (GFARM_ERR_INVALID_ARGUMENT); } hostaliases[nhostaliases] = line; if (line[len] == '\0') { line += len; } else { line[len] = '\0'; line += len + 1; } s = validate_hostname(hostaliases[nhostaliases]); if (s != NULL) { fprintf(stderr, "line %d: " "invalid character '%c' in hostalias \"%s\"\n", lineno, *s, hostaliases[nhostaliases]); return (GFARM_ERR_INVALID_ARGUMENT); } } hostaliases[nhostaliases] = NULL; e = add_host(hostname, port, hostaliases, architecture, ncpu, flags); if (e != GFARM_ERR_NO_ERROR) fprintf(stderr, "line %d: %s\n", lineno, gfarm_error_string(e)); return (e); }
int main(int argc, char **argv) { int argc_save = argc; char **argv_save = argv; gfarm_error_t e, e_save = GFARM_ERR_NO_ERROR; char opt_operation = '\0'; /* default operation */ int opt_concurrency = DEFAULT_CONCURRENCY; int opt_alter_aliases = 0; char *opt_architecture = NULL; char *opt_domainname = NULL; long opt_ncpu = 0; int opt_port = 0, opt_flags = -1; int opt_plain_order = 0; /* i.e. do not sort */ int opt_sort_by_loadavg = 0; int i, c, opt_use_metadb = 1; char *s; if (argc > 0) program_name = basename(argv[0]); while ((c = getopt(argc, argv, "AD:HLMPUa:cdf:ij:lmn:p:ruv?")) != -1) { switch (c) { case 'A': opt_alter_aliases = 1; break; case 'L': opt_sort_by_loadavg = 1; break; case 'M': case 'H': case 'R': case 'c': case 'd': case 'l': case 'm': if (opt_operation != '\0' && opt_operation != c) inconsistent_option(opt_operation, c); opt_operation = c; break; case 'a': opt_architecture = optarg; s = validate_architecture(opt_architecture); if (s != NULL) { fprintf(stderr, "%s: " "invalid character '%c' in \"-a %s\"\n", program_name, *s, opt_architecture); exit(1); } break; case 'D': opt_domainname = optarg; s = validate_hostname(opt_domainname); if (s != NULL) { fprintf(stderr, "%s: " "invalid character '%c' in \"-a %s\"\n", program_name, *s, opt_domainname); exit(1); } break; case 'i': opt_resolv_addr = resolv_addr_without_address_use; break; case 'j': opt_concurrency = parse_opt_long(optarg, c, "<concurrency>"); if (opt_concurrency <= 0) { fprintf(stderr, "%s: invalid value: -%c %d\n", program_name, c, opt_concurrency); usage(); } break; case 'f': opt_flags = parse_opt_long(optarg, c, "<flags>"); break; case 'n': opt_ncpu = parse_opt_long(optarg, c, "<ncpu>"); break; case 'p': opt_port = parse_opt_long(optarg, c, "<port>"); break; case 'r': output_sort_reverse = 1; break; case 'U': opt_udp_only = 1; break; case 'u': opt_plain_order = 1; break; case 'v': opt_verbose = 1; break; case '?': usage(); } } argc -= optind; argv += optind; switch (opt_operation) { case OP_CREATE_ENTRY: if (opt_architecture == NULL) { fprintf(stderr, "%s: missing -a <architecture>\n", program_name); usage(); } if (opt_ncpu == 0) opt_ncpu = 1; if (opt_flags == -1) opt_flags = 0; /* opt_alter_aliases is meaningless, but allowed */ break; case OP_REGISTER_DB: case OP_DELETE_ENTRY: if (opt_architecture != NULL) invalid_option('a'); if (opt_domainname != NULL) invalid_option('D'); /* fall through */ case OP_NODENAME: case OP_LIST_GFSD_INFO: case OP_LIST_LONG: case OP_DUMP_METADB: if (opt_ncpu != 0) invalid_option('n'); if (opt_alter_aliases) invalid_option('A'); break; case OP_MODIFY_ENTRY: if (opt_domainname != NULL) invalid_option('D'); break; default: ; } for (i = 0; i < argc; i++) { s = validate_hostname(argv[i]); if (s != NULL) { fprintf(stderr, "%s: " "invalid character '%c' in hostname \"%s\"\n", program_name, *s, argv[i]); exit(1); } } e = gfarm_initialize(&argc_save, &argv_save); if (opt_operation == OP_LIST_GFSD_INFO && argc > 0 && opt_resolv_addr == resolv_addr_without_address_use) { /* * An implicit feature to access gfsd directly * without having working gfmd. * e.g. gfhost -Hi <hostname> * * XXX should describe this in the manual? * or use explicit and different option? */ opt_use_metadb = 0; opt_resolv_addr = resolv_addr_without_metadb; } else if (e != GFARM_ERR_NO_ERROR) { fprintf(stderr, "%s: %s\n", program_name, gfarm_error_string(e)); exit(1); } switch (opt_operation) { case OP_CREATE_ENTRY: if (argc > 0) { if (opt_port == 0) { fprintf(stderr, "%s: option -p <port> is " "mandatory with -c\n", program_name); usage(); } e_save = add_host(argv[0], opt_port, &argv[1], opt_architecture, opt_ncpu, opt_flags); if (e_save != GFARM_ERR_NO_ERROR) fprintf(stderr, "%s: %s: %s\n", program_name, argv[0], gfarm_error_string(e_save)); } break; case OP_MODIFY_ENTRY: if (argc > 0) { e_save = gfarm_modify_host(argv[0], opt_port, &argv[1], opt_architecture, opt_ncpu, opt_flags, !opt_alter_aliases); if (e_save != GFARM_ERR_NO_ERROR) fprintf(stderr, "%s: %s: %s\n", program_name, argv[0], gfarm_error_string(e_save)); } break; case OP_DELETE_ENTRY: for (i = 0; i < argc; i++) { e = gfm_client_host_info_remove(gfarm_metadb_server, argv[i]); if (e != GFARM_ERR_NO_ERROR) { fprintf(stderr, "%s: %s\n", argv[i], gfarm_error_string(e)); if (e_save == GFARM_ERR_NO_ERROR) e_save = e; } } break; case OP_REGISTER_DB: if (argc > 0) { fprintf(stderr, "%s: too many argument: %s\n", program_name, argv[0]); exit(1); } e_save = register_db(); break; case OP_LIST_GFSD_INFO: e = paraccess_list(opt_concurrency, opt_udp_only, opt_architecture, opt_domainname, opt_port, opt_plain_order, opt_sort_by_loadavg, opt_use_metadb, argc, argv, request_gfsd_info, callback_gfsd_info); break; case OP_NODENAME: e = paraccess_list(opt_concurrency, opt_udp_only, opt_architecture, opt_domainname, opt_port, opt_plain_order, opt_sort_by_loadavg, opt_use_metadb, argc, argv, request_nodename, callback_nodename); break; case OP_LIST_LONG: e = paraccess_list(opt_concurrency, opt_udp_only, opt_architecture, opt_domainname, opt_port, opt_plain_order, opt_sort_by_loadavg, opt_use_metadb, argc, argv, request_long_format, callback_long_format); break; case OP_DUMP_METADB: if (argc == 0) { e_save = list_all(opt_architecture, opt_domainname, print_host_info, NULL); } else { e_save = list(argc, argv, print_host_info, NULL); } break; } e = gfarm_terminate(); if (e != GFARM_ERR_NO_ERROR) { fprintf(stderr, "%s: %s\n", program_name, gfarm_error_string(e)); exit(1); } exit(e_save == GFARM_ERR_NO_ERROR ? 0 : 1); }