blob: df56210c63571086356b0c974d91211589817594 [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 <secconv_security_context_token.h>
#include <axutil_utils_defines.h>
#include <axutil_env.h>
#include <trust_rst.h>
#include <trust_rstr.h>
#include <oxs_buffer.h>
#include <rampart_constants.h>
#include <rampart_context.h>
#include <openssl_hmac.h>
#include <oxs_utility.h>
#include <openssl_util.h>
#include <rampart_handler_util.h>
static security_context_token_t *
rahas_create_security_context_token(
const axutil_env_t *env,
axis2_bool_t server_entropy_needed,
trust_entropy_t *requester_entropy,
int key_size,
oxs_buffer_t **server_secret);
static axis2_status_t
rahas_store_security_context_token(
const axutil_env_t *env,
security_context_token_t *sct,
axis2_msg_ctx_t *msg_ctx);
static axis2_status_t
rahas_validate_issue_request_parameters(
const axutil_env_t *env,
trust_rst_t *rst,
trust_rstr_t *rstr,
axis2_msg_ctx_t *msg_ctx,
int trust_version,
axis2_bool_t client_entropy_needed,
trust_entropy_t** requester_entropy);
static axis2_status_t
rahas_populate_rstr_for_issue_request(
const axutil_env_t *env,
trust_rstr_t *rstr,
int trust_version,
axis2_bool_t client_entropy_needed,
oxs_buffer_t *server_secret,
security_context_token_t *sct,
int key_size);
static axis2_status_t
rahas_get_sts_policy_parameters(
const axutil_env_t *env,
axis2_msg_ctx_t *msg_ctx,
axis2_bool_t *client_entropy_needed,
axis2_bool_t *server_entropy_needed);
/**
* Processes issue request
* @param env pointer to environment struct
* @param rst request security token struct
* @param rstr request security token response struct
* @param msg_ctx message context structure
* @param trust_version Trust specification. Can be TRUST_VERSION_05_02 or TRUST_VERSION_05_12
* @return AXIS2_SUCCESS if processed successfully. AXIS2_FAILURE otherwise.
*/
AXIS2_EXTERN axis2_status_t AXIS2_CALL
rahas_process_issue_request(
const axutil_env_t *env,
trust_rst_t *rst,
trust_rstr_t *rstr,
axis2_msg_ctx_t *msg_ctx,
int trust_version)
{
trust_entropy_t* requester_entropy = NULL;
oxs_buffer_t *server_secret = NULL;
security_context_token_t *sct = NULL;
axis2_bool_t client_entropy_needed = AXIS2_FALSE;
axis2_bool_t server_entropy_needed = AXIS2_FALSE;
int key_size = TRUST_DEFAULT_KEY_SIZE;
/* check whether client entropy and server entropy are needed */
if (rahas_get_sts_policy_parameters(
env, msg_ctx, &client_entropy_needed, &server_entropy_needed) != AXIS2_SUCCESS)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot issue SecurityContextToken because security token service policy "
"could not be found.");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_FAILED,
"The specified request failed", RAMPART_FAULT_TRUST_REQUEST_FAILED, msg_ctx);
return AXIS2_FAILURE;
}
/* validate whether given parameters are ok to proceed */
if(rahas_validate_issue_request_parameters(env, rst, rstr, msg_ctx, trust_version,
client_entropy_needed, &requester_entropy) != AXIS2_SUCCESS)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot issue SecurityContextToken because parameter validation failed.");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_INVALID,
"The request was invalid or malformed", RAMPART_FAULT_TRUST_REQUEST_INVALID, msg_ctx);
return AXIS2_FAILURE;
}
/* Get the size of the key*/
key_size = trust_rst_get_key_size(rst, env);
/* size is not a compulsary field. If missing, we can use default size */
if(key_size <= 0)
{
key_size = TRUST_DEFAULT_KEY_SIZE;
}
/* Create sct and populate it */
sct = rahas_create_security_context_token(
env, server_entropy_needed, requester_entropy, key_size, &server_secret);
if(!sct)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot issue SecurityContextToken because SCT creation failed.");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_FAILED,
"The specified request failed", RAMPART_FAULT_TRUST_REQUEST_FAILED, msg_ctx);
return AXIS2_FAILURE;
}
/* set sct version */
if(trust_version == TRUST_VERSION_05_02)
{
security_context_token_set_is_sc10(sct, env, AXIS2_TRUE);
}
else if(trust_version == TRUST_VERSION_05_12)
{
security_context_token_set_is_sc10(sct, env, AXIS2_FALSE);
}
/* store SCT so that when server needs it, can be extracted. It is the responsibility of the
* storing implementer to switch to global pool if needed */
if(rahas_store_security_context_token(env, sct, msg_ctx) != AXIS2_SUCCESS)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rahas]Cannot store SecurityContextToken.");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_FAILED,
"The specified request failed", RAMPART_FAULT_TRUST_REQUEST_FAILED, msg_ctx);
security_context_token_free(sct, env);
return AXIS2_FAILURE;
}
/* Populate rstr structure */
if (rahas_populate_rstr_for_issue_request(env, rstr, trust_version,
client_entropy_needed, server_secret, sct, key_size) != AXIS2_SUCCESS)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot issue SecurityContextToken because response createion failed.");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_FAILED,
"The specified request failed", RAMPART_FAULT_TRUST_REQUEST_FAILED, msg_ctx);
security_context_token_free(sct, env);
return AXIS2_FAILURE;
}
return AXIS2_SUCCESS;
}
/* this method validates whether rst, rstr, msg_ctx, trust_version are correct. If they are ok,
* it will populate requester_entropy. requester_entropy will be output parameter */
static axis2_status_t
rahas_validate_issue_request_parameters(
const axutil_env_t *env,
trust_rst_t *rst,
trust_rstr_t *rstr,
axis2_msg_ctx_t *msg_ctx,
int trust_version,
axis2_bool_t client_entropy_needed,
trust_entropy_t** requester_entropy)
{
axis2_char_t *token_type = NULL;
axis2_char_t *expected_token_type = NULL;
if(!rst)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Given RequestSecurityToken structure is not valid.");
return AXIS2_FAILURE;
}
if(!rstr)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Given RequestSecurityTokenResponse structure is not valid.");
return AXIS2_FAILURE;
}
if(!msg_ctx)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Given Message context structure is not valid.");
return AXIS2_FAILURE;
}
/* check whether trust version is valid, and if so, get trust version specific constants */
if(trust_version == TRUST_VERSION_05_02)
{
expected_token_type = OXS_VALUE_TYPE_SECURITY_CONTEXT_TOKEN_05_02;
}
else if(trust_version == TRUST_VERSION_05_12)
{
expected_token_type = OXS_VALUE_TYPE_SECURITY_CONTEXT_TOKEN_05_12;
}
else
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Given trust specification version is not valid or not supported.");
return AXIS2_FAILURE;
}
/* check whether token type is valid and can be processed */
token_type = trust_rst_get_token_type(rst, env);
if(!token_type)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rahas]Token type is not given.");
return AXIS2_FAILURE;
}
if(axutil_strcmp(token_type, expected_token_type))
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Given token type [%s] is not valid. Expected token type is [%s]",
token_type, expected_token_type);
return AXIS2_FAILURE;
}
/* check whether client entropy is needed according to policy and whether it is provided */
*requester_entropy = trust_rst_get_entropy(rst, env);
if(client_entropy_needed)
{
if(!*requester_entropy)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Client entropy is expected, but not given by client.");
return AXIS2_FAILURE;
}
}
else
{
if(*requester_entropy)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Client entropy is not expected, but it is given by client.");
return AXIS2_FAILURE;
}
}
return AXIS2_SUCCESS;
}
static security_context_token_t *
rahas_create_security_context_token(
const axutil_env_t *env,
axis2_bool_t server_entropy_needed,
trust_entropy_t *requester_entropy,
int key_size,
oxs_buffer_t **server_secret)
{
axis2_char_t *global_id = NULL;
axis2_char_t *local_id = NULL;
security_context_token_t *sct = NULL;
/* given key size will be in bits. Convert into bytes */
int key_size_in_byte = key_size / 8;
/* we are going to create objects which will be shared among multiple requests. So we have to
* create in global pool */
axutil_allocator_switch_to_global_pool(env->allocator);
/* create security context token */
sct = security_context_token_create(env);
if(!sct)
{
axutil_allocator_switch_to_local_pool(env->allocator);
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot create security context token. Insufficient memory.");
return NULL;
}
/* create global id, local id */
global_id = oxs_util_generate_id(env, SECCONV_GLOBAL_ID_PREFIX);
local_id = axutil_stracat(
env, OXS_LOCAL_REFERENCE_PREFIX, oxs_util_generate_id(env, SECCONV_LOCAL_ID_PREFIX));
/* check whether server secret is needed. If specifically said "server entropy needed" then
* no problem. If not said specifically, and if client entropy is not there, then again we have
* to provide a shared secret */
if((server_entropy_needed) || (!requester_entropy))
{
int server_secret_size = key_size_in_byte;
/* if client entropy is given, our entropy should be half of the size given */
if(requester_entropy)
{
server_secret_size = server_secret_size / 2;
}
*server_secret = oxs_buffer_create(env);
openssl_generate_random_data(env, *server_secret, server_secret_size);
}
/* populate security context token */
security_context_token_set_global_identifier(sct, env, global_id);
security_context_token_set_local_identifier(sct, env, local_id);
if(requester_entropy)
{
axis2_char_t *requester_nonce = NULL;
int requester_entropy_len = 0;
axis2_char_t *decoded_requester_entropy = NULL;
oxs_buffer_t *buffer = NULL;
/* client entropy will be in base64 format. should decode it */
requester_nonce = trust_entropy_get_binary_secret(requester_entropy, env);
requester_entropy_len = axutil_base64_decode_len(requester_nonce);
decoded_requester_entropy = AXIS2_MALLOC(env->allocator, requester_entropy_len);
axutil_base64_decode_binary((unsigned char*)decoded_requester_entropy, requester_nonce);
buffer = oxs_buffer_create(env);
if(server_entropy_needed)
{
/* we have client entropy and server entropy. so shared secret will be combined key */
axis2_char_t *output = NULL;
output = AXIS2_MALLOC(env->allocator, key_size);
openssl_p_hash(env,
(unsigned char*)decoded_requester_entropy, requester_entropy_len,
oxs_buffer_get_data(*server_secret, env), oxs_buffer_get_size(*server_secret, env),
(unsigned char*)output, key_size_in_byte);
oxs_buffer_populate(buffer, env, (unsigned char*)output, key_size_in_byte);
}
else
{
/* we have to use client entropy as the sct shared secret */
oxs_buffer_populate(
buffer, env, (unsigned char*)decoded_requester_entropy, requester_entropy_len);
}
security_context_token_set_secret(sct, env, buffer);
}
else
{
/* we have to use server entropy as the sct shared secret */
security_context_token_set_secret(sct, env, *server_secret);
}
/* we are done with creating the SCT. Now we can switch back to local pool */
axutil_allocator_switch_to_local_pool(env->allocator);
return sct;
}
static axis2_status_t
rahas_populate_rstr_for_issue_request(
const axutil_env_t *env,
trust_rstr_t *rstr,
int trust_version,
axis2_bool_t client_entropy_needed,
oxs_buffer_t *server_secret,
security_context_token_t *sct,
int key_size)
{
axis2_char_t *token_type = NULL;
axis2_char_t *trust_ns_uri = NULL;
axis2_char_t *computed_key_algo = NULL;
/* Get trust version specific constants */
if(trust_version == TRUST_VERSION_05_02)
{
trust_ns_uri = TRUST_WST_XMLNS_05_02;
token_type = OXS_VALUE_TYPE_SECURITY_CONTEXT_TOKEN_05_02;
computed_key_algo = TRUST_COMPUTED_KEY_PSHA1;
security_context_token_set_is_sc10(sct, env, AXIS2_TRUE);
}
else if(trust_version == TRUST_VERSION_05_12)
{
trust_ns_uri = TRUST_WST_XMLNS_05_12;
token_type = OXS_VALUE_TYPE_SECURITY_CONTEXT_TOKEN_05_12;
computed_key_algo = TRUST_COMPUTED_KEY_PSHA1_05_12;
security_context_token_set_is_sc10(sct, env, AXIS2_FALSE);
}
/* We have to populate issue request specific items.
* (1) Token Type
* (2) Attached reference
* (3) Unattached reference
* (4) SCT representation
* (5) Shared secret.
* We are assuming request_type, namespace, etc. are already populated. */
trust_rstr_set_token_type(rstr, env, token_type);
trust_rstr_set_requested_unattached_reference(rstr, env,
security_context_token_get_unattached_reference(sct, env));
trust_rstr_set_requested_attached_reference(rstr, env,
security_context_token_get_attached_reference(sct, env));
trust_rstr_set_requested_security_token(rstr, env,
security_context_token_get_token(sct, env));
/* we have to send the key detail to client.
* (1) If client entropy and server entropy is used, we have to send server entropy and computed
key
* (2) If only server entropy is used, then we have to send entropy as proof token
* (3) If only client entropy is used, then we don't have to send anything.
*/
if((client_entropy_needed) && (server_secret))
{
/* we have to send computed key and entropy */
axis2_char_t *nonce = NULL;
trust_entropy_t* entropy = NULL;
axiom_node_t *computed_key = NULL;
axiom_element_t *computed_key_element = NULL;
axiom_node_t *requested_proof = NULL;
/* if client and server entropy are there, then server entropy will be half the key_size.
* Also, key size is in bits. So, actual server_entropy size is key_size / 16 */
int size = key_size / 16;
trust_rstr_set_key_size(rstr, env, key_size);
nonce = AXIS2_MALLOC(env->allocator, sizeof(char) * (axutil_base64_encode_len(size)+1));
axutil_base64_encode(nonce, (char*)oxs_buffer_get_data(server_secret, env), size);
entropy = trust_entropy_create(env);
trust_entropy_set_binary_secret(entropy, env, nonce);
trust_entropy_set_ns_uri(entropy, env, trust_ns_uri);
trust_entropy_set_binary_secret_type(entropy, env, NONCE);
trust_rstr_set_entropy(rstr, env, entropy);
computed_key = trust_util_computed_key_element(env, trust_ns_uri, NULL);
computed_key_element = axiom_node_get_data_element(computed_key, env);
axiom_element_set_text(computed_key_element, env, computed_key_algo, computed_key);
requested_proof = trust_util_create_requsted_proof_token_element(
env, trust_ns_uri, NULL, computed_key);
trust_rstr_set_requested_proof_token(rstr, env, requested_proof);
}
else if(!client_entropy_needed)
{
/* server key only. so have to send proof token */
trust_rstr_set_requested_proof_token(
rstr, env, security_context_token_get_requested_proof_token(sct, env));
}
return AXIS2_SUCCESS;
}
/* this method uses store_method defined in rampart context to store sct */
static axis2_status_t
rahas_store_security_context_token(
const axutil_env_t *env,
security_context_token_t *sct,
axis2_msg_ctx_t *msg_ctx)
{
axutil_property_t *property = NULL;
axis2_status_t status = AXIS2_SUCCESS;
property = axis2_msg_ctx_get_property(msg_ctx, env, RAMPART_CONTEXT);
if(property)
{
rampart_context_t *rampart_context = NULL;
rampart_context = (rampart_context_t *)axutil_property_get_value(property, env);
if(rampart_context)
{
store_security_context_token_fn store_fn = NULL;
void *user_param = NULL;
store_fn = rampart_context_get_store_security_context_token_fn(rampart_context, env);
user_param = rampart_context_get_security_context_token_user_params(
rampart_context, env);
status = store_fn(env, msg_ctx, security_context_token_get_global_identifier(sct, env),
security_context_token_get_local_identifier(sct, env), sct, user_param);
}
else
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot find rampart context. Cannot store security context token.");
status = AXIS2_FAILURE;
}
}
else
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot find rampart context property. Cannot store security context token.");
status = AXIS2_FAILURE;
}
return status;
}
/* This method checks whether rampart policy has STS related parameters. If so, will extract it */
static axis2_status_t
rahas_get_sts_policy_parameters(
const axutil_env_t *env,
axis2_msg_ctx_t *msg_ctx,
axis2_bool_t *client_entropy_needed,
axis2_bool_t *server_entropy_needed)
{
axutil_property_t *property = NULL;
axis2_status_t status = AXIS2_SUCCESS;
property = axis2_msg_ctx_get_property(msg_ctx, env, RAMPART_CONTEXT);
if(property)
{
rampart_context_t *rampart_context = NULL;
rampart_context = (rampart_context_t *)axutil_property_get_value(property, env);
if(rampart_context)
{
rp_secpolicy_t *sec_policy = NULL;
sec_policy = rampart_context_get_secpolicy(rampart_context, env);
if(sec_policy)
{
rp_trust10_t *trust_policy = NULL;
trust_policy = rp_secpolicy_get_trust10(sec_policy, env);
if(trust_policy)
{
*client_entropy_needed = rp_trust10_get_require_client_entropy(trust_policy, env);
*server_entropy_needed = rp_trust10_get_require_server_entropy(trust_policy, env);
}
else
{
*client_entropy_needed = AXIS2_FALSE;
*server_entropy_needed = AXIS2_FALSE;
}
}
else
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot find security policy related to security context token service "
"from rampart context.");
status = AXIS2_FAILURE;
}
}
else
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot find rampart context. "
"Cannot find policy related to security context token service.");
status = AXIS2_FAILURE;
}
}
else
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot find rampart context property. "
"Cannot find policy related to security context token service.");
status = AXIS2_FAILURE;
}
return status;
}