Modified: webservices/rampart/trunk/c/src/util/rampart_token_processor.c URL: http://svn.apache.org/viewvc/webservices/rampart/trunk/c/src/util/rampart_token_processor.c?rev=794624&r1=794623&r2=794624&view=diff ============================================================================== --- webservices/rampart/trunk/c/src/util/rampart_token_processor.c (original) +++ webservices/rampart/trunk/c/src/util/rampart_token_processor.c Thu Jul 16 10:57:25 2009 @@ -20,163 +20,547 @@ #include <oxs_xml_key_processor.h> #include <axiom_util.h> #include <rampart_token_processor.h> +#include <rampart_saml.h> +#include <rampart_sec_header_processor.h> +#include <saml.h> /** - * extract certificate related information using given token_reference node and scope node - * @param env Environment structure - * @param st_ref_node security token reference node. - * @param scope_node node where additional details should be found. Can be NULL for all other - * scenarios but the Direct Reference - * @param cert certificate where values extracted shuold be populated - * @return status of the operation + * extract certificate/key using reference id given in reference node */ -AXIS2_EXTERN axis2_status_t AXIS2_CALL -rampart_token_process_security_token_reference( +static axis2_status_t +rampart_token_process_direct_ref( const axutil_env_t *env, - axiom_node_t *st_ref_node, + axiom_node_t *ref_node, axiom_node_t *scope_node, - oxs_x509_cert_t *cert) + axis2_msg_ctx_t *msg_ctx, + rampart_context_t *rampart_context, + oxs_x509_cert_t **cert, + oxs_key_t **key, + axis2_char_t **token_type) { - axis2_char_t *child_name = NULL; - axiom_node_t *child_node = NULL; - axis2_status_t status = AXIS2_FAILURE; + axis2_char_t *ref_id = NULL; + axis2_bool_t external_reference = AXIS2_TRUE; - child_node = axiom_node_get_first_element(st_ref_node, env); - child_name = axiom_util_get_localname(child_node, env); + /* Get the reference value in the @URI */ + ref_id = oxs_token_get_reference(env, ref_node); + *token_type = oxs_token_get_reference_value_type(env, ref_node); - if(!axutil_strcmp(child_name, OXS_NODE_REFERENCE)) + if(!ref_id) { - status = rampart_token_process_direct_ref(env, child_node, scope_node, cert); + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Failed to get key name from reference node"); + return AXIS2_FAILURE; } - else if(!axutil_strcmp(child_name, OXS_NODE_EMBEDDED)) + + if(ref_id[0] == '#') { - status = rampart_token_process_embedded(env, child_node, cert); + /* Need to remove # sign from the ID */ + axis2_char_t *id = NULL; + id = axutil_string_substring_starting_at(axutil_strdup(env, ref_id), 1); + external_reference = AXIS2_FALSE; + ref_id = id; + if(!ref_id) + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Failed to get key name from reference node"); + return AXIS2_FAILURE; + } + } + + if(!external_reference) + { + /* this could point to binary security token, which means it is x509 token */ + axiom_node_t *bst_node = NULL; + axis2_char_t *data = NULL; + + bst_node = oxs_axiom_get_node_by_id(env, scope_node, OXS_ATTR_ID, ref_id, OXS_WSU_XMLNS); + if(bst_node) + { + axis2_char_t *local_name = NULL; + local_name = axiom_util_get_localname(bst_node, env); + if(!axutil_strcmp(local_name, OXS_NODE_BINARY_SECURITY_TOKEN)) + { + /* This is an X509 token */ + *token_type = oxs_token_get_reference_value_type(env, bst_node); + + /* Process data. */ + data = oxs_axiom_get_node_content(env, bst_node); + *cert = oxs_key_mgr_load_x509_cert_from_string(env, data); + if(*cert) + { + return AXIS2_SUCCESS; + } + else + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, + "Cannot load certificate from string =%s", data); + return AXIS2_FAILURE; + } + } + } + } + + *key = rampart_context_get_key(rampart_context, env, ref_id); + if(!(*key) && external_reference) + { + if((0 == axutil_strcmp(*token_type, OXS_VALUE_TYPE_SECURITY_CONTEXT_TOKEN_05_02)) || + (0 == axutil_strcmp(*token_type, OXS_VALUE_TYPE_SECURITY_CONTEXT_TOKEN_05_12))) + { + rampart_shp_add_security_context_token(env, ref_id, ref_id, rampart_context, msg_ctx); + } + *key = rampart_context_get_key(rampart_context, env, ref_id); } - else if(!axutil_strcmp(child_name, OXS_NODE_KEY_IDENTIFIER)) + + if(!(*key)) { - status = rampart_token_process_key_identifier(env, child_node, cert); + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Cannot find key referenced by URI %s", ref_id); + return AXIS2_FAILURE; } - else if(!axutil_strcmp(child_name, OXS_NODE_X509_DATA)) - { - status = rampart_token_process_x509_data(env, child_node, cert); + return AXIS2_SUCCESS; +} + +/** + * extract certificate/key using key identifier + */ +static axis2_status_t +rampart_token_process_key_identifier( + const axutil_env_t *env, + axiom_node_t *key_identifier_node, + axiom_node_t *scope_node, + axiom_node_t *str_node, + rampart_context_t *rampart_context, + axis2_bool_t is_signature, + oxs_x509_cert_t **cert, + oxs_key_t **key, + axis2_char_t **token_type) +{ + axis2_char_t *value_type = NULL; + value_type = oxs_axiom_get_attribute_value_of_node_by_name(env, key_identifier_node, + OXS_ATTR_VALUE_TYPE, NULL); + + if(axutil_strcmp(value_type, OXS_X509_SUBJ_KI) == 0)/* X509 Token */ + { + /* In the client side, it is preferred to use certificate files instead of key store, + * because one client normally interact with only one service. To handle this scenario, + * if we found receiver certificate file specified in rampart_context we directly call the + * get_reciever_certificate. + */ + *cert = rampart_context_get_receiver_certificate(rampart_context, env); + if(!*cert) + { + axis2_char_t *ski = NULL; + oxs_key_mgr_t *key_mgr = NULL; + key_mgr = rampart_context_get_key_mgr(rampart_context, env); + ski = oxs_axiom_get_node_content(env, key_identifier_node); + *cert = oxs_key_mgr_get_receiver_certificate_from_ski(key_mgr, env, ski); + if(!*cert) + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, + "Cannot retrieve certificate using key identifier"); + return AXIS2_FAILURE; + } + } + } + else if(axutil_strcmp(value_type, OXS_X509_ENCRYPTED_KEY_SHA1) == 0) /* EncryptedKey */ + { + axis2_char_t *hash_value = NULL; + hash_value = oxs_axiom_get_node_content(env, key_identifier_node); + if(!hash_value) + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Failed to get value of EncryptedKeySHA1"); + return AXIS2_FAILURE; + } + + *key = rampart_context_get_key_using_hash(rampart_context, env, hash_value); + if(!*key) + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, + "Cannot get key corresponding to EncryptedKeySHA1"); + return AXIS2_FAILURE; + } + } + else if(axutil_strcmp(value_type, OXS_ST_KEY_ID_VALUE_TYPE) == 0) /* SAML token reference */ + { + axiom_node_t *assertion = NULL; + rampart_saml_token_t *saml = NULL; + rampart_st_type_t tok_type; + oxs_key_mgr_t *key_mgr = NULL; + openssl_pkey_t *pvt_key = NULL; + + key_mgr = rampart_context_get_key_mgr(rampart_context, env); + pvt_key = oxs_key_mgr_get_prv_key(key_mgr, env); + if(!pvt_key) + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Cannot load private key"); + return AXIS2_FAILURE; + } + + assertion = oxs_saml_token_get_from_key_identifer_reference(env, key_identifier_node, NULL); + if(!assertion) + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Cannot get key SAML Assertion"); + return AXIS2_FAILURE; + } + if(is_signature) + { + tok_type = RAMPART_ST_TYPE_SIGNATURE_TOKEN; + } + else + { + tok_type = RAMPART_ST_TYPE_ENCRYPTION_TOKEN; + } + saml = rampart_saml_add_token(rampart_context, env, assertion, str_node, tok_type); + *key = rampart_saml_token_get_session_key(saml, env); + if(!*key) + { + *key = saml_assertion_get_session_key(env, assertion, pvt_key); + rampart_saml_token_set_session_key(saml, env, *key); + oxs_key_set_name(*key, env, "for-algo"); + } + + if(!*key) + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Cannot get key corresponding to SAML Token"); + return AXIS2_FAILURE; + } } else { - /* reference method is not supported */ - AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, - "[rampart]%s of wsse:SecurityTokenReference is not supported.", child_name); + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Failed to identify Key Identifier %s", value_type); return AXIS2_FAILURE; } - return status; + return AXIS2_SUCCESS; } - /** - * extract certificate using reference id given in reference node - * @param env Environment structure - * @param ref_node security token reference node. - * @param scope_node node where certificate details should be found using reference id - * @param cert certificate where values extracted shuold be populated - * @return status of the operation + * extract embedded certificate from given embed_node */ -AXIS2_EXTERN axis2_status_t AXIS2_CALL -rampart_token_process_direct_ref( +static axis2_status_t +rampart_token_process_embedded( const axutil_env_t *env, - axiom_node_t *ref_node, - axiom_node_t *scope_node, - oxs_x509_cert_t *cert) + axiom_node_t *embed_node, + oxs_x509_cert_t **cert) { - axis2_char_t *ref = NULL; - axis2_char_t *ref_id = NULL; - axis2_status_t status = AXIS2_FAILURE; - axiom_node_t *bst_node = NULL; axis2_char_t *data = NULL; - oxs_x509_cert_t *_cert = NULL; - - /* Select ref using <wsse:Reference> node. Since it is relative reference, we have to remove - * first character (which is '#') from the reference */ - ref = oxs_token_get_reference(env, ref_node); - ref_id = axutil_string_substring_starting_at(axutil_strdup(env, ref), 1); + axiom_node_t *bst_node = NULL; - /* Find the token with the id = ref_id within the scope of scope_node */ - bst_node = oxs_axiom_get_node_by_id(env, scope_node, OXS_ATTR_ID, ref_id, OXS_WSU_XMLNS); + bst_node = axiom_node_get_first_element(embed_node, env); if(!bst_node) { - AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, - "[rampart]Error retrieving element with ID = %s", ref_id); + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "BinarySecurityToken element is not found"); return AXIS2_FAILURE; } - /* Process data. */ + /* Process data */ data = oxs_axiom_get_node_content(env, bst_node); - _cert = oxs_key_mgr_load_x509_cert_from_string(env, data); - if(_cert) + *cert = oxs_key_mgr_load_x509_cert_from_string(env, data); + if(!*cert) { - status = AXIS2_SUCCESS; + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Cannot load certificate from string =%s", data); + return AXIS2_FAILURE; + } + + return AXIS2_SUCCESS; +} + +/* Get the client certificate from key manager by giving + * issuer and serial number of the certificate + */ +static oxs_x509_cert_t * +rampart_token_process_issuer_serial( + const axutil_env_t *env, + rampart_context_t *rampart_ctx, + axiom_node_t *x509_data_node) +{ + oxs_x509_cert_t *cert = NULL; + axiom_node_t *issuer_serial_node = NULL; + axiom_element_t *issuer_serial_ele = NULL; + axiom_child_element_iterator_t *child_itr = NULL; + axiom_node_t *child_node = NULL; + axiom_element_t *child_ele = NULL; + axis2_char_t *ele_name = NULL; + axis2_char_t *issuer_name_str = NULL; + axis2_char_t *serial_num_str = NULL; + int serial_num = -1; + oxs_key_mgr_t *key_mgr = NULL; + + if((cert = rampart_context_get_receiver_certificate(rampart_ctx, env))) + { + /* In the client side, it is preferred to use certificate files instead + * of key store, because one client normally interact with only one + * service. To handle this scenario, if we found receiver certificate file + * specified in rampart_context we directly call the get_reciever_certificate. + */ + return cert; + } + + issuer_serial_node = axiom_node_get_first_child(x509_data_node, env); + issuer_serial_ele = axiom_node_get_data_element(issuer_serial_node, env); + + child_itr = axiom_element_get_child_elements(issuer_serial_ele, env, issuer_serial_node); + while(axiom_child_element_iterator_has_next(child_itr, env)) + { + child_node = axiom_child_element_iterator_next(child_itr, env); + child_ele = axiom_node_get_data_element(child_node, env); + ele_name = axiom_element_get_localname(child_ele, env); + if(axutil_strcmp(ele_name, OXS_NODE_X509_ISSUER_NAME) == 0) + { + issuer_name_str = axiom_element_get_text(child_ele, env, child_node); + if(!issuer_name_str) + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Issuer Name cannot be NULL."); + return NULL; + } + AXIS2_LOG_INFO(env->log, AXIS2_LOG_SI, "X509 Certificate Issuer Name Found: %s", + issuer_name_str); + } + else if(axutil_strcmp(ele_name, OXS_NODE_X509_SERIAL_NUMBER) == 0) + { + serial_num_str = axiom_element_get_text(child_ele, env, child_node); + if(!serial_num_str) + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Serial number cannot be null."); + } + AXIS2_LOG_INFO(env->log, AXIS2_LOG_SI, "X509 Certificate Serial Number Found: %s", + serial_num_str); + } + else + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, + "Error in incoming key info. These types not supported: %", ele_name); + return NULL; + } + } + + serial_num = atoi(serial_num_str); + key_mgr = rampart_context_get_key_mgr(rampart_ctx, env); + + cert = oxs_key_mgr_get_receiver_certificate_from_issuer_serial(key_mgr, env, issuer_name_str, + serial_num); + + return cert; +} + +/** + * Extract certificate/session_key related information using given key_info node and scope node + * This will extract either certificate(asymmetric signing) or session_key (symmetric signing) + * @param env Environment structure + * @param key_info_node key info node. + * @param rampart_context rampart context where key details could be found. + * @param msg_ctx message context + * @param is_signature boolean denoting whether the key_info is for signature + * @param cert where the certificate extracted (if any) should be populated + * @param key where the session key extracted (if any) should be populated + * @return status of the operation + */ +AXIS2_EXTERN axis2_status_t AXIS2_CALL +rampart_token_process_key_info( + const axutil_env_t *env, + axiom_node_t *key_info_node, + axiom_node_t *sec_node, + rampart_context_t* rampart_context, + axis2_msg_ctx_t *msg_ctx, + axis2_bool_t is_signature, + oxs_x509_cert_t **cert, + oxs_key_t **key, + axis2_char_t **token_type, + axis2_char_t **reference_method) +{ + axiom_node_t *str_node = NULL; + axis2_status_t status = AXIS2_FAILURE; + + /* Get the SecurityTokenReference, which is the common case, but not the only case */ + str_node = oxs_axiom_get_first_child_node_by_name(env, key_info_node, + OXS_NODE_SECURITY_TOKEN_REFRENCE, OXS_WSSE_XMLNS, NULL); + + if(str_node) + { + axiom_node_t *str_child_node = NULL; + + /* A <wsse:SecurityTokenReference> element MAY reference an X.509 token type + * by one of the following means: + * - Reference to a Subject Key Identifier (<wsse:KeyIdentifier>) + * - Reference to a Binary Security Token (<wsse:Reference> element that + * references a local <wsse:BinarySecurityToken> element or a remote data + * source that contains the token data itself) + * - Reference to an Issuer and Serial Number (<ds:X509Data> element that + * contains a <ds:X509IssuerSerial> element that uniquely identifies an + * end entity certificate) + */ + str_child_node = axiom_node_get_first_element(str_node, env); + if(!str_child_node) + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, + "No Child node in the Security Token Reference Element."); + return AXIS2_FAILURE; + } + + *reference_method = axiom_util_get_localname(str_child_node, env); + if(!*reference_method) + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, + "Cannot get the key Reference Type from the message."); + return AXIS2_FAILURE; + } + + if(0 == axutil_strcmp(*reference_method, OXS_NODE_REFERENCE)) + { + status = rampart_token_process_direct_ref(env, str_child_node, sec_node, msg_ctx, + rampart_context, cert, key, token_type); + } + else if(0 == axutil_strcmp(*reference_method, OXS_NODE_EMBEDDED)) + { + /* embedded tokens are only possible with x509 token */ + status = rampart_token_process_embedded(env, str_child_node, cert); + } + else if(0 == axutil_strcmp(*reference_method, OXS_NODE_KEY_IDENTIFIER)) + { + status = rampart_token_process_key_identifier(env, str_child_node, sec_node, str_node, + rampart_context, is_signature, cert, key, token_type); + } + else if(0 == axutil_strcmp(*reference_method, OXS_NODE_X509_DATA)) + { + /* <ds:X509Data> contains a <ds:X509IssuerSerial> element which is used to specify a + * reference to an X.509 security token by means of the certificate issuer name and + * serial number. */ + *cert = rampart_token_process_issuer_serial(env, rampart_context, str_child_node); + status = AXIS2_SUCCESS; + } + else + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Key Reference %s not supported ", + *reference_method); + return AXIS2_FAILURE; + } } else { - AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, - "[rampart]Cannot load certificate from string =%s", data); - status = AXIS2_FAILURE; + /* There may be scenarios where there is no Security Token Reference Element. */ + + /*In such case policy support only Isssuer Serial scenario.*/ + + /*if(axutil_strcmp(eki, RAMPART_STR_ISSUER_SERIAL) == 0) + { + key_info_child_node = axiom_node_get_first_element(key_info_node, env); + if(key_info_child_node) + { + axis2_char_t *key_info_child_name = NULL; + key_info_child_name = axiom_util_get_localname(key_info_child_node, env); + if(key_info_child_name) + { + if(0 == axutil_strcmp(key_info_child_name, OXS_NODE_X509_DATA)) + { + status = rampart_token_process_x509_data(env, key_info_child_node, cert); + if(status != AXIS2_SUCCESS || !cert) + { + rampart_create_fault_envelope(env, + RAMPART_FAULT_INVALID_SECURITY_TOKEN, + "Cannot load the key to verify the message .", + RAMPART_FAULT_IN_SIGNATURE, msg_ctx); + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, + "[Rampart][shp] Cannot load the key to verify the message"); + return AXIS2_FAILURE; + } + } + else + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, + "[Rampart][shp]Cannot get the key Reference Type from the message."); + return AXIS2_FAILURE; + } + } + else + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, + "[Rampart][shp]Cannot get the key Reference Type from the message."); + return AXIS2_FAILURE; + } + } + else + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, + "[Rampart][shp]Cannot get the key Reference Type from the message."); + return AXIS2_FAILURE; + } + } + + else + { + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, + "[Rampart][shp]Can't be used as a direct child of Key Info"); + return AXIS2_FAILURE; + }*/ + + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Failed to key from key_info node"); + return AXIS2_FAILURE; } - oxs_x509_cert_copy_to(_cert, env, cert); - oxs_x509_cert_free(_cert, env); - _cert = NULL; + if((status != AXIS2_SUCCESS) || ((!*cert) && (!*key))) + { + /* either status is AXIS2_FAILURE or both cert and key are NULL. This means error */ + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Cannot get key/certificate from key info node"); + return AXIS2_FAILURE; + } - return status; + return AXIS2_SUCCESS; } + + + +#if 0 /** - * extract embedded certificate from given embed_node + * extract certificate related information using given token_reference node and scope node * @param env Environment structure - * @param embed_node node where certificate is embedded. + * @param st_ref_node security token reference node. + * @param scope_node node where additional details should be found. Can be NULL for all other + * scenarios but the Direct Reference * @param cert certificate where values extracted shuold be populated * @return status of the operation */ AXIS2_EXTERN axis2_status_t AXIS2_CALL -rampart_token_process_embedded( +rampart_token_process_security_token_reference( const axutil_env_t *env, - axiom_node_t *embed_node, + axiom_node_t *st_ref_node, + axiom_node_t *scope_node, oxs_x509_cert_t *cert) { + axis2_char_t *child_name = NULL; + axiom_node_t *child_node = NULL; axis2_status_t status = AXIS2_FAILURE; - axis2_char_t *data = NULL; - oxs_x509_cert_t *_cert = NULL; - axiom_node_t *bst_node = NULL; - bst_node = axiom_node_get_first_element(embed_node, env); + child_node = axiom_node_get_first_element(st_ref_node, env); + child_name = axiom_util_get_localname(child_node, env); - if(!bst_node) + if(!axutil_strcmp(child_name, OXS_NODE_REFERENCE)) { - AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rampart]BST element is not found"); - return AXIS2_FAILURE; + status = rampart_token_process_direct_ref(env, child_node, scope_node, cert); } - - /* Process data */ - data = oxs_axiom_get_node_content(env, bst_node); - _cert = oxs_key_mgr_load_x509_cert_from_string(env, data); - if(_cert) + else if(!axutil_strcmp(child_name, OXS_NODE_EMBEDDED)) + { + status = rampart_token_process_embedded(env, child_node, cert); + } + else if(!axutil_strcmp(child_name, OXS_NODE_KEY_IDENTIFIER)) + { + status = rampart_token_process_key_identifier(env, child_node, cert); + } + else if(!axutil_strcmp(child_name, OXS_NODE_X509_DATA)) { - status = AXIS2_SUCCESS; + status = rampart_token_process_x509_data(env, child_node, cert); } else { - AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, - "[rampart]Cannot load certificate from string =%s", data); - status = AXIS2_FAILURE; + /* reference method is not supported */ + AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, + "[rampart]%s of wsse:SecurityTokenReference is not supported.", child_name); + return AXIS2_FAILURE; } - oxs_x509_cert_copy_to(_cert, env, cert); - oxs_x509_cert_free(_cert, env); return status; } /** * extract key identifier and populate the certificate * @param env Environment structure - * @param ki_node node where key identifier is available. + * @param ki_node node where key identifier is available. * @param cert certificate where values extracted shuold be populated * @return status of the operation */ @@ -196,7 +580,7 @@ /** * extract key details from x509data node * @param env Environment structure - * @param x509_data_node x509data node. + * @param x509_data_node x509data node. * @param cert certificate where values extracted shuold be populated * @return status of the operation */ @@ -208,3 +592,5 @@ { return oxs_xml_key_process_X509Data(env, x509_data_node, cert); } + +#endif
