| /* |
| * 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_ctx.h> |
| #include <oxs_error.h> |
| #include <oxs_buffer.h> |
| #include <oxs_encryption.h> |
| #include <oxs_cipher.h> |
| #include <oxs_iv.h> |
| #include <openssl_cipher_ctx.h> |
| #include <openssl_crypt.h> |
| #include <openssl_constants.h> |
| #include <openssl_rsa.h> |
| #include <openssl_util.h> |
| #include <oxs_key_mgr.h> |
| |
| |
| AXIS2_EXTERN axis2_status_t AXIS2_CALL |
| oxs_encryption_symmetric_crypt(const axutil_env_t *env, |
| oxs_ctx_t *enc_ctx, |
| oxs_buffer_t *input, |
| oxs_buffer_t *result) |
| { |
| openssl_cipher_ctx_t *oc_ctx = NULL; |
| openssl_cipher_property_t *cprop = NULL; |
| axis2_char_t *iv = NULL; |
| axis2_char_t *cipher_name = NULL; |
| axis2_status_t ret = AXIS2_FAILURE; |
| |
| /*Get cipher property*/ |
| cprop = oxs_get_cipher_property_for_url(env, |
| oxs_ctx_get_enc_mtd_algorithm(enc_ctx, env)); |
| if (!cprop) |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_INVALID_DATA, |
| "Cipher property is NULL"); |
| return AXIS2_FAILURE; |
| } |
| /*Get the IV*/ |
| iv = axutil_strndup(env, |
| (axis2_char_t *)oxs_iv_generate_for_algo(env, |
| oxs_ctx_get_enc_mtd_algorithm(enc_ctx, env)), |
| openssl_cipher_property_get_iv_size(cprop, env)); |
| |
| |
| /*Create the openssl context*/ |
| oc_ctx = openssl_cipher_ctx_create(env); |
| if (!oc_ctx) |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_INVALID_DATA, |
| "openssl_cipher_ctx_create failed"); |
| return AXIS2_FAILURE; |
| } |
| |
| /*Set IV*/ |
| ret = openssl_cipher_ctx_set_iv(oc_ctx, env, iv); |
| |
| /*Set key*/ |
| ret = openssl_cipher_ctx_set_key(oc_ctx, env, |
| oxs_ctx_get_key(enc_ctx, env)); |
| |
| /*Set the cipher*/ |
| cipher_name = (axis2_char_t*)openssl_cipher_property_get_name(cprop, env); |
| if (!cipher_name) |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_INVALID_DATA, |
| "oxs_get_cipher failed"); |
| |
| return AXIS2_FAILURE; |
| } |
| |
| ret = openssl_cipher_ctx_set_cipher(oc_ctx, |
| env, |
| (EVP_CIPHER*) |
| openssl_get_evp_cipher_by_name( |
| env, (axis2_char_t*)cipher_name) |
| ); |
| |
| /*Now everything is ready for the en/decryption*/ |
| /*ENCRYPTION*/ |
| if (oxs_ctx_get_operation(enc_ctx, env) == OXS_CTX_OPERATION_ENCRYPT) |
| { |
| axis2_char_t *encoded_str = NULL; |
| int enclen = -1; |
| int encodedlen = -1; |
| oxs_buffer_t *output = NULL; |
| |
| output = oxs_buffer_create(env); |
| |
| /*Encrypt*/ |
| enclen = openssl_bc_crypt(env, oc_ctx, input, output, OPENSSL_ENCRYPT); |
| if (enclen < 0){ |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_ENCRYPT_FAILED, |
| "openssl_block_cipher_crypt FAILED"); |
| return AXIS2_FAILURE; |
| } |
| |
| encodedlen = axutil_base64_encode_len(enclen); |
| encoded_str = AXIS2_MALLOC(env->allocator, encodedlen); |
| ret = axutil_base64_encode_binary(encoded_str, |
| oxs_buffer_get_data(output, env), |
| enclen); |
| if (ret < 0) |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_INVALID_DATA, |
| "axutil_base64_encode_binary failed"); |
| return AXIS2_FAILURE; |
| } |
| |
| /*Attach the result to the result buf*/ |
| ret = oxs_buffer_populate(result, env, (unsigned char*)encoded_str, |
| encodedlen); |
| |
| /*Free*/ |
| oxs_buffer_free(output, env); |
| output = NULL; |
| AXIS2_FREE(env->allocator, encoded_str); |
| encoded_str = NULL; |
| |
| /*DECRYPTION*/ |
| } |
| else if (oxs_ctx_get_operation(enc_ctx, env) == OXS_CTX_OPERATION_DECRYPT) |
| { |
| unsigned char *decoded_data = NULL;/*Can be binary*/ |
| int decoded_len = -1; |
| int enclen = -1; |
| int x=-1; |
| oxs_buffer_t *decoded_buf = NULL; |
| |
| decoded_buf = oxs_buffer_create(env); |
| |
| /*First we need to base64 decode*/ |
| /*x = axutil_base64_decode_len((const char*) |
| oxs_buffer_get_data(input,env));*/ |
| /*x = axutil_strlen(oxs_buffer_get_data(input,env)) + 1;*/ /* decoded length will be less than this*/ |
| x = oxs_buffer_get_size(input, env) + 1; |
| decoded_data = AXIS2_MALLOC(env->allocator, x); |
| decoded_len = axutil_base64_decode_binary(decoded_data, |
| (char*)oxs_buffer_get_data(input, env)); |
| if (decoded_len < 0) |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_DECRYPT_FAILED, |
| "axutil_base64_decode_binary failed"); |
| return AXIS2_FAILURE; |
| } |
| /*Populate decoded (input to the crypto function) buffer*/ |
| ret = oxs_buffer_populate(decoded_buf, env, decoded_data, decoded_len); |
| |
| /*Then we decrypt*/ |
| enclen = openssl_bc_crypt(env, oc_ctx, decoded_buf, result, |
| OPENSSL_DECRYPT); |
| |
| if (enclen < 0) |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_DECRYPT_FAILED, |
| "openssl_block_cipher_crypt FAILED"); |
| return AXIS2_FAILURE; |
| } |
| |
| /*Free*/ |
| oxs_buffer_free(decoded_buf, env); |
| decoded_buf = NULL; |
| AXIS2_FREE(env->allocator, decoded_data); |
| decoded_data = NULL; |
| |
| } |
| else |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_INVALID_DATA, |
| "Invalid operation type %d", |
| oxs_ctx_get_operation(enc_ctx, env)); |
| |
| return AXIS2_FAILURE; |
| } |
| |
| /*FREE*/ |
| openssl_cipher_property_free(cprop, env); |
| cprop = NULL; |
| |
| AXIS2_FREE(env->allocator, iv); |
| iv = NULL; |
| |
| openssl_cipher_ctx_free(oc_ctx, env); |
| oc_ctx = NULL; |
| |
| return AXIS2_SUCCESS; |
| } |
| |
| |
| AXIS2_EXTERN axis2_status_t AXIS2_CALL |
| oxs_encryption_asymmetric_crypt(const axutil_env_t *env, |
| oxs_asym_ctx_t *asym_ctx, |
| oxs_buffer_t *input, |
| oxs_buffer_t *result) |
| { |
| openssl_pkey_t *pkey = NULL; |
| oxs_asym_ctx_operation_t operation = -1; |
| axis2_status_t status = AXIS2_FAILURE; |
| axis2_char_t *algorithm = NULL; |
| axis2_char_t *padding = NULL; |
| |
| algorithm = oxs_asym_ctx_get_algorithm(asym_ctx, env); |
| /* We support RSA v1.5 encryption only. If any other algorithm is |
| * specified, replace it with the proper one |
| if(0 != (axutil_strcmp(OXS_HREF_RSA_PKCS1, algorithm ))) { |
| oxs_asym_ctx_set_algorithm(asym_ctx, env, OXS_HREF_RSA_PKCS1); |
| }*/ |
| |
| /*Set the proper padding for the algorithm*/ |
| if ((axutil_strcmp(OXS_HREF_RSA_OAEP, algorithm)) == 0) |
| { |
| padding = OPENSSL_RSA_PKCS1_OAEP_PADDING; |
| } |
| else if ((axutil_strcmp(OXS_HREF_RSA_PKCS1, algorithm)) == 0) |
| { |
| padding = OPENSSL_RSA_PKCS1_PADDING; |
| } |
| |
| /*Check for the operation and call appropriate method*/ |
| operation = oxs_asym_ctx_get_operation(asym_ctx, env); |
| if (operation == OXS_ASYM_CTX_OPERATION_PUB_ENCRYPT) |
| { |
| axis2_char_t *encoded_str = NULL; |
| oxs_x509_cert_t *x509_cert = NULL; |
| oxs_buffer_t *out_buf = NULL; |
| int enclen = -1; |
| int encodedlen = -1; |
| int ret = -1; |
| |
| /*Operation is PUB ENCRYPT; Get the public key from the context*/ |
| x509_cert = oxs_asym_ctx_get_certificate(asym_ctx, env); |
| if (!x509_cert) |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_INVALID_DATA, |
| "Certificate not set"); |
| return AXIS2_FAILURE; |
| } |
| pkey = oxs_x509_cert_get_public_key(x509_cert, env); |
| |
| /* Encrypt using the public key. Then base64 encode and populate the |
| * buffer |
| */ |
| out_buf = oxs_buffer_create(env); |
| enclen = openssl_rsa_pub_encrypt(env, pkey, padding, input, out_buf); |
| encodedlen = axutil_base64_encode_len(enclen); |
| encoded_str = AXIS2_MALLOC(env->allocator, encodedlen); |
| |
| ret = axutil_base64_encode(encoded_str, |
| (const char *)oxs_buffer_get_data(out_buf, env), enclen); |
| |
| status = oxs_buffer_populate(result, env, |
| (unsigned char*)encoded_str, |
| encodedlen); |
| |
| /*Free*/ |
| oxs_buffer_free(out_buf, env); |
| out_buf = NULL; |
| AXIS2_FREE(env->allocator, encoded_str); |
| encoded_str = NULL; |
| |
| } |
| else if (operation == OXS_ASYM_CTX_OPERATION_PRV_DECRYPT) |
| { |
| unsigned char *decoded_encrypted_str = NULL; |
| oxs_buffer_t *dec_enc_buf = NULL; |
| int ret = -1; |
| int declen = -1; |
| |
| /*Operation id PRV DECRYPT; Get the private key from the context*/ |
| pkey = oxs_asym_ctx_get_private_key(asym_ctx, env); |
| |
| /*Base64 decode first. Then do the decryption and populate the buffer*/ |
| decoded_encrypted_str = |
| AXIS2_MALLOC(env->allocator, |
| axutil_base64_decode_len( |
| (char*)oxs_buffer_get_data(input, env))); |
| |
| ret = axutil_base64_decode_binary(decoded_encrypted_str, |
| (char*)oxs_buffer_get_data(input, env)); |
| |
| dec_enc_buf = oxs_buffer_create(env); |
| oxs_buffer_populate(dec_enc_buf, env, decoded_encrypted_str, ret); |
| declen = openssl_rsa_prv_decrypt(env, pkey, padding, dec_enc_buf, |
| result); |
| /*Free*/ |
| AXIS2_FREE(env->allocator, decoded_encrypted_str); |
| decoded_encrypted_str = NULL; |
| oxs_buffer_free(dec_enc_buf, env); |
| dec_enc_buf = NULL; |
| if (declen < 0) |
| { |
| return AXIS2_FAILURE; |
| } |
| } |
| else |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_INVALID_DATA, |
| "Operation not supported."); |
| return AXIS2_FAILURE; |
| } |
| |
| return AXIS2_SUCCESS; |
| } |