static gnutls_session initialize_state(void) { gnutls_session session; gnutls_init(&session, GNUTLS_SERVER); gnutls_protocol_set_priority(session, protocol_priority); gnutls_cipher_set_priority(session, cipher_priority); gnutls_compression_set_priority(session, comp_priority); gnutls_kx_set_priority(session, kx_priority); gnutls_mac_set_priority(session, mac_priority); gnutls_certificate_type_set_priority(session, cert_type_priority); gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); return session; }
int init_ssl_connection(struct socket *socket, const unsigned char *server_name) { #ifdef USE_OPENSSL socket->ssl = SSL_new(context); if (!socket->ssl) return S_SSL_ERROR; if (!SSL_set_ex_data(socket->ssl, socket_SSL_ex_data_idx, socket)) { SSL_free(socket->ssl); socket->ssl = NULL; return S_SSL_ERROR; } /* If the server name is known, pass it to OpenSSL. * * The return value of SSL_set_tlsext_host_name is not * documented. The source shows that it returns 1 if * successful; on error, it calls SSLerr and returns 0. */ if (server_name && !SSL_set_tlsext_host_name(socket->ssl, server_name)) { SSL_free(socket->ssl); socket->ssl = NULL; return S_SSL_ERROR; } #elif defined(CONFIG_GNUTLS) ssl_t *state = mem_alloc(sizeof(ssl_t)); if (!state) return S_SSL_ERROR; if (gnutls_init(state, GNUTLS_CLIENT) < 0) { /* DBG("sslinit %s", gnutls_strerror(ret)); */ mem_free(state); return S_SSL_ERROR; } if (gnutls_cred_set(*state, GNUTLS_CRD_ANON, anon_cred) < 0) { /* DBG("sslanoncred %s", gnutls_strerror(ret)); */ gnutls_deinit(*state); mem_free(state); return S_SSL_ERROR; } if (gnutls_cred_set(*state, GNUTLS_CRD_CERTIFICATE, xcred) < 0) { /* DBG("sslx509cred %s", gnutls_strerror(ret)); */ gnutls_deinit(*state); mem_free(state); return S_SSL_ERROR; } #ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT /* Disable OpenPGP certificates because they are not widely * used and ELinks does not yet support verifying them. * Besides, in GnuTLS < 2.4.0, they require the gnutls-extra * library, whose GPLv3+ is not compatible with GPLv2 of * ELinks. * * Disable TLS1.1 because https://bugzilla.novell.com/ does * not reply to it and leaves the connection open so that * ELinks does not detect an SSL error but rather times out. * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=528661#25 * * There is another gnutls_priority_set_direct call elsewhere * in ELinks. If you change the priorities here, please check * whether that one needs to be changed as well. */ if (gnutls_priority_set_direct(*state, "NORMAL:-CTYPE-OPENPGP:-VERS-TLS1.1", NULL)) { gnutls_deinit(*state); mem_free(state); return S_SSL_ERROR; } #else gnutls_set_default_priority(*state); #endif #if 0 /* Deprecated functions */ /* gnutls_handshake_set_private_extensions(*state, 1); */ gnutls_cipher_set_priority(*state, cipher_priority); gnutls_kx_set_priority(*state, kx_priority); /* gnutls_certificate_type_set_priority(*state, cert_type_priority); */ #endif if (server_name && gnutls_server_name_set(*state, GNUTLS_NAME_DNS, server_name, strlen(server_name))) { gnutls_deinit(*state); mem_free(state); return S_SSL_ERROR; } socket->ssl = state; #endif return S_OK; }
static gnutls_session tls_session_init(int side, uschar *expciphers, uschar *expmac, uschar *expkx, uschar *expproto) { gnutls_session session; gnutls_init(&session, side); /* Initialize the lists of permitted protocols, key-exchange methods, ciphers, and MACs. */ memcpy(cipher_priority, default_cipher_priority, sizeof(cipher_priority)); memcpy(mac_priority, default_mac_priority, sizeof(mac_priority)); memcpy(kx_priority, default_kx_priority, sizeof(kx_priority)); memcpy(proto_priority, default_proto_priority, sizeof(proto_priority)); /* The names OpenSSL uses in tls_require_ciphers are of the form DES-CBC3-SHA, using hyphen separators. GnuTLS uses underscore separators. So that I can use either form for tls_require_ciphers in my tests, and also for general convenience, we turn hyphens into underscores before scanning the list. */ if (expciphers != NULL) { uschar *s = expciphers; while (*s != 0) { if (*s == '-') *s = '_'; s++; } } if ((expciphers != NULL && !set_priority(cipher_priority, sizeof(cipher_priority)/sizeof(int), expciphers, cipher_index, sizeof(cipher_index)/sizeof(pri_item), US"cipher")) || (expmac != NULL && !set_priority(mac_priority, sizeof(mac_priority)/sizeof(int), expmac, mac_index, sizeof(mac_index)/sizeof(pri_item), US"MAC")) || (expkx != NULL && !set_priority(kx_priority, sizeof(kx_priority)/sizeof(int), expkx, kx_index, sizeof(kx_index)/sizeof(pri_item), US"key-exchange")) || (expproto != NULL && !set_priority(proto_priority, sizeof(proto_priority)/sizeof(int), expproto, proto_index, sizeof(proto_index)/sizeof(pri_item), US"protocol"))) { gnutls_deinit(session); return NULL; } /* Define the various priorities */ gnutls_cipher_set_priority(session, cipher_priority); gnutls_compression_set_priority(session, comp_priority); gnutls_kx_set_priority(session, kx_priority); gnutls_protocol_set_priority(session, proto_priority); gnutls_mac_set_priority(session, mac_priority); gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); gnutls_dh_set_prime_bits(session, DH_BITS); /* Request or demand a certificate of the peer, as configured. This will happen only in a server. */ if (verify_requirement != VERIFY_NONE) gnutls_certificate_server_set_request(session, (verify_requirement == VERIFY_OPTIONAL)? GNUTLS_CERT_REQUEST : GNUTLS_CERT_REQUIRE); gnutls_db_set_cache_expiration(session, ssl_session_timeout); /* Reduce security in favour of increased compatibility, if the admin decides to make that trade-off. */ if (gnutls_compat_mode) { #if LIBGNUTLS_VERSION_NUMBER >= 0x020104 DEBUG(D_tls) debug_printf("lowering GnuTLS security, compatibility mode\n"); gnutls_session_enable_compatibility_mode(session); #else DEBUG(D_tls) debug_printf("Unable to set gnutls_compat_mode - GnuTLS version too old\n"); #endif } DEBUG(D_tls) debug_printf("initialized GnuTLS session\n"); return session; }
struct connection_state *initialize_gnutls(intptr_t sd, char *name, Pop3 pc, const char *remote_hostname) { static int gnutls_initialized; int zok; struct connection_state *scs = malloc(sizeof(struct connection_state)); memset(scs, 0, sizeof(struct connection_state)); /* clears the unprocessed buffer */ scs->pc = pc; assert(sd >= 0); if (gnutls_initialized == 0) { assert(gnutls_global_init() == 0); gnutls_initialized = 1; } assert(gnutls_init(&scs->tls_state, GNUTLS_CLIENT) == 0); { const char *err_pos; if (GNUTLS_E_SUCCESS != gnutls_priority_set_direct(scs->tls_state, tls, &err_pos)) { DMA(DEBUG_ERROR, "Unable to set the priorities to use on the ciphers, " "key exchange methods, macs and/or compression methods.\n" "See 'tls' parameter in config file: '%s'.\n", err_pos); exit(1); } /* no client private key */ if (gnutls_certificate_allocate_credentials(&scs->xcred) < 0) { DMA(DEBUG_ERROR, "gnutls memory error\n"); exit(1); } /* certfile seems to work. */ if (certificate_filename != NULL) { if (!exists(certificate_filename)) { DMA(DEBUG_ERROR, "Certificate file (certfile=) %s not found.\n", certificate_filename); exit(1); } zok = gnutls_certificate_set_x509_trust_file(scs->xcred, (char *) certificate_filename, GNUTLS_X509_FMT_PEM); if (zok < 0) { DMA(DEBUG_ERROR, "GNUTLS did not like your certificate file %s (%d).\n", certificate_filename, zok); gnutls_perror(zok); exit(1); } } gnutls_cred_set(scs->tls_state, GNUTLS_CRD_CERTIFICATE, scs->xcred); gnutls_transport_set_ptr(scs->tls_state, (gnutls_transport_ptr_t) sd); do { zok = gnutls_handshake(scs->tls_state); } while (zok == GNUTLS_E_INTERRUPTED || zok == GNUTLS_E_AGAIN); tls_check_certificate(scs, remote_hostname); } if (zok < 0) { TDM(DEBUG_ERROR, "%s: Handshake failed\n", name); TDM(DEBUG_ERROR, "%s: This may be a problem in gnutls, " "which is under development\n", name); TDM(DEBUG_ERROR, "%s: This copy of wmbiff was compiled with \n" " gnutls version %s.\n", name, LIBGNUTLS_VERSION); gnutls_perror(zok); if (scs->pc->u.pop_imap.serverPort != 143 /* starttls */ ) { TDM(DEBUG_ERROR, "%s: Please run 'gnutls-cli-debug -p %d %s' to test ssl directly.\n" " That tool provides a lower-level test of gnutls with your server.\n", name, scs->pc->u.pop_imap.serverPort, remote_hostname); } gnutls_deinit(scs->tls_state); free(scs); return (NULL); } else { TDM(DEBUG_INFO, "%s: Handshake was completed\n", name); if (scs->pc->debug >= DEBUG_INFO) print_info(scs->tls_state, remote_hostname); scs->sd = sd; scs->name = name; } return (scs); }