blob: d537f929173f9966a7f31e14c998b40b495c017d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <axis2_util.h>
#include <oxs_constants.h>
#include <oxs_error.h>
#include <oxs_buffer.h>
#include <oxs_cipher.h>
#include <oxs_c14n.h>
#include <oxs_axiom.h>
#include <oxs_utility.h>
#include <openssl_rsa.h>
#include <openssl_digest.h>
#include <oxs_sign_ctx.h>
#include <oxs_sign_part.h>
#include <oxs_xml_signature.h>
#include <oxs_signature.h>
#include <oxs_transform.h>
#include <oxs_transforms_factory.h>
#include <oxs_tokens.h>
#include <axiom_util.h>
/* This method is common for both signing and verification */
static axis2_char_t *
oxs_xml_sig_transform_n_digest(
const axutil_env_t *env,
axiom_node_t *node,
axutil_array_list_t *transforms,
axis2_char_t *digest_mtd)
{
axis2_char_t *serialized_node = NULL;
axis2_char_t *digest = NULL;
axiom_node_t *ori_node = NULL, *sig_node = NULL;
oxs_tr_dtype_t output_dtype = OXS_TRANSFORM_TYPE_UNKNOWN;/*This will always be the current dtype*/
void *tr_output = NULL;
int i = 0;
if((transforms) && (0 < axutil_array_list_size(transforms, env)))
{
output_dtype = OXS_TRANSFORM_TYPE_NODE; /*We always begin with a node*/
tr_output = node; /*The first transformation is applied to the node*/
/*LOOP: Apply transforms. For example exclusive C14N*/
for(i = 0; i < axutil_array_list_size(transforms, env); i++)
{
oxs_transform_t *tr = NULL;
oxs_transform_tr_func tr_func = NULL;
oxs_tr_dtype_t input_dtype = OXS_TRANSFORM_TYPE_UNKNOWN;
void *tr_input = NULL;
axis2_char_t *tr_id = NULL;
/*Get the ith transform*/
tr = (oxs_transform_t*)axutil_array_list_get(transforms, env, i);
tr_id = oxs_transform_get_id(tr, env);
tr_func = oxs_transform_get_transform_function(tr, env);
input_dtype = oxs_transform_get_input_data_type(tr, env);
/*Prepare the input*/
/*If the required input type is CHAR and what we have is a NODE*/
if((input_dtype == OXS_TRANSFORM_TYPE_CHAR)
&& (output_dtype == OXS_TRANSFORM_TYPE_NODE))
{
/*Serialize*/
tr_input = axiom_node_to_string((axiom_node_t*)tr_output, env);
/*If the required input type is NODE and what we have is a CHAR*/
}
else if((input_dtype == OXS_TRANSFORM_TYPE_NODE) && (output_dtype
== OXS_TRANSFORM_TYPE_CHAR))
{
/*De-serialize*/
tr_input = oxs_axiom_deserialize_node(env, (axis2_char_t *)tr_output);
}
else if((input_dtype == OXS_TRANSFORM_TYPE_NODE) && (output_dtype
== OXS_TRANSFORM_TYPE_NODE_ARRAY_LIST))
{
ori_node = axutil_array_list_get((axutil_array_list_t*)tr_output, env, 0);
sig_node = axutil_array_list_get((axutil_array_list_t*)tr_output, env, 1);
tr_input = ori_node;
}
else if((input_dtype == OXS_TRANSFORM_TYPE_CHAR) && (output_dtype
== OXS_TRANSFORM_TYPE_NODE_ARRAY_LIST))
{
ori_node = axutil_array_list_get((axutil_array_list_t*)tr_output, env, 0);
sig_node = axutil_array_list_get((axutil_array_list_t*)tr_output, env, 1);
tr_input = axiom_node_to_string(ori_node, env);
}
else
{
/*Let it go as it is. */
tr_input = tr_output;
}
/*Apply transform*/
if(tr_func)
{
output_dtype = (*tr_func)(env, tr_input, input_dtype, &tr_output);
}
else
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_TRANSFORM_FAILED,
"Cannot get the transform implementation for %s", tr_id);
}
/*If the output data type is unknown OR the output is NULL its an error*/
if((output_dtype == OXS_TRANSFORM_TYPE_UNKNOWN) || (!tr_output))
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_TRANSFORM_FAILED,
"Transform failed for %s", tr_id);
return NULL;
}
}/*eof for loop*/
/*We have applied all our transforms now*/
/*Serialize node*/
if(OXS_TRANSFORM_TYPE_NODE == output_dtype)
{
serialized_node = axiom_node_to_string((axiom_node_t*)tr_output, env);
}
else if(OXS_TRANSFORM_TYPE_CHAR == output_dtype)
{
serialized_node = (axis2_char_t*)tr_output;
}
else if(OXS_TRANSFORM_TYPE_NODE_ARRAY_LIST == output_dtype)
{
ori_node
= (axiom_node_t*)axutil_array_list_get((axutil_array_list_t*)tr_output, env, 0);
sig_node
= (axiom_node_t*)axutil_array_list_get((axutil_array_list_t*)tr_output, env, 1);
serialized_node = axiom_node_to_string(ori_node, env);
}
else
{
/*Error*/
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_TRANSFORM_FAILED,
"Unsupported transform data type %d", output_dtype);
}
}
else
{
/*No transforms defined. Thus we simply direct the node, to make the digest*/
serialized_node = axiom_node_to_string(node, env);
}
if(0 == axutil_strcmp(OXS_HREF_SHA1, digest_mtd))
{
digest = openssl_sha1(env, serialized_node, axutil_strlen(serialized_node));
}
else if(0 == axutil_strcmp(OXS_HREF_SHA256, digest_mtd))
{
digest = openssl_sha256(env, serialized_node, axutil_strlen(serialized_node));
}
else
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_TRANSFORM_FAILED,
"Unsupported digest method %s", digest_mtd);
return NULL;
}
if(ori_node && sig_node)
{
axiom_node_add_child(ori_node, env, sig_node);
}
if(serialized_node)
{
AXIS2_FREE(env->allocator, serialized_node);
serialized_node = NULL;
}
return digest;
}
/*parent is ds:SignedInfo*/
static axis2_status_t
oxs_xml_sig_build_reference(
const axutil_env_t *env,
axiom_node_t *parent,
oxs_sign_part_t *sign_part)
{
axis2_char_t *digest = NULL;
axis2_char_t *digest_mtd = NULL;
axis2_char_t *ref_id = NULL;
axis2_char_t *id = NULL, *id_name = NULL;
axiom_namespace_t *ns = NULL;
axis2_char_t *ns_uri = NULL;
axutil_array_list_t *transforms = NULL;
axiom_node_t *node = NULL;
axiom_node_t *reference_node = NULL;
axiom_node_t *digest_value_node = NULL;
axiom_node_t *digest_mtd_node = NULL;
int i = 0;
/*Get the node to digest*/
node = oxs_sign_part_get_node(sign_part, env);
id_name = oxs_sign_part_get_id_name(sign_part, env);
ns = oxs_sign_part_get_sign_namespace(sign_part, env);
if(ns)
ns_uri = axiom_namespace_get_uri(ns, env);
else if(!ns && !id_name)
ns_uri = OXS_WSU_XMLNS;
else
ns_uri = NULL;
if(!id_name)
id_name = OXS_ATTR_ID;
/*Get the reference ID from the node and hence to the ds:Reference node*/
id = oxs_axiom_get_attribute_value_of_node_by_name(env, node, id_name, ns_uri);
ref_id = axutil_stracat(env, OXS_LOCAL_REFERENCE_PREFIX, id);/* <ds:Reference URI="#id">*/
reference_node = oxs_token_build_ds_reference_element(env, parent, NULL, ref_id, NULL);
AXIS2_FREE(env->allocator, ref_id);
ref_id = NULL;
/*Get transforms if any*/
transforms = oxs_sign_part_get_transforms(sign_part, env);
/*Get the digest method*/
digest_mtd = oxs_sign_part_get_digest_mtd(sign_part, env);
/*Transform and Digest*/
digest = oxs_xml_sig_transform_n_digest(env, node, transforms, digest_mtd);
if(!digest)
{
return AXIS2_FAILURE;
}
/*Build ds:Transforms node and its children*/
if((transforms) && (0 < axutil_array_list_size(transforms, env)))
{
axiom_node_t *transforms_node = NULL;
transforms_node = oxs_token_build_transforms_element(env, reference_node);
for(i = 0; i < axutil_array_list_size(transforms, env); i++)
{
oxs_transform_t *tr = NULL;
axis2_char_t *tr_id = NULL;
/*Get the ith transform*/
tr = (oxs_transform_t*)axutil_array_list_get(transforms, env, i);
tr_id = oxs_transform_get_id(tr, env);
oxs_token_build_transform_element(env, transforms_node, tr_id);
}
}
/*Construct nodes*/
digest_mtd_node = oxs_token_build_digest_method_element(env, reference_node, digest_mtd);
digest_value_node = oxs_token_build_digest_value_element(env, reference_node, digest);
/*Free*/
AXIS2_FREE(env->allocator, digest);
digest = NULL;
return AXIS2_SUCCESS;
}
/**
* C14N -> Serialize -> Sign the <SignedInfo> element
*/
static axis2_status_t
oxs_xml_sig_sign_signed_info(
const axutil_env_t *env,
axiom_node_t *signature_node,
axiom_node_t *signed_info_node,
oxs_sign_ctx_t *sign_ctx)
{
axis2_char_t *signature_val = NULL;
axis2_char_t *serialized_signed_info = NULL;
axis2_char_t *c14n_algo = NULL;
axis2_char_t *c14nized = NULL;
axiom_node_t *signature_val_node = NULL;
axiom_document_t *doc = NULL;
oxs_buffer_t *input_buf = NULL;
oxs_buffer_t *output_buf = NULL;
axis2_status_t status = AXIS2_FAILURE;
/*Cannonicalize <SignedInfo>*/
c14n_algo = oxs_sign_ctx_get_c14n_mtd(sign_ctx, env);
doc = axiom_node_get_document(signed_info_node, env);
/*oxs_c14n_apply(env, doc, AXIS2_FALSE, &c14nized, AXIS2_TRUE, NULL, signed_info_node); */
oxs_c14n_apply_algo(env, doc, &c14nized, NULL, signed_info_node, c14n_algo);
AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[oxs][xml_sig] C14N (sig)= %s ", c14nized);
/*Then serialize <SignedInfo>*/
serialized_signed_info = c14nized; /*axiom_node_to_string(signed_info_node, env);*/
/*Make the input and out put buffers*/
input_buf = oxs_buffer_create(env);
output_buf = oxs_buffer_create(env);
oxs_buffer_populate(input_buf, env, (unsigned char *)serialized_signed_info, axutil_strlen(
serialized_signed_info));
/*Then sign... NOTE: The signature process includes making the digest. e.g. rsa-sha1 => RSA(SHA-1(contents))*/
status = oxs_sig_sign(env, sign_ctx, input_buf, output_buf);
signature_val = (axis2_char_t*)oxs_buffer_get_data(output_buf, env);
/*Construct <SignatureValue>*/
signature_val_node
= oxs_token_build_signature_value_element(env, signature_node, signature_val);
/*Free*/
AXIS2_FREE(env->allocator, c14nized);
c14nized = NULL;
oxs_buffer_free(input_buf, env);
input_buf = NULL;
oxs_buffer_free(output_buf, env);
output_buf = NULL;
return status;
}
/*Public functions*/
AXIS2_EXTERN axis2_status_t AXIS2_CALL
oxs_xml_sig_sign(
const axutil_env_t *env,
oxs_sign_ctx_t *sign_ctx,
axiom_node_t *parent,
axiom_node_t **sig_node)
{
axiom_node_t *signed_info_node = NULL;
axiom_node_t *signature_node = NULL;
axiom_node_t *signature_mtd_node = NULL;
axiom_node_t *c14n_mtd_node = NULL;
axis2_char_t *sign_algo = NULL;
axis2_char_t *c14n_algo = NULL;
axis2_char_t *sig_id = NULL;
axutil_array_list_t *sign_parts = NULL;
axis2_status_t status = AXIS2_FAILURE;
int i = 0;
/*Construct the <Signature> element*/
sig_id = oxs_util_generate_id(env, OXS_SIG_ID);
signature_node = oxs_token_build_signature_element(env, parent, sig_id);
AXIS2_FREE(env->allocator, sig_id);
sig_id = NULL;
/*Construct the <SignedInfo> */
signed_info_node = oxs_token_build_signed_info_element(env, signature_node);
/*Construct the <CanonicalizationMethod> */
c14n_algo = oxs_sign_ctx_get_c14n_mtd(sign_ctx, env);
c14n_mtd_node = oxs_token_build_c14n_method_element(env, signed_info_node, c14n_algo);
/*Construct the <SignatureMethod> */
sign_algo = oxs_sign_ctx_get_sign_mtd_algo(sign_ctx, env);
signature_mtd_node = oxs_token_build_signature_method_element(env, signed_info_node, sign_algo);
/*Look for signature parts*/
sign_parts = oxs_sign_ctx_get_sign_parts(sign_ctx, env);
/*For each and every signature part in sig ctx,*/
for(i = 0; i < axutil_array_list_size(sign_parts, env); i++)
{
oxs_sign_part_t *sign_part = NULL;
/*Get ith sign_part*/
sign_part = (oxs_sign_part_t*)axutil_array_list_get(sign_parts, env, i);
/*Create <ds:Reference> elements */
if(oxs_xml_sig_build_reference(env, signed_info_node, sign_part) != AXIS2_SUCCESS)
{
return AXIS2_FAILURE;
}
}
/*At this point we have a complete <SignedInfo> node. Now we need to sign it*/
status = oxs_xml_sig_sign_signed_info(env, signature_node, signed_info_node, sign_ctx);
/*sig_id = axiom_node_to_string(parent, env);*/
*sig_node = signature_node;
return status;
}
/*******************************Verification specific*****************************/
/*Populates a sign_part according to the <ds:Reference> node*/
AXIS2_EXTERN axis2_status_t AXIS2_CALL
oxs_xml_sig_process_ref_node(
const axutil_env_t *env,
oxs_sign_part_t *sign_part,
axiom_node_t *ref_node,
axiom_node_t *scope_node)
{
axis2_char_t *ref_id = NULL;
axis2_char_t *ref_id2 = NULL;
axis2_char_t *child_node_name = NULL;
axiom_node_t *reffed_node = NULL;
axiom_node_t *child_node = NULL, *cn = NULL;
axis2_char_t *id_name = NULL;
axiom_namespace_t *ns = NULL;
axis2_char_t *ns_uri = NULL;
axiom_attribute_t *attr = NULL;
axutil_hash_t *attr_hash = NULL;
axutil_hash_index_t *hi = NULL;
axiom_element_t *element = NULL, *ce = NULL;
axiom_child_element_iterator_t *ci = NULL;
ref_id = oxs_token_get_ds_reference(env, ref_node);
oxs_sign_part_set_id(sign_part, env, ref_id);
/*Remove the # from the id*/
ref_id2 = axutil_string_substring_starting_at(axutil_strdup(env, ref_id), 1);
/*Look for the attribute with the Reference URI value*/
if(scope_node)
{
element = axiom_node_get_data_element(scope_node, env);
if(element)
attr_hash = axiom_element_get_all_attributes(element, env);
if(attr_hash)
{
for(hi = axutil_hash_first(attr_hash, env); hi; hi = axutil_hash_next(env, hi))
{
void *v = NULL;
axutil_hash_this(hi, NULL, NULL, &v);
if(v)
{
axis2_char_t *attr_val = NULL;
axiom_attribute_t *attribute = (axiom_attribute_t*)v;
attr_val = axiom_attribute_get_value(attribute, env);
if(!axutil_strcmp(attr_val, ref_id2))
{
attr = attribute;
break;
}
}
}
}
}
/* if we cannot find the Id in the scope node proceed to childs*/
if(!attr)
{
element = axiom_node_get_data_element(scope_node, env);
if(element)
{
ci = axiom_element_get_child_elements(element, env, scope_node);
if(ci)
{
while(AXIS2_TRUE == axiom_child_element_iterator_has_next(ci, env))
{
cn = axiom_child_element_iterator_next(ci, env);
ce = axiom_node_get_data_element(cn, env);
if(ce)
attr_hash = axiom_element_get_all_attributes(ce, env);
if(attr_hash)
{
for(hi = axutil_hash_first(attr_hash, env); hi; hi = axutil_hash_next(env,
hi))
{
void *v = NULL;
axutil_hash_this(hi, NULL, NULL, &v);
if(v)
{
axis2_char_t *attr_val = NULL;
axiom_attribute_t *attribute = (axiom_attribute_t*)v;
attr_val = axiom_attribute_get_value(attribute, env);
if(!axutil_strcmp(attr_val, ref_id2))
{
attr = attribute;
if(env)
AXIS2_FREE(env->allocator, hi);
break;
}
}
}
}
}
}
}
}
if(attr)
{
id_name = axiom_attribute_get_localname(attr, env);
ns = axiom_attribute_get_namespace(attr, env);
if(ns)
ns_uri = axiom_namespace_get_uri(ns, env);
else
ns_uri = "";
reffed_node = oxs_axiom_get_node_by_id(env, scope_node, id_name, ref_id2, ns_uri);
}
else
{
reffed_node = oxs_axiom_get_node_by_id(env, scope_node, "Id", ref_id2, OXS_WSU_XMLNS);
/*for endorsing, we have to check "Id", not "wsu:Id"*/
if(!reffed_node)
{
reffed_node = oxs_axiom_get_node_by_id(env, scope_node, "Id", ref_id2, NULL);
}
}
/*Find the node refered by this ref_id2 and set to the sign part*/
if(reffed_node)
{
oxs_sign_part_set_node(sign_part, env, reffed_node);
}
else
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_SIG_VERIFICATION_FAILED,
"Cannot find node with Id=%s ", ref_id2);
AXIS2_FREE(env->allocator, ref_id2);
ref_id2 = NULL;
return AXIS2_FAILURE; /*No such node. Its an error*/
}
AXIS2_FREE(env->allocator, ref_id2);
ref_id2 = NULL;
/*First child is optional Transforms element*/
child_node = axiom_node_get_first_element(ref_node, env);
child_node_name = axiom_util_get_localname(child_node, env);
if(0 == axutil_strcmp(child_node_name, OXS_NODE_TRANSFORMS))
{
/*Transforms found*/
axiom_node_t *tr_node = NULL;
axutil_array_list_t *tr_list = NULL;
/*Create a list to hold transforms*/
tr_list = axutil_array_list_create(env, 1);
tr_node = axiom_node_get_first_element(child_node, env);
/*Iterate thru all the <ds:Transform> nodes in <ds:Transforms>*/
while(tr_node)
{
axis2_char_t *node_name = NULL;
node_name = axiom_util_get_localname(tr_node, env);
if(0 == axutil_strcmp(OXS_NODE_TRANSFORM, node_name))
{
axis2_char_t *tr_id = NULL;
oxs_transform_t *tr = NULL;
tr_id = oxs_token_get_transform(env, tr_node);
/*Get the transform given the id*/
tr = oxs_transforms_factory_produce_transform(env, tr_id);
if(!tr)
{
/*The transform not supported*/
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_TRANSFORM_FAILED,
"Cannot produce the transform for %s", tr_id);
return AXIS2_FAILURE;
}
/*Add the transform to the list*/
axutil_array_list_add(tr_list, env, tr);
}
else
{
/*<ds:Transforms> cant have any other element*/
/*NOTE: Removed this check for interop testing*/
/*oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_TRANSFORM_FAILED,"<ds:Transforms> cannot have node %s ", node_name );
return AXIS2_FAILURE;*/
}
/*Set the next node to be processed*/
tr_node = axiom_node_get_next_sibling(tr_node, env);
/*axiom_util_get_next_sibling_element(axiom_node_get_data_element(tr_node, env), env,
tr_node, &tr_node);*/
}/*eof while*/
/*Set transforms for this signature part*/
oxs_sign_part_set_transforms(sign_part, env, tr_list);
/*At the end, set the next node as the child node*/
/*child_node = axiom_node_get_next_sibling(child_node, env);*/
axiom_util_get_next_sibling_element(axiom_node_get_data_element(child_node, env), env,
child_node, &child_node);
}
else
{
/*There are no transforms for this sign part*/
}
/* Process mandatory ds:DigestMethod*/
child_node_name = axiom_util_get_localname(child_node, env);
if(0 == axutil_strcmp(child_node_name, OXS_NODE_DIGEST_METHOD))
{
axis2_char_t *digest_mtd = NULL;
/*ds:DigestMethod found*/
digest_mtd = oxs_token_get_digest_method(env, child_node);
oxs_sign_part_set_digest_mtd(sign_part, env, digest_mtd);
/*At the end, set the next node as the child node*/
/*child_node = axiom_node_get_next_sibling(child_node, env);*/
axiom_util_get_next_sibling_element(axiom_node_get_data_element(child_node, env), env,
child_node, &child_node);
}
else
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_SIG_VERIFICATION_FAILED,
"Cannot find <ds:DigestMethod> ");
return AXIS2_FAILURE;
}
/* Process mandatory ds:DigestValue*/
child_node_name = axiom_util_get_localname(child_node, env);
if(0 == axutil_strcmp(child_node_name, OXS_NODE_DIGEST_VALUE))
{
/*ds:DigestValue found*/
axis2_char_t *digest_val = NULL;
digest_val = oxs_token_get_digest_value(env, child_node);
oxs_sign_part_set_digest_val(sign_part, env, digest_val);
}
else
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_SIG_VERIFICATION_FAILED,
"Cannot find <ds:DigestValue> ");
return AXIS2_FAILURE;
}
return AXIS2_SUCCESS;
}
/*Process Signature Node along with its most loving child ds:SignedInfo.
* We need to populate
* 1. Sig_mtd
* 2. C14N Mtd
* 3. Sign parts
* 3.1. Id
* 3.2 Digest mtd
* 3.3. Transforms*/
AXIS2_EXTERN axis2_status_t AXIS2_CALL
oxs_xml_sig_process_signature_node(
const axutil_env_t *env,
oxs_sign_ctx_t *sign_ctx,
axiom_node_t *signature_node,
axiom_node_t *scope_node)
{
axiom_node_t *cur_node = NULL;
axiom_node_t *signed_info_node = NULL;
axiom_node_t *sig_val_node = NULL;
axis2_status_t status = AXIS2_FAILURE;
axutil_array_list_t *sign_part_list = NULL;
signed_info_node = oxs_axiom_get_first_child_node_by_name(env, signature_node,
OXS_NODE_SIGNEDINFO, OXS_DSIG_NS, OXS_DS);
/*signed_info_node = oxs_axiom_get_first_child_node_by_name(env, signature_node,
OXS_NODE_SIGNEDINFO, NULL,NULL);*/
if(!signed_info_node)
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_SIG_VERIFICATION_FAILED,
"Cannot find <ds:SignedInfo> ");
return AXIS2_FAILURE;
}
/*Create the list for sign parts*/
sign_part_list = axutil_array_list_create(env, 5);
/*Process signed info element*/
cur_node = axiom_node_get_first_element(signed_info_node, env);
/*Iterate thru children of <SignedInfo>*/
while(cur_node)
{
axis2_char_t *localname = NULL;
localname = axiom_util_get_localname(cur_node, env);
if(0 == axutil_strcmp(localname, OXS_NODE_CANONICALIZATION_METHOD))
{
axis2_char_t *c14n_mtd = NULL;
c14n_mtd = oxs_token_get_c14n_method(env, cur_node);
oxs_sign_ctx_set_c14n_mtd(sign_ctx, env, c14n_mtd);
}
else if(0 == axutil_strcmp(localname, OXS_NODE_SIGNATURE_METHOD))
{
axis2_char_t *sig_mtd = NULL;
sig_mtd = oxs_token_get_signature_method(env, cur_node);
oxs_sign_ctx_set_sign_mtd_algo(sign_ctx, env, sig_mtd);
}
else if(0 == axutil_strcmp(localname, OXS_NODE_REFERENCE))
{
oxs_sign_part_t *sign_part = NULL;
/* There might be multiple references.
* For each create a sign_part and add to sign_part_list in the sign_ctx*/
sign_part = oxs_sign_part_create(env);
status = oxs_xml_sig_process_ref_node(env, sign_part, cur_node, scope_node);
if(status == AXIS2_FAILURE)
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_SIG_VERIFICATION_FAILED,
"<ds:Reference> node processing failed ");
return AXIS2_FAILURE;
}
/*Now we have a new sign_part. Add it to the list.*/
axutil_array_list_add(sign_part_list, env, sign_part);
}
else
{
/*We do not process*/
}
cur_node = axiom_node_get_next_sibling(cur_node, env);
/*axiom_util_get_next_sibling_element(axiom_node_get_data_element(cur_node, env), env,
cur_node, &cur_node);*/
}
oxs_sign_ctx_set_sign_parts(sign_ctx, env, sign_part_list);
/*Finished processing SignedInfo. Now we are processing the Signature Value element*/
/*The very next child of SignedInfo Should be the ds:SignatureValue*/
/*sig_val_node = axiom_node_get_next_sibling(signed_info_node, env);*/
axiom_util_get_next_sibling_element(axiom_node_get_data_element(signed_info_node, env), env,
signed_info_node, &sig_val_node);
if(0 == axutil_strcmp(OXS_NODE_SIGNATURE_VALUE, axiom_util_get_localname(sig_val_node, env)))
{
axis2_char_t *sig_val = NULL;
axis2_char_t *newline_removed = NULL;
sig_val = oxs_token_get_signature_value(env, sig_val_node);
if(!sig_val)
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_SIG_VERIFICATION_FAILED,
"Cannot find signature value. ");
return AXIS2_FAILURE;
}
/*We now remove \n in this text.Otherwise verifications failed.*/
newline_removed = oxs_util_get_newline_removed_string(env, sig_val);
if(!newline_removed)
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_SIG_VERIFICATION_FAILED,
"Cannot Remove new lines. ");
return AXIS2_FAILURE;
}
oxs_sign_ctx_set_sig_val(sign_ctx, env, newline_removed);
/*We can free newline_removed string as sign_ctx duplicates it*/
AXIS2_FREE(env->allocator, newline_removed);
newline_removed = NULL;
}
else
{
/*Error the node should be the ds:SignatureValue*/
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_SIG_VERIFICATION_FAILED,
"Cannot find <ds:SignatureValue> ");
return AXIS2_FAILURE;
}
return AXIS2_SUCCESS;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
oxs_xml_sig_verify_sign_part(
const axutil_env_t *env,
oxs_sign_part_t *sign_part)
{
axis2_char_t *id = NULL;
axis2_char_t *digest_mtd = NULL;
axis2_char_t *digest_val = NULL;
axis2_char_t *new_digest = NULL;
axiom_node_t *node = NULL;
axutil_array_list_t *transforms = NULL;
axis2_status_t status = AXIS2_FAILURE;
id = oxs_sign_part_get_id(sign_part, env);
digest_mtd = oxs_sign_part_get_digest_mtd(sign_part, env);
digest_val = oxs_sign_part_get_digest_val(sign_part, env);
node = oxs_sign_part_get_node(sign_part, env);
transforms = oxs_sign_part_get_transforms(sign_part, env);
AXIS2_LOG_INFO(env->log, "[oxs][xml_sig] Verifying signature part %s ", id);
/*Do transforms to the node*/
new_digest = oxs_xml_sig_transform_n_digest(env, node, transforms, digest_mtd);
/*Compare values*/
if(0 == axutil_strcmp(new_digest, digest_val))
{
AXIS2_LOG_INFO(env->log, "[oxs][xml_sig] Digest verification success for node Id= %s ", id);
status = AXIS2_SUCCESS;
}
else
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_SIG_VERIFICATION_FAILED,
"Digest verification failed for node Id= %s. Calculated digest is [%s] and given digest is [%s]", id, new_digest, digest_val);
status = AXIS2_FAILURE;
}
/*FREE*/
AXIS2_FREE(env->allocator, new_digest);
new_digest = NULL;
return status;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
oxs_xml_sig_verify_digests(
const axutil_env_t *env,
oxs_sign_ctx_t *sign_ctx)
{
axis2_status_t status = AXIS2_FAILURE;
axutil_array_list_t *sign_parts = NULL;
int i = 0;
/*Get the sign_part list*/
sign_parts = oxs_sign_ctx_get_sign_parts(sign_ctx, env);
/*For each and every signature part in sig ctx,*/
for(i = 0; i < axutil_array_list_size(sign_parts, env); i++)
{
oxs_sign_part_t *sign_part = NULL;
/*Get ith sign_part*/
sign_part = (oxs_sign_part_t*)axutil_array_list_get(sign_parts, env, i);
status = oxs_xml_sig_verify_sign_part(env, sign_part);
if(AXIS2_FAILURE == status)
{
return AXIS2_FAILURE;
}
}
return status;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
oxs_xml_sig_verify(
const axutil_env_t *env,
oxs_sign_ctx_t *sign_ctx,
axiom_node_t *signature_node,
axiom_node_t *scope_node)
{
axis2_status_t status = AXIS2_FAILURE;
axiom_node_t *signed_info_node = NULL;
axiom_document_t *doc = NULL;
axis2_char_t *c14n_mtd = NULL;
axis2_char_t *content = NULL;
axis2_char_t *signature_val = NULL;
/*Set operation to verify*/
oxs_sign_ctx_set_operation(sign_ctx, env, OXS_SIGN_OPERATION_VERIFY);
/*Populate the sign_ctx by inspecting the ds:Signature node*/
status = oxs_xml_sig_process_signature_node(env, sign_ctx, signature_node, scope_node);
if(status != AXIS2_SUCCESS)
{
/*Something went wrong while processing the Signature node!!! :(*/
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_SIG_VERIFICATION_FAILED,
"<ds:Signature> node processing failed ");
return AXIS2_FAILURE;
}
/*-----------------------------------------------------------------------------------------*/
/*At this point we have a ready to process signature context. So start verification process*/
/*-----------------------------------------------------------------------------------------*/
/*Verify the integrity of the signed parts by comparing the digest values of each and every reference.*/
status = oxs_xml_sig_verify_digests(env, sign_ctx);
if(AXIS2_FAILURE == status)
{
return AXIS2_FAILURE;
}
else
{
AXIS2_LOG_INFO(env->log, "[oxs][xml_sig] Digests verification SUCCESS ");
}
/*At this point we have compared the digest. Next step is to compare the Signature value */
/*First get the signature value from the context*/
signature_val = oxs_sign_ctx_get_sig_val(sign_ctx, env);
/*Then we apply the C14N for the ds:SignedInfo*/
signed_info_node = oxs_axiom_get_first_child_node_by_name(env, signature_node,
OXS_NODE_SIGNEDINFO, OXS_DSIG_NS, OXS_DS);
/*signed_info_node = oxs_axiom_get_first_child_node_by_name(env, signature_node,
OXS_NODE_SIGNEDINFO, NULL,NULL );*/
c14n_mtd = oxs_sign_ctx_get_c14n_mtd(sign_ctx, env);
doc = axiom_node_get_document(signed_info_node, env);
IF_AXIS2_LOG_DEBUG_ENABLED(env->log)
{
axis2_char_t *node_value = NULL;
node_value = axiom_node_to_string(signed_info_node, env);
AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[rampart] C14N (verif1)= %s ", node_value);
AXIS2_FREE(env->allocator, node_value);
}
oxs_c14n_apply_algo(env, doc, &content, NULL, signed_info_node, c14n_mtd);
AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[oxs][xml_sig] C14N (verif2)=\n\n%s\n\n", content);
/*In the final step we Verify*/
status = oxs_sig_verify(env, sign_ctx, content, signature_val);
AXIS2_FREE(env->allocator, content);
content = NULL;
if(AXIS2_FAILURE == status)
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_SIG_VERIFICATION_FAILED,
"Signature is not valid ");
return AXIS2_FAILURE;
}
else
{
return AXIS2_SUCCESS;
}
}