コード例 #1
0
ファイル: verify.c プロジェクト: intgr/gnutls
/* Finds an issuer of the certificate. If multiple issuers
 * are present, returns one that is activated and not expired.
 */
static inline gnutls_x509_crt_t
find_issuer (gnutls_x509_crt_t cert,
             const gnutls_x509_crt_t * trusted_cas, int tcas_size)
{
int i;
gnutls_x509_crt_t issuer = NULL;

  /* this is serial search. 
   */

  for (i = 0; i < tcas_size; i++)
    {
      if (is_issuer (cert, trusted_cas[i]) == 1)
        {
          if (issuer == NULL) 
            {
              issuer = trusted_cas[i];
            }
          else
            {
              time_t now = gnutls_time(0);

              if (now < gnutls_x509_crt_get_expiration_time(trusted_cas[i]) && 
                now >= gnutls_x509_crt_get_activation_time(trusted_cas[i]))
                {
                  issuer = trusted_cas[i];
                }
            }
        }
    }

  return issuer;
}
コード例 #2
0
/* Returns the base64 key if found 
 */
static int verify_pubkey(const char* file, 
                             const char* host, const char* service, 
                             const gnutls_datum_t* pubkey)
{
FILE* fd;
char* line = NULL;
size_t line_size = 0;
int ret, l2, mismatch = 0;
size_t host_len = 0, service_len = 0;
time_t now = gnutls_time(0);
gnutls_datum_t b64key = { NULL, 0 };

  ret = raw_pubkey_to_base64(pubkey, &b64key);
  if (ret < 0)
    return gnutls_assert_val(ret);

  if (host != NULL) host_len = strlen(host);
  if (service != NULL) service_len = strlen(service);

  fd = fopen(file, "rb");
  if (fd == NULL)
    {
      ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR);
      goto cleanup;
    }
  
  do 
    {
      l2 = getline(&line, &line_size, fd);
      if (l2 > 0)
        {
          ret = parse_line(line, host, host_len, service, service_len, now, pubkey, &b64key);
          if (ret == 0) /* found */
            {
              goto cleanup;
            }
          else if (ret == GNUTLS_E_CERTIFICATE_KEY_MISMATCH)
            mismatch = 1;
        }
    }
  while(l2 >= 0);

  if (mismatch)
    ret = GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
  else
    ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
  
cleanup:
  free(line);
  if (fd != NULL)
    fclose(fd);
  gnutls_free(b64key.data);
  
  return ret;
}
コード例 #3
0
static int
do_device_source_egd (int init)
{
  time_t now = gnutls_time (NULL);
  unsigned int read_size = DEVICE_READ_SIZE;

  if (init)
    {
      device_fd = _rndegd_connect_socket ();
      if (device_fd < 0)
        {
          _gnutls_debug_log ("Cannot open egd socket!\n");
          return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
        }

      device_last_read = now;

      read_size = DEVICE_READ_SIZE_MAX; /* initially read more data */
    }

  if ((device_fd > 0)
      && (init || ((now - device_last_read) > DEVICE_READ_INTERVAL)))
    {

      /* More than 20 minutes since we last read the device */
      uint8_t buf[DEVICE_READ_SIZE_MAX];
      uint32_t done;

      for (done = 0; done < read_size;)
        {
          int res;
          res = _rndegd_read (&device_fd, buf + done, sizeof (buf) - done);
          if (res <= 0)
            {
              if (res < 0)
                {
                  _gnutls_debug_log ("Failed to read egd.\n");
                }
              else
                {
                  _gnutls_debug_log ("Failed to read egd: end of file\n");
                }

              return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
            }
          done += res;
        }

      device_last_read = now;
      return yarrow256_update (&yctx, RANDOM_SOURCE_DEVICE, read_size * 8 / 2,
                               read_size, buf);
    }
  return 0;
}
コード例 #4
0
static cdk_error_t
literal_encode (void *data, FILE * in, FILE * out)
{
  literal_filter_t *pfx = data;
  cdk_pkt_literal_t pt;
  cdk_stream_t si;
  cdk_packet_t pkt;
  size_t filelen;
  cdk_error_t rc;

  _cdk_log_debug ("literal filter: encode\n");

  if (!pfx || !in || !out)
    return CDK_Inv_Value;
  if (!pfx->filename)
    {
      pfx->filename = cdk_strdup ("_CONSOLE");
      if (!pfx->filename)
        return CDK_Out_Of_Core;
    }

  rc = _cdk_stream_fpopen (in, STREAMCTL_READ, &si);
  if (rc)
    return rc;

  filelen = strlen (pfx->filename);
  cdk_pkt_new (&pkt);
  pt = pkt->pkt.literal = cdk_calloc (1, sizeof *pt + filelen);
  pt->name = (char *) pt + sizeof (*pt);
  if (!pt)
    {
      cdk_pkt_release (pkt);
      cdk_stream_close (si);
      return CDK_Out_Of_Core;
    }
  memcpy (pt->name, pfx->filename, filelen);
  pt->namelen = filelen;
  pt->name[pt->namelen] = '\0';
  pt->timestamp = (u32) gnutls_time (NULL);
  pt->mode = intmode_to_char (pfx->mode);
  pt->len = cdk_stream_get_length (si);
  pt->buf = si;
  pkt->old_ctb = 1;
  pkt->pkttype = CDK_PKT_LITERAL;
  pkt->pkt.literal = pt;
  rc = _cdk_pkt_write_fp (out, pkt);

  cdk_pkt_release (pkt);
  cdk_stream_close (si);
  return rc;
}
コード例 #5
0
ファイル: gnutls_db.c プロジェクト: ares89/vlc
/**
 * gnutls_db_check_entry:
 * @session: is a #gnutls_session_t structure.
 * @session_entry: is the session data (not key)
 *
 * Check if database entry has expired.  This function is to be used
 * when you want to clear unnesessary session which occupy space in
 * your backend.
 *
 * Returns: Returns %GNUTLS_E_EXPIRED, if the database entry has
 *   expired or 0 otherwise.
 **/
