static int
_dsa_params_generate(struct ck_function_list *module, ck_session_handle_t session,
		     unsigned long bits, struct dsa_params *params,
		     struct ck_attribute *a, int *a_val)
{
	struct ck_mechanism mech = { CKM_DSA_PARAMETER_GEN };
	struct ck_attribute attr = { CKA_PRIME_BITS, &bits, sizeof(bits) };
	ck_object_handle_t key;
	ck_rv_t rv;

	/* Generate DSA parameters from prime length. */

	rv = pkcs11_generate_key(module, session, &mech, &attr, 1, &key);
	if (rv != CKR_OK) {
		gnutls_assert();
		_gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv));
		return pkcs11_rv_to_err(rv);
	}

	/* Retrieve generated parameters to be used with the new key pair. */

	a[*a_val + 0].type = CKA_PRIME;
	a[*a_val + 0].value = params->prime;
	a[*a_val + 0].value_len = sizeof(params->prime);

	a[*a_val + 1].type = CKA_SUBPRIME;
	a[*a_val + 1].value = params->subprime;
	a[*a_val + 1].value_len = sizeof(params->subprime);

	a[*a_val + 2].type = CKA_BASE;
	a[*a_val + 2].value = params->generator;
	a[*a_val + 2].value_len = sizeof(params->generator);

	rv = pkcs11_get_attribute_value(module, session, key, &a[*a_val], 3);
	if (rv != CKR_OK) {
		gnutls_assert();
		_gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv));
		return pkcs11_rv_to_err(rv);
	}

	*a_val += 3;

	return 0;
}
/**
 * gnutls_pkcs11_privkey_import_url:
 * @pkey: The private key
 * @url: a PKCS 11 url identifying the key
 * @flags: Or sequence of GNUTLS_PKCS11_OBJ_* flags
 *
 * This function will "import" a PKCS 11 URL identifying a private
 * key to the #gnutls_pkcs11_privkey_t type. In reality since
 * in most cases keys cannot be exported, the private key structure
 * is being associated with the available operations on the token.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 **/
int
gnutls_pkcs11_privkey_import_url(gnutls_pkcs11_privkey_t pkey,
				 const char *url, unsigned int flags)
{
	int ret;
	struct ck_attribute *attr;
	struct ck_attribute a[4];
	ck_key_type_t key_type;
	ck_bool_t reauth = 0;

	PKCS11_CHECK_INIT;

	memset(&pkey->sinfo, 0, sizeof(pkey->sinfo));

	if (pkey->url) {
		gnutls_free(pkey->url);
		pkey->url = NULL;
	}

	if (pkey->uinfo) {
		p11_kit_uri_free(pkey->uinfo);
		pkey->uinfo = NULL;
	}

	pkey->url = gnutls_strdup(url);
	if (pkey->url == NULL)
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

	ret = pkcs11_url_to_info(pkey->url, &pkey->uinfo, flags|GNUTLS_PKCS11_OBJ_FLAG_EXPECT_PRIVKEY);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	pkey->flags = flags;

	attr = p11_kit_uri_get_attribute(pkey->uinfo, CKA_CLASS);
	if (!attr || attr->value_len != sizeof(ck_object_class_t) ||
	    *(ck_object_class_t *) attr->value != CKO_PRIVATE_KEY) {
		gnutls_assert();
		ret = GNUTLS_E_INVALID_REQUEST;
		goto cleanup;
	}

	attr = p11_kit_uri_get_attribute(pkey->uinfo, CKA_ID);
	if (!attr) {
		attr = p11_kit_uri_get_attribute(pkey->uinfo, CKA_LABEL);
		if (!attr) {
			gnutls_assert();
			ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
			goto cleanup;
		}
	}

	FIND_OBJECT(pkey);

	pkey->pk_algorithm = GNUTLS_PK_UNKNOWN;
	a[0].type = CKA_KEY_TYPE;
	a[0].value = &key_type;
	a[0].value_len = sizeof(key_type);

	if (pkcs11_get_attribute_value(pkey->sinfo.module, pkey->sinfo.pks, pkey->ref, a, 1)
	    == CKR_OK) {
		pkey->pk_algorithm = key_type_to_pk(key_type);
	}

	if (pkey->pk_algorithm == GNUTLS_PK_UNKNOWN) {
		_gnutls_debug_log
		    ("Cannot determine PKCS #11 key algorithm\n");
		ret = GNUTLS_E_UNKNOWN_ALGORITHM;
		goto cleanup;
	}

	a[0].type = CKA_ALWAYS_AUTHENTICATE;
	a[0].value = &reauth;
	a[0].value_len = sizeof(reauth);

	if (pkcs11_get_attribute_value(pkey->sinfo.module, pkey->sinfo.pks, pkey->ref, a, 1)
	    == CKR_OK) {
		pkey->reauth = reauth;
	}

	ret = 0;

	return ret;

      cleanup:
	if (pkey->uinfo != NULL) {
		p11_kit_uri_free(pkey->uinfo);
		pkey->uinfo = NULL;
	}
	gnutls_free(pkey->url);
	pkey->url = NULL;

	return ret;
}
Exemple #3
0
/**
 * gnutls_pkcs11_privkey_import_url:
 * @pkey: The structure to store the parsed key
 * @url: a PKCS 11 url identifying the key
 * @flags: sequence of GNUTLS_PKCS_PRIVKEY_*
 *
 * This function will "import" a PKCS 11 URL identifying a private
 * key to the #gnutls_pkcs11_privkey_t structure. In reality since
 * in most cases keys cannot be exported, the private key structure
 * is being associated with the available operations on the token.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 **/
