/* 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; }
/* the same as _gnutls_handshake_sign_cert_vrfy except that it is made for TLS 1.2 */ static int _gnutls_handshake_sign_cert_vrfy12 (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; gnutls_sign_algorithm_t sign_algo; gnutls_digest_algorithm_t hash_algo; digest_hd_st *handshake_td; 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_debug_log ("sign handshake cert vrfy: picked %s with %s\n", gnutls_sign_algorithm_get_name (sign_algo), gnutls_mac_get_name (hash_algo)); if ((gnutls_mac_algorithm_t)hash_algo == session->internals.handshake_mac_handle.tls12.sha1.algorithm) handshake_td = &session->internals.handshake_mac_handle.tls12.sha1; else if ((gnutls_mac_algorithm_t)hash_algo == session->internals.handshake_mac_handle.tls12.sha256.algorithm) handshake_td = &session->internals.handshake_mac_handle.tls12.sha256; else return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); /* too bad we only support SHA1 and SHA256 */ ret = _gnutls_hash_copy (&td, handshake_td); if (ret < 0) { gnutls_assert (); return ret; } _gnutls_hash_deinit (&td, concat); dconcat.data = concat; dconcat.size = _gnutls_hash_get_algo_len (hash_algo); ret = sign_tls_hash (session, hash_algo, cert, pkey, &dconcat, signature); if (ret < 0) { gnutls_assert (); return ret; } return sign_algo; }
/* Check if the given signature algorithm is accepted by * the peer. Returns 0 on success or a negative value * on error. */ int _gnutls_session_sign_algo_requested (gnutls_session_t session, gnutls_sign_algorithm_t sig) { unsigned i; int ret, hash; gnutls_protocol_t ver = gnutls_protocol_get_version (session); sig_ext_st *priv; extension_priv_data_t epriv; if (!_gnutls_version_has_selectable_sighash (ver)) { return 0; } ret = _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS, &epriv); if (ret < 0) { gnutls_assert (); /* extension not received allow SHA1 and SHA256 */ hash = _gnutls_sign_get_hash_algorithm (sig); if (hash == GNUTLS_DIG_SHA1 || hash == GNUTLS_DIG_SHA256) return 0; else return ret; } priv = epriv.ptr; if (priv->sign_algorithms_size == 0) /* none set, allow all */ { return 0; } for (i = 0; i < priv->sign_algorithms_size; i++) { if (priv->sign_algorithms[i] == sig) { return 0; /* ok */ } } return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM; }
/* 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; }
/* * Verifies the given certificate again a certificate list of * trusted CAs. * * Returns only 0 or 1. If 1 it means that the certificate * was successfuly verified. * * 'flags': an OR of the gnutls_certificate_verify_flags enumeration. * * Output will hold some extra information about the verification * procedure. Issuer will hold the actual issuer from the trusted list. */ static int _gnutls_verify_certificate2 (gnutls_x509_crt_t cert, const gnutls_x509_crt_t * trusted_cas, int tcas_size, unsigned int flags, unsigned int *output, gnutls_x509_crt_t * _issuer, time_t now, gnutls_verify_output_function func) { gnutls_datum_t cert_signed_data = { NULL, 0 }; gnutls_datum_t cert_signature = { NULL, 0 }; gnutls_x509_crt_t issuer = NULL; int issuer_version, result, hash_algo; unsigned int out = 0; if (output) *output = 0; if (tcas_size >= 1) issuer = find_issuer (cert, trusted_cas, tcas_size); else { gnutls_assert (); out = GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID; if (output) *output |= out; result = 0; goto cleanup; } /* issuer is not in trusted certificate * authorities. */ if (issuer == NULL) { out = GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID; if (output) *output |= out; gnutls_assert (); result = 0; goto cleanup; } if (_issuer != NULL) *_issuer = issuer; issuer_version = gnutls_x509_crt_get_version (issuer); if (issuer_version < 0) { gnutls_assert (); return issuer_version; } if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN) && ((flags & GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT) || issuer_version != 1)) { if (check_if_ca (cert, issuer, flags) == 0) { gnutls_assert (); out = GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID; if (output) *output |= out; result = 0; goto cleanup; } } result = _gnutls_x509_get_signed_data (cert->cert, "tbsCertificate", &cert_signed_data); if (result < 0) { gnutls_assert (); goto cleanup; } result = _gnutls_x509_get_signature (cert->cert, "signature", &cert_signature); if (result < 0) { gnutls_assert (); goto cleanup; } result = _gnutls_x509_get_signature_algorithm(cert->cert, "signatureAlgorithm.algorithm"); if (result < 0) { gnutls_assert (); goto cleanup; } hash_algo = _gnutls_sign_get_hash_algorithm(result); result = _gnutls_x509_verify_data (hash_algo, &cert_signed_data, &cert_signature, issuer); if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED) { gnutls_assert (); out |= GNUTLS_CERT_INVALID; /* error. ignore it */ if (output) *output |= out; result = 0; } else if (result < 0) { gnutls_assert(); goto cleanup; } /* If the certificate is not self signed check if the algorithms * used are secure. If the certificate is self signed it doesn't * really matter. */ if (is_issuer (cert, cert) == 0) { int sigalg; sigalg = gnutls_x509_crt_get_signature_algorithm (cert); if (((sigalg == GNUTLS_SIGN_RSA_MD2) && !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) || ((sigalg == GNUTLS_SIGN_RSA_MD5) && !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5))) { out = GNUTLS_CERT_INSECURE_ALGORITHM | GNUTLS_CERT_INVALID; if (output) *output |= out; result = 0; } } /* Check activation/expiration times */ if (!(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) { /* check the time of the issuer first */ if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS)) { out |= check_time (issuer, now); if (out != 0) { result = 0; if (output) *output |= out; } } out |= check_time (cert, now); if (out != 0) { result = 0; if (output) *output |= out; } } cleanup: if (result >= 0 && func) func(cert, issuer, NULL, out); _gnutls_free_datum (&cert_signed_data); _gnutls_free_datum (&cert_signature); return result; }
/* * Returns only 0 or 1. If 1 it means that the CRL * was successfuly verified. * * 'flags': an OR of the gnutls_certificate_verify_flags enumeration. * * Output will hold information about the verification * procedure. */ static int _gnutls_verify_crl2 (gnutls_x509_crl_t crl, const gnutls_x509_crt_t * trusted_cas, int tcas_size, unsigned int flags, unsigned int *output) { /* CRL is ignored for now */ gnutls_datum_t crl_signed_data = { NULL, 0 }; gnutls_datum_t crl_signature = { NULL, 0 }; gnutls_x509_crt_t issuer; int result, hash_algo; if (output) *output = 0; if (tcas_size >= 1) issuer = find_crl_issuer (crl, trusted_cas, tcas_size); else { gnutls_assert (); if (output) *output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID; return 0; } /* issuer is not in trusted certificate * authorities. */ if (issuer == NULL) { gnutls_assert (); if (output) *output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID; return 0; } if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN)) { if (gnutls_x509_crt_get_ca_status (issuer, NULL) != 1) { gnutls_assert (); if (output) *output |= GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID; return 0; } } result = _gnutls_x509_get_signed_data (crl->crl, "tbsCertList", &crl_signed_data); if (result < 0) { gnutls_assert (); goto cleanup; } result = _gnutls_x509_get_signature (crl->crl, "signature", &crl_signature); if (result < 0) { gnutls_assert (); goto cleanup; } result = _gnutls_x509_get_signature_algorithm(crl->crl, "signatureAlgorithm.algorithm"); if (result < 0) { gnutls_assert (); goto cleanup; } hash_algo = _gnutls_sign_get_hash_algorithm(result); result = _gnutls_x509_verify_data (hash_algo, &crl_signed_data, &crl_signature, issuer); if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED) { gnutls_assert (); /* error. ignore it */ if (output) *output |= GNUTLS_CERT_INVALID; result = 0; } else if (result < 0) { gnutls_assert (); goto cleanup; } { int sigalg; sigalg = gnutls_x509_crl_get_signature_algorithm (crl); if (((sigalg == GNUTLS_SIGN_RSA_MD2) && !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) || ((sigalg == GNUTLS_SIGN_RSA_MD5) && !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5))) { if (output) *output |= GNUTLS_CERT_INSECURE_ALGORITHM | GNUTLS_CERT_INVALID; result = 0; } } cleanup: _gnutls_free_datum (&crl_signed_data); _gnutls_free_datum (&crl_signature); return result; }
/* 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_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; }
/* 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; }