int
gnutls_db_check_entry (gnutls_session_t session, gnutls_datum_t session_entry)
{
  time_t timestamp;

  timestamp = gnutls_time (0);

  if (session_entry.data != NULL)
    if (timestamp -
        ((security_parameters_st *) (session_entry.data))->timestamp <=
        session->internals.expire_time
        || ((security_parameters_st *) (session_entry.data))->timestamp >
        timestamp
        || ((security_parameters_st *) (session_entry.data))->timestamp == 0)
      return GNUTLS_E_EXPIRED;

  return 0;
}
コード例 #6
0
static int
do_device_source (int init)
{
  time_t now = gnutls_time (NULL);
  int read_size = DEVICE_READ_SIZE;

  if (init)
    {
      int old;

      if (!CryptAcquireContext
          (&device_fd, NULL, NULL, PROV_RSA_FULL,
           CRYPT_SILENT | CRYPT_VERIFYCONTEXT))
        {
          _gnutls_debug_log ("error in CryptAcquireContext!\n");
          return GNUTLS_E_INTERNAL_ERROR;
        }
      device_last_read = now;
      read_size = DEVICE_READ_SIZE_MAX; /* initially read more data */
    }

  if ((device_fd != 0)
      && (init || ((now - device_last_read) > DEVICE_READ_INTERVAL)))
    {

      /* More than 20 minutes since we last read the device */
      uint8_t buf[DEVICE_READ_SIZE_MAX];

      if (!CryptGenRandom (device_fd, (DWORD) read_size, buf))
        {
          _gnutls_debug_log ("Error in CryptGenRandom: %s\n",
                             GetLastError ());
          return GNUTLS_E_INTERNAL_ERROR;
        }

      device_last_read = now;
      return yarrow256_update (&yctx, RANDOM_SOURCE_DEVICE,
                               read_size * 8 /
                               2 /* we trust the system RNG */ ,
                               read_size, buf);
    }
  return 0;
}
コード例 #7
0
ファイル: gnutls_v2_compat.c プロジェクト: Distrotech/gnutls
/* Read a v2 client hello. Some browsers still use that beast!
 * However they set their version to 3.0 or 3.1.
 */
int
_gnutls_read_client_hello_v2(gnutls_session_t session, uint8_t * data,
			     unsigned int datalen)
{
	uint16_t session_id_len = 0;
	int pos = 0;
	int ret = 0, sret = 0;
	uint16_t sizeOfSuites;
	gnutls_protocol_t adv_version;
	uint8_t rnd[GNUTLS_RANDOM_SIZE];
	int len = datalen;
	uint16_t challenge;
	uint8_t session_id[GNUTLS_MAX_SESSION_ID_SIZE];

	DECR_LEN(len, 2);

	_gnutls_handshake_log
	    ("HSK[%p]: SSL 2.0 Hello: Client's version: %d.%d\n", session,
	     data[pos], data[pos + 1]);

	set_adv_version(session, data[pos], data[pos + 1]);

	adv_version = _gnutls_version_get(data[pos], data[pos + 1]);

	ret = _gnutls_negotiate_version(session, adv_version);
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	pos += 2;

	/* Read uint16_t cipher_spec_length */
	DECR_LEN(len, 2);
	sizeOfSuites = _gnutls_read_uint16(&data[pos]);
	pos += 2;

	/* read session id length */
	DECR_LEN(len, 2);
	session_id_len = _gnutls_read_uint16(&data[pos]);
	pos += 2;

	if (session_id_len > GNUTLS_MAX_SESSION_ID_SIZE) {
		gnutls_assert();
		return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
	}

	/* read challenge length */
	DECR_LEN(len, 2);
	challenge = _gnutls_read_uint16(&data[pos]);
	pos += 2;

	if (challenge < 16 || challenge > GNUTLS_RANDOM_SIZE) {
		gnutls_assert();
		return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
	}

	/* call the user hello callback
	 */
	ret = _gnutls_user_hello_func(session, adv_version);
	if (ret < 0) {
		if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) {
			sret = GNUTLS_E_INT_RET_0;
		} else {
			gnutls_assert();
			return ret;
		}
	}

	/* find an appropriate cipher suite */

	DECR_LEN(len, sizeOfSuites);
	ret =
	    _gnutls_handshake_select_v2_suite(session, &data[pos],
					      sizeOfSuites);

	pos += sizeOfSuites;
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	/* check if the credentials (username, public key etc.) are ok
	 */
	if (_gnutls_get_kx_cred
	    (session,
	     _gnutls_cipher_suite_get_kx_algo(session->security_parameters.
					      cipher_suite)) == NULL) {
		gnutls_assert();
		return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
	}

	/* set the mod_auth_st to the appropriate struct
	 * according to the KX algorithm. This is needed since all the
	 * handshake functions are read from there;
	 */
	session->internals.auth_struct =
	    _gnutls_kx_auth_struct(_gnutls_cipher_suite_get_kx_algo
				   (session->security_parameters.
				    cipher_suite));
	if (session->internals.auth_struct == NULL) {

		_gnutls_handshake_log
		    ("HSK[%p]: SSL 2.0 Hello: Cannot find the appropriate handler for the KX algorithm\n",
		     session);

		gnutls_assert();
		return GNUTLS_E_INTERNAL_ERROR;
	}

	/* read random new values -skip session id for now */
	DECR_LEN(len, session_id_len);	/* skip session id for now */
	memcpy(session_id, &data[pos], session_id_len);
	pos += session_id_len;

	DECR_LEN(len, challenge);
	memset(rnd, 0, GNUTLS_RANDOM_SIZE);

	memcpy(&rnd[GNUTLS_RANDOM_SIZE - challenge], &data[pos],
	       challenge);

	ret = _gnutls_set_client_random(session, rnd);
	if (ret < 0)
		return gnutls_assert_val(ret);

	/* generate server random value */
	ret = _gnutls_set_server_random(session, NULL);
	if (ret < 0)
		return gnutls_assert_val(ret);

	session->security_parameters.timestamp = gnutls_time(NULL);


	/* RESUME SESSION */

	DECR_LEN(len, session_id_len);
	ret =
	    _gnutls_server_restore_session(session, session_id,
					   session_id_len);

	if (ret == 0) {		/* resumed! */
		/* get the new random values */
		memcpy(session->internals.resumed_security_parameters.
		       server_random,
		       session->security_parameters.server_random,
		       GNUTLS_RANDOM_SIZE);
		memcpy(session->internals.resumed_security_parameters.
		       client_random,
		       session->security_parameters.client_random,
		       GNUTLS_RANDOM_SIZE);

		session->internals.resumed = RESUME_TRUE;
		return 0;
	} else {
		_gnutls_generate_session_id(session->security_parameters.
					    session_id,
					    &session->security_parameters.
					    session_id_size);
		session->internals.resumed = RESUME_FALSE;
	}

	_gnutls_epoch_set_compression(session, EPOCH_NEXT,
				      GNUTLS_COMP_NULL);
	session->security_parameters.compression_method = GNUTLS_COMP_NULL;

	return sret;
}
コード例 #8
0
ファイル: key_update.c プロジェクト: gnutls/gnutls
int _gnutls13_recv_key_update(gnutls_session_t session, gnutls_buffer_st *buf)
{
	int ret;
	time_t now = gnutls_time(0);

	if (buf->length != 1)
		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

	if (unlikely(now - session->internals.last_key_update < KEY_UPDATES_PER_SEC)) {
		_gnutls_debug_log("reached maximum number of key updates per second (%d)\n",
				  KEY_UPDATES_PER_SEC);
		return gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
	}

	session->internals.last_key_update = now;

	_gnutls_epoch_gc(session);

	_gnutls_handshake_log("HSK[%p]: received TLS 1.3 key update (%u)\n",
			      session, (unsigned)buf->data[0]);

	switch(buf->data[0]) {
	case 0:
		/* peer updated its key, not requested our key update */
		ret = update_keys(session, STAGE_UPD_PEERS);
		if (ret < 0)
			return gnutls_assert_val(ret);

		break;
	case 1:
		if (session->internals.hsk_flags & HSK_KEY_UPDATE_ASKED) {
			/* if we had asked a key update we shouldn't get this
			 * reply */
			return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
		}

		/* peer updated its key, requested our key update */
		ret = update_keys(session, STAGE_UPD_PEERS);
		if (ret < 0)
			return gnutls_assert_val(ret);

		/* we mark that a key update is schedule, and it
		 * will be performed prior to sending the next application
		 * message.
		 */
		if (session->internals.rsend_state == RECORD_SEND_NORMAL)
			session->internals.rsend_state = RECORD_SEND_KEY_UPDATE_1;
		else if (session->internals.rsend_state == RECORD_SEND_CORKED)
			session->internals.rsend_state = RECORD_SEND_CORKED_TO_KU;
		else
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);

		break;
	default:
		return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
	}

	session->internals.hsk_flags &= ~(unsigned)(HSK_KEY_UPDATE_ASKED);

	return 0;
}
コード例 #9
0
ファイル: verify.c プロジェクト: GostCrypt/GnuTLS
/* Verify X.509 certificate chain.
 *
 * Note that the return value is an OR of GNUTLS_CERT_* elements.
 *
 * This function verifies a X.509 certificate list. The certificate
 * list should lead to a trusted certificate in order to be trusted.
 */