int
gnutls_pkcs11_privkey_import_url(gnutls_pkcs11_privkey_t pkey,
				 const char *url, unsigned int flags)
{
	int ret;
	struct ck_attribute *attr;
	ck_object_handle_t obj;
	struct ck_attribute a[4];
	ck_key_type_t key_type;
	struct pkcs11_session_info sinfo;

	PKCS11_CHECK_INIT;

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

	ret = pkcs11_url_to_info(url, &pkey->info);
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	pkey->flags = flags;

	attr = p11_kit_uri_get_attribute(pkey->info, CKA_CLASS);
	if (!attr || attr->value_len != sizeof(ck_object_class_t) ||
	    *(ck_object_class_t *) attr->value != CKO_PRIVATE_KEY) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	attr = p11_kit_uri_get_attribute(pkey->info, CKA_ID);
	if (!attr || !attr->value_len) {
		attr = p11_kit_uri_get_attribute(pkey->info, CKA_LABEL);
		if (!attr || !attr->value_len) {
			gnutls_assert();
			return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
		}
	}

	FIND_OBJECT(&sinfo, &pkey->pin, obj, pkey);

	a[0].type = CKA_KEY_TYPE;
	a[0].value = &key_type;
	a[0].value_len = sizeof(key_type);

	if (pkcs11_get_attribute_value(sinfo.module, sinfo.pks, obj, a, 1)
	    == CKR_OK) {
		pkey->pk_algorithm = mech_to_pk(key_type);
		if (pkey->pk_algorithm == GNUTLS_PK_UNKNOWN) {
			_gnutls_debug_log
			    ("Cannot determine PKCS #11 key algorithm\n");
			ret = GNUTLS_E_UNKNOWN_ALGORITHM;
			goto cleanup;
		}
	}

	ret = 0;

	if (pkey->sinfo.init)
		pkcs11_close_session(&pkey->sinfo);

	if (sinfo.tinfo.max_session_count != 1) {
		/* We do not keep the session open in tokens that can 
		 * only support a single session.
		 */
		memcpy(&pkey->sinfo, &sinfo, sizeof(pkey->sinfo));
		pkey->obj = obj;
		return ret;
	}

      cleanup:
	pkcs11_close_session(&sinfo);

	return ret;
}
Exemple #4
0
int pkcs11_override_cert_exts(struct pkcs11_session_info *sinfo, gnutls_datum_t *spki, gnutls_datum_t *der)
{
	int ret;
	gnutls_datum_t new_der = {NULL, 0};
	struct ck_attribute a[2];
	struct ck_attribute b[1];
	unsigned long count;
	unsigned ext_data_size = der->size;
	uint8_t *ext_data = NULL;
	ck_object_class_t class = -1;
	gnutls_x509_crt_t crt = NULL;
	unsigned finalize = 0;
	ck_rv_t rv;
	ck_object_handle_t obj;

	/* retrieve the extensions */
	class = CKO_X_CERTIFICATE_EXTENSION;
	a[0].type = CKA_CLASS;
	a[0].value = &class;
	a[0].value_len = sizeof class;

	a[1].type = CKA_PUBLIC_KEY_INFO;
	a[1].value = spki->data;
	a[1].value_len = spki->size;

	rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 2);
	if (rv != CKR_OK) {
		gnutls_assert();
		_gnutls_debug_log
		    ("p11: FindObjectsInit failed for cert extensions.\n");
		ret = pkcs11_rv_to_err(rv);
		goto cleanup;
	}
	finalize = 1;

	rv = pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count);
	if (rv == CKR_OK && count == 1) {
		ext_data = gnutls_malloc(ext_data_size);
		if (ext_data == NULL) {
			gnutls_assert();
			ret = GNUTLS_E_MEMORY_ERROR;
			goto cleanup;
		}

		ret = gnutls_x509_crt_init(&crt);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		ret = gnutls_x509_crt_import(crt, der, GNUTLS_X509_FMT_DER);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		do {

			b[0].type = CKA_VALUE;
			b[0].value = ext_data;
			b[0].value_len = ext_data_size;

			if (pkcs11_get_attribute_value
			    (sinfo->module, sinfo->pks, obj, b, 1) == CKR_OK) {
				gnutls_datum_t data = { b[0].value, b[0].value_len };

				ret = override_ext(crt, &data);
				if (ret < 0) {
					gnutls_assert();
					goto cleanup;
				}
			}
		} while (pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK && count == 1);

		/* overwrite the old certificate with the new */
		ret = gnutls_x509_crt_export2(crt, GNUTLS_X509_FMT_DER, &new_der);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		gnutls_free(der->data);
		der->data = new_der.data;
		der->size = new_der.size;
	}

	ret = 0;
 cleanup:
 	if (crt != NULL)
	 	gnutls_x509_crt_deinit(crt);
	if (finalize != 0)
		pkcs11_find_objects_final(sinfo);
 	gnutls_free(ext_data);
 	return ret;

}
/**
 * gnutls_pkcs11_privkey_import_url:
 * @pkey: The structure to store the parsed key
 * @url: a PKCS 11 url identifying the key
 * @flags: sequence of GNUTLS_PKCS_PRIVKEY_*
 *
 * This function will "import" a PKCS 11 URL identifying a private
 * key to the #gnutls_pkcs11_privkey_t structure. In reality since
 * in most cases keys cannot be exported, the private key structure
 * is being associated with the available operations on the token.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 **/
