Beispiel #1
0
static int verify_certificate_callback (gnutls_session_t session)
{
  if (trust_override)
    return 0;

  // This verification function uses the trusted CAs in the credentials
  // structure. So you must have installed one or more CA certificates.
  unsigned int status = 0;
#if GNUTLS_VERSION_NUMBER >= 0x030104
  int ret = gnutls_certificate_verify_peers3 (session, NULL, &status);
#else
  int ret = gnutls_certificate_verify_peers2 (session, &status);
#endif
  if (ret < 0)
    return GNUTLS_E_CERTIFICATE_ERROR;

#if GNUTLS_VERSION_NUMBER >= 0x030105
  gnutls_certificate_type_t type = gnutls_certificate_type_get (session);
  gnutls_datum_t out;
  ret = gnutls_certificate_verification_status_print (status, type, &out, 0);
  if (ret < 0)
    return GNUTLS_E_CERTIFICATE_ERROR;

  gnutls_free (out.data);
#endif

  if (status != 0)
    return GNUTLS_E_CERTIFICATE_ERROR;

  // Continue handshake.
  return 0;
}
Beispiel #2
0
/* sanity-checking wrapper for gnutls_certificate_verify_peers */
static gnutls_certificate_status tls_verify_peers (gnutls_session tlsstate)
{
  int verify_ret;
  unsigned int status;

  verify_ret = gnutls_certificate_verify_peers2 (tlsstate, &status);
  if (!verify_ret)
    return status;

  if (status == GNUTLS_E_NO_CERTIFICATE_FOUND)
  {
    mutt_error (_("Unable to get certificate from peer"));
    mutt_sleep (2);
    return 0;
  }
  if (verify_ret < 0)
  {
    mutt_error (_("Certificate verification error (%s)"),
                gnutls_strerror (status));
    mutt_sleep (2);
    return 0;
  }

  /* We only support X.509 certificates (not OpenPGP) at the moment */
  if (gnutls_certificate_type_get (tlsstate) != GNUTLS_CRT_X509)
  {
    mutt_error (_("Certificate is not X.509"));
    mutt_sleep (2);
    return 0;
  }

  return status;
}
Beispiel #3
0
int main(int argc, char const* argv[])
{
    int ret;
    int tls_status;
    state_t *handle = (state_t *)malloc(sizeof(state_t));

    ret = gnutls_certificate_verify_peers2(handle->gnutls_state, &tls_status);
    if ((ret < 0) || tls_status) {
        int flag_continue = 1;
        char *msg2;

        if (tls_status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
            msg2 = gettext("no issuer was found");
        } else if (tls_status & GNUTLS_CERT_SIGNER_NOT_CA) {
            msg2 = gettext("issuer is not a CA");
        } else if (tls_status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
            msg2 = gettext("the certificate has no known issuer");
        } else if (tls_status & GNUTLS_CERT_REVOKED) {
            msg2 = gettext("the certificate has been revoked");
        } else {
            msg2 = gettext("the certificate is not trusted");
        }
    }

    return 0;
}
Beispiel #4
0
static int verify_certificate_callback( gnutls_session_t session )
{
	unsigned int status;
	const gnutls_datum_t *cert_list;
	unsigned int cert_list_size;
	int gnutlsret;
	int verifyret = 0;
	gnutls_x509_crt_t cert;
	const char *hostname;
	
	hostname = gnutls_session_get_ptr( session );

	gnutlsret = gnutls_certificate_verify_peers2( session, &status );
	if( gnutlsret < 0 )
		return VERIFY_CERT_ERROR;

	if( status & GNUTLS_CERT_INVALID )
		verifyret |= VERIFY_CERT_INVALID;

	if( status & GNUTLS_CERT_REVOKED )
		verifyret |= VERIFY_CERT_REVOKED;

	if( status & GNUTLS_CERT_SIGNER_NOT_FOUND )
		verifyret |= VERIFY_CERT_SIGNER_NOT_FOUND;

	if( status & GNUTLS_CERT_SIGNER_NOT_CA )
		verifyret |= VERIFY_CERT_SIGNER_NOT_CA;

	if( status & GNUTLS_CERT_INSECURE_ALGORITHM )
		verifyret |= VERIFY_CERT_INSECURE_ALGORITHM;

#ifdef GNUTLS_CERT_NOT_ACTIVATED
	/* Amusingly, the GnuTLS function used above didn't check for expiry
	   until GnuTLS 2.8 or so. (See CVE-2009-1417) */
	if( status & GNUTLS_CERT_NOT_ACTIVATED )
		verifyret |= VERIFY_CERT_NOT_ACTIVATED;

	if( status & GNUTLS_CERT_EXPIRED )
		verifyret |= VERIFY_CERT_EXPIRED;
#endif

	if( gnutls_certificate_type_get( session ) != GNUTLS_CRT_X509 || gnutls_x509_crt_init( &cert ) < 0 )
		return VERIFY_CERT_ERROR;

	cert_list = gnutls_certificate_get_peers( session, &cert_list_size );
	if( cert_list == NULL || gnutls_x509_crt_import( cert, &cert_list[0], GNUTLS_X509_FMT_DER ) < 0 )
		return VERIFY_CERT_ERROR;

	if( !gnutls_x509_crt_check_hostname( cert, hostname ) )
	{
		verifyret |= VERIFY_CERT_INVALID;
		verifyret |= VERIFY_CERT_WRONG_HOSTNAME;
	}

	gnutls_x509_crt_deinit( cert );

	return verifyret;
}
Beispiel #5
0
/* Verifies an SSL server certificate. */
static int check_certificate(ne_session *sess, gnutls_session sock,
                             ne_ssl_certificate *chain)
{
    int ret, failures = 0;
    ne_uri server;
    unsigned int status;

    memset(&server, 0, sizeof server);
    ne_fill_server_uri(sess, &server);
    ret = check_identity(&server, chain->subject, NULL);
    ne_uri_free(&server);

    if (ret < 0) {
        ne_set_error(sess, _("Server certificate was missing commonName "
                             "attribute in subject name"));
        return NE_ERROR;
    } 
    else if (ret > 0) {
        failures |= NE_SSL_IDMISMATCH;
    }
    
    failures |= check_chain_expiry(chain);

    ret = gnutls_certificate_verify_peers2(sock, &status);
    NE_DEBUG(NE_DBG_SSL, "ssl: Verify peers returned %d, status=%u\n", 
             ret, status);
    if (ret != GNUTLS_E_SUCCESS) {
        ne_set_error(sess, _("Could not verify server certificate: %s"),
                     gnutls_strerror(ret));
        return NE_ERROR;
    }

    failures |= map_verify_failures(&status);

    NE_DEBUG(NE_DBG_SSL, "ssl: Verification failures = %d (status = %u).\n", 
             failures, status);
    
    if (status && status != GNUTLS_CERT_INVALID) {
        char *errstr = verify_error_string(status);
        ne_set_error(sess, _("Certificate verification error: %s"), errstr);
        ne_free(errstr);       
        return NE_ERROR;
    }

    if (failures == 0) {
        ret = NE_OK;
    } else {
        ne__ssl_set_verify_err(sess, failures);
        ret = NE_ERROR;
        if (sess->ssl_verify_fn
            && sess->ssl_verify_fn(sess->ssl_verify_ud, failures, chain) == 0)
            ret = NE_OK;
    }

    return ret;
}
Beispiel #6
0
static void ssl_vfy_ca(struct sockifo* ifo) {
	unsigned int status = 0;
	if (gnutls_certificate_verify_peers2(ifo->ssl, &status)) {
		esock(ifo, "Error in peer verification");
	} else if (status & GNUTLS_CERT_INVALID) {
		esock(ifo, "Certificate Invalid");
	} else if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
		esock(ifo, "Certificate Signer not found");
	} else if (status) {
		esock(ifo, "Other certificate verification error");
	}
}
Beispiel #7
0
static void
print_cert_vrfy (gnutls_session_t session)
{
  int rc;
  unsigned int status;

  rc = gnutls_certificate_verify_peers2 (session, &status);
  if (rc < 0)
    {
      printf ("- Could not verify certificate (err: %s)\n",
              gnutls_strerror (rc));
      return;
    }

  if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND)
    {
      printf ("- Peer did not send any certificate.\n");
      return;
    }

  if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
    {
      if (status & GNUTLS_CERT_REVOKED)
        printf ("- Peer's certificate chain revoked\n");
      if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
        printf ("- Peer's certificate issuer is unknown\n");
      if (status & GNUTLS_CERT_SIGNER_NOT_CA)
        printf ("- Peer's certificate issuer is not a CA\n");
      if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
        printf ("- Peer's certificate chain uses insecure algorithm\n");
      if (status & GNUTLS_CERT_NOT_ACTIVATED)
        printf
          ("- Peer's certificate chain uses not yet valid certificate\n");
      if (status & GNUTLS_CERT_EXPIRED)
        printf ("- Peer's certificate chain uses expired certificate\n");
      if (status & GNUTLS_CERT_INVALID)
        printf ("- Peer's certificate is NOT trusted\n");
      else
        printf ("- Peer's certificate is trusted\n");
    }
  else
    {
      if (status & GNUTLS_CERT_INVALID)
        printf ("- Peer's key is invalid\n");
      else
        printf ("- Peer's key is valid\n");
      if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
        printf ("- Could not find a signer of the peer's key\n");
    }
}
Beispiel #8
0
/**
  * gnutls_certificate_verify_peers - This function returns the peer's certificate verification status
  * @session: is a gnutls session
  *
  * This function will try to verify the peer's certificate and return
  * its status (trusted, invalid etc.).  However you must also check
  * the peer's name in order to check if the verified certificate
  * belongs to the actual peer.
  *
  * The return value should be one or more of the
  * gnutls_certificate_status_t enumerated elements bitwise or'd, or a
  * negative value on error.
  *
  * This is the same as gnutls_x509_crt_list_verify().
  *
  * Deprecated: Use gnutls_certificate_verify_peers2() instead.
  **/
