javacommons/security/src/midpauthenticationmoduleimpl.cpp
changeset 21 2a9601315dfc
child 46 4376525cdefb
child 49 35baca0e7a2e
equal deleted inserted replaced
18:e8e63152f320 21:2a9601315dfc
       
     1 /*
       
     2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "javajniutils.h"
       
    20 #include "com_nokia_mj_impl_security_midp_authentication_AuthenticationModule.h"
       
    21 #include "midpauthenticationmodule.h"
       
    22 #include "midpauthenticationmoduleimpl.h"
       
    23 #include "storagehandler.h"
       
    24 #include "securityutils.h"
       
    25 #include "javacertstorehandler.h"
       
    26 #include "securitycommsmessagedefs.h"
       
    27 #include "javastorage.h"
       
    28 #include "javastoragenames.h"
       
    29 #include "logger.h"
       
    30 
       
    31 #include <memory>
       
    32 #include <string>
       
    33 #include <vector>
       
    34 #include <openssl/x509.h>
       
    35 #include <openssl/x509v3.h>
       
    36 #include <openssl/x509_vfy.h>
       
    37 #include <openssl/asn1.h>
       
    38 #include <openssl/err.h>
       
    39 #include <openssl/rsa.h>
       
    40 #include <openssl/sha.h>
       
    41 #include <sys/time.h>
       
    42 #include <string.h>
       
    43 
       
    44 using namespace java::security;
       
    45 using namespace java::storage;
       
    46 using namespace java::util;
       
    47 using namespace std;
       
    48 
       
    49 /* The DER encoding of the algorithm ID for the SHA-1 hash function */
       
    50 const char SHA_1_ALG_FOOTPRINT[] =
       
    51     {0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14};
       
    52 
       
    53 /* forward declarations of local/private methods */
       
    54 static int verify_callback(int, X509_STORE_CTX *);
       
    55 int getErrCode(int);
       
    56 int verifyCertChain(char **, int, const unsigned char *, int, vector<string> CAs, char *, char *, CERT_DETAILS*);
       
    57 
       
    58 JNIEXPORT jobjectArray JNICALL Java_com_nokia_mj_impl_security_midp_authentication_AuthenticationModule__1validateChainsAndSignatures
       
    59 (JNIEnv * env, jobject, jobjectArray authInfos)
       
    60 {
       
    61     // get the roots from JavaCertStore
       
    62     vector<string> CAs;
       
    63     JavaCertStoreHandler::retrieveRootsContents(CAs);
       
    64     if (CAs.size() == 0)
       
    65     {
       
    66         SecurityUtils::throw_exception(env, "CONNECTION_TO_CAPTAIN_FAILED");
       
    67         return NULL;
       
    68     }
       
    69 
       
    70     // validate each of the chains&signatures and
       
    71     jint len = env->GetArrayLength(authInfos);
       
    72     vector<AUTH_CREDENTIALS*> all_auth_credentials;
       
    73     all_auth_credentials.reserve(len);
       
    74     AUTH_CREDENTIALS * auth_credentials = NULL;
       
    75     CERT_DETAILS* details = NULL;
       
    76     AUTH_INFO* authInfo = NULL;
       
    77     char * jar_hash = NULL;
       
    78     char * root_hash = NULL;
       
    79     int validation_result = KDefault;
       
    80     for (int i=0; i<len; i++)
       
    81     {
       
    82         // validate the chain
       
    83         authInfo = new AUTH_INFO();
       
    84         SecurityUtils::getAuthInfo(env, authInfos, i, authInfo);
       
    85         jar_hash = new char[2*SHA_1_DIGEST_LEN + 1];
       
    86         jar_hash[0] = '\0';
       
    87         root_hash = new char[MD5_DIGEST_LEN + 1];
       
    88         root_hash[0] = '\0';
       
    89         details = new CERT_DETAILS();
       
    90         int chain_verification_result = verifyCertChain(
       
    91                                             authInfo->cert_chain, authInfo->cert_chain_len,
       
    92                                             (const unsigned char *)authInfo->signature,
       
    93                                             authInfo->signature_len, CAs, jar_hash,
       
    94                                             root_hash, details);
       
    95         if (chain_verification_result == KCertAndSignatureOk)
       
    96         {
       
    97             validation_result = KCertAndSignatureOk;
       
    98             auth_credentials = new AUTH_CREDENTIALS();
       
    99             auth_credentials->jar_hash = new char[2*SHA_1_DIGEST_LEN + 1];
       
   100             auth_credentials->root_hash = new char[MD5_DIGEST_LEN + 1];
       
   101             memmove(auth_credentials->jar_hash, jar_hash, 2*SHA_1_DIGEST_LEN + 1);
       
   102             memmove(auth_credentials->root_hash, root_hash, MD5_DIGEST_LEN + 1);
       
   103             auth_credentials->chain_index = i+1;
       
   104             auth_credentials->signing_cert = details;
       
   105             all_auth_credentials.push_back(auth_credentials);
       
   106             auth_credentials->predefined_domain_category = details->domain_category;
       
   107             // the domain info is coming shortly
       
   108         }
       
   109         else
       
   110         {
       
   111             delete details;
       
   112             details = NULL;
       
   113             delete[] jar_hash;
       
   114             jar_hash = NULL;
       
   115             delete[] root_hash;
       
   116             root_hash = NULL;
       
   117             // just record the failure of the chain validation
       
   118             if (chain_verification_result > validation_result)
       
   119             {
       
   120                 validation_result = chain_verification_result;
       
   121             }
       
   122         }
       
   123         // release the elements
       
   124         delete[] authInfo->signature;
       
   125         authInfo->signature = NULL;
       
   126         for (int j=0 ; j<authInfo->cert_chain_len; j++)
       
   127         {
       
   128             delete[] authInfo->cert_chain[j];
       
   129             authInfo->cert_chain[j] = NULL;
       
   130         }
       
   131         delete[] authInfo->cert_chain;
       
   132         authInfo->cert_chain = NULL;
       
   133 
       
   134         // free memory
       
   135         delete authInfo;
       
   136         authInfo = NULL;
       
   137     }
       
   138     // release the CAs
       
   139     CAs.clear();
       
   140 
       
   141     // analyze the result of authentication
       
   142     switch (validation_result)
       
   143     {
       
   144     case KDefault:
       
   145         // there were no chains to be validated
       
   146         return NULL;
       
   147     case KCertValidationFailure:
       
   148         SecurityUtils::throw_exception(env, "CERT_VERIFICATION_FAILED");
       
   149         return NULL;
       
   150     case KSignatureVerificationFailure:
       
   151         SecurityUtils::throw_exception(env, "SIG_VERIFICATION_FAILED");
       
   152         return NULL;
       
   153     case KMissingRoot:
       
   154         SecurityUtils::throw_exception(env, "MISSING_ROOT");
       
   155         return NULL;
       
   156     case KCertNotYetValidFailure:
       
   157         SecurityUtils::throw_exception(env, "CERT_NOT_YET_VALID");
       
   158         return NULL;
       
   159     case KCertExpiredFailure:
       
   160         SecurityUtils::throw_exception(env, "CERT_EXPIRED");
       
   161         return NULL;
       
   162     case KSelfSignedCertInChainFailure:
       
   163         SecurityUtils::throw_exception(env, "ROOT_CERT_IN_CHAIN");
       
   164         return NULL;
       
   165     case KUnknownExtendedKeyUsage:
       
   166         SecurityUtils::throw_exception(env, "UNKNOWN_EXT_KEY_USAGE");
       
   167         return NULL;
       
   168     }
       
   169 
       
   170     // try to fill in the domain info for each of the existing credentials
       
   171     int i=0;
       
   172     int domain_mappings = 0;
       
   173     while (i < all_auth_credentials.size())
       
   174     {
       
   175         // init the domain name and category
       
   176         all_auth_credentials[i]->domain_name = NULL;
       
   177         all_auth_credentials[i]->domain_category = NULL;
       
   178         std::string protection_domain_name;
       
   179         std::string protection_domain_category;
       
   180         JavaCertStoreHandler::retrieveRootProtDomainInfo(
       
   181             all_auth_credentials[i]->root_hash,
       
   182             protection_domain_name,
       
   183             protection_domain_category);
       
   184         if (strcmp(protection_domain_name.c_str(),""))
       
   185         {
       
   186             // DeveloperCertificates: if domain_category is manufacturer and we have predefined_domain_category use the predefined one
       
   187             // Get the domain constants from ApplicationInfo&policy
       
   188             if ((strcmp(protection_domain_category.c_str(),"MFD") == 0
       
   189                     && all_auth_credentials[i]->predefined_domain_category == DEVCERT_UNKNOWN_DOMAIN)
       
   190                     || (strcmp(protection_domain_category.c_str(),"OPD") == 0
       
   191                         && all_auth_credentials[i]->predefined_domain_category == DEVCERT_UNKNOWN_DOMAIN))
       
   192             {
       
   193                 i++;
       
   194                 continue;
       
   195             }
       
   196             if ((strcmp(protection_domain_category.c_str(),"MFD") == 0
       
   197                     && (all_auth_credentials[i]->predefined_domain_category == DEVCERT_OPERATOR_DOMAIN
       
   198                         || all_auth_credentials[i]->predefined_domain_category == DEVCERT_IDENTIFIEDTHIRDPARTY_DOMAIN))
       
   199                     || (strcmp(protection_domain_category.c_str(),"OPD") == 0
       
   200                         && all_auth_credentials[i]->predefined_domain_category == DEVCERT_IDENTIFIEDTHIRDPARTY_DOMAIN))
       
   201             {
       
   202                 switch (all_auth_credentials[i]->predefined_domain_category)
       
   203                 {
       
   204                 case DEVCERT_OPERATOR_DOMAIN:
       
   205                     all_auth_credentials[i]->domain_name = new char[strlen("Operator") + 1];
       
   206                     strcpy(all_auth_credentials[i]->domain_name,"Operator");
       
   207                     all_auth_credentials[i]->domain_category = new char[strlen("OPD") + 1];
       
   208                     strcpy(all_auth_credentials[i]->domain_category,"OPD");
       
   209                     break;
       
   210                 case DEVCERT_IDENTIFIEDTHIRDPARTY_DOMAIN:
       
   211                     all_auth_credentials[i]->domain_name = new char[strlen("IdentifiedThirdParty") + 1];
       
   212                     strcpy(all_auth_credentials[i]->domain_name,"IdentifiedThirdParty");
       
   213                     all_auth_credentials[i]->domain_category = new char[strlen("ITPD") + 1];
       
   214                     strcpy(all_auth_credentials[i]->domain_category,"ITPD");
       
   215                     break;
       
   216                 }
       
   217             }
       
   218             else
       
   219             {
       
   220                 all_auth_credentials[i]->domain_name = new char[protection_domain_name.size() + 1 /* for the \n */];
       
   221                 strcpy(all_auth_credentials[i]->domain_name,protection_domain_name.c_str());
       
   222                 all_auth_credentials[i]->domain_category = new char[protection_domain_category.size() + 1 /* for the \n */];
       
   223                 strcpy(all_auth_credentials[i]->domain_category,protection_domain_category.c_str());
       
   224             }
       
   225             domain_mappings++;
       
   226         }
       
   227         i++;
       
   228     }
       
   229 
       
   230     // if no protection domain was found -> throw corresponding exception
       
   231     if (domain_mappings == 0)
       
   232     {
       
   233         SecurityUtils::throw_exception(env, "MISSING_DOMAIN_MAPPING");
       
   234         return NULL;
       
   235     }
       
   236 
       
   237     // send the response
       
   238     return SecurityUtils::getJNIAuthCredentials(env, all_auth_credentials);
       
   239 }
       
   240 
       
   241 JNIEXPORT jstring JNICALL Java_com_nokia_mj_impl_security_midp_authentication_AuthenticationModule__1computeHash
       
   242 (JNIEnv * env, jobject, jstring appJARPath)
       
   243 {
       
   244     jboolean isCopy;
       
   245     const char* app_jar_path(env->GetStringUTFChars(appJARPath, &isCopy));
       
   246     char * jar_hash_value = SecurityUtils::computeDigest(app_jar_path);
       
   247     env->ReleaseStringUTFChars(appJARPath, app_jar_path);
       
   248     if (jar_hash_value != NULL)
       
   249     {
       
   250         jstring hash = env->NewStringUTF(jar_hash_value);
       
   251         delete[] jar_hash_value;
       
   252         jar_hash_value = NULL;
       
   253         return hash;
       
   254     }
       
   255     return NULL;
       
   256 }
       
   257 
       
   258 JNIEXPORT jobject JNICALL Java_com_nokia_mj_impl_security_midp_authentication_AuthenticationModule__1parseCertificate
       
   259 (JNIEnv * env, jobject, jstring rawCertificate)
       
   260 {
       
   261     int len = env->GetStringLength(rawCertificate);
       
   262     jboolean isCopy;
       
   263     const char* raw_cert(env->GetStringUTFChars(rawCertificate, &isCopy));
       
   264     if (len == 0 || raw_cert == NULL)
       
   265     {
       
   266         return NULL;
       
   267     }
       
   268     char * encoded_cert = SecurityUtils::encodePEM(raw_cert, len);
       
   269     if (encoded_cert == NULL)
       
   270     {
       
   271         return NULL;
       
   272     }
       
   273     env->ReleaseStringUTFChars(rawCertificate, raw_cert);
       
   274     X509 * x509_cert = SecurityUtils::readCert(encoded_cert, strlen(encoded_cert), PEM);
       
   275     delete[] encoded_cert;
       
   276     encoded_cert = NULL;
       
   277     if (x509_cert != NULL)
       
   278     {
       
   279         CERT_DETAILS * details = new CERT_DETAILS();
       
   280         SecurityUtils::getCertDetails(*x509_cert, details, false /* don't parse domain info */);
       
   281         delete x509_cert;
       
   282         x509_cert = NULL;
       
   283         jobject cert_details = SecurityUtils::getJNICertDetails(env, *details);
       
   284         delete[] details->issuer;
       
   285         details->issuer = NULL;
       
   286         delete[] details->subject;
       
   287         details->subject = NULL;
       
   288         delete[] details->organization;
       
   289         details->organization = NULL;
       
   290         delete[] details->notBefore;
       
   291         details->notBefore = NULL;
       
   292         delete[] details->notAfter;
       
   293         details->notAfter = NULL;
       
   294         delete[] details->serial_number;
       
   295         details->serial_number = NULL;
       
   296         delete[] details->fingerprint;
       
   297         details->fingerprint = NULL;
       
   298         delete details;
       
   299         details = NULL;
       
   300         return cert_details;
       
   301     }
       
   302     return NULL;
       
   303 }
       
   304 
       
   305 JNIEXPORT jobject JNICALL Java_com_nokia_mj_impl_security_midp_authentication_AuthenticationModule__1getRootCertificate
       
   306 (JNIEnv * env, jobject, jstring jRootHash)
       
   307 {
       
   308     // get the certificate content from JavaCertStore
       
   309     std::wstring rootHash = JniUtils::jstringToWstring(env, jRootHash);
       
   310     std::string rootContent;
       
   311     long long len;
       
   312     JavaCertStoreHandler::retrieveRootContent(rootHash, &len, rootContent);
       
   313     X509* root = SecurityUtils::readCert((char *)rootContent.c_str(), len  , DER);
       
   314     if (root != NULL)
       
   315     {
       
   316         CERT_DETAILS * details = new CERT_DETAILS();
       
   317         SecurityUtils::getCertDetails(*root, details, false /* don't parse domain info */);
       
   318         delete root;
       
   319         root = NULL;
       
   320         jobject root_details = SecurityUtils::getJNICertDetails(env, *details);
       
   321         delete[] details->issuer;
       
   322         details->issuer = NULL;
       
   323         delete[] details->subject;
       
   324         details->subject = NULL;
       
   325         delete[] details->organization;
       
   326         details->organization = NULL;
       
   327         delete[] details->notBefore;
       
   328         details->notBefore = NULL;
       
   329         delete[] details->notAfter;
       
   330         details->notAfter = NULL;
       
   331         delete[] details->serial_number;
       
   332         details->serial_number = NULL;
       
   333         delete[] details->fingerprint;
       
   334         details->fingerprint = NULL;
       
   335         delete details;
       
   336         details = NULL;
       
   337         return root_details;
       
   338     }
       
   339 
       
   340     // return the prased cert to java
       
   341     return NULL;
       
   342 }
       
   343 
       
   344 OS_EXPORT void MIDPAuthenticationModuleImpl::getCertChains(
       
   345     const Uid& aUid,
       
   346     std::list<std::string>& aChains)
       
   347 {
       
   348     auto_ptr<StorageHandler> storageHandler(new StorageHandler());
       
   349     list<int> indexes;
       
   350     storageHandler->readValidCerts(aUid, indexes);
       
   351 
       
   352     JavaStorageEntry attr;
       
   353     JavaStorageApplicationEntry_t entry;
       
   354 
       
   355     attr.setEntry(ID, aUid.toString());
       
   356     entry.insert(attr);
       
   357 
       
   358     auto_ptr<JavaStorage> js(JavaStorage::createInstance());
       
   359     JavaStorageApplicationList_t foundApps;
       
   360 
       
   361     try
       
   362     {
       
   363         js->open();
       
   364         js->search(APPLICATION_PACKAGE_ATTRIBUTES_TABLE, entry, foundApps);
       
   365         js->close();
       
   366     }
       
   367     catch (JavaStorageException& aJse)
       
   368     {
       
   369         ELOG1(EJavaStorage, "CertChains: %s", aJse.toString().c_str());
       
   370     }
       
   371 
       
   372     entry.clear();
       
   373 
       
   374     list<int>::const_iterator iter;
       
   375 
       
   376     for (iter = indexes.begin(); iter != indexes.end(); iter++)
       
   377     {
       
   378 
       
   379         string chain("");
       
   380         storageHandler->getChainFromIndex(foundApps, (*iter), chain);
       
   381 
       
   382         if (chain.size() > 0)
       
   383         {
       
   384             aChains.push_back(chain);
       
   385         }
       
   386     }
       
   387 }
       
   388 
       
   389 MIDPAuthenticationModuleImpl::MIDPAuthenticationModuleImpl()
       
   390 {
       
   391 }
       
   392 
       
   393 int verifyCertChain(char **cert_chain, int no_certs,
       
   394                     const unsigned char * sig, int sig_len,
       
   395                     vector<string> CAs, char * jar_hash,
       
   396                     char * root_hash, CERT_DETAILS* details)
       
   397 {
       
   398     X509 *end_entity_cert;
       
   399     X509_STORE_CTX *x509_ctx = NULL;
       
   400     X509_STORE *x509_store = NULL;
       
   401     STACK_OF(X509) *validated_certs_st = sk_X509_new_null();
       
   402     STACK_OF(X509) *roots_certs_st = sk_X509_new_null();
       
   403     RSA * rsakey = NULL;
       
   404     unsigned char * plainSig = NULL;
       
   405     int ret_code = KCertAndSignatureOk;
       
   406 
       
   407     // Calling OpenSSL_add_all_algorithms() links in all algorithms: as a result a statically linked executable can be quite large. Pick up the supported algorithms only
       
   408     OpenSSL_add_all_algorithms();
       
   409 
       
   410     // get the end entity certificate
       
   411     end_entity_cert = SecurityUtils::readCert(cert_chain[0], strlen(cert_chain[0]), PEM);
       
   412 
       
   413     while (true)
       
   414     {
       
   415         // add certs 1.. into the STACK
       
   416         for (int i=1; i<no_certs; i++)
       
   417         {
       
   418             X509 *x = SecurityUtils::readCert(cert_chain[i], strlen(cert_chain[i]), PEM);
       
   419             if (!x)
       
   420             {
       
   421                 ret_code = getErrCode(ERR_get_error());
       
   422                 break;
       
   423             }
       
   424             sk_X509_push(validated_certs_st,x);
       
   425         }
       
   426 
       
   427         // create the cerificate storing object
       
   428         x509_store = X509_STORE_new();
       
   429         if (!(x509_store))
       
   430         {
       
   431             ret_code = getErrCode(ERR_get_error());
       
   432             break;
       
   433         }
       
   434 
       
   435         // load the CAs
       
   436         for (int i=0; i<CAs.size(); i++)
       
   437         {
       
   438             X509 *x = SecurityUtils::readCert((char *)CAs[i].c_str(), CAs[i].size(), DER);
       
   439             sk_X509_push(roots_certs_st,x);
       
   440             X509_STORE_add_cert(x509_store, x);
       
   441         }
       
   442 
       
   443         // create and initialize X509 vertification context
       
   444         x509_ctx = X509_STORE_CTX_new();
       
   445         if (!(x509_ctx))
       
   446         {
       
   447             ret_code = getErrCode(ERR_get_error());
       
   448             break;
       
   449         }
       
   450 
       
   451         if (X509_STORE_CTX_init(x509_ctx, x509_store, end_entity_cert, validated_certs_st)
       
   452                 != 1)
       
   453         {
       
   454             ret_code = getErrCode(ERR_get_error());
       
   455             break;
       
   456         }
       
   457 
       
   458         struct timeval tv;
       
   459         int i = gettimeofday(&tv, NULL);
       
   460         X509_STORE_CTX_set_time(x509_ctx, X509_V_FLAG_USE_CHECK_TIME, tv.tv_sec);
       
   461         // set the callback for validation - needed for the critical extension
       
   462         // used by developer certificates
       
   463         X509_STORE_CTX_set_verify_cb(x509_ctx, verify_callback);
       
   464 
       
   465         // verify certificate
       
   466         if (X509_verify_cert(x509_ctx) != 1)
       
   467         {
       
   468             ret_code = getErrCode(X509_STORE_CTX_get_error(x509_ctx));
       
   469             break;
       
   470         }
       
   471         // verify the extended key usage: it must point to id-kp-codeSigning (RFC3280 code signing)
       
   472         // or 1.3.6.1.4.1.94.1.49.1.2.2.3 (Nokia Java Code Signing Extension)
       
   473         EXTENDED_KEY_USAGE *extKeyUsage;
       
   474         if ((extKeyUsage=(EXTENDED_KEY_USAGE*)X509_get_ext_d2i(end_entity_cert, NID_ext_key_usage, NULL, NULL)) != NULL)
       
   475         {
       
   476             bool extKeyUsageKnown = false;
       
   477             char EXT_KEY_USAGE_OID[80];
       
   478             for (i = 0; i < sk_ASN1_OBJECT_num(extKeyUsage); i++)
       
   479             {
       
   480                 ASN1_OBJECT *usage = sk_ASN1_OBJECT_value(extKeyUsage,i);
       
   481                 OBJ_obj2txt(EXT_KEY_USAGE_OID,
       
   482                             sizeof(EXT_KEY_USAGE_OID),
       
   483                             usage,
       
   484                             1 /* use numerical form */);
       
   485                 if (strcmp(EXT_KEY_USAGE_OID, X509_CODE_SIGNING_OID) == 0
       
   486                         || strcmp(EXT_KEY_USAGE_OID, NOKIA_CODE_SIGNING_OID) == 0)
       
   487                 {
       
   488                     extKeyUsageKnown = true;
       
   489                     break;
       
   490                 }
       
   491             }
       
   492             sk_ASN1_OBJECT_pop_free(extKeyUsage, ASN1_OBJECT_free);
       
   493             if (!extKeyUsageKnown)
       
   494             {
       
   495                 ret_code = KUnknownExtendedKeyUsage;
       
   496                 break;
       
   497             }
       
   498         }
       
   499 
       
   500         // compute the root hash value if requested
       
   501         sprintf(root_hash,"%08lX",X509_issuer_name_hash(x509_ctx->current_issuer));
       
   502         // add the '\0'
       
   503         root_hash[MD5_DIGEST_LEN] = '\0';
       
   504 
       
   505         // 1. get the public key of the signing cert
       
   506         // 2. decode the provided signature using the signing cert's public key
       
   507         // 3. parse the digest/decrypted signature
       
   508         EVP_PKEY *pkey = X509_get_pubkey(end_entity_cert);
       
   509         rsakey = EVP_PKEY_get1_RSA(pkey);
       
   510         EVP_PKEY_free(pkey);
       
   511         plainSig = new unsigned char[RSA_size(rsakey) * 2];
       
   512         int digest_len = RSA_public_decrypt(sig_len, sig, plainSig, rsakey, RSA_PKCS1_PADDING);
       
   513         if (digest_len != (sizeof(SHA_1_ALG_FOOTPRINT) + SHA_1_DIGEST_LEN))
       
   514         {
       
   515             ret_code = KSignatureVerificationFailure;
       
   516             break;
       
   517         }
       
   518         if (memcmp(SHA_1_ALG_FOOTPRINT,
       
   519                    (const char *)plainSig,
       
   520                    sizeof(SHA_1_ALG_FOOTPRINT)))
       
   521         {
       
   522             ret_code = KSignatureVerificationFailure;
       
   523             break;
       
   524         }
       
   525         // save the plainSig into jar_hash
       
   526         char * tmp_jar_hash = NULL;
       
   527         tmp_jar_hash = jar_hash;
       
   528         // format it as hex
       
   529         for (int i=0; i<SHA_1_DIGEST_LEN; i++)
       
   530         {
       
   531             sprintf(tmp_jar_hash, "%02X", *(plainSig + sizeof(SHA_1_ALG_FOOTPRINT) + i));
       
   532             tmp_jar_hash = tmp_jar_hash + 2;
       
   533         }
       
   534         // add the '\0'
       
   535         jar_hash[2*SHA_1_DIGEST_LEN] = '\0';
       
   536         tmp_jar_hash = NULL;
       
   537         break;
       
   538     }
       
   539 
       
   540     // cleanup
       
   541     RSA_free(rsakey);
       
   542     delete[] plainSig;
       
   543     plainSig = NULL;
       
   544     EVP_cleanup();
       
   545     if (NULL != x509_ctx)
       
   546     {
       
   547         X509_STORE_CTX_free(x509_ctx);
       
   548     }
       
   549     X509_STORE_free(x509_store);
       
   550     for (;;)
       
   551     {
       
   552         X509* x = sk_X509_pop(validated_certs_st);
       
   553         if (!x) break;
       
   554         X509_free(x);
       
   555     }
       
   556     sk_X509_free(validated_certs_st);
       
   557     for (;;)
       
   558     {
       
   559         X509* x = sk_X509_pop(roots_certs_st);
       
   560         if (!x) break;
       
   561         X509_free(x);
       
   562     }
       
   563     sk_X509_free(roots_certs_st);
       
   564 
       
   565     // if things are ok, save the cert_details
       
   566     if (end_entity_cert != NULL && ret_code == KCertAndSignatureOk)
       
   567     {
       
   568         SecurityUtils::getCertDetails(*end_entity_cert, details, true /* parse domain info */);
       
   569     }
       
   570     X509_free(end_entity_cert);
       
   571 
       
   572     return ret_code;
       
   573 }
       
   574 
       
   575 static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
       
   576 {
       
   577     int    err;
       
   578     err = X509_STORE_CTX_get_error(ctx);
       
   579     if (!preverify_ok)
       
   580     {
       
   581         switch (err)
       
   582         {
       
   583         case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
       
   584             if (SecurityUtils::areAllCriticalExtsKnown(X509_STORE_CTX_get_current_cert(ctx)))
       
   585             {
       
   586                 return !preverify_ok;
       
   587             }
       
   588             break;
       
   589         case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
       
   590             return !preverify_ok;
       
   591         }
       
   592     }
       
   593     return preverify_ok;
       
   594 }
       
   595 
       
   596 int getErrCode(int x509_err_code)
       
   597 {
       
   598     // Needed to handle other error codes?
       
   599     switch (x509_err_code)
       
   600     {
       
   601     case X509_V_ERR_CERT_NOT_YET_VALID:
       
   602         return KCertNotYetValidFailure;
       
   603     case X509_V_ERR_CERT_HAS_EXPIRED:
       
   604         return KCertExpiredFailure;
       
   605     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
       
   606     case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
       
   607         return KSelfSignedCertInChainFailure;
       
   608     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
       
   609         return KMissingRoot;
       
   610     default:
       
   611         return KCertValidationFailure;
       
   612     }
       
   613 }