Blame lib/pkcs11x.c

Packit Service 4684c1
/*
Packit Service 4684c1
 * GnuTLS PKCS#11 support
Packit Service 4684c1
 * Copyright (C) 2010-2016 Free Software Foundation, Inc.
Packit Service 4684c1
 * Copyright (C) 2016 Red Hat
Packit Service 4684c1
 * 
Packit Service 4684c1
 * Authors: Nikos Mavrogiannopoulos
Packit Service 4684c1
 *
Packit Service 4684c1
 * GnuTLS is free software; you can redistribute it and/or
Packit Service 4684c1
 * modify it under the terms of the GNU Lesser General Public License
Packit Service 4684c1
 * as published by the Free Software Foundation; either version 2.1 of
Packit Service 4684c1
 * the License, or (at your option) any later version.
Packit Service 4684c1
 *
Packit Service 4684c1
 * This library is distributed in the hope that it will be useful, but
Packit Service 4684c1
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 4684c1
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 4684c1
 * Lesser General Public License for more details.
Packit Service 4684c1
 *
Packit Service 4684c1
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 4684c1
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
Packit Service 4684c1
 */
Packit Service 4684c1
Packit Service 4684c1
#include "gnutls_int.h"
Packit Service 4684c1
#include <gnutls/pkcs11.h>
Packit Service 4684c1
#include <global.h>
Packit Service 4684c1
#include "errors.h"
Packit Service 4684c1
#include "x509/common.h"
Packit Service 4684c1
Packit Service 4684c1
#include <pkcs11_int.h>
Packit Service 4684c1
#include <p11-kit/p11-kit.h>
Packit Service 4684c1
#include "pkcs11x.h"
Packit Service 4684c1
Packit Service 4684c1
struct find_ext_data_st {
Packit Service 4684c1
	/* in */
Packit Service 4684c1
	gnutls_pkcs11_obj_t obj;
Packit Service 4684c1
	gnutls_datum_t spki;
Packit Service 4684c1
Packit Service 4684c1
	/* out */
Packit Service 4684c1
	gnutls_x509_ext_st *exts;
Packit Service 4684c1
	unsigned int exts_size;
Packit Service 4684c1
};
Packit Service 4684c1
Packit Service 4684c1
static int override_ext(gnutls_x509_crt_t crt, gnutls_datum_t *ext)
Packit Service 4684c1
{
Packit Service 4684c1
	gnutls_x509_ext_st parsed;
Packit Service 4684c1
	int ret;
Packit Service 4684c1
Packit Service 4684c1
	ret = _gnutls_x509_decode_ext(ext, &parsed);
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
	/* set the new extension */
Packit Service 4684c1
	ret = _gnutls_x509_crt_set_extension(crt, parsed.oid, &parsed.data, parsed.critical);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		goto cleanup;
Packit Service 4684c1
	}
Packit Service 4684c1
	
Packit Service 4684c1
	ret = 0;
Packit Service 4684c1
 cleanup:
Packit Service 4684c1
	gnutls_x509_ext_deinit(&parsed);
Packit Service 4684c1
	return ret;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* This function re-encodes a certificate to contain its stapled extensions.
Packit Service 4684c1
 * That assumes that the certificate is not in the distrusted list.
Packit Service 4684c1
 */
Packit Service 4684c1
int pkcs11_override_cert_exts(struct pkcs11_session_info *sinfo, gnutls_datum_t *spki, gnutls_datum_t *der)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	gnutls_datum_t new_der = {NULL, 0};
Packit Service 4684c1
	struct ck_attribute a[2];
Packit Service 4684c1
	struct ck_attribute b[1];
Packit Service 4684c1
	unsigned long count;
Packit Service 4684c1
	unsigned ext_data_size = der->size;
Packit Service 4684c1
	uint8_t *ext_data = NULL;
Packit Service 4684c1
	ck_object_class_t class = -1;
Packit Service 4684c1
	gnutls_x509_crt_t crt = NULL;
Packit Service 4684c1
	unsigned finalize = 0;
Packit Service 4684c1
	ck_rv_t rv;
Packit Service 4684c1
	ck_object_handle_t obj;
Packit Service 4684c1
Packit Service 4684c1
	if (sinfo->trusted == 0) {
Packit Service 4684c1
		_gnutls_debug_log("p11: cannot override extensions on a non-p11-kit trust module\n");
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	/* retrieve the extensions */
Packit Service 4684c1
	class = CKO_X_CERTIFICATE_EXTENSION;
Packit Service 4684c1
	a[0].type = CKA_CLASS;
Packit Service 4684c1
	a[0].value = &class;
Packit Service 4684c1
	a[0].value_len = sizeof class;
Packit Service 4684c1
Packit Service 4684c1
	a[1].type = CKA_PUBLIC_KEY_INFO;
Packit Service 4684c1
	a[1].value = spki->data;
Packit Service 4684c1
	a[1].value_len = spki->size;
Packit Service 4684c1
Packit Service 4684c1
	rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 2);