int
gnutls_certificate_verify_peers (gnutls_session_t session)
{
  unsigned int status;
  int ret;

  ret = gnutls_certificate_verify_peers2 (session, &status);

  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  return status;
}
Beispiel #9
0
    int TLSSocket::verify(VerifyResult& result) {
        const char* hostname = (const char*) gnutls_session_get_ptr (session);

        unsigned int status;
        int ret = gnutls_certificate_verify_peers2 (session, &status);
        if (ret < 0) {
            return -1;
        }

        result.distrusted    = (status & GNUTLS_CERT_INVALID);
        result.unknownIssuer = (status & GNUTLS_CERT_SIGNER_NOT_FOUND);
        result.revoked       = (status & GNUTLS_CERT_REVOKED);
        result.expired       = (status & GNUTLS_CERT_EXPIRED);
        result.inactive      = (status & GNUTLS_CERT_NOT_ACTIVATED);
        result.invalidCert   = false;
        if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) {
            result.invalidCert = true;
            return -1;
        }

        gnutls_x509_crt_t cert;
        if (gnutls_x509_crt_init (&cert) < 0) {
            return -1;
        }

        const gnutls_datum_t *cert_list;
        unsigned int cert_list_size;
        cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
        if (cert_list == NULL) {
            result.invalidCert = true;
            gnutls_x509_crt_deinit (cert);
            return -1;
        }

        if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0){
            result.invalidCert = true;
            gnutls_x509_crt_deinit (cert);
            return -1;
        }

        result.hostnameMismatch = !gnutls_x509_crt_check_hostname (cert, hostname);
        gnutls_x509_crt_deinit (cert);

        return 0;
    }
Beispiel #10
0
static int
cert_verify_callback (gnutls_session_t session)
{
  int rc;
  unsigned int status;

  if (!x509_cafile && !pgp_keyring)
    return 0;

  rc = gnutls_certificate_verify_peers2 (session, &status);
  if (rc != 0 || status != 0)
    {
      printf ("*** Verifying server certificate failed...\n");
      if (!insecure)
	return -1;
    }

  return 0;
}
Beispiel #11
0
/* Certs are not automatically varified during the handshake */
static int
tlsg_cert_verify( tlsg_session *ssl )
{
	unsigned int status = 0;
	int err;
	time_t now = time(0);
	time_t peertime;

	err = gnutls_certificate_verify_peers2( ssl->session, &status );
	if ( err < 0 ) {
		Debug( LDAP_DEBUG_ANY,"TLS: gnutls_certificate_verify_peers2 failed %d\n",
			err,0,0 );
		return -1;
	}
	if ( status ) {
		Debug( LDAP_DEBUG_TRACE,"TLS: peer cert untrusted or revoked (0x%x)\n",
			status, 0,0 );
		return -1;
	}
	peertime = gnutls_certificate_expiration_time_peers( ssl->session );
	if ( peertime == (time_t) -1 ) {
		Debug( LDAP_DEBUG_ANY, "TLS: gnutls_certificate_expiration_time_peers failed\n",
			0, 0, 0 );
		return -1;
	}
	if ( peertime < now ) {
		Debug( LDAP_DEBUG_ANY, "TLS: peer certificate is expired\n",
			0, 0, 0 );
		return -1;
	}
	peertime = gnutls_certificate_activation_time_peers( ssl->session );
	if ( peertime == (time_t) -1 ) {
		Debug( LDAP_DEBUG_ANY, "TLS: gnutls_certificate_activation_time_peers failed\n",
			0, 0, 0 );
		return -1;
	}
	if ( peertime > now ) {
		Debug( LDAP_DEBUG_ANY, "TLS: peer certificate not yet active\n",
			0, 0, 0 );
		return -1;
	}
	return 0;
}
Beispiel #12
0
static int verify_cert_authorized(gnutls_session_t session) {
        unsigned status;
        gnutls_certificate_type_t type;
        gnutls_datum_t out;
        int r;

        r = gnutls_certificate_verify_peers2(session, &status);
        if (r < 0)
                return log_error_errno(r, "gnutls_certificate_verify_peers2 failed: %m");

        type = gnutls_certificate_type_get(session);
        r = gnutls_certificate_verification_status_print(status, type, &out, 0);
        if (r < 0)
                return log_error_errno(r, "gnutls_certificate_verification_status_print failed: %m");

        log_info("Certificate status: %s", out.data);

        return status == 0 ? 0 : -EPERM;
}
Beispiel #13
0
static int
do_handshake (socket_st * socket)
{
  int ret;
  gnutls_transport_set_ptr (socket->session,
			    (gnutls_transport_ptr) socket->fd);
  do
    {
      ret = gnutls_handshake (socket->session);

      if (ret < 0)
	{
	  handle_error (socket, ret);
	}
    }
  while (ret < 0 && gnutls_error_is_fatal (ret) == 0);

  if (ret == 0)
    {
      /* print some information */
      print_info (socket->session, socket->hostname);

      if ((x509_cafile || pgp_trustdb) && !insecure)
	{
	  int rc;
	  unsigned int status;

	  /* abort if verification fail  */
	  rc = gnutls_certificate_verify_peers2 (socket->session, &status);
	  if (rc != 0 || status != 0)
	    {
	      printf ("*** Verifying server certificate failed...\n");
	      exit (1);
	    }
	}

      socket->secure = 1;

    }
  return ret;
}
Beispiel #14
0
/* The actual verification callback. */
static int auto_verify_cb(gnutls_session_t session)
{
        unsigned int status;
        int ret;

        if (session->internals.vc_elements == 0) {
        	ret = gnutls_certificate_verify_peers2(session, &status);
	} else {
	        ret = gnutls_certificate_verify_peers(session, session->internals.vc_data,
						      session->internals.vc_elements, &status);
        }
        if (ret < 0) {
                return gnutls_assert_val(GNUTLS_E_CERTIFICATE_ERROR);
        }

        session->internals.vc_status = status;

        if (status != 0)        /* Certificate is not trusted */
                return gnutls_assert_val(GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR);

        /* notify gnutls to continue handshake normally */
        return 0;
}
Beispiel #15
0
static int
_verify_certificate_callback (gnutls_session_t session)
{
  unsigned int status;
  const gnutls_datum_t *cert_list;
  unsigned int cert_list_size;
  int ret;
  gnutls_x509_crt_t cert;

  ret = gnutls_certificate_verify_peers2 (session, &status);
  if (ret < 0)
    return GNUTLS_E_CERTIFICATE_ERROR;

  if (status & GNUTLS_CERT_INVALID ||
      status & GNUTLS_CERT_SIGNER_NOT_FOUND ||
      status & GNUTLS_CERT_REVOKED ||
      status & GNUTLS_CERT_EXPIRED ||
      status & GNUTLS_CERT_NOT_ACTIVATED)
    return GNUTLS_E_CERTIFICATE_ERROR;

  if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509)
    return GNUTLS_E_CERTIFICATE_ERROR;

  if (gnutls_x509_crt_init (&cert) < 0)
    return GNUTLS_E_CERTIFICATE_ERROR;

  cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
  if (cert_list == NULL)
    return GNUTLS_E_CERTIFICATE_ERROR;

  if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
    return GNUTLS_E_CERTIFICATE_ERROR;

  gnutls_x509_crt_deinit (cert);

  return 0;
}
static int tls_connection_verify_peer(struct tls_connection *conn)
{
	unsigned int status, num_certs, i;
	struct os_time now;
	const gnutls_datum_t *certs;
	gnutls_x509_crt_t cert;

	if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
			   "certificate chain");
		return -1;
	}

	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
		return -1;
	}

	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
			   "known issuer");
		return -1;
	}

	if (status & GNUTLS_CERT_REVOKED) {
		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
		return -1;
	}

	os_get_time(&now);

	certs = gnutls_certificate_get_peers(conn->session, &num_certs);
	if (certs == NULL) {
		wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
			   "received");
		return -1;
	}

	for (i = 0; i < num_certs; i++) {
		char *buf;
		size_t len;
		if (gnutls_x509_crt_init(&cert) < 0) {
			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
				   "failed");
			return -1;
		}

		if (gnutls_x509_crt_import(cert, &certs[i],
					   GNUTLS_X509_FMT_DER) < 0) {
			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
				   "certificate %d/%d", i + 1, num_certs);
			gnutls_x509_crt_deinit(cert);
			return -1;
		}

		gnutls_x509_crt_get_dn(cert, NULL, &len);
		len++;
		buf = os_malloc(len + 1);
		if (buf) {
			buf[0] = buf[len] = '\0';
			gnutls_x509_crt_get_dn(cert, buf, &len);
		}
		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
			   i + 1, num_certs, buf);

		if (i == 0) {
			/* TODO: validate subject_match and altsubject_match */
		}

		os_free(buf);

		if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
		    gnutls_x509_crt_get_activation_time(cert) > now.sec) {
			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
				   "not valid at this time",
				   i + 1, num_certs);
			gnutls_x509_crt_deinit(cert);
			return -1;
		}

		gnutls_x509_crt_deinit(cert);
	}

	return 0;
}
Beispiel #17
0
	void VerifyCertificate(issl_session* session, StreamSocket* user)
	{
		if (!session->sess || !user)
			return;

		unsigned int status;
		const gnutls_datum_t* cert_list;
		int ret;
		unsigned int cert_list_size;
		gnutls_x509_crt_t cert;
		char str[512];
		unsigned char digest[512];
		size_t digest_size = sizeof(digest);
		size_t name_size = sizeof(str);
		ssl_cert* certinfo = new ssl_cert;
		session->cert = certinfo;

		/* This verification function uses the trusted CAs in the credentials
		 * structure. So you must have installed one or more CA certificates.
		 */
		ret = gnutls_certificate_verify_peers2(session->sess, &status);

		if (ret < 0)
		{
			certinfo->error = std::string(gnutls_strerror(ret));
			return;
		}

		certinfo->invalid = (status & GNUTLS_CERT_INVALID);
		certinfo->unknownsigner = (status & GNUTLS_CERT_SIGNER_NOT_FOUND);
		certinfo->revoked = (status & GNUTLS_CERT_REVOKED);
		certinfo->trusted = !(status & GNUTLS_CERT_SIGNER_NOT_CA);

		/* Up to here the process is the same for X.509 certificates and
		 * OpenPGP keys. From now on X.509 certificates are assumed. This can
		 * be easily extended to work with openpgp keys as well.
		 */
		if (gnutls_certificate_type_get(session->sess) != GNUTLS_CRT_X509)
		{
			certinfo->error = "No X509 keys sent";
			return;
		}

		ret = gnutls_x509_crt_init(&cert);
		if (ret < 0)
		{
			certinfo->error = gnutls_strerror(ret);
			return;
		}

		cert_list_size = 0;
		cert_list = gnutls_certificate_get_peers(session->sess, &cert_list_size);
		if (cert_list == NULL)
		{
			certinfo->error = "No certificate was found";
			goto info_done_dealloc;
		}

		/* This is not a real world example, since we only check the first
		 * certificate in the given chain.
		 */

		ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
		if (ret < 0)
		{
			certinfo->error = gnutls_strerror(ret);
			goto info_done_dealloc;
		}

		gnutls_x509_crt_get_dn(cert, str, &name_size);
		certinfo->dn = str;

		gnutls_x509_crt_get_issuer_dn(cert, str, &name_size);
		certinfo->issuer = str;

		if ((ret = gnutls_x509_crt_get_fingerprint(cert, hash, digest, &digest_size)) < 0)
		{
			certinfo->error = gnutls_strerror(ret);
		}
		else
		{
			certinfo->fingerprint = BinToHex(digest, digest_size);
		}

		/* Beware here we do not check for errors.
		 */
		if ((gnutls_x509_crt_get_expiration_time(cert) < ServerInstance->Time()) || (gnutls_x509_crt_get_activation_time(cert) > ServerInstance->Time()))
		{
			certinfo->error = "Not activated, or expired certificate";
		}

info_done_dealloc:
		gnutls_x509_crt_deinit(cert);
	}
