static 
int store_pubkey(const char* db_name, const char* host,
                 const char* service, time_t expiration, 
                 const gnutls_datum_t* pubkey)
{
FILE* fd = NULL;
gnutls_datum_t b64key = { NULL, 0 };
int ret;

  ret = gnutls_mutex_lock(&_gnutls_file_mutex);
  if (ret != 0)
    return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR);

  ret = raw_pubkey_to_base64(pubkey, &b64key);
  if (ret < 0)
    {
      gnutls_assert();
      goto cleanup;
    }

  fd = fopen(db_name, "ab+");
  if (fd == NULL)
    {
      ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR);
      goto cleanup;
    }

  if (service == NULL) service = "*";
  if (host == NULL) host = "*";

  fprintf(fd, "|g0|%s|%s|%lu|%.*s\n", host, service, (unsigned long)expiration, 
    b64key.size, b64key.data);

  ret = 0;

cleanup:
  if (fd != NULL)
    fclose(fd);

  gnutls_mutex_unlock(&_gnutls_file_mutex);
  gnutls_free(b64key.data);
  
  return ret;
}
Exemplo n.º 2
0
/*-
 * _gnutls_pkcs11_privkey_decrypt_data:
 * @key: Holds the key
 * @flags: should be 0 for now
 * @ciphertext: holds the data to be signed
 * @plaintext: will contain the plaintext, allocated with gnutls_malloc()
 *
 * This function will decrypt the given data using the public key algorithm
 * supported by the private key. 
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 -*/
int
_gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
				    unsigned int flags,
				    const gnutls_datum_t * ciphertext,
				    gnutls_datum_t * plaintext)
{
	ck_rv_t rv;
	int ret;
	struct ck_mechanism mech;
	unsigned long siglen;
	unsigned req_login = 0;
	unsigned login_flags = SESSION_LOGIN|SESSION_CONTEXT_SPECIFIC;

	PKCS11_CHECK_INIT_PRIVKEY(key);

	if (key->pk_algorithm != GNUTLS_PK_RSA)
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

	mech.mechanism = CKM_RSA_PKCS;
	mech.parameter = NULL;
	mech.parameter_len = 0;

	ret = gnutls_mutex_lock(&key->mutex);
	if (ret != 0)
		return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR);

	/* Initialize signing operation; using the private key discovered
	 * earlier. */
	REPEAT_ON_INVALID_HANDLE(rv = pkcs11_decrypt_init(key->sinfo.module, key->sinfo.pks, &mech, key->ref));
	if (rv != CKR_OK) {
		gnutls_assert();
		ret = pkcs11_rv_to_err(rv);
		goto cleanup;
	}

 retry_login:
	if (key->reauth || req_login) {
		if (req_login)
			login_flags = SESSION_LOGIN|SESSION_FORCE_LOGIN;

		ret =
		    pkcs11_login(&key->sinfo, &key->pin,
				 key->uinfo, login_flags);
		if (ret < 0) {
			gnutls_assert();
			_gnutls_debug_log("PKCS #11 login failed, trying operation anyway\n");
			/* let's try the operation anyway */
		}
	}

	/* Work out how long the plaintext must be: */
	rv = pkcs11_decrypt(key->sinfo.module, key->sinfo.pks, ciphertext->data,
			    ciphertext->size, NULL, &siglen);
	if (unlikely(rv == CKR_USER_NOT_LOGGED_IN && req_login == 0)) {
		req_login = 1;
		goto retry_login;
	}

	if (rv != CKR_OK) {
		gnutls_assert();
		ret = pkcs11_rv_to_err(rv);
		goto cleanup;
	}

	plaintext->data = gnutls_malloc(siglen);
	plaintext->size = siglen;

	rv = pkcs11_decrypt(key->sinfo.module, key->sinfo.pks, ciphertext->data,
			    ciphertext->size, plaintext->data, &siglen);
	if (rv != CKR_OK) {
		gnutls_free(plaintext->data);
		gnutls_assert();
		ret = pkcs11_rv_to_err(rv);
		goto cleanup;
	}

	plaintext->size = siglen;

	ret = 0;

      cleanup:
	gnutls_mutex_unlock(&key->mutex);
	return ret;
}
Exemplo n.º 3
0
/*-
 * _gnutls_pkcs11_privkey_sign_hash:
 * @key: Holds the key
 * @hash: holds the data to be signed (should be output of a hash)
 * @signature: will contain the signature allocated with gnutls_malloc()
 *
 * This function will sign the given data using a signature algorithm
 * supported by the private key. It is assumed that the given data
 * are the output of a hash function.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 -*/
