예제 #1
0
static mod_context *mod_gnutls_context_new(liServer *srv) {
	mod_context *ctx = g_slice_new0(mod_context);
	int r;

	if (GNUTLS_E_SUCCESS > (r = gnutls_certificate_allocate_credentials(&ctx->server_cert))) {
		ERROR(srv, "gnutls_certificate_allocate_credentials failed(%s): %s",
			gnutls_strerror_name(r), gnutls_strerror(r));
		goto error0;
	}

	if (GNUTLS_E_SUCCESS > (r = gnutls_priority_init(&ctx->server_priority, "NORMAL", NULL))) {
		ERROR(srv, "gnutls_priority_init('NORMAL') failed(%s): %s",
			gnutls_strerror_name(r), gnutls_strerror(r));
		goto error1;
	}

	if (GNUTLS_E_SUCCESS > (r = gnutls_priority_init(&ctx->server_priority_beast, "NORMAL:-CIPHER-ALL:+ARCFOUR-128", NULL))) {
		int r1;
		if (GNUTLS_E_SUCCESS > (r1 = gnutls_priority_init(&ctx->server_priority_beast, "NORMAL", NULL))) {
			ERROR(srv, "gnutls_priority_init('NORMAL') failed(%s): %s",
				gnutls_strerror_name(r1), gnutls_strerror(r1));
			goto error2;
		} else {
			ERROR(srv, "gnutls_priority_init('NORMAL:-CIPHER-ALL:+ARCFOUR-128') failed(%s): %s. Using 'NORMAL' instead (BEAST mitigation not available)",
				gnutls_strerror_name(r), gnutls_strerror(r));
		}
	}

#ifdef HAVE_SESSION_TICKET
	if (GNUTLS_E_SUCCESS > (r = gnutls_session_ticket_key_generate(&ctx->ticket_key))) {
		ERROR(srv, "gnutls_session_ticket_key_generate failed(%s): %s",
			gnutls_strerror_name(r), gnutls_strerror(r));
		goto error3;
	}
#endif

	ctx->srv = srv;

	ctx->ocsp = li_gnutls_ocsp_new();

	ctx->refcount = 1;
	ctx->protect_against_beast = 1;

	return ctx;

error3:
	gnutls_priority_deinit(ctx->server_priority_beast);

error2:
	gnutls_priority_deinit(ctx->server_priority);

error1:
	gnutls_certificate_free_credentials(ctx->server_cert);

error0:
	g_slice_free(mod_context, ctx);
	return NULL;
}
예제 #2
0
static int main_texinfo(void)
{
	int i, j;
	const char *desc;
	const char *_name;
	char buffer[500];
	error_name names_to_sort[MAX_CODES];	/* up to MAX_CODES names  */

	printf("@multitable @columnfractions .15 .40 .37\n");

	memset(names_to_sort, 0, sizeof(names_to_sort));
	j = 0;
	for (i = 0; i > -MAX_CODES; i--) {
		_name = gnutls_strerror_name(i);
		if (_name == NULL)
			continue;

		desc = gnutls_strerror(i);

		printf("@item %d @tab %s @tab %s\n", i,
		       escape_texi_string(_name, buffer, sizeof(buffer)),
		       desc);

		strcpy(names_to_sort[j].name, _name);
		names_to_sort[j].error_index = i;
		j++;
	}

	printf("@end multitable\n");

	return 0;
}
예제 #3
0
gboolean li_gnutls_ocsp_search_datum(liServer *srv, liGnuTLSOCSP *ocsp, gnutls_datum_t const* file) {
	int r;
	gnutls_datum_t decoded = { NULL, 0 };
	gboolean result = FALSE;

	r = gnutls_pem_base64_decode_alloc("OCSP RESPONSE", file, &decoded);

	if (GNUTLS_E_SUCCESS <= r) {
		result = add_response(srv, ocsp, &decoded);
		if (!result) {
			ERROR(srv, "%s", "Failed loading OCSP response from PEM block");
			goto error;
		}
	} else if (GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR == r) {
		/* ignore GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR */
	} else {
		ERROR(srv, "gnutls_pem_base64_decode_alloc failed to decode OCSP RESPONSE from PEM block (%s): %s",
			gnutls_strerror_name(r), gnutls_strerror(r));
		/* continue anyway */
	}
	result = TRUE;

error:
	gnutls_free(decoded.data);
	return result;
}
예제 #4
0
static void do_handle_error(liGnuTLSFilter *f, const char *gnutlsfunc, int r, gboolean writing) {
	switch (r) {
	case GNUTLS_E_AGAIN:
		if (writing) f->write_wants_read = TRUE;
		break;
	case GNUTLS_E_REHANDSHAKE:
#ifdef HAVE_SAVE_RENEGOTIATION
		if (f->initial_handshaked_finished && !gnutls_safe_renegotiation_status(f->session)) {
			_ERROR(f->srv, f->wrk, f->log_context, "%s: client initiated unsafe renegotitation, closing connection", gnutlsfunc);
			f_close_with_alert(f, r);
		} else {
			_DEBUG(f->srv, f->wrk, f->log_context, "%s: client initiated renegotitation", gnutlsfunc);
		}
#else
		if (f->initial_handshaked_finished) {
			_ERROR(f->srv, f->wrk, f->log_context, "%s: client initiated renegotitation, closing connection", gnutlsfunc);
			f_close_with_alert(f, r);
		}
#endif
		break;
	case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
		f_close_with_alert(f, r);
		break;
	case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
	case GNUTLS_E_UNSUPPORTED_VERSION_PACKET:
		_DEBUG(f->srv, f->wrk, f->log_context, "%s (%s): %s", gnutlsfunc,
			gnutls_strerror_name(r), gnutls_strerror(r));
		f_close_with_alert(f, r);
		break;
	default:
		if (gnutls_error_is_fatal(r)) {
			_ERROR(f->srv, f->wrk, f->log_context, "%s (%s): %s", gnutlsfunc,
				gnutls_strerror_name(r), gnutls_strerror(r));
			if (f->initial_handshaked_finished) {
				f_close_with_alert(f, r);
			} else {
				f_abort_gnutls(f);
			}
		} else {
			_ERROR(f->srv, f->wrk, f->log_context, "%s non fatal (%s): %s", gnutlsfunc,
				gnutls_strerror_name(r), gnutls_strerror(r));
		}
	}
}
예제 #5
0
/* pass ownership of der_data */
static gboolean add_response(liServer *srv, liGnuTLSOCSP *ocsp, gnutls_datum_t* der_data) {
	ocsp_response response;
	int r;
	guint i;

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

	response.resp_data = *der_data;
	der_data->data = NULL; der_data->size = 0;

	if (GNUTLS_E_SUCCESS > (r = gnutls_ocsp_resp_init(&response.resp))) {
		ERROR(srv, "gnutls_ocsp_resp_init (%s): %s",
			gnutls_strerror_name(r), gnutls_strerror(r));
		goto error;
	}

	if (GNUTLS_E_SUCCESS > (r = gnutls_ocsp_resp_import(response.resp, &response.resp_data))) {
		ERROR(srv, "gnutls_ocsp_resp_import (%s): %s",
			gnutls_strerror_name(r), gnutls_strerror(r));
		goto error;
	}

	response.certificates = g_array_new(FALSE, TRUE, sizeof(ocsp_response_cert_entry));
	for (i = 0; ; ++i) {
		ocsp_response_cert_entry entry;

		r = get_entry(srv, &entry, response.resp, i);
		if (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE == r) break; /* got them all */
		if (GNUTLS_E_SUCCESS > r) goto error;

		g_array_append_vals(response.certificates, &entry, 1);

		if (entry.serial.size > ocsp->max_serial_length) ocsp->max_serial_length = entry.serial.size;
		if (entry.issuer_name_hash.size > ocsp->max_hash_length) ocsp->max_hash_length = entry.issuer_name_hash.size;
	}

	g_array_append_vals(ocsp->responses, &response, 1);
	return TRUE;

error:
	clear_response(&response);
	return FALSE;
}
예제 #6
0
gboolean li_gnutls_ocsp_add(liServer *srv, liGnuTLSOCSP *ocsp, const char* filename) {
	int r;
	gnutls_datum_t file = { NULL, 0 };
	gnutls_datum_t decoded = { NULL, 0 };
	gnutls_datum_t* der_data;
	gboolean result = FALSE;

	if (GNUTLS_E_SUCCESS > (r = gnutls_load_file(filename, &file))) {
		ERROR(srv, "Failed to load OCSP file '%s' (%s): %s",
				filename,
				gnutls_strerror_name(r), gnutls_strerror(r));
		goto error;
	}

	/* decode pem "-----BEGIN OCSP RESPONSE-----", otherwise expect DER */
	if (file.size > 20 && 0 == memcmp(file.data, CONST_STR_LEN("-----BEGIN "))) {
		r = gnutls_pem_base64_decode_alloc("OCSP RESPONSE", &file, &decoded);

		if (GNUTLS_E_SUCCESS > r) {
			ERROR(srv, "gnutls_pem_base64_decode_alloc failed to decode OCSP RESPONSE from '%s' (%s): %s",
				filename,
				gnutls_strerror_name(r), gnutls_strerror(r));
			goto error;
		}
		der_data = &decoded;
	} else {
		der_data = &file;
	}

	result = add_response(srv, ocsp, der_data);
	if (!result) {
		ERROR(srv, "Failed loading OCSP response from '%s'", filename);
	}

error:
	gnutls_free(file.data);
	gnutls_free(decoded.data);
	return result;
}
예제 #7
0
static Eina_Bool
_process_data(gnutls_session_t client, Ecore_Fd_Handler * fd_handler)
{
	static int ret, lastret;
	static unsigned int count = 0;

	if (!done) {
		lastret = ret;
		ret = gnutls_handshake(client);
		count++;
		if (gnutls_record_get_direction(client))
			ecore_main_fd_handler_active_set(fd_handler,
							 ECORE_FD_WRITE);
		else
			ecore_main_fd_handler_active_set(fd_handler,
							 ECORE_FD_READ);
		/* avoid printing messages infinity times */
		if (lastret != ret && ret != 0 && ret != GNUTLS_E_AGAIN) {
			print("gnutls returned with: %s - %s",
			      gnutls_strerror_name(ret),
			      gnutls_strerror(ret));
			if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
			    || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED))
				print("Also received alert: %s",
				      gnutls_alert_get_name
				      (gnutls_alert_get(client)));
			print("last out: %s",
			      SSL_GNUTLS_PRINT_HANDSHAKE_STATUS
			      (gnutls_handshake_get_last_out(client)));
			print("last in: %s",
			      SSL_GNUTLS_PRINT_HANDSHAKE_STATUS
			      (gnutls_handshake_get_last_in(client)));
		}

		if (gnutls_error_is_fatal(ret)) {
			print("yarrr this be an error!");
			exit(1);
		}

	}
	if (ret == GNUTLS_E_SUCCESS) {
		done = 1;
		//print("Handshake successful in %u handshake calls!", count);
		ecore_main_loop_quit();
	}

	return ECORE_CALLBACK_RENEW;
}
예제 #8
0
static void main_latex(void)
{
	int i, j;
	static char buffer1[500];
	static char buffer2[500];
	const char *desc;
	const char *_name;
	error_name names_to_sort[MAX_CODES];	/* up to MAX_CODES names  */

	puts(headers);

	printf
	    ("\\begin{supertabular}{|p{.05\\linewidth}|p{.40\\linewidth}|p{.45\\linewidth}|}\n");

	memset(names_to_sort, 0, sizeof(names_to_sort));
	j = 0;
	for (i = 0; i > -MAX_CODES; i--) {
		_name = gnutls_strerror_name(i);
		if (_name == NULL)
			continue;

		strcpy(names_to_sort[j].name, _name);
		names_to_sort[j].error_index = i;
		j++;
	}

//qsort( names_to_sort, j, sizeof(error_name), compar);

	for (i = 0; i < j; i++) {
		_name = names_to_sort[i].name;
		desc = gnutls_strerror(names_to_sort[i].error_index);
		if (desc == NULL || _name == NULL)
			continue;

		printf("%d & {\\scriptsize{%s}} & %s",
		       names_to_sort[i].error_index, escape_string(_name,
								   buffer1,
								   sizeof
								   (buffer1)),
		       escape_string(desc, buffer2, sizeof(buffer2)));
		printf("\\\\\n");
	}

	printf("\\end{supertabular}\n\n");

	return;

}
예제 #9
0
int main(int argc, char *argv[])
{
	if (argc != 2) {
		fprintf(stderr, "usage: %s <error_code>\n", argv[0]);
		return 1;
	}

	char *end = NULL;
	long error = strtol(argv[1], &end, 10);
	if (*end != '\0' || error < INT_MIN || error > INT_MAX) {
		fprintf(stderr, "Invalid error code.\n");
		return 1;
	}

	printf("%s (%ld): %s\n", gnutls_strerror_name(error), error, gnutls_strerror(error));

	return 0;
}
예제 #10
0
파일: errcodes.c 프로젝트: ares89/vlc
int
main (int argc, char *argv[])
{
  int i, j;
  const char *desc;
  const char *_name;
  error_name names_to_sort[400];        /* up to 400 names  */

  printf ("@table @code\n");

  memset (names_to_sort, 0, sizeof (names_to_sort));
  j = 0;
  for (i = 0; i > -400; i--)
    {
      _name = gnutls_strerror_name (i);
      if (_name == NULL)
        continue;

      strcpy (names_to_sort[j].name, _name);
      names_to_sort[j].error_index = i;
      j++;
    }

  qsort (names_to_sort, j, sizeof (error_name), compar);

  for (i = 0; i < j; i++)
    {
      _name = names_to_sort[i].name;
      desc = gnutls_strerror (names_to_sort[i].error_index);
      if (desc == NULL || _name == NULL)
        continue;

      printf ("@item %s:\n%s\n\n", _name, desc);
    }

  printf ("@end table\n");

  return 0;
}
예제 #11
0
static int get_entry(liServer *srv, ocsp_response_cert_entry* entry, gnutls_ocsp_resp_t resp, unsigned int ndx) {
	int r;
	memset(entry, 0, sizeof(*entry));

	r = gnutls_ocsp_resp_get_single(
			resp, ndx, &entry->digest, &entry->issuer_name_hash, NULL, &entry->serial,
			NULL, NULL, NULL, NULL, NULL);

	if (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE == r) return r;

	if (GNUTLS_E_SUCCESS > r) {
		ERROR(srv, "Couldn't retrieve OCSP response information for entry %u (%s): %s",
				ndx,
				gnutls_strerror_name(r), gnutls_strerror(r));
		return r;
	}

	if (0 == entry->serial.size || GNUTLS_DIG_UNKNOWN == entry->digest || entry->issuer_name_hash.size != gnutls_hash_get_len(entry->digest)) {
		ERROR(srv, "Invalid OCSP response data in entry %u", ndx);
		return GNUTLS_E_OCSP_RESPONSE_ERROR;
	}

	return GNUTLS_E_SUCCESS;
}
예제 #12
0
static void do_handle_error(liGnuTLSFilter *f, const char *gnutlsfunc, int r, gboolean writing) {
	switch (r) {
	case GNUTLS_E_AGAIN:
		if (writing) f->write_wants_read = TRUE;
		return;
	case GNUTLS_E_REHANDSHAKE:
#ifdef HAVE_SAVE_RENEGOTIATION
		if (f->initial_handshaked_finished && !gnutls_safe_renegotiation_status(f->session)) {
			_ERROR(f->srv, f->wrk, f->log_context, "%s: client initiated unsafe renegotitation, closing connection", gnutlsfunc);
			f_close_with_alert(f, r);
		} else {
			_DEBUG(f->srv, f->wrk, f->log_context, "%s: client initiated renegotitation", gnutlsfunc);
		}
#else
		if (f->initial_handshaked_finished) {
			_ERROR(f->srv, f->wrk, f->log_context, "%s: client initiated renegotitation, closing connection", gnutlsfunc);
			f_close_with_alert(f, r);
		}
#endif
		return;
	case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
		f_close_with_alert(f, r);
		return;
	case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
	case GNUTLS_E_UNSUPPORTED_VERSION_PACKET:
		_DEBUG(f->srv, f->wrk, f->log_context, "%s (%s): %s", gnutlsfunc,
			gnutls_strerror_name(r), gnutls_strerror(r));
		f_close_with_alert(f, r);
		return;
	case GNUTLS_E_FATAL_ALERT_RECEIVED:
	case GNUTLS_E_WARNING_ALERT_RECEIVED:
		{
			gnutls_alert_description_t alert_desc = gnutls_alert_get(f->session);
			const char* alert_desc_name = gnutls_alert_get_name(alert_desc);
			_INFO(f->srv, f->wrk, f->log_context, "%s (%s): %s %s (%u)", gnutlsfunc,
				gnutls_strerror_name(r), gnutls_strerror(r),
				(NULL != alert_desc_name) ? alert_desc_name : "unknown alert",
				(unsigned int) alert_desc);
		}
		/* error not handled yet: break instead of return */
		break;
	default:
		if (gnutls_error_is_fatal(r)) {
			_ERROR(f->srv, f->wrk, f->log_context, "%s (%s): %s", gnutlsfunc,
				gnutls_strerror_name(r), gnutls_strerror(r));
		} else {
			_WARNING(f->srv, f->wrk, f->log_context, "%s non fatal (%s): %s", gnutlsfunc,
				gnutls_strerror_name(r), gnutls_strerror(r));
		}
		/* error not handled yet: break instead of return */
		break;
	}

	/* generic error handling */
	if (gnutls_error_is_fatal(r)) {
		if (f->initial_handshaked_finished) {
			f_close_with_alert(f, r);
		} else {
			f_abort_gnutls(f);
		}
	}
}
예제 #13
0
/*
 * Helper function converts a data blob to a gnutls_datum_t.
 * Note that this does not copy the data.
 *      So the returned value should be treated as read only.
 *      And that changes to the length of the underlying DATA_BLOB
 *      will not be reflected in the returned object.
 *
 */