Beispiel #18
0
/** Handles one client.
 * This one connects to the remote server, and proxies every traffic
 * between our client and the server.
 *
 * @param config is the main CryWrap configuration structure.
 * @param insock is the socket through which the client sends input.
 * @param outsock is the socket through which we send output.
 *
 * @note Exits on error.
 */
static int
_crywrap_do_one(const crywrap_config_t * config, int insock, int outsock)
{
	int sock, ret, tls_pending;
	gnutls_session_t session;
	char buffer[_CRYWRAP_MAXBUF + 2];
	fd_set fdset;
	unsigned int status = 0;
	struct sockaddr_storage faddr;
	socklen_t socklen = sizeof(struct sockaddr_storage);
	char peer_name[NI_MAXHOST];

	/* Log the connection */
	if (getpeername(insock, (struct sockaddr *) &faddr, &socklen) != 0)
		cry_error("getpeername(): %s", strerror(errno));
	else {
		getnameinfo((struct sockaddr *) &faddr,
			    sizeof(struct sockaddr_storage), peer_name,
			    sizeof(peer_name), NULL, 0, NI_NUMERICHOST);
		cry_log("Accepted connection from %s on %d to %s/%d",
			peer_name, insock, config->dest.host,
			config->dest.port);
	}

	/* Do the handshake with our peer */
	session = _crywrap_tls_session_create(config);
	gnutls_transport_set_ptr2(session,
				  (gnutls_transport_ptr_t) insock,
				  (gnutls_transport_ptr_t) outsock);

	do {
		ret = gnutls_handshake(session);
	}
	while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);

	if (ret < 0) {
		cry_error("Handshake failed: %s", gnutls_strerror(ret));
		gnutls_alert_send_appropriate(session, ret);
		goto error;
	}

	/* Verify the client's certificate, if any. */
	if (config->verify) {
		ret = gnutls_certificate_verify_peers2(session, &status);
		if (ret < 0)
			cry_log
			    ("Error getting certificate from client: %s",
			     gnutls_strerror(ret));

		if (ret == 0 && status != 0) {
			if (status & GNUTLS_CERT_INVALID)
				cry_log("%s",
					"Client certificate not trusted or invalid");
		}

		if (config->verify > 0 && status != 0) {
			ret = -1;
			gnutls_alert_send(session, GNUTLS_AL_FATAL,
					  GNUTLS_A_INSUFFICIENT_SECURITY);
			goto error;
		}
	}

	/* Connect to the remote host */
	sock = _crywrap_remote_connect(config->dest.addr,
				       htons(config->dest.port));

	for (;;) {
		FD_ZERO(&fdset);
		FD_SET(insock, &fdset);
		FD_SET(sock, &fdset);

		memset(buffer, 0, _CRYWRAP_MAXBUF + 1);

		tls_pending = 0;

		if (gnutls_record_check_pending(session) > 0)
			tls_pending = 1;
		else {
			select(sock + 1, &fdset, NULL, NULL, NULL);
			if (FD_ISSET(insock, &fdset))
				tls_pending = 1;
		}
		/* TLS client */
		if (tls_pending != 0) {
			ret =
			    gnutls_record_recv(session, buffer,
					       _CRYWRAP_MAXBUF);
			if (ret == 0) {
				cry_log("%s",
					"Peer has closed the GNUTLS connection");
				break;
			} else if (ret < 0) {
				cry_log("Received corrupted data: %s.",
					gnutls_strerror(ret));
				break;
			} else
				send(sock, buffer, ret, 0);
		}

		/* Remote server */
		if (FD_ISSET(sock, &fdset)) {
			ret = recv(sock, buffer, _CRYWRAP_MAXBUF, 0);
			if (ret == 0) {
				cry_log("%s",
					"Server has closed the connection");
				break;
			} else if (ret < 0) {
				cry_log("Received corrupted data: %s.",
					strerror(errno));
				break;
			} else {
				int r, o = 0;

				do {
					r = gnutls_record_send(session,
							       &buffer[o],
							       ret - o);
					o += r;
				} while (r > 0 && ret > o);

				if (r < 0)
					cry_log
					    ("Received corrupt data: %s",
					     gnutls_strerror(r));
			}
		}
	}

      error:
	gnutls_bye(session, GNUTLS_SHUT_WR);
	gnutls_deinit(session);
	close(insock);
	close(outsock);

	return (ret == 0) ? 0 : 1;
}
Beispiel #19
0
int CTlsSocket::VerifyCertificate()
{
	if (m_tlsState != handshake)
	{
		m_pOwner->LogMessage(::Debug_Warning, _T("VerifyCertificate called at wrong time"));
		return FZ_REPLY_ERROR;
	}

	m_tlsState = verifycert;

	if (gnutls_certificate_type_get(m_session) != GNUTLS_CRT_X509)
	{
		m_pOwner->LogMessage(::Error, _("Unsupported certificate type"));
		Failure(0, ECONNABORTED);
		return FZ_REPLY_ERROR;
	}

	unsigned int status = 0;
	if (gnutls_certificate_verify_peers2(m_session, &status) < 0)
	{
		m_pOwner->LogMessage(::Error, _("Failed to verify peer certificate"));
		Failure(0, ECONNABORTED);
		return FZ_REPLY_ERROR;
	}

	if (status & GNUTLS_CERT_REVOKED)
	{
		m_pOwner->LogMessage(::Error, _("Beware! Certificate has been revoked"));
		Failure(0, ECONNABORTED);
		return FZ_REPLY_ERROR;
	}

	if (status & GNUTLS_CERT_SIGNER_NOT_CA)
	{
		m_pOwner->LogMessage(::Error, _("Incomplete chain, top certificate is not self-signed certificate authority certificate"));
		Failure(0, ECONNABORTED);
		return FZ_REPLY_ERROR;
	}

	if (m_require_root_trust && status & GNUTLS_CERT_SIGNER_NOT_FOUND)
	{
		m_pOwner->LogMessage(::Error, _("Root certificate is not trusted"));
		Failure(0, ECONNABORTED);
		return FZ_REPLY_ERROR;
	}

	unsigned int cert_list_size;
	const gnutls_datum_t* cert_list = gnutls_certificate_get_peers(m_session, &cert_list_size);
	if (!cert_list || !cert_list_size)
	{
		m_pOwner->LogMessage(::Error, _("gnutls_certificate_get_peers returned no certificates"));
		Failure(0, ECONNABORTED);
		return FZ_REPLY_ERROR;
	}

	if (m_implicitTrustedCert.data)
	{
		if (m_implicitTrustedCert.size != cert_list[0].size ||
			memcmp(m_implicitTrustedCert.data, cert_list[0].data, cert_list[0].size))
		{
			m_pOwner->LogMessage(::Error, _("Primary connection and data connection certificates don't match."));
			Failure(0, ECONNABORTED);
			return FZ_REPLY_ERROR;
		}

		TrustCurrentCert(true);

		if (m_tlsState != conn)
			return FZ_REPLY_ERROR;
		return FZ_REPLY_OK;
	}

	std::vector<CCertificate> certificates;
	for (unsigned int i = 0; i < cert_list_size; i++)
	{
		CCertificate cert;
		if (ExtractCert(cert_list, cert))
			certificates.push_back(cert);
		else
		{
			Failure(0, ECONNABORTED);
			return FZ_REPLY_ERROR;
		}

		++cert_list;
	}

	CCertificateNotification *pNotification = new CCertificateNotification(
		m_pOwner->GetCurrentServer()->GetHost(),
		m_pOwner->GetCurrentServer()->GetPort(),
		GetProtocolName(),
		GetKeyExchange(),
		GetCipherName(),
		GetMacName(),
		certificates);

	m_pOwner->SendAsyncRequest(pNotification);

	m_pOwner->LogMessage(Status, _("Verifying certificate..."));

	return FZ_REPLY_WOULDBLOCK;
}
Beispiel #20
0
static Ecore_Con_Ssl_Error
_ecore_con_ssl_client_init_gnutls(Ecore_Con_Client *cl)
{
   const gnutls_datum_t *cert_list;
   unsigned int iter, cert_list_size;
   const char *priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0:+VERS-SSL3.0";
   int ret = 0;

   switch (cl->ssl_state)
     {
      case ECORE_CON_SSL_STATE_DONE:
        return ECORE_CON_SSL_ERROR_NONE;

      case ECORE_CON_SSL_STATE_INIT:
        if (cl->host_server->type & ECORE_CON_USE_SSL2) /* not supported because of security issues */
          return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED;

        switch (cl->host_server->type & ECORE_CON_SSL)
          {
           case ECORE_CON_USE_SSL3:
           case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT:
             priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:!VERS-TLS1.0:!VERS-TLS1.1";
             break;

           case ECORE_CON_USE_TLS:
           case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT:
             priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:!VERS-SSL3.0";
             break;

           case ECORE_CON_USE_MIXED:
           case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT:
             break;

           default:
             return ECORE_CON_SSL_ERROR_NONE;
          }

        _client_connected++;

        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_init(&cl->session, GNUTLS_SERVER));
        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_session_ticket_key_generate(&cl->session_ticket));
        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_session_ticket_enable_server(cl->session, &cl->session_ticket));
        INF("Applying priority string: %s", priority);
        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_priority_set_direct(cl->session, priority, NULL));
        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_CERTIFICATE, cl->host_server->cert));
        //  SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_PSK, cl->host_server->pskcred_s));
        if (!cl->host_server->use_cert)
          SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_ANON, cl->host_server->anoncred_s));

        gnutls_certificate_server_set_request(cl->session, GNUTLS_CERT_REQUEST);

        gnutls_dh_set_prime_bits(cl->session, 2048);
        gnutls_transport_set_ptr(cl->session, (gnutls_transport_ptr_t)((intptr_t)cl->fd));
        cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;

      case ECORE_CON_SSL_STATE_HANDSHAKING:
        if (!cl->session)
          {
             DBG("Client was previously lost, going to error condition");
             goto error;
          }
        DBG("calling gnutls_handshake()");
        ret = gnutls_handshake(cl->session);
        SSL_ERROR_CHECK_GOTO_ERROR(gnutls_error_is_fatal(ret));

        if (!ret)
          {
             cl->handshaking = EINA_FALSE;
             cl->ssl_state = ECORE_CON_SSL_STATE_DONE;
          }
        else
          {
             if (gnutls_record_get_direction(cl->session))
               ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE);
             else
               ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ);
             return ECORE_CON_SSL_ERROR_NONE;
          }

      default:
        break;
     }

   if (!cl->host_server->verify)
     /* not verifying certificates, so we're done! */
     return ECORE_CON_SSL_ERROR_NONE;
   ret = 0;
   /* use CRL/CA lists to verify */
   SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_certificate_verify_peers2(cl->session, &iter));
   if (iter & GNUTLS_CERT_INVALID)
     ERR("The certificate is not trusted.");
   else if (iter & GNUTLS_CERT_SIGNER_NOT_FOUND)
     ERR("The certificate hasn't got a known issuer.");
   else if (iter & GNUTLS_CERT_REVOKED)
     ERR("The certificate has been revoked.");
   else if (iter & GNUTLS_CERT_EXPIRED)
     ERR("The certificate has expired");
   else if (iter & GNUTLS_CERT_NOT_ACTIVATED)
     ERR("The certificate is not yet activated");

   if (iter)
     goto error;

   if (gnutls_certificate_type_get(cl->session) != GNUTLS_CRT_X509)
     {
        ERR("Warning: PGP certificates are not yet supported!");
        goto error;
     }

   SSL_ERROR_CHECK_GOTO_ERROR(!(cert_list = gnutls_certificate_get_peers(cl->session, &cert_list_size)));
   SSL_ERROR_CHECK_GOTO_ERROR(!cert_list_size);

   DBG("SSL certificate verification succeeded!");
   return ECORE_CON_SSL_ERROR_NONE;

