/* this is _gnutls_handshake_verify_cert_vrfy for TLS 1.2 */ static int _gnutls_handshake_verify_cert_vrfy12 (gnutls_session_t session, gnutls_pcert_st* cert, gnutls_datum_t * signature, gnutls_sign_algorithm_t sign_algo) { int ret; opaque concat[MAX_SIG_SIZE]; digest_hd_st td; gnutls_datum_t dconcat; gnutls_sign_algorithm_t _sign_algo; gnutls_digest_algorithm_t hash_algo; digest_hd_st *handshake_td; gnutls_protocol_t ver = gnutls_protocol_get_version (session); gnutls_pk_algorithm_t pk = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL); handshake_td = &session->internals.handshake_mac_handle.tls12.sha1; hash_algo = handshake_td->algorithm; _sign_algo = _gnutls_x509_pk_to_sign (pk, hash_algo); if (_sign_algo != sign_algo) { handshake_td = &session->internals.handshake_mac_handle.tls12.sha256; hash_algo = handshake_td->algorithm; _sign_algo = _gnutls_x509_pk_to_sign (pk, hash_algo); if (sign_algo != _sign_algo) { gnutls_assert (); return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM; } } ret = _gnutls_hash_copy (&td, handshake_td); if (ret < 0) { gnutls_assert (); return GNUTLS_E_HASH_FAILED; } _gnutls_hash_deinit (&td, concat); dconcat.data = concat; dconcat.size = _gnutls_hash_get_algo_len (hash_algo); ret = verify_tls_hash (ver, cert, &dconcat, signature, 0, pk); if (ret < 0) { gnutls_assert (); return ret; } return ret; }
/* Returns a requested by the peer signature algorithm that * matches the given certificate's public key algorithm. */ gnutls_sign_algorithm_t _gnutls_session_get_sign_algo(gnutls_session_t session, gnutls_pcert_st * cert) { unsigned i; int ret; const version_entry_st *ver = get_version(session); sig_ext_st *priv; extension_priv_data_t epriv; unsigned int cert_algo; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); cert_algo = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL); ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS, &epriv); priv = epriv; if (ret < 0 || !_gnutls_version_has_selectable_sighash(ver) || priv->sign_algorithms_size == 0) /* none set, allow SHA-1 only */ { ret = gnutls_pk_to_sign(cert_algo, GNUTLS_DIG_SHA1); if (_gnutls_session_sign_algo_enabled(session, ret) < 0) goto fail; return ret; } for (i = 0; i < priv->sign_algorithms_size; i++) { if (gnutls_sign_get_pk_algorithm(priv->sign_algorithms[i]) == cert_algo) { if (_gnutls_pubkey_compatible_with_sig (session, cert->pubkey, ver, priv->sign_algorithms[i]) < 0) continue; if (_gnutls_session_sign_algo_enabled (session, priv->sign_algorithms[i]) < 0) continue; return priv->sign_algorithms[i]; } } fail: return GNUTLS_SIGN_UNKNOWN; }
/* returns error if the certificate has different algorithm than * the given key parameters. */ int _gnutls_check_key_cert_match (gnutls_certificate_credentials_t res) { int pk = gnutls_pubkey_get_pk_algorithm(res->certs[res->ncerts-1].cert_list[0].pubkey, NULL); int pk2 = gnutls_privkey_get_pk_algorithm (res->pkey[res->ncerts - 1], NULL); if (pk2 != pk) { gnutls_assert (); return GNUTLS_E_CERTIFICATE_KEY_MISMATCH; } return 0; }
/* returns the KX algorithms that are supported by a * certificate. (Eg a certificate with RSA params, supports * GNUTLS_KX_RSA algorithm). * This function also uses the KeyUsage field of the certificate * extensions in order to disable unneded algorithms. */ int _gnutls_selected_cert_supported_kx (gnutls_session_t session, gnutls_kx_algorithm_t * alg, int *alg_size) { gnutls_kx_algorithm_t kx; gnutls_pk_algorithm_t pk, cert_pk; gnutls_pcert_st *cert; int i; if (session->internals.selected_cert_list_length == 0) { *alg_size = 0; return 0; } cert = &session->internals.selected_cert_list[0]; cert_pk = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL); i = 0; for (kx = 0; kx < MAX_ALGOS; kx++) { pk = _gnutls_map_pk_get_pk (kx); if (pk == cert_pk) { /* then check key usage */ if (_gnutls_check_key_usage (cert, kx) == 0) { alg[i] = kx; i++; if (i > *alg_size) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); } } } if (i == 0) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } *alg_size = i; return 0; }
/* this is _gnutls_handshake_verify_crt_vrfy for TLS 1.2 */ static int _gnutls_handshake_verify_crt_vrfy12(gnutls_session_t session, gnutls_pcert_st * cert, gnutls_datum_t * signature, gnutls_sign_algorithm_t sign_algo) { int ret; uint8_t concat[MAX_HASH_SIZE]; gnutls_datum_t dconcat; const version_entry_st *ver = get_version(session); gnutls_pk_algorithm_t pk = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL); const mac_entry_st *me; ret = _gnutls_session_sign_algo_enabled(session, sign_algo); if (ret < 0) return gnutls_assert_val(ret); gnutls_sign_algorithm_set_client(session, sign_algo); me = hash_to_entry(gnutls_sign_get_hash_algorithm(sign_algo)); ret = _gnutls_hash_fast((gnutls_digest_algorithm_t)me->id, session->internals.handshake_hash_buffer. data, session->internals. handshake_hash_buffer_prev_len, concat); if (ret < 0) return gnutls_assert_val(ret); dconcat.data = concat; dconcat.size = _gnutls_hash_get_algo_len(me); ret = verify_tls_hash(session, ver, cert, &dconcat, signature, 0, sign_algo, pk); if (ret < 0) { gnutls_assert(); return ret; } return ret; }
/* Returns a requested by the peer signature algorithm that * matches the given certificate's public key algorithm. */ gnutls_sign_algorithm_t _gnutls_session_get_sign_algo (gnutls_session_t session, gnutls_pcert_st* cert) { unsigned i; int ret; gnutls_protocol_t ver = gnutls_protocol_get_version (session); sig_ext_st *priv; extension_priv_data_t epriv; unsigned int cert_algo; cert_algo = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL); ret = _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS, &epriv); priv = epriv.ptr; if (ret < 0 || !_gnutls_version_has_selectable_sighash (ver) || priv->sign_algorithms_size == 0) /* none set, allow SHA-1 only */ { return gnutls_pk_to_sign (cert_algo, GNUTLS_DIG_SHA1); } for (i = 0; i < priv->sign_algorithms_size; i++) { if (_gnutls_sign_get_pk_algorithm (priv->sign_algorithms[i]) == cert_algo) { if (_gnutls_pubkey_compatible_with_sig(cert->pubkey, ver, priv->sign_algorithms[i]) < 0) continue; if (_gnutls_session_sign_algo_enabled(session, priv->sign_algorithms[i]) < 0) continue; return priv->sign_algorithms[i]; } } return GNUTLS_SIGN_UNKNOWN; }
/* if the peer's certificate is of 512 bits or less, returns non zero. */ int _gnutls_peers_cert_less_512 (gnutls_session_t session) { gnutls_pcert_st peer_cert; int ret; cert_auth_info_t info = _gnutls_get_auth_info (session); if (info == NULL || info->ncerts == 0) { gnutls_assert (); /* we need this in order to get peer's certificate */ return 0; } if ((ret = _gnutls_get_auth_info_pcert (&peer_cert, session->security_parameters.cert_type, info)) < 0) { gnutls_assert (); return 0; } if (gnutls_pubkey_get_pk_algorithm(peer_cert.pubkey, NULL) != GNUTLS_PK_RSA) { gnutls_assert (); gnutls_pcert_deinit (&peer_cert); return 0; } if (_gnutls_pubkey_is_over_rsa_512(peer_cert.pubkey) < 0) { gnutls_pcert_deinit (&peer_cert); return 1; } gnutls_pcert_deinit (&peer_cert); return 0; }
Blob PublicKey::encrypt(const Blob& data) const { if (!pk) throw CryptoException("Can't read public key !"); unsigned key_len = 0; int err = gnutls_pubkey_get_pk_algorithm(pk, &key_len); if (err < 0) throw CryptoException("Can't read public key length !"); if (err != GNUTLS_PK_RSA) throw CryptoException("Must be an RSA key"); unsigned max_block_sz = key_len / 8 - 11; unsigned cypher_block_sz = key_len / 8; unsigned block_num = data.empty() ? 1 : 1 + (data.size() - 1) / max_block_sz; Blob ret; auto eb = data.cbegin(); auto ee = data.cend(); for (unsigned i=0; i<block_num; i++) { auto blk_sz = std::min<unsigned>(ee - eb, max_block_sz); const gnutls_datum_t dat {(uint8_t*)&(*eb), blk_sz}; gnutls_datum_t encrypted; err = gnutls_pubkey_encrypt_data(pk, 0, &dat, &encrypted); if (err != GNUTLS_E_SUCCESS) throw CryptoException(std::string("Can't encrypt data: ") + gnutls_strerror(err)); if (encrypted.size != cypher_block_sz) throw CryptoException("Unexpected cypherblock size"); ret.insert(ret.end(), encrypted.data, encrypted.data+encrypted.size); eb += blk_sz; gnutls_free(encrypted.data); } return ret; }
void doit(void) { gnutls_x509_privkey_t key; gnutls_x509_crt_t crt; gnutls_pubkey_t pubkey; gnutls_privkey_t privkey; gnutls_sign_algorithm_t sign_algo; gnutls_datum_t signature; gnutls_datum_t signature2; int ret; size_t i; global_init(); gnutls_global_set_log_function(tls_log_func); if (debug) gnutls_global_set_log_level(6); for (i = 0; i < sizeof(key_dat) / sizeof(key_dat[0]); i++) { if (debug) success("loop %d\n", (int) i); ret = gnutls_x509_privkey_init(&key); if (ret < 0) fail("gnutls_x509_privkey_init\n"); ret = gnutls_x509_privkey_import(key, &key_dat[i], GNUTLS_X509_FMT_PEM); if (ret < 0) fail("gnutls_x509_privkey_import\n"); ret = gnutls_pubkey_init(&pubkey); if (ret < 0) fail("gnutls_privkey_init\n"); ret = gnutls_privkey_init(&privkey); if (ret < 0) fail("gnutls_pubkey_init\n"); ret = gnutls_privkey_import_x509(privkey, key, 0); if (ret < 0) fail("gnutls_privkey_import_x509\n"); ret = gnutls_privkey_sign_hash(privkey, GNUTLS_DIG_SHA1, 0, &hash_data, &signature2); if (ret < 0) fail("gnutls_privkey_sign_hash\n"); ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0, &raw_data, &signature); if (ret < 0) fail("gnutls_x509_privkey_sign_hash\n"); ret = gnutls_x509_crt_init(&crt); if (ret < 0) fail("gnutls_x509_crt_init\n"); ret = gnutls_x509_crt_import(crt, &cert_dat[i], GNUTLS_X509_FMT_PEM); if (ret < 0) fail("gnutls_x509_crt_import\n"); ret = gnutls_pubkey_import_x509(pubkey, crt, 0); if (ret < 0) fail("gnutls_x509_pubkey_import\n"); ret = gnutls_x509_crt_get_signature_algorithm(crt); if (ret != GNUTLS_SIGN_RSA_SHA1) fail("gnutls_crt_get_signature_algorithm\n"); ret = gnutls_pubkey_verify_hash2(pubkey, GNUTLS_SIGN_RSA_SHA1, 0, &hash_data, &signature); if (ret < 0) fail("gnutls_x509_pubkey_verify_hash2\n"); ret = gnutls_pubkey_verify_hash2(pubkey, GNUTLS_SIGN_RSA_SHA1, 0, &hash_data, &signature2); if (ret < 0) fail("gnutls_x509_pubkey_verify_hash-1 (hashed data)\n"); /* should fail */ ret = gnutls_pubkey_verify_hash2(pubkey, GNUTLS_SIGN_RSA_SHA1, 0, &invalid_hash_data, &signature2); if (ret != GNUTLS_E_PK_SIG_VERIFY_FAILED) fail("gnutls_x509_pubkey_verify_hash-2 (hashed data)\n"); sign_algo = gnutls_pk_to_sign(gnutls_pubkey_get_pk_algorithm (pubkey, NULL), GNUTLS_DIG_SHA1); ret = gnutls_pubkey_verify_hash2(pubkey, sign_algo, 0, &hash_data, &signature2); if (ret < 0) fail("gnutls_x509_pubkey_verify_hash2-1 (hashed data)\n"); /* should fail */ ret = gnutls_pubkey_verify_hash2(pubkey, sign_algo, 0, &invalid_hash_data, &signature2); if (ret != GNUTLS_E_PK_SIG_VERIFY_FAILED) fail("gnutls_x509_pubkey_verify_hash2-2 (hashed data)\n"); /* test the raw interface */ gnutls_free(signature.data); signature.data = NULL; if (gnutls_pubkey_get_pk_algorithm(pubkey, NULL) == GNUTLS_PK_RSA) { ret = gnutls_privkey_sign_hash(privkey, GNUTLS_DIG_SHA1, GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA, &hash_data, &signature); if (ret < 0) fail("gnutls_privkey_sign_hash: %s\n", gnutls_strerror(ret)); sign_algo = gnutls_pk_to_sign (gnutls_pubkey_get_pk_algorithm(pubkey, NULL), GNUTLS_DIG_SHA1); ret = gnutls_pubkey_verify_hash2(pubkey, sign_algo, GNUTLS_PUBKEY_VERIFY_FLAG_TLS1_RSA, &hash_data, &signature); if (ret < 0) fail("gnutls_pubkey_verify_hash-3 (raw hashed data)\n"); gnutls_free(signature.data); /* test the legacy API */ ret = gnutls_privkey_sign_raw_data(privkey, 0, &hash_data, &signature); if (ret < 0) fail("gnutls_privkey_sign_raw_data: %s\n", gnutls_strerror(ret)); ret = gnutls_pubkey_verify_hash2(pubkey, sign_algo, GNUTLS_PUBKEY_VERIFY_FLAG_TLS1_RSA, &hash_data, &signature); if (ret < 0) fail("gnutls_pubkey_verify_hash-4 (legacy raw hashed data)\n"); } gnutls_free(signature.data); gnutls_free(signature2.data); gnutls_x509_privkey_deinit(key); gnutls_x509_crt_deinit(crt); gnutls_privkey_deinit(privkey); gnutls_pubkey_deinit(pubkey); } gnutls_global_deinit(); }
void pkcs11_test_sign(FILE * outfile, const char *url, unsigned int flags, common_info_st * info) { gnutls_privkey_t privkey; gnutls_pubkey_t pubkey; int ret; gnutls_datum_t data, sig = {NULL, 0}; int pk; pkcs11_common(info); FIX(url, outfile, 0, info); data.data = (void*)TEST_DATA; data.size = sizeof(TEST_DATA)-1; ret = gnutls_privkey_init(&privkey); if (ret < 0) { fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret)); exit(1); } ret = gnutls_pubkey_init(&pubkey); if (ret < 0) { fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret)); exit(1); } ret = gnutls_privkey_import_url(privkey, url, flags); if (ret < 0) { fprintf(stderr, "Cannot import private key: %s\n", gnutls_strerror(ret)); exit(1); } ret = gnutls_pubkey_import_privkey(pubkey, privkey, GNUTLS_KEY_DIGITAL_SIGNATURE, flags); if (ret < 0) { fprintf(stderr, "Cannot import public key: %s\n", gnutls_strerror(ret)); exit(1); } ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0, &data, &sig); if (ret < 0) { fprintf(stderr, "Cannot sign data: %s\n", gnutls_strerror(ret)); exit(1); } pk = gnutls_pubkey_get_pk_algorithm(pubkey, NULL); fprintf(stderr, "Verifying against private key parameters... "); ret = gnutls_pubkey_verify_data2(pubkey, gnutls_pk_to_sign(pk, GNUTLS_DIG_SHA1), 0, &data, &sig); if (ret < 0) { fprintf(stderr, "Cannot verify signed data: %s\n", gnutls_strerror(ret)); exit(1); } fprintf(stderr, "ok\n"); /* now try to verify against a public key within the token */ gnutls_pubkey_deinit(pubkey); ret = gnutls_pubkey_init(&pubkey); if (ret < 0) { fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret)); exit(1); } ret = gnutls_pubkey_import_url(pubkey, url, flags); if (ret < 0) { fprintf(stderr, "Cannot find a corresponding public key object in token: %s\n", gnutls_strerror(ret)); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) exit(0); exit(1); } fprintf(stderr, "Verifying against public key in the token... "); ret = gnutls_pubkey_verify_data2(pubkey, gnutls_pk_to_sign(pk, GNUTLS_DIG_SHA1), 0, &data, &sig); if (ret < 0) { fprintf(stderr, "Cannot verify signed data: %s\n", gnutls_strerror(ret)); exit(1); } fprintf(stderr, "ok\n"); gnutls_free(sig.data); gnutls_pubkey_deinit(pubkey); gnutls_privkey_deinit(privkey); UNFIX; }
/** * gnutls_pkcs11_copy_pubkey: * @token_url: A PKCS #11 URL specifying a token * @pubkey: The public key to copy * @label: The name to be used for the stored data * @cid: The CKA_ID to set for the object -if NULL, the ID will be derived from the public key * @key_usage: One of GNUTLS_KEY_* * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_* * * This function will copy a public key object into a PKCS #11 token specified by * a URL. Valid flags to mark the key: %GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED, * %GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE, %GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE, * %GNUTLS_PKCS11_OBJ_FLAG_MARK_CA, %GNUTLS_PKCS11_OBJ_FLAG_MARK_ALWAYS_AUTH. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.4.6 **/ int gnutls_pkcs11_copy_pubkey(const char *token_url, gnutls_pubkey_t pubkey, const char *label, const gnutls_datum_t *cid, unsigned int key_usage, unsigned int flags) { int ret; struct p11_kit_uri *info = NULL; ck_rv_t rv; size_t id_size; uint8_t id[20]; struct ck_attribute a[MAX_ASIZE]; gnutls_pk_algorithm_t pk; ck_object_class_t class = CKO_PUBLIC_KEY; ck_object_handle_t ctx; unsigned a_val; ck_key_type_t type; struct pkcs11_session_info sinfo; PKCS11_CHECK_INIT; ret = pkcs11_url_to_info(token_url, &info, 0); if (ret < 0) { gnutls_assert(); return ret; } ret = pkcs11_open_session(&sinfo, NULL, info, SESSION_WRITE | pkcs11_obj_flags_to_int(flags)); p11_kit_uri_free(info); if (ret < 0) { gnutls_assert(); return ret; } a[0].type = CKA_CLASS; a[0].value = &class; a[0].value_len = sizeof(class); a[1].type = CKA_TOKEN; a[1].value = (void *) &tval; a[1].value_len = sizeof(tval); a_val = 2; ret = add_pubkey(pubkey, a, &a_val); if (ret < 0) { gnutls_assert(); goto cleanup; } if (label) { a[a_val].type = CKA_LABEL; a[a_val].value = (void *) label; a[a_val].value_len = strlen(label); a_val++; } pk = gnutls_pubkey_get_pk_algorithm(pubkey, NULL); type = pk_to_key_type(pk); FIX_KEY_USAGE(pk, key_usage); a[a_val].type = CKA_KEY_TYPE; a[a_val].value = &type; a[a_val].value_len = sizeof(type); a_val++; a[a_val].type = CKA_ID; if (cid == NULL || cid->size == 0) { id_size = sizeof(id); ret = gnutls_pubkey_get_key_id(pubkey, 0, id, &id_size); if (ret < 0) { gnutls_assert(); goto cleanup; } a[a_val].value = id; a[a_val].value_len = id_size; } else { a[a_val].value = cid->data; a[a_val].value_len = cid->size; } a_val++; mark_flags(flags, a, &a_val, sinfo.trusted); a[a_val].type = CKA_VERIFY; if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) { a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof(tval); } else { a[a_val].value = (void*)&fval; a[a_val].value_len = sizeof(fval); } a_val++; if (pk == GNUTLS_PK_RSA) { a[a_val].type = CKA_ENCRYPT; if (key_usage & (GNUTLS_KEY_ENCIPHER_ONLY|GNUTLS_KEY_DECIPHER_ONLY)) { a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof(tval); } else { a[a_val].value = (void*)&fval; a[a_val].value_len = sizeof(fval); } a_val++; } rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &ctx); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); ret = pkcs11_rv_to_err(rv); goto cleanup; } /* generated! */ ret = 0; cleanup: clean_pubkey(a, a_val); pkcs11_close_session(&sinfo); return ret; }
/* Verifies a TLS signature (like the one in the client certificate * verify message). */ int _gnutls_handshake_verify_cert_vrfy (gnutls_session_t session, gnutls_pcert_st *cert, gnutls_datum_t * signature, gnutls_sign_algorithm_t sign_algo) { int ret; opaque concat[MAX_SIG_SIZE]; digest_hd_st td_md5; digest_hd_st td_sha; gnutls_datum_t dconcat; gnutls_protocol_t ver = gnutls_protocol_get_version (session); _gnutls_handshake_log ("HSK[%p]: verify cert vrfy: using %s\n", session, gnutls_sign_algorithm_get_name (sign_algo)); if (session->security_parameters.handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_12) { return _gnutls_handshake_verify_cert_vrfy12 (session, cert, signature, sign_algo); } else if (session->security_parameters.handshake_mac_handle_type != HANDSHAKE_MAC_TYPE_10) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } ret = _gnutls_hash_copy (&td_md5, &session->internals.handshake_mac_handle.tls10.md5); if (ret < 0) { gnutls_assert (); return ret; } ret = _gnutls_hash_copy (&td_sha, &session->internals.handshake_mac_handle.tls10.sha); if (ret < 0) { gnutls_assert (); _gnutls_hash_deinit (&td_md5, NULL); return GNUTLS_E_HASH_FAILED; } if (ver == GNUTLS_SSL3) { ret = _gnutls_generate_master (session, 1); if (ret < 0) { _gnutls_hash_deinit (&td_md5, NULL); _gnutls_hash_deinit (&td_sha, NULL); return gnutls_assert_val(ret); } ret = _gnutls_mac_deinit_ssl3_handshake (&td_md5, concat, session-> security_parameters.master_secret, GNUTLS_MASTER_SIZE); if (ret < 0) { _gnutls_hash_deinit (&td_sha, NULL); return gnutls_assert_val(ret); } ret = _gnutls_mac_deinit_ssl3_handshake (&td_sha, &concat[16], session-> security_parameters.master_secret, GNUTLS_MASTER_SIZE); if (ret < 0) { return gnutls_assert_val(ret); } } else { _gnutls_hash_deinit (&td_md5, concat); _gnutls_hash_deinit (&td_sha, &concat[16]); } dconcat.data = concat; dconcat.size = 20 + 16; /* md5+ sha */ ret = verify_tls_hash (ver, cert, &dconcat, signature, 16, gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL)); if (ret < 0) { gnutls_assert (); return ret; } return ret; }
/* Generates a signature of all the random data and the parameters. * Used in DHE_* ciphersuites. */ int _gnutls_handshake_sign_data (gnutls_session_t session, gnutls_pcert_st* cert, gnutls_privkey_t pkey, gnutls_datum_t * params, gnutls_datum_t * signature, gnutls_sign_algorithm_t * sign_algo) { gnutls_datum_t dconcat; int ret; digest_hd_st td_sha; opaque concat[MAX_SIG_SIZE]; gnutls_protocol_t ver = gnutls_protocol_get_version (session); gnutls_digest_algorithm_t hash_algo; *sign_algo = _gnutls_session_get_sign_algo (session, cert); if (*sign_algo == GNUTLS_SIGN_UNKNOWN) { gnutls_assert (); return GNUTLS_E_UNKNOWN_PK_ALGORITHM; } hash_algo = _gnutls_sign_get_hash_algorithm (*sign_algo); _gnutls_handshake_log ("HSK[%p]: signing handshake data: using %s\n", session, gnutls_sign_algorithm_get_name (*sign_algo)); ret = _gnutls_hash_init (&td_sha, hash_algo); if (ret < 0) { gnutls_assert (); return ret; } _gnutls_hash (&td_sha, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); _gnutls_hash (&td_sha, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); _gnutls_hash (&td_sha, params->data, params->size); switch (gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL)) { case GNUTLS_PK_RSA: if (!_gnutls_version_has_selectable_sighash (ver)) { digest_hd_st td_md5; ret = _gnutls_hash_init (&td_md5, GNUTLS_MAC_MD5); if (ret < 0) { gnutls_assert (); return ret; } _gnutls_hash (&td_md5, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); _gnutls_hash (&td_md5, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); _gnutls_hash (&td_md5, params->data, params->size); _gnutls_hash_deinit (&td_md5, concat); _gnutls_hash_deinit (&td_sha, &concat[16]); dconcat.data = concat; dconcat.size = 36; } else { /* TLS 1.2 way */ _gnutls_hash_deinit (&td_sha, concat); dconcat.data = concat; dconcat.size = _gnutls_hash_get_algo_len (hash_algo); } break; case GNUTLS_PK_DSA: _gnutls_hash_deinit (&td_sha, concat); if ((hash_algo != GNUTLS_DIG_SHA1) && (hash_algo != GNUTLS_DIG_SHA224) && (hash_algo != GNUTLS_DIG_SHA256)) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } dconcat.data = concat; dconcat.size = _gnutls_hash_get_algo_len (hash_algo); break; default: gnutls_assert (); _gnutls_hash_deinit (&td_sha, NULL); return GNUTLS_E_INTERNAL_ERROR; } ret = sign_tls_hash (session, hash_algo, cert, pkey, &dconcat, signature); if (ret < 0) { gnutls_assert (); } return ret; }
static int verify_tls_hash(gnutls_session_t session, const version_entry_st * ver, gnutls_pcert_st * cert, const gnutls_datum_t * hash_concat, gnutls_datum_t * signature, size_t sha1pos, gnutls_sign_algorithm_t sign_algo, gnutls_pk_algorithm_t pk_algo) { int ret; gnutls_datum_t vdata; unsigned int key_usage = 0, flags; if (cert == NULL) { gnutls_assert(); return GNUTLS_E_CERTIFICATE_ERROR; } gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage); /* If the certificate supports signing continue. */ if (key_usage != 0) if (!(key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { gnutls_assert(); _gnutls_audit_log(session, "Peer's certificate does not allow digital signatures. Key usage violation detected (ignored).\n"); } if (pk_algo == GNUTLS_PK_UNKNOWN) pk_algo = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL); switch (pk_algo) { case GNUTLS_PK_RSA: vdata.data = hash_concat->data; vdata.size = hash_concat->size; /* verify signature */ if (!_gnutls_version_has_selectable_sighash(ver)) flags = GNUTLS_PUBKEY_VERIFY_FLAG_TLS_RSA; else flags = 0; break; case GNUTLS_PK_DSA: case GNUTLS_PK_EC: vdata.data = &hash_concat->data[sha1pos]; vdata.size = hash_concat->size - sha1pos; flags = 0; break; default: gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } gnutls_sign_algorithm_set_server(session, sign_algo); ret = gnutls_pubkey_verify_hash2(cert->pubkey, sign_algo, flags, &vdata, signature); if (ret < 0) return gnutls_assert_val(ret); return 0; }
/* This will create a PKCS1 or DSA signature, as defined in the TLS protocol. * Cert is the certificate of the corresponding private key. It is only checked if * it supports signing. */ static int sign_tls_hash(gnutls_session_t session, const mac_entry_st * hash_algo, gnutls_pcert_st * cert, gnutls_privkey_t pkey, const gnutls_datum_t * hash_concat, gnutls_datum_t * signature) { const version_entry_st *ver = get_version(session); unsigned int key_usage = 0; /* If our certificate supports signing */ if (cert != NULL) { gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage); if (key_usage != 0) if (!(key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { gnutls_assert(); _gnutls_audit_log(session, "Peer's certificate does not allow digital signatures. Key usage violation detected (ignored).\n"); } /* External signing. Deprecated. To be removed. */ if (!pkey) { int ret; if (!session->internals.sign_func) return gnutls_assert_val (GNUTLS_E_INSUFFICIENT_CREDENTIALS); if (!_gnutls_version_has_selectable_sighash(ver)) return (*session->internals.sign_func) (session, session->internals.sign_func_userdata, cert->type, &cert->cert, hash_concat, signature); else { gnutls_datum_t digest; ret = _gnutls_set_datum(&digest, hash_concat->data, hash_concat->size); if (ret < 0) return gnutls_assert_val(ret); ret = pk_prepare_hash (gnutls_pubkey_get_pk_algorithm (cert->pubkey, NULL), hash_algo, &digest); if (ret < 0) { gnutls_assert(); goto es_cleanup; } ret = (*session->internals.sign_func) (session, session->internals.sign_func_userdata, cert->type, &cert->cert, &digest, signature); es_cleanup: gnutls_free(digest.data); return ret; } } } if (!_gnutls_version_has_selectable_sighash(ver)) return gnutls_privkey_sign_raw_data(pkey, 0, hash_concat, signature); else return gnutls_privkey_sign_hash(pkey, (gnutls_digest_algorithm_t)hash_algo->id, 0, hash_concat, signature); }
static void test_sig(gnutls_pk_algorithm_t pk, unsigned hash, unsigned bits) { gnutls_pubkey_t pubkey; gnutls_privkey_t privkey; gnutls_sign_algorithm_t sign_algo; gnutls_datum_t signature; const gnutls_datum_t *hash_data; int ret; unsigned j; if (hash == GNUTLS_DIG_SHA1) hash_data = &sha1_data; else if (hash == GNUTLS_DIG_SHA256) hash_data = &sha256_data; else abort(); sign_algo = gnutls_pk_to_sign(pk, hash); for (j = 0; j < 100; j++) { ret = gnutls_pubkey_init(&pubkey); if (ret < 0) ERR(__LINE__); ret = gnutls_privkey_init(&privkey); if (ret < 0) ERR(__LINE__); ret = gnutls_privkey_generate(privkey, pk, bits, 0); if (ret < 0) ERR(__LINE__); ret = gnutls_privkey_sign_hash(privkey, hash, 0, hash_data, &signature); if (ret < 0) ERR(__LINE__); ret = gnutls_pubkey_import_privkey(pubkey, privkey, GNUTLS_KEY_DIGITAL_SIGNATURE, 0); if (ret < 0) ERR(__LINE__); ret = gnutls_pubkey_verify_hash2(pubkey, sign_algo, 0, hash_data, &signature); if (ret < 0) ERR(__LINE__); /* should fail */ ret = gnutls_pubkey_verify_hash2(pubkey, sign_algo, 0, &invalid_hash_data, &signature); if (ret != GNUTLS_E_PK_SIG_VERIFY_FAILED) ERR(__LINE__); sign_algo = gnutls_pk_to_sign(gnutls_pubkey_get_pk_algorithm (pubkey, NULL), hash); ret = gnutls_pubkey_verify_hash2(pubkey, sign_algo, 0, hash_data, &signature); if (ret < 0) ERR(__LINE__); /* should fail */ ret = gnutls_pubkey_verify_hash2(pubkey, sign_algo, 0, &invalid_hash_data, &signature); if (ret != GNUTLS_E_PK_SIG_VERIFY_FAILED) ERR(__LINE__); /* test the raw interface */ gnutls_free(signature.data); signature.data = NULL; if (pk == GNUTLS_PK_RSA) { ret = gnutls_privkey_sign_hash(privkey, hash, GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA, hash_data, &signature); if (ret < 0) ERR(__LINE__); sign_algo = gnutls_pk_to_sign (gnutls_pubkey_get_pk_algorithm (pubkey, NULL), hash); ret = gnutls_pubkey_verify_hash2(pubkey, sign_algo, GNUTLS_PUBKEY_VERIFY_FLAG_TLS1_RSA, hash_data, &signature); if (ret < 0) ERR(__LINE__); } gnutls_free(signature.data); gnutls_privkey_deinit(privkey); gnutls_pubkey_deinit(pubkey); } }
/* Generates a signature of all the previous sent packets in the * handshake procedure. * 20040227: now it works for SSL 3.0 as well * 20091031: works for TLS 1.2 too! * * For TLS1.x, x<2 returns negative for failure and zero or unspecified for success. * For TLS1.2 returns the signature algorithm used on success, or a negative value; */ int _gnutls_handshake_sign_cert_vrfy (gnutls_session_t session, gnutls_pcert_st* cert, gnutls_privkey_t pkey, gnutls_datum_t * signature) { gnutls_datum_t dconcat; int ret; opaque concat[MAX_SIG_SIZE]; digest_hd_st td_md5; digest_hd_st td_sha; gnutls_protocol_t ver = gnutls_protocol_get_version (session); gnutls_pk_algorithm_t pk = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL); if (session->security_parameters.handshake_mac_handle_type == HANDSHAKE_MAC_TYPE_12) { return _gnutls_handshake_sign_cert_vrfy12 (session, cert, pkey, signature); } else if (session->security_parameters.handshake_mac_handle_type != HANDSHAKE_MAC_TYPE_10) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } ret = _gnutls_hash_copy (&td_sha, &session->internals.handshake_mac_handle.tls10.sha); if (ret < 0) { gnutls_assert (); return ret; } if (ver == GNUTLS_SSL3) { ret = _gnutls_generate_master (session, 1); if (ret < 0) { gnutls_assert (); _gnutls_hash_deinit (&td_sha, NULL); return ret; } ret = _gnutls_mac_deinit_ssl3_handshake (&td_sha, &concat[16], session-> security_parameters.master_secret, GNUTLS_MASTER_SIZE); if (ret < 0) return gnutls_assert_val(ret); } else _gnutls_hash_deinit (&td_sha, &concat[16]); /* ensure 1024 bit DSA keys are used */ ret = _gnutls_pubkey_compatible_with_sig(cert->pubkey, ver, GNUTLS_SIGN_UNKNOWN); if (ret < 0) return gnutls_assert_val(ret); switch (pk) { case GNUTLS_PK_RSA: ret = _gnutls_hash_copy (&td_md5, &session->internals.handshake_mac_handle.tls10. md5); if (ret < 0) { gnutls_assert (); return ret; } if (ver == GNUTLS_SSL3) { ret = _gnutls_mac_deinit_ssl3_handshake (&td_md5, concat, session-> security_parameters.master_secret, GNUTLS_MASTER_SIZE); if (ret < 0) return gnutls_assert_val(ret); } else _gnutls_hash_deinit (&td_md5, concat); dconcat.data = concat; dconcat.size = 36; break; case GNUTLS_PK_DSA: dconcat.data = &concat[16]; dconcat.size = 20; break; default: return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); } ret = sign_tls_hash (session, GNUTLS_DIG_NULL, cert, pkey, &dconcat, signature); if (ret < 0) { gnutls_assert (); } return ret; }
static int add_pubkey(gnutls_pubkey_t pubkey, struct ck_attribute *a, unsigned *a_val) { gnutls_pk_algorithm_t pk; int ret; pk = gnutls_pubkey_get_pk_algorithm(pubkey, NULL); switch (pk) { case GNUTLS_PK_RSA: { gnutls_datum_t m, e; ret = gnutls_pubkey_export_rsa_raw(pubkey, &m, &e); if (ret < 0) { gnutls_assert(); return ret; } /* PKCS#11 defines integers as unsigned having most significant byte * first, e.g., 32768 = 0x80 0x00. This is interpreted literraly by * some HSMs which do not accept an integer with a leading zero */ skip_leading_zeros(&m); skip_leading_zeros(&e); a[*a_val].type = CKA_MODULUS; a[*a_val].value = m.data; a[*a_val].value_len = m.size; (*a_val)++; a[*a_val].type = CKA_PUBLIC_EXPONENT; a[*a_val].value = e.data; a[*a_val].value_len = e.size; (*a_val)++; break; } case GNUTLS_PK_DSA: { gnutls_datum_t p, q, g, y; ret = gnutls_pubkey_export_dsa_raw(pubkey, &p, &q, &g, &y); if (ret < 0) { gnutls_assert(); return ret; } skip_leading_zeros(&p); skip_leading_zeros(&q); skip_leading_zeros(&g); skip_leading_zeros(&y); a[*a_val].type = CKA_PRIME; a[*a_val].value = p.data; a[*a_val].value_len = p.size; (*a_val)++; a[*a_val].type = CKA_SUBPRIME; a[*a_val].value = q.data; a[*a_val].value_len = q.size; (*a_val)++; a[*a_val].type = CKA_BASE; a[*a_val].value = g.data; a[*a_val].value_len = g.size; (*a_val)++; a[*a_val].type = CKA_VALUE; a[*a_val].value = y.data; a[*a_val].value_len = y.size; (*a_val)++; break; } case GNUTLS_PK_EC: { gnutls_datum_t params, point; ret = gnutls_pubkey_export_ecc_x962(pubkey, ¶ms, &point); if (ret < 0) { gnutls_assert(); return ret; } a[*a_val].type = CKA_EC_PARAMS; a[*a_val].value = params.data; a[*a_val].value_len = params.size; (*a_val)++; a[*a_val].type = CKA_EC_POINT; a[*a_val].value = point.data; a[*a_val].value_len = point.size; (*a_val)++; break; } default: _gnutls_debug_log("requested writing public key of unsupported type %u\n", (unsigned)pk); return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); } return 0; }
/* Verifies a TLS signature (like the one in the client certificate * verify message). */ int _gnutls_handshake_verify_crt_vrfy(gnutls_session_t session, gnutls_pcert_st * cert, gnutls_datum_t * signature, gnutls_sign_algorithm_t sign_algo) { int ret; uint8_t concat[MAX_SIG_SIZE]; digest_hd_st td_md5; digest_hd_st td_sha; gnutls_datum_t dconcat; const version_entry_st *ver = get_version(session); _gnutls_handshake_log("HSK[%p]: verify cert vrfy: using %s\n", session, gnutls_sign_algorithm_get_name(sign_algo)); if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); if (_gnutls_version_has_selectable_sighash(ver)) return _gnutls_handshake_verify_crt_vrfy12(session, cert, signature, sign_algo); ret = _gnutls_hash_init(&td_md5, hash_to_entry(GNUTLS_DIG_MD5)); if (ret < 0) { gnutls_assert(); return ret; } ret = _gnutls_hash_init(&td_sha, hash_to_entry(GNUTLS_DIG_SHA1)); if (ret < 0) { gnutls_assert(); _gnutls_hash_deinit(&td_md5, NULL); return GNUTLS_E_HASH_FAILED; } _gnutls_hash(&td_sha, session->internals.handshake_hash_buffer.data, session->internals.handshake_hash_buffer_prev_len); _gnutls_hash(&td_md5, session->internals.handshake_hash_buffer.data, session->internals.handshake_hash_buffer_prev_len); if (ver->id == GNUTLS_SSL3) { ret = _gnutls_generate_master(session, 1); if (ret < 0) { _gnutls_hash_deinit(&td_md5, NULL); _gnutls_hash_deinit(&td_sha, NULL); return gnutls_assert_val(ret); } ret = _gnutls_mac_deinit_ssl3_handshake(&td_md5, concat, session->security_parameters. master_secret, GNUTLS_MASTER_SIZE); if (ret < 0) { _gnutls_hash_deinit(&td_sha, NULL); return gnutls_assert_val(ret); } ret = _gnutls_mac_deinit_ssl3_handshake(&td_sha, &concat[16], session->security_parameters. master_secret, GNUTLS_MASTER_SIZE); if (ret < 0) { return gnutls_assert_val(ret); } } else { _gnutls_hash_deinit(&td_md5, concat); _gnutls_hash_deinit(&td_sha, &concat[16]); } dconcat.data = concat; dconcat.size = 20 + 16; /* md5+ sha */ ret = verify_tls_hash(session, ver, cert, &dconcat, signature, 16, GNUTLS_SIGN_UNKNOWN, gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL)); if (ret < 0) { gnutls_assert(); return ret; } return ret; }
void doit (void) { gnutls_x509_privkey_t key; gnutls_x509_crt_t crt; gnutls_pubkey_t pubkey; gnutls_privkey_t privkey; gnutls_digest_algorithm_t hash_algo; gnutls_sign_algorithm_t sign_algo; gnutls_datum_t signature; gnutls_datum_t signature2; int ret; size_t i; gnutls_global_init (); gnutls_global_set_log_function (tls_log_func); if (debug) gnutls_global_set_log_level (6); for (i = 0; i < sizeof (key_dat) / sizeof (key_dat[0]); i++) { if (debug) success ("loop %d\n", (int) i); ret = gnutls_x509_privkey_init (&key); if (ret < 0) fail ("gnutls_x509_privkey_init\n"); ret = gnutls_x509_privkey_import (key, &key_dat[i], GNUTLS_X509_FMT_PEM); if (ret < 0) fail ("gnutls_x509_privkey_import\n"); ret = gnutls_pubkey_init (&pubkey); if (ret < 0) fail ("gnutls_privkey_init\n"); ret = gnutls_privkey_init (&privkey); if (ret < 0) fail ("gnutls_pubkey_init\n"); ret = gnutls_privkey_import_x509 (privkey, key, 0); if (ret < 0) fail ("gnutls_privkey_import_x509\n"); ret = gnutls_privkey_sign_hash (privkey, GNUTLS_DIG_SHA1, 0, &hash_data, &signature2); if (ret < 0) fail ("gnutls_privkey_sign_hash\n"); ret = gnutls_privkey_sign_data (privkey, GNUTLS_DIG_SHA1, 0, &raw_data, &signature); if (ret < 0) fail ("gnutls_x509_privkey_sign_hash\n"); ret = gnutls_x509_crt_init (&crt); if (ret < 0) fail ("gnutls_x509_crt_init\n"); ret = gnutls_x509_crt_import (crt, &cert_dat[i], GNUTLS_X509_FMT_PEM); if (ret < 0) fail ("gnutls_x509_crt_import\n"); ret = gnutls_pubkey_import_x509 (pubkey, crt, 0); if (ret < 0) fail ("gnutls_x509_pubkey_import\n"); ret = gnutls_pubkey_get_verify_algorithm (pubkey, &signature, &hash_algo); if (ret < 0 || hash_algo != GNUTLS_DIG_SHA1) fail ("gnutls_x509_crt_get_verify_algorithm\n"); ret = gnutls_pubkey_verify_hash (pubkey, 0, &hash_data, &signature); if (ret < 0) fail ("gnutls_x509_pubkey_verify_hash\n"); ret = gnutls_pubkey_get_verify_algorithm (pubkey, &signature2, &hash_algo); if (ret < 0 || hash_algo != GNUTLS_DIG_SHA1) fail ("gnutls_x509_crt_get_verify_algorithm (hashed data)\n"); ret = gnutls_pubkey_verify_hash (pubkey, 0, &hash_data, &signature2); if (ret < 0) fail ("gnutls_x509_pubkey_verify_hash-1 (hashed data)\n"); /* should fail */ ret = gnutls_pubkey_verify_hash (pubkey, 0, &invalid_hash_data, &signature2); if (ret != GNUTLS_E_PK_SIG_VERIFY_FAILED) fail ("gnutls_x509_pubkey_verify_hash-2 (hashed data)\n"); sign_algo = gnutls_pk_to_sign(gnutls_pubkey_get_pk_algorithm(pubkey, NULL), GNUTLS_DIG_SHA1); ret = gnutls_pubkey_verify_hash2 (pubkey, sign_algo, 0, &hash_data, &signature2); if (ret < 0) fail ("gnutls_x509_pubkey_verify_hash2-1 (hashed data)\n"); /* should fail */ ret = gnutls_pubkey_verify_hash2 (pubkey, sign_algo, 0, &invalid_hash_data, &signature2); if (ret != GNUTLS_E_PK_SIG_VERIFY_FAILED) fail ("gnutls_x509_pubkey_verify_hash2-2 (hashed data)\n"); gnutls_free(signature.data); gnutls_free(signature2.data); gnutls_x509_privkey_deinit (key); gnutls_x509_crt_deinit (crt); gnutls_privkey_deinit (privkey); gnutls_pubkey_deinit (pubkey); } gnutls_global_deinit (); }
static int verify_tls_hash (gnutls_protocol_t ver, gnutls_pcert_st* cert, const gnutls_datum_t * hash_concat, gnutls_datum_t * signature, size_t sha1pos, gnutls_pk_algorithm_t pk_algo) { int ret; gnutls_datum_t vdata; unsigned int key_usage = 0, flags; if (cert == NULL) { gnutls_assert (); return GNUTLS_E_CERTIFICATE_ERROR; } gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage); /* If the certificate supports signing continue. */ if (key_usage != 0) if (!(key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { gnutls_assert (); return GNUTLS_E_KEY_USAGE_VIOLATION; } if (pk_algo == GNUTLS_PK_UNKNOWN) pk_algo = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL); switch (pk_algo) { case GNUTLS_PK_RSA: vdata.data = hash_concat->data; vdata.size = hash_concat->size; /* verify signature */ if (!_gnutls_version_has_selectable_sighash (ver)) flags = GNUTLS_PUBKEY_VERIFY_FLAG_TLS_RSA; else flags = 0; break; case GNUTLS_PK_DSA: vdata.data = &hash_concat->data[sha1pos]; vdata.size = hash_concat->size - sha1pos; flags = 0; break; default: gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } ret = gnutls_pubkey_verify_hash(cert->pubkey, flags, &vdata, signature); if (ret < 0) return gnutls_assert_val(ret); return 0; }