void listen_sslctx_setup_2(void* ctxt) { #ifdef HAVE_SSL SSL_CTX* ctx = (SSL_CTX*)ctxt; (void)ctx; #if HAVE_DECL_SSL_CTX_SET_ECDH_AUTO if(!SSL_CTX_set_ecdh_auto(ctx,1)) { log_crypto_err("Error in SSL_CTX_ecdh_auto, not enabling ECDHE"); } #elif defined(USE_ECDSA) if(1) { EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1); if (!ecdh) { log_crypto_err("could not find p256, not enabling ECDHE"); } else { if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh)) { log_crypto_err("Error in SSL_CTX_set_tmp_ecdh, not enabling ECDHE"); } EC_KEY_free (ecdh); } } #endif #else (void)ctxt; #endif /* HAVE_SSL */ }
void* outgoing_ssl_fd(void* sslctx, int fd) { SSL* ssl = SSL_new((SSL_CTX*)sslctx); if(!ssl) { log_crypto_err("could not SSL_new"); return NULL; } SSL_set_connect_state(ssl); (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); if(!SSL_set_fd(ssl, fd)) { log_crypto_err("could not SSL_set_fd"); SSL_free(ssl); return NULL; } return ssl; }
int ssl_read_line(SSL* ssl, char* buf, size_t max) { int r; size_t len = 0; if(!ssl) return 0; while(len < max) { ERR_clear_error(); if((r=SSL_read(ssl, buf+len, 1)) <= 0) { if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { buf[len] = 0; return 1; } log_crypto_err("could not SSL_read"); return 0; } if(buf[len] == '\n') { /* return string without \n */ buf[len] = 0; return 1; } len++; } buf[max-1] = 0; log_err("control line too long (%d): %s", (int)max, buf); return 0; }
void* listen_sslctx_create(char* key, char* pem, char* verifypem) { #ifdef HAVE_SSL SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method()); if(!ctx) { log_crypto_err("could not SSL_CTX_new"); return NULL; } if(!listen_sslctx_setup(ctx)) { SSL_CTX_free(ctx); return NULL; } if(!SSL_CTX_use_certificate_chain_file(ctx, pem)) { log_err("error for cert file: %s", pem); log_crypto_err("error in SSL_CTX use_certificate_chain_file"); SSL_CTX_free(ctx); return NULL; } if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) { log_err("error for private key file: %s", key); log_crypto_err("Error in SSL_CTX use_PrivateKey_file"); SSL_CTX_free(ctx); return NULL; } if(!SSL_CTX_check_private_key(ctx)) { log_err("error for key file: %s", key); log_crypto_err("Error in SSL_CTX check_private_key"); SSL_CTX_free(ctx); return NULL; } listen_sslctx_setup_2(ctx); if(verifypem && verifypem[0]) { if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) { log_crypto_err("Error in SSL_CTX verify locations"); SSL_CTX_free(ctx); return NULL; } SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file( verifypem)); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); } return ctx; #else (void)key; (void)pem; (void)verifypem; return NULL; #endif }
/** send the TCP queries and print answers */ static void send_em(const char* svr, int udp, int usessl, int noanswer, int num, char** qs) { sldns_buffer* buf = sldns_buffer_new(65553); int fd = open_svr(svr, udp); int i; SSL_CTX* ctx = NULL; SSL* ssl = NULL; if(!buf) fatal_exit("out of memory"); if(usessl) { ctx = connect_sslctx_create(NULL, NULL, NULL); if(!ctx) fatal_exit("cannot create ssl ctx"); ssl = outgoing_ssl_fd(ctx, fd); if(!ssl) fatal_exit("cannot create ssl"); while(1) { int r; ERR_clear_error(); if( (r=SSL_do_handshake(ssl)) == 1) break; r = SSL_get_error(ssl, r); if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) { log_crypto_err("could not ssl_handshake"); exit(1); } } if(1) { X509* x = SSL_get_peer_certificate(ssl); if(!x) printf("SSL: no peer certificate\n"); else { X509_print_fp(stdout, x); X509_free(x); } } } for(i=0; i<num; i+=3) { printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]); write_q(fd, udp, ssl, buf, (uint16_t)get_random(), qs[i], qs[i+1], qs[i+2]); /* print at least one result */ if(!noanswer) recv_one(fd, udp, ssl, buf); } if(usessl) { SSL_shutdown(ssl); SSL_free(ssl); SSL_CTX_free(ctx); } #ifndef USE_WINSOCK close(fd); #else closesocket(fd); #endif sldns_buffer_free(buf); printf("orderly exit\n"); }
void* incoming_ssl_fd(void* sslctx, int fd) { #ifdef HAVE_SSL SSL* ssl = SSL_new((SSL_CTX*)sslctx); if(!ssl) { log_crypto_err("could not SSL_new"); return NULL; } SSL_set_accept_state(ssl); (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); if(!SSL_set_fd(ssl, fd)) { log_crypto_err("could not SSL_set_fd"); SSL_free(ssl); return NULL; } return ssl; #else (void)sslctx; (void)fd; return NULL; #endif }
void* connect_sslctx_create(char* key, char* pem, char* verifypem) { #ifdef HAVE_SSL SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method()); if(!ctx) { log_crypto_err("could not allocate SSL_CTX pointer"); return NULL; } if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) != SSL_OP_NO_SSLv2) { log_crypto_err("could not set SSL_OP_NO_SSLv2"); SSL_CTX_free(ctx); return NULL; } if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) != SSL_OP_NO_SSLv3) { log_crypto_err("could not set SSL_OP_NO_SSLv3"); SSL_CTX_free(ctx); return NULL; } if(key && key[0]) { if(!SSL_CTX_use_certificate_chain_file(ctx, pem)) { log_err("error in client certificate %s", pem); log_crypto_err("error in certificate file"); SSL_CTX_free(ctx); return NULL; } if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) { log_err("error in client private key %s", key); log_crypto_err("error in key file"); SSL_CTX_free(ctx); return NULL; } if(!SSL_CTX_check_private_key(ctx)) { log_err("error in client key %s", key); log_crypto_err("error in SSL_CTX_check_private_key"); SSL_CTX_free(ctx); return NULL; } } if(verifypem && verifypem[0]) { if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) { log_crypto_err("error in SSL_CTX verify"); SSL_CTX_free(ctx); return NULL; } SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); } return ctx; #else (void)key; (void)pem; (void)verifypem; return NULL; #endif }
int listen_sslctx_setup(void* ctxt) { #ifdef HAVE_SSL SSL_CTX* ctx = (SSL_CTX*)ctxt; /* no SSLv2, SSLv3 because has defects */ if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) != SSL_OP_NO_SSLv2){ log_crypto_err("could not set SSL_OP_NO_SSLv2"); return 0; } if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) != SSL_OP_NO_SSLv3){ log_crypto_err("could not set SSL_OP_NO_SSLv3"); return 0; } #if defined(SSL_OP_NO_TLSv1) && defined(SSL_OP_NO_TLSv1_1) /* if we have tls 1.1 disable 1.0 */ if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1) & SSL_OP_NO_TLSv1) != SSL_OP_NO_TLSv1){ log_crypto_err("could not set SSL_OP_NO_TLSv1"); return 0; } #endif #if defined(SSL_OP_NO_TLSv1_1) && defined(SSL_OP_NO_TLSv1_2) /* if we have tls 1.2 disable 1.1 */ if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_1) & SSL_OP_NO_TLSv1_1) != SSL_OP_NO_TLSv1_1){ log_crypto_err("could not set SSL_OP_NO_TLSv1_1"); return 0; } #endif #if defined(SHA256_DIGEST_LENGTH) && defined(USE_ECDSA) /* if we have sha256, set the cipher list to have no known vulns */ if(!SSL_CTX_set_cipher_list(ctx, "TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256")) log_crypto_err("could not set cipher list with SSL_CTX_set_cipher_list"); #endif if((SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE) & SSL_OP_CIPHER_SERVER_PREFERENCE) != SSL_OP_CIPHER_SERVER_PREFERENCE) { log_crypto_err("could not set SSL_OP_CIPHER_SERVER_PREFERENCE"); return 0; } #ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL SSL_CTX_set_security_level(ctx, 0); #endif #else (void)ctxt; #endif /* HAVE_SSL */ return 1; }
int ssl_print_text(SSL* ssl, const char* text) { int r; if(!ssl) return 0; ERR_clear_error(); if((r=SSL_write(ssl, text, (int)strlen(text))) <= 0) { if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { verbose(VERB_QUERY, "warning, in SSL_write, peer " "closed connection"); return 0; } log_crypto_err("could not SSL_write"); return 0; } return 1; }
void* listen_sslctx_create(char* key, char* pem, char* verifypem) { SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method()); if(!ctx) { log_crypto_err("could not SSL_CTX_new"); return NULL; } /* no SSLv2 because has defects */ if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)){ log_crypto_err("could not set SSL_OP_NO_SSLv2"); SSL_CTX_free(ctx); return NULL; } if(!SSL_CTX_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) { log_err("error for cert file: %s", pem); log_crypto_err("error in SSL_CTX use_certificate_file"); SSL_CTX_free(ctx); return NULL; } if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) { log_err("error for private key file: %s", key); log_crypto_err("Error in SSL_CTX use_PrivateKey_file"); SSL_CTX_free(ctx); return NULL; } if(!SSL_CTX_check_private_key(ctx)) { log_err("error for key file: %s", key); log_crypto_err("Error in SSL_CTX check_private_key"); SSL_CTX_free(ctx); return NULL; } if(verifypem && verifypem[0]) { if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) { log_crypto_err("Error in SSL_CTX verify locations"); SSL_CTX_free(ctx); return NULL; } SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file( verifypem)); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); } return ctx; }
int remote_accept_callback(struct comm_point* c, void* arg, int err, struct comm_reply* ATTR_UNUSED(rep)) { struct daemon_remote* rc = (struct daemon_remote*)arg; struct sockaddr_storage addr; socklen_t addrlen; int newfd; struct rc_state* n; if(err != NETEVENT_NOERROR) { log_err("error %d on remote_accept_callback", err); return 0; } /* perform the accept */ newfd = comm_point_perform_accept(c, &addr, &addrlen); if(newfd == -1) return 0; /* create new commpoint unless we are servicing already */ if(rc->active >= rc->max_active) { log_warn("drop incoming remote control: too many connections"); comm_point_stop_listening(c); close_exit: #ifndef USE_WINSOCK close(newfd); #else closesocket(newfd); #endif return 0; } /* setup commpoint to service the remote control command */ n = (struct rc_state*)calloc(1, sizeof(*n)); if(!n) { log_err("out of memory"); goto close_exit; } /* start in reading state */ n->c = comm_point_create_raw(rc->worker->base, newfd, 0, &remote_control_callback, n); if(!n->c) { log_err("out of memory"); free(n); goto close_exit; } log_addr(VERB_QUERY, "new control connection from", &addr, addrlen); n->c->do_not_close = 0; comm_point_stop_listening(n->c); comm_point_start_listening(n->c, -1, REMOTE_CONTROL_TCP_TIMEOUT); memcpy(&n->c->repinfo.addr, &addr, addrlen); n->c->repinfo.addrlen = addrlen; n->shake_state = rc_hs_read; n->ssl = SSL_new(rc->ctx); if(!n->ssl) { log_crypto_err("could not SSL_new"); free(n); goto close_exit; } SSL_set_accept_state(n->ssl); (void)SSL_set_mode(n->ssl, SSL_MODE_AUTO_RETRY); if(!SSL_set_fd(n->ssl, newfd)) { log_crypto_err("could not SSL_set_fd"); SSL_free(n->ssl); free(n); goto close_exit; } n->rc = rc; n->next = rc->busy_list; rc->busy_list = n; rc->active ++; /* perform the first nonblocking read already, for windows, * so it can return wouldblock. could be faster too. */ (void)remote_control_callback(n->c, n, NETEVENT_NOERROR, NULL); return 0; }
struct daemon_remote* daemon_remote_create(struct config_file* cfg) { char* s_cert; char* s_key; struct daemon_remote* rc = (struct daemon_remote*)calloc(1, sizeof(*rc)); if(!rc) { log_err("out of memory in daemon_remote_create"); return NULL; } rc->max_active = 10; if(!cfg->remote_control_enable) { rc->ctx = NULL; return rc; } rc->ctx = SSL_CTX_new(SSLv23_server_method()); if(!rc->ctx) { log_crypto_err("could not SSL_CTX_new"); free(rc); return NULL; } /* no SSLv2 because has defects */ if(!(SSL_CTX_set_options(rc->ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)){ log_crypto_err("could not set SSL_OP_NO_SSLv2"); daemon_remote_delete(rc); return NULL; } s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1); s_key = fname_after_chroot(cfg->server_key_file, cfg, 1); if(!s_cert || !s_key) { log_err("out of memory in remote control fname"); goto setup_error; } verbose(VERB_ALGO, "setup SSL certificates"); if (!SSL_CTX_use_certificate_file(rc->ctx,s_cert,SSL_FILETYPE_PEM)) { log_err("Error for server-cert-file: %s", s_cert); log_crypto_err("Error in SSL_CTX use_certificate_file"); goto setup_error; } if(!SSL_CTX_use_PrivateKey_file(rc->ctx,s_key,SSL_FILETYPE_PEM)) { log_err("Error for server-key-file: %s", s_key); log_crypto_err("Error in SSL_CTX use_PrivateKey_file"); goto setup_error; } if(!SSL_CTX_check_private_key(rc->ctx)) { log_err("Error for server-key-file: %s", s_key); log_crypto_err("Error in SSL_CTX check_private_key"); goto setup_error; } if(!SSL_CTX_load_verify_locations(rc->ctx, s_cert, NULL)) { log_crypto_err("Error setting up SSL_CTX verify locations"); setup_error: free(s_cert); free(s_key); daemon_remote_delete(rc); return NULL; } SSL_CTX_set_client_CA_list(rc->ctx, SSL_load_client_CA_file(s_cert)); SSL_CTX_set_verify(rc->ctx, SSL_VERIFY_PEER, NULL); free(s_cert); free(s_key); return rc; }
/** receive DNS datagram over TCP and print it */ static void recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf) { char* pktstr; uint16_t len; if(!udp) { if(ssl) { if(SSL_read(ssl, (void*)&len, (int)sizeof(len)) <= 0) { log_crypto_err("could not SSL_read"); exit(1); } } else { if(recv(fd, (void*)&len, sizeof(len), 0) < (ssize_t)sizeof(len)) { #ifndef USE_WINSOCK perror("read() len failed"); #else printf("read len: %s\n", wsa_strerror(WSAGetLastError())); #endif exit(1); } } len = ntohs(len); sldns_buffer_clear(buf); sldns_buffer_set_limit(buf, len); if(ssl) { int r = SSL_read(ssl, (void*)sldns_buffer_begin(buf), (int)len); if(r <= 0) { log_crypto_err("could not SSL_read"); exit(1); } if(r != (int)len) fatal_exit("ssl_read %d of %d", r, len); } else { if(recv(fd, (void*)sldns_buffer_begin(buf), len, 0) < (ssize_t)len) { #ifndef USE_WINSOCK perror("read() data failed"); #else printf("read data: %s\n", wsa_strerror(WSAGetLastError())); #endif exit(1); } } } else { ssize_t l; sldns_buffer_clear(buf); if((l=recv(fd, (void*)sldns_buffer_begin(buf), sldns_buffer_capacity(buf), 0)) < 0) { #ifndef USE_WINSOCK perror("read() data failed"); #else printf("read data: %s\n", wsa_strerror(WSAGetLastError())); #endif exit(1); } sldns_buffer_set_limit(buf, (size_t)l); len = (size_t)l; } printf("\nnext received packet\n"); log_buf(0, "data", buf); pktstr = sldns_wire2str_pkt(sldns_buffer_begin(buf), len); printf("%s", pktstr); free(pktstr); }
/** write a query over the TCP fd */ static void write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id, const char* strname, const char* strtype, const char* strclass) { struct query_info qinfo; uint16_t len; /* qname */ qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len); if(!qinfo.qname) { printf("cannot parse query name: '%s'\n", strname); exit(1); } /* qtype and qclass */ qinfo.qtype = sldns_get_rr_type_by_name(strtype); qinfo.qclass = sldns_get_rr_class_by_name(strclass); /* make query */ qinfo_query_encode(buf, &qinfo); sldns_buffer_write_u16_at(buf, 0, id); sldns_buffer_write_u16_at(buf, 2, BIT_RD); if(1) { /* add EDNS DO */ struct edns_data edns; memset(&edns, 0, sizeof(edns)); edns.edns_present = 1; edns.bits = EDNS_DO; edns.udp_size = 4096; attach_edns_record(buf, &edns); } /* send it */ if(!udp) { len = (uint16_t)sldns_buffer_limit(buf); len = htons(len); if(ssl) { if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) { log_crypto_err("cannot SSL_write"); exit(1); } } else { if(send(fd, (void*)&len, sizeof(len), 0) < (ssize_t)sizeof(len)){ #ifndef USE_WINSOCK perror("send() len failed"); #else printf("send len: %s\n", wsa_strerror(WSAGetLastError())); #endif exit(1); } } } if(ssl) { if(SSL_write(ssl, (void*)sldns_buffer_begin(buf), (int)sldns_buffer_limit(buf)) <= 0) { log_crypto_err("cannot SSL_write"); exit(1); } } else { if(send(fd, (void*)sldns_buffer_begin(buf), sldns_buffer_limit(buf), 0) < (ssize_t)sldns_buffer_limit(buf)) { #ifndef USE_WINSOCK perror("send() data failed"); #else printf("send data: %s\n", wsa_strerror(WSAGetLastError())); #endif exit(1); } } free(qinfo.qname); }