error:
   _gnutls_print_errors(ret);
   if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED))
     ERR("Also received alert: %s", gnutls_alert_get_name(gnutls_alert_get(cl->session)));
   if (cl->session && (cl->ssl_state != ECORE_CON_SSL_STATE_DONE))
     {
        ERR("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(cl->session)));
        ERR("last in: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(cl->session)));
     }
   _ecore_con_ssl_client_shutdown_gnutls(cl);
   return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
}
Beispiel #21
0
/*
 * This function is called after the TCP connect has completed. Setup the TLS
 * layer and do all necessary magic.
 */
CURLcode
Curl_gtls_connect(struct connectdata *conn,
                  int sockindex)

{
    const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
    struct SessionHandle *data = conn->data;
    gnutls_session session;
    int rc;
    unsigned int cert_list_size;
    const gnutls_datum *chainp;
    unsigned int verify_status;
    gnutls_x509_crt x509_cert;
    char certbuf[256]; /* big enough? */
    size_t size;
    unsigned int algo;
    unsigned int bits;
    time_t clock;
    const char *ptr;
    void *ssl_sessionid;
    size_t ssl_idsize;

    /* GnuTLS only supports TLSv1 (and SSLv3?) */
    if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
        failf(data, "GnuTLS does not support SSLv2");
        return CURLE_SSL_CONNECT_ERROR;
    }

    /* allocate a cred struct */
    rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred);
    if(rc < 0) {
        failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
        return CURLE_SSL_CONNECT_ERROR;
    }

    if(data->set.ssl.CAfile) {
        /* set the trusted CA cert bundle file */
        gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
                                            GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);

        rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
                data->set.ssl.CAfile,
                GNUTLS_X509_FMT_PEM);
        if(rc < 0) {
            infof(data, "error reading ca cert file %s (%s)\n",
                  data->set.ssl.CAfile, gnutls_strerror(rc));
            if (data->set.ssl.verifypeer)
                return CURLE_SSL_CACERT_BADFILE;
        }
        else
            infof(data, "found %d certificates in %s\n",
                  rc, data->set.ssl.CAfile);
    }

    /* Initialize TLS session as a client */
    rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT);
    if(rc) {
        failf(data, "gnutls_init() failed: %d", rc);
        return CURLE_SSL_CONNECT_ERROR;
    }

    /* convenient assign */
    session = conn->ssl[sockindex].session;

    /* Use default priorities */
    rc = gnutls_set_default_priority(session);
    if(rc < 0)
        return CURLE_SSL_CONNECT_ERROR;

    /* Sets the priority on the certificate types supported by gnutls. Priority
       is higher for types specified before others. After specifying the types
       you want, you must append a 0. */
    rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
    if(rc < 0)
        return CURLE_SSL_CONNECT_ERROR;

    if(data->set.cert) {
        if( gnutls_certificate_set_x509_key_file(
                    conn->ssl[sockindex].cred, data->set.cert,
                    data->set.key != 0 ? data->set.key : data->set.cert,
                    do_file_type(data->set.cert_type) ) ) {
            failf(data, "error reading X.509 key or certificate file");
            return CURLE_SSL_CONNECT_ERROR;
        }
    }

    /* put the credentials to the current session */
    rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
                                conn->ssl[sockindex].cred);

    /* set the connection handle (file descriptor for the socket) */
    gnutls_transport_set_ptr(session,
                             (gnutls_transport_ptr)conn->sock[sockindex]);

    /* register callback functions to send and receive data. */
    gnutls_transport_set_push_function(session, Curl_gtls_push);
    gnutls_transport_set_pull_function(session, Curl_gtls_pull);

    /* lowat must be set to zero when using custom push and pull functions. */
    gnutls_transport_set_lowat(session, 0);

    /* This might be a reconnect, so we check for a session ID in the cache
       to speed up things */

    if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
        /* we got a session id, use it! */
        gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);

        /* Informational message */
        infof (data, "SSL re-using session ID\n");
    }

    rc = handshake(conn, session, sockindex, TRUE);
    if(rc)
        /* handshake() sets its own error message with failf() */
        return rc;

    /* This function will return the peer's raw certificate (chain) as sent by
       the peer. These certificates are in raw format (DER encoded for
       X.509). In case of a X.509 then a certificate list may be present. The
       first certificate in the list is the peer's certificate, following the
       issuer's certificate, then the issuer's issuer etc. */

    chainp = gnutls_certificate_get_peers(session, &cert_list_size);
    if(!chainp) {
        if(data->set.ssl.verifyhost) {
            failf(data, "failed to get server cert");
            return CURLE_SSL_PEER_CERTIFICATE;
        }
        infof(data, "\t common name: WARNING couldn't obtain\n");
    }

    /* This function will try to verify the peer's certificate and return its
       status (trusted, invalid etc.). The value of status should be one or more
       of the gnutls_certificate_status_t enumerated elements bitwise or'd. To
       avoid denial of service attacks some default upper limits regarding the
       certificate key size and chain size are set. To override them use
       gnutls_certificate_set_verify_limits(). */

    rc = gnutls_certificate_verify_peers2(session, &verify_status);
    if (rc < 0) {
        failf(data, "server cert verify failed: %d", rc);
        return CURLE_SSL_CONNECT_ERROR;
    }

    /* verify_status is a bitmask of gnutls_certificate_status bits */
    if(verify_status & GNUTLS_CERT_INVALID) {
        if (data->set.ssl.verifypeer) {
            failf(data, "server certificate verification failed. CAfile: %s",
                  data->set.ssl.CAfile?data->set.ssl.CAfile:"none");
            return CURLE_SSL_CACERT;
        }
        else
            infof(data, "\t server certificate verification FAILED\n");
    }
    else
        infof(data, "\t server certificate verification OK\n");

    /* initialize an X.509 certificate structure. */
    gnutls_x509_crt_init(&x509_cert);

    /* convert the given DER or PEM encoded Certificate to the native
       gnutls_x509_crt_t format */
    gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);

    size=sizeof(certbuf);
    rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
                                       0, /* the first and only one */
                                       FALSE,
                                       certbuf,
                                       &size);
    if(rc) {
        infof(data, "error fetching CN from cert:%s\n",
              gnutls_strerror(rc));
    }

    /* This function will check if the given certificate's subject matches the
       given hostname. This is a basic implementation of the matching described
       in RFC2818 (HTTPS), which takes into account wildcards, and the subject
       alternative name PKIX extension. Returns non zero on success, and zero on
       failure. */
    rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);

    if(!rc) {
        if (data->set.ssl.verifyhost > 1) {
            failf(data, "SSL: certificate subject name (%s) does not match "
                  "target host name '%s'", certbuf, conn->host.dispname);
            gnutls_x509_crt_deinit(x509_cert);
            return CURLE_SSL_PEER_CERTIFICATE;
        }
        else
            infof(data, "\t common name: %s (does not match '%s')\n",
                  certbuf, conn->host.dispname);
    }
    else
        infof(data, "\t common name: %s (matched)\n", certbuf);

    /* Show:

    - ciphers used
    - subject
    - start date
    - expire date
    - common name
    - issuer

    */

    /* public key algorithm's parameters */
    algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
    infof(data, "\t certificate public key: %s\n",
          gnutls_pk_algorithm_get_name(algo));

    /* version of the X.509 certificate. */
    infof(data, "\t certificate version: #%d\n",
          gnutls_x509_crt_get_version(x509_cert));


    size = sizeof(certbuf);
    gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
    infof(data, "\t subject: %s\n", certbuf);

    clock = gnutls_x509_crt_get_activation_time(x509_cert);
    showtime(data, "start date", clock);

    clock = gnutls_x509_crt_get_expiration_time(x509_cert);
    showtime(data, "expire date", clock);

    size = sizeof(certbuf);
    gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
    infof(data, "\t issuer: %s\n", certbuf);

    gnutls_x509_crt_deinit(x509_cert);

    /* compression algorithm (if any) */
    ptr = gnutls_compression_get_name(gnutls_compression_get(session));
    /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
    infof(data, "\t compression: %s\n", ptr);

    /* the name of the cipher used. ie 3DES. */
    ptr = gnutls_cipher_get_name(gnutls_cipher_get(session));
    infof(data, "\t cipher: %s\n", ptr);

    /* the MAC algorithms name. ie SHA1 */
    ptr = gnutls_mac_get_name(gnutls_mac_get(session));
    infof(data, "\t MAC: %s\n", ptr);

    if(!ssl_sessionid) {
        /* this session was not previously in the cache, add it now */

        /* get the session ID data size */
        gnutls_session_get_data(session, NULL, &ssl_idsize);
        ssl_sessionid = malloc(ssl_idsize); /* get a buffer for it */

        if(ssl_sessionid) {
            /* extract session ID to the allocated buffer */
            gnutls_session_get_data(session, ssl_sessionid, &ssl_idsize);

            /* store this session id */
            return Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_idsize);
        }
    }

    return CURLE_OK;
}
Beispiel #22
0
int TLSClient::verify_certificate () const
{
  if (_trust == TLSClient::allow_all)
    return 0;

  // This verification function uses the trusted CAs in the credentials
  // structure. So you must have installed one or more CA certificates.
  unsigned int status = 0;
  const char* hostname = _host.c_str();
#if GNUTLS_VERSION_NUMBER >= 0x030104
  if (_trust == TLSClient::ignore_hostname)
    hostname = NULL;

  int ret = gnutls_certificate_verify_peers3 (_session, hostname, &status);
  if (ret < 0)
  {
    if (_debug)
      std::cout << "c: ERROR Certificate verification peers3 failed. " << gnutls_strerror (ret) << "\n";
    return GNUTLS_E_CERTIFICATE_ERROR;
  }
#else
  int ret = gnutls_certificate_verify_peers2 (_session, &status);
  if (ret < 0)
  {
    if (_debug)
      std::cout << "c: ERROR Certificate verification peers2 failed. " << gnutls_strerror (ret) << "\n";
    return GNUTLS_E_CERTIFICATE_ERROR;
  }

  if ((status == 0) && (_trust != TLSClient::ignore_hostname))
  {
    if (gnutls_certificate_type_get (_session) == GNUTLS_CRT_X509)
    {
      const gnutls_datum* cert_list;
      unsigned int cert_list_size;
      gnutls_x509_crt cert;

      cert_list = gnutls_certificate_get_peers (_session, &cert_list_size);
      if (cert_list_size == 0)
      {
        if (_debug)
          std::cout << "c: ERROR Certificate get peers failed. " << gnutls_strerror (ret) << "\n";
        return GNUTLS_E_CERTIFICATE_ERROR;
      }

      ret = gnutls_x509_crt_init (&cert);
      if (ret < 0)
      {
        if (_debug)
          std::cout << "c: ERROR x509 init failed. " << gnutls_strerror (ret) << "\n";
        return GNUTLS_E_CERTIFICATE_ERROR;
      }

      ret = gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER);
      if (ret < 0)
      {
        if (_debug)
          std::cout << "c: ERROR x509 cert import. " << gnutls_strerror (ret) << "\n";
        gnutls_x509_crt_deinit(cert);
        return GNUTLS_E_CERTIFICATE_ERROR;
      }

      if (gnutls_x509_crt_check_hostname (cert, hostname) == 0)
      {
        if (_debug)
          std::cout << "c: ERROR x509 cert check hostname. " << gnutls_strerror (ret) << "\n";
        gnutls_x509_crt_deinit(cert);
        return GNUTLS_E_CERTIFICATE_ERROR;
      }
    }
    else
      return GNUTLS_E_CERTIFICATE_ERROR;
  }