unsigned int
_gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
				int clist_size,
				const gnutls_x509_crt_t * trusted_cas,
				int tcas_size,
				unsigned int flags,
				const char *purpose,
				gnutls_verify_output_function func)
{
	int i = 0, ret;
	unsigned int status = 0, output;
	time_t now = gnutls_time(0);
	verify_state_st vparams;

	if (clist_size > 1) {
		/* Check if the last certificate in the path is self signed.
		 * In that case ignore it (a certificate is trusted only if it
		 * leads to a trusted party by us, not the server's).
		 *
		 * This prevents from verifying self signed certificates against
		 * themselves. This (although not bad) caused verification
		 * failures on some root self signed certificates that use the
		 * MD2 algorithm.
		 */
		if (gnutls_x509_crt_check_issuer
		    (certificate_list[clist_size - 1],
		     certificate_list[clist_size - 1]) != 0) {
			clist_size--;
		}
	}

	/* We want to shorten the chain by removing the cert that matches
	 * one of the certs we trust and all the certs after that i.e. if
	 * cert chain is A signed-by B signed-by C signed-by D (signed-by
	 * self-signed E but already removed above), and we trust B, remove
	 * B, C and D. */
	if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME))
		i = 0;		/* also replace the first one */
	else
		i = 1;		/* do not replace the first one */

	for (; i < clist_size; i++) {
		int j;

		for (j = 0; j < tcas_size; j++) {
			/* we check for a certificate that may not be identical with the one
			 * sent by the client, but will have the same name and key. That is
			 * because it can happen that a CA certificate is upgraded from intermediate
			 * CA to self-signed CA at some point. */
			if (_gnutls_check_if_same_key
			    (certificate_list[i], trusted_cas[j], i) != 0) {
				/* explicit time check for trusted CA that we remove from
				 * list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS
				 */

				if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) &&
					!(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) {
					status |=
					    check_time_status(trusted_cas[j],
						       now);
					if (status != 0) {
						if (func)
							func(certificate_list[i], trusted_cas[j], NULL, status);
						return status;
					}
				}

				if (func)
					func(certificate_list[i],
					     trusted_cas[j], NULL, status);
				clist_size = i;
				break;
			}
		}
		/* clist_size may have been changed which gets out of loop */
	}

	if (clist_size == 0) {
		/* The certificate is already present in the trusted certificate list.
		 * Nothing to verify. */
		return status;
	}

	memset(&vparams, 0, sizeof(vparams));
	vparams.now = now;
	vparams.max_path = MAX_VERIFY_DEPTH;
	vparams.func = func;

	ret = gnutls_x509_name_constraints_init(&vparams.nc);
	if (ret < 0) {
		gnutls_assert();
		status |= GNUTLS_CERT_INVALID;
		return status;
	}

	ret = gnutls_x509_tlsfeatures_init(&vparams.tls_feat);
	if (ret < 0) {
		gnutls_assert();
		status |= GNUTLS_CERT_INVALID;
		goto cleanup;
	}

	/* Verify the last certificate in the certificate path
	 * against the trusted CA certificate list.
	 *
	 * If no CAs are present returns CERT_INVALID. Thus works
	 * in self signed etc certificates.
	 */
	output = 0;

	ret = verify_crt(certificate_list[clist_size - 1],
					  trusted_cas, tcas_size, flags,
					  &output,
					  &vparams,
					  clist_size==1?1:0);
	if (ret != 1) {
		/* if the last certificate in the certificate
		 * list is invalid, then the certificate is not
		 * trusted.
		 */
		gnutls_assert();
		status |= output;
		status |= GNUTLS_CERT_INVALID;
		goto cleanup;
	}

	/* Verify the certificate path (chain)
	 */
	for (i = clist_size - 1; i > 0; i--) {
		output = 0;
		if (i - 1 < 0)
			break;

		if (purpose != NULL) {
			ret = _gnutls_check_key_purpose(certificate_list[i], purpose, 1);
			if (ret != 1) {
				gnutls_assert();
				status |= GNUTLS_CERT_INVALID;
				status |= GNUTLS_CERT_PURPOSE_MISMATCH;

				if (func)
					func(certificate_list[i-1],
					     certificate_list[i], NULL, status);
				goto cleanup;
			}
		}

		/* note that here we disable this V1 CA flag. So that no version 1
		 * certificates can exist in a supplied chain.
		 */
		if (!(flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT)) {
			flags |= GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT;
		}

		if ((ret =
		     verify_crt(certificate_list[i - 1],
						 &certificate_list[i], 1,
						 flags, &output,
						 &vparams,
						 i==1?1:0)) != 1) {
			gnutls_assert();
			status |= output;
			status |= GNUTLS_CERT_INVALID;
			goto cleanup;
		}
	}