static const gnutls_datum_t convert_from_data_blob(DATA_BLOB blob) {

	const gnutls_datum_t datum = {
		.size = blob.length,
		.data = blob.data,
	};
	return datum;
}

/*
 * @brief Get the gnutls algorithm needed to decrypt the EncryptedSecret
 *
 * @param ldb ldb context, to allow logging.
 * @param es  the encrypted secret
 *
 * @return The gnutls algoritm number, or 0 if there is no match.
 *
 */
static int gnutls_get_algorithm(struct ldb_context *ldb,
				struct EncryptedSecret *es) {

	switch (es->header.algorithm) {
	case ENC_SECRET_AES_128_AEAD:
		return GNUTLS_CIPHER_AES_128_GCM;
	default:
		ldb_asprintf_errstring(ldb,
				       "Unsupported encryption algorithm %d\n",
				       es->header.algorithm);
		return 0;
	}
}

/*
 *
 * @param err  Pointer to an error code, set to:
 *             LDB_SUCESS               If the value was successfully encrypted
 *             LDB_ERR_OPERATIONS_ERROR If there was an error.
 *
 * @param ctx  Talloc memory context the will own the memory allocated
 * @param ldb  ldb context, to allow logging.
 * @param val  The ldb value to encrypt, not altered or freed
 * @param data The context data for this module.
 *
 * @return The encrypted ldb_val, or data_blob_null if there was an error.
 */
