blob: 4f9387c84150c508a343edd5da0a0121dd45ddd9 [file] [log] [blame]
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed 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_utils.h>
#include <oxs_ctx.h>
#include <oxs_error.h>
#include <oxs_enc_engine.h>
#include <rampart_crypto_engine.h>
#include <oxs_token_encrypted_data.h>
#include <oxs_token_encrypted_key.h>
#include <oxs_token_encryption_method.h>
#include <oxs_token_data_reference.h>
#include <oxs_token_cipher_data.h>
#include <oxs_token_cipher_value.h>
#include <oxs_token_key_info.h>
#include <oxs_token_key_name.h>
#include <oxs_key.h>
#include <rampart_action.h>
#include <rampart_constants.h>
#include <oxs_token_reference_list.h>
#include <axis2_array_list.h>
#include <oxs_axiom.h>
typedef struct rampart_crypto_engine_impl
{
rampart_crypto_engine_t engine;
}
rampart_crypto_engine_impl_t;
#define AXIS2_INTF_TO_IMPL(engine) ((rampart_crypto_engine_impl_t *)engine)
/*******************Function Headers ****************************/
static void
rampart_crypto_engine_init_ops(
rampart_crypto_engine_t *engine);
/*Public function*/
axis2_status_t AXIS2_CALL
rampart_crypto_engine_free(
rampart_crypto_engine_t *engine,
const axis2_env_t *env);
axis2_status_t AXIS2_CALL
rampart_crypto_engine_encrypt_message(
rampart_crypto_engine_t *engine,
const axis2_env_t *env,
axis2_msg_ctx_t *msg_ctx,
rampart_actions_t *actions,
axiom_soap_envelope_t *soap_envelope ,
axiom_node_t *sec_node);
axis2_status_t AXIS2_CALL
rampart_crypto_engine_decrypt_message(
rampart_crypto_engine_t *engine,
const axis2_env_t *env,
axis2_msg_ctx_t *msg_ctx,
rampart_actions_t *actions,
axiom_soap_envelope_t *soap_envelope ,
axiom_node_t *sec_node);
/*****************End of function headers ****************************/
rampart_crypto_engine_t *AXIS2_CALL
rampart_crypto_engine_create(
const axis2_env_t *env)
{
rampart_crypto_engine_impl_t *engine_impl = NULL;
AXIS2_ENV_CHECK(env, NULL);
engine_impl = (rampart_crypto_engine_impl_t *) AXIS2_MALLOC(env->allocator,
sizeof(rampart_crypto_engine_impl_t));
if (NULL == engine_impl)
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
return NULL;
}
engine_impl->engine.ops = AXIS2_MALLOC(env->allocator,
sizeof(rampart_crypto_engine_ops_t));
if (NULL == engine_impl->engine.ops)
{
rampart_crypto_engine_free(&(engine_impl->engine), env);
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
return NULL;
}
/** initialize ops */
rampart_crypto_engine_init_ops(&(engine_impl->engine));
return &(engine_impl->engine);
}
static void
rampart_crypto_engine_init_ops(
rampart_crypto_engine_t *engine)
{
engine->ops->decrypt_message = rampart_crypto_engine_decrypt_message;
engine->ops->encrypt_message = rampart_crypto_engine_encrypt_message;
engine->ops->free = rampart_crypto_engine_free;
}
axis2_status_t AXIS2_CALL
rampart_crypto_engine_free(
rampart_crypto_engine_t *engine,
const axis2_env_t *env)
{
rampart_crypto_engine_impl_t *engine_impl = NULL;
AXIS2_ENV_CHECK(env, AXIS2_FAILURE);
engine_impl = AXIS2_INTF_TO_IMPL(engine);
if (engine->ops)
{
AXIS2_FREE(env->allocator, engine->ops);
engine->ops = NULL;
}
if (engine_impl)
{
AXIS2_FREE(env->allocator, engine_impl);
engine_impl = NULL;
}
return AXIS2_SUCCESS;
}
axis2_status_t AXIS2_CALL
rampart_crypto_engine_encrypt_message(
rampart_crypto_engine_t *engine,
const axis2_env_t *env,
axis2_msg_ctx_t *msg_ctx,
rampart_actions_t *actions,
axiom_soap_envelope_t *soap_envelope ,
axiom_node_t *sec_node)
{
axis2_status_t ret = AXIS2_FAILURE;
axiom_node_t *node_to_enc = NULL;
axiom_node_t *body_node = NULL;
/*EncryptedData variables*/
axiom_node_t *enc_data_node = NULL;
axiom_node_t *enc_mtd_node = NULL;
axiom_node_t *key_info_node = NULL;
axiom_node_t *key_name_node = NULL;
axiom_node_t *cv_node = NULL;
axiom_node_t *cd_node = NULL;
axiom_node_t *enc_key_ref_list_node = NULL;
axiom_node_t *enc_key_data_ref_node = NULL;
/*EncryptedKey varaibles*/
axiom_node_t *enc_key_node = NULL;
axiom_node_t *enc_key_enc_mtd_node = NULL;
axiom_node_t *enc_key_key_info_node = NULL;
axiom_node_t *enc_key_key_name_node = NULL;
axiom_node_t *enc_key_cv_node = NULL;
axiom_node_t *enc_key_cd_node = NULL;
axiom_soap_body_t *body = NULL;
axis2_char_t *str_to_enc = NULL;
oxs_ctx_t * enc_ctx = NULL;
oxs_key_t *sessionkey = NULL;
oxs_buffer_t *session_key_buf_plain = NULL;
oxs_buffer_t *session_key_buf_encrypted = NULL;
axis2_char_t* uuid = NULL;
oxs_enc_engine_t *enc_engine = NULL;
rampart_crypto_engine_impl_t *engine_impl = NULL;
axiom_node_t *removed_node = NULL;
axis2_char_t* tmp_str = NULL;
AXIS2_ENV_CHECK(env, AXIS2_FAILURE);
engine_impl = AXIS2_INTF_TO_IMPL(engine);
/*Generate the session key*/
sessionkey = oxs_key_create_key(env);
if (!sessionkey)
{
oxs_error(ERROR_LOCATION, OXS_ERROR_ENCRYPT_FAILED,
"Session key generate failed");
return AXIS2_FAILURE;
}
/*Generate a random key for the encryption session*/
ret = OXS_KEY_FOR_ALGO(sessionkey, env, RAMPART_ACTIONS_GET_ENC_SYM_ALGO(actions, env));
ret = OXS_KEY_SET_NAME(sessionkey, env, "sessionkey");
ret = OXS_KEY_SET_USAGE(sessionkey, env, OXS_KEY_USAGE_ENCRYPT);
/*printf("\nSession Key is %s", OXS_KEY_GET_DATA(sessionkey,env)); */
body = AXIOM_SOAP_ENVELOPE_GET_BODY(soap_envelope, env);
body_node = AXIOM_SOAP_BODY_GET_BASE_NODE(body, env);
/*TODO Get the node to be encrypted. As per encryptionParts in the OutflowSecurity*/
/*TODO Generate uuid for the EncryptedDataNode*/
uuid = "EncDataId-34526";
/*If non is specified we encrypt the first element of the Body element*/
if (!node_to_enc)
{
node_to_enc = AXIOM_NODE_GET_FIRST_CHILD(body_node, env);
}
str_to_enc = AXIOM_NODE_TO_STRING(node_to_enc, env);
/*Build the template*/
tmp_str = AXIOM_NODE_TO_STRING(AXIOM_NODE_GET_PARENT(node_to_enc, env), env) ;
enc_data_node = oxs_token_build_encrypted_data_element(env,
AXIOM_NODE_GET_PARENT(node_to_enc, env),
OXS_TypeEncElement,
uuid);
enc_mtd_node = oxs_token_build_encryption_method_element(env, enc_data_node, RAMPART_ACTIONS_GET_ENC_SYM_ALGO(actions, env));
key_info_node = oxs_token_build_key_info_element(env, enc_data_node);
key_name_node = oxs_token_build_key_name_element(env, key_info_node, OXS_KEY_GET_NAME(sessionkey, env));
cd_node = oxs_token_build_cipher_data_element(env, enc_data_node);
cv_node = oxs_token_build_cipher_value_element(env, cd_node, NULL); /*We pass NULL here OMXMLSEC will populate this*/
/*Build the encryption ctx*/
enc_ctx = oxs_ctx_create(env);
/*Set the key*/
OXS_CTX_SET_KEY(enc_ctx, env, sessionkey);
/*printf("\nSession_key for encryption = %s\n", OXS_KEY_GET_DATA(sessionkey, env));*/
printf("\nString for encryption = %s\n", str_to_enc);
/*Hand the template over to OMXMLSEC*/
enc_engine = oxs_enc_engine_create(env);
ret = OXS_ENC_ENGINE_ENCRYPT_TEMPLATE(enc_engine, env, enc_data_node, str_to_enc, enc_ctx);
if (ret == AXIS2_FAILURE)
{
oxs_error(ERROR_LOCATION, OXS_ERROR_ENCRYPT_FAILED,
"Template encryption failed");
return AXIS2_FAILURE;
}
else
{
/*printf("Encryption template is \n %s", AXIOM_NODE_TO_STRING(enc_data_node, env));*/
}
/*Here u have the public key file name or the key store name. Right now we support only the key file name.
The meaning is totally wrong but for the moment we have to live with this*/
session_key_buf_plain = oxs_buffer_create(env);
ret = OXS_BUFFER_POPULATE(session_key_buf_plain, env,
OXS_KEY_GET_DATA(sessionkey, env),
OXS_KEY_GET_SIZE(sessionkey, env));
session_key_buf_encrypted = oxs_buffer_create(env);
ret = OXS_ENC_ENGINE_PUB_KEY_ENCRYPT_DATA(enc_engine, env, session_key_buf_plain,
session_key_buf_encrypted,
RAMPART_ACTIONS_GET_ENC_PROP_FILE(actions, env));
if (ret == AXIS2_FAILURE)
{
oxs_error(ERROR_LOCATION, OXS_ERROR_ENCRYPT_FAILED,
"oxs_pubkey_encrypt_data failed");
return ret;
}
/*Create the key info*/
enc_key_node = oxs_token_build_encrypted_key_element(env, sec_node);
/*return AXIS2_SUCCESS;*/ /*TODO remove: This is here to test the SOAP HEADER problem while attaching enc_mtd_node*/
tmp_str = AXIOM_NODE_TO_STRING(AXIOM_NODE_GET_PARENT(sec_node, env), env) ;
tmp_str = RAMPART_ACTIONS_GET_ENC_KT_ALGO(actions, env);
enc_key_enc_mtd_node = oxs_token_build_encryption_method_element(env, enc_key_node, RAMPART_ACTIONS_GET_ENC_KT_ALGO(actions, env));
enc_key_key_info_node = oxs_token_build_key_info_element(env, enc_key_node);
enc_key_key_name_node = oxs_token_build_key_name_element(env, enc_key_key_info_node, "hard-coded-key-name");
enc_key_cd_node = oxs_token_build_cipher_data_element(env, enc_key_node);
enc_key_cv_node = oxs_token_build_cipher_value_element(env, enc_key_cd_node,
(axis2_char_t*)OXS_BUFFER_GET_DATA(session_key_buf_encrypted, env));
enc_key_ref_list_node = oxs_token_build_reference_list_element(env, enc_key_node);
/*TODO If there are multiple elements encrypted by the same session key, enqueue those here*/
enc_key_data_ref_node = (axiom_node_t*)oxs_token_build_data_reference_element(env, enc_key_ref_list_node, uuid);
/*Remove the encrypted node*/
removed_node = AXIOM_NODE_DETACH(node_to_enc, env);
if (!removed_node)
{
oxs_error(ERROR_LOCATION, OXS_ERROR_ENCRYPT_FAILED,
"Detaching encrypyted node failed");
return AXIS2_FAILURE;
}
/*Now arrange this encrypted nodes in a suitable manner to the envelope*/
/*FREE*/
/*oxs_ctx_free_ctx(enc_ctx); */
return ret;
}
axis2_status_t AXIS2_CALL
rampart_crypto_engine_decrypt_message(
rampart_crypto_engine_t *engine,
const axis2_env_t *env,
axis2_msg_ctx_t *msg_ctx,
rampart_actions_t *actions,
axiom_soap_envelope_t *soap_envelope ,
axiom_node_t *sec_node)
{
axiom_node_t *enc_data_node = NULL;
axiom_node_t *parent_of_enc_node = NULL;
axiom_node_t *body_node = NULL;
axiom_node_t *decrypted_node = NULL;
axiom_node_t *ref_list_node = NULL;
axiom_soap_body_t *body = NULL;
axis2_char_t *decrypted_data = NULL;
oxs_ctx_t * enc_ctx = NULL;
axiom_node_t *enc_key_node = NULL;
oxs_key_t *session_key = NULL;
oxs_key_t *prv_key = NULL;
axis2_array_list_t *uuid_list = NULL;
oxs_enc_engine_t *enc_engine = NULL;
rampart_crypto_engine_impl_t *engine_impl = NULL;
axis2_status_t ret = AXIS2_FAILURE;
axis2_char_t *temp_str = NULL;
AXIS2_ENV_CHECK(env, AXIS2_FAILURE);
engine_impl = AXIS2_INTF_TO_IMPL(engine);
body = AXIOM_SOAP_ENVELOPE_GET_BODY(soap_envelope, env);
body_node = AXIOM_SOAP_BODY_GET_BASE_NODE(body, env);
/*TODO Get the Encrypted key*/
enc_key_node = (axiom_node_t*)oxs_axiom_get_first_child_node_by_name(env, sec_node, OXS_NodeEncryptedKey, NULL, NULL);
/*Create a private key and use to extract the session key*/
temp_str = RAMPART_ACTIONS_GET_DEC_PROP_FILE(actions, env) ;
prv_key = oxs_key_create_key(env);
ret = OXS_KEY_POPULATE(prv_key, env, NULL,
RAMPART_ACTIONS_GET_DEC_PROP_FILE(actions, env) ,
0, OXS_KEY_USAGE_DECRYPT);
/*We support only one Encrypted Key element at the moment*/
session_key = oxs_key_create_key(env);
enc_engine = oxs_enc_engine_create(env);
ret = OXS_ENC_ENGINE_GET_ENCRYPTED_KEY(enc_engine, env, enc_key_node, prv_key , session_key);
if (ret == AXIS2_FAILURE)
{
oxs_error(ERROR_LOCATION, OXS_ERROR_DECRYPT_FAILED,
"Cannot get the encrypted key");
return ret;
}
/*Ohh yeah... now we got the seesion key, which is used encrypt data referred by the reference list*/
ref_list_node = (axiom_node_t*)oxs_axiom_get_first_child_node_by_name(env, enc_key_node, OXS_NodeReferenceList, NULL, NULL);
if (!ref_list_node)
{
oxs_error(ERROR_LOCATION, OXS_ERROR_DECRYPT_FAILED,
"Cannot get the ReferenceList node");
return ret;
}
uuid_list = oxs_token_get_reference_list_data(env, ref_list_node);
/*TODO Get the encrypted node(s). Right now we support only one. To support more than one EncryptedData element use the uuid_list*/
enc_data_node = (axiom_node_t*)oxs_axiom_get_first_child_node_by_name(env, body_node, OXS_NodeEncryptedData, NULL, NULL);
/*TODO We assume that the very first element of bpody is encrypted data.
This might be different if a sub element is encrypted*/
/*Build the encryption ctx*/
enc_ctx = oxs_ctx_create(env);
/*Set the key*/
OXS_CTX_SET_KEY(enc_ctx, env, session_key);
ret = OXS_ENC_ENGINE_DECRYPT_TEMPLATE(enc_engine, env, enc_data_node, &decrypted_data, enc_ctx);
if (ret == AXIS2_FAILURE)
{
oxs_error(ERROR_LOCATION, OXS_ERROR_DECRYPT_FAILED,
"oxs_enc_decrypt_template failed");
return ret;
}
else
{
printf("\nDecrypted data is \n %s\n\n", decrypted_data);
}
/*Now build the node using decrypted data*/
if (!decrypted_data)
{
oxs_error(ERROR_LOCATION, OXS_ERROR_INVALID_DATA,
"No decrypted data");
return AXIS2_FAILURE;
}
parent_of_enc_node = AXIOM_NODE_GET_PARENT(enc_data_node, env);
#if 1
decrypted_node = (axiom_node_t*)oxs_axiom_deserialize_node(env, decrypted_data);
/*Remove enc_node*/
AXIOM_NODE_DETACH(enc_data_node, env);
/*Replace with decrypted node*/
ret = AXIOM_NODE_ADD_CHILD(parent_of_enc_node, env, decrypted_node);
if (ret != AXIS2_SUCCESS)
{
oxs_error(ERROR_LOCATION, OXS_ERROR_INVALID_DATA,
"Attaching decrypted node failed");
return AXIS2_FAILURE;
}
#endif
return ret;
}