X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=lib%2Fgnutls_cert.c;h=9ed0609acb1854c2b0375f9d72c0d8a4feb3a739;hb=1def961b3af11a5720a0360977c229f2cf1d10d0;hp=ac2505199929c6c30258ae5fd5e3f58d70d71b40;hpb=23c081d9a1c00db32df06f99301f9dc99d34c4fb;p=platform%2Fupstream%2Fgnutls.git diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c index ac25051..9ed0609 100644 --- a/lib/gnutls_cert.c +++ b/lib/gnutls_cert.c @@ -7,7 +7,7 @@ * * The GnuTLS is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 3 of + * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but @@ -37,10 +37,13 @@ #include #include #include +#include #include "x509/x509_int.h" #ifdef ENABLE_OPENPGP #include "openpgp/gnutls_openpgp.h" #endif +#include "gettext.h" +#define _(String) dgettext (PACKAGE, String) /** * gnutls_certificate_free_keys: @@ -51,33 +54,29 @@ * TLS negotiation that uses the credentials is in progress. * **/ -void -gnutls_certificate_free_keys (gnutls_certificate_credentials_t sc) +void gnutls_certificate_free_keys(gnutls_certificate_credentials_t sc) { - unsigned i, j; - - for (i = 0; i < sc->ncerts; i++) - { - for (j = 0; j < sc->certs[i].cert_list_length; j++) - { - gnutls_pcert_deinit (&sc->certs[i].cert_list[j]); - } - gnutls_free (sc->certs[i].cert_list); - _gnutls_str_array_clear (&sc->certs[i].names); - } - - gnutls_free (sc->certs); - sc->certs = NULL; - - for (i = 0; i < sc->ncerts; i++) - { - gnutls_privkey_deinit (sc->pkey[i]); - } - - gnutls_free (sc->pkey); - sc->pkey = NULL; - - sc->ncerts = 0; + unsigned i, j; + + for (i = 0; i < sc->ncerts; i++) { + for (j = 0; j < sc->certs[i].cert_list_length; j++) { + gnutls_pcert_deinit(&sc->certs[i].cert_list[j]); + } + gnutls_free(sc->certs[i].cert_list); + _gnutls_str_array_clear(&sc->certs[i].names); + } + + gnutls_free(sc->certs); + sc->certs = NULL; + + for (i = 0; i < sc->ncerts; i++) { + gnutls_privkey_deinit(sc->pkey[i]); + } + + gnutls_free(sc->pkey); + sc->pkey = NULL; + + sc->ncerts = 0; } /** @@ -89,11 +88,10 @@ gnutls_certificate_free_keys (gnutls_certificate_credentials_t sc) * gnutls_certificate_verify_peers2() may call this to save some * memory. **/ -void -gnutls_certificate_free_cas (gnutls_certificate_credentials_t sc) +void gnutls_certificate_free_cas(gnutls_certificate_credentials_t sc) { - /* FIXME: do nothing for now */ - return; + /* FIXME: do nothing for now */ + return; } /** @@ -111,10 +109,52 @@ gnutls_certificate_free_cas (gnutls_certificate_credentials_t sc) * Since: 3.0 **/ int -gnutls_certificate_get_issuer (gnutls_certificate_credentials_t sc, - gnutls_x509_crt_t cert, gnutls_x509_crt_t* issuer, unsigned int flags) +gnutls_certificate_get_issuer(gnutls_certificate_credentials_t sc, + gnutls_x509_crt_t cert, + gnutls_x509_crt_t * issuer, + unsigned int flags) { - return gnutls_x509_trust_list_get_issuer(sc->tlist, cert, issuer, flags); + return gnutls_x509_trust_list_get_issuer(sc->tlist, cert, issuer, + flags); +} + +/** + * gnutls_certificate_get_crt_raw: + * @sc: is a #gnutls_certificate_credentials_t structure. + * @idx1: the index of the certificate if multiple are present + * @idx2: the index in the certificate list. Zero gives the server's certificate. + * @cert: Will hold the DER encoded certificate. + * + * This function will return the DER encoded certificate of the + * server or any other certificate on its certificate chain (based on @idx2). + * The returned data should be treated as constant and only accessible during the lifetime + * of @sc. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. In case the indexes are out of bounds %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE + * is returned. + * + * Since: 3.2.5 + **/ +int +gnutls_certificate_get_crt_raw(gnutls_certificate_credentials_t sc, + unsigned idx1, + unsigned idx2, gnutls_datum_t * cert) +{ + if (idx1 >= sc->ncerts) + return + gnutls_assert_val + (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + + if (idx2 >= sc->certs[idx1].cert_list_length) + return + gnutls_assert_val + (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + + cert->data = sc->certs[idx1].cert_list[idx2].cert.data; + cert->size = sc->certs[idx1].cert_list[idx2].cert.size; + + return 0; } /** @@ -131,48 +171,9 @@ gnutls_certificate_get_issuer (gnutls_certificate_credentials_t sc, * CA names are used by servers to advertise the CAs they support to * clients. **/ -void -gnutls_certificate_free_ca_names (gnutls_certificate_credentials_t sc) -{ - _gnutls_free_datum (&sc->x509_rdn_sequence); -} - -/*- - * _gnutls_certificate_get_rsa_params - Returns the RSA parameters pointer - * @rsa_params: holds the RSA parameters or NULL. - * @func: function to retrieve the parameters or NULL. - * @session: The session. - * - * This function will return the rsa parameters pointer. - -*/ -gnutls_rsa_params_t -_gnutls_certificate_get_rsa_params (gnutls_rsa_params_t rsa_params, - gnutls_params_function * func, - gnutls_session_t session) +void gnutls_certificate_free_ca_names(gnutls_certificate_credentials_t sc) { - gnutls_params_st params; - int ret; - - if (session->internals.params.rsa_params) - { - return session->internals.params.rsa_params; - } - - if (rsa_params) - { - session->internals.params.rsa_params = rsa_params; - } - else if (func) - { - ret = func (session, GNUTLS_PARAMS_RSA_EXPORT, ¶ms); - if (ret == 0 && params.type == GNUTLS_PARAMS_RSA_EXPORT) - { - session->internals.params.rsa_params = params.params.rsa_export; - session->internals.params.free_rsa_params = params.deinit; - } - } - - return session->internals.params.rsa_params; + _gnutls_free_datum(&sc->tlist->x509_rdn_sequence); } @@ -188,17 +189,17 @@ _gnutls_certificate_get_rsa_params (gnutls_rsa_params_t rsa_params, * function). **/ void -gnutls_certificate_free_credentials (gnutls_certificate_credentials_t sc) +gnutls_certificate_free_credentials(gnutls_certificate_credentials_t sc) { - gnutls_x509_trust_list_deinit(sc->tlist, 1); - gnutls_certificate_free_keys (sc); - gnutls_certificate_free_ca_names (sc); - + gnutls_x509_trust_list_deinit(sc->tlist, 1); + gnutls_certificate_free_keys(sc); + gnutls_free(sc->ocsp_response_file); + memset(sc->pin_tmp, 0, sizeof(sc->pin_tmp)); #ifdef ENABLE_OPENPGP - gnutls_openpgp_keyring_deinit (sc->keyring); + gnutls_openpgp_keyring_deinit(sc->keyring); #endif - gnutls_free (sc); + gnutls_free(sc); } @@ -212,27 +213,26 @@ gnutls_certificate_free_credentials (gnutls_certificate_credentials_t sc) * Returns: %GNUTLS_E_SUCCESS on success, or an error code. **/ int -gnutls_certificate_allocate_credentials (gnutls_certificate_credentials_t * - res) +gnutls_certificate_allocate_credentials(gnutls_certificate_credentials_t * + res) { -int ret; + int ret; - *res = gnutls_calloc (1, sizeof (certificate_credentials_st)); + *res = gnutls_calloc(1, sizeof(certificate_credentials_st)); - if (*res == NULL) - return GNUTLS_E_MEMORY_ERROR; + if (*res == NULL) + return GNUTLS_E_MEMORY_ERROR; - ret = gnutls_x509_trust_list_init( &(*res)->tlist, 0); - if (ret < 0) - { - gnutls_assert(); - gnutls_free(*res); - return GNUTLS_E_MEMORY_ERROR; - } - (*res)->verify_bits = DEFAULT_VERIFY_BITS; - (*res)->verify_depth = DEFAULT_VERIFY_DEPTH; + ret = gnutls_x509_trust_list_init(&(*res)->tlist, 0); + if (ret < 0) { + gnutls_assert(); + gnutls_free(*res); + return GNUTLS_E_MEMORY_ERROR; + } + (*res)->verify_bits = DEFAULT_MAX_VERIFY_BITS; + (*res)->verify_depth = DEFAULT_MAX_VERIFY_DEPTH; - return 0; + return 0; } @@ -243,51 +243,48 @@ int ret; * 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_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; + unsigned 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; } @@ -303,10 +300,10 @@ _gnutls_selected_cert_supported_kx (gnutls_session_t session, * function then the client will not be asked to send a certificate. **/ void -gnutls_certificate_server_set_request (gnutls_session_t session, - gnutls_certificate_request_t req) +gnutls_certificate_server_set_request(gnutls_session_t session, + gnutls_certificate_request_t req) { - session->internals.send_cert_req = req; + session->internals.send_cert_req = req; } /** @@ -344,10 +341,9 @@ gnutls_certificate_server_set_request (gnutls_session_t session, * indicates error and the handshake will be terminated. **/ void gnutls_certificate_client_set_retrieve_function - (gnutls_certificate_credentials_t cred, - gnutls_certificate_client_retrieve_function * func) -{ - cred->client_get_cert_callback = func; + (gnutls_certificate_credentials_t cred, + gnutls_certificate_client_retrieve_function * func) { + cred->client_get_cert_callback = func; } /** @@ -373,10 +369,9 @@ void gnutls_certificate_client_set_retrieve_function * will be terminated. **/ void gnutls_certificate_server_set_retrieve_function - (gnutls_certificate_credentials_t cred, - gnutls_certificate_server_retrieve_function * func) -{ - cred->server_get_cert_callback = func; + (gnutls_certificate_credentials_t cred, + gnutls_certificate_server_retrieve_function * func) { + cred->server_get_cert_callback = func; } /** @@ -417,10 +412,9 @@ void gnutls_certificate_server_set_retrieve_function * Since: 3.0 **/ void gnutls_certificate_set_retrieve_function - (gnutls_certificate_credentials_t cred, - gnutls_certificate_retrieve_function * func) -{ - cred->get_cert_callback = func; + (gnutls_certificate_credentials_t cred, + gnutls_certificate_retrieve_function * func) { + cred->get_cert_callback = func; } /** @@ -464,10 +458,9 @@ void gnutls_certificate_set_retrieve_function * Since: 3.0 **/ void gnutls_certificate_set_retrieve_function2 - (gnutls_certificate_credentials_t cred, - gnutls_certificate_retrieve_function2 * func) -{ - cred->get_cert_callback2 = func; + (gnutls_certificate_credentials_t cred, + gnutls_certificate_retrieve_function2 * func) { + cred->get_cert_callback2 = func; } /** @@ -494,11 +487,10 @@ void gnutls_certificate_set_retrieve_function2 * Since: 2.10.0 **/ void - gnutls_certificate_set_verify_function - (gnutls_certificate_credentials_t cred, - gnutls_certificate_verify_function * func) -{ - cred->verify_callback = func; + gnutls_certificate_set_verify_function + (gnutls_certificate_credentials_t cred, + gnutls_certificate_verify_function * func) { + cred->verify_callback = func; } /*- @@ -512,27 +504,26 @@ void * -*/ static time_t -_gnutls_x509_get_raw_crt_activation_time (const gnutls_datum_t * cert) +_gnutls_x509_get_raw_crt_activation_time(const gnutls_datum_t * cert) { - gnutls_x509_crt_t xcert; - time_t result; + gnutls_x509_crt_t xcert; + time_t result; - result = gnutls_x509_crt_init (&xcert); - if (result < 0) - return (time_t) - 1; + result = gnutls_x509_crt_init(&xcert); + if (result < 0) + return (time_t) - 1; - result = gnutls_x509_crt_import (xcert, cert, GNUTLS_X509_FMT_DER); - if (result < 0) - { - gnutls_x509_crt_deinit (xcert); - return (time_t) - 1; - } + result = gnutls_x509_crt_import(xcert, cert, GNUTLS_X509_FMT_DER); + if (result < 0) { + gnutls_x509_crt_deinit(xcert); + return (time_t) - 1; + } - result = gnutls_x509_crt_get_activation_time (xcert); + result = gnutls_x509_crt_get_activation_time(xcert); - gnutls_x509_crt_deinit (xcert); + gnutls_x509_crt_deinit(xcert); - return result; + return result; } /*- @@ -546,27 +537,26 @@ _gnutls_x509_get_raw_crt_activation_time (const gnutls_datum_t * cert) * -*/ static time_t -_gnutls_x509_get_raw_crt_expiration_time (const gnutls_datum_t * cert) +_gnutls_x509_get_raw_crt_expiration_time(const gnutls_datum_t * cert) { - gnutls_x509_crt_t xcert; - time_t result; + gnutls_x509_crt_t xcert; + time_t result; - result = gnutls_x509_crt_init (&xcert); - if (result < 0) - return (time_t) - 1; + result = gnutls_x509_crt_init(&xcert); + if (result < 0) + return (time_t) - 1; - result = gnutls_x509_crt_import (xcert, cert, GNUTLS_X509_FMT_DER); - if (result < 0) - { - gnutls_x509_crt_deinit (xcert); - return (time_t) - 1; - } + result = gnutls_x509_crt_import(xcert, cert, GNUTLS_X509_FMT_DER); + if (result < 0) { + gnutls_x509_crt_deinit(xcert); + return (time_t) - 1; + } - result = gnutls_x509_crt_get_expiration_time (xcert); + result = gnutls_x509_crt_get_expiration_time(xcert); - gnutls_x509_crt_deinit (xcert); + gnutls_x509_crt_deinit(xcert); - return result; + return result; } #ifdef ENABLE_OPENPGP @@ -578,57 +568,60 @@ _gnutls_x509_get_raw_crt_expiration_time (const gnutls_datum_t * cert) * Returns a negative error code in case of an error, or GNUTLS_E_NO_CERTIFICATE_FOUND if no certificate was sent. -*/ static int -_gnutls_openpgp_crt_verify_peers (gnutls_session_t session, - unsigned int *status) +_gnutls_openpgp_crt_verify_peers(gnutls_session_t session, + const char *hostname, + unsigned int *status) { - cert_auth_info_t info; - gnutls_certificate_credentials_t cred; - int peer_certificate_list_size, ret; - - CHECK_AUTH (GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST); - - info = _gnutls_get_auth_info (session); - if (info == NULL) - return GNUTLS_E_INVALID_REQUEST; - - cred = (gnutls_certificate_credentials_t) - _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL); - if (cred == NULL) - { - gnutls_assert (); - return GNUTLS_E_INSUFFICIENT_CREDENTIALS; - } - - if (info->raw_certificate_list == NULL || info->ncerts == 0) - { - gnutls_assert (); - return GNUTLS_E_NO_CERTIFICATE_FOUND; - } - - /* generate a list of gnutls_certs based on the auth info - * raw certs. - */ - peer_certificate_list_size = info->ncerts; - - if (peer_certificate_list_size != 1) - { - gnutls_assert (); - return GNUTLS_E_INTERNAL_ERROR; - } - - /* Verify certificate - */ - ret = - _gnutls_openpgp_verify_key (cred, &info->raw_certificate_list[0], - peer_certificate_list_size, status); - - if (ret < 0) - { - gnutls_assert (); - return ret; - } - - return 0; + cert_auth_info_t info; + gnutls_certificate_credentials_t cred; + int peer_certificate_list_size, ret; + unsigned int verify_flags; + + CHECK_AUTH(GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST); + + info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE); + if (info == NULL) + return GNUTLS_E_INVALID_REQUEST; + + cred = (gnutls_certificate_credentials_t) + _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE); + if (cred == NULL) { + gnutls_assert(); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + if (info->raw_certificate_list == NULL || info->ncerts == 0) { + gnutls_assert(); + return GNUTLS_E_NO_CERTIFICATE_FOUND; + } + + verify_flags = cred->verify_flags | session->internals.priorities.additional_verify_flags; + + /* generate a list of gnutls_certs based on the auth info + * raw certs. + */ + peer_certificate_list_size = info->ncerts; + + if (peer_certificate_list_size != 1) { + gnutls_assert(); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* Verify certificate + */ + ret = + _gnutls_openpgp_verify_key(cred, hostname, + &info->raw_certificate_list[0], + peer_certificate_list_size, + verify_flags, + status); + + if (ret < 0) { + gnutls_assert(); + return ret; + } + + return 0; } #endif @@ -637,50 +630,151 @@ _gnutls_openpgp_crt_verify_peers (gnutls_session_t session, * @session: is a gnutls session * @status: is the output of the verification * - * This function will try to verify the peer's certificate and return - * its status (trusted, invalid etc.). The value of @status should - * be one or more of the gnutls_certificate_status_t enumerated - * elements bitwise or'd. To avoid denial of service attacks some + * This function will verify the peer's certificate and store + * the status in the @status variable as a bitwise or'd gnutls_certificate_status_t + * values or zero if the certificate is trusted. Note that value in @status + * is set only when the return value of this function is success (i.e, failure + * to trust a certificate does not imply a negative return value). + * The default verification flags used by this function can be overridden + * using gnutls_certificate_set_verify_flags(). + * + * This function will take into account the OCSP Certificate Status TLS extension, + * as well as the following X.509 certificate extensions: Name Constraints, + * Key Usage, and Basic Constraints (pathlen). + * + * To avoid denial of service attacks some * default upper limits regarding the certificate key size and chain - * size are set. To override them use - * gnutls_certificate_set_verify_limits(). + * size are set. To override them use gnutls_certificate_set_verify_limits(). * * Note that you must also check the peer's name in order to check if - * the verified certificate belongs to the actual peer. - * - * This function uses gnutls_x509_crt_list_verify() with the CAs in - * the credentials as trusted CAs. + * the verified certificate belongs to the actual peer, see gnutls_x509_crt_check_hostname(), + * or use gnutls_certificate_verify_peers3(). * * Returns: a negative error code on error and %GNUTLS_E_SUCCESS (0) on success. **/ int -gnutls_certificate_verify_peers2 (gnutls_session_t session, - unsigned int *status) +gnutls_certificate_verify_peers2(gnutls_session_t session, + unsigned int *status) { - cert_auth_info_t info; + return gnutls_certificate_verify_peers(session, NULL, 0, status); +} - CHECK_AUTH (GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST); +/** + * gnutls_certificate_verify_peers3: + * @session: is a gnutls session + * @hostname: is the expected name of the peer; may be %NULL + * @status: is the output of the verification + * + * This function will verify the peer's certificate and store the + * status in the @status variable as a bitwise or'd gnutls_certificate_status_t + * values or zero if the certificate is trusted. Note that value in @status + * is set only when the return value of this function is success (i.e, failure + * to trust a certificate does not imply a negative return value). + * The default verification flags used by this function can be overridden + * using gnutls_certificate_set_verify_flags(). See the documentation + * of gnutls_certificate_verify_peers2() for details in the verification process. + * + * If the @hostname provided is non-NULL then this function will compare + * the hostname in the certificate against the given. The comparison will + * be accurate for ascii names; non-ascii names are compared byte-by-byte. + * If names do not match the %GNUTLS_CERT_UNEXPECTED_OWNER status flag will be set. + * + * In order to verify the purpose of the end-certificate (by checking the extended + * key usage), use gnutls_certificate_verify_peers(). + * + * Returns: a negative error code on error and %GNUTLS_E_SUCCESS (0) on success. + * + * Since: 3.1.4 + **/ +int +gnutls_certificate_verify_peers3(gnutls_session_t session, + const char *hostname, + unsigned int *status) +{ +gnutls_typed_vdata_st data; - info = _gnutls_get_auth_info (session); - if (info == NULL) - { - return GNUTLS_E_NO_CERTIFICATE_FOUND; - } + data.type = GNUTLS_DT_DNS_HOSTNAME; + data.size = 0; + data.data = (void*)hostname; - if (info->raw_certificate_list == NULL || info->ncerts == 0) - return GNUTLS_E_NO_CERTIFICATE_FOUND; + return gnutls_certificate_verify_peers(session, &data, 1, status); +} - switch (gnutls_certificate_type_get (session)) - { - case GNUTLS_CRT_X509: - return _gnutls_x509_cert_verify_peers (session, status); +/** + * gnutls_certificate_verify_peers: + * @session: is a gnutls session + * @data: an array of typed data + * @elements: the number of data elements + * @status: is the output of the verification + * + * This function will verify the peer's certificate and store the + * status in the @status variable as a bitwise or'd gnutls_certificate_status_t + * values or zero if the certificate is trusted. Note that value in @status + * is set only when the return value of this function is success (i.e, failure + * to trust a certificate does not imply a negative return value). + * The default verification flags used by this function can be overridden + * using gnutls_certificate_set_verify_flags(). See the documentation + * of gnutls_certificate_verify_peers2() for details in the verification process. + * + * The acceptable data types are %GNUTLS_DT_DNS_HOSTNAME and %GNUTLS_DT_KEY_PURPOSE_OID. + * If a DNS hostname is provided then this function will compare + * the hostname in the certificate against the given. The comparison will + * be accurate for ascii names; non-ascii names are compared byte-by-byte. + * If names do not match the %GNUTLS_CERT_UNEXPECTED_OWNER status flag will be set. + * + * If a key purpose OID is provided and the end-certificate contains the extended key + * usage PKIX extension, it will be required to be have the provided key purpose + * (e.g., %GNUTLS_KP_TLS_WWW_SERVER), or be marked for any purpose, otherwise + * verification will fail with %GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE status. + * + * Returns: a negative error code on error and %GNUTLS_E_SUCCESS (0) on success. + * + * Since: 3.3.0 + **/ +int +gnutls_certificate_verify_peers(gnutls_session_t session, + gnutls_typed_vdata_st * data, + unsigned int elements, + unsigned int *status) +{ + cert_auth_info_t info; + const char *hostname = NULL; + const char *purpose = NULL; + unsigned i; + + CHECK_AUTH(GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST); + + info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE); + if (info == NULL) { + return GNUTLS_E_NO_CERTIFICATE_FOUND; + } + + if (info->raw_certificate_list == NULL || info->ncerts == 0) + return GNUTLS_E_NO_CERTIFICATE_FOUND; + + for (i=0;iraw_certificate_list == NULL || info->ncerts == 0) - { - gnutls_assert (); - return (time_t) - 1; - } - - switch (gnutls_certificate_type_get (session)) - { - case GNUTLS_CRT_X509: - return - _gnutls_x509_get_raw_crt_expiration_time (&info->raw_certificate_list - [0]); + cert_auth_info_t info; + + CHECK_AUTH(GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST); + + info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE); + if (info == NULL) { + return (time_t) - 1; + } + + if (info->raw_certificate_list == NULL || info->ncerts == 0) { + gnutls_assert(); + return (time_t) - 1; + } + + switch (gnutls_certificate_type_get(session)) { + case GNUTLS_CRT_X509: + return + _gnutls_x509_get_raw_crt_expiration_time(&info-> + raw_certificate_list + [0]); #ifdef ENABLE_OPENPGP - case GNUTLS_CRT_OPENPGP: - return - _gnutls_openpgp_get_raw_key_expiration_time - (&info->raw_certificate_list[0]); + case GNUTLS_CRT_OPENPGP: + return + _gnutls_openpgp_get_raw_key_expiration_time + (&info->raw_certificate_list[0]); #endif - default: - return (time_t) - 1; - } + default: + return (time_t) - 1; + } } /** @@ -740,40 +831,38 @@ gnutls_certificate_expiration_time_peers (gnutls_session_t session) * * Deprecated: gnutls_certificate_verify_peers2() now verifies activation times. **/ -time_t -gnutls_certificate_activation_time_peers (gnutls_session_t session) +time_t gnutls_certificate_activation_time_peers(gnutls_session_t session) { - cert_auth_info_t info; - - CHECK_AUTH (GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST); - - info = _gnutls_get_auth_info (session); - if (info == NULL) - { - return (time_t) - 1; - } - - if (info->raw_certificate_list == NULL || info->ncerts == 0) - { - gnutls_assert (); - return (time_t) - 1; - } - - switch (gnutls_certificate_type_get (session)) - { - case GNUTLS_CRT_X509: - return - _gnutls_x509_get_raw_crt_activation_time (&info->raw_certificate_list - [0]); + cert_auth_info_t info; + + CHECK_AUTH(GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST); + + info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE); + if (info == NULL) { + return (time_t) - 1; + } + + if (info->raw_certificate_list == NULL || info->ncerts == 0) { + gnutls_assert(); + return (time_t) - 1; + } + + switch (gnutls_certificate_type_get(session)) { + case GNUTLS_CRT_X509: + return + _gnutls_x509_get_raw_crt_activation_time(&info-> + raw_certificate_list + [0]); #ifdef ENABLE_OPENPGP - case GNUTLS_CRT_OPENPGP: - return - _gnutls_openpgp_get_raw_key_creation_time (&info->raw_certificate_list - [0]); + case GNUTLS_CRT_OPENPGP: + return + _gnutls_openpgp_get_raw_key_creation_time(&info-> + raw_certificate_list + [0]); #endif - default: - return (time_t) - 1; - } + default: + return (time_t) - 1; + } } /** @@ -796,13 +885,13 @@ gnutls_certificate_activation_time_peers (gnutls_session_t session) * callback function. See also gnutls_sign_callback_get(). * * Deprecated: Use the PKCS 11 or #gnutls_privkey_t interfacess like gnutls_privkey_import_ext() instead. - */ + **/ void -gnutls_sign_callback_set (gnutls_session_t session, - gnutls_sign_func sign_func, void *userdata) +gnutls_sign_callback_set(gnutls_session_t session, + gnutls_sign_func sign_func, void *userdata) { - session->internals.sign_func = sign_func; - session->internals.sign_func_userdata = userdata; + session->internals.sign_func = sign_func; + session->internals.sign_func_userdata = userdata; } /** @@ -816,13 +905,175 @@ gnutls_sign_callback_set (gnutls_session_t session, * if not set, %NULL. * * Deprecated: Use the PKCS 11 interfaces instead. - */ + **/ gnutls_sign_func -gnutls_sign_callback_get (gnutls_session_t session, void **userdata) +gnutls_sign_callback_get(gnutls_session_t session, void **userdata) { - if (userdata) - *userdata = session->internals.sign_func_userdata; - return session->internals.sign_func; + if (userdata) + *userdata = session->internals.sign_func_userdata; + return session->internals.sign_func; } +#define TEST_TEXT "test text" +/* returns error if the certificate has different algorithm than + * the given key parameters. + */ +int _gnutls_check_key_cert_match(gnutls_certificate_credentials_t res) +{ + gnutls_datum_t test = {(void*)TEST_TEXT, sizeof(TEST_TEXT)-1}; + gnutls_datum_t sig = {NULL, 0}; + int pk, pk2, ret; + + pk = + gnutls_pubkey_get_pk_algorithm(res->certs[res->ncerts - 1]. + cert_list[0].pubkey, NULL); + pk2 = + gnutls_privkey_get_pk_algorithm(res->pkey[res->ncerts - 1], + NULL); + + if (pk2 != pk) { + gnutls_assert(); + return GNUTLS_E_CERTIFICATE_KEY_MISMATCH; + } + + /* now check if keys really match. We use the sign/verify approach + * because we cannot always obtain the parameters from the abstract + * keys (e.g. PKCS #11). */ + ret = gnutls_privkey_sign_data(res->pkey[res->ncerts - 1], + GNUTLS_DIG_SHA256, 0, &test, &sig); + if (ret < 0) { + /* for some reason we couldn't sign that. That shouldn't have + * happened, but since it did, report the issue and do not + * try the key matching test */ + _gnutls_debug_log("%s: failed signing\n", __func__); + goto finish; + } + + ret = gnutls_pubkey_verify_data2(res->certs[res->ncerts - 1].cert_list[0].pubkey, + gnutls_pk_to_sign(pk, GNUTLS_DIG_SHA256), + 0, &test, &sig); + + gnutls_free(sig.data); + + if (ret < 0) + return gnutls_assert_val(GNUTLS_E_CERTIFICATE_KEY_MISMATCH); + + finish: + return 0; +} +/** + * gnutls_certificate_verification_status_print: + * @status: The status flags to be printed + * @type: The certificate type + * @out: Newly allocated datum with (0) terminated string. + * @flags: should be zero + * + * This function will pretty print the status of a verification + * process -- eg. the one obtained by gnutls_certificate_verify_peers3(). + * + * The output @out needs to be deallocated using gnutls_free(). + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.1.4 + **/ +int +gnutls_certificate_verification_status_print(unsigned int status, + gnutls_certificate_type_t + type, gnutls_datum_t * out, + unsigned int flags) +{ + gnutls_buffer_st str; + int ret; + + _gnutls_buffer_init(&str); + + if (status == 0) + _gnutls_buffer_append_str(&str, + _ + ("The certificate is trusted. ")); + else + _gnutls_buffer_append_str(&str, + _ + ("The certificate is NOT trusted. ")); + + if (type == GNUTLS_CRT_X509) { + if (status & GNUTLS_CERT_REVOKED) + _gnutls_buffer_append_str(&str, + _ + ("The certificate chain is revoked. ")); + + if (status & GNUTLS_CERT_MISMATCH) + _gnutls_buffer_append_str(&str, + _ + ("The certificate doesn't match the local copy (TOFU). ")); + + if (status & GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED) + _gnutls_buffer_append_str(&str, + _ + ("The revocation data are old and have been superseded. ")); + + if (status & GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE) + _gnutls_buffer_append_str(&str, + _ + ("The revocation data are issued with a future date. ")); + + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) + _gnutls_buffer_append_str(&str, + _ + ("The certificate issuer is unknown. ")); + + if (status & GNUTLS_CERT_SIGNER_NOT_CA) + _gnutls_buffer_append_str(&str, + _ + ("The certificate issuer is not a CA. ")); + } else if (type == GNUTLS_CRT_OPENPGP) { + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) + _gnutls_buffer_append_str(&str, + _ + ("Could not find a signer of the certificate. ")); + + if (status & GNUTLS_CERT_REVOKED) + _gnutls_buffer_append_str(&str, + _ + ("The certificate is revoked. ")); + } + + if (status & GNUTLS_CERT_INSECURE_ALGORITHM) + _gnutls_buffer_append_str(&str, + _ + ("The certificate chain uses insecure algorithm. ")); + + if (status & GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE) + _gnutls_buffer_append_str(&str, + _ + ("The certificate chain violates the signer's constraints. ")); + + if (status & GNUTLS_CERT_NOT_ACTIVATED) + _gnutls_buffer_append_str(&str, + _ + ("The certificate chain uses not yet valid certificate. ")); + + if (status & GNUTLS_CERT_EXPIRED) + _gnutls_buffer_append_str(&str, + _ + ("The certificate chain uses expired certificate. ")); + + if (status & GNUTLS_CERT_SIGNATURE_FAILURE) + _gnutls_buffer_append_str(&str, + _ + ("The signature in the certificate is invalid. ")); + + if (status & GNUTLS_CERT_UNEXPECTED_OWNER) + _gnutls_buffer_append_str(&str, + _ + ("The name in the certificate does not match the expected. ")); + + ret = _gnutls_buffer_to_datum(&str, out); + if (out->size > 0) + out->size--; + + return ret; +}