int
gnutls_pkcs11_privkey_import_url (gnutls_pkcs11_privkey_t pkey,
                                  const char *url, unsigned int flags)
{
  int ret;
  struct ck_function_list *module;
  struct ck_attribute *attr;
  ck_session_handle_t pks;
  ck_object_handle_t obj;
  struct ck_attribute a[4];
  ck_key_type_t key_type;

  ret = pkcs11_url_to_info (url, &pkey->info);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  pkey->flags = flags;

  attr = p11_kit_uri_get_attribute (pkey->info, CKA_CLASS);
  if (!attr || attr->value_len != sizeof (ck_object_class_t) ||
      *(ck_object_class_t*)attr->value != CKO_PRIVATE_KEY)
    {
      gnutls_assert ();
      return GNUTLS_E_INVALID_REQUEST;
    }

  attr = p11_kit_uri_get_attribute (pkey->info, CKA_ID);
  if (!attr || !attr->value_len)
    {
      attr = p11_kit_uri_get_attribute (pkey->info, CKA_LABEL);
      if (!attr || !attr->value_len)
        {
          gnutls_assert ();
          return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
        }
    }

  FIND_OBJECT (module, pks, obj, pkey);
  a[0].type = CKA_KEY_TYPE;
  a[0].value = &key_type;
  a[0].value_len = sizeof (key_type);

  if (pkcs11_get_attribute_value (module, pks, obj, a, 1) == CKR_OK)
    {
      pkey->pk_algorithm = mech_to_pk(key_type);
      if (pkey->pk_algorithm == GNUTLS_PK_UNKNOWN)
        {
          _gnutls_debug_log("Cannot determine PKCS #11 key algorithm\n");
          ret = GNUTLS_E_UNKNOWN_ALGORITHM;
          goto cleanup;
        }
    }

  ret = 0;

cleanup:
  pkcs11_close_session (module, pks);

  return ret;
}