blob: 04fa4dd39bb6c878f1c403620a59939b7365d2a4 [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 <openssl/sha.h>
#include <openssl/md5.h>
#include <openssl_hmac.h>
#include <axutil_base64.h>
#include <axis2_util.h>
#include <openssl_constants.h>
#include <oxs_utility.h>
/**
*/
AXIS2_EXTERN axis2_status_t AXIS2_CALL
openssl_hmac_sha1(const axutil_env_t *env,
oxs_key_t *secret,
oxs_buffer_t *input,
oxs_buffer_t *output)
{
HMAC_CTX ctx;
unsigned char hmac[EVP_MAX_MD_SIZE + 1];
unsigned int hashed_len;
if(!secret){
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_SIGN_FAILED,"[oxs][openssl] No key to sign ");
return AXIS2_FAILURE;
}
if(!input){
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_SIGN_FAILED,"[oxs][openssl] Nothing to sign ");
return AXIS2_FAILURE;
}
if(!output){
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_SIGN_FAILED,"[oxs][openssl] The buffer to place signature is NULL ");
return AXIS2_FAILURE;
}
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, oxs_key_get_data(secret, env), oxs_key_get_size(secret, env), EVP_sha1(), NULL);
HMAC_Update(&ctx, oxs_buffer_get_data(input, env), oxs_buffer_get_size(input, env));
HMAC_Final(&ctx, hmac, &hashed_len);
/*Fill the output buffer*/
oxs_buffer_populate(output, env, hmac, hashed_len);
HMAC_cleanup(&ctx);
HMAC_CTX_cleanup(&ctx);
return AXIS2_SUCCESS;
}
/*
* Borrowed from openssl library. Thankyou
*/
AXIS2_EXTERN axis2_status_t AXIS2_CALL
openssl_p_hash(const axutil_env_t *env,
unsigned char *secret,
unsigned int secret_len,
unsigned char *seed,
unsigned int seed_len,
unsigned char *output,
unsigned int output_len)
{
int chunk;
unsigned int j;
HMAC_CTX ctx;
HMAC_CTX ctx_tmp;
unsigned char A1[EVP_MAX_MD_SIZE];
unsigned int A1_len;
/*
char a[5000];
printf("seed_len %d\n", seed_len);
axutil_base64_encode(a, (const char*)seed, seed_len);
printf("seed is %s\n", a);
*/
if(!secret)
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_KEY_DERIVATION_FAILED,"[oxs][openssl] No key to derive ");
return AXIS2_FAILURE;
}
if(!seed)
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_KEY_DERIVATION_FAILED,"[oxs][openssl] lable+seed is empty ");
return AXIS2_FAILURE;
}
if(!output)
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_KEY_DERIVATION_FAILED,"[oxs][openssl] The buffer to place hash is NULL ");
return AXIS2_FAILURE;
}
chunk=EVP_MD_size(EVP_sha1());
HMAC_CTX_init(&ctx);
HMAC_CTX_init(&ctx_tmp);
HMAC_Init_ex(&ctx, secret, secret_len, EVP_sha1(), NULL);
HMAC_Init_ex(&ctx_tmp, secret, secret_len, EVP_sha1(), NULL);
HMAC_Update(&ctx, seed, seed_len);
HMAC_Final(&ctx, A1, &A1_len);
for (;;)
{
HMAC_Init_ex(&ctx, NULL, 0, NULL, NULL); /* re-init */
HMAC_Init_ex(&ctx_tmp, NULL, 0, NULL, NULL); /* re-init */
HMAC_Update(&ctx, A1, A1_len);
HMAC_Update(&ctx_tmp, A1, A1_len);
HMAC_Update(&ctx, seed, seed_len);
if (output_len > chunk)
{
HMAC_Final(&ctx, output, &j);
output+=j;
output_len-=j;
HMAC_Final(&ctx_tmp, A1, &A1_len); /* calc the next A1 value */
}
else /* last one */
{
HMAC_Final(&ctx, A1, &A1_len);
memcpy(output, A1, output_len);
break;
}
}
HMAC_CTX_cleanup(&ctx);
HMAC_CTX_cleanup(&ctx_tmp);
OPENSSL_cleanse(A1,sizeof(A1));
return AXIS2_SUCCESS;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
openssl_p_sha1(const axutil_env_t *env,
oxs_key_t *secret,
axis2_char_t *label,
axis2_char_t *seed,
oxs_key_t *derived_key)
{
oxs_buffer_t *label_and_seed = NULL;
unsigned int key_len = 0;
unsigned char *output = NULL;
axis2_char_t *dk_id = NULL;
axis2_char_t *dk_name = NULL;
axis2_char_t *decoded_seed = NULL;
unsigned int decoded_seed_len = 0;
axis2_status_t status = AXIS2_FAILURE;
unsigned int length;
unsigned int offset;
if(!derived_key)
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_KEY_DERIVATION_FAILED,"[oxs][openssl] derived key is null ");
return status;
}
if (!secret)
{
oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_KEY_DERIVATION_FAILED,"[oxs][openssl] secret is not valid ");
return status;
}
length = oxs_key_get_length(derived_key, env);
offset = oxs_key_get_offset(derived_key, env);
if (!length)
{
length = OPENSSL_DEFAULT_KEY_LEN_FOR_PSHA1;
oxs_key_set_length(derived_key, env, length);
}
label_and_seed = oxs_buffer_create(env);
if((!label) || (!axutil_strlen(label)))
{
label = axutil_stracat(env, OPENSSL_DEFAULT_LABEL_FOR_PSHA1, OPENSSL_DEFAULT_LABEL_FOR_PSHA1);
oxs_key_set_label(derived_key, env, label);
oxs_buffer_append(label_and_seed, env, (unsigned char*)label, axutil_strlen(label));
AXIS2_FREE(env->allocator, label);
label = NULL;
}
else
{
oxs_buffer_append(label_and_seed, env, (unsigned char*)label, axutil_strlen(label));
}
if ((!seed) || (!axutil_strlen(seed)))
{
seed = oxs_util_generate_nonce(env, 16);
oxs_key_set_nonce(derived_key, env, seed);
decoded_seed_len = axutil_base64_decode_len(seed);
decoded_seed = AXIS2_MALLOC(env->allocator, decoded_seed_len);
axutil_base64_decode_binary((unsigned char*)decoded_seed, seed);
AXIS2_FREE(env->allocator, seed);
seed = NULL;
}
else
{
decoded_seed_len = axutil_base64_decode_len(seed);
decoded_seed = AXIS2_MALLOC(env->allocator, decoded_seed_len);
axutil_base64_decode_binary((unsigned char*)decoded_seed, seed);
}
if(decoded_seed)
{
oxs_buffer_append(label_and_seed, env, (unsigned char*)decoded_seed, decoded_seed_len);
AXIS2_FREE(env->allocator, decoded_seed);
decoded_seed = NULL;
}
oxs_key_set_offset(derived_key, env, offset);
key_len = length + offset;
output = (unsigned char*)AXIS2_MALLOC(env->allocator, key_len + 1);
status = openssl_p_hash(env, oxs_key_get_data(secret, env),
oxs_key_get_size(secret, env),
oxs_buffer_get_data(label_and_seed, env),
oxs_buffer_get_size(label_and_seed, env),
output, key_len);
/*output = (unsigned char*)axutil_string_substring_starting_at((axis2_char_t*)output, offset);*/
dk_id = (axis2_char_t*)oxs_util_generate_id(env, (axis2_char_t*)OXS_DERIVED_ID);
dk_name = axutil_stracat(env, OXS_LOCAL_REFERENCE_PREFIX, dk_id);
status = status && oxs_key_populate(derived_key, env, (unsigned char*)(output+offset), dk_name, length, OXS_KEY_USAGE_DERIVED);
AXIS2_FREE(env->allocator, output);
AXIS2_FREE(env->allocator, dk_id);
AXIS2_FREE(env->allocator, dk_name);
oxs_buffer_free(label_and_seed, env);
return status;
}