cleanup:
	gnutls_x509_name_constraints_deinit(vparams.nc);
	gnutls_x509_tlsfeatures_deinit(vparams.tls_feat);
	return status;
}
コード例 #10
0
ファイル: verify.c プロジェクト: GostCrypt/GnuTLS
/**
 * gnutls_x509_crl_verify:
 * @crl: is the crl to be verified
 * @trusted_cas: is a certificate list that is considered to be trusted one
 * @tcas_size: holds the number of CA certificates in CA_list
 * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations.
 * @verify: will hold the crl verification output.
 *
 * This function will try to verify the given crl and return its verification status.
 * See gnutls_x509_crt_list_verify() for a detailed description of
 * return values. Note that since GnuTLS 3.1.4 this function includes
 * the time checks.
 *
 * Note that value in @verify is set only when the return value of this 
 * function is success (i.e, failure to trust a CRL a certificate does not imply 
 * a negative return value).
 *
 * Before GnuTLS 3.5.7 this function would return zero or a positive
 * number on success.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0), otherwise a
 *   negative error value.
 **/
int
gnutls_x509_crl_verify(gnutls_x509_crl_t crl,
		       const gnutls_x509_crt_t * trusted_cas,
		       unsigned tcas_size, unsigned int flags,
		       unsigned int *verify)
{
/* CRL is ignored for now */
	gnutls_datum_t crl_signed_data = { NULL, 0 };
	gnutls_datum_t crl_signature = { NULL, 0 };
	gnutls_x509_crt_t issuer = NULL;
	int result, hash_algo;
	time_t now = gnutls_time(0);
	unsigned int usage;

	if (verify)
		*verify = 0;

	if (tcas_size >= 1)
		issuer = find_crl_issuer(crl, trusted_cas, tcas_size);

	result =
	    _gnutls_x509_get_signed_data(crl->crl, &crl->der, "tbsCertList",
					 &crl_signed_data);
	if (result < 0) {
		gnutls_assert();
		if (verify)
			*verify |= GNUTLS_CERT_INVALID;
		goto cleanup;
	}

	result =
	    _gnutls_x509_get_signature(crl->crl, "signature",
				       &crl_signature);
	if (result < 0) {
		gnutls_assert();
		if (verify)
			*verify |= GNUTLS_CERT_INVALID;
		goto cleanup;
	}

	result =
	    _gnutls_x509_get_signature_algorithm(crl->crl,
						 "signatureAlgorithm.algorithm");
	if (result < 0) {
		gnutls_assert();
		if (verify)
			*verify |= GNUTLS_CERT_INVALID;
		goto cleanup;
	}

	hash_algo = gnutls_sign_get_hash_algorithm(result);

	/* issuer is not in trusted certificate
	 * authorities.
	 */
	if (issuer == NULL) {
		gnutls_assert();
		if (verify)
			*verify |=
			    GNUTLS_CERT_SIGNER_NOT_FOUND |
			    GNUTLS_CERT_INVALID;
	} else {
		if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN)) {
			if (gnutls_x509_crt_get_ca_status(issuer, NULL) != 1) {
				gnutls_assert();
				if (verify)
					*verify |=
					    GNUTLS_CERT_SIGNER_NOT_CA |
					    GNUTLS_CERT_INVALID;
			}

			result =
			    gnutls_x509_crt_get_key_usage(issuer, &usage, NULL);
			if (result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
				if (result < 0) {
					gnutls_assert();
					if (verify)
						*verify |= GNUTLS_CERT_INVALID;
				} else if (!(usage & GNUTLS_KEY_CRL_SIGN)) {
					gnutls_assert();
					if (verify)
						*verify |=
						    GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE
						    | GNUTLS_CERT_INVALID;
				}
			}
		}

		result =
		    _gnutls_x509_verify_data(mac_to_entry(hash_algo),
					     &crl_signed_data, &crl_signature,
					     issuer);
		if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED) {
			gnutls_assert();
			/* error. ignore it */
			if (verify)
				*verify |= GNUTLS_CERT_SIGNATURE_FAILURE;
			result = 0;
		} else if (result < 0) {
			gnutls_assert();
			if (verify)
				*verify |= GNUTLS_CERT_INVALID;
			goto cleanup;
		} else if (result >= 0) {
			result = 0; /* everything ok */
		}
	}

	{
		int sigalg;

		sigalg = gnutls_x509_crl_get_signature_algorithm(crl);

		if (((sigalg == GNUTLS_SIGN_RSA_MD2) &&
		     !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) ||
		    ((sigalg == GNUTLS_SIGN_RSA_MD5) &&
		     !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5))) {
			if (verify)
				*verify |= GNUTLS_CERT_INSECURE_ALGORITHM;
			result = 0;
		}
	}

	if (gnutls_x509_crl_get_this_update(crl) > now && verify)
		*verify |= GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE;

	if (gnutls_x509_crl_get_next_update(crl) < now && verify)
		*verify |= GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED;


      cleanup:
	if (verify && *verify != 0)
		*verify |= GNUTLS_CERT_INVALID;

	_gnutls_free_datum(&crl_signed_data);
	_gnutls_free_datum(&crl_signature);

	return result;
}
コード例 #11
0
ファイル: verify.c プロジェクト: GostCrypt/GnuTLS
/* Verify X.509 certificate chain using a PKCS #11 token.
 *
 * Note that the return value is an OR of GNUTLS_CERT_* elements.
 *
 * Unlike the non-PKCS#11 version, this function accepts a key purpose
 * (from GNUTLS_KP_...). That is because in the p11-kit trust modules
 * anchors are mixed and get assigned a purpose.
 *
 * This function verifies a X.509 certificate list. The certificate
 * list should lead to a trusted certificate in order to be trusted.
 */
