#ifndef GLOBUS_DONT_DOCUMENT_INTERNAL /** * @file globus_gsi_credential.c * @author Sam Lang, Sam Meder * * $RCSfile: globus_gsi_credential.c,v $ * $Revision: 1.26.4.1 $ * $Date: 2003/06/21 14:29:35 $ */ #endif #include "globus_i_gsi_credential.h" #include "globus_gsi_system_config.h" #include "globus_gsi_cert_utils.h" #include "version.h" #include #include #include #include #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL static int globus_l_gsi_credential_activate(void); static int globus_l_gsi_credential_deactivate(void); int globus_i_gsi_cred_debug_level = 0; FILE * globus_i_gsi_cred_debug_fstream = NULL; /** * Module descriptor static initializer. */ globus_module_descriptor_t globus_i_gsi_credential_module = { "globus_credential", globus_l_gsi_credential_activate, globus_l_gsi_credential_deactivate, GLOBUS_NULL, GLOBUS_NULL, &local_version }; /** * Module activation */ static int globus_l_gsi_credential_activate(void) { int result = (int) GLOBUS_SUCCESS; char * tmp_string; static char * _function_name_ = "globus_l_gsi_credential_activate"; tmp_string = globus_module_getenv("GLOBUS_GSI_CRED_DEBUG_LEVEL"); if(tmp_string != GLOBUS_NULL) { globus_i_gsi_cred_debug_level = atoi(tmp_string); if(globus_i_gsi_cred_debug_level < 0) { globus_i_gsi_cred_debug_level = 0; } } tmp_string = globus_module_getenv("GLOBUS_GSI_CRED_DEBUG_FILE"); if(tmp_string != GLOBUS_NULL) { globus_i_gsi_cred_debug_fstream = fopen(tmp_string, "a"); if(globus_i_gsi_cred_debug_fstream == NULL) { result = (int) GLOBUS_FAILURE; goto exit; } } else { /* if the env. var. isn't set, use stderr */ globus_i_gsi_cred_debug_fstream = stderr; } GLOBUS_I_GSI_CRED_DEBUG_ENTER; result = globus_module_activate(GLOBUS_COMMON_MODULE); if(result != GLOBUS_SUCCESS) { goto exit; } result = globus_module_activate(GLOBUS_GSI_SYSCONFIG_MODULE); if(result != GLOBUS_SUCCESS) { goto exit; } result = globus_module_activate(GLOBUS_GSI_CALLBACK_MODULE); if(result != GLOBUS_SUCCESS) { goto exit; } OpenSSL_add_all_algorithms(); GLOBUS_I_GSI_CRED_DEBUG_EXIT; exit: return result; } /** * Module deactivation * */ static int globus_l_gsi_credential_deactivate(void) { int result = (int) GLOBUS_SUCCESS; static char * _function_name_ = "globus_l_gsi_credential_deactivate"; GLOBUS_I_GSI_CRED_DEBUG_ENTER; EVP_cleanup(); globus_module_deactivate(GLOBUS_GSI_CALLBACK_MODULE); globus_module_deactivate(GLOBUS_GSI_SYSCONFIG_MODULE); globus_module_deactivate(GLOBUS_COMMON_MODULE); GLOBUS_I_GSI_CRED_DEBUG_EXIT; if(globus_i_gsi_cred_debug_fstream != stderr) { fclose(globus_i_gsi_cred_debug_fstream); } return result; } /* globus_l_gsi_credential_deactivate() */ static globus_result_t globus_l_gsi_cred_get_service( X509_NAME * subject, char ** service); static globus_result_t globus_l_gsi_cred_subject_cmp( X509_NAME * actual_subject, X509_NAME * desired_subject); #endif /** * Read Credential * @ingroup globus_gsi_cred_operation */ /* @{ */ /** * Read a Credential from a filesystem location. The credential * to read will be determined by the search order of the handle * attributes. * NOTE: This function always searches for the desired credential. * If you don't want to perform a search, then don't use this * function. The search goes in the order of the handle * attributes' search order. * * @param handle * The credential handle to set. This credential handle * should already be initialized using globus_gsi_cred_handle_init. * @param desired_subject * The subject to check for when reading in a credential. The * desired_subject should be either a exact match of the read cert's * subject or should just contain the /CN entry. If null, the * credential read in is the first match based on the system * configuration (paths and environment variables) * @return * GLOBUS_SUCCESS if no errors occured, otherwise, an error object * identifier is returned. * * @see globus_gsi_cred_read_proxy * @see globus_gsi_cred_read_cert_and_key */ globus_result_t globus_gsi_cred_read( globus_gsi_cred_handle_t handle, X509_NAME * desired_subject) { time_t lifetime = 0; int index = 0; int result_index = 0; int result_count = 0; globus_result_t result = GLOBUS_SUCCESS; globus_result_t results[4]; X509_NAME * found_subject = NULL; char * cert = NULL; char * key = NULL; char * proxy = NULL; char * service_name = NULL; static char * _function_name_ = "globus_gsi_cred_read"; GLOBUS_I_GSI_CRED_DEBUG_ENTER; for(result_index = 0; result_index < 4; ++result_index) { results[result_index] = GLOBUS_SUCCESS; } result_index = 0; if(handle == NULL) { GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Null handle passed to function: %s", _function_name_)); goto exit; } /* search for the credential of choice */ do { switch(handle->attrs->search_order[index]) { case GLOBUS_PROXY: results[result_index] = GLOBUS_GSI_SYSCONFIG_GET_PROXY_FILENAME( &proxy, GLOBUS_PROXY_FILE_INPUT); if(results[result_index] != GLOBUS_SUCCESS) { proxy = NULL; GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_PROXY_CRED); break; } results[result_index] = globus_gsi_cred_read_proxy(handle, proxy); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_PROXY_CRED); goto exit; } if(desired_subject != NULL) { results[result_index] = globus_gsi_cred_get_X509_subject_name( handle, &found_subject); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_PROXY_CRED); goto exit; } results[result_index] = globus_l_gsi_cred_subject_cmp(found_subject, desired_subject); X509_NAME_free(found_subject); found_subject = NULL; if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_PROXY_CRED); goto exit; } } results[result_index] = globus_gsi_cred_get_lifetime( handle, &lifetime); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_WITH_CRED); goto exit; } if(lifetime <= 0) { char * subject = NULL; subject = X509_NAME_oneline( X509_get_subject_name(handle->cert), NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_WITH_CRED, ("The proxy credential: %s\n with subject: %s\n" " expired %d minutes ago.\n", proxy, subject, (-lifetime)/60)); free(subject); goto exit; } goto exit; case GLOBUS_USER: results[result_index] = GLOBUS_GSI_SYSCONFIG_GET_USER_CERT_FILENAME(&cert, &key); if(results[result_index] != GLOBUS_SUCCESS) { cert = NULL; key = NULL; GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_CRED); break; } results[result_index] = globus_gsi_cred_read_cert(handle, cert); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_CRED); goto exit; } results[result_index] = globus_gsi_cred_read_key( handle, key, globus_i_gsi_cred_password_callback_no_prompt); if(results[result_index] != GLOBUS_SUCCESS) { globus_object_t * error_obj; error_obj = globus_error_get(results[result_index]); if(globus_error_get_type(error_obj) == GLOBUS_GSI_CRED_ERROR_KEY_IS_PASS_PROTECTED) { results[result_index] = globus_error_put(error_obj); GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_CRED); break; } results[result_index] = globus_error_put(error_obj); GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_CRED); goto exit; } results[result_index] = globus_i_gsi_cred_goodtill( handle, &(handle->goodtill)); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_CRED); goto exit; } if(desired_subject != NULL) { results[result_index] = globus_gsi_cred_get_X509_subject_name( handle, &found_subject); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_CRED); goto exit; } results[result_index] = globus_l_gsi_cred_subject_cmp( found_subject, desired_subject); X509_NAME_free(found_subject); found_subject = NULL; if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_CRED); goto exit; } } results[result_index] = globus_gsi_cred_get_lifetime( handle, &lifetime); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_WITH_CRED); goto exit; } if(lifetime <= 0) { char * subject = NULL; subject = X509_NAME_oneline( X509_get_subject_name(handle->cert), NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_WITH_CRED, ("The user credential: %s\n with subject: %s\n" " has expired %d minutes ago.\n", cert, subject, (-lifetime)/60)); free(subject); goto exit; } goto exit; case GLOBUS_HOST: results[result_index] = GLOBUS_GSI_SYSCONFIG_GET_HOST_CERT_FILENAME(&cert, &key); if(results[result_index] != GLOBUS_SUCCESS) { cert = NULL; key = NULL; GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_HOST_CRED); break; } results[result_index] = globus_gsi_cred_read_cert(handle, cert); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_HOST_CRED); goto exit; } results[result_index] = globus_gsi_cred_read_key( handle, key, globus_i_gsi_cred_password_callback_no_prompt); if(results[result_index] != GLOBUS_SUCCESS) { globus_object_t * error_obj; error_obj = globus_error_get(results[result_index]); if(globus_error_get_type(error_obj) == GLOBUS_GSI_CRED_ERROR_KEY_IS_PASS_PROTECTED) { results[result_index] = globus_error_put(error_obj); GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_HOST_CRED); break; } results[result_index] = globus_error_put(error_obj); GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_HOST_CRED); goto exit; } results[result_index] = globus_i_gsi_cred_goodtill( handle, &(handle->goodtill)); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_HOST_CRED); goto exit; } if(desired_subject != NULL) { results[result_index] = globus_gsi_cred_get_X509_subject_name( handle, &found_subject); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_HOST_CRED); goto exit; } results[result_index] = globus_l_gsi_cred_subject_cmp(found_subject, desired_subject); X509_NAME_free(found_subject); found_subject = NULL; if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_HOST_CRED); goto exit; } } results[result_index] = globus_gsi_cred_get_lifetime( handle, &lifetime); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_WITH_CRED); goto exit; } if(lifetime <= 0) { char * subject = NULL; subject = X509_NAME_oneline( X509_get_subject_name(handle->cert), NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_WITH_CRED, ("The host credential: %s\n with subject: %s\n " "has expired %d minutes ago.\n", cert, subject, (-lifetime)/60)); free(subject); goto exit; } goto exit; case GLOBUS_SERVICE: if(desired_subject != NULL) { results[result_index] = globus_l_gsi_cred_get_service(desired_subject, &service_name); if(results[result_index] != GLOBUS_SUCCESS) { service_name = NULL; GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_SERVICE_CRED); break; } results[result_index] = GLOBUS_GSI_SYSCONFIG_GET_SERVICE_CERT_FILENAME( service_name, &cert, &key); if(results[result_index] != GLOBUS_SUCCESS) { cert = NULL; key = NULL; GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_SERVICE_CRED); break; } results[result_index] = globus_gsi_cred_read_cert(handle, cert); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_SERVICE_CRED); goto exit; } results[result_index] = globus_gsi_cred_read_key( handle, key, globus_i_gsi_cred_password_callback_no_prompt); if(results[result_index] != GLOBUS_SUCCESS) { globus_object_t * error_obj; error_obj = globus_error_get(results[result_index]); if(globus_error_get_type(error_obj) == GLOBUS_GSI_CRED_ERROR_KEY_IS_PASS_PROTECTED) { results[result_index] = globus_error_put(error_obj); GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_SERVICE_CRED); break; } results[result_index] = globus_error_put(error_obj); GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_SERVICE_CRED); goto exit; } results[result_index] = globus_i_gsi_cred_goodtill( handle, &(handle->goodtill)); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_WITH_CRED); goto exit; } if(desired_subject != NULL) { results[result_index] = globus_gsi_cred_get_X509_subject_name( handle, &found_subject); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_SERVICE_CRED); goto exit; } results[result_index] = globus_l_gsi_cred_subject_cmp(found_subject, desired_subject); X509_NAME_free(found_subject); found_subject = NULL; if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_READING_SERVICE_CRED); break; } } results[result_index] = globus_gsi_cred_get_lifetime( handle, &lifetime); if(results[result_index] != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_WITH_CRED); goto exit; } if(lifetime <= 0) { char * subject = NULL; subject = X509_NAME_oneline( X509_get_subject_name(handle->cert), NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_WITH_CRED, ("The service credential: %s\n with subject:\n%s\n" " has expired %d minutes ago.\n", cert, subject, (-lifetime)/60)); free(subject); goto exit; } goto exit; } else { result_index--; break; } case GLOBUS_SO_END: result_count = result_index; for(result_index = (result_count - 2); result_index >= 0; --result_index) { results[result_index] = globus_i_gsi_cred_error_join_chains_result( results[result_index], results[result_index + 1]); results[result_index + 1] = GLOBUS_SUCCESS; } result_index = 0; GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( results[result_index], GLOBUS_GSI_CRED_ERROR_NO_CRED_FOUND); goto exit; } if(proxy) { free(proxy); proxy = NULL; } if(cert) { free(cert); cert = NULL; } if(key) { free(key); key = NULL; } if(service_name) { free(service_name); service_name = NULL; } result_index++; } while(++index); exit: result = results[result_index]; for(index = 0; index < result_index; ++index) { globus_object_t * result_obj; if(results[index] != GLOBUS_SUCCESS) { result_obj = globus_error_get(results[index]); globus_object_free(result_obj); } } if(proxy) { free(proxy); } if(cert) { free(cert); } if(key) { free(key); } if(service_name) { free(service_name); } GLOBUS_I_GSI_CRED_DEBUG_EXIT; return result; } /* @} */ /** * Read Proxy * @ingroup globus_gsi_cred_operation */ /* @{ */ /** * Read a proxy from a PEM file. Assumes that the handle * attributes contain the filename of the proxy to read * * @param handle * The credential handle to set based on the proxy * parameters read from the file * @return * GLOBUS_SUCCESS or an error object identifier */ globus_result_t globus_gsi_cred_read_proxy( globus_gsi_cred_handle_t handle, char * proxy_filename) { BIO * proxy_bio = NULL; globus_result_t result; static char * _function_name_ = "globus_gsi_cred_read_proxy"; GLOBUS_I_GSI_CRED_DEBUG_ENTER; if(handle == NULL) { GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_PROXY_CRED, ("NULL handle passed to function: %s", _function_name_)); goto exit; } /* create the bio to read the proxy in from */ if((proxy_bio = BIO_new_file(proxy_filename, "r")) == NULL) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_PROXY_CRED, ("Can't open proxy file: %s for reading", proxy_filename)); goto exit; } result = globus_gsi_cred_read_proxy_bio(handle, proxy_bio); if(result != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_PROXY_CRED); goto exit; } exit: if(proxy_bio) { BIO_free(proxy_bio); } GLOBUS_I_GSI_CRED_DEBUG_EXIT; return result; } /* @} */ /** * Read Credential * @ingroup globus_gsi_cred_operations */ /* @{ */ /** * Read a Credential from a BIO stream and set the * credential handle to represent the read credential. * The values read from the stream, in order, will be * the signed certificate, the private key, * and the certificate chain * * @param handle * The credential handle to set. The credential * should not be initialized (i.e. NULL). * @param bio * The stream to read the credential from * @return * GLOBUS_SUCCESS unless an error occurred, in which * case an error object is returned */ globus_result_t globus_gsi_cred_read_proxy_bio( globus_gsi_cred_handle_t handle, BIO * bio) { int i = 0; globus_result_t result; X509 * tmp_cert = NULL; static char * _function_name_ = "globus_gsi_cred_read_proxy_bio"; GLOBUS_I_GSI_CRED_DEBUG_ENTER; if(handle == NULL) { GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_PROXY_CRED, ("Null handle passed to function: %s", _function_name_)); goto exit; } if(bio == NULL) { GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_PROXY_CRED, ("Null bio variable passed to function: %s", _function_name_)); goto exit; } /* read in the certificate of the handle */ if(handle->cert != NULL) { X509_free(handle->cert); handle->cert = NULL; } if(!PEM_read_bio_X509(bio, & handle->cert, NULL, NULL)) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_PROXY_CRED, ("Couldn't read X509 proxy cert from bio")); goto exit; } /* read in the private key of the handle */ if(handle->key != NULL) { EVP_PKEY_free(handle->key); handle->key = NULL; } handle->key = PEM_read_bio_PrivateKey( bio, NULL, (int (*) ()) globus_i_gsi_cred_password_callback_no_prompt, NULL); if(!handle->key) { if(ERR_GET_REASON(ERR_peek_error()) == PEM_R_BAD_PASSWORD_READ) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_KEY_IS_PASS_PROTECTED, ("The proxy certificate's private key " "is password protected.\n")); goto exit; } GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_PROXY_CRED, ("Couldn't read proxy's private key from bio")); goto exit; } /* read in the certificate chain of the handle */ if(handle->cert_chain != NULL) { sk_X509_pop_free(handle->cert_chain, X509_free); handle->cert_chain = NULL; } if((handle->cert_chain = sk_X509_new_null()) == NULL) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_PROXY_CRED, ("Can't initialize cert chain")); goto exit; } while(!BIO_eof(bio)) { tmp_cert = NULL; if(!PEM_read_bio_X509(bio, &tmp_cert, NULL, NULL)) { /* appears to continue reading after EOF and * so an error occurs here */ break; } if(!sk_X509_insert(handle->cert_chain, tmp_cert, i)) { X509_free(tmp_cert); GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_PROXY_CRED, ("Error adding certificate to proxy's cert chain")); goto exit; } ++i; } result = globus_i_gsi_cred_goodtill(handle, &(handle->goodtill)); if(result != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( result, GLOBUS_GSI_CRED_ERROR_WITH_CRED); goto exit; } result = GLOBUS_SUCCESS; exit: GLOBUS_I_GSI_CRED_DEBUG_EXIT; return result; } /* @} */ /** * Read Key * @ingroup globus_gsi_cred_operations */ /* @{ */ /** * Read a key from a the file locations specified in the * handle attributes. Cert and key should be in PEM format. * * @param handle * the handle to set based on the key that is read * @param key_filename * the filename of the key to read * @param pw_cb * the callback for the password to read in the key * @return * GLOBUS_SUCCESS or an error object identifier */ globus_result_t globus_gsi_cred_read_key( globus_gsi_cred_handle_t handle, char * key_filename, int (*pw_cb)()) { BIO * key_bio = NULL; globus_result_t result; static char * _function_name_ = "globus_gsi_cred_read_key"; GLOBUS_I_GSI_CRED_DEBUG_ENTER; if(handle == NULL) { GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("NULL handle passed to function: %s", _function_name_)); goto exit; } if(!(key_bio = BIO_new_file(key_filename, "r"))) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Can't open bio stream for " "key file: %s for reading", key_filename)); goto exit; } /* read in the key */ if(handle->key != NULL) { EVP_PKEY_free(handle->key); handle->key = NULL; } if(!PEM_read_bio_PrivateKey(key_bio, & handle->key, pw_cb, NULL)) { if(ERR_GET_REASON(ERR_peek_error()) == PEM_R_BAD_PASSWORD_READ) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_KEY_IS_PASS_PROTECTED, ("GSI does not currently support password protected " "private keys.")); goto exit; } GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Can't read credential's private key from PEM")); goto exit; } result = GLOBUS_SUCCESS; exit: if(key_bio) { BIO_free(key_bio); } GLOBUS_I_GSI_CRED_DEBUG_EXIT; return result; } /* @} */ /** * Read Cert * @ingroup globus_gsi_cred_operations */ /* @{ */ /** * Read a cert from a the file locations specified in the * handle attributes. Cert should be in PEM format. * * @param handle * the handle to set based on the certificate that is read * @param cert_filename * the filename of the certificate to read * @return * GLOBUS_SUCCESS or an error object identifier */ globus_result_t globus_gsi_cred_read_cert( globus_gsi_cred_handle_t handle, char * cert_filename) { BIO * cert_bio = NULL; globus_result_t result; int i = 0; static char * _function_name_ = "globus_gsi_cred_read_cert"; GLOBUS_I_GSI_CRED_DEBUG_ENTER; if(handle == NULL) { GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("NULL handle passed to function: %s", _function_name_)); goto exit; } if(!(cert_bio = BIO_new_file(cert_filename, "r"))) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Can't open cert file: %s for reading", cert_filename)); goto exit; } /* read in the cert */ if(handle->cert != NULL) { X509_free(handle->cert); handle->cert = NULL; } if(!PEM_read_bio_X509(cert_bio, &handle->cert, NULL, NULL)) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Can't read credential cert from bio stream")); goto exit; } if(handle->cert_chain != NULL) { sk_X509_pop_free(handle->cert_chain, X509_free); } if((handle->cert_chain = sk_X509_new_null()) == NULL) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Can't initialize cert chain\n")); goto exit; } while(!BIO_eof(cert_bio)) { X509 * tmp_cert = NULL; if(!PEM_read_bio_X509(cert_bio, &tmp_cert, NULL, NULL)) { ERR_clear_error(); break; } if(!sk_X509_insert(handle->cert_chain, tmp_cert, i)) { X509_free(tmp_cert); GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Error adding cert: %s\n to issuer cert chain\n", X509_NAME_oneline(X509_get_subject_name(tmp_cert), 0, 0))); goto exit; } ++i; } result = globus_i_gsi_cred_goodtill(handle, &(handle->goodtill)); if(result != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( result, GLOBUS_GSI_CRED_ERROR_WITH_CRED); goto exit; } result = GLOBUS_SUCCESS; exit: if(cert_bio) { BIO_free(cert_bio); } GLOBUS_I_GSI_CRED_DEBUG_EXIT; return result; } /* @} */ globus_result_t globus_gsi_cred_read_pkcs12( globus_gsi_cred_handle_t handle, char * pkcs12_filename) { globus_result_t result = GLOBUS_SUCCESS; char password[100]; STACK_OF(X509) * pkcs12_certs = NULL; PKCS12 * pkcs12 = NULL; PKCS12_SAFEBAG * bag = NULL; STACK_OF(PKCS12_SAFEBAG) * pkcs12_safebags = NULL; PKCS7 * pkcs7 = NULL; STACK_OF(PKCS7) * auth_safes = NULL; PKCS8_PRIV_KEY_INFO * pkcs8 = NULL; BIO * pkcs12_bio = NULL; int i, j, bag_NID; static char * _function_name_ = "globus_gsi_cred_read_pkcs12"; GLOBUS_I_GSI_CRED_DEBUG_ENTER; if(handle == NULL) { GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("NULL handle passed to function: %s", _function_name_)); goto exit; } pkcs12_bio = BIO_new_file(pkcs12_filename, "r"); if(!pkcs12_bio) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Couldn't create BIO for file: %s", pkcs12_filename)); goto exit; } d2i_PKCS12_bio(pkcs12_bio, &pkcs12); if(!pkcs12) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Couldn't read in PKCS12 credential from BIO")); goto exit; } EVP_read_pw_string(password, 100, NULL, 0); if(!PKCS12_verify_mac(pkcs12, password, -1)) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Couldn't verify the PKCS12 MAC using the specified password")); goto exit; } auth_safes = M_PKCS12_unpack_authsafes(pkcs12); if(!auth_safes) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Couldn't dump cert and key from PKCS12 credential")); goto exit; } pkcs12_certs = sk_X509_new_null(); for (i = 0; i < sk_PKCS7_num(auth_safes); i++) { pkcs7 = sk_PKCS7_value(auth_safes, i); bag_NID = OBJ_obj2nid(pkcs7->type); if(bag_NID == NID_pkcs7_data) { pkcs12_safebags = M_PKCS12_unpack_p7data(pkcs7); } else if(bag_NID == NID_pkcs7_encrypted) { pkcs12_safebags = M_PKCS12_unpack_p7encdata (pkcs7, password, -1); } else { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Couldn't get NID from PKCS7 that matched " "{NID_pkcs7_data, NID_pkcs7_encrypted}")); goto exit; } if(!pkcs12_safebags) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Couldn't unpack the PKCS12 safebags from " "the PKCS7 credential")); goto exit; } for (j = 0; j < sk_PKCS12_SAFEBAG_num(pkcs12_safebags); j++) { bag = sk_PKCS12_SAFEBAG_value(pkcs12_safebags, j); if(M_PKCS12_bag_type(bag) == NID_certBag && M_PKCS12_cert_bag_type(bag) == NID_x509Certificate) { sk_X509_push(pkcs12_certs, M_PKCS12_certbag2x509(bag)); } else if(M_PKCS12_bag_type(bag) == NID_keyBag && handle->key == NULL) { pkcs8 = bag->value.keybag; handle->key = EVP_PKCS82PKEY(pkcs8); if (!handle->key) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Couldn't get the private key from the" "PKCS12 credential")); goto exit; } } else if(M_PKCS12_bag_type(bag) == NID_pkcs8ShroudedKeyBag && handle->key == NULL) { pkcs8 = M_PKCS12_decrypt_skey(bag, password, strlen(password)); if(!pkcs8) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Couldn't get PKCS8 key from PKCS12 credential")); goto exit; } handle->key = EVP_PKCS82PKEY(pkcs8); if (!handle->key) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Couldn't get private key from PKCS12 credential")); goto exit; } PKCS8_PRIV_KEY_INFO_free(pkcs8); } } } if(!handle->key) { GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Couldn't read private key from PKCS12 credential " "for unknown reason")); goto exit; } for(i = 0 ; i < sk_X509_num(pkcs12_certs); i++) { handle->cert = sk_X509_pop(pkcs12_certs); if(X509_check_private_key(handle->cert, handle->key)) { sk_X509_pop_free(pkcs12_certs, X509_free); pkcs12_certs = NULL; break; } else { X509_free(handle->cert); handle->cert = NULL; } } if(!handle->cert) { GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_READING_CRED, ("Couldn't read X509 certificate from PKCS12 credential")); goto exit; } result = globus_i_gsi_cred_goodtill(handle, &(handle->goodtill)); if(result != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( result, GLOBUS_GSI_CRED_ERROR_WITH_CRED); goto exit; } exit: if(pkcs12_bio) { BIO_free(pkcs12_bio); } if(pkcs12) { PKCS12_free(pkcs12); } if(pkcs12_certs) { sk_X509_pop_free(pkcs12_certs, X509_free); } GLOBUS_I_GSI_CRED_DEBUG_EXIT; return result; } /** * Write Credential * @ingroup globus_gsi_cred_operations */ /* @{ */ /** * Write out a credential to a BIO. The credential parameters written, * in order, are the signed certificate, the RSA private key, * and the certificate chain (a set of X509 certificates). * the credential is written out in PEM format. * * @param handle * The credential to write out * @param bio * The BIO stream to write out to * @return * GLOBUS_SUCCESS unless an error occurred, in which * case an error object ID is returned. */ globus_result_t globus_gsi_cred_write( globus_gsi_cred_handle_t handle, BIO * bio) { int i; globus_result_t result = GLOBUS_SUCCESS; static char * _function_name_ = "globus_gsi_cred_write"; GLOBUS_I_GSI_CRED_DEBUG_ENTER; if(handle == NULL) { GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_WRITING_CRED, ("NULL handle passed to function: %s", _function_name_)); goto error_exit; } if(bio == NULL) { GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_WRITING_CRED, ("NULL bio variable passed to function: %s", _function_name_)); goto error_exit; } if(!PEM_write_bio_X509(bio, handle->cert)) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_WRITING_CRED, ("Can't write PEM formatted X509 cert to BIO stream")); goto error_exit; } if(!PEM_ASN1_write_bio(i2d_PrivateKey, PEM_STRING_RSA, bio, (char *) handle->key, NULL, NULL, 0, NULL, NULL)) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_WRITING_CRED, ("Can't write PEM formatted private key to BIO stream")); goto error_exit; } for(i = 0; i < sk_X509_num(handle->cert_chain); ++i) { if(!PEM_write_bio_X509(bio, sk_X509_value(handle->cert_chain, i))) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_WRITING_CRED, ("Can't write PEM formatted X509 cert" " in cert chain to BIO stream")); goto error_exit; } } error_exit: GLOBUS_I_GSI_CRED_DEBUG_EXIT; return result; } /* @} */ /* Utility function that will write the credential to the standard * proxy file. */ globus_result_t globus_gsi_cred_write_proxy( globus_gsi_cred_handle_t handle, char * proxy_filename) { globus_result_t result = GLOBUS_SUCCESS; BIO * proxy_bio = NULL; static char * _function_name_ = "globus_gsi_cred_write_proxy"; GLOBUS_I_GSI_CRED_DEBUG_ENTER; if(handle == NULL) { GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_WRITING_PROXY_CRED, ("NULL handle passed to function: %s", _function_name_)); goto exit; } if(!(proxy_bio = BIO_new_file(proxy_filename, "w"))) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_WRITING_PROXY_CRED, ("Can't open bio stream for writing to file: %s", proxy_filename)); goto exit; } result = GLOBUS_GSI_SYSCONFIG_SET_KEY_PERMISSIONS(proxy_filename); if(result != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( result, GLOBUS_GSI_CRED_ERROR_WRITING_PROXY_CRED); goto exit; } result = globus_gsi_cred_write(handle, proxy_bio); if(result != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( result, GLOBUS_GSI_CRED_ERROR_WRITING_PROXY_CRED); goto close_proxy_bio; } if(proxy_bio) { BIO_free(proxy_bio); proxy_bio = NULL; } goto exit; close_proxy_bio: if(proxy_bio != NULL) { BIO_free(proxy_bio); } exit: GLOBUS_I_GSI_CRED_DEBUG_EXIT; return result; } globus_result_t globus_gsi_cred_get_cert_type( globus_gsi_cred_handle_t handle, globus_gsi_cert_utils_cert_type_t * type) { globus_result_t result; static char * _function_name_ = "globus_gsi_cred_check_proxy"; GLOBUS_I_GSI_CRED_DEBUG_ENTER; result = globus_gsi_cert_utils_get_cert_type(handle->cert, type); if(result != GLOBUS_SUCCESS) { GLOBUS_GSI_CRED_ERROR_CHAIN_RESULT( result, GLOBUS_GSI_CRED_ERROR_WITH_CRED_CERT); } GLOBUS_I_GSI_CRED_DEBUG_EXIT; return result; } #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL /** * Get PROXYCERTINFO Struct * @ingroup globus_i_gsi_cred */ /* @{ */ /** * Get the PROXYCERTINFO struct from the X509 struct. * The PROXYCERTINFO struct that gets set must be freed * with a call to PROXYCERTINFO_free. * * @param cert * The X509 struct containing the PROXYCERTINFO struct * in its extensions * @param proxycertinfo * The resulting PROXYCERTINFO struct. This variable * should be freed with a call to PROXYCERTINFO_free when * no longer in use. It will have a value of NULL if no * proxycertinfo extension exists in the X509 certificate * @return * GLOBUS_SUCCESS (even if no proxycertinfo extension was found) * or an globus error object id if an error occurred */ globus_result_t globus_i_gsi_cred_get_proxycertinfo( X509 * cert, PROXYCERTINFO ** proxycertinfo) { globus_result_t result = GLOBUS_SUCCESS; int pci_NID; X509_EXTENSION * pci_extension = NULL; ASN1_OCTET_STRING * ext_data = NULL; int extension_loc; static char * _function_name_ = "globus_i_gsi_cred_get_proxycertinfo"; GLOBUS_I_GSI_CRED_DEBUG_ENTER; *proxycertinfo = NULL; pci_NID = OBJ_sn2nid(PROXYCERTINFO_SN); if(pci_NID == NID_undef) { GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_WITH_CRED, ("Couldn't get numeric ID for PROXYCERTINFO extension")); goto exit; } if(cert == NULL) { GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_WITH_CRED, ("NULL X509 cert parameter passed to function: %s", _function_name_)); goto exit; } if((extension_loc = X509_get_ext_by_NID( cert, pci_NID, -1)) == -1) { /* no proxycertinfo extension found in cert */ result = GLOBUS_SUCCESS; goto exit; } if((pci_extension = X509_get_ext(cert, extension_loc)) == NULL) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_WITH_CRED, ("Can't find PROXYCERTINFO extension in X509 cert at " "expected location: %d in extension stack", extension_loc)); goto exit; } if((ext_data = X509_EXTENSION_get_data(pci_extension)) == NULL) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_WITH_CRED, ("Can't get DER encoded extension " "data from X509 extension object")); goto exit; } if((ext_data = ASN1_OCTET_STRING_dup(ext_data)) == NULL) { GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_WITH_CRED, ("Failed to copy extension data.")); goto exit; } if((d2i_PROXYCERTINFO( proxycertinfo, &ext_data->data, ext_data->length)) == NULL) { ASN1_OCTET_STRING_free(ext_data); *proxycertinfo = NULL; GLOBUS_GSI_CRED_OPENSSL_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_WITH_CRED, ("Can't convert DER encoded PROXYCERTINFO " "extension to internal form")); goto exit; } exit: GLOBUS_I_GSI_CRED_DEBUG_EXIT; return result; } /* @} */ int globus_i_gsi_cred_password_callback_no_prompt( char * buffer, int size, int w) { static char * _function_name_ = "globus_i_gsi_cred_password_callback_no_prompt"; GLOBUS_I_GSI_CRED_DEBUG_ENTER; /* current gsi implementation does not allow for a password * encrypted certificate to be used for authentication */ GLOBUS_I_GSI_CRED_DEBUG_EXIT; return -1; } static globus_result_t globus_l_gsi_cred_subject_cmp( X509_NAME * actual_subject, X509_NAME * desired_subject) { int cn_index; char * desired_cn = NULL; char * actual_cn = NULL; char * desired_service; char * actual_service; char * desired_host; char * actual_host; char * desired_str = NULL; char * actual_str = NULL; globus_result_t result = GLOBUS_SUCCESS; int length; static char * _function_name_ = "globus_l_gsi_cred_subject_cmp"; GLOBUS_I_GSI_CRED_DEBUG_ENTER; /* if desired subject is NULL return success */ if(!desired_subject) { goto exit; } /* check for single /CN entry */ if(X509_NAME_entry_count(desired_subject) == 1) { /* make sure we actually got a common name */ cn_index = X509_NAME_get_index_by_NID(desired_subject, NID_commonName, -1); if(cn_index < 0) { desired_str = X509_NAME_oneline(desired_subject, NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_SUBJECT_CMP, ("No Common Name found in desired subject %s.\n", desired_str)); goto exit; } /* find /CN entry in actual subject */ cn_index = X509_NAME_get_index_by_NID(actual_subject, NID_commonName, -1); /* error if no common name was found */ if(cn_index < 0) { actual_str = X509_NAME_oneline(actual_subject, NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_SUBJECT_CMP, ("No Common Name found in subject %s.\n", actual_str)); goto exit; } /* check that actual subject only has one CN entry */ if(X509_NAME_get_index_by_NID(actual_subject, NID_commonName, cn_index) != -1) { actual_str = X509_NAME_oneline(actual_subject, NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_SUBJECT_CMP, ("More than one Common Name found in subject %s.\n", actual_str)); goto exit; } /* get CN text for desired subject */ length = X509_NAME_get_text_by_NID(desired_subject, NID_commonName, NULL, 1024) + 1; desired_cn = malloc(length); X509_NAME_get_text_by_NID(desired_subject, NID_commonName, desired_cn, length); /* get CN text for actual subject */ length = X509_NAME_get_text_by_NID(actual_subject, NID_commonName, NULL, 1024) + 1; actual_cn = malloc(length); X509_NAME_get_text_by_NID(actual_subject, NID_commonName, actual_cn, length); /* straight comparison */ if(!strcmp(desired_cn,actual_cn)) { goto exit; } actual_host = strchr(actual_cn,'/'); if(actual_host == NULL) { actual_host = actual_cn; actual_service = NULL; } else { *actual_host = '\0'; actual_service = actual_cn; actual_host++; } desired_host = strchr(desired_cn,'/'); if(desired_host == NULL) { desired_host = desired_cn; desired_service = NULL; } else { *desired_host = '\0'; desired_service = desired_cn; desired_host++; } if(desired_service == NULL && actual_service == NULL) { actual_str = X509_NAME_oneline(actual_subject, NULL, 0); desired_str = X509_NAME_oneline(desired_subject, NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_SUBJECT_CMP, ("Desired subject and actual subject of certificate" " do not match.\n" " Desired subject: %s\n" " Actual subject: %s\n", desired_str, actual_str)); goto exit; } else if(desired_service == NULL) { if(strcmp("host",actual_service)) { actual_str = X509_NAME_oneline(actual_subject, NULL, 0); desired_str = X509_NAME_oneline(desired_subject, NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_SUBJECT_CMP, ("Desired subject and actual subject of certificate" " do not match.\n" " Desired subject: %s\n" " Actual subject: %s\n", desired_str, actual_str)); } goto exit; } else if(actual_service == NULL) { if(strcmp("host",desired_service)) { actual_str = X509_NAME_oneline(actual_subject, NULL, 0); desired_str = X509_NAME_oneline(desired_subject, NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_SUBJECT_CMP, ("Desired subject and actual subject of certificate" " do not match.\n" " Desired subject: %s\n" " Actual subject: %s\n", desired_str, actual_str)); } goto exit; } else { if(strcmp(desired_service,actual_service)) { actual_str = X509_NAME_oneline(actual_subject, NULL, 0); desired_str = X509_NAME_oneline(desired_subject, NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_SUBJECT_CMP, ("Desired subject and actual subject of certificate" " do not match.\n" " Desired subject: %s\n" " Actual subject: %s\n", desired_str, actual_str)); } goto exit; } } else { /* full subject name, don't care about equivalence classes */ if(X509_NAME_cmp(desired_subject, actual_subject)) { actual_str = X509_NAME_oneline(actual_subject, NULL, 0); desired_str = X509_NAME_oneline(desired_subject, NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_SUBJECT_CMP, ("Desired subject and actual subject of certificate" " do not match.\n" " Desired subject: %s\n" " Actual subject: %s\n", desired_str, actual_str)); } goto exit; } exit: if(actual_cn) { free(actual_cn); } if(desired_cn) { free(desired_cn); } if(actual_str) { free(actual_str); } if(desired_str) { free(desired_str); } GLOBUS_I_GSI_CRED_DEBUG_EXIT; return result; } static globus_result_t globus_l_gsi_cred_get_service( X509_NAME * subject, char ** service) { int cn_index; int length; char * cn = NULL; char * host; char * subject_str = NULL; globus_result_t result = GLOBUS_SUCCESS; static char * _function_name_ = "globus_l_gsi_cred_get_service"; GLOBUS_I_GSI_CRED_DEBUG_ENTER; *service = NULL; /* if desired subject is NULL return success */ if(!subject) { goto exit; } /* find /CN entry in subject */ cn_index = X509_NAME_get_index_by_NID(subject, NID_commonName, -1); /* error if no common name was found */ if(cn_index < 0) { subject_str = X509_NAME_oneline(subject, NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_GETTING_SERVICE_NAME, ("No Common Name found in subject %s.\n", subject_str)); goto exit; } /* check that subject only has one CN entry */ if(X509_NAME_get_index_by_NID(subject, NID_commonName, cn_index) != -1) { subject_str = X509_NAME_oneline(subject, NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_GETTING_SERVICE_NAME, ("More than one Common Name found in subject %s.\n", subject_str)); goto exit; } /* get CN text for subject */ length = X509_NAME_get_text_by_NID(subject, NID_commonName, NULL, 1024) + 1; cn = malloc(length); X509_NAME_get_text_by_NID(subject, NID_commonName, cn, length); host = strchr(cn,'/'); if(host == NULL) { subject_str = X509_NAME_oneline(subject, NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_GETTING_SERVICE_NAME, ("No service name found in subject %s.\n", subject_str)); goto exit; } *host = '\0'; if(strcmp("host",cn)) { *service = strdup(cn); } else { subject_str = X509_NAME_oneline(subject, NULL, 0); GLOBUS_GSI_CRED_ERROR_RESULT( result, GLOBUS_GSI_CRED_ERROR_GETTING_SERVICE_NAME, ("No service name found in subject %s.\n", subject_str)); } goto exit; exit: if(cn) { free(cn); } if(subject_str) { free(subject_str); } GLOBUS_I_GSI_CRED_DEBUG_EXIT; return result; } #endif