/** * Verify that an addressing element is located in <Envelope>/<Header> */ int verify_addr_hdr_elem_loc(axiom_node_t *signed_node, const axutil_env_t *env, axis2_char_t *ref) { axiom_node_t *parent = axiom_node_get_parent(signed_node,env); if(axutil_strcmp(OXS_NODE_HEADER, axiom_util_get_localname(parent, env))) { AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[euca-rampart] parent of addressing elem is %s", axiom_node_to_string(parent, env)); oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_ELEMENT_FAILED, "Unexpected location of signed addressing elem with ID = %s", ref); return 1; } parent = axiom_node_get_parent(parent,env); if(axutil_strcmp(OXS_NODE_ENVELOPE, axiom_util_get_localname(parent, env))) { AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[euca-rampart] second parent of addressing elem is %s", axiom_node_to_string(parent, env)); oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_ELEMENT_FAILED, "Unexpected location of signed addressing elem with ID = %s", ref); return 1; } parent = axiom_node_get_parent(parent,env); if(parent) { AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[euca-rampart] parent of Envelope = %s", axiom_node_to_string(parent, env)); oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_ELEMENT_FAILED, "Unexpected location of signed Body with ID = %s", ref); return 1; } return 0; }
/** * Traverse thru the node and its descendents. Check if the localname is equal to the given name * @param env Environment. MUST NOT be NULL, * @param node the node to be searched * @param localname the local name of the node to be searched * @return the node if found, else NULL */ AXIS2_EXTERN axiom_node_t* AXIS2_CALL oxs_axiom_get_node_by_local_name( const axutil_env_t *env, axiom_node_t *node, axis2_char_t *local_name) { axis2_char_t *temp_name = NULL; if(!node) { return NULL; } if(axiom_node_get_node_type(node, env) != AXIOM_ELEMENT) { return NULL; } temp_name = axiom_util_get_localname(node, env); AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[rampart]Checking node %s for %s", temp_name, local_name ); if(!axutil_strcmp(temp_name, local_name)) { /* Gottcha.. return this node */ return node; } else { /* Doesn't match? Get the children and search for them */ axiom_node_t *temp_node = NULL; temp_node = axiom_node_get_first_element(node, env); while(temp_node) { axiom_node_t *res_node = NULL; res_node = oxs_axiom_get_node_by_local_name(env, temp_node, local_name); if(res_node) { return res_node; } temp_node = axiom_node_get_next_sibling(temp_node, env); } } return NULL; }
/** * 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 */ AXIS2_EXTERN axis2_status_t AXIS2_CALL rampart_token_process_security_token_reference( const axutil_env_t *env, 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; child_node = axiom_node_get_first_element(st_ref_node, env); child_name = axiom_util_get_localname(child_node, env); if(!axutil_strcmp(child_name, OXS_NODE_REFERENCE)) { status = rampart_token_process_direct_ref(env, child_node, scope_node, 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 = rampart_token_process_x509_data(env, child_node, cert); } else { /* 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; } return status; }
/** * Verifies XPath location of signed elements. */ int verify_node(axiom_node_t *signed_node, const axutil_env_t *env, axis2_msg_ctx_t *msg_ctx, axis2_char_t *ref, short *signed_elems) { if(!axutil_strcmp(OXS_NODE_BODY, axiom_util_get_localname(signed_node, env))) { AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[euca-rampart] node %s is Body", ref); signed_elems[0] = 1; axiom_node_t *parent = axiom_node_get_parent(signed_node,env); if(axutil_strcmp(OXS_NODE_ENVELOPE, axiom_util_get_localname(parent, env))) { oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_ELEMENT_FAILED, "Unexpected parent element for Body with ID = %s", ref); return 1; } parent = axiom_node_get_parent(parent,env); if(parent) { AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[euca-rampart] parent of Envelope = %s", axiom_node_to_string(parent, env)); oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_ELEMENT_FAILED, "Unexpected location of signed Body with ID = %s", ref); return 1; } } else if(!axutil_strcmp(RAMPART_SECURITY_TIMESTAMP, axiom_util_get_localname(signed_node, env))) { AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[euca-rampart] node %s is Timestamp", ref); signed_elems[1] = 1; /* Regardless of the location of the Timestamp, verify the one that is signed */ if(AXIS2_FAILURE == rampart_timestamp_token_validate(env, msg_ctx, signed_node, 20)) { oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_ELEMENT_FAILED, "Validation failed for Timestamp with ID = %s", ref); return 1; } } else if(!axutil_strcmp(AXIS2_WSA_ACTION, axiom_util_get_localname(signed_node, env))) { AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[euca-rampart] node %s is Action", ref); signed_elems[2] = 1; if(verify_addr_hdr_elem_loc(signed_node, env, ref)) { oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_ELEMENT_FAILED, "Validation failed for Action with ID = %s", ref); return 1; } } else if(!axutil_strcmp(AXIS2_WSA_TO, axiom_util_get_localname(signed_node, env))) { AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[euca-rampart] node %s is To", ref); signed_elems[3] = 1; if(verify_addr_hdr_elem_loc(signed_node, env, ref)) { oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_ELEMENT_FAILED, "Validation failed for To with ID = %s", ref); return 1; } } else if(!axutil_strcmp(AXIS2_WSA_MESSAGE_ID, axiom_util_get_localname(signed_node, env))) { AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[euca-rampart] node %s is MessageId", ref); signed_elems[4] = 1; if(verify_addr_hdr_elem_loc(signed_node, env, ref)) { oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_ELEMENT_FAILED, "Validation failed for MessageId with ID = %s", ref); return 1; } } else { AXIS2_LOG_WARNING(env->log, AXIS2_LOG_SI, "[euca-rampart] node %s is UNKNOWN", ref); } return 0; }
/*Public functions*/ AXIS2_EXTERN axis2_status_t AXIS2_CALL rampart_shb_ensure_sec_header_order(const axutil_env_t *env, axis2_msg_ctx_t *msg_ctx, rampart_context_t *rampart_context, axiom_node_t* sec_node) { axis2_bool_t signature_protection = AXIS2_FALSE; axis2_bool_t is_encrypt_before_sign = AXIS2_FALSE; axiom_node_t *sig_node = NULL; axiom_node_t *enc_key_node = NULL; axiom_node_t *ref_list_node = NULL; axiom_node_t *h_node = NULL; axutil_array_list_t *dk_list = NULL; axutil_array_list_t *enc_key_list = NULL; axiom_node_t* first_protection_item = NULL; int i = 0; signature_protection = rampart_context_is_encrypt_signature(rampart_context, env); is_encrypt_before_sign = rampart_context_is_encrypt_before_sign(rampart_context, env); dk_list = axutil_array_list_create(env, 5); enc_key_list = axutil_array_list_create(env, 2); h_node = axiom_node_get_first_child(sec_node, env); while(h_node) { if(0 == axutil_strcmp(OXS_NODE_DERIVED_KEY_TOKEN, axiom_util_get_localname(h_node, env)) || (0 == axutil_strcmp(OXS_NODE_BINARY_SECURITY_TOKEN, axiom_util_get_localname(h_node, env)))) { axutil_array_list_add(dk_list, env, h_node); } else if((0 == axutil_strcmp(OXS_NODE_ENCRYPTED_KEY, axiom_util_get_localname(h_node, env))) || (0 == axutil_strcmp(OXS_NODE_SECURITY_CONTEXT_TOKEN, axiom_util_get_localname(h_node, env)))) { axutil_array_list_add(enc_key_list, env, h_node); } h_node = axiom_node_get_next_sibling(h_node, env); } ref_list_node = oxs_axiom_get_first_child_node_by_name(env, sec_node, OXS_NODE_REFERENCE_LIST, OXS_ENC_NS, NULL); sig_node = oxs_axiom_get_first_child_node_by_name(env, sec_node, OXS_NODE_SIGNATURE, OXS_DSIG_NS, NULL); /*Ensure the protection order in the header*/ if(sig_node && ref_list_node) { if(is_encrypt_before_sign) { int no_of_sig_node = 0; /*Encrypt->Sig <Sig><RefList>*/ oxs_axiom_interchange_nodes(env, sig_node, ref_list_node ); first_protection_item = sig_node; no_of_sig_node = oxs_axiom_get_number_of_children_with_qname(env, sec_node, OXS_NODE_SIGNATURE, OXS_DSIG_NS, NULL); if(no_of_sig_node > 1) { axiom_node_t* cur_node = NULL; cur_node = axiom_node_get_first_child(sec_node, env); while(cur_node) { axis2_char_t *cur_local_name = NULL; cur_local_name = axiom_util_get_localname(cur_node, env); if(0 == axutil_strcmp(cur_local_name, OXS_NODE_SIGNATURE)) { oxs_axiom_interchange_nodes(env, cur_node, ref_list_node); } cur_node = axiom_node_get_next_sibling(cur_node, env); } } } else { /*Sig->Encrypt <RefList> <Sig>*/ oxs_axiom_interchange_nodes(env, ref_list_node, sig_node ); first_protection_item = ref_list_node; } } else if(sig_node) { first_protection_item = sig_node; } else { first_protection_item = ref_list_node; } /*makesure enc_key_node is appearing before first protection item*/ if(first_protection_item) { for(i = 0; i < axutil_array_list_size(enc_key_list, env); i++) { axiom_node_t *tmp_node = NULL; tmp_node = (axiom_node_t*)axutil_array_list_get(enc_key_list, env, i); enc_key_node = axiom_node_detach_without_namespaces(tmp_node, env); axiom_node_insert_sibling_before(first_protection_item, env, enc_key_node); } } /* * If there are derived keys, make sure they come after the EncryptedKey/security context token 1. First we get all the derived keys 2. Then we attach after the EncryptedKey(hidden sessionkey)/security context token 3. If key is not available, then attach derived keys before sig_node and ref_list_node (whichever is first) */ if(enc_key_node) { for(i = 0; i < axutil_array_list_size(dk_list, env); i++) { axiom_node_t *dk_node = NULL; axiom_node_t *tmp_node = NULL; dk_node = (axiom_node_t*)axutil_array_list_get(dk_list, env, i); tmp_node = axiom_node_detach(dk_node, env); axiom_node_insert_sibling_after(enc_key_node, env, tmp_node); } } else { if(first_protection_item) { for(i = 0; i < axutil_array_list_size(dk_list, env); i++) { axiom_node_t *dk_node = NULL; axiom_node_t *tmp_node = NULL; dk_node = (axiom_node_t*)axutil_array_list_get(dk_list, env, i); tmp_node = axiom_node_detach(dk_node, env); axiom_node_insert_sibling_before(first_protection_item, env, tmp_node); } } } axutil_array_list_free(dk_list, env); axutil_array_list_free(enc_key_list, env); return AXIS2_SUCCESS; }
/** * 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 { /* 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; } 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 AXIS2_SUCCESS; }
/** * extract certificate/key using reference id given in reference node */ static axis2_status_t rampart_token_process_direct_ref( const axutil_env_t *env, axiom_node_t *ref_node, axiom_node_t *scope_node, 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 *ref_id = NULL; axis2_bool_t external_reference = AXIS2_TRUE; /* 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(!ref_id) { AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Failed to get key name from reference node"); return AXIS2_FAILURE; } if(ref_id[0] == '#') { /* 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); } if(!(*key)) { AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Cannot find key referenced by URI %s", ref_id); return AXIS2_FAILURE; } return AXIS2_SUCCESS; }