unsigned int
_gnutls_pkcs11_verify_crt_status(const char* url,
				const gnutls_x509_crt_t * certificate_list,
				unsigned clist_size,
				const char *purpose,
				unsigned int flags,
				gnutls_verify_output_function func)
{
	int ret;
	unsigned int status = 0, i;
	gnutls_x509_crt_t issuer = NULL;
	gnutls_datum_t raw_issuer = {NULL, 0};
	time_t now = gnutls_time(0);

	if (clist_size > 1) {
		/* Check if the last certificate in the path is self signed.
		 * In that case ignore it (a certificate is trusted only if it
		 * leads to a trusted party by us, not the server's).
		 *
		 * This prevents from verifying self signed certificates against
		 * themselves. This (although not bad) caused verification
		 * failures on some root self signed certificates that use the
		 * MD2 algorithm.
		 */
		if (gnutls_x509_crt_check_issuer
		    (certificate_list[clist_size - 1],
		     certificate_list[clist_size - 1]) != 0) {
			clist_size--;
		}
	}

	/* We want to shorten the chain by removing the cert that matches
	 * one of the certs we trust and all the certs after that i.e. if
	 * cert chain is A signed-by B signed-by C signed-by D (signed-by
	 * self-signed E but already removed above), and we trust B, remove
	 * B, C and D. */
	if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME))
		i = 0;		/* also replace the first one */
	else
		i = 1;		/* do not replace the first one */

	for (; i < clist_size; i++) {
		unsigned vflags;

		if (i == 0) /* in the end certificate do full comparison */
			vflags = GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
				GNUTLS_PKCS11_OBJ_FLAG_COMPARE|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED;
		else
			vflags = GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
				GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED;

		if (gnutls_pkcs11_crt_is_known (url, certificate_list[i], vflags) != 0) {

			if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) &&
				!(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) {
				status |=
				    check_time_status(certificate_list[i], now);
				if (status != 0) {
					if (func)
						func(certificate_list[i], certificate_list[i], NULL, status);
					return status;
				}
			}
			if (func)
				func(certificate_list[i],
				     certificate_list[i], NULL, status);

			clist_size = i;
			break;
		}
		/* clist_size may have been changed which gets out of loop */
	}

	if (clist_size == 0) {
		/* The certificate is already present in the trusted certificate list.
		 * Nothing to verify. */
		return status;
	}

	/* check for blacklists */
	for (i = 0; i < clist_size; i++) {
		if (gnutls_pkcs11_crt_is_known (url, certificate_list[i], 
			GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
			GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED) != 0) {
			status |= GNUTLS_CERT_INVALID;
			status |= GNUTLS_CERT_REVOKED;
			if (func)
				func(certificate_list[i], certificate_list[i], NULL, status);
			goto cleanup;
		}
	}

	/* check against issuer */
	ret = gnutls_pkcs11_get_raw_issuer(url, certificate_list[clist_size - 1],
					   &raw_issuer, GNUTLS_X509_FMT_DER,
					   GNUTLS_PKCS11_OBJ_FLAG_OVERWRITE_TRUSTMOD_EXT|GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE);
	if (ret < 0) {
		gnutls_assert();
		if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && clist_size > 2) {

			/* check if the last certificate in the chain is present
			 * in our trusted list, and if yes, verify against it. */
			ret = gnutls_pkcs11_crt_is_known(url, certificate_list[clist_size - 1],
				GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED|GNUTLS_PKCS11_OBJ_FLAG_COMPARE);
			if (ret != 0) {
				return _gnutls_verify_crt_status(certificate_list, clist_size,
					&certificate_list[clist_size - 1], 1, flags,
					purpose, func);
			}
		}

		status |= GNUTLS_CERT_INVALID;
		status |= GNUTLS_CERT_SIGNER_NOT_FOUND;
		/* verify the certificate list against 0 trusted CAs in order
		 * to get, any additional flags from the certificate list (e.g.,
		 * insecure algorithms or expired */
		status |= _gnutls_verify_crt_status(certificate_list, clist_size,
						    NULL, 0, flags, purpose, func);
		goto cleanup;
	}

	ret = gnutls_x509_crt_init(&issuer);
	if (ret < 0) {
		gnutls_assert();
		status |= GNUTLS_CERT_INVALID;
		status |= GNUTLS_CERT_SIGNER_NOT_FOUND;
		goto cleanup;
	}

	ret = gnutls_x509_crt_import(issuer, &raw_issuer, GNUTLS_X509_FMT_DER);
	if (ret < 0) {
		gnutls_assert();
		status |= GNUTLS_CERT_INVALID;
		status |= GNUTLS_CERT_SIGNER_NOT_FOUND;
		goto cleanup;
	}

	/* check if the raw issuer is blacklisted (it can happen if
	 * the issuer is both in the trusted list and the blacklisted)
	 */
	if (gnutls_pkcs11_crt_is_known (url, issuer,
		GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
		GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED) != 0) {
		status |= GNUTLS_CERT_INVALID;
		status |= GNUTLS_CERT_SIGNER_NOT_FOUND; /* if the signer is revoked - it is as if it doesn't exist */
		goto cleanup;
	}

	/* security modules that provide trust, bundle all certificates (of all purposes)
	 * together. In software that doesn't specify any purpose assume the default to
	 * be www-server. */
	ret = _gnutls_check_key_purpose(issuer, purpose==NULL?GNUTLS_KP_TLS_WWW_SERVER:purpose, 0);
	if (ret != 1) {
		gnutls_assert();
		status |= GNUTLS_CERT_INVALID;
		status |= GNUTLS_CERT_SIGNER_NOT_FOUND;
		goto cleanup;
	}

	status = _gnutls_verify_crt_status(certificate_list, clist_size,
				&issuer, 1, flags, purpose, func);

cleanup:
	gnutls_free(raw_issuer.data);
	if (issuer != NULL)
		gnutls_x509_crt_deinit(issuer);

	return status;
}
コード例 #12
0
ファイル: certificate.c プロジェクト: gnutls/gnutls
static
int append_status_request(void *_ctx, gnutls_buffer_st *buf)
{
	struct ocsp_req_ctx_st *ctx = _ctx;
	gnutls_session_t session = ctx->session;
	int ret;
	gnutls_datum_t resp;
	unsigned free_resp = 0;

	assert(session->internals.selected_ocsp_func != NULL ||
	       session->internals.selected_ocsp_length != 0);

	/* The global ocsp callback function can only be used to return
	 * a single certificate request */
	if (session->internals.selected_ocsp_length == 1 && ctx->cert_index != 0)
		return 0;

	if (session->internals.selected_ocsp_length > 0) {
		if (ctx->cert_index < session->internals.selected_ocsp_length) {
			if ((session->internals.selected_ocsp[ctx->cert_index].exptime != 0 &&
			    gnutls_time(0) >= session->internals.selected_ocsp[ctx->cert_index].exptime) ||
			    session->internals.selected_ocsp[ctx->cert_index].response.data == NULL) {
				return 0;
			}

			resp.data = session->internals.selected_ocsp[ctx->cert_index].response.data;
			resp.size = session->internals.selected_ocsp[ctx->cert_index].response.size;
			ret = 0;
		} else {
			return 0;
		}
	} else if (session->internals.selected_ocsp_func) {
		if (ctx->cert_index == 0) {
			ret = session->internals.selected_ocsp_func(session, session->internals.selected_ocsp_func_ptr, &resp);
			free_resp = 1;
		} else {
			return 0;
		}
	} else
		return 0;

	if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS || resp.data == 0) {
		return 0;
	} else if (ret < 0) {
		return gnutls_assert_val(ret);
	}

	ret = _gnutls_buffer_append_data(buf, "\x01", 1);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	ret = _gnutls_buffer_append_data_prefix(buf, 24, resp.data, resp.size);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	ret = 0;
 cleanup:
	if (free_resp)
		gnutls_free(resp.data);
	return ret;
}
コード例 #13
0
ファイル: session_ticket.c プロジェクト: GostCrypt/GnuTLS
static int
encrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv,
               struct ticket_st *ticket)
{
    cipher_hd_st cipher_hd;
    gnutls_datum_t key, IV;
    gnutls_datum_t state = {NULL,0}, encrypted_state = {NULL,0};
    uint8_t iv[IV_SIZE];
    gnutls_datum_t mac_secret;
    uint32_t t;
    int ret;

