/*- * _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; struct pkcs11_session_info *sinfo; ck_object_handle_t obj; PKCS11_CHECK_INIT; if (key->sinfo.init != 0) { sinfo = &key->sinfo; obj = key->obj; } else { sinfo = &_sinfo; memset(sinfo, 0, sizeof(*sinfo)); FIND_OBJECT(sinfo, &key->pin, obj, key); } mech.mechanism = pk_to_mech(key->pk_algorithm); mech.parameter = NULL; mech.parameter_len = 0; /* Initialize signing operation; using the private key discovered * earlier. */ rv = pkcs11_sign_init(sinfo->module, sinfo->pks, &mech, obj); if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } /* Work out how long the signature must be: */ rv = pkcs11_sign(sinfo->module, sinfo->pks, hash->data, hash->size, NULL, &siglen); 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: if (sinfo != &key->sinfo) pkcs11_close_session(sinfo); if (ret < 0) gnutls_free(tmp.data); return ret; }
/*- * _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; }
/*- * _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; unsigned long siglen; struct ck_function_list *module; ck_session_handle_t pks; ck_object_handle_t obj; FIND_OBJECT (module, pks, obj, key); mech.mechanism = pk_to_mech(key->pk_algorithm); mech.parameter = NULL; mech.parameter_len = 0; /* Initialize signing operation; using the private key discovered * earlier. */ rv = pkcs11_sign_init (module, pks, &mech, obj); if (rv != CKR_OK) { gnutls_assert (); ret = pkcs11_rv_to_err (rv); goto cleanup; } /* Work out how long the signature must be: */ rv = pkcs11_sign (module, pks, hash->data, hash->size, NULL, &siglen); if (rv != CKR_OK) { gnutls_assert (); ret = pkcs11_rv_to_err (rv); goto cleanup; } signature->data = gnutls_malloc (siglen); signature->size = siglen; rv = pkcs11_sign (module, pks, hash->data, hash->size, signature->data, &siglen); if (rv != CKR_OK) { gnutls_free (signature->data); gnutls_assert (); ret = pkcs11_rv_to_err (rv); goto cleanup; } signature->size = siglen; if (key->pk_algorithm == GNUTLS_PK_EC || key->pk_algorithm == GNUTLS_PK_DSA) { bigint_t r,s; if (siglen % 2 != 0) { gnutls_assert(); ret = GNUTLS_E_PK_SIGN_FAILED; goto cleanup; } ret = read_rs(&r, &s, signature->data, signature->size); if (ret < 0) { gnutls_assert(); goto cleanup; } gnutls_free(signature->data); ret = _gnutls_encode_ber_rs (signature, r, s); _gnutls_mpi_release(&r); _gnutls_mpi_release(&s); if (ret < 0) { gnutls_assert(); goto cleanup; } } ret = 0; cleanup: pkcs11_close_session (module, pks); return ret; }