uint8_t * cga_key2der(EVP_PKEY *k, int *dlen) { uint8_t *p; uint8_t *der = NULL; X509_PUBKEY *pki = NULL; if (X509_PUBKEY_set(&pki, k) == 0) { ssl_err(__FUNCTION__, "X509_PUBKEY_set() failed"); goto done; } if ((*dlen = i2d_X509_PUBKEY(pki, NULL)) < 0) { ssl_err(__FUNCTION__, "i2d_PublicKey failed"); goto done; } if ((der = malloc(*dlen)) == NULL) { APPLOG_NOMEM(); goto done; } p = der; if (i2d_X509_PUBKEY(pki, &p) < 0) { ssl_err(__FUNCTION__, "i2d_PublicKey failed"); free(der); der = NULL; } DBG(&dbg_asn1, "DER-encoded key is %d bytes", *dlen); done: if (pki) X509_PUBKEY_free(pki); return (der); }
/** setup SSL context */ static SSL_CTX* setup_ctx(struct config_file* cfg) { char* s_cert, *c_key, *c_cert; SSL_CTX* ctx; s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1); c_key = fname_after_chroot(cfg->control_key_file, cfg, 1); c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1); if(!s_cert || !c_key || !c_cert) fatal_exit("out of memory"); ctx = SSL_CTX_new(SSLv23_client_method()); if(!ctx) ssl_err("could not allocate SSL_CTX pointer"); if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)) ssl_err("could not set SSL_OP_NO_SSLv2"); if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM) || !SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM) || !SSL_CTX_check_private_key(ctx)) ssl_err("Error setting up SSL_CTX client key and cert"); if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1) ssl_err("Error setting up SSL_CTX verify, server cert"); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); free(s_cert); free(c_key); free(c_cert); return ctx; }
/** setup SSL on the connection */ static SSL* setup_ssl(SSL_CTX* ctx, int fd) { SSL* ssl; X509* x; int r; ssl = SSL_new(ctx); if(!ssl) ssl_err("could not SSL_new"); SSL_set_connect_state(ssl); (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); if(!SSL_set_fd(ssl, fd)) ssl_err("could not SSL_set_fd"); while(1) { 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) ssl_err("SSL handshake failed"); /* wants to be called again */ } /* check authenticity of server */ if(SSL_get_verify_result(ssl) != X509_V_OK) ssl_err("SSL verification failed"); x = SSL_get_peer_certificate(ssl); if(!x) ssl_err("Server presented no peer certificate"); X509_free(x); return ssl; }
/** send command and display result */ static int go_cmd(SSL* ssl, int quiet, int argc, char* argv[]) { char pre[10]; const char* space=" "; const char* newline="\n"; int was_error = 0, first_line = 1; int r, i; char buf[1024]; snprintf(pre, sizeof(pre), "UBCT%d ", UNBOUND_CONTROL_VERSION); if(SSL_write(ssl, pre, (int)strlen(pre)) <= 0) ssl_err("could not SSL_write"); for(i=0; i<argc; i++) { if(SSL_write(ssl, space, (int)strlen(space)) <= 0) ssl_err("could not SSL_write"); if(SSL_write(ssl, argv[i], (int)strlen(argv[i])) <= 0) ssl_err("could not SSL_write"); } if(SSL_write(ssl, newline, (int)strlen(newline)) <= 0) ssl_err("could not SSL_write"); if(argc == 1 && strcmp(argv[0], "load_cache") == 0) { send_file(ssl, stdin, buf, sizeof(buf)); } else if(argc == 1 && (strcmp(argv[0], "local_zones") == 0 || strcmp(argv[0], "local_zones_remove") == 0 || strcmp(argv[0], "local_datas") == 0 || strcmp(argv[0], "local_datas_remove") == 0)) { send_file(ssl, stdin, buf, sizeof(buf)); send_eof(ssl); } while(1) { ERR_clear_error(); if((r = SSL_read(ssl, buf, (int)sizeof(buf)-1)) <= 0) { if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { /* EOF */ break; } ssl_err("could not SSL_read"); } buf[r] = 0; if(first_line && strncmp(buf, "error", 5) == 0) { printf("%s", buf); was_error = 1; } else if (!quiet) printf("%s", buf); first_line = 0; } return was_error; }
/** send end-of-file marker to server */ static void send_eof(SSL* ssl) { char e[] = {0x04, 0x0a}; if(SSL_write(ssl, e, (int)sizeof(e)) <= 0) ssl_err("could not SSL_write end-of-file marker"); }
/** read from ssl or fd, fatalexit on error, 0 EOF, 1 success */ static int remote_read(SSL* ssl, int fd, char* buf, size_t len) { if(ssl) { int r; ERR_clear_error(); if((r = SSL_read(ssl, buf, (int)len-1)) <= 0) { if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { /* EOF */ return 0; } ssl_err("could not SSL_read"); } buf[r] = 0; } else { ssize_t rr = recv(fd, buf, len-1, 0); if(rr <= 0) { if(rr == 0) { /* EOF */ return 0; } #ifndef USE_WINSOCK fatal_exit("could not recv: %s", strerror(errno)); #else fatal_exit("could not recv: %s", wsa_strerror(WSAGetLastError())); #endif } buf[rr] = 0; } return 1; }
/** read from ssl or fd, fatalexit on error, 0 EOF, 1 success */ static int remote_read(SSL* ssl, int fd, char* buf, size_t len) { if(ssl) { int r; ERR_clear_error(); if((r = SSL_read(ssl, buf, (int)len-1)) <= 0) { if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { /* EOF */ return 0; } ssl_err("could not SSL_read"); } buf[r] = 0; } else { ssize_t rr = read(fd, buf, len-1); if(rr <= 0) { if(rr == 0) { /* EOF */ return 0; } fprintf(stderr, "could not read: %s\n", strerror(errno)); exit(1); } buf[rr] = 0; } return 1; }
/** send stdin to server */ static void send_file(SSL* ssl, FILE* in, char* buf, size_t sz) { while(fgets(buf, (int)sz, in)) { if(SSL_write(ssl, buf, (int)strlen(buf)) <= 0) ssl_err("could not SSL_write contents"); } }
void ldns_err(const char* s, ldns_status err) { if (err == LDNS_STATUS_SSL_ERR) { ssl_err(s); } else { fprintf(stderr, "%s: %s\n", s, ldns_get_errorstr_by_id(err)); exit(EXIT_FAILURE); } }
/** setup SSL context */ static SSL_CTX* setup_ctx(struct nsd_options* cfg) { char* s_cert, *c_key, *c_cert; SSL_CTX* ctx; if(!options_remote_is_address(cfg)) return NULL; s_cert = cfg->server_cert_file; c_key = cfg->control_key_file; c_cert = cfg->control_cert_file; /* filenames may be relative to zonesdir */ if (cfg->zonesdir && cfg->zonesdir[0] && (s_cert[0] != '/' || c_key[0] != '/' || c_cert[0] != '/')) { if(chdir(cfg->zonesdir)) error("could not chdir to zonesdir: %s %s", cfg->zonesdir, strerror(errno)); } ctx = SSL_CTX_new(SSLv23_client_method()); if(!ctx) ssl_err("could not allocate SSL_CTX pointer"); if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) != SSL_OP_NO_SSLv2) ssl_err("could not set SSL_OP_NO_SSLv2"); if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) != SSL_OP_NO_SSLv3) ssl_err("could not set SSL_OP_NO_SSLv3"); if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM)) ssl_path_err("Error setting up SSL_CTX client cert", c_cert); if(!SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM)) ssl_path_err("Error setting up SSL_CTX client key", c_key); if(!SSL_CTX_check_private_key(ctx)) ssl_err("Error setting up SSL_CTX client key"); if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1) ssl_path_err("Error setting up SSL_CTX verify, server cert", s_cert); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); return ctx; }
static int ssl_socket_write (CONNECTION* conn, const char* buf, size_t len) { sslsockdata *data = conn->sockdata; int rc; rc = SSL_write (data->ssl, buf, len); if (rc <= 0) ssl_err (data, rc); return rc; }
/** send command and display result */ static int go_cmd(SSL* ssl, int argc, char* argv[]) { const char* pre="UBCT"; const char* space=" "; const char* newline="\n"; int was_error = 0, first_line = 1; int r, i; char buf[1024]; if(SSL_write(ssl, pre, (int)strlen(pre)) <= 0) ssl_err("could not SSL_write"); for(i=0; i<argc; i++) { if(SSL_write(ssl, space, (int)strlen(space)) <= 0) ssl_err("could not SSL_write"); if(SSL_write(ssl, argv[i], (int)strlen(argv[i])) <= 0) ssl_err("could not SSL_write"); } if(SSL_write(ssl, newline, (int)strlen(newline)) <= 0) ssl_err("could not SSL_write"); if(argc == 1 && strcmp(argv[0], "load_cache") == 0) { send_file(ssl, stdin, buf, sizeof(buf)); } while(1) { ERR_clear_error(); if((r = SSL_read(ssl, buf, (int)sizeof(buf)-1)) <= 0) { if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { /* EOF */ break; } ssl_err("could not SSL_read"); } buf[r] = 0; printf("%s", buf); if(first_line && strncmp(buf, "error", 5) == 0) was_error = 1; first_line = 0; } return was_error; }
static int ssl_socket_read (CONNECTION* conn, char* buf, size_t len) { sslsockdata *data = conn->sockdata; int rc; rc = SSL_read (data->ssl, buf, len); if (rc <= 0) { data->isopen = 0; ssl_err (data, rc); } return rc; }
/** write to ssl or fd, fatalexit on error */ static void remote_write(SSL* ssl, int fd, const char* buf, size_t len) { if(ssl) { if(SSL_write(ssl, buf, (int)len) <= 0) ssl_err("could not SSL_write"); } else { if(write(fd, buf, len) < (ssize_t)len) { fprintf(stderr, "could not write: %s\n", strerror(errno)); exit(1); } } }
/** exit with ssl error related to a file path */ static void ssl_path_err(const char* s, const char *path) { unsigned long err; err = ERR_peek_error(); if (ERR_GET_LIB(err) == ERR_LIB_SYS && (ERR_GET_FUNC(err) == SYS_F_FOPEN || ERR_GET_FUNC(err) == SYS_F_FREAD) ) { fprintf(stderr, "error: %s\n%s: %s\n", s, path, ERR_reason_error_string(err)); exit(1); } else { ssl_err(s); } }
NS_INTERNAL int tls_cl_hello(SSL *ssl) { int i = 0; struct tls_cl_hello hello; /* hello */ hello.type = HANDSHAKE_CLIENT_HELLO; hello.len_hi = 0; hello.len = htobe16(sizeof(hello) - 4); hello.version = htobe16(0x0303); hello.random.time = htobe32(time(NULL)); if (!kr_get_random(hello.random.opaque, sizeof(hello.random.opaque))) { ssl_err(ssl, SSL_ERROR_SYSCALL); return 0; } hello.sess_id_len = 0; #if ALLOW_NULL_CIPHERS /* if we allow them, it's for testing reasons, so NULL comes first */ hello.cipher_suite[i++] = htobe16(TLS_RSA_WITH_NULL_MD5); hello.cipher_suite[i++] = htobe16(TLS_RSA_WITH_AES_128_CBC_SHA256); hello.cipher_suite[i++] = htobe16(TLS_RSA_WITH_AES_128_CBC_SHA); hello.cipher_suite[i++] = htobe16(TLS_RSA_WITH_RC4_128_SHA); hello.cipher_suite[i++] = htobe16(TLS_RSA_WITH_RC4_128_MD5); hello.cipher_suite[i++] = htobe16(TLS_EMPTY_RENEGOTIATION_INFO_SCSV); #else hello.cipher_suite[i++] = htobe16(TLS_RSA_WITH_AES_128_CBC_SHA256); hello.cipher_suite[i++] = htobe16(TLS_RSA_WITH_AES_128_CBC_SHA); hello.cipher_suite[i++] = htobe16(TLS_RSA_WITH_RC4_128_SHA); hello.cipher_suite[i++] = htobe16(TLS_RSA_WITH_RC4_128_MD5); hello.cipher_suite[i++] = htobe16(TLS_EMPTY_RENEGOTIATION_INFO_SCSV); #endif hello.cipher_suites_len = htobe16(i * 2); hello.num_compressors = 1; hello.compressor[0] = COMPRESSOR_NULL; hello.ext_len = htobe16(sizeof(hello.ext_reneg)); hello.ext_reneg.type = htobe16(EXT_RENEG_INFO); hello.ext_reneg.len = htobe16(1); hello.ext_reneg.ri_len = 0; if (!tls_send(ssl, TLS_HANDSHAKE, &hello, sizeof(hello))) return 0; SHA256_Update(&ssl->nxt->handshakes_hash, ((uint8_t *) &hello), sizeof(hello)); /* store the random we generated */ memcpy(&ssl->nxt->cl_rnd, &hello.random, sizeof(ssl->nxt->cl_rnd)); return 1; }
/** write to ssl or fd, fatalexit on error */ static void remote_write(SSL* ssl, int fd, const char* buf, size_t len) { if(ssl) { if(SSL_write(ssl, buf, (int)len) <= 0) ssl_err("could not SSL_write"); } else { if(send(fd, buf, len, 0) < (ssize_t)len) { #ifndef USE_WINSOCK fatal_exit("could not send: %s", strerror(errno)); #else fatal_exit("could not send: %s", wsa_strerror(WSAGetLastError())); #endif } } }
/** * Loads a certificate from a file and sets its key into the CGA context. * * cga: the CGA context * f: the file name * * returns 0 on success, -1 on failure */ int cga_load_cert(cga_ctx_t *cga, const char *f) { X509 *x; FILE *fp; EVP_PKEY *k; int r; if ((fp = fopen(f, "r")) == NULL) { DBG(&dbg_ssl, "fopen failed: %s", strerror(errno)); return (-1); } x = PEM_read_X509(fp, NULL, NULL, NULL); if (x == NULL) { ssl_err(__FUNCTION__, "PEM_read_x509 failed"); goto fail; } k = X509_PUBKEY_get(x->cert_info->key); if (cga->key && cga->free_key) { free(cga->key); cga->key = NULL; } if ((cga->key = cga_key2der(k, &cga->klen)) == NULL) { goto fail; } cga->free_key = 1; cga->key_set = 1; r = 0; goto done; fail: r = -1; if (cga->key) free(cga->key); cga->key = NULL; cga->klen = 0; done: fclose(fp); X509_free(x); return (r); }
/** * ssl_socket_write - Write data to an SSL socket - Implements Connection::conn_write() */ static int ssl_socket_write(struct Connection *conn, const char *buf, size_t count) { struct SslSockData *data = conn->sockdata; int rc; rc = SSL_write(data->ssl, buf, count); if ((rc <= 0) || (errno == EINTR)) { if (errno == EINTR) { rc = -1; } ssl_err(data, rc); } return rc; }
int cga_load_key(cga_ctx_t *cga, const char *f) { FILE *fp; EVP_PKEY *k = NULL; int r = 0; int first = 1; struct stat sb[1]; if (stat(f, sb) < 0) { DBG(&dbg_ssl, "Could not stat file: %s\n", strerror(errno)); return (-1); } if ((fp = fopen(f, "r")) == NULL) { DBG(&dbg_ssl, "Could not open file: %s\n", strerror(errno)); return (-1); } if (cga->key && cga->free_key) { free(cga->key); } cga->key = NULL; cga->klen = 0; while (ftell(fp) < sb->st_size) { if ((k = PEM_read_PrivateKey(fp, NULL, NULL, NULL)) == NULL) { ssl_err(__FUNCTION__, "PEM_read_PrivateKey"); r = -1; break; } if (cga_add_key(cga, k, first, CGA_MULTIKEY_EXT) < 0) { EVP_PKEY_free(k); r = -1; break; } first = 0; EVP_PKEY_free(k); } fclose(fp); return (r); }
/** setup SSL context */ static SSL_CTX* setup_ctx(struct config_file* cfg) { char* s_cert=NULL, *c_key=NULL, *c_cert=NULL; SSL_CTX* ctx; if(cfg->remote_control_use_cert) { s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1); c_key = fname_after_chroot(cfg->control_key_file, cfg, 1); c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1); if(!s_cert || !c_key || !c_cert) fatal_exit("out of memory"); } ctx = SSL_CTX_new(SSLv23_client_method()); if(!ctx) ssl_err("could not allocate SSL_CTX pointer"); if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) != SSL_OP_NO_SSLv2) ssl_err("could not set SSL_OP_NO_SSLv2"); if(cfg->remote_control_use_cert) { if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) != SSL_OP_NO_SSLv3) ssl_err("could not set SSL_OP_NO_SSLv3"); if(!SSL_CTX_use_certificate_chain_file(ctx,c_cert) || !SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM) || !SSL_CTX_check_private_key(ctx)) ssl_err("Error setting up SSL_CTX client key and cert"); if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1) ssl_err("Error setting up SSL_CTX verify, server cert"); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); free(s_cert); free(c_key); free(c_cert); } else { /* Use ciphers that don't require authentication */ #if defined(SSL_OP_NO_TLSv1_3) /* in openssl 1.1.1, negotiation code for tls 1.3 does * not allow the unauthenticated aNULL and eNULL ciphers */ SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_3); #endif #ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL SSL_CTX_set_security_level(ctx, 0); #endif if(!SSL_CTX_set_cipher_list(ctx, "aNULL:eNULL")) ssl_err("Error setting NULL cipher!"); } return ctx; }
/** setup SSL context */ static SSL_CTX* setup_ctx(struct config_file* cfg) { char* s_cert=NULL, *c_key=NULL, *c_cert=NULL; SSL_CTX* ctx; if(cfg->remote_control_use_cert) { s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1); c_key = fname_after_chroot(cfg->control_key_file, cfg, 1); c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1); if(!s_cert || !c_key || !c_cert) fatal_exit("out of memory"); } ctx = SSL_CTX_new(SSLv23_client_method()); if(!ctx) ssl_err("could not allocate SSL_CTX pointer"); if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) != SSL_OP_NO_SSLv2) ssl_err("could not set SSL_OP_NO_SSLv2"); if(cfg->remote_control_use_cert) { if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) != SSL_OP_NO_SSLv3) ssl_err("could not set SSL_OP_NO_SSLv3"); if(!SSL_CTX_use_certificate_chain_file(ctx,c_cert) || !SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM) || !SSL_CTX_check_private_key(ctx)) ssl_err("Error setting up SSL_CTX client key and cert"); if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1) ssl_err("Error setting up SSL_CTX verify, server cert"); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); free(s_cert); free(c_key); free(c_cert); } else { /* Use ciphers that don't require authentication */ if(!SSL_CTX_set_cipher_list(ctx, "aNULL")) ssl_err("Error setting NULL cipher!"); } return ctx; }