    /* Pack security parameters. */
    ret = _gnutls_session_pack(session, &state);
    if (ret < 0) {
        gnutls_assert();
        return ret;
    }

    encrypted_state.size = ((state.size + BLOCK_SIZE - 1) / BLOCK_SIZE) * BLOCK_SIZE;
    encrypted_state.data = gnutls_calloc(1, encrypted_state.size);
    if (!encrypted_state.data) {
        gnutls_assert();
        ret = GNUTLS_E_MEMORY_ERROR;
        goto cleanup;
    }
    memcpy(encrypted_state.data, state.data, state.size);

    /* Encrypt state */
    key.data = (void *) &priv->key[KEY_POS];
    key.size = CIPHER_KEY_SIZE;
    IV.data = iv;
    IV.size = IV_SIZE;

    t = gnutls_time(0);
    memcpy(iv, &t, 4);
    ret = gnutls_rnd(GNUTLS_RND_NONCE, iv+4, IV_SIZE-4);
    if (ret < 0) {
        gnutls_assert();
        goto cleanup;
    }

    ret =
        _gnutls_cipher_init(&cipher_hd,
                            cipher_to_entry(CIPHER),
                            &key, &IV, 1);
    if (ret < 0) {
        gnutls_assert();
        goto cleanup;
    }

    ret = _gnutls_cipher_encrypt(&cipher_hd, encrypted_state.data,
                                 encrypted_state.size);
    if (ret < 0) {
        gnutls_assert();
        goto cleanup2;
    }


    /* Fill the ticket structure to compute MAC. */
    memcpy(ticket->key_name, &priv->key[NAME_POS], KEY_NAME_SIZE);
    memcpy(ticket->IV, IV.data, IV.size);
    ticket->encrypted_state_len = encrypted_state.size;
    ticket->encrypted_state = encrypted_state.data;

    mac_secret.data = &priv->key[MAC_SECRET_POS];
    mac_secret.size = MAC_SECRET_SIZE;
    ret = digest_ticket(&mac_secret, ticket, ticket->mac);
    if (ret < 0) {
        gnutls_assert();
        goto cleanup2;
    }

    encrypted_state.data = NULL;

    ret = 0;

cleanup2:
    _gnutls_cipher_deinit(&cipher_hd);

cleanup:
    _gnutls_free_datum(&state);
    _gnutls_free_datum(&encrypted_state);

    return ret;
}
コード例 #14
0
ファイル: gnutls_record.c プロジェクト: intgr/gnutls
/* This will receive record layer packets and add them to 
 * application_data_buffer and handshake_data_buffer.
 *
 * If the htype is not -1 then handshake timeouts
 * will be enforced.
 */
ssize_t
_gnutls_recv_in_buffers (gnutls_session_t session, content_type_t type,
                         gnutls_handshake_description_t htype)
{
  uint64 *packet_sequence;
  uint8_t *ciphertext;
  mbuffer_st* bufel = NULL, *decrypted = NULL;
  int ret;
  int empty_packet = 0;
  record_parameters_st *record_params;
  record_state_st *record_state;
  struct tls_record_st record;
  time_t now, tleft = 0;

begin:

  if (empty_packet > MAX_EMPTY_PACKETS_SEQUENCE)
    {
      gnutls_assert ();
      return GNUTLS_E_TOO_MANY_EMPTY_PACKETS;
    }

  memset(&record, 0, sizeof(record));

  if (session->internals.read_eof != 0)
    {
      /* if we have already read an EOF
       */
      return 0;
    }
  else if (session_is_valid (session) != 0
           || session->internals.may_not_read != 0)
    return gnutls_assert_val(GNUTLS_E_INVALID_SESSION);

  /* get the record state parameters */
  ret = _gnutls_epoch_get (session, EPOCH_READ_CURRENT, &record_params);
  if (ret < 0)
    return gnutls_assert_val (ret);

  /* Safeguard against processing data with an incomplete cipher state. */
  if (!record_params->initialized)
    return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);

  record_state = &record_params->read;

  if (htype != (unsigned)-1 && session->internals.handshake_endtime > 0)
    {
      now = gnutls_time(0);
      if (now < session->internals.handshake_endtime)
        tleft = (session->internals.handshake_endtime - now) * 1000;
      else
        return gnutls_assert_val(GNUTLS_E_TIMEDOUT);
    }

  /* receive headers */
  ret = recv_headers(session, type, htype, &record, tleft);
  if (ret < 0)
    {
      ret = gnutls_assert_val_fatal(ret);
      goto recv_error;
    }

  if (IS_DTLS(session)) 
    packet_sequence = &record.sequence;
  else
    packet_sequence = &record_state->sequence_number;

  if (htype != (unsigned)-1 && session->internals.handshake_endtime > 0)
    {
      now = gnutls_time(0);
      if (now < session->internals.handshake_endtime)
        tleft = (session->internals.handshake_endtime - now) * 1000;
      else
        return gnutls_assert_val(GNUTLS_E_TIMEDOUT);
    }

  /* Read the packet data and insert it to record_recv_buffer.
   */
  ret =
       _gnutls_io_read_buffered (session, record.packet_size,
                                 record.type, tleft);
  if (ret != record.packet_size)
    {
      gnutls_assert();
      goto recv_error;
    }

  /* ok now we are sure that we have read all the data - so
   * move on !
   */
  ret = _mbuffer_linearize (&session->internals.record_recv_buffer);
  if (ret < 0)
    return gnutls_assert_val(ret);

  bufel = _mbuffer_head_get_first (&session->internals.record_recv_buffer, NULL);
  if (bufel == NULL)
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

  /* We allocate the maximum possible to allow few compressed bytes to expand to a
   * full record.
   */
  decrypted = _mbuffer_alloc(MAX_RECORD_RECV_SIZE(session), 
                             MAX_RECORD_RECV_SIZE(session));
  if (decrypted == NULL)
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

  ciphertext = (uint8_t*)_mbuffer_get_udata_ptr(bufel) + record.header_size;

  /* decrypt the data we got. 
   */
  ret =
    _gnutls_decrypt (session, ciphertext, record.length, 
        _mbuffer_get_udata_ptr(decrypted), _mbuffer_get_udata_size(decrypted),
		     record.type, record_params, packet_sequence);
  if (ret >= 0) _mbuffer_set_udata_size(decrypted, ret);

  _mbuffer_head_remove_bytes (&session->internals.record_recv_buffer,
                              record.header_size + record.length);
  if (ret < 0)
    {
      gnutls_assert();
      _gnutls_audit_log(session, "Discarded message[%u] due to invalid decryption\n", 
            (unsigned int)_gnutls_uint64touint32 (packet_sequence));
      goto sanity_check_error;
    }

  /* check for duplicates. We check after the message
   * is processed and authenticated to avoid someone
   * messing with our windows.
   */
  if (IS_DTLS(session)) 
    {
      ret = _dtls_record_check(record_params, packet_sequence);
      if (ret < 0)
        {
          _gnutls_audit_log(session, "Discarded duplicate message[%u]: %s\n",
            (unsigned int) _gnutls_uint64touint32 (packet_sequence), _gnutls_packet2str (record.type));
          goto sanity_check_error;
        }
      _gnutls_record_log
        ("REC[%p]: Decrypted Packet[%u.%u] %s(%d) with length: %d\n", session,
        (unsigned int)record.sequence.i[0]*256 +(unsigned int)record.sequence.i[1],
        (unsigned int) _gnutls_uint64touint32 (packet_sequence),
        _gnutls_packet2str (record.type), record.type, (int)_mbuffer_get_udata_size(decrypted));
    }
  else
    {
      _gnutls_record_log
        ("REC[%p]: Decrypted Packet[%u] %s(%d) with length: %d\n", session,
        (unsigned int) _gnutls_uint64touint32 (packet_sequence),
        _gnutls_packet2str (record.type), record.type, (int)_mbuffer_get_udata_size(decrypted));
    }

  /* increase sequence number 
   */
  if (!IS_DTLS(session) && sequence_increment (session, &record_state->sequence_number) != 0)
    {
      session_invalidate (session);
      gnutls_assert ();
      ret = GNUTLS_E_RECORD_LIMIT_REACHED;
      goto sanity_check_error;
    }

