/* Returns a requested by the peer signature algorithm that * matches the given public key algorithm. Index can be increased * to return the second choice etc. */ gnutls_sign_algorithm_t _gnutls_session_get_sign_algo (gnutls_session_t session, gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t * hash) { unsigned i; gnutls_protocol_t ver = gnutls_protocol_get_version (session); if (!_gnutls_version_has_selectable_sighash (ver) || session->security_parameters.extensions.sign_algorithms_size == 0) /* none set, allow all */ { *hash = GNUTLS_DIG_SHA1; return _gnutls_x509_pk_to_sign (pk, *hash); } for (i = 0; i < session->security_parameters.extensions.sign_algorithms_size; i++) { if (_gnutls_sign_get_pk_algorithm (session->security_parameters.extensions.sign_algorithms[i]) == pk) { *hash = _gnutls_sign_get_hash_algorithm (session->security_parameters. extensions.sign_algorithms[i]); return session->security_parameters.extensions.sign_algorithms[i]; } } return GNUTLS_SIGN_UNKNOWN; }
/* 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; }
/* Returns a requested by the peer signature algorithm that * matches the given public key algorithm. Index can be increased * to return the second choice etc. */ gnutls_sign_algorithm_t _gnutls_session_get_sign_algo (gnutls_session_t session, gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t * hash) { unsigned i; int ret; gnutls_protocol_t ver = gnutls_protocol_get_version (session); sig_ext_st *priv; extension_priv_data_t epriv; 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 all */ { *hash = GNUTLS_DIG_SHA1; return _gnutls_x509_pk_to_sign (pk, *hash); } for (i = 0; i < priv->sign_algorithms_size; i++) { if (_gnutls_sign_get_pk_algorithm (priv->sign_algorithms[i]) == pk) { *hash = _gnutls_sign_get_hash_algorithm (priv->sign_algorithms[i]); return priv->sign_algorithms[i]; } } return GNUTLS_SIGN_UNKNOWN; }
/* Generates a signature of all the random data and the parameters. * Used in DHE_* ciphersuites. */ int _gnutls_handshake_verify_data (gnutls_session_t session, gnutls_cert * cert, const gnutls_datum_t * params, gnutls_datum_t * signature, gnutls_sign_algorithm_t algo) { gnutls_datum_t dconcat; int ret; digest_hd_st td_md5; 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 = GNUTLS_DIG_SHA1; ret = _gnutls_session_sign_algo_enabled (session, algo); if (ret < 0) { gnutls_assert (); return ret; } if (!_gnutls_version_has_selectable_prf (ver)) { 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); } if (algo != GNUTLS_SIGN_UNKNOWN) hash_algo = _gnutls_sign_get_hash_algorithm (algo); ret = _gnutls_hash_init (&td_sha, hash_algo); if (ret < 0) { gnutls_assert (); if (!_gnutls_version_has_selectable_prf (ver)) _gnutls_hash_deinit (&td_md5, NULL); 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); if (!_gnutls_version_has_selectable_prf (ver)) { _gnutls_hash_deinit (&td_md5, concat); _gnutls_hash_deinit (&td_sha, &concat[16]); dconcat.data = concat; dconcat.size = 36; } else { gnutls_datum_t hash; _gnutls_hash_deinit (&td_sha, concat); hash.data = concat; hash.size = _gnutls_hash_get_algo_len (hash_algo); dconcat.data = concat; dconcat.size = sizeof concat; _gnutls_rsa_encode_sig (hash_algo, &hash, &dconcat); } ret = _gnutls_verify_sig (cert, &dconcat, signature, dconcat.size - _gnutls_hash_get_algo_len (hash_algo), _gnutls_sign_get_pk_algorithm (algo)); 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_verify_data (gnutls_session_t session, gnutls_pcert_st* cert, const gnutls_datum_t * params, gnutls_datum_t * signature, gnutls_sign_algorithm_t algo) { gnutls_datum_t dconcat; int ret; digest_hd_st td_md5; 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; if (_gnutls_version_has_selectable_sighash (ver)) { _gnutls_handshake_log ("HSK[%p]: verify handshake data: using %s\n", session, gnutls_sign_algorithm_get_name (algo)); ret = _gnutls_pubkey_compatible_with_sig(cert->pubkey, ver, algo); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_session_sign_algo_enabled (session, algo); if (ret < 0) return gnutls_assert_val(ret); hash_algo = _gnutls_sign_get_hash_algorithm (algo); } else { 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); hash_algo = GNUTLS_DIG_SHA1; } ret = _gnutls_hash_init (&td_sha, hash_algo); if (ret < 0) { gnutls_assert (); if (!_gnutls_version_has_selectable_sighash (ver)) _gnutls_hash_deinit (&td_md5, NULL); 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); if (!_gnutls_version_has_selectable_sighash (ver)) { _gnutls_hash_deinit (&td_md5, concat); _gnutls_hash_deinit (&td_sha, &concat[16]); dconcat.data = concat; dconcat.size = 36; } else { _gnutls_hash_deinit (&td_sha, concat); dconcat.data = concat; dconcat.size = _gnutls_hash_get_algo_len (hash_algo); } ret = verify_tls_hash (ver, cert, &dconcat, signature, dconcat.size - _gnutls_hash_get_algo_len (hash_algo), _gnutls_sign_get_pk_algorithm (algo)); if (ret < 0) { gnutls_assert (); return ret; } return ret; }