static int dsa_sign (const gnutls_datum_t * text, bigint_t * params, int params_len, gnutls_datum_t * signature) { int ret; opaque _digest[MAX_HASH_SIZE]; digest_hd_st hd; gnutls_datum_t digest; gnutls_digest_algorithm_t hash = _gnutls_dsa_q_to_hash (params[1]); ret = _gnutls_hash_init (&hd, hash); if (ret < 0) { gnutls_assert (); return ret; } _gnutls_hash (&hd, text->data, text->size); _gnutls_hash_deinit (&hd, _digest); digest.data = _digest; digest.size = _gnutls_hash_get_algo_len (hash); if ((ret = _gnutls_sign (GNUTLS_PK_DSA, params, params_len, &digest, signature)) < 0) { gnutls_assert (); return ret; } return 0; }
/* Hashes input data and verifies a DSA signature. */ static int dsa_verify_sig (const gnutls_datum_t * text, const gnutls_datum_t * hash, const gnutls_datum_t * signature, bigint_t * params, int params_len) { int ret; opaque _digest[MAX_HASH_SIZE]; gnutls_datum_t digest; digest_hd_st hd; gnutls_digest_algorithm_t algo; unsigned int hash_len; algo = _gnutls_dsa_q_to_hash (params[1], &hash_len); if (hash) { /* SHA1 or better allowed */ if (!hash->data || hash->size < hash_len) { gnutls_assert(); _gnutls_debug_log("Hash size (%d) does not correspond to hash %s", (int)hash->size, gnutls_mac_get_name(algo)); if (hash->size != 20) return GNUTLS_E_PK_SIG_VERIFY_FAILED; } digest = *hash; } else { ret = _gnutls_hash_init (&hd, algo); if (ret < 0) { gnutls_assert (); return ret; } _gnutls_hash (&hd, text->data, text->size); _gnutls_hash_deinit (&hd, _digest); digest.data = _digest; digest.size = _gnutls_hash_get_algo_len(algo); } ret = _gnutls_dsa_verify (&digest, signature, params, params_len); return ret; }
int pk_hash_data (gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t hash, bigint_t * params, const gnutls_datum_t * data, gnutls_datum_t * digest) { int ret; switch (pk) { case GNUTLS_PK_RSA: break; case GNUTLS_PK_DSA: if (params && hash != _gnutls_dsa_q_to_hash (params[1])) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } break; default: gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } digest->size = _gnutls_hash_get_algo_len (hash); digest->data = gnutls_malloc (digest->size); if (digest->data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_hash_fast (hash, data->data, data->size, digest->data); if (ret < 0) { gnutls_assert (); goto cleanup; } return 0; cleanup: gnutls_free (digest->data); return ret; }
/** * gnutls_pubkey_get_preferred_hash_algorithm: * @key: Holds the certificate * @hash: The result of the call with the hash algorithm used for signature * @mand: If non zero it means that the algorithm MUST use this hash. May be NULL. * * This function will read the certificate and return the appropriate digest * algorithm to use for signing with this certificate. Some certificates (i.e. * DSA might not be able to sign without the preferred algorithm). * * To get the signature algorithm instead of just the hash use gnutls_pk_to_sign() * with the algorithm of the certificate/key and the provided @hash. * * Returns: the 0 if the hash algorithm is found. A negative error code is * returned on error. * * Since: 2.12.0 **/ int gnutls_pubkey_get_preferred_hash_algorithm(gnutls_pubkey_t key, gnutls_digest_algorithm_t * hash, unsigned int *mand) { int ret; const mac_entry_st *me; if (key == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } if (mand) *mand = 0; switch (key->pk_algorithm) { case GNUTLS_PK_DSA: if (mand) *mand = 1; /* fallthrough */ case GNUTLS_PK_EC: me = _gnutls_dsa_q_to_hash(key->pk_algorithm, &key->params, NULL); if (hash) *hash = (gnutls_digest_algorithm_t)me->id; ret = 0; break; case GNUTLS_PK_RSA: if (hash) *hash = GNUTLS_DIG_SHA256; ret = 0; break; default: gnutls_assert(); ret = GNUTLS_E_INTERNAL_ERROR; } return ret; }
/* This will return the appropriate hash to verify the given signature. * If signature is NULL it will return an (or the) appropriate hash for * the given parameters. */ int _gnutls_x509_verify_algorithm (gnutls_mac_algorithm_t * hash, const gnutls_datum_t * signature, gnutls_pk_algorithm pk, bigint_t * issuer_params, unsigned int issuer_params_size) { opaque digest[MAX_HASH_SIZE]; gnutls_datum_t decrypted; int digest_size; int ret; switch (pk) { case GNUTLS_PK_DSA: if (hash) *hash = _gnutls_dsa_q_to_hash (issuer_params[1], NULL); ret = 0; break; case GNUTLS_PK_RSA: if (signature == NULL) { /* return a sensible algorithm */ if (hash) *hash = GNUTLS_DIG_SHA256; return 0; } ret = _gnutls_pkcs1_rsa_decrypt (&decrypted, signature, issuer_params, issuer_params_size, 1); if (ret < 0) { gnutls_assert (); goto cleanup; } digest_size = sizeof (digest); if ((ret = decode_ber_digest_info (&decrypted, hash, digest, &digest_size)) != 0) { gnutls_assert (); _gnutls_free_datum (&decrypted); goto cleanup; } _gnutls_free_datum (&decrypted); if (digest_size != _gnutls_hash_get_algo_len (*hash)) { gnutls_assert (); ret = GNUTLS_E_ASN1_GENERIC_ERROR; goto cleanup; } ret = 0; break; default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; } cleanup: return ret; }
static int _wrap_nettle_pk_verify (gnutls_pk_algorithm_t algo, const gnutls_datum_t * vdata, const gnutls_datum_t * signature, const gnutls_pk_params_st * pk_params) { int ret; unsigned int hash_len; bigint_t tmp[2] = { NULL, NULL }; switch (algo) { case GNUTLS_PK_EC: /* ECDSA */ { ecc_key pub; struct dsa_signature sig; int stat; int curve_id = pk_params->flags; if (is_supported_curve(curve_id) == 0) return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE); ret = _gnutls_decode_ber_rs (signature, &tmp[0], &tmp[1]); if (ret < 0) { gnutls_assert (); goto cleanup; } _ecc_params_to_pubkey(pk_params, &pub); memcpy (&sig.r, tmp[0], sizeof (sig.r)); memcpy (&sig.s, tmp[1], sizeof (sig.s)); _gnutls_dsa_q_to_hash (algo, pk_params, &hash_len); if (hash_len > vdata->size) hash_len = vdata->size; ret = ecc_verify_hash(&sig, vdata->data, hash_len, &stat, &pub, curve_id); if (ret != 0 || stat != 1) { gnutls_assert(); ret = GNUTLS_E_PK_SIG_VERIFY_FAILED; } else ret = 0; _gnutls_mpi_release (&tmp[0]); _gnutls_mpi_release (&tmp[1]); _ecc_params_clear( &pub); break; } case GNUTLS_PK_DSA: { struct dsa_public_key pub; struct dsa_signature sig; ret = _gnutls_decode_ber_rs (signature, &tmp[0], &tmp[1]); if (ret < 0) { gnutls_assert (); goto cleanup; } memset(&pub, 0, sizeof(pub)); _dsa_params_to_pubkey (pk_params, &pub); memcpy (&sig.r, tmp[0], sizeof (sig.r)); memcpy (&sig.s, tmp[1], sizeof (sig.s)); _gnutls_dsa_q_to_hash (algo, pk_params, &hash_len); if (hash_len > vdata->size) hash_len = vdata->size; ret = _dsa_verify (&pub, hash_len, vdata->data, &sig); if (ret == 0) { gnutls_assert(); ret = GNUTLS_E_PK_SIG_VERIFY_FAILED; } else ret = 0; _gnutls_mpi_release (&tmp[0]); _gnutls_mpi_release (&tmp[1]); break; } case GNUTLS_PK_RSA: { struct rsa_public_key pub; _rsa_params_to_pubkey (pk_params, &pub); ret = _gnutls_mpi_scan_nz (&tmp[0], signature->data, signature->size); if (ret < 0) { gnutls_assert (); goto cleanup; } ret = rsa_pkcs1_verify (&pub, vdata->size, vdata->data, TOMPZ(tmp[0])); if (ret == 0) ret = gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED); else ret = 0; _gnutls_mpi_release (&tmp[0]); break; } default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } cleanup: return ret; }
/* in case of DSA puts into data, r,s */ static int _wrap_nettle_pk_sign (gnutls_pk_algorithm_t algo, gnutls_datum_t * signature, const gnutls_datum_t * vdata, const gnutls_pk_params_st * pk_params) { int ret; unsigned int hash; unsigned int hash_len; switch (algo) { case GNUTLS_PK_EC: /* we do ECDSA */ { ecc_key priv; struct dsa_signature sig; int curve_id = pk_params->flags; if (is_supported_curve(curve_id) == 0) return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE); _ecc_params_to_privkey(pk_params, &priv); dsa_signature_init (&sig); hash = _gnutls_dsa_q_to_hash (algo, pk_params, &hash_len); if (hash_len > vdata->size) { gnutls_assert (); _gnutls_debug_log("Security level of algorithm requires hash %s(%d) or better\n", gnutls_mac_get_name(hash), hash_len); hash_len = vdata->size; } ret = ecc_sign_hash(vdata->data, hash_len, &sig, NULL, rnd_func, &priv, curve_id); if (ret != 0) { gnutls_assert (); ret = GNUTLS_E_PK_SIGN_FAILED; goto ecdsa_fail; } ret = _gnutls_encode_ber_rs (signature, &sig.r, &sig.s); ecdsa_fail: dsa_signature_clear (&sig); _ecc_params_clear( &priv); if (ret < 0) { gnutls_assert (); goto cleanup; } break; } case GNUTLS_PK_DSA: { struct dsa_public_key pub; struct dsa_private_key priv; struct dsa_signature sig; memset(&priv, 0, sizeof(priv)); memset(&pub, 0, sizeof(pub)); _dsa_params_to_pubkey (pk_params, &pub); _dsa_params_to_privkey (pk_params, &priv); dsa_signature_init (&sig); hash = _gnutls_dsa_q_to_hash (algo, pk_params, &hash_len); if (hash_len > vdata->size) { gnutls_assert (); _gnutls_debug_log("Security level of algorithm requires hash %s(%d) or better\n", gnutls_mac_get_name(hash), hash_len); hash_len = vdata->size; } ret = _dsa_sign (&pub, &priv, NULL, rnd_func, hash_len, vdata->data, &sig); if (ret == 0) { gnutls_assert (); ret = GNUTLS_E_PK_SIGN_FAILED; goto dsa_fail; } ret = _gnutls_encode_ber_rs (signature, &sig.r, &sig.s); dsa_fail: dsa_signature_clear (&sig); if (ret < 0) { gnutls_assert (); goto cleanup; } break; } case GNUTLS_PK_RSA: { struct rsa_private_key priv; struct rsa_public_key pub; mpz_t s; _rsa_params_to_privkey (pk_params, &priv); _rsa_params_to_pubkey (pk_params, &pub); mpz_init(s); ret = rsa_pkcs1_sign_tr(&pub, &priv, NULL, rnd_func, vdata->size, vdata->data, s); if (ret == 0) { gnutls_assert(); ret = GNUTLS_E_PK_SIGN_FAILED; goto rsa_fail; } ret = _gnutls_mpi_dprint (s, signature); rsa_fail: mpz_clear(s); if (ret < 0) { gnutls_assert (); goto cleanup; } break; } default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } ret = 0; cleanup: return ret; }
/* Given a signature and parameters, it should return * the hash algorithm used in the signature. This is a kludge * but until we deprecate gnutls_pubkey_get_verify_algorithm() * we depend on it. */ static int wrap_nettle_hash_algorithm (gnutls_pk_algorithm_t pk, const gnutls_datum_t * sig, gnutls_pk_params_st * issuer_params, gnutls_digest_algorithm_t* hash_algo) { uint8_t digest[MAX_HASH_SIZE]; uint8_t digest_info[MAX_HASH_SIZE*3]; gnutls_datum_t di; unsigned digest_size; mpz_t s; struct rsa_public_key pub; int ret; mpz_init(s); switch (pk) { case GNUTLS_PK_DSA: case GNUTLS_PK_EC: if (hash_algo) *hash_algo = _gnutls_dsa_q_to_hash (pk, issuer_params, NULL); ret = 0; break; case GNUTLS_PK_RSA: if (sig == NULL) { /* return a sensible algorithm */ if (hash_algo) *hash_algo = GNUTLS_DIG_SHA256; return 0; } _rsa_params_to_pubkey (issuer_params, &pub); digest_size = sizeof(digest); nettle_mpz_set_str_256_u(s, sig->size, sig->data); digest_size = sizeof (digest_info); ret = extract_digest_info( &pub, &digest_size, digest_info, s); if (ret == 0) { ret = GNUTLS_E_PK_SIG_VERIFY_FAILED; gnutls_assert (); goto cleanup; } di.data = digest_info; di.size = digest_size; digest_size = sizeof(digest); if ((ret = decode_ber_digest_info (&di, hash_algo, digest, &digest_size)) < 0) { gnutls_assert (); goto cleanup; } if (digest_size != _gnutls_hash_get_algo_len (*hash_algo)) { gnutls_assert (); ret = GNUTLS_E_PK_SIG_VERIFY_FAILED; goto cleanup; } ret = 0; break; default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; } cleanup: mpz_clear(s); return ret; }
static int _wrap_nettle_pk_verify (gnutls_pk_algorithm_t algo, const gnutls_datum_t * vdata, const gnutls_datum_t * signature, const gnutls_pk_params_st * pk_params) { int ret; unsigned int hash_len; bigint_t tmp[2] = { NULL, NULL }; switch (algo) { case GNUTLS_PK_EC: /* ECDSA */ { ecc_key pub; struct dsa_signature sig; int stat; ret = _gnutls_decode_ber_rs (signature, &tmp[0], &tmp[1]); if (ret < 0) { gnutls_assert (); goto cleanup; } _ecc_params_to_pubkey(pk_params, &pub); memcpy (&sig.r, tmp[0], sizeof (sig.r)); memcpy (&sig.s, tmp[1], sizeof (sig.s)); _gnutls_dsa_q_to_hash (algo, pk_params, &hash_len); if (hash_len > vdata->size) hash_len = vdata->size; ret = ecc_verify_hash(&sig, vdata->data, hash_len, &stat, &pub); if (ret != 0 || stat != 1) { gnutls_assert(); ret = GNUTLS_E_PK_SIG_VERIFY_FAILED; } else ret = 0; _gnutls_mpi_release (&tmp[0]); _gnutls_mpi_release (&tmp[1]); _ecc_params_clear( &pub); break; } case GNUTLS_PK_DSA: { struct dsa_public_key pub; struct dsa_signature sig; ret = _gnutls_decode_ber_rs (signature, &tmp[0], &tmp[1]); if (ret < 0) { gnutls_assert (); goto cleanup; } memset(&pub, 0, sizeof(pub)); _dsa_params_to_pubkey (pk_params, &pub); memcpy (&sig.r, tmp[0], sizeof (sig.r)); memcpy (&sig.s, tmp[1], sizeof (sig.s)); _gnutls_dsa_q_to_hash (algo, pk_params, &hash_len); if (hash_len > vdata->size) hash_len = vdata->size; ret = _dsa_verify (&pub, hash_len, vdata->data, &sig); if (ret == 0) { gnutls_assert(); ret = GNUTLS_E_PK_SIG_VERIFY_FAILED; } else ret = 0; _gnutls_mpi_release (&tmp[0]); _gnutls_mpi_release (&tmp[1]); break; } case GNUTLS_PK_RSA: { bigint_t hash; if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } ret = _gnutls_mpi_scan_nz (&tmp[0], signature->data, signature->size); if (ret < 0) { gnutls_assert (); goto cleanup; } ret = _int_rsa_verify (pk_params, hash, tmp[0]); _gnutls_mpi_release (&tmp[0]); _gnutls_mpi_release (&hash); break; } default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } cleanup: return ret; }
/* in case of DSA puts into data, r,s */ static int _wrap_nettle_pk_sign (gnutls_pk_algorithm_t algo, gnutls_datum_t * signature, const gnutls_datum_t * vdata, const gnutls_pk_params_st * pk_params) { int ret; unsigned int hash; unsigned int hash_len; switch (algo) { case GNUTLS_PK_EC: /* we do ECDSA */ { ecc_key priv; struct dsa_signature sig; _ecc_params_to_privkey(pk_params, &priv); dsa_signature_init (&sig); hash = _gnutls_dsa_q_to_hash (algo, pk_params, &hash_len); if (hash_len > vdata->size) { gnutls_assert (); _gnutls_debug_log("Security level of algorithm requires hash %s(%d) or better\n", gnutls_mac_get_name(hash), hash_len); hash_len = vdata->size; } ret = ecc_sign_hash(vdata->data, hash_len, &sig, NULL, rnd_func, &priv); if (ret != 0) { gnutls_assert (); ret = GNUTLS_E_PK_SIGN_FAILED; goto ecdsa_fail; } ret = _gnutls_encode_ber_rs (signature, &sig.r, &sig.s); ecdsa_fail: dsa_signature_clear (&sig); _ecc_params_clear( &priv); if (ret < 0) { gnutls_assert (); goto cleanup; } break; } case GNUTLS_PK_DSA: { struct dsa_public_key pub; struct dsa_private_key priv; struct dsa_signature sig; memset(&priv, 0, sizeof(priv)); memset(&pub, 0, sizeof(pub)); _dsa_params_to_pubkey (pk_params, &pub); _dsa_params_to_privkey (pk_params, &priv); dsa_signature_init (&sig); hash = _gnutls_dsa_q_to_hash (algo, pk_params, &hash_len); if (hash_len > vdata->size) { gnutls_assert (); _gnutls_debug_log("Security level of algorithm requires hash %s(%d) or better\n", gnutls_mac_get_name(hash), hash_len); hash_len = vdata->size; } ret = _dsa_sign (&pub, &priv, NULL, rnd_func, hash_len, vdata->data, &sig); if (ret == 0) { gnutls_assert (); ret = GNUTLS_E_PK_SIGN_FAILED; goto dsa_fail; } ret = _gnutls_encode_ber_rs (signature, &sig.r, &sig.s); dsa_fail: dsa_signature_clear (&sig); if (ret < 0) { gnutls_assert (); goto cleanup; } break; } case GNUTLS_PK_RSA: { struct rsa_private_key priv; bigint_t hash, nc, ri; if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } memset(&priv, 0, sizeof(priv)); _rsa_params_to_privkey (pk_params, &priv); nc = rsa_blind (hash, pk_params->params[1] /*e */ , pk_params->params[0] /*m */ , &ri); _gnutls_mpi_release (&hash); if (nc == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto rsa_fail; } rsa_compute_root (&priv, TOMPZ (nc), TOMPZ (nc)); rsa_unblind (nc, ri, pk_params->params[0] /*m */ ); ret = _gnutls_mpi_dprint (nc, signature); rsa_fail: _gnutls_mpi_release (&nc); _gnutls_mpi_release (&ri); if (ret < 0) { gnutls_assert (); goto cleanup; } break; } default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } ret = 0; cleanup: return ret; }
int _gnutls_x509_verify_algorithm (gnutls_mac_algorithm_t * hash, const gnutls_datum_t * signature, const gnutls_x509_crt_t issuer) { bigint_t issuer_params[MAX_PUBLIC_PARAMS_SIZE]; opaque digest[MAX_HASH_SIZE]; gnutls_datum_t decrypted; int issuer_params_size; int digest_size; int ret, i; issuer_params_size = MAX_PUBLIC_PARAMS_SIZE; ret = _gnutls_x509_crt_get_mpis (issuer, issuer_params, &issuer_params_size); if (ret < 0) { gnutls_assert (); return ret; } switch (gnutls_x509_crt_get_pk_algorithm (issuer, NULL)) { case GNUTLS_PK_DSA: if (hash) *hash = _gnutls_dsa_q_to_hash (issuer_params[1]); ret = 0; break; case GNUTLS_PK_RSA: ret = _gnutls_pkcs1_rsa_decrypt (&decrypted, signature, issuer_params, issuer_params_size, 1); if (ret < 0) { gnutls_assert (); goto cleanup; } digest_size = sizeof (digest); if ((ret = decode_ber_digest_info (&decrypted, hash, digest, &digest_size)) != 0) { gnutls_assert (); _gnutls_free_datum (&decrypted); goto cleanup; } _gnutls_free_datum (&decrypted); if (digest_size != _gnutls_hash_get_algo_len (*hash)) { gnutls_assert (); ret = GNUTLS_E_ASN1_GENERIC_ERROR; goto cleanup; } ret = 0; break; default: gnutls_assert (); ret = GNUTLS_E_INTERNAL_ERROR; } cleanup: /* release allocated mpis */ for (i = 0; i < issuer_params_size; i++) { _gnutls_mpi_release (&issuer_params[i]); } return ret; }
static int pct_test(gnutls_pk_algorithm_t algo, const gnutls_pk_params_st* params) { int ret; gnutls_datum_t sig = {NULL, 0}; const char const_data[20] = "onetwothreefourfive"; gnutls_datum_t ddata, tmp = {NULL,0}; char* gen_data = NULL; if (algo == GNUTLS_PK_DSA || algo == GNUTLS_PK_EC) { unsigned hash_len; _gnutls_dsa_q_to_hash(algo, params, &hash_len); gen_data = gnutls_malloc(hash_len); gnutls_rnd(GNUTLS_RND_NONCE, gen_data, hash_len); ddata.data = (void*)gen_data; ddata.size = hash_len; } else { ddata.data = (void*)const_data; ddata.size = sizeof(const_data); } switch (algo) { case GNUTLS_PK_RSA: ret = _gnutls_pk_encrypt(algo, &sig, &ddata, params); if (ret < 0) { ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR); goto cleanup; } if (ddata.size == sig.size && memcmp(ddata.data, sig.data, sig.size) == 0) { ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR); gnutls_assert(); goto cleanup; } ret = _gnutls_pk_decrypt(algo, &tmp, &sig, params); if (ret < 0) { ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR); gnutls_assert(); goto cleanup; } if (tmp.size != ddata.size || memcmp(tmp.data, ddata.data, tmp.size) != 0) { ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR); gnutls_assert(); goto cleanup; } free(sig.data); sig.data = NULL; /* Here we don't know the purpose of the key. Check both * signing and encryption. */ case GNUTLS_PK_EC: /* we only do keys for ECDSA */ case GNUTLS_PK_DSA: ret = _gnutls_pk_sign(algo, &sig, &ddata, params); if (ret < 0) { ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR); goto cleanup; } ret = _gnutls_pk_verify(algo, &ddata, &sig, params); if (ret < 0) { ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR); gnutls_assert(); goto cleanup; } break; default: ret = gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); goto cleanup; } ret = 0; cleanup: if (ret == GNUTLS_E_PK_GENERATION_ERROR) { _gnutls_switch_lib_state(LIB_STATE_ERROR); } gnutls_free(gen_data); gnutls_free(sig.data); gnutls_free(tmp.data); return ret; }