/* (originally for) TLS 1.0 CBC protection. 
 * Actually this code is called if we just received
 * an empty packet. An empty TLS packet is usually
 * sent to protect some vulnerabilities in the CBC mode.
 * In that case we go to the beginning and start reading
 * the next packet.
 */
  if (_mbuffer_get_udata_size(decrypted) == 0)
    {
      _mbuffer_xfree(&decrypted);
      empty_packet++;
      goto begin;
    }

  if (record.v2)
    decrypted->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2;
  else
    {
      uint8_t * p = _mbuffer_get_udata_ptr(decrypted);
      decrypted->htype = p[0];
    }

  ret =
    record_add_to_buffers (session, &record, type, htype, 
                           packet_sequence, decrypted);

  /* bufel is now either deinitialized or buffered somewhere else */

  if (ret < 0)
    return gnutls_assert_val(ret);

  return ret;

discard:
  session->internals.dtls.packets_dropped++;

  /* discard the whole received fragment. */
  bufel = _mbuffer_head_pop_first(&session->internals.record_recv_buffer);
  _mbuffer_xfree(&bufel);
  return gnutls_assert_val(GNUTLS_E_AGAIN);

sanity_check_error:
  if (IS_DTLS(session))
    {
      session->internals.dtls.packets_dropped++;
      ret = gnutls_assert_val(GNUTLS_E_AGAIN);
      goto cleanup;
    }

  session_unresumable (session);
  session_invalidate (session);

cleanup:
  _mbuffer_xfree(&decrypted);
  return ret;

recv_error:
  if (ret < 0 && gnutls_error_is_fatal (ret) == 0)
    return ret;

  if (IS_DTLS(session))
    {
      goto discard;
    }

  session_invalidate (session);
  if (type == GNUTLS_ALERT) /* we were expecting close notify */
    {
      gnutls_assert ();
      return 0;             
    }
  session_unresumable (session);

  if (ret == 0)
    return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
  else
    return ret;
}
コード例 #15
0
static int
do_device_source_urandom (int init)
{
  time_t now = gnutls_time (NULL);
  unsigned int read_size = DEVICE_READ_SIZE;

  if (init)
    {
      int old;

      device_fd = open ("/dev/urandom", O_RDONLY);
      if (device_fd < 0)
        {
          _gnutls_debug_log ("Cannot open urandom!\n");
          return GNUTLS_E_FILE_ERROR;
        }

      old = fcntl (device_fd, F_GETFD);
      fcntl (device_fd, F_SETFD, old | 1);
      device_last_read = now;

      read_size = DEVICE_READ_SIZE_MAX; /* initially read more data */
    }

  if ((device_fd > 0)
      && (init || ((now - device_last_read) > DEVICE_READ_INTERVAL)))
    {
      /* More than 20 minutes since we last read the device */
      uint8_t buf[DEVICE_READ_SIZE_MAX];
      uint32_t done;

      for (done = 0; done < read_size;)
        {
          int res;
          do
            res = read (device_fd, buf + done, sizeof (buf) - done);
          while (res < 0 && errno == EINTR);

          if (res <= 0)
            {
              if (res < 0)
                {
                  _gnutls_debug_log ("Failed to read /dev/urandom: %s\n",
                                     strerror (errno));
                }
              else
                {
                  _gnutls_debug_log
                    ("Failed to read /dev/urandom: end of file\n");
                }

              return GNUTLS_E_INTERNAL_ERROR;
            }

          done += res;
        }

      device_last_read = now;
      return yarrow256_update (&yctx, RANDOM_SOURCE_DEVICE,
                               read_size * 8 / 2 /* we trust the RNG */ ,
                               read_size, buf);
    }
  return 0;
}
コード例 #16
0
ファイル: rnd.c プロジェクト: GostCrypt/GnuTLS
static int
wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize)
{
	struct generators_ctx_st *ctx = _ctx;
	struct prng_ctx_st *prng_ctx;
	int ret, reseed = 0;
	uint8_t new_key[PRNG_KEY_SIZE];
	time_t now;

	if (level == GNUTLS_RND_RANDOM || level == GNUTLS_RND_KEY)
		prng_ctx = &ctx->normal;
	else if (level == GNUTLS_RND_NONCE)
		prng_ctx = &ctx->nonce;
	else
		return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);

	/* Two reasons for this memset():
	 *  1. avoid getting filled with valgrind warnings
	 *  2. avoid a cipher/PRNG failure to expose stack data
	 */
	memset(data, 0, datasize);

	now = gnutls_time(0);

	/* We re-seed based on time in addition to output data. That is,
	 * to prevent a temporal state compromise to become permanent for low
	 * traffic sites */
	if (unlikely(_gnutls_detect_fork(prng_ctx->forkid))) {
		reseed = 1;
	} else {
		if (now > prng_ctx->last_reseed + prng_reseed_time[level])
			reseed = 1;
	}

	if (reseed != 0 || prng_ctx->counter > prng_reseed_limits[level]) {
		if (level == GNUTLS_RND_NONCE) {
			ret = wrap_nettle_rnd(_ctx, GNUTLS_RND_RANDOM, new_key, sizeof(new_key));
		} else {

			/* we also use the system entropy to reduce the impact
			 * of a temporal state compromise for these two levels. */
			ret = _rnd_get_system_entropy(new_key, sizeof(new_key));
		}

		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		ret = single_prng_init(prng_ctx, new_key, sizeof(new_key), 0);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		prng_ctx->last_reseed = now;
		prng_ctx->forkid = _gnutls_get_forkid();
	}

	chacha_crypt(&prng_ctx->ctx, datasize, data, data);
	prng_ctx->counter += datasize;

	if (level == GNUTLS_RND_KEY) { /* prevent backtracking */
		ret = wrap_nettle_rnd(_ctx, GNUTLS_RND_RANDOM, new_key, sizeof(new_key));
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		ret = single_prng_init(prng_ctx, new_key, sizeof(new_key), 0);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}
	}

	ret = 0;