int
_gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key,
				 const gnutls_datum_t * hash,
				 gnutls_datum_t * signature)
{
	ck_rv_t rv;
	int ret;
	struct ck_mechanism mech;
	gnutls_datum_t tmp = { NULL, 0 };
	unsigned long siglen;
	struct pkcs11_session_info *sinfo;
	unsigned req_login = 0;
	unsigned login_flags = SESSION_LOGIN|SESSION_CONTEXT_SPECIFIC;

	PKCS11_CHECK_INIT_PRIVKEY(key);

	sinfo = &key->sinfo;

	mech.mechanism = pk_to_mech(key->pk_algorithm);
	mech.parameter = NULL;
	mech.parameter_len = 0;

	ret = gnutls_mutex_lock(&key->mutex);
	if (ret != 0)
		return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR);

	/* Initialize signing operation; using the private key discovered
	 * earlier. */
	REPEAT_ON_INVALID_HANDLE(rv = pkcs11_sign_init(sinfo->module, sinfo->pks, &mech, key->ref));
	if (rv != CKR_OK) {
		gnutls_assert();
		ret = pkcs11_rv_to_err(rv);
		goto cleanup;
	}

 retry_login:
	if (key->reauth || req_login) {
		if (req_login)
			login_flags = SESSION_LOGIN|SESSION_FORCE_LOGIN;

		ret =
		    pkcs11_login(&key->sinfo, &key->pin,
				 key->uinfo, login_flags);
		if (ret < 0) {
			gnutls_assert();
			_gnutls_debug_log("PKCS #11 login failed, trying operation anyway\n");
			/* let's try the operation anyway */
		}
	}

	/* Work out how long the signature must be: */
	rv = pkcs11_sign(sinfo->module, sinfo->pks, hash->data, hash->size,
			 NULL, &siglen);
	if (unlikely(rv == CKR_USER_NOT_LOGGED_IN && req_login == 0)) {
		req_login = 1;
		goto retry_login;
	}

	if (rv != CKR_OK) {
		gnutls_assert();
		ret = pkcs11_rv_to_err(rv);
		goto cleanup;
	}

	tmp.data = gnutls_malloc(siglen);
	tmp.size = siglen;

	rv = pkcs11_sign(sinfo->module, sinfo->pks, hash->data, hash->size,
			 tmp.data, &siglen);
	if (rv != CKR_OK) {
		gnutls_assert();
		ret = pkcs11_rv_to_err(rv);
		goto cleanup;
	}


	if (key->pk_algorithm == GNUTLS_PK_EC
	    || key->pk_algorithm == GNUTLS_PK_DSA) {
		unsigned int hlen = siglen / 2;
		gnutls_datum_t r, s;

		if (siglen % 2 != 0) {
			gnutls_assert();
			ret = GNUTLS_E_PK_SIGN_FAILED;
			goto cleanup;
		}

		r.data = tmp.data;
		r.size = hlen;

		s.data = &tmp.data[hlen];
		s.size = hlen;

		ret = _gnutls_encode_ber_rs_raw(signature, &r, &s);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		gnutls_free(tmp.data);
		tmp.data = NULL;
	} else {
		signature->size = siglen;
		signature->data = tmp.data;
	}

	ret = 0;

      cleanup:
	gnutls_mutex_unlock(&key->mutex);
	if (sinfo != &key->sinfo)
		pkcs11_close_session(sinfo);
	if (ret < 0)
		gnutls_free(tmp.data);

	return ret;
}