| /* |
| * 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 <openssl_rsa.h> |
| #include <openssl/rand.h> |
| #include <openssl/evp.h> |
| #include <openssl/pem.h> |
| #include <openssl/bio.h> |
| #include <openssl/rand.h> |
| #include <openssl/x509v3.h> |
| #include <oxs_buffer.h> |
| #include <oxs_error.h> |
| #include <openssl_pkcs12.h> |
| #include <openssl_x509.h> |
| #include <oxs_utility.h> |
| |
| /*Usefull when we have BinarySecurityTokn*/ |
| AXIS2_EXTERN axis2_status_t AXIS2_CALL |
| openssl_x509_load_from_buffer(const axutil_env_t *env, |
| axis2_char_t *b64_encoded_buf, |
| X509 **cert) |
| { |
| unsigned char *buff = NULL; |
| BIO *mem = NULL; |
| int ilen = 0; |
| axis2_char_t *formatted_buf = NULL; |
| axis2_char_t *buf_to_format = NULL; |
| int decode_len = 0; |
| int decoded_len = -1; |
| |
| /*We should remove new lines here.*/ |
| buf_to_format = (axis2_char_t*)axutil_strdup(env, b64_encoded_buf); |
| if(buf_to_format) |
| { |
| formatted_buf = oxs_util_get_newline_removed_string(env,buf_to_format); |
| AXIS2_FREE(env->allocator,buf_to_format); |
| buf_to_format = NULL; |
| } |
| else |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_DEFAULT, "New line removed buffer creation failed."); |
| return AXIS2_FAILURE; |
| } |
| |
| decode_len = axutil_base64_decode_len(formatted_buf ); |
| buff = AXIS2_MALLOC(env->allocator, decode_len); |
| ilen = axutil_strlen(formatted_buf); |
| decoded_len = axutil_base64_decode_binary(buff, formatted_buf); |
| |
| AXIS2_FREE(env->allocator, formatted_buf); |
| formatted_buf = NULL; |
| |
| if (decoded_len < 0) |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_DEFAULT, "axutil_base64_decode_binary failed"); |
| return AXIS2_FAILURE; |
| } |
| |
| if ((mem = BIO_new_mem_buf(buff, ilen)) == NULL) |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_DEFAULT, "Cannot create a new memory buffer"); |
| return AXIS2_FAILURE; |
| } |
| |
| *cert = d2i_X509_bio(mem, NULL); |
| /*Free*/ |
| BIO_free(mem); |
| mem = NULL; |
| |
| AXIS2_FREE(env->allocator, buff); |
| buff = NULL; |
| |
| if (*cert == NULL){ |
| return AXIS2_FAILURE; |
| } |
| |
| return AXIS2_SUCCESS; |
| } |
| |
| AXIS2_EXTERN axis2_status_t AXIS2_CALL |
| openssl_x509_load_from_pem(const axutil_env_t *env, |
| axis2_char_t *filename, |
| X509 **cert) |
| { |
| BIO *in = NULL; |
| |
| in = BIO_new_file(filename,"r"); |
| |
| if (!in) |
| { |
| return AXIS2_FAILURE; |
| } |
| /*Read certificate*/ |
| PEM_read_bio_X509(in, cert, NULL, NULL); |
| |
| if (-1 == BIO_reset(in) ){ |
| BIO_free(in); |
| return AXIS2_FAILURE; |
| } |
| |
| if (-1 == BIO_free(in) ){ |
| return AXIS2_FAILURE; |
| } |
| |
| if(!*cert) |
| { |
| return AXIS2_FAILURE; |
| } |
| |
| return AXIS2_SUCCESS; |
| } |
| |
| |
| AXIS2_EXTERN axis2_status_t AXIS2_CALL |
| openssl_x509_load_from_pkcs12(const axutil_env_t *env, |
| axis2_char_t *filename, |
| axis2_char_t *password, |
| X509 **cert, |
| EVP_PKEY **pkey, |
| STACK_OF(X509) **ca) |
| { |
| PKCS12 *p12 = NULL; |
| axis2_status_t status = AXIS2_FAILURE; |
| |
| /*Load*/ |
| status = openssl_pkcs12_load(env, filename, &p12); |
| if(AXIS2_FAILURE == status){ |
| return AXIS2_FAILURE; |
| } |
| /*Parse*/ |
| status = openssl_pkcs12_parse(env, password, p12, pkey, |
| cert, |
| ca); |
| if(AXIS2_FAILURE == status){ |
| return AXIS2_FAILURE; |
| } |
| /*Free*/ |
| status = openssl_pkcs12_free(env, p12); |
| if(AXIS2_FAILURE == status){ |
| return AXIS2_FAILURE; |
| } |
| |
| return AXIS2_SUCCESS; |
| } |
| |
| AXIS2_EXTERN axis2_status_t AXIS2_CALL |
| openssl_x509_load_certificate(const axutil_env_t *env, |
| openssl_x509_format_t format, |
| axis2_char_t *filename, |
| axis2_char_t *password, |
| X509 **cert) |
| { |
| axis2_status_t status = AXIS2_FAILURE; |
| |
| if(OPENSSL_X509_FORMAT_PEM == format){ |
| /*Load from PEM*/ |
| status = openssl_x509_load_from_pem(env, filename, cert); |
| if(AXIS2_FAILURE == status){ |
| return AXIS2_FAILURE; |
| } |
| }else if(OPENSSL_X509_FORMAT_PKCS12 == format){ |
| /*Load from PKCS12*/ |
| EVP_PKEY *pkey = NULL; |
| STACK_OF(X509) *ca = NULL; |
| status = openssl_x509_load_from_pkcs12(env, filename, password, cert, &pkey, &ca); |
| if(AXIS2_FAILURE == status){ |
| return AXIS2_FAILURE; |
| } |
| }else if(OPENSSL_X509_FORMAT_DER == format){ |
| /*Load from DER*/ |
| |
| }else{ |
| /*Unspported*/ |
| } |
| return AXIS2_SUCCESS; |
| } |
| |
| |
| /* |
| * Here we take data in btwn |
| -----BEGIN CERTIFICATE----- |
| -----END CERTIFICATE----- |
| */ |
| |
| AXIS2_EXTERN axis2_char_t *AXIS2_CALL |
| openssl_x509_get_cert_data(const axutil_env_t *env, |
| X509 *cert) |
| { |
| axis2_char_t *unformatted = NULL; |
| axis2_char_t *core_tail = NULL; |
| axis2_char_t *core = NULL; |
| axis2_char_t *res = NULL; |
| axis2_char_t *buffer = NULL; |
| |
| unformatted = openssl_x509_get_info(env, OPENSSL_X509_INFO_DATA_CERT, cert); |
| core_tail = axutil_strstr(unformatted, "\n"); |
| res = axutil_strstr(core_tail,"-----END"); |
| res[0] = '\0'; |
| core = (axis2_char_t*)axutil_strdup(env, core_tail); |
| if(core) |
| { |
| buffer = oxs_util_get_newline_removed_string(env, core); |
| AXIS2_FREE(env->allocator, core); |
| AXIS2_FREE(env->allocator, unformatted); |
| unformatted = NULL; |
| core = NULL; |
| return buffer; |
| }else{ |
| return NULL; |
| } |
| } |
| |
| |
| AXIS2_EXTERN int AXIS2_CALL |
| openssl_x509_get_serial( |
| const axutil_env_t *env, |
| X509 *cert) |
| { |
| axis2_char_t *serial = NULL; |
| int no = 0; |
| |
| /*WARN: Do not use the serial number without converting it to the integer.*/ |
| serial = (axis2_char_t*)i2s_ASN1_INTEGER(NULL, X509_get_serialNumber(cert)); |
| if(serial) |
| { |
| no = atoi(serial); |
| OPENSSL_free(serial); |
| serial = NULL; |
| return no; |
| } |
| else |
| { |
| return -1; |
| } |
| } |
| |
| AXIS2_EXTERN unsigned long AXIS2_CALL |
| openssl_x509_get_subject_name_hash(const axutil_env_t *env, |
| X509 *cert) |
| { |
| unsigned long l = 0; |
| l=X509_subject_name_hash(cert); |
| return l; |
| } |
| |
| AXIS2_EXTERN axis2_status_t AXIS2_CALL |
| openssl_x509_get_pubkey(const axutil_env_t *env, |
| X509 *cert, |
| EVP_PKEY **pubkey) |
| { |
| *pubkey = X509_get_pubkey(cert); |
| return AXIS2_SUCCESS; |
| } |
| |
| AXIS2_EXTERN axis2_char_t *AXIS2_CALL |
| openssl_x509_get_subject_key_identifier(const axutil_env_t *env, |
| X509 *cert) |
| { |
| X509_EXTENSION *ext; |
| ASN1_OCTET_STRING *key_id = NULL; |
| int index = 0; |
| EVP_ENCODE_CTX ctx; |
| int len, ret; |
| char buf[1000]; |
| char output[100]; |
| axis2_char_t *ski = NULL; |
| |
| /*Get ext by ID*/ |
| index = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1); |
| if (index < 0) { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_DEFAULT, |
| "The extenension index of NID_subject_key_identifier is not valid"); |
| return NULL; |
| } |
| /*Get the extension*/ |
| ext = X509_get_ext(cert, index); |
| if (ext == NULL) { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_DEFAULT, |
| "The extension for NID_subject_key_identifier is NULL"); |
| return NULL; |
| } |
| /*Subject Key Identifier*/ |
| key_id = (ASN1_OCTET_STRING *)X509V3_EXT_d2i(ext); |
| if (key_id == NULL) { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_DEFAULT, |
| "The SubjectKeyIdentifier is NULL"); |
| return NULL; |
| } |
| memcpy(buf, key_id->data, key_id->length); |
| buf[key_id->length] = 0; |
| |
| EVP_EncodeInit(&ctx); |
| EVP_EncodeUpdate(&ctx, (unsigned char*)output, &len, (unsigned char*)buf, key_id->length); |
| EVP_EncodeFinal(&ctx, (unsigned char*)(output+len), &ret); |
| |
| /*Free key_id*/ |
| M_ASN1_OCTET_STRING_free(key_id); |
| key_id = NULL; |
| |
| ret += len; |
| ski = axutil_strdup(env, output); |
| return ski; |
| } |
| |
| AXIS2_EXTERN axis2_char_t *AXIS2_CALL |
| openssl_x509_get_info(const axutil_env_t *env, |
| openssl_x509_info_type_t type, |
| X509 *cert) |
| { |
| BIO *out = NULL; |
| unsigned char *data= NULL; |
| axis2_char_t *result = NULL; |
| int n = 0; |
| |
| out = BIO_new(BIO_s_mem()); |
| if(OPENSSL_X509_INFO_SUBJECT==type){ |
| X509_NAME_print_ex(out, X509_get_subject_name(cert), 0, 0); |
| }else if(OPENSSL_X509_INFO_ISSUER == type){ |
| X509_NAME_print_ex(out, X509_get_issuer_name(cert), 0, 0); |
| }else if(OPENSSL_X509_INFO_VALID_FROM == type){ |
| ASN1_TIME_print(out, X509_get_notBefore(cert)); |
| }else if(OPENSSL_X509_INFO_VALID_TO == type){ |
| ASN1_TIME_print(out, X509_get_notAfter(cert)); |
| }else if(OPENSSL_X509_INFO_DATA_CERT == type){ |
| if(!PEM_write_bio_X509_AUX(out, cert)){ |
| return NULL; |
| } |
| }else if(OPENSSL_X509_INFO_FINGER == type){ |
| const EVP_MD *digest = NULL; |
| unsigned char md[EVP_MAX_MD_SIZE]; |
| unsigned int _n = 0; |
| |
| digest = EVP_sha1();/*If we use EVP_md5(); here we can get the digest from md5. */ |
| if(X509_digest(cert,digest,md,&_n)) |
| { |
| /*BIO_printf(out, "%s:", OBJ_nid2sn(EVP_MD_type(digest))); |
| int j = 0; |
| for (j=0; j<(int)_n; j++) |
| { |
| BIO_printf (out, "%02X",md[j]); |
| if (j+1 != (int)_n) BIO_printf(out,":"); |
| }*/ |
| /*We need to base64 encode the digest value of the finger print*/ |
| axis2_char_t *encoded_str = NULL; |
| |
| encoded_str = AXIS2_MALLOC(env->allocator, axutil_base64_encode_len(_n)); |
| axutil_base64_encode(encoded_str, (char*)md, SHA_DIGEST_LENGTH); |
| BIO_printf(out, "%s", encoded_str); |
| AXIS2_FREE(env->allocator, encoded_str); |
| } |
| }else if(OPENSSL_X509_INFO_SIGNATURE == type){ |
| int i = 0; |
| unsigned char *s = NULL; |
| |
| n=cert->signature->length; |
| s=cert->signature->data; |
| for (i=0; i<n; i++) |
| { |
| if ( ((i%18) == 0) && (i!=0) ) BIO_printf(out,"\n"); |
| BIO_printf(out,"%02x%s",s[i], (((i+1)%18) == 0)?"":":"); |
| } |
| |
| }else if(OPENSSL_X509_INFO_VERSION == type){ |
| long l = 0.0; |
| |
| l = X509_get_version(cert); |
| BIO_printf (out,"%lu (0x%lx)",l+1,l); |
| }else if(OPENSSL_X509_INFO_PUBKEY == type){ |
| EVP_PKEY *pkey = NULL; |
| |
| pkey=X509_get_pubkey(cert); |
| if (pkey != NULL) |
| { |
| if (pkey->type == EVP_PKEY_RSA){ |
| RSA_print(out,pkey->pkey.rsa,0); |
| }else if (pkey->type == EVP_PKEY_DSA){ |
| DSA_print(out,pkey->pkey.dsa,0); |
| } |
| EVP_PKEY_free(pkey); |
| pkey = NULL; |
| } |
| }else if(OPENSSL_X509_INFO_PUBKEY_ALGO == type){ |
| X509_CINF *ci = NULL; |
| |
| ci = cert->cert_info; |
| i2a_ASN1_OBJECT(out, ci->key->algor->algorithm); |
| } |
| n = BIO_get_mem_data(out, &data); |
| result = axutil_strndup( env, data, n); |
| |
| BIO_free(out); |
| out = NULL; |
| |
| return result; |
| } |
| |
| AXIS2_EXTERN axis2_char_t * AXIS2_CALL |
| openssl_x509_get_common_name( |
| const axutil_env_t *env, |
| X509 *cert) |
| { |
| X509_NAME *subject = NULL; |
| int pos = -1; |
| X509_NAME_ENTRY *entry = NULL; |
| ASN1_STRING *entry_str; |
| BIO *out = NULL; |
| unsigned char *data= NULL; |
| axis2_char_t *result = NULL; |
| int n = 0; |
| |
| out = BIO_new(BIO_s_mem()); |
| subject = X509_get_subject_name(cert); |
| pos = X509_NAME_get_index_by_NID(subject, NID_commonName, -1); |
| |
| if(pos < 0) |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_DEFAULT, |
| "No Common Name in given X509 Certificate!"); |
| return NULL; |
| } |
| |
| if (X509_NAME_get_index_by_NID(subject, NID_commonName, pos) >= 0) |
| { |
| /* Handling multiple common names. */ |
| } |
| |
| if ((entry = X509_NAME_get_entry(subject, pos)) == 0) |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_DEFAULT, |
| "Error occured during when retrieving common name from X509_NAME!"); |
| return NULL; |
| } |
| |
| if ((entry_str = X509_NAME_ENTRY_get_data(entry)) == 0) |
| { |
| oxs_error(env, OXS_ERROR_LOCATION, OXS_ERROR_DEFAULT, |
| "Error occured during when retrieving common name from X509_NAME_ENTRY!"); |
| return NULL; |
| } |
| |
| ASN1_TIME_print(out, entry_str); |
| n = BIO_get_mem_data(out, &data); |
| result = axutil_strndup( env, data, n); |
| |
| BIO_free(out); |
| out = NULL; |
| |
| return result; |
| } |
| |
| AXIS2_EXTERN void AXIS2_CALL |
| openssl_x509_print(const axutil_env_t *env, |
| X509 *cert) |
| { |
| printf("\n*************START PRINTING*****************\n"); |
| printf("OPENSSL_X509_INFO_SUBJECT : %s\n", openssl_x509_get_info(env, OPENSSL_X509_INFO_SUBJECT,cert)); |
| printf("OPENSSL_X509_INFO_ISSUER : %s\n", openssl_x509_get_info(env,OPENSSL_X509_INFO_ISSUER ,cert)); |
| printf("OPENSSL_X509_INFO_VALID_FROM : %s\n", openssl_x509_get_info(env, OPENSSL_X509_INFO_VALID_FROM,cert)); |
| printf("OPENSSL_X509_INFO_VALID_TO : %s\n", openssl_x509_get_info(env,OPENSSL_X509_INFO_VALID_TO ,cert)); |
| printf("OPENSSL_X509_INFO_FINGER : %s\n", openssl_x509_get_info(env,OPENSSL_X509_INFO_FINGER ,cert)); |
| printf("OPENSSL_X509_INFO_SIGNATURE : %s\n", openssl_x509_get_info(env, OPENSSL_X509_INFO_SIGNATURE,cert)); |
| printf("OPENSSL_X509_INFO_VERSION : %s\n", openssl_x509_get_info(env,OPENSSL_X509_INFO_VERSION ,cert)); |
| printf("OPENSSL_X509_INFO_PUBKEY : %s\n", openssl_x509_get_info(env,OPENSSL_X509_INFO_PUBKEY ,cert)); |
| printf("OPENSSL_X509_INFO_PUBKEY_ALGO : %s\n", openssl_x509_get_info(env,OPENSSL_X509_INFO_PUBKEY_ALGO ,cert)); |
| printf("SERIAL : %u\n", openssl_x509_get_serial(env,cert)); |
| printf("PUBKEY : %s\n", openssl_x509_get_cert_data(env,cert)); |
| |
| printf("\n*************END PRINTING********************\n"); |
| |
| |
| } |