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