diff options
Diffstat (limited to 'lib/auth')
-rw-r--r-- | lib/auth/cert.c | 93 | ||||
-rw-r--r-- | lib/auth/rsa.c | 23 | ||||
-rw-r--r-- | lib/auth/srp_rsa.c | 3 |
3 files changed, 85 insertions, 34 deletions
diff --git a/lib/auth/cert.c b/lib/auth/cert.c index 4e2e484a2e..069968c5d3 100644 --- a/lib/auth/cert.c +++ b/lib/auth/cert.c @@ -308,7 +308,7 @@ get_issuers(gnutls_session_t session, int i; unsigned size; - if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) + if (gnutls_certificate_type_get2(session, GNUTLS_CTYPE_CLIENT) != GNUTLS_CRT_X509) return 0; /* put the requested DNs to req_dn, only in case @@ -339,7 +339,7 @@ get_issuers(gnutls_session_t session, return 0; } -/* Calls the client or server get callback. +/* Calls the client or server certificate get callback. */ static int call_get_cert_callback(gnutls_session_t session, @@ -349,7 +349,7 @@ call_get_cert_callback(gnutls_session_t session, { gnutls_privkey_t local_key = NULL; int ret = GNUTLS_E_INTERNAL_ERROR; - gnutls_certificate_type_t type = gnutls_certificate_type_get(session); + gnutls_certificate_type_t type; gnutls_certificate_credentials_t cred; gnutls_pcert_st *pcert = NULL; gnutls_ocsp_data_st *ocsp = NULL; @@ -363,6 +363,19 @@ call_get_cert_callback(gnutls_session_t session, return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } + /* Correctly set the certificate type depending on whether we + * have explicitly negotiated certificate types (RFC7250). + */ + if (_gnutls_has_negotiate_ctypes(session)) { + if (IS_SERVER(session)) { + type = gnutls_certificate_type_get2(session, GNUTLS_CTYPE_SERVER); + } else { // Client mode + type = gnutls_certificate_type_get2(session, GNUTLS_CTYPE_CLIENT); + } + } else { + type = DEFAULT_CERT_TYPE; + } + if (cred->get_cert_callback3) { struct gnutls_cert_retr_st info; unsigned int flags = 0; @@ -432,9 +445,9 @@ _gnutls_select_client_cert(gnutls_session_t session, if (cred->get_cert_callback3 != NULL) { - /* use a callback to get certificate + /* use a callback to get certificate */ - if (session->security_parameters.cert_type == GNUTLS_CRT_X509) { + if (session->security_parameters.client_ctype == GNUTLS_CRT_X509) { issuers_dn_length = get_issuers_num(session, data, data_size); if (issuers_dn_length < 0) { @@ -473,7 +486,7 @@ _gnutls_select_client_cert(gnutls_session_t session, } else { /* If we have no callbacks, try to guess. */ - if (session->security_parameters.cert_type == GNUTLS_CRT_X509) { + if (session->security_parameters.client_ctype == GNUTLS_CRT_X509) { result = find_x509_client_cert(session, cred, _data, _data_size, pk_algos, pk_algos_length, &indx); @@ -565,7 +578,7 @@ static int gen_x509_crt(gnutls_session_t session, gnutls_buffer_st * data) int _gnutls_gen_cert_client_crt(gnutls_session_t session, gnutls_buffer_st * data) { - switch (session->security_parameters.cert_type) { + switch (session->security_parameters.client_ctype) { case GNUTLS_CRT_X509: return gen_x509_crt(session, data); default: @@ -577,7 +590,7 @@ _gnutls_gen_cert_client_crt(gnutls_session_t session, gnutls_buffer_st * data) int _gnutls_gen_cert_server_crt(gnutls_session_t session, gnutls_buffer_st * data) { - switch (session->security_parameters.cert_type) { + switch (session->security_parameters.server_ctype) { case GNUTLS_CRT_X509: return gen_x509_crt(session, data); default: @@ -756,6 +769,7 @@ int _gnutls_proc_crt(gnutls_session_t session, uint8_t * data, size_t data_size) { int ret; gnutls_certificate_credentials_t cred; + gnutls_certificate_type_t cert_type; cred = (gnutls_certificate_credentials_t) _gnutls_get_cred(session, @@ -765,19 +779,28 @@ int _gnutls_proc_crt(gnutls_session_t session, uint8_t * data, size_t data_size) return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } - switch (session->security_parameters.cert_type) { - case GNUTLS_CRT_X509: - ret = _gnutls_proc_x509_server_crt(session, data, data_size); - break; - default: - gnutls_assert(); - return GNUTLS_E_INTERNAL_ERROR; + /* Determine what certificate type we need to process */ + if (IS_SERVER(session)) { + // We are the server therefore we process the client certificate + cert_type = gnutls_certificate_type_get2(session, GNUTLS_CTYPE_CLIENT); + } else { + // We are the client therefore we process the server certificate + cert_type = gnutls_certificate_type_get2(session, GNUTLS_CTYPE_SERVER); + } + + switch (cert_type) { + case GNUTLS_CRT_X509: + ret = _gnutls_proc_x509_server_crt(session, data, data_size); + break; + default: + gnutls_assert(); + return GNUTLS_E_INTERNAL_ERROR; } return ret; } -/* Checks if we support the given signature algorithm +/* Checks if we support the given signature algorithm * (RSA or DSA). Returns the corresponding gnutls_pk_algorithm_t * if true; */ @@ -1016,7 +1039,7 @@ _gnutls_proc_cert_client_crt_vrfy(gnutls_session_t session, ret = _gnutls_get_auth_info_pcert(&peer_cert, session->security_parameters. - cert_type, info); + client_ctype, info); if (ret < 0) { gnutls_assert(); @@ -1078,7 +1101,7 @@ _gnutls_gen_cert_server_cert_req(gnutls_session_t session, } } - if (session->security_parameters.cert_type == GNUTLS_CRT_X509 && + if (session->security_parameters.client_ctype == GNUTLS_CRT_X509 && session->internals.ignore_rdn_sequence == 0) { ret = @@ -1215,9 +1238,17 @@ static void get_server_name(gnutls_session_t session, uint8_t * name, return; } -/* Selects a signature algorithm (if required by the ciphersuite and TLS - * version), appropriate for the certificate. If none can be selected - * returns an error. +/* Checks the compatibility of the pubkey in the certificate with the + * ciphersuite and selects a signature algorithm (if required by the + * ciphersuite and TLS version) appropriate for the certificate. If none + * can be selected returns an error. + * + * IMPORTANT + * Currently this function is only called from _gnutls_server_select_cert, + * i.e. it is only called at the server. We therefore retrieve the + * negotiated server certificate type within this function. + * If, in the future, this routine is called at the client then we + * need to adapt the implementation accordingly. */ static int cert_select_sign_algorithm(gnutls_session_t session, @@ -1231,8 +1262,14 @@ int cert_select_sign_algorithm(gnutls_session_t session, unsigned key_usage; gnutls_sign_algorithm_t algo; const version_entry_st *ver = get_version(session); + gnutls_certificate_type_t ctype; - if (session->security_parameters.cert_type != cert_type) { + assert(IS_SERVER(session)); + + /* Retrieve the server certificate type */ + ctype = gnutls_certificate_type_get2(session, GNUTLS_CTYPE_SERVER); + + if (ctype != cert_type) { return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); } @@ -1297,7 +1334,7 @@ _gnutls_server_select_cert(gnutls_session_t session, const gnutls_cipher_suite_e * the ciphersuites. */ - /* If the callback which retrieves certificate has been set, + /* If the callback which retrieves the certificate has been set, * use it and leave. We make sure that this is called once. */ if (cred->get_cert_callback3) { @@ -1358,8 +1395,6 @@ _gnutls_server_select_cert(gnutls_session_t session, const gnutls_cipher_suite_e /* found */ goto finished; } - - } } } @@ -1524,6 +1559,7 @@ _gnutls_proc_dhe_signature(gnutls_session_t session, uint8_t * data, const version_entry_st *ver = get_version(session); gnutls_certificate_credentials_t cred; unsigned vflags; + gnutls_certificate_type_t cert_type; if (unlikely(info == NULL || info->ncerts == 0 || ver == NULL)) { gnutls_assert(); @@ -1565,10 +1601,11 @@ _gnutls_proc_dhe_signature(gnutls_session_t session, uint8_t * data, signature.data = data; signature.size = sigsize; + // Retrieve the negotiated certificate type + cert_type = gnutls_certificate_type_get2(session, GNUTLS_CTYPE_SERVER); + if ((ret = - _gnutls_get_auth_info_pcert(&peer_cert, - session->security_parameters.cert_type, - info)) < 0) { + _gnutls_get_auth_info_pcert(&peer_cert, cert_type, info)) < 0) { gnutls_assert(); return ret; } diff --git a/lib/auth/rsa.c b/lib/auth/rsa.c index f2e36bbe22..6afc91ae67 100644 --- a/lib/auth/rsa.c +++ b/lib/auth/rsa.c @@ -82,6 +82,18 @@ int check_key_usage_for_enc(gnutls_session_t session, unsigned key_usage) } /* This function reads the RSA parameters from peer's certificate; + * + * IMPORTANT: + * Currently this function gets only called on the client side + * during generation of the client kx msg. This function + * retrieves the RSA params from the peer's certificate. That is in + * this case the server's certificate. As of GNUTLS version 3.6.4 it is + * possible to negotiate different certificate types for client and + * server. Therefore the correct cert type needs to be retrieved to be + * used for the _gnutls_get_auth_info_pcert call. If this + * function is to be called on the server side in the future, extra + * checks need to be build in order to retrieve te correct + * certificate type. */ int _gnutls_get_public_rsa_params(gnutls_session_t session, @@ -91,6 +103,9 @@ _gnutls_get_public_rsa_params(gnutls_session_t session, cert_auth_info_t info; unsigned key_usage; gnutls_pcert_st peer_cert; + gnutls_certificate_type_t cert_type; + + assert(!IS_SERVER(session)); /* normal non export case */ @@ -101,10 +116,10 @@ _gnutls_get_public_rsa_params(gnutls_session_t session, return GNUTLS_E_INTERNAL_ERROR; } - ret = - _gnutls_get_auth_info_pcert(&peer_cert, - session->security_parameters. - cert_type, info); + // Get the negotiated server certificate type + cert_type = gnutls_certificate_type_get2(session, GNUTLS_CTYPE_SERVER); + + ret = _gnutls_get_auth_info_pcert(&peer_cert, cert_type, info); if (ret < 0) { gnutls_assert(); diff --git a/lib/auth/srp_rsa.c b/lib/auth/srp_rsa.c index 2101f70a0f..06c6971d80 100644 --- a/lib/auth/srp_rsa.c +++ b/lib/auth/srp_rsa.c @@ -241,8 +241,7 @@ proc_srp_cert_server_kx(gnutls_session_t session, uint8_t * data, ret = _gnutls_get_auth_info_pcert(&peer_cert, - session->security_parameters. - cert_type, info); + session->security_parameters.server_ctype, info); if (ret < 0) { gnutls_assert(); |