Beispiel #1
0
/* tls_negotiate: After TLS state has been initialised, attempt to negotiate
 *   TLS over the wire, including certificate checks. */
static int tls_negotiate (CONNECTION * conn)
{
  tlssockdata *data;
  int err;
  size_t nproto = 0; /* number of tls/ssl protocols */

  data = (tlssockdata *) safe_calloc (1, sizeof (tlssockdata));
  conn->sockdata = data;
  err = gnutls_certificate_allocate_credentials (&data->xcred);
  if (err < 0)
  {
    FREE(&conn->sockdata);
    mutt_error ("gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err));
    mutt_sleep (2);
    return -1;
  }

  gnutls_certificate_set_x509_trust_file (data->xcred, SslCertFile,
					  GNUTLS_X509_FMT_PEM);
  /* ignore errors, maybe file doesn't exist yet */

  if (SslCACertFile)
  {
    gnutls_certificate_set_x509_trust_file (data->xcred, SslCACertFile,
                                            GNUTLS_X509_FMT_PEM);
  }

  if (SslClientCert)
  {
    dprint (2, (debugfile, "Using client certificate %s\n", SslClientCert));
    gnutls_certificate_set_x509_key_file (data->xcred, SslClientCert,
                                          SslClientCert, GNUTLS_X509_FMT_PEM);
  }

#if HAVE_DECL_GNUTLS_VERIFY_DISABLE_TIME_CHECKS
  /* disable checking certificate activation/expiration times
     in gnutls, we do the checks ourselves */
  gnutls_certificate_set_verify_flags(data->xcred, GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
#endif

  if ((err = gnutls_init(&data->state, GNUTLS_CLIENT)))
  {
    mutt_error ("gnutls_handshake: %s", gnutls_strerror(err));
    mutt_sleep (2);
    goto fail;
  }

  /* set socket */
  gnutls_transport_set_ptr (data->state, (gnutls_transport_ptr)conn->fd);

  if (option(OPTTLSV1_2))
    protocol_priority[nproto++] = GNUTLS_TLS1_2;
  if (option(OPTTLSV1_1))
    protocol_priority[nproto++] = GNUTLS_TLS1_1;
  if (option(OPTTLSV1))
    protocol_priority[nproto++] = GNUTLS_TLS1;
  if (option(OPTSSLV3))
    protocol_priority[nproto++] = GNUTLS_SSL3;
  protocol_priority[nproto] = 0;

  /* disable TLS/SSL protocols as needed */
  if (nproto == 0)
  {
    mutt_error (_("All available protocols for TLS/SSL connection disabled"));
    goto fail;
  }
  /*
  else
    use the list set above
  */

  /* We use default priorities (see gnutls documentation),
     except for protocol version */
  gnutls_set_default_priority (data->state);
  gnutls_protocol_set_priority (data->state, protocol_priority);

  if (SslDHPrimeBits > 0)
  {
    gnutls_dh_set_prime_bits (data->state, SslDHPrimeBits);
  }

/*
  gnutls_set_cred (data->state, GNUTLS_ANON, NULL);
*/

  gnutls_credentials_set (data->state, GNUTLS_CRD_CERTIFICATE, data->xcred);

  err = gnutls_handshake(data->state);

  while (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED)
  {
    err = gnutls_handshake(data->state);
  }
  if (err < 0) {
    if (err == GNUTLS_E_FATAL_ALERT_RECEIVED)
    {
      mutt_error("gnutls_handshake: %s(%s)", gnutls_strerror(err),
		 gnutls_alert_get_name(gnutls_alert_get(data->state)));
    }
    else
    {
      mutt_error("gnutls_handshake: %s", gnutls_strerror(err));
    }
    mutt_sleep (2);
    goto fail;
  }

  if (!tls_check_certificate(conn))
    goto fail;

  /* set Security Strength Factor (SSF) for SASL */
  /* NB: gnutls_cipher_get_key_size() returns key length in bytes */
  conn->ssf = gnutls_cipher_get_key_size (gnutls_cipher_get (data->state)) * 8;

  tls_get_client_cert (conn);

  if (!option(OPTNOCURSES)) {
    mutt_message (_("SSL/TLS connection using %s (%s/%s/%s)"),
                  gnutls_protocol_get_name (gnutls_protocol_get_version (data->state)),
                  gnutls_kx_get_name (gnutls_kx_get (data->state)),
                  gnutls_cipher_get_name (gnutls_cipher_get (data->state)),
                  gnutls_mac_get_name (gnutls_mac_get (data->state)));
    mutt_sleep (0);
  }

  return 0;

 fail:
  gnutls_certificate_free_credentials (data->xcred);
  gnutls_deinit (data->state);
  FREE(&conn->sockdata);
  return -1;
}
Beispiel #2
0
/**
 * tls_negotiate - Negotiate TLS connection
 * @param conn Connection to a server
 * @retval  0 Success
 * @retval -1 Error
 *
 * After TLS state has been initialized, attempt to negotiate TLS over the
 * wire, including certificate checks.
 */
static int tls_negotiate(struct Connection *conn)
{
  struct TlsSockData *data = mutt_mem_calloc(1, sizeof(struct TlsSockData));
  conn->sockdata = data;
  int err = gnutls_certificate_allocate_credentials(&data->xcred);
  if (err < 0)
  {
    FREE(&conn->sockdata);
    mutt_error("gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err));
    return -1;
  }

  gnutls_certificate_set_x509_trust_file(data->xcred, C_CertificateFile, GNUTLS_X509_FMT_PEM);
  /* ignore errors, maybe file doesn't exist yet */

  if (C_SslCaCertificatesFile)
  {
    gnutls_certificate_set_x509_trust_file(data->xcred, C_SslCaCertificatesFile,
                                           GNUTLS_X509_FMT_PEM);
  }

  if (C_SslClientCert)
  {
    mutt_debug(LL_DEBUG2, "Using client certificate %s\n", C_SslClientCert);
    gnutls_certificate_set_x509_key_file(data->xcred, C_SslClientCert,
                                         C_SslClientCert, GNUTLS_X509_FMT_PEM);
  }

#ifdef HAVE_DECL_GNUTLS_VERIFY_DISABLE_TIME_CHECKS
  /* disable checking certificate activation/expiration times
   * in gnutls, we do the checks ourselves */
  gnutls_certificate_set_verify_flags(data->xcred, GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
#endif

  err = gnutls_init(&data->state, GNUTLS_CLIENT);
  if (err)
  {
    mutt_error("gnutls_handshake: %s", gnutls_strerror(err));
    goto fail;
  }

  /* set socket */
  gnutls_transport_set_ptr(data->state, (gnutls_transport_ptr_t)(long) conn->fd);

  if (gnutls_server_name_set(data->state, GNUTLS_NAME_DNS, conn->account.host,
                             mutt_str_strlen(conn->account.host)))
  {
    mutt_error(_("Warning: unable to set TLS SNI host name"));
  }

  if (tls_set_priority(data) < 0)
  {
    goto fail;
  }

  if (C_SslMinDhPrimeBits > 0)
  {
    gnutls_dh_set_prime_bits(data->state, C_SslMinDhPrimeBits);
  }

  /* gnutls_set_cred (data->state, GNUTLS_ANON, NULL); */

  gnutls_credentials_set(data->state, GNUTLS_CRD_CERTIFICATE, data->xcred);

  err = gnutls_handshake(data->state);

  while (err == GNUTLS_E_AGAIN)
  {
    err = gnutls_handshake(data->state);
  }
  if (err < 0)
  {
    if (err == GNUTLS_E_FATAL_ALERT_RECEIVED)
    {
      mutt_error("gnutls_handshake: %s(%s)", gnutls_strerror(err),
                 gnutls_alert_get_name(gnutls_alert_get(data->state)));
    }
    else
    {
      mutt_error("gnutls_handshake: %s", gnutls_strerror(err));
    }
    goto fail;
  }

  if (tls_check_certificate(conn) == 0)
    goto fail;

  /* set Security Strength Factor (SSF) for SASL */
  /* NB: gnutls_cipher_get_key_size() returns key length in bytes */
  conn->ssf = gnutls_cipher_get_key_size(gnutls_cipher_get(data->state)) * 8;

  tls_get_client_cert(conn);

  if (!OptNoCurses)
  {
    mutt_message(_("SSL/TLS connection using %s (%s/%s/%s)"),
                 gnutls_protocol_get_name(gnutls_protocol_get_version(data->state)),
                 gnutls_kx_get_name(gnutls_kx_get(data->state)),
                 gnutls_cipher_get_name(gnutls_cipher_get(data->state)),
                 gnutls_mac_get_name(gnutls_mac_get(data->state)));
    mutt_sleep(0);
  }

  return 0;

fail:
  gnutls_certificate_free_credentials(data->xcred);
  gnutls_deinit(data->state);
  FREE(&conn->sockdata);
  return -1;
}
Beispiel #3
0
/*-------------------------------------------------------------------------*/
svalue_t *
f_tls_check_certificate(svalue_t *sp)

/* EFUN tls_check_certificate()
 *
 *   mixed *tls_check_certificate(object obj);
 *   mixed *tls_check_certificate(object obj, int extra);
 * 
 * tls_check_certificate() checks the certificate of the secured
 * connection bound to <obj> (default is the current object).  If
 * <obj> is not interactive, or if TLS is not available, an error
 * is thrown.
 * 
 * If <obj> doesn't have a secure connection up and running, an
 * error is thrown.
 * Otherwise, the result is an array with these values:
 * 
 *   int [0]      : Result code of SSL_get_verify_result (see man 1 verify
 *                  subsection DIAGNOSTICS for possible values)
 *   array [1]          : array with 3*n entries of extra x509 data.
 *                       structure is:
 *                       3*i    : numerical form of object name, e.g. "2.5.4.3"
 *                       3*i + 1: long or short name if available, e.g. "commonName"
 *                       3*i + 2: value
 *   array [2]          : if extra is set:
 *                       array with 3*n entries of x509 extension data
 *                       data structure is:
 *                       3*i    : numerical form of extension name
 *                       3*i + 1: long or short name of extension name if available
 *                       3*i + 2: array of strings with the data structure of [1]
 *
 * Note: a x509 certificate can have more than one object with the same name
 *
 * See associated documentation for code that generates more convient mapping
 * data structures
 */

{
    vector_t *v = NULL;
    interactive_t *ip;
    int more;

    /* more information requested */
    more = sp->u.number;
    free_svalue(sp--);

    if (!tls_available())
        errorf("tls_check_certificate(): TLS layer hasn't been initialized.\n");

    if (!O_SET_INTERACTIVE(ip, sp->u.ob))
        errorf("Bad arg 1 to tls_check_certificate(): "
              "object not interactive.\n");

    if (ip->tls_status != TLS_ACTIVE) 
        errorf("tls_check_certificate(): object doesn't have a secure connection.\n");

    if (more < 0 || more > 1)
        errorf("tls_check_certificate(): invalid flag passed as second argument.\n");

    v = tls_check_certificate(ip, (more == 1) ? MY_TRUE : MY_FALSE);

    free_svalue(sp);

    if (v != NULL)
        put_array(sp, v);
    else
        put_number(sp, 0);
    return sp;
} /* tls_check_certificate() */
Beispiel #4
0
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);
}