|
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 } |