Packit Service 4684c1
	if (rv != CKR_OK) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		_gnutls_debug_log
Packit Service 4684c1
		    ("p11: FindObjectsInit failed for cert extensions.\n");
Packit Service 4684c1
		ret = pkcs11_rv_to_err(rv);
Packit Service 4684c1
		goto cleanup;
Packit Service 4684c1
	}
Packit Service 4684c1
	finalize = 1;
Packit Service 4684c1
Packit Service 4684c1
	rv = pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count);
Packit Service 4684c1
	if (rv == CKR_OK && count == 1) {
Packit Service 4684c1
		ext_data = gnutls_malloc(ext_data_size);
Packit Service 4684c1
		if (ext_data == NULL) {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			ret = GNUTLS_E_MEMORY_ERROR;
Packit Service 4684c1
			goto cleanup;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		ret = gnutls_x509_crt_init(&crt;;
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			goto cleanup;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		ret = gnutls_x509_crt_import(crt, der, GNUTLS_X509_FMT_DER);
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			goto cleanup;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		do {
Packit Service 4684c1
Packit Service 4684c1
			b[0].type = CKA_VALUE;
Packit Service 4684c1
			b[0].value = ext_data;
Packit Service 4684c1
			b[0].value_len = ext_data_size;
Packit Service 4684c1
Packit Service 4684c1
			if (pkcs11_get_attribute_value
Packit Service 4684c1
			    (sinfo->module, sinfo->pks, obj, b, 1) == CKR_OK) {
Packit Service 4684c1
				gnutls_datum_t data = { b[0].value, b[0].value_len };
Packit Service 4684c1
Packit Service 4684c1
				ret = override_ext(crt, &data);
Packit Service 4684c1
				if (ret < 0) {
Packit Service 4684c1
					gnutls_assert();
Packit Service 4684c1
					goto cleanup;
Packit Service 4684c1
				}
Packit Service 4684c1
			}
Packit Service 4684c1
		} while (pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK && count == 1);
Packit Service 4684c1
Packit Service 4684c1
		/* overwrite the old certificate with the new */
Packit Service 4684c1
		ret = gnutls_x509_crt_export2(crt, GNUTLS_X509_FMT_DER, &new_der);
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			goto cleanup;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		gnutls_free(der->data);
Packit Service 4684c1
		der->data = new_der.data;
Packit Service 4684c1
		der->size = new_der.size;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	ret = 0;
Packit Service 4684c1
 cleanup:
Packit Service 4684c1
	if (crt != NULL)
Packit Service 4684c1
		gnutls_x509_crt_deinit(crt);
Packit Service 4684c1
	if (finalize != 0)
Packit Service 4684c1
		pkcs11_find_objects_final(sinfo);
Packit Service 4684c1
	gnutls_free(ext_data);
Packit Service 4684c1
	return ret;
Packit Service 4684c1
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static int
Packit Service 4684c1
find_ext_cb(struct ck_function_list *module, struct pkcs11_session_info *sinfo,
Packit Service 4684c1
	    struct ck_token_info *tinfo, struct ck_info *lib_info,
Packit Service 4684c1
	    void *input)
Packit Service 4684c1
{
Packit Service 4684c1
	struct find_ext_data_st *find_data = input;
Packit Service 4684c1
	struct ck_attribute a[4];
Packit Service 4684c1
	ck_object_class_t class = -1;
Packit Service 4684c1
	unsigned long count;
Packit Service 4684c1
	ck_rv_t rv;
Packit Service 4684c1
	ck_object_handle_t obj;
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	gnutls_datum_t ext;
Packit Service 4684c1
Packit Service 4684c1
	if (tinfo == NULL) {	/* we don't support multiple calls */
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	/* do not bother reading the token if basic fields do not match
Packit Service 4684c1
	 */
Packit Service 4684c1
	if (!p11_kit_uri_match_token_info
Packit Service 4684c1
	    (find_data->obj->info, tinfo)
Packit Service 4684c1
	    || !p11_kit_uri_match_module_info(find_data->obj->info,
Packit Service 4684c1
					      lib_info)) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	/* retrieve the extensions */
Packit Service 4684c1
	class = CKO_X_CERTIFICATE_EXTENSION;
Packit Service 4684c1
	a[0].type = CKA_CLASS;
Packit Service 4684c1
	a[0].value = &class;
Packit Service 4684c1
	a[0].value_len = sizeof class;
Packit Service 4684c1
Packit Service 4684c1
	a[1].type = CKA_PUBLIC_KEY_INFO;
Packit Service 4684c1
	a[1].value = find_data->spki.data;
Packit Service 4684c1
	a[1].value_len = find_data->spki.size;
Packit Service 4684c1
Packit Service 4684c1
	rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 2);
Packit Service 4684c1
	if (rv != CKR_OK) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		_gnutls_debug_log
Packit Service 4684c1
		    ("p11: FindObjectsInit failed for cert extensions.\n");
Packit Service 4684c1
		return pkcs11_rv_to_err(rv);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	while(pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK && count == 1) {
Packit Service 4684c1
		rv = pkcs11_get_attribute_avalue(sinfo->module, sinfo->pks, obj, CKA_VALUE, &ext;;
Packit Service 4684c1
		if (rv == CKR_OK) {
Packit Service 4684c1
Packit Service 4684c1
			find_data->exts = gnutls_realloc_fast(find_data->exts, (1+find_data->exts_size)*sizeof(find_data->exts[0]));
Packit Service 4684c1
			if (find_data->exts == NULL) {
Packit Service 4684c1
				gnutls_assert();
Packit Service 4684c1
				ret = pkcs11_rv_to_err(rv);
Packit Service 4684c1
				goto cleanup;
Packit Service 4684c1
			}
Packit Service 4684c1
Packit Service 4684c1
			if (_gnutls_x509_decode_ext(&ext, &find_data->exts[find_data->exts_size]) == 0) {
Packit Service 4684c1
				find_data->exts_size++;
Packit Service 4684c1
			}
Packit Service 4684c1
			gnutls_free(ext.data);
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	ret = 0;
Packit Service 4684c1
 cleanup:
Packit Service 4684c1
	pkcs11_find_objects_final(sinfo);
Packit Service 4684c1
	return ret;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/**
Packit Service 4684c1
 * gnutls_pkcs11_obj_get_exts:
Packit Service 4684c1
 * @obj: should contain a #gnutls_pkcs11_obj_t type
Packit Service 4684c1
 * @exts: a pointer to a %gnutls_x509_ext_st pointer
Packit Service 4684c1
 * @exts_size: will be updated with the number of @exts
Packit Service 4684c1
 * @flags: Or sequence of %GNUTLS_PKCS11_OBJ_* flags 
Packit Service 4684c1
 *
Packit Service 4684c1
 * This function will return information about attached extensions
Packit Service 4684c1
 * that associate to the provided object (which should be a certificate).
Packit Service 4684c1
 * The extensions are the attached p11-kit trust module extensions.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Each element of @exts must be deinitialized using gnutls_x509_ext_deinit()
Packit Service 4684c1
 * while @exts should be deallocated using gnutls_free().
Packit Service 4684c1
 *
Packit Service 4684c1
 * Returns: %GNUTLS_E_SUCCESS (0) on success or a negative error code on error.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Since: 3.3.8
Packit Service 4684c1
 **/
Packit Service 4684c1
int
Packit Service 4684c1
gnutls_pkcs11_obj_get_exts(gnutls_pkcs11_obj_t obj,
Packit Service 4684c1
			   gnutls_x509_ext_st **exts, unsigned int *exts_size,
Packit Service 4684c1
			   unsigned int flags)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	gnutls_datum_t spki = {NULL, 0};
Packit Service 4684c1
	struct find_ext_data_st find_data;
Packit Service 4684c1
	unsigned deinit_spki = 0;
Packit Service 4684c1
Packit Service 4684c1
	PKCS11_CHECK_INIT;
Packit Service 4684c1
	memset(&find_data, 0, sizeof(find_data));
Packit Service 4684c1
Packit Service 4684c1
	*exts_size = 0;
Packit Service 4684c1
Packit Service 4684c1
	if (obj->type != GNUTLS_PKCS11_OBJ_X509_CRT && obj->type != GNUTLS_PKCS11_OBJ_PUBKEY)
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit Service 4684c1
Packit Service 4684c1
	if (obj->type == GNUTLS_PKCS11_OBJ_PUBKEY) {
Packit Service 4684c1
		spki.data = obj->raw.data;
Packit Service 4684c1
		spki.size = obj->raw.size;
Packit Service 4684c1
	} else {
Packit Service 4684c1
		ret = _gnutls_x509_raw_crt_to_raw_pubkey(&obj->raw, &spki);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			return gnutls_assert_val(ret);
Packit Service 4684c1
		deinit_spki = 1;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	find_data.spki.data = spki.data;
Packit Service 4684c1
	find_data.spki.size = spki.size;
Packit Service 4684c1
	find_data.obj = obj;
Packit Service 4684c1
	ret =
Packit Service 4684c1
	    _pkcs11_traverse_tokens(find_ext_cb, &find_data, obj->info,
Packit Service 4684c1
				    &obj->pin,
Packit Service 4684c1
				    pkcs11_obj_flags_to_int(flags));
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		goto cleanup;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	*exts = find_data.exts;
Packit Service 4684c1
	*exts_size = find_data.exts_size;
Packit Service 4684c1
Packit Service 4684c1
	ret = 0;
Packit Service 4684c1
 cleanup:
Packit Service 4684c1
	if (deinit_spki)
Packit Service 4684c1
		gnutls_free(spki.data);
Packit Service 4684c1
	return ret;
Packit Service 4684c1
}
Packit Service 4684c1