cleanup:
	return ret;
}
コード例 #17
0
ファイル: verify.c プロジェクト: intgr/gnutls
/* Verify X.509 certificate chain.
 *
 * Note that the return value is an OR of GNUTLS_CERT_* elements.
 *
 * This function verifies a X.509 certificate list. The certificate
 * list should lead to a trusted certificate in order to be trusted.
 */
unsigned int
_gnutls_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list,
                                 int clist_size,
                                 const gnutls_x509_crt_t * trusted_cas,
                                 int tcas_size,
                                 unsigned int flags, 
                                 gnutls_verify_output_function func)
{
  int i = 0, ret;
  unsigned int status = 0, output;
  time_t now = gnutls_time (0);
  gnutls_x509_crt_t issuer = NULL;

  if (clist_size > 1)
    {
      /* Check if the last certificate in the path is self signed.
       * In that case ignore it (a certificate is trusted only if it
       * leads to a trusted party by us, not the server's).
       *
       * This prevents from verifying self signed certificates against
       * themselves. This (although not bad) caused verification
       * failures on some root self signed certificates that use the
       * MD2 algorithm.
       */
      if (gnutls_x509_crt_check_issuer (certificate_list[clist_size - 1],
                                        certificate_list[clist_size - 1]) > 0)
        {
          clist_size--;
        }
    }

  /* We want to shorten the chain by removing the cert that matches
   * one of the certs we trust and all the certs after that i.e. if
   * cert chain is A signed-by B signed-by C signed-by D (signed-by
   * self-signed E but already removed above), and we trust B, remove
   * B, C and D. */
  if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME))
    i = 0;                      /* also replace the first one */
  else
    i = 1;                      /* do not replace the first one */

  for (; i < clist_size; i++)
    {
      int j;

      for (j = 0; j < tcas_size; j++)
        {
          if (check_if_same_cert (certificate_list[i], trusted_cas[j]) == 0)
            {
              /* explicity time check for trusted CA that we remove from
               * list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS
               */
              if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS)
                  && !(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS))
                {
                  status |= check_time (trusted_cas[j], now);
                  if (status != 0)
                    {
                      if (func) func(certificate_list[i], trusted_cas[j], NULL, status);
                      return status;
                    }
                }

              if (func) func(certificate_list[i], trusted_cas[j], NULL, status);
              clist_size = i;
              break;
            }
        }
      /* clist_size may have been changed which gets out of loop */
    }

  if (clist_size == 0)
    {
      /* The certificate is already present in the trusted certificate list.
       * Nothing to verify. */
      return status;
    }

  /* Verify the last certificate in the certificate path
   * against the trusted CA certificate list.
   *
   * If no CAs are present returns CERT_INVALID. Thus works
   * in self signed etc certificates.
   */
  output = 0;
  ret = _gnutls_verify_certificate2 (certificate_list[clist_size - 1],
                                     trusted_cas, tcas_size, flags, &output,
                                     &issuer, now, func);
  if (ret == 0)
    {
      /* if the last certificate in the certificate
       * list is invalid, then the certificate is not
       * trusted.
       */
      gnutls_assert ();
      status |= output;
      status |= GNUTLS_CERT_INVALID;
      return status;
    }

  /* Verify the certificate path (chain)
   */
  for (i = clist_size - 1; i > 0; i--)
    {
      output = 0;
      if (i - 1 < 0)
        break;

      /* note that here we disable this V1 CA flag. So that no version 1
       * certificates can exist in a supplied chain.
       */
      if (!(flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT))
        flags &= ~(GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
      if ((ret =
           _gnutls_verify_certificate2 (certificate_list[i - 1],
                                        &certificate_list[i], 1, flags,
                                        &output, NULL, now, func)) == 0)
        {
          status |= output;
          status |= GNUTLS_CERT_INVALID;
          return status;
        }
    }

  return 0;
}
コード例 #18
0
ファイル: session_ticket.c プロジェクト: GostCrypt/GnuTLS
static int
decrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv,
               struct ticket_st *ticket)
{
    cipher_hd_st cipher_hd;
    gnutls_datum_t key, IV, state, mac_secret;
    uint8_t cmac[MAC_SIZE];
    time_t timestamp = gnutls_time(0);
    int ret;

    /* Check the integrity of ticket */
    mac_secret.data = (void *) &priv->key[MAC_SECRET_POS];
    mac_secret.size = MAC_SECRET_SIZE;
    ret = digest_ticket(&mac_secret, ticket, cmac);
    if (ret < 0)
        return gnutls_assert_val(ret);

    if (memcmp(ticket->mac, cmac, MAC_SIZE))
        return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

    if (ticket->encrypted_state_len % BLOCK_SIZE != 0)
        return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

    /* Decrypt encrypted_state */
    key.data = (void *) &priv->key[KEY_POS];
    key.size = CIPHER_KEY_SIZE;
    IV.data = ticket->IV;
    IV.size = IV_SIZE;
    ret =
        _gnutls_cipher_init(&cipher_hd,
                            cipher_to_entry(CIPHER),
                            &key, &IV, 0);
    if (ret < 0) {
        gnutls_assert();
        return ret;
    }
    ret = _gnutls_cipher_decrypt(&cipher_hd, ticket->encrypted_state,
                                 ticket->encrypted_state_len);
    if (ret < 0) {
        gnutls_assert();
        goto cleanup;
    }

    /* Unpack security parameters. */
    state.data = ticket->encrypted_state;
    state.size = ticket->encrypted_state_len;
    ret = _gnutls_session_unpack(session, &state);
    if (ret < 0) {
        gnutls_assert();
        goto cleanup;
    }

    if (timestamp -
            session->internals.resumed_security_parameters.timestamp >
            session->internals.expire_time
            || session->internals.resumed_security_parameters.timestamp >
            timestamp) {
        gnutls_assert();
        ret = GNUTLS_E_EXPIRED;
        goto cleanup;
    }

    ret = _gnutls_check_resumed_params(session);
    if (ret < 0) {
        gnutls_assert();
        goto cleanup;
    }

    session->internals.resumed = RESUME_TRUE;

    ret = 0;
cleanup:
    _gnutls_cipher_deinit(&cipher_hd);

    return ret;

}