javacommons/security/src/utils/securityutils.cpp
changeset 21 2a9601315dfc
child 25 9ac0a0a7da70
equal deleted inserted replaced
18:e8e63152f320 21:2a9601315dfc
       
     1 /*
       
     2 * Copyright (c) 2009 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 #include <string.h>
       
    18 #include "securityutils.h"
       
    19 #include "telutils.h"
       
    20 #include "fileutils.h"
       
    21 #include "com_nokia_mj_impl_security_utils_TelUtils.h"
       
    22 
       
    23 using namespace java::security;
       
    24 using namespace std;
       
    25 
       
    26 JNIEXPORT jobject JNICALL Java_com_nokia_mj_impl_security_utils_TelUtils__1getNetworkCodes
       
    27 (JNIEnv * env, jclass)
       
    28 {
       
    29     std::string mcc;
       
    30     std::string mnc;
       
    31     TelUtils * telUtils = TelUtils::createInstance();
       
    32     telUtils->getNetworkCodes(mcc, mnc);
       
    33     delete telUtils;
       
    34     telUtils = NULL;
       
    35     jclass network_codes_class = env->FindClass(
       
    36                                      "com/nokia/mj/impl/security/utils/TelUtils$NetworkCodes");
       
    37     jmethodID network_codes_cid = env->GetMethodID(network_codes_class,"<init>",
       
    38                                   "(Ljava/lang/String;Ljava/lang/String;)V");
       
    39     jstring jmcc = env->NewStringUTF(mcc.c_str());
       
    40     jstring jmnc = env->NewStringUTF(mnc.c_str());
       
    41     jobject network_codes = env->NewObject(
       
    42                                 network_codes_class,
       
    43                                 network_codes_cid,
       
    44                                 jmcc,jmnc);
       
    45     return network_codes;
       
    46 }
       
    47 
       
    48 // Checks if all critical extensions are known. If true and developer
       
    49 // certificates extensions are found as well, it handles them as following:
       
    50 //  - get the list of allowed IMEIs from signing certificate extension
       
    51 //  - get my IMEI
       
    52 //      - check if my IMEI is among the allowed ones
       
    53 //      - get the protection domain binding from signing certificate extension
       
    54 //      - check that protection domain is valid (manufacturer || operator || trusted third party)
       
    55 //      - return the MIDlet to the protection domain
       
    56 bool SecurityUtils::areAllCriticalExtsKnown(X509 *cert)
       
    57 {
       
    58     char EXT_OID[80];
       
    59     X509_EXTENSION *ext;
       
    60     int extCount = X509_get_ext_count(cert);
       
    61     for (int i = 1; i<= extCount; i++)
       
    62     {
       
    63         ext = X509_get_ext(cert, i);
       
    64         if (X509_EXTENSION_get_critical(ext)
       
    65                 && !X509_supported_extension(ext))
       
    66         {
       
    67             // check if the extension is known
       
    68             OBJ_obj2txt(
       
    69                 EXT_OID,
       
    70                 sizeof(EXT_OID),
       
    71                 X509_EXTENSION_get_object(ext),
       
    72                 1 /* use numerical form */);
       
    73             if (!strcmp(EXT_OID, DEVCERT_IMEI_LIST_OID) == 0)
       
    74             {
       
    75                 return false;
       
    76             }
       
    77             // compare my IMEI against the list of IMEI from the certificate extension
       
    78             std::string imei;
       
    79             TelUtils * telUtils = TelUtils::createInstance();
       
    80             telUtils->getImei(imei);
       
    81             delete telUtils;
       
    82             telUtils = NULL;
       
    83             return checkIMEI(ext, imei.c_str());
       
    84         }
       
    85     }
       
    86     return true;
       
    87 }
       
    88 
       
    89 X509 * SecurityUtils::readCert(const char * cert, int len, int type)
       
    90 {
       
    91     X509 *x = NULL;
       
    92     BIO *bio;
       
    93     bio = BIO_new_mem_buf((void *) cert, len);
       
    94     if ((bio))
       
    95     {
       
    96         BIO_set_close(bio, BIO_CLOSE);
       
    97         switch (type)
       
    98         {
       
    99         case PEM:
       
   100             x = PEM_read_bio_X509(bio, 0, 0, 0);
       
   101             break;
       
   102         case DER:
       
   103             x = d2i_X509_bio(bio,NULL);
       
   104             break;
       
   105         }
       
   106         BIO_free(bio);
       
   107     }
       
   108     return x;
       
   109 }
       
   110 
       
   111 char * SecurityUtils::encodePEM(const char *str, int len)
       
   112 {
       
   113     const char PEM_PREFIX[] = "-----BEGIN CERTIFICATE-----\n";
       
   114     const char PEM_SUFFIX[] = "\n-----END CERTIFICATE-----\n";
       
   115 
       
   116     // wrap the lines at 64 characters and add the header and footer
       
   117     // lines (required by OpenSSL)
       
   118     // if the length is multiple of 64 don't add the last \n
       
   119     int prefixLen = sizeof(PEM_PREFIX);
       
   120     int suffixLen = sizeof(PEM_SUFFIX);
       
   121     int new_len = len + prefixLen
       
   122                   + suffixLen + (len/64) /* wrap lines */
       
   123                   + 1 /* the terminating null separator */;
       
   124     if (len%64 == 0)
       
   125     {
       
   126         new_len = new_len - 1;
       
   127     }
       
   128     char * encStr = new char[ new_len ];
       
   129     // add the prefix
       
   130     strncpy(encStr, PEM_PREFIX, prefixLen);
       
   131     // add the actual string
       
   132     int i=0;
       
   133     int k = prefixLen - 1;
       
   134     while (i<len)
       
   135     {
       
   136         encStr[k] = str[i];
       
   137         k++;
       
   138         if ((i + 1)%64 == 0 && i != (len - 1))
       
   139         {
       
   140             // insert a \n
       
   141             encStr[k] = '\n';
       
   142             k++;
       
   143         }
       
   144         i++;
       
   145     }
       
   146     encStr[k] = '\0';
       
   147     // add the suffix
       
   148     strcat(encStr, PEM_SUFFIX);
       
   149     // add the null terminator
       
   150     encStr[new_len - 1] = '\0';
       
   151     return encStr;
       
   152 }
       
   153 
       
   154 char * SecurityUtils::computeDigest1(const char* jarFileName)
       
   155 {
       
   156     FILE    *jarFile;
       
   157     jarFile = fopen(jarFileName, "r");
       
   158     if (jarFile == NULL)
       
   159     {
       
   160         return NULL;
       
   161     }
       
   162     // figure out the len of the file
       
   163     unsigned long len;
       
   164     fseek(jarFile, 0L, SEEK_END);
       
   165     len = ftell(jarFile);
       
   166     fseek(jarFile, 0L, SEEK_SET);
       
   167     // if the size of the file is less than the size of the chunks,
       
   168     // then do the hash calculation in on go
       
   169     unsigned char * computed_digest = new unsigned char[SHA_1_DIGEST_LEN];
       
   170     unsigned char * buf = NULL;
       
   171     if (len > 0 && len <= SHA_1_HASH_CHUNK_LEN)
       
   172     {
       
   173         // do the hash calculation in one go
       
   174         buf = new unsigned char[len];
       
   175         len = fread(buf, sizeof(unsigned char), len, jarFile);
       
   176         if (ferror(jarFile))
       
   177         {
       
   178             // stop right here
       
   179             fclose(jarFile);
       
   180             delete[] buf;
       
   181             buf = NULL;
       
   182             delete[] computed_digest;
       
   183             computed_digest = NULL;
       
   184             return NULL;
       
   185         }
       
   186         fclose(jarFile);
       
   187         SHA1(buf, len, computed_digest);
       
   188         delete[] buf;
       
   189         buf = NULL;
       
   190     }
       
   191     else
       
   192     {
       
   193         // do the hash calculation in chunks
       
   194         SHA_CTX c;
       
   195         SHA1_Init(&c);
       
   196         buf = new unsigned char[SHA_1_HASH_CHUNK_LEN];
       
   197         while ((len = fread(buf, sizeof(unsigned char), SHA_1_HASH_CHUNK_LEN, jarFile)) > 0
       
   198                 && !feof(jarFile) && !ferror(jarFile))
       
   199         {
       
   200             SHA1_Update(&c, buf, len);
       
   201             len = 0;
       
   202         }
       
   203         if (ferror(jarFile))
       
   204         {
       
   205             // stop right here
       
   206             delete[] buf;
       
   207             buf = NULL;
       
   208             delete[] computed_digest;
       
   209             computed_digest = NULL;
       
   210             fclose(jarFile);
       
   211             return NULL;
       
   212         }
       
   213         fclose(jarFile);
       
   214         // the end of file was reached
       
   215         if (len > 0)
       
   216         {
       
   217             // write the leftovers
       
   218             SHA1_Update(&c, buf, len);
       
   219         }
       
   220         SHA1_Final(computed_digest, &c);
       
   221         delete[] buf;
       
   222         buf = NULL;
       
   223     }
       
   224     // format it as hex
       
   225     char * digest = new char[2*SHA_1_DIGEST_LEN + 1];
       
   226     char * tmp = digest;
       
   227     for (int i=0; i<SHA_1_DIGEST_LEN; i++)
       
   228     {
       
   229         sprintf(tmp, "%02X", computed_digest[i]);
       
   230         tmp = tmp + 2;
       
   231     }
       
   232     delete[] computed_digest;
       
   233     computed_digest = NULL;
       
   234     digest[2*SHA_1_DIGEST_LEN] = '\0';
       
   235     tmp = NULL;
       
   236     return digest;
       
   237 }
       
   238 
       
   239 char * SecurityUtils::computeDigest(const char* jarFileName)
       
   240 {
       
   241     char * digest = SecurityUtils::computeDigest1(jarFileName);
       
   242     if (digest == NULL)
       
   243     {
       
   244         // one more try
       
   245         digest = FileUtils::computeDigest(jarFileName);
       
   246     }
       
   247     return digest;
       
   248 }
       
   249 
       
   250 jobject SecurityUtils::getJNICertDetails(JNIEnv * env, const CERT_DETAILS details)
       
   251 {
       
   252     jclass cert_class = env->FindClass(
       
   253                             "com/nokia/mj/impl/security/common/Certificate");
       
   254     jmethodID cert_class_cid = env->GetMethodID(cert_class,"<init>",
       
   255                                "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
       
   256     jstring j_issuer = NULL;
       
   257     if (strlen(details.issuer) > 0)
       
   258     {
       
   259         j_issuer = env->NewStringUTF(details.issuer);
       
   260     }
       
   261     jstring j_subject = NULL;
       
   262     if (strlen(details.subject) > 0)
       
   263     {
       
   264         j_subject = env->NewStringUTF(details.subject);
       
   265     }
       
   266     jstring j_organization = NULL;
       
   267     if (strlen(details.organization) > 0)
       
   268     {
       
   269         j_organization = env->NewStringUTF(details.organization);
       
   270     }
       
   271     jstring j_notAfter =
       
   272         env->NewStringUTF(details.notAfter);
       
   273     jstring j_notBefore =
       
   274         env->NewStringUTF(details.notBefore);
       
   275     jstring j_serial_number =
       
   276         env->NewStringUTF(details.serial_number);
       
   277     jstring j_fingerprint =
       
   278         env->NewStringUTF(details.fingerprint);
       
   279     jobject cert_details = env->NewObject(
       
   280                                cert_class,
       
   281                                cert_class_cid,
       
   282                                j_issuer,j_subject,j_organization, j_notBefore,j_notAfter,j_serial_number,j_fingerprint);
       
   283     return cert_details;
       
   284 }
       
   285 
       
   286 void SecurityUtils::getCertDetails(X509 cert, CERT_DETAILS* details, bool parse_domain_info)
       
   287 {
       
   288     X509_NAME * subject_name = X509_get_subject_name(&cert);
       
   289     details->issuer = new char[512];
       
   290     X509_NAME_oneline(X509_get_issuer_name(&cert),details->issuer,512);
       
   291     details->subject = new char[512];
       
   292     X509_NAME_oneline(subject_name,details->subject,512);
       
   293     details->organization = new char[512];
       
   294     int ret = X509_NAME_get_text_by_NID(subject_name, NID_organizationName, details->organization, 512);
       
   295     if (ret == -1)
       
   296     {
       
   297         details->organization[0] = '\0';
       
   298     }
       
   299     ASN1_GENERALIZEDTIME * gTimeBefore = ASN1_TIME_to_generalizedtime(X509_get_notBefore(&cert), NULL);
       
   300     details->notBefore = new char[15];
       
   301     strncpy(details->notBefore,(const char*)gTimeBefore->data, 14 /* the format is YYYYMMDDHHMMSSZ and we leave the Z out */);
       
   302     details->notBefore[14] = '\0';
       
   303     ASN1_TIME_free(gTimeBefore);
       
   304     ASN1_GENERALIZEDTIME * gTimeAfter = ASN1_TIME_to_generalizedtime(X509_get_notAfter(&cert), NULL);
       
   305     details->notAfter = new char[15];
       
   306     strncpy(details->notAfter,(const char*)gTimeAfter->data, 14 /* the format is YYMMDDHHMMSSZ and we and we leave the Z out */);
       
   307     details->notAfter[14] = '\0';
       
   308     ASN1_TIME_free(gTimeAfter);
       
   309     // serial number
       
   310     ASN1_INTEGER* serial_number = X509_get_serialNumber(&cert);
       
   311     details->serial_number = new char[10];
       
   312     unsigned char * int_serial_number = new unsigned char[20];
       
   313     unsigned char * tmp_serial_number = int_serial_number;
       
   314     int len = i2c_ASN1_INTEGER(serial_number, &tmp_serial_number);
       
   315     if (len > 0)
       
   316     {
       
   317         // format it as hex
       
   318         sprintf(details->serial_number,"%08lX",int_serial_number);
       
   319         details->serial_number[8] = '\0';
       
   320     }
       
   321     delete[] int_serial_number;
       
   322     int_serial_number = NULL;
       
   323     tmp_serial_number = NULL;
       
   324     // fingerprint
       
   325     const EVP_MD * SHA1=EVP_sha1();
       
   326     unsigned int n;
       
   327     unsigned char * digest = new unsigned char[SHA_1_DIGEST_LEN];
       
   328     if (X509_digest(&cert,SHA1,digest,&n))
       
   329     {
       
   330         details->fingerprint = new char[50];
       
   331         char * tmp_fingerprint = NULL;
       
   332         tmp_fingerprint = details->fingerprint;
       
   333         // format it as hex
       
   334         for (int i=0; i<n; i++)
       
   335         {
       
   336             sprintf(tmp_fingerprint, "%02X", digest[i]);
       
   337             tmp_fingerprint = tmp_fingerprint + 2;
       
   338         }
       
   339         details->fingerprint[2*n] = '\0';
       
   340         tmp_fingerprint = NULL;
       
   341     }
       
   342     delete[] digest;
       
   343     digest = NULL;
       
   344     // domain info
       
   345     // initialize the domain info to unknown value
       
   346     details->domain_category = DEVCERT_ANY_DOMAIN;
       
   347     if (parse_domain_info)
       
   348     {
       
   349         ASN1_OBJECT *imei_list_ext_obj = OBJ_txt2obj(DEVCERT_IMEI_LIST_OID, 1);
       
   350         if (X509_get_ext_by_OBJ(&cert, imei_list_ext_obj, -1) != -1)
       
   351         {
       
   352             details->domain_category = DEVCERT_UNKNOWN_DOMAIN;
       
   353         }
       
   354         // the extension carrying the domain info
       
   355         STACK_OF(POLICYINFO) *policiesInfo;
       
   356         POLICYINFO *policyInfo;
       
   357         char POLICY_OID[80];
       
   358         if ((policiesInfo = (STACK_OF(POLICYINFO)*)X509_get_ext_d2i(&cert, NID_certificate_policies, NULL, NULL)) != NULL)
       
   359         {
       
   360             for (int i=0; i<sk_POLICYINFO_num(policiesInfo); i++)
       
   361             {
       
   362                 policyInfo = sk_POLICYINFO_value(policiesInfo, i);
       
   363                 OBJ_obj2txt(POLICY_OID, sizeof(POLICY_OID),
       
   364                             policyInfo->policyid,
       
   365                             1 /* use numerical form */);
       
   366                 if (strcmp(POLICY_OID, DEVCERT_MANUFACTURER_DOMAIN_OID) == 0)
       
   367                 {
       
   368                     details->domain_category = DEVCERT_MANUFACTURER_DOMAIN;
       
   369                     break;
       
   370                 }
       
   371                 else if (strcmp(POLICY_OID, DEVCERT_OPERATOR_DOMAIN_OID) == 0)
       
   372                 {
       
   373                     details->domain_category = DEVCERT_OPERATOR_DOMAIN;
       
   374                     break;
       
   375                 }
       
   376                 else if (strcmp(POLICY_OID, DEVCERT_IDENTIFIEDTHIRDPARTY_DOMAIN_OID) == 0)
       
   377                 {
       
   378                     details->domain_category = DEVCERT_IDENTIFIEDTHIRDPARTY_DOMAIN;
       
   379                     break;
       
   380                 }
       
   381             }
       
   382             // cleanup
       
   383             for (;;)
       
   384             {
       
   385                 POLICYINFO* policyInfo = sk_POLICYINFO_pop(policiesInfo);
       
   386                 if (!policyInfo) break;
       
   387                 POLICYINFO_free(policyInfo);
       
   388             }
       
   389             sk_POLICYINFO_free(policiesInfo);
       
   390         }
       
   391         ASN1_OBJECT_free(imei_list_ext_obj);
       
   392     }
       
   393 }
       
   394 
       
   395 jobjectArray SecurityUtils::getJNIAuthCredentials(JNIEnv * env, vector<AUTH_CREDENTIALS*> all_auth_credentials)
       
   396 {
       
   397     jclass auth_credentials_class = env->FindClass(
       
   398                                         "com/nokia/mj/impl/security/midp/authentication/Credentials");
       
   399     jmethodID cid = env->GetMethodID(auth_credentials_class,"<init>",
       
   400                                      "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILcom/nokia/mj/impl/security/common/Certificate;)V");
       
   401 
       
   402     jobjectArray result = env->NewObjectArray(all_auth_credentials.size(), auth_credentials_class, NULL);
       
   403     if (result != NULL)
       
   404     {
       
   405         for (int i=0; i<all_auth_credentials.size(); i++)
       
   406         {
       
   407             jobject signing_cert = SecurityUtils::getJNICertDetails(env, *(all_auth_credentials[i]->signing_cert));
       
   408             delete[] all_auth_credentials[i]->signing_cert->issuer;
       
   409             all_auth_credentials[i]->signing_cert->issuer = NULL;
       
   410             delete[] all_auth_credentials[i]->signing_cert->subject;
       
   411             all_auth_credentials[i]->signing_cert->subject = NULL;
       
   412             delete[] all_auth_credentials[i]->signing_cert->organization;
       
   413             all_auth_credentials[i]->signing_cert->organization = NULL;
       
   414             delete[] all_auth_credentials[i]->signing_cert->notBefore;
       
   415             all_auth_credentials[i]->signing_cert->notBefore = NULL;
       
   416             delete[] all_auth_credentials[i]->signing_cert->notAfter;
       
   417             all_auth_credentials[i]->signing_cert->notAfter = NULL;
       
   418             delete[] all_auth_credentials[i]->signing_cert->serial_number;
       
   419             all_auth_credentials[i]->signing_cert->serial_number = NULL;
       
   420             delete[] all_auth_credentials[i]->signing_cert->fingerprint;
       
   421             all_auth_credentials[i]->signing_cert->fingerprint = NULL;
       
   422             delete all_auth_credentials[i]->signing_cert;
       
   423             all_auth_credentials[i]->signing_cert = NULL;
       
   424             jstring j_jar_hash_value =
       
   425                 env->NewStringUTF(all_auth_credentials[i]->jar_hash);
       
   426             jstring j_root_hash_value =
       
   427                 env->NewStringUTF(all_auth_credentials[i]->root_hash);
       
   428             jstring j_protection_domain_name = NULL;
       
   429             if (all_auth_credentials[i]->domain_name != NULL)
       
   430             {
       
   431                 j_protection_domain_name =
       
   432                     env->NewStringUTF(all_auth_credentials[i]->domain_name);
       
   433 
       
   434             }
       
   435             jstring j_protection_domain_category = NULL;
       
   436             if (all_auth_credentials[i]->domain_category != NULL)
       
   437             {
       
   438                 j_protection_domain_category =
       
   439                     env->NewStringUTF(all_auth_credentials[i]->domain_category);
       
   440             }
       
   441             jobject auth_credentials = env->NewObject(
       
   442                                            auth_credentials_class,
       
   443                                            cid,
       
   444                                            j_protection_domain_name,
       
   445                                            j_protection_domain_category,
       
   446                                            j_jar_hash_value,
       
   447                                            j_root_hash_value,
       
   448                                            all_auth_credentials[i]->chain_index,
       
   449                                            signing_cert);
       
   450             delete[] all_auth_credentials[i]->domain_name;
       
   451             all_auth_credentials[i]->domain_name = NULL;
       
   452             delete[] all_auth_credentials[i]->domain_category;
       
   453             all_auth_credentials[i]->domain_category = NULL;
       
   454             delete[] all_auth_credentials[i]->jar_hash;
       
   455             all_auth_credentials[i]->jar_hash = NULL;
       
   456             delete[] all_auth_credentials[i]->root_hash;
       
   457             all_auth_credentials[i]->root_hash = NULL;
       
   458             delete all_auth_credentials[i];
       
   459             all_auth_credentials[i] = NULL;
       
   460             env->SetObjectArrayElement(result, i, auth_credentials);
       
   461         }
       
   462     }
       
   463     all_auth_credentials.clear();
       
   464     return result;
       
   465 }
       
   466 
       
   467 void SecurityUtils::getAuthInfo(JNIEnv* env, jobjectArray authInfos, int authInfoIndex, AUTH_INFO * authInfo)
       
   468 {
       
   469     jboolean isCopy;
       
   470     jobject jAuthInfo = env->GetObjectArrayElement(authInfos, authInfoIndex);
       
   471     jclass authInfoClass = env->GetObjectClass(jAuthInfo);
       
   472     jmethodID certChainMethod = env->GetMethodID(
       
   473                                     authInfoClass,"getCertChain", "()[Ljava/lang/String;");
       
   474     jobjectArray certChain = (jobjectArray)env->CallObjectMethod(
       
   475                                  jAuthInfo, certChainMethod);
       
   476     jmethodID signatureMethod = env->GetMethodID(
       
   477                                     authInfoClass,"getSignature", "()Ljava/lang/String;");
       
   478     jstring signature = (jstring)env->CallObjectMethod(
       
   479                             jAuthInfo, signatureMethod);
       
   480     authInfo->cert_chain_len = env->GetArrayLength(certChain);
       
   481     authInfo->cert_chain = new char* [authInfo->cert_chain_len];
       
   482     const char * sig(env->GetStringUTFChars(signature, &isCopy));
       
   483     int sig_len = env->GetStringLength(signature);
       
   484     jstring *jcert = new jstring[authInfo->cert_chain_len];
       
   485     for (int i=0; i<authInfo->cert_chain_len; i++)
       
   486     {
       
   487         jcert[i] = (jstring)env->GetObjectArrayElement(certChain, i);
       
   488         const char *str(env->GetStringUTFChars(jcert[i], &isCopy));
       
   489         int len = env->GetStringLength(jcert[i]);
       
   490         authInfo->cert_chain[i] = SecurityUtils::encodePEM(str, len);
       
   491         env->ReleaseStringUTFChars(jcert[i],str);
       
   492     }
       
   493     // do the base64 decoding
       
   494     authInfo->signature = new char[sig_len];
       
   495     BIO * b64 = BIO_new(BIO_f_base64());
       
   496     BIO * mem = BIO_new_mem_buf((char *)sig, sig_len);
       
   497     if ((NULL == b64) || (NULL == mem))
       
   498     {
       
   499         env->ReleaseStringUTFChars(signature,sig);
       
   500         delete[] jcert;
       
   501         jcert = NULL;
       
   502     }
       
   503     BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
       
   504     BIO_set_close(b64, BIO_CLOSE);
       
   505     BIO_set_close(mem, BIO_CLOSE);
       
   506     mem = BIO_push(b64, mem);
       
   507     authInfo->signature_len = BIO_read(mem, authInfo->signature, sig_len);
       
   508     BIO_free_all(mem);
       
   509     env->ReleaseStringUTFChars(signature,sig);
       
   510     delete[] jcert;
       
   511     jcert = NULL;
       
   512 }
       
   513 
       
   514 
       
   515 void SecurityUtils::throw_exception(JNIEnv* env, const char * name)
       
   516 {
       
   517     jclass excClass = env->FindClass("com/nokia/mj/impl/security/midp/authentication/AuthenticationException");
       
   518     jmethodID excCid = env->GetMethodID(excClass,"<init>", "(I)V");
       
   519     jfieldID errCodeID = env->GetStaticFieldID(excClass, name, "I");
       
   520     jthrowable exc = (jthrowable)env->NewObject(excClass, excCid, env->GetStaticIntField(excClass, errCodeID));
       
   521     env->Throw(exc);
       
   522     env->DeleteLocalRef(excClass);
       
   523 }
       
   524 
       
   525 
       
   526 // The list of IMEIs is encoded according to Distinguished Encoding Rule (DER)
       
   527 // of Abstract Syntax Notation One (ASN.1) syntax encapsulating a sequence of
       
   528 // UTF-8 strings. The exact syntax is:
       
   529 // sequence_tag  length_tag  total_imei_length  list_of_imeis
       
   530 // where:
       
   531 //       sequence_tag = 0x30
       
   532 //       length_tag = 0x82 (saying that the length is represented on 2 bytes)
       
   533 //       total_imei_length = hexavalue of (number of imeis multiplied by 17) represented on 2 bytes
       
   534 //       list_of_imei = zero or more if these elements (utf8string_tag  imei_length imei_hexvalue)
       
   535 //       utf8string_tag = 0x0C
       
   536 //       imei_length = hexavalue of length of imei represented on 1 byte (0x0F)
       
   537 //       imei_hexavalue = array of UTF-8 representation of each of the IMEI digit
       
   538 bool SecurityUtils::checkIMEI(const X509_EXTENSION * ext, const char * IMEI)
       
   539 {
       
   540     int SEQUENCE_TAG = 0x30;
       
   541     int LENGTH_TAG = 0x82;
       
   542     int UTF8STRING_TAG = 0x0C;
       
   543     int IMEI_LENGTH = 0x0F;
       
   544     if (ext == NULL
       
   545             || ext->value == NULL
       
   546             || ext->value->data == NULL
       
   547             || ext->value->length <= 4 /* at least sequence_tag length_tag totam_imei_length */)
       
   548     {
       
   549         return false;
       
   550     }
       
   551     unsigned char *imei_list = ext->value->data;
       
   552     int len = ext->value->length;
       
   553     if (imei_list[0] == SEQUENCE_TAG
       
   554             && imei_list[1] == LENGTH_TAG)
       
   555     {
       
   556         long total_imei_length = (((long)imei_list[2] << 8) | ((long)imei_list[3]));
       
   557         // sanity check
       
   558         if (total_imei_length == len - 4)
       
   559         {
       
   560             int imei_index = 4;
       
   561             while (imei_index + 17 <= len
       
   562                     && imei_list[imei_index] == UTF8STRING_TAG
       
   563                     && imei_list[++imei_index] == IMEI_LENGTH)
       
   564             {
       
   565                 imei_index++;
       
   566                 bool found = false;
       
   567                 for (int i=0; i<strlen(IMEI); i++)
       
   568                 {
       
   569                     if (imei_list[imei_index] == '*'
       
   570                             || imei_list[imei_index] == IMEI[i])
       
   571                     {
       
   572                         found = true;
       
   573                     }
       
   574                     else
       
   575                     {
       
   576                         // go to the next IMEI
       
   577                         found = false;
       
   578                         imei_index = imei_index + strlen(IMEI) - i;
       
   579                         break;
       
   580                     }
       
   581                     imei_index++;
       
   582                 }
       
   583                 if (found)
       
   584                 {
       
   585                     return true;
       
   586                 }
       
   587             }
       
   588         }
       
   589     }
       
   590     return false;
       
   591 }