#endif

#if GNUTLS_VERSION_NUMBER >= 0x030104
  gnutls_certificate_type_t type = gnutls_certificate_type_get (_session);
  gnutls_datum_t out;
  ret = gnutls_certificate_verification_status_print (status, type, &out, 0);
  if (ret < 0)
  {
    if (_debug)
      std::cout << "c: ERROR certificate verification status. " << gnutls_strerror (ret) << "\n";
    return GNUTLS_E_CERTIFICATE_ERROR;
  }

  if (_debug)
    std::cout << "c: INFO " << out.data << "\n";
  gnutls_free (out.data);
#endif

  if (status != 0)
    return GNUTLS_E_CERTIFICATE_ERROR;

  // Continue handshake.
  return 0;
}
static void
inf_gtk_certificate_manager_certificate_func(InfXmppConnection* connection,
                                             gnutls_session_t session,
                                             InfCertificateChain* chain,
                                             gpointer user_data)
{
  InfGtkCertificateManager* manager;
  InfGtkCertificateManagerPrivate* priv;

  InfGtkCertificateDialogFlags flags;
  gnutls_x509_crt_t presented_cert;
  gnutls_x509_crt_t known_cert;
  gchar* hostname;

  gboolean match_hostname;
  gboolean issuer_known;
  gnutls_x509_crt_t root_cert;

  int ret;
  unsigned int verify;
  GHashTable* table;
  gboolean cert_equal;
  time_t expiration_time;

  InfGtkCertificateManagerQuery* query;
  gchar* text;
  GtkWidget* vbox;
  GtkWidget* button;
  GtkWidget* image;
  GtkWidget* label;

  GError* error;

  manager = INF_GTK_CERTIFICATE_MANAGER(user_data);
  priv = INF_GTK_CERTIFICATE_MANAGER_PRIVATE(manager);

  g_object_get(G_OBJECT(connection), "remote-hostname", &hostname, NULL);
  presented_cert = inf_certificate_chain_get_own_certificate(chain);

  match_hostname = gnutls_x509_crt_check_hostname(presented_cert, hostname);

  /* First, validate the certificate */
  ret = gnutls_certificate_verify_peers2(session, &verify);
  error = NULL;

  if(ret != GNUTLS_E_SUCCESS)
    inf_gnutls_set_error(&error, ret);

  /* Remove the GNUTLS_CERT_ISSUER_NOT_KNOWN flag from the verification
   * result, and if the certificate is still invalid, then set an error. */
  if(error == NULL)
  {
    issuer_known = TRUE;
    if(verify & GNUTLS_CERT_SIGNER_NOT_FOUND)
    {
      issuer_known = FALSE;

      /* Re-validate the certificate for other failure reasons --
       * unfortunately the gnutls_certificate_verify_peers2() call
       * does not tell us whether the certificate is otherwise invalid
       * if a signer is not found already. */
      /* TODO: Here it would be good to use the verify flags from the
       * certificate credentials, but GnuTLS does not have API to
       * retrieve them. */
      root_cert = inf_certificate_chain_get_root_certificate(chain);

      ret = gnutls_x509_crt_list_verify(
        inf_certificate_chain_get_raw(chain),
        inf_certificate_chain_get_n_certificates(chain),
        &root_cert,
        1,
        NULL,
        0,
        GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
        &verify
      );

      if(ret != GNUTLS_E_SUCCESS)
        inf_gnutls_set_error(&error, ret);
      else if(verify & GNUTLS_CERT_INVALID)
        inf_gnutls_certificate_verification_set_error(&error, verify);
    }
  }

  /* Look up the host in our database of pinned certificates if we could not
   * fully verify the certificate, i.e. if either the issuer is not known or
   * the hostname of the connection does not match the certificate. */
  table = NULL;
  if(error == NULL)
  {
    known_cert = NULL;
    if(!match_hostname || !issuer_known)
    {
      /* If we cannot load the known host file, then cancel the connection.
       * Otherwise it might happen that someone shows us a certificate that we
       * tell the user we don't know, if though actually for that host we expect
       * a different certificate. */
      table = inf_gtk_certificate_manager_ref_known_hosts(manager, &error);
      if(table != NULL)
        known_cert = g_hash_table_lookup(table, hostname);
    }
  }

  /* Next, configure the flags for the dialog to be shown based on the
   * verification result, and on whether the pinned certificate matches
   * the one presented by the host or not. */
  flags = 0;
  if(error == NULL)
  {
    if(known_cert != NULL)
    {
      cert_equal = inf_gtk_certificate_manager_compare_fingerprint(
        known_cert,
        presented_cert,
        &error
      );

      if(error == NULL && cert_equal == FALSE)
      {
        if(!match_hostname)
          flags |= INF_GTK_CERTIFICATE_DIALOG_CERT_HOSTNAME_MISMATCH;
        if(!issuer_known)
          flags |= INF_GTK_CERTIFICATE_DIALOG_CERT_ISSUER_NOT_KNOWN;

        flags |= INF_GTK_CERTIFICATE_DIALOG_CERT_UNEXPECTED;
        expiration_time = gnutls_x509_crt_get_expiration_time(known_cert);
        if(expiration_time != (time_t)(-1))
        {
          expiration_time -= INF_GTK_CERTIFICATE_MANAGER_EXPIRATION_TOLERANCE;
          if(time(NULL) > expiration_time)
          {
            flags |= INF_GTK_CERTIFICATE_DIALOG_CERT_OLD_EXPIRED;
          }
        }
      }
    }
    else
    {
      if(!match_hostname)
        flags |= INF_GTK_CERTIFICATE_DIALOG_CERT_HOSTNAME_MISMATCH;
      if(!issuer_known)
        flags |= INF_GTK_CERTIFICATE_DIALOG_CERT_ISSUER_NOT_KNOWN;
    }
  }

  /* Now proceed either by accepting the connection, rejecting it, or
   * bothering the user with an annoying dialog. */
  if(error == NULL)
  {
    if(flags == 0)
    {
      if(match_hostname && issuer_known)
      {
        /* Remove the pinned entry if we now have a valid certificate for
         * this host. */
        if(table != NULL && g_hash_table_remove(table, hostname) == TRUE)
        {
          inf_gtk_certificate_manager_write_known_hosts_with_warning(
            manager,
            table
          );
        }
      }

      inf_xmpp_connection_certificate_verify_continue(connection);
    }
    else
    {
      query = g_slice_new(InfGtkCertificateManagerQuery);
      query->manager = manager;
      query->known_hosts = table;
      query->connection = connection;
      query->dialog = inf_gtk_certificate_dialog_new(
        priv->parent_window,
        0,
        flags,
        hostname,
        chain
      );
      query->certificate_chain = chain;

      table = NULL;

      g_object_ref(query->connection);
      inf_certificate_chain_ref(chain);

      g_signal_connect(
        G_OBJECT(connection),
        "notify::status",
        G_CALLBACK(inf_gtk_certificate_manager_notify_status_cb),
        query
      );

      g_signal_connect(
        G_OBJECT(query->dialog),
        "response",
        G_CALLBACK(inf_gtk_certificate_manager_response_cb),
        query
      );

      image = gtk_image_new_from_stock(GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON);
      gtk_widget_show(image);

      button = gtk_dialog_add_button(
        GTK_DIALOG(query->dialog),
        _("_Cancel connection"),
        GTK_RESPONSE_REJECT
      );

      gtk_button_set_image(GTK_BUTTON(button), image);

      image = gtk_image_new_from_stock(GTK_STOCK_CONNECT, GTK_ICON_SIZE_BUTTON);
      gtk_widget_show(image);

      button = gtk_dialog_add_button(
        GTK_DIALOG(query->dialog),
        _("C_ontinue connection"),
        GTK_RESPONSE_ACCEPT
      );

      gtk_button_set_image(GTK_BUTTON(button), image);

      text = g_strdup_printf(
        _("Do you want to continue the connection to host \"%s\"? If you "
          "choose to continue, this certificate will be trusted in the "
          "future when connecting to this host."),
        hostname
      );

      label = gtk_label_new(text);
      gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
      gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD_CHAR);
      gtk_label_set_width_chars(GTK_LABEL(label), 60);
      gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
      gtk_widget_show(label);
      g_free(text);

      vbox = gtk_dialog_get_content_area(GTK_DIALOG(query->dialog));
      gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);

      priv->queries = g_slist_prepend(priv->queries, query);
      gtk_window_present(GTK_WINDOW(query->dialog));
    }
  }
  else
  {
    inf_xmpp_connection_certificate_verify_cancel(connection, error);
    g_error_free(error);
  }

  if(table != NULL) g_hash_table_unref(table);
  g_free(hostname);
}
Beispiel #24
0
static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
{
    TLSContext *p = h->priv_data;
    TLSShared *c = &p->tls_shared;
    int ret;

    ff_gnutls_init();

    if ((ret = ff_tls_open_underlying(c, h, uri, options)) < 0)
        goto fail;

    gnutls_init(&p->session, c->listen ? GNUTLS_SERVER : GNUTLS_CLIENT);
    if (!c->listen && !c->numerichost)
        gnutls_server_name_set(p->session, GNUTLS_NAME_DNS, c->host, strlen(c->host));
    gnutls_certificate_allocate_credentials(&p->cred);
    if (c->ca_file) {
        ret = gnutls_certificate_set_x509_trust_file(p->cred, c->ca_file, GNUTLS_X509_FMT_PEM);
        if (ret < 0)
            av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
    }
#if GNUTLS_VERSION_MAJOR >= 3
    else
        gnutls_certificate_set_x509_system_trust(p->cred);
#endif
    gnutls_certificate_set_verify_flags(p->cred, c->verify ?
                                        GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT : 0);
    if (c->cert_file && c->key_file) {
        ret = gnutls_certificate_set_x509_key_file(p->cred,
                                                   c->cert_file, c->key_file,
                                                   GNUTLS_X509_FMT_PEM);
        if (ret < 0) {
            av_log(h, AV_LOG_ERROR,
                   "Unable to set cert/key files %s and %s: %s\n",
                   c->cert_file, c->key_file, gnutls_strerror(ret));
            ret = AVERROR(EIO);
            goto fail;
        }
    } else if (c->cert_file || c->key_file)
        av_log(h, AV_LOG_ERROR, "cert and key required\n");
    gnutls_credentials_set(p->session, GNUTLS_CRD_CERTIFICATE, p->cred);
    gnutls_transport_set_pull_function(p->session, gnutls_url_pull);
    gnutls_transport_set_push_function(p->session, gnutls_url_push);
    gnutls_transport_set_ptr(p->session, c->tcp);
    gnutls_priority_set_direct(p->session, "NORMAL", NULL);
    ret = gnutls_handshake(p->session);
    if (ret) {
        ret = print_tls_error(h, ret);
        goto fail;
    }
    p->need_shutdown = 1;
    if (c->verify) {
        unsigned int status, cert_list_size;
        gnutls_x509_crt_t cert;
        const gnutls_datum_t *cert_list;
        if ((ret = gnutls_certificate_verify_peers2(p->session, &status)) < 0) {
            av_log(h, AV_LOG_ERROR, "Unable to verify peer certificate: %s\n",
                                    gnutls_strerror(ret));
            ret = AVERROR(EIO);
            goto fail;
        }
        if (status & GNUTLS_CERT_INVALID) {
            av_log(h, AV_LOG_ERROR, "Peer certificate failed verification\n");
            ret = AVERROR(EIO);
            goto fail;
        }
        if (gnutls_certificate_type_get(p->session) != GNUTLS_CRT_X509) {
            av_log(h, AV_LOG_ERROR, "Unsupported certificate type\n");
            ret = AVERROR(EIO);
            goto fail;
        }
        gnutls_x509_crt_init(&cert);
        cert_list = gnutls_certificate_get_peers(p->session, &cert_list_size);
        gnutls_x509_crt_import(cert, cert_list, GNUTLS_X509_FMT_DER);
        ret = gnutls_x509_crt_check_hostname(cert, c->host);
        gnutls_x509_crt_deinit(cert);
        if (!ret) {
            av_log(h, AV_LOG_ERROR,
                   "The certificate's owner does not match hostname %s\n", c->host);
            ret = AVERROR(EIO);
            goto fail;
        }
    }

    return 0;
fail:
    tls_close(h);
    return ret;
}
Beispiel #25
0
static gboolean
ssl_verify_certificate (LmSSL *ssl, const gchar *server)
{
    LmSSLBase *base;
    unsigned int        status;
    int rc;

    base = LM_SSL_BASE (ssl);

    /* This verification function uses the trusted CAs in the credentials
     * structure. So you must have installed one or more CA certificates.
     */
    rc = gnutls_certificate_verify_peers2 (ssl->gnutls_session, &status);

    if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND) {
        if (base->func (ssl,
                        LM_SSL_STATUS_NO_CERT_FOUND,
                        base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            return FALSE;
        }
    }

    if (rc != 0) {
        if (base->func (ssl,
                        LM_SSL_STATUS_GENERIC_ERROR,
                        base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            return FALSE;
        }
    }

    if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND) {
        if (base->func (ssl,
                        LM_SSL_STATUS_NO_CERT_FOUND,
                        base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            return FALSE;
        }
    }

    if (status & GNUTLS_CERT_INVALID
        || status & GNUTLS_CERT_REVOKED) {
        if (base->func (ssl, LM_SSL_STATUS_UNTRUSTED_CERT,
                        base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            return FALSE;
        }
    }

    if (gnutls_certificate_expiration_time_peers (ssl->gnutls_session) < time (0)) {
        if (base->func (ssl, LM_SSL_STATUS_CERT_EXPIRED,
                        base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            return FALSE;
        }
    }

    if (gnutls_certificate_activation_time_peers (ssl->gnutls_session) > time (0)) {
        if (base->func (ssl, LM_SSL_STATUS_CERT_NOT_ACTIVATED,
                        base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            return FALSE;
        }
    }

    if (gnutls_certificate_type_get (ssl->gnutls_session) == GNUTLS_CRT_X509) {
        const gnutls_datum_t* cert_list;
        guint cert_list_size;
        gnutls_digest_algorithm_t digest = GNUTLS_DIG_SHA256;
        guchar digest_bin[LM_FINGERPRINT_LENGTH];
        size_t digest_size;
        gnutls_x509_crt_t cert;

        cert_list = gnutls_certificate_get_peers (ssl->gnutls_session, &cert_list_size);
        if (cert_list == NULL) {
            if (base->func (ssl, LM_SSL_STATUS_NO_CERT_FOUND,
                            base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
                return FALSE;
            }
        }

        gnutls_x509_crt_init (&cert);

        if (gnutls_x509_crt_import (cert, &cert_list[0],
                                    GNUTLS_X509_FMT_DER) != 0) {
            if (base->func (ssl, LM_SSL_STATUS_NO_CERT_FOUND,
                            base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
                return FALSE;
            }
        }

        if (!gnutls_x509_crt_check_hostname (cert, server)) {
            if (base->func (ssl, LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH,
                            base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
                return FALSE;
            }
        }

        gnutls_x509_crt_deinit (cert);

        digest_size = gnutls_hash_get_len(digest);
        g_assert(digest_size < sizeof(digest_bin));

        if (gnutls_fingerprint (digest,
                                &cert_list[0],
                                digest_bin,
                                &digest_size) >= 0) {
            _lm_ssl_base_set_fingerprint(base, digest_bin, digest_size);
            if (_lm_ssl_base_check_fingerprint(base) != 0 &&
                base->func (ssl,
                            LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH,
                            base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
                return FALSE;
            }
        }
        else if (base->func (ssl, LM_SSL_STATUS_GENERIC_ERROR,
                             base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
            return FALSE;
        }
    }

    return TRUE;
}
Beispiel #26
0
int vnc_tls_validate_certificate(struct VncState *vs)
{
    int ret;
    unsigned int status;
    const gnutls_datum_t *certs;
    unsigned int nCerts, i;
    time_t now;

    VNC_DEBUG("Validating client certificate\n");
    if ((ret = gnutls_certificate_verify_peers2 (vs->tls.session, &status)) < 0) {
        VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
        return -1;
    }

    if ((now = time(NULL)) == ((time_t)-1)) {
        return -1;
    }

    if (status != 0) {
        if (status & GNUTLS_CERT_INVALID)
            VNC_DEBUG("The certificate is not trusted.\n");

        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
            VNC_DEBUG("The certificate hasn't got a known issuer.\n");

        if (status & GNUTLS_CERT_REVOKED)
            VNC_DEBUG("The certificate has been revoked.\n");

        if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
            VNC_DEBUG("The certificate uses an insecure algorithm\n");

        return -1;
    } else {
        VNC_DEBUG("Certificate is valid!\n");
    }

    /* Only support x509 for now */
    if (gnutls_certificate_type_get(vs->tls.session) != GNUTLS_CRT_X509)
        return -1;

    if (!(certs = gnutls_certificate_get_peers(vs->tls.session, &nCerts)))
        return -1;

    for (i = 0 ; i < nCerts ; i++) {
        gnutls_x509_crt_t cert;
        VNC_DEBUG ("Checking certificate chain %d\n", i);
        if (gnutls_x509_crt_init (&cert) < 0)
            return -1;

        if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
            gnutls_x509_crt_deinit (cert);
            return -1;
        }

        if (gnutls_x509_crt_get_expiration_time (cert) < now) {
            VNC_DEBUG("The certificate has expired\n");
            gnutls_x509_crt_deinit (cert);
            return -1;
        }

        if (gnutls_x509_crt_get_activation_time (cert) > now) {
            VNC_DEBUG("The certificate is not yet activated\n");
            gnutls_x509_crt_deinit (cert);
            return -1;
        }

        if (gnutls_x509_crt_get_activation_time (cert) > now) {
            VNC_DEBUG("The certificate is not yet activated\n");
            gnutls_x509_crt_deinit (cert);
            return -1;
        }

        if (i == 0) {
            size_t dnameSize = 1024;
            vs->tls.dname = g_malloc(dnameSize);
        requery:
            if ((ret = gnutls_x509_crt_get_dn (cert, vs->tls.dname, &dnameSize)) != 0) {
                if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
                    vs->tls.dname = g_realloc(vs->tls.dname, dnameSize);
                    goto requery;
                }
                gnutls_x509_crt_deinit (cert);
                VNC_DEBUG("Cannot get client distinguished name: %s",
                          gnutls_strerror (ret));
                return -1;
            }

            if (vs->vd->tls.x509verify) {
                int allow;
                if (!vs->vd->tls.acl) {
                    VNC_DEBUG("no ACL activated, allowing access");
                    gnutls_x509_crt_deinit (cert);
                    continue;
                }

                allow = qemu_acl_party_is_allowed(vs->vd->tls.acl,
                                                  vs->tls.dname);

                VNC_DEBUG("TLS x509 ACL check for %s is %s\n",
                          vs->tls.dname, allow ? "allowed" : "denied");
                if (!allow) {
                    gnutls_x509_crt_deinit (cert);
                    return -1;
                }
            }
        }

        gnutls_x509_crt_deinit (cert);
    }

    return 0;
}
Beispiel #27
0
         bool gtlsGeneric::verifyCertificate(gnutls_session_t & _session)
         {
            bool status = true;

            unsigned int cert_status;
            const gnutls_datum_t *cert_list;
            int cert_list_size, ret;
            gnutls_x509_crt_t cert;

            ret = gnutls_certificate_verify_peers2(_session, &cert_status);

            if (ret < 0)
               {
                  status = false;
                  return status;
               }

            if (cert_status & GNUTLS_CERT_INVALID)
               {
                  //BTG_NOTICE("The certificate is not trusted.");
                  status = false;
               }

            if (cert_status & GNUTLS_CERT_SIGNER_NOT_FOUND)
               {
                  //BTG_NOTICE("The certificate hasn't got a known issuer.");
                  status = false;
               }

            if (cert_status & GNUTLS_CERT_REVOKED)
               {
                  //BTG_NOTICE("The certificate has been revoked.\n");
                  status = false;
               }

            if (gnutls_x509_crt_init(&cert) < 0)
               {
                  //BTG_NOTICE("gnutls_x509_crt_init failed.");
                  status = false;
                  return status;
               }

            cert_list = gnutls_certificate_get_peers(_session, reinterpret_cast<unsigned int*>(&cert_list_size));
            if (cert_list == 0)
               {
                  //BTG_NOTICE("No certificate was found");
                  status = false;
                  return status;
               }

            // Just check the first certificate.
            if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
               {
                  //BTG_NOTICE("error parsing certificate.");
                  status = false;
                  return status;
               }

            time_t now       = time(0);
            time_t cert_exptime = gnutls_x509_crt_get_expiration_time(cert);

            if (cert_exptime == static_cast<time_t>(-1))
               {
                  //BTG_NOTICE("gnutls_x509_crt_get_expiration_time failed.");
                  status = false;
                  return status;
               }

            if (cert_exptime < now)
               {
                  //BTG_NOTICE("The certificate has expired.");
                  status = false;
                  return status;
               }

            time_t cert_act = gnutls_x509_crt_get_activation_time(cert);

            if (cert_exptime == static_cast<time_t>(-1))
               {
                  // BTG_NOTICE("gnutls_x509_crt_get_activation_time failed.");
                  status = false;
                  return status;
               }

            if (cert_act > now)
               {
                  // BTG_NOTICE("The certificate is not yet activated.");
                  status = false;
                  return status;
               }

            gnutls_x509_crt_deinit(cert);

            return status;
         }
Beispiel #28
0
static int
qcrypto_tls_session_check_certificate(QCryptoTLSSession *session,
                                      Error **errp)
{
    int ret;
    unsigned int status;
    const gnutls_datum_t *certs;
    unsigned int nCerts, i;
    time_t now;
    gnutls_x509_crt_t cert = NULL;

    now = time(NULL);
    if (now == ((time_t)-1)) {
        error_setg_errno(errp, errno, "Cannot get current time");
        return -1;
    }

    ret = gnutls_certificate_verify_peers2(session->handle, &status);
    if (ret < 0) {
        error_setg(errp, "Verify failed: %s", gnutls_strerror(ret));
        return -1;
    }

    if (status != 0) {
        const char *reason = "Invalid certificate";

        if (status & GNUTLS_CERT_INVALID) {
            reason = "The certificate is not trusted";
        }

        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
            reason = "The certificate hasn't got a known issuer";
        }

        if (status & GNUTLS_CERT_REVOKED) {
            reason = "The certificate has been revoked";
        }

        if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
            reason = "The certificate uses an insecure algorithm";
        }

        error_setg(errp, "%s", reason);
        return -1;
    }

    certs = gnutls_certificate_get_peers(session->handle, &nCerts);
    if (!certs) {
        error_setg(errp, "No certificate peers");
        return -1;
    }

    for (i = 0; i < nCerts; i++) {
        ret = gnutls_x509_crt_init(&cert);
        if (ret < 0) {
            error_setg(errp, "Cannot initialize certificate: %s",
                       gnutls_strerror(ret));
            return -1;
        }

        ret = gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER);
        if (ret < 0) {
            error_setg(errp, "Cannot import certificate: %s",
                       gnutls_strerror(ret));
            goto error;
        }

        if (gnutls_x509_crt_get_expiration_time(cert) < now) {
            error_setg(errp, "The certificate has expired");
            goto error;
        }

        if (gnutls_x509_crt_get_activation_time(cert) > now) {
            error_setg(errp, "The certificate is not yet activated");
            goto error;
        }

        if (gnutls_x509_crt_get_activation_time(cert) > now) {
            error_setg(errp, "The certificate is not yet activated");
            goto error;
        }

        if (i == 0) {
            size_t dnameSize = 1024;
            session->peername = g_malloc(dnameSize);
        requery:
            ret = gnutls_x509_crt_get_dn(cert, session->peername, &dnameSize);
            if (ret < 0) {
                if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
                    session->peername = g_realloc(session->peername,
                                                  dnameSize);
                    goto requery;
                }
                error_setg(errp, "Cannot get client distinguished name: %s",
                           gnutls_strerror(ret));
                goto error;
            }
            if (session->aclname) {
                qemu_acl *acl = qemu_acl_find(session->aclname);
                int allow;
                if (!acl) {
                    error_setg(errp, "Cannot find ACL %s",
                               session->aclname);
                    goto error;
                }

                allow = qemu_acl_party_is_allowed(acl, session->peername);

                if (!allow) {
                    error_setg(errp, "TLS x509 ACL check for %s is denied",
                               session->peername);
                    goto error;
                }
            }
            if (session->hostname) {
                if (!gnutls_x509_crt_check_hostname(cert, session->hostname)) {
                    error_setg(errp,
                               "Certificate does not match the hostname %s",
                               session->hostname);
                    goto error;
                }
            }
        }

        gnutls_x509_crt_deinit(cert);
    }

    return 0;

 error:
    gnutls_x509_crt_deinit(cert);
    return -1;
}
Beispiel #29
0
/* returns false (0) if not verified, or true (1) otherwise 
 */
int
cert_verify (gnutls_session_t session, const char* hostname)
{
    int rc;
    unsigned int status = 0;
    int type;

    rc = gnutls_certificate_verify_peers2 (session, &status);
    if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND)
      {
          printf ("- Peer did not send any certificate.\n");
          return 0;
      }

    if (rc < 0)
      {
          printf ("- Could not verify certificate (err: %s)\n",
                  gnutls_strerror (rc));
          return 0;
      }

    type = gnutls_certificate_type_get (session);
    if (type == GNUTLS_CRT_X509)
      {

          if (status & GNUTLS_CERT_REVOKED)
              printf ("- Peer's certificate chain revoked\n");
          if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
              printf ("- Peer's certificate issuer is unknown\n");
          if (status & GNUTLS_CERT_SIGNER_NOT_CA)
              printf ("- Peer's certificate issuer is not a CA\n");
          if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
              printf
                  ("- Peer's certificate chain uses insecure algorithm\n");
          if (status & GNUTLS_CERT_NOT_ACTIVATED)
              printf
                  ("- Peer's certificate chain uses not yet valid certificate\n");
          if (status & GNUTLS_CERT_EXPIRED)
              printf
                  ("- Peer's certificate chain uses expired certificate\n");
          if (status & GNUTLS_CERT_INVALID)
              printf ("- Peer's certificate is NOT trusted\n");
          else
              printf ("- Peer's certificate is trusted\n");

          rc = verify_x509_hostname (session, hostname);
          if (rc == 0) status |= GNUTLS_CERT_INVALID;
      }
    else if (type == GNUTLS_CRT_OPENPGP)
      {
          if (status & GNUTLS_CERT_INVALID)
              printf ("- Peer's key is invalid\n");
          else
              printf ("- Peer's key is valid\n");
          if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
              printf ("- Could not find a signer of the peer's key\n");

          rc = verify_openpgp_hostname (session, hostname);
          if (rc == 0) status |= GNUTLS_CERT_INVALID;
      }
    else
      {
        fprintf(stderr, "Unknown certificate type\n");
        status |= GNUTLS_CERT_INVALID;
      }

    if (status)
      return 0;

    return 1;
}
Beispiel #30
0
static CURLcode
gtls_connect_step3(struct connectdata *conn,
                   int sockindex)
{
  unsigned int cert_list_size;
  const gnutls_datum *chainp;
  unsigned int verify_status;
  gnutls_x509_crt x509_cert,x509_issuer;
  gnutls_datum issuerp;
  char certbuf[256]; /* big enough? */
  size_t size;
  unsigned int algo;
  unsigned int bits;
  time_t certclock;
  const char *ptr;
  struct SessionHandle *data = conn->data;
  gnutls_session session = conn->ssl[sockindex].session;
  int rc;
  int incache;
  void *ssl_sessionid;
  CURLcode result = CURLE_OK;

  /* This function will return the peer's raw certificate (chain) as sent by
     the peer. These certificates are in raw format (DER encoded for
     X.509). In case of a X.509 then a certificate list may be present. The
     first certificate in the list is the peer's certificate, following the
     issuer's certificate, then the issuer's issuer etc. */

  chainp = gnutls_certificate_get_peers(session, &cert_list_size);
  if(!chainp) {
    if(data->set.ssl.verifypeer ||
       data->set.ssl.verifyhost ||
       data->set.ssl.issuercert) {
#ifdef USE_TLS_SRP
      if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
         && data->set.ssl.username != NULL
         && !data->set.ssl.verifypeer
         && gnutls_cipher_get(session)) {
        /* no peer cert, but auth is ok if we have SRP user and cipher and no
           peer verify */
      }
      else {
#endif
        failf(data, "failed to get server cert");
        return CURLE_PEER_FAILED_VERIFICATION;
#ifdef USE_TLS_SRP
      }
#endif
    }
    infof(data, "\t common name: WARNING couldn't obtain\n");
  }

  if(data->set.ssl.verifypeer) {
    /* This function will try to verify the peer's certificate and return its
       status (trusted, invalid etc.). The value of status should be one or
       more of the gnutls_certificate_status_t enumerated elements bitwise
       or'd. To avoid denial of service attacks some default upper limits
       regarding the certificate key size and chain size are set. To override
       them use gnutls_certificate_set_verify_limits(). */

    rc = gnutls_certificate_verify_peers2(session, &verify_status);
    if(rc < 0) {
      failf(data, "server cert verify failed: %d", rc);
      return CURLE_SSL_CONNECT_ERROR;
    }

    /* verify_status is a bitmask of gnutls_certificate_status bits */
    if(verify_status & GNUTLS_CERT_INVALID) {
      if(data->set.ssl.verifypeer) {
        failf(data, "server certificate verification failed. CAfile: %s "
              "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none",
              data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none");
        return CURLE_SSL_CACERT;
      }
      else
        infof(data, "\t server certificate verification FAILED\n");
    }
    else
      infof(data, "\t server certificate verification OK\n");
  }
  else {
    infof(data, "\t server certificate verification SKIPPED\n");
    goto after_server_cert_verification;
  }

  /* initialize an X.509 certificate structure. */
  gnutls_x509_crt_init(&x509_cert);

  /* convert the given DER or PEM encoded Certificate to the native
     gnutls_x509_crt_t format */
  gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);

  if(data->set.ssl.issuercert) {
    gnutls_x509_crt_init(&x509_issuer);
    issuerp = load_file(data->set.ssl.issuercert);
    gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
    rc = gnutls_x509_crt_check_issuer(x509_cert,x509_issuer);
    unload_file(issuerp);
    if(rc <= 0) {
      failf(data, "server certificate issuer check failed (IssuerCert: %s)",
            data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
      return CURLE_SSL_ISSUER_ERROR;
    }
    infof(data,"\t server certificate issuer check OK (Issuer Cert: %s)\n",
          data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
  }

  size=sizeof(certbuf);
  rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
                                     0, /* the first and only one */
                                     FALSE,
                                     certbuf,
                                     &size);
  if(rc) {
    infof(data, "error fetching CN from cert:%s\n",
          gnutls_strerror(rc));
  }

  /* This function will check if the given certificate's subject matches the
     given hostname. This is a basic implementation of the matching described
     in RFC2818 (HTTPS), which takes into account wildcards, and the subject
     alternative name PKIX extension. Returns non zero on success, and zero on
     failure. */
  rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);

  if(!rc) {
    if(data->set.ssl.verifyhost) {
      failf(data, "SSL: certificate subject name (%s) does not match "
            "target host name '%s'", certbuf, conn->host.dispname);
      gnutls_x509_crt_deinit(x509_cert);
      return CURLE_PEER_FAILED_VERIFICATION;
    }
    else
      infof(data, "\t common name: %s (does not match '%s')\n",
            certbuf, conn->host.dispname);
  }
  else
    infof(data, "\t common name: %s (matched)\n", certbuf);

  /* Check for time-based validity */
  certclock = gnutls_x509_crt_get_expiration_time(x509_cert);

  if(certclock == (time_t)-1) {
    failf(data, "server cert expiration date verify failed");
    return CURLE_SSL_CONNECT_ERROR;
  }

  if(certclock < time(NULL)) {
    if(data->set.ssl.verifypeer) {
      failf(data, "server certificate expiration date has passed.");
      return CURLE_PEER_FAILED_VERIFICATION;
    }
    else
      infof(data, "\t server certificate expiration date FAILED\n");
  }
  else
    infof(data, "\t server certificate expiration date OK\n");

  certclock = gnutls_x509_crt_get_activation_time(x509_cert);

  if(certclock == (time_t)-1) {
    failf(data, "server cert activation date verify failed");
    return CURLE_SSL_CONNECT_ERROR;
  }

  if(certclock > time(NULL)) {
    if(data->set.ssl.verifypeer) {
      failf(data, "server certificate not activated yet.");
      return CURLE_PEER_FAILED_VERIFICATION;
    }
    else
      infof(data, "\t server certificate activation date FAILED\n");
  }
  else
    infof(data, "\t server certificate activation date OK\n");

  /* Show:

  - ciphers used
  - subject
  - start date
  - expire date
  - common name
  - issuer

  */

  /* public key algorithm's parameters */
  algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
  infof(data, "\t certificate public key: %s\n",
        gnutls_pk_algorithm_get_name(algo));

  /* version of the X.509 certificate. */
  infof(data, "\t certificate version: #%d\n",
        gnutls_x509_crt_get_version(x509_cert));


  size = sizeof(certbuf);
  gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
  infof(data, "\t subject: %s\n", certbuf);

  certclock = gnutls_x509_crt_get_activation_time(x509_cert);
  showtime(data, "start date", certclock);

  certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
  showtime(data, "expire date", certclock);

  size = sizeof(certbuf);
  gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
  infof(data, "\t issuer: %s\n", certbuf);

  gnutls_x509_crt_deinit(x509_cert);

after_server_cert_verification:

  /* compression algorithm (if any) */
  ptr = gnutls_compression_get_name(gnutls_compression_get(session));
  /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
  infof(data, "\t compression: %s\n", ptr);

  /* the name of the cipher used. ie 3DES. */
  ptr = gnutls_cipher_get_name(gnutls_cipher_get(session));
  infof(data, "\t cipher: %s\n", ptr);

  /* the MAC algorithms name. ie SHA1 */
  ptr = gnutls_mac_get_name(gnutls_mac_get(session));
  infof(data, "\t MAC: %s\n", ptr);

  conn->ssl[sockindex].state = ssl_connection_complete;
  conn->recv[sockindex] = gtls_recv;
  conn->send[sockindex] = gtls_send;

  {
    /* we always unconditionally get the session id here, as even if we
       already got it from the cache and asked to use it in the connection, it
       might've been rejected and then a new one is in use now and we need to
       detect that. */
    void *connect_sessionid;
    size_t connect_idsize;

    /* get the session ID data size */
    gnutls_session_get_data(session, NULL, &connect_idsize);
    connect_sessionid = malloc(connect_idsize); /* get a buffer for it */

    if(connect_sessionid) {
      /* extract session ID to the allocated buffer */
      gnutls_session_get_data(session, connect_sessionid, &connect_idsize);

      incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL));
      if(incache) {
        /* there was one before in the cache, so instead of risking that the
           previous one was rejected, we just kill that and store the new */
        Curl_ssl_delsessionid(conn, ssl_sessionid);
      }

      /* store this session id */
      result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
      if(result) {
        free(connect_sessionid);
        result = CURLE_OUT_OF_MEMORY;
      }
    }
    else
      result = CURLE_OUT_OF_MEMORY;
  }

  return result;
}