static struct ldb_val gnutls_encrypt_aead(int *err,
					  TALLOC_CTX *ctx,
					  struct ldb_context *ldb,
					  const struct ldb_val val,
					  const struct es_data *data)
{
	struct EncryptedSecret *es = NULL;
	struct ldb_val enc = data_blob_null;
	DATA_BLOB pt = data_blob_null;
	gnutls_aead_cipher_hd_t cipher_hnd;
	int rc;

	TALLOC_CTX *frame = talloc_stackframe();

	es = makeEncryptedSecret(ldb, frame);
	if (es == NULL) {
		goto error_exit;
	}

	pt = makePlainText(frame, ldb, val);
	if (pt.length == 0) {
		goto error_exit;
	}

	/*
	 * Set the encryption key and initialize the encryption handle.
	 */
	{
		const size_t key_size = gnutls_cipher_get_key_size(
			data->encryption_algorithm);
		gnutls_datum_t cipher_key;
		DATA_BLOB key_blob = get_key(data);

		if (key_blob.length != key_size) {
			ldb_asprintf_errstring(ldb,
					       "Invalid EncryptedSecrets key "
					       "size, expected %zu bytes and "
					       "it is %zu bytes\n",
					       key_size,
					       key_blob.length);
			goto error_exit;
		}
		cipher_key = convert_from_data_blob(key_blob);

		rc = gnutls_aead_cipher_init(&cipher_hnd,
					     data->encryption_algorithm,
					     &cipher_key);
		if (rc !=0) {
			ldb_asprintf_errstring(ldb,
					       "gnutls_aead_cipher_init failed "
					       "%s - %s\n",
					       gnutls_strerror_name(rc),
					       gnutls_strerror(rc));
			goto error_exit;
		}

	}

	/*
	 * Set the initialisation vector
	 */
	{
		unsigned iv_size = gnutls_cipher_get_iv_size(
			data->encryption_algorithm);
		uint8_t *iv;

		iv = talloc_zero_size(frame, iv_size);
		if (iv == NULL) {
			ldb_set_errstring(ldb,
					  "Out of memory allocating IV\n");
			goto error_exit_handle;
		}

		rc = gnutls_rnd(GNUTLS_RND_NONCE, iv, iv_size);
		if (rc !=0) {
			ldb_asprintf_errstring(ldb,
					       "gnutls_rnd failed %s - %s\n",
					       gnutls_strerror_name(rc),
					       gnutls_strerror(rc));
			goto error_exit_handle;
		}
		es->iv.length = iv_size;
		es->iv.data   = iv;
	}

	/*
	 * Encrypt the value.
	 */
	{
		const unsigned block_size = gnutls_cipher_get_block_size(
			data->encryption_algorithm);
		const unsigned tag_size = gnutls_cipher_get_tag_size(
			data->encryption_algorithm);
		const size_t ed_size = round_to_block_size(
			block_size,
			sizeof(struct PlaintextSecret) + val.length);
		const size_t en_size = ed_size + tag_size;
		uint8_t *ct = talloc_zero_size(frame, en_size);
		size_t el = en_size;

		if (ct == NULL) {
			ldb_set_errstring(ldb,
					  "Out of memory allocation cipher "
					  "text\n");
			goto error_exit_handle;
		}

		rc = gnutls_aead_cipher_encrypt(
			cipher_hnd,
			es->iv.data,
			es->iv.length,
			&es->header,
			sizeof(struct EncryptedSecretHeader),
			tag_size,
			pt.data,
			pt.length,
			ct,
			&el);
		if (rc !=0) {
			ldb_asprintf_errstring(ldb,
					       "gnutls_aead_cipher_encrypt '"
					       "failed %s - %s\n",
					       gnutls_strerror_name(rc),
					       gnutls_strerror(rc));
			*err = LDB_ERR_OPERATIONS_ERROR;
			return data_blob_null;
		}
		es->encrypted.length = el;
		es->encrypted.data   = ct;
		gnutls_aead_cipher_deinit(cipher_hnd);
	}

	rc = ndr_push_struct_blob(&enc,
				  ctx,
				  es,
				  (ndr_push_flags_fn_t)
					ndr_push_EncryptedSecret);
	if (!NDR_ERR_CODE_IS_SUCCESS(rc)) {
		ldb_set_errstring(ldb,
				  "Unable to ndr push EncryptedSecret\n");
		goto error_exit;
	}
	TALLOC_FREE(frame);
	return enc;

error_exit_handle:
	gnutls_aead_cipher_deinit(cipher_hnd);
error_exit:
	*err = LDB_ERR_OPERATIONS_ERROR;
	TALLOC_FREE(frame);
	return data_blob_null;
}

/*
 * @brief Decrypt data encrypted using an aead algorithm.
 *
 * Decrypt the data in ed and insert it into ev. The data was encrypted
 * with one of the gnutls aead compatable algorithms.
 *
 * @param err  Pointer to an error code, set to:
 *             LDB_SUCESS               If the value was successfully decrypted
 *             LDB_ERR_OPERATIONS_ERROR If there was an error.
 *
 * @param ctx  The talloc context that will own the PlaintextSecret
 * @param ldb  ldb context, to allow logging.
 * @param ev   The value to be updated with the decrypted data.
 * @param ed   The data to decrypt.
 * @param data The context data for this module.
 *
 * @return ev is updated with the unencrypted data.
 */
static void gnutls_decrypt_aead(int *err,
				TALLOC_CTX *ctx,
				struct ldb_context *ldb,
				struct EncryptedSecret *es,
				struct PlaintextSecret *ps,
				const struct es_data *data)
{

	gnutls_aead_cipher_hd_t cipher_hnd;
	DATA_BLOB pt = data_blob_null;
	const unsigned tag_size =
		gnutls_cipher_get_tag_size(es->header.algorithm);
	int rc;

	/*
	 * Get the encryption key and initialise the encryption handle
	 */
	{
		gnutls_datum_t cipher_key;
		DATA_BLOB key_blob;
		const int algorithm = gnutls_get_algorithm(ldb, es);
		const size_t key_size = gnutls_cipher_get_key_size(algorithm);
		key_blob   = get_key(data);

		if (algorithm == 0) {
			goto error_exit;
		}

		if (key_blob.length != key_size) {
			ldb_asprintf_errstring(ldb,
					       "Invalid EncryptedSecrets key "
					       "size, expected %zu bytes and "
					       "it is %zu bytes\n",
					       key_size,
					       key_blob.length);
			goto error_exit;
		}
		cipher_key = convert_from_data_blob(key_blob);

		rc = gnutls_aead_cipher_init(
			&cipher_hnd,
			algorithm,
			&cipher_key);
		if (rc != 0) {
			ldb_asprintf_errstring(ldb,
					       "gnutls_aead_cipher_init failed "
					       "%s - %s\n",
					       gnutls_strerror_name(rc),
					       gnutls_strerror(rc));
			goto error_exit;
		}
	}

	/*
	 * Decrypt and validate the encrypted value
	 */

	pt.length = es->encrypted.length;
	pt.data = talloc_zero_size(ctx, es->encrypted.length);

	if (pt.data == NULL) {
		ldb_set_errstring(ldb,
				  "Out of memory allocating plain text\n");
		goto error_exit_handle;
	}

	rc = gnutls_aead_cipher_decrypt(cipher_hnd,
					es->iv.data,
					es->iv.length,
					&es->header,
					sizeof(struct EncryptedSecretHeader),
					tag_size,
					es->encrypted.data,
					es->encrypted.length,
					pt.data,
					&pt.length);
	if (rc != 0) {
		/*
		 * Typically this will indicate that the data has been
		 * corrupted i.e. the tag comparison has failed.
		 * At the moment gnutls does not provide a separate
		 * error code to indicate this
		 */
		ldb_asprintf_errstring(ldb,
				       "gnutls_aead_cipher_decrypt failed "
				       "%s - %s. Data possibly corrupted or "
				       "altered\n",
				       gnutls_strerror_name(rc),
				       gnutls_strerror(rc));
		goto error_exit_handle;
	}
	gnutls_aead_cipher_deinit(cipher_hnd);

	rc = ndr_pull_struct_blob(&pt,
				  ctx,
				  ps,
				  (ndr_pull_flags_fn_t)
					ndr_pull_PlaintextSecret);
	if(!NDR_ERR_CODE_IS_SUCCESS(rc)) {
		ldb_asprintf_errstring(ldb,
				       "Error(%d) unpacking decrypted data, "
				       "data possibly corrupted or altered\n",
				       rc);
		goto error_exit;
	}
	return;

error_exit_handle:
	gnutls_aead_cipher_deinit(cipher_hnd);
error_exit:
	*err = LDB_ERR_OPERATIONS_ERROR;
	return;
}
예제 #14
0
static Ecore_Con_Ssl_Error
_ecore_con_ssl_server_init_gnutls(Ecore_Con_Server *svr)
{
   const gnutls_datum_t *cert_list;
   unsigned int iter, cert_list_size;
   gnutls_x509_crt_t cert = NULL;
   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 (svr->ssl_state)
     {
      case ECORE_CON_SSL_STATE_DONE:
        return ECORE_CON_SSL_ERROR_NONE;

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

        switch (svr->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;
          }

        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_init(&svr->session, GNUTLS_CLIENT));
        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_session_ticket_enable_client(svr->session));
        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_server_name_set(svr->session, GNUTLS_NAME_DNS, svr->name, strlen(svr->name)));
        INF("Applying priority string: %s", priority);
        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_priority_set_direct(svr->session, priority, NULL));
        SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_CERTIFICATE, svr->cert));
        // SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_PSK, svr->pskcred_c));
        if (!svr->use_cert)
          SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_ANON, svr->anoncred_c));

        gnutls_dh_set_prime_bits(svr->session, 512);
        gnutls_transport_set_ptr(svr->session, (gnutls_transport_ptr_t)((intptr_t)svr->fd));
        svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;

      case ECORE_CON_SSL_STATE_HANDSHAKING:
        if (!svr->session)
          {
             DBG("Server was previously lost, going to error condition");
             goto error;
          }
        ret = gnutls_handshake(svr->session);
        DBG("calling gnutls_handshake(): returned with '%s'", gnutls_strerror_name(ret));
        SSL_ERROR_CHECK_GOTO_ERROR(gnutls_error_is_fatal(ret));
        if (!ret)
          {
             svr->handshaking = EINA_FALSE;
             svr->ssl_state = ECORE_CON_SSL_STATE_DONE;
          }
        else
          {
             if (gnutls_record_get_direction(svr->session))
               ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE);
             else
               ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
             return ECORE_CON_SSL_ERROR_NONE;
          }

      default:
        break;
     }

   if (!svr->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(svr->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(svr->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(svr->session, &cert_list_size)));
   SSL_ERROR_CHECK_GOTO_ERROR(!cert_list_size);

   SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_init(&cert));
   SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER));

   SSL_ERROR_CHECK_GOTO_ERROR(!gnutls_x509_crt_check_hostname(cert, svr->name));
   gnutls_x509_crt_deinit(cert);
   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(svr->session)));
   if (svr->session && (svr->ssl_state != ECORE_CON_SSL_STATE_DONE))
     {
        ERR("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(svr->session)));
        ERR("last in: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(svr->session)));
     }
   if (cert)
     gnutls_x509_crt_deinit(cert);
   _ecore_con_ssl_server_shutdown_gnutls(svr);
   return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
}
예제 #15
0
static void
_gnutls_print_errors(int ret)
{
   if (ret)
     ERR("gnutls returned with error: %s - %s", gnutls_strerror_name(ret), gnutls_strerror(ret));
}
예제 #16
0
char *
crypto_encrypt (const char *cipher,
                const GByteArray *data,
                const char *iv,
                const gsize iv_len,
                const char *key,
                gsize key_len,
                gsize *out_len,
                GError **error)
{
	gnutls_cipher_hd_t ctx;
	gnutls_datum_t key_dt, iv_dt;
	int err;
	int cipher_mech;
	char *output = NULL;
	gboolean success = FALSE;
	gsize padded_buf_len, pad_len, output_len;
	char *padded_buf = NULL;
	guint32 i;
	gsize salt_len;

	if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) {
		cipher_mech = GNUTLS_CIPHER_3DES_CBC;
		salt_len = SALT_LEN;
	} else if (!strcmp (cipher, CIPHER_AES_CBC)) {
		cipher_mech = GNUTLS_CIPHER_AES_128_CBC;
		salt_len = iv_len;
	} else {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERR_UNKNOWN_CIPHER,
		             _("Private key cipher '%s' was unknown."),
		             cipher);
		return NULL;
	}

	/* If data->len % ivlen == 0, then we add another complete block
	 * onto the end so that the decrypter knows there's padding.
	 */
	pad_len = iv_len - (data->len % iv_len);
	output_len = padded_buf_len = data->len + pad_len;
	padded_buf = g_malloc0 (padded_buf_len);

	memcpy (padded_buf, data->data, data->len);
	for (i = 0; i < pad_len; i++)
		padded_buf[data->len + i] = (guint8) (pad_len & 0xFF);

	output = g_malloc0 (output_len);

	key_dt.data = (unsigned char *) key;
	key_dt.size = key_len;
	iv_dt.data = (unsigned char *) iv;
	iv_dt.size = iv_len;

	err = gnutls_cipher_init (&ctx, cipher_mech, &key_dt, &iv_dt);
	if (err < 0) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERR_CIPHER_INIT_FAILED,
		             _("Failed to initialize the encryption cipher context: %s (%s)"),
		             gnutls_strerror_name (err), gnutls_strerror (err));
		goto out;
	}

	err = gnutls_cipher_encrypt2 (ctx, padded_buf, padded_buf_len, output, output_len);
	if (err < 0) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
		             _("Failed to encrypt the data: %s (%s)"),
		             gnutls_strerror_name (err), gnutls_strerror (err));
		goto out;
	}

	*out_len = output_len;
	success = TRUE;

out:
	if (padded_buf) {
		memset (padded_buf, 0, padded_buf_len);
		g_free (padded_buf);
		padded_buf = NULL;
	}

	if (!success) {
		if (output) {
			/* Don't expose key material */
			memset (output, 0, output_len);
			g_free (output);
			output = NULL;
		}
	}
	gnutls_cipher_deinit (ctx);
	return output;
}
예제 #17
0
gboolean
crypto_md5_hash (const char *salt,
                 const gsize salt_len,
                 const char *password,
                 gsize password_len,
                 char *buffer,
                 gsize buflen,
                 GError **error)
{
	gnutls_hash_hd_t ctx;
	int err;
	int nkey = buflen;
	const gsize digest_len = 16;
	int count = 0;
	char digest[MD5_HASH_LEN];
	char *p = buffer;

	if (salt)
		g_return_val_if_fail (salt_len >= SALT_LEN, FALSE);

	g_return_val_if_fail (password != NULL, FALSE);
	g_return_val_if_fail (password_len > 0, FALSE);
	g_return_val_if_fail (buffer != NULL, FALSE);
	g_return_val_if_fail (buflen > 0, FALSE);

	if (gnutls_hash_get_len (GNUTLS_DIG_MD5) > MD5_HASH_LEN) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERR_MD5_INIT_FAILED,
		             _("Hash length too long (%d > %d)."),
		             gnutls_hash_get_len (GNUTLS_DIG_MD5), MD5_HASH_LEN);
		return FALSE;
	}

	while (nkey > 0) {
		int i = 0;

		err = gnutls_hash_init (&ctx, GNUTLS_DIG_MD5);
		if (err < 0)
			goto error;

		if (count++)
			gnutls_hash (ctx, digest, digest_len);
		gnutls_hash (ctx, password, password_len);
		if (salt)
			gnutls_hash (ctx, salt, SALT_LEN); /* Only use 8 bytes of salt */
		gnutls_hash_deinit (ctx, digest);

		while (nkey && (i < digest_len)) {
			*(p++) = digest[i++];
			nkey--;
		}
	}

	memset (digest, 0, sizeof (digest));
	return TRUE;
error:
	memset (digest, 0, sizeof (digest));
	g_set_error (error, NM_CRYPTO_ERROR,
	             NM_CRYPTO_ERR_MD5_INIT_FAILED,
	             _("Failed to initialize the MD5 engine: %s (%s)"),
	             gnutls_strerror_name (err), gnutls_strerror (err));
	return FALSE;
}
예제 #18
0
static gboolean mod_gnutls_con_new(liConnection *con, int fd) {
	liEventLoop *loop = &con->wrk->loop;
	liServer *srv = con->srv;
	mod_context *ctx = con->srv_sock->data;
	mod_connection_ctx *conctx;
	gnutls_session_t session;
	int r;

	if (GNUTLS_E_SUCCESS > (r = gnutls_init(&session, GNUTLS_SERVER))) {
		ERROR(srv, "gnutls_init (%s): %s",
			gnutls_strerror_name(r), gnutls_strerror(r));
		return FALSE;
	}

	mod_gnutls_context_acquire(ctx);

	if (GNUTLS_E_SUCCESS > (r = gnutls_priority_set(session, ctx->server_priority))) {
		ERROR(srv, "gnutls_priority_set (%s): %s",
			gnutls_strerror_name(r), gnutls_strerror(r));
		goto fail;
	}
	if (GNUTLS_E_SUCCESS > (r = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctx->server_cert))) {
		ERROR(srv, "gnutls_credentials_set (%s): %s",
			gnutls_strerror_name(r), gnutls_strerror(r));
		goto fail;
	}

	if (NULL != ctx->session_db) {
		gnutls_db_set_ptr(session, ctx->session_db);
		gnutls_db_set_remove_function(session, session_db_remove_cb);
		gnutls_db_set_retrieve_function(session, session_db_retrieve_cb);
		gnutls_db_set_store_function(session, session_db_store_cb);
	}

#ifdef HAVE_SESSION_TICKET
	if (GNUTLS_E_SUCCESS > (r = gnutls_session_ticket_enable_server(session, &ctx->ticket_key))) {
		ERROR(srv, "gnutls_session_ticket_enable_server (%s): %s",
			gnutls_strerror_name(r), gnutls_strerror(r));
		goto fail;
	}
#endif

#ifdef GNUTLS_ALPN_MAND
	{
		static const gnutls_datum_t proto_http1 = { (unsigned char*) CONST_STR_LEN("http/1.1") };
		gnutls_alpn_set_protocols(session, &proto_http1, 1, 0);
	}
#endif

	conctx = g_slice_new0(mod_connection_ctx);
	conctx->session = session;
	conctx->sock_stream = li_iostream_new(con->wrk, fd, tcp_io_cb, conctx);

	conctx->client_hello_stream = li_ssl_client_hello_stream(&con->wrk->loop, gnutls_client_hello_cb, conctx);
#ifdef USE_SNI
	li_job_init(&conctx->sni_job, sni_job_cb);
	conctx->sni_jobref = li_job_ref(&con->wrk->loop.jobqueue, &conctx->sni_job);
#endif

	li_stream_connect(&conctx->sock_stream->stream_in, conctx->client_hello_stream);

	conctx->tls_filter = li_gnutls_filter_new(srv, con->wrk, &filter_callbacks, conctx, conctx->session,
		conctx->client_hello_stream, &conctx->sock_stream->stream_out);

	conctx->con = con;
	conctx->ctx = ctx;

	con->con_sock.data = conctx;
	con->con_sock.callbacks = &gnutls_tcp_cbs;
	con->con_sock.raw_out = li_stream_plug_new(loop);
	con->con_sock.raw_in = li_stream_plug_new(loop);
	con->info.is_ssl = TRUE;

	return TRUE;

fail:
	gnutls_deinit(session);
	mod_gnutls_context_release(ctx);

	return FALSE;
}
예제 #19
0
char *
crypto_decrypt (const char *cipher,
                int key_type,
                GByteArray *data,
                const char *iv,
                const gsize iv_len,
                const char *key,
                const gsize key_len,
                gsize *out_len,
                GError **error)
{
	gnutls_cipher_hd_t ctx;
	gnutls_datum_t key_dt, iv_dt;
	int err;
	int cipher_mech, i;
	char *output = NULL;
	gboolean success = FALSE;
	gsize pad_len, real_iv_len;

	if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) {
		cipher_mech = GNUTLS_CIPHER_3DES_CBC;
		real_iv_len = SALT_LEN;
	} else if (!strcmp (cipher, CIPHER_DES_CBC)) {
		cipher_mech = GNUTLS_CIPHER_DES_CBC;
		real_iv_len = SALT_LEN;
	} else if (!strcmp (cipher, CIPHER_AES_CBC)) {
		cipher_mech = GNUTLS_CIPHER_AES_128_CBC;
		real_iv_len = 16;
	} else {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERR_UNKNOWN_CIPHER,
		             _("Private key cipher '%s' was unknown."),
		             cipher);
		return NULL;
	}

	if (iv_len < real_iv_len) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERR_RAW_IV_INVALID,
		             _("Invalid IV length (must be at least %zd)."),
		             real_iv_len);
		return NULL;
	}

	output = g_malloc0 (data->len);

	key_dt.data = (unsigned char *) key;
	key_dt.size = key_len;
	iv_dt.data = (unsigned char *) iv;
	iv_dt.size = iv_len;

	err = gnutls_cipher_init (&ctx, cipher_mech, &key_dt, &iv_dt);
	if (err < 0) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERR_CIPHER_INIT_FAILED,
		             _("Failed to initialize the decryption cipher context: %s (%s)"),
		             gnutls_strerror_name (err), gnutls_strerror (err));
		goto out;
	}

	err = gnutls_cipher_decrypt2 (ctx, data->data, data->len, output, data->len);
	if (err < 0) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
		             _("Failed to decrypt the private key: %s (%s)"),
		             gnutls_strerror_name (err), gnutls_strerror (err));
		goto out;
	}
	pad_len = output[data->len - 1];

	/* Check if the padding at the end of the decrypted data is valid */
	if (pad_len == 0 || pad_len > real_iv_len) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
		             _("Failed to decrypt the private key: unexpected padding length."));
		goto out;
	}

	/* Validate tail padding; last byte is the padding size, and all pad bytes
	 * should contain the padding size.
	 */
	for (i = 1; i <= pad_len; ++i) {
		if (output[data->len - i] != pad_len) {
			g_set_error (error, NM_CRYPTO_ERROR,
			             NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
			             _("Failed to decrypt the private key."));
			goto out;
		}
	}

	*out_len = data->len - pad_len;
	success = TRUE;

out:
	if (!success) {
		if (output) {
			/* Don't expose key material */
			memset (output, 0, data->len);
			g_free (output);
			output = NULL;
		}
	}
	gnutls_cipher_deinit (ctx);
	return output;
}