2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file SignatureValidator.cpp
18 * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
20 * @brief Implementatin of tizen signature validation protocol.
22 #include <vcore/SignatureValidator.h>
23 #include <vcore/CertificateCollection.h>
24 #include <vcore/Certificate.h>
25 #include <vcore/OCSPCertMgrUtil.h>
26 #include <vcore/ReferenceValidator.h>
27 #include <vcore/ValidatorFactories.h>
28 #include <vcore/XmlsecAdapter.h>
29 #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL
30 #include <vcore/CertificateVerifier.h>
33 #include <dpl/log/log.h>
36 const time_t TIMET_DAY = 60 * 60 * 24;
38 const std::string TOKEN_ROLE_AUTHOR_URI =
39 "http://www.w3.org/ns/widgets-digsig#role-author";
40 const std::string TOKEN_ROLE_DISTRIBUTOR_URI =
41 "http://www.w3.org/ns/widgets-digsig#role-distributor";
42 const std::string TOKEN_PROFILE_URI =
43 "http://www.w3.org/ns/widgets-digsig#profile";
45 } // namespace anonymouse
48 static tm _ASN1_GetTimeT(ASN1_TIME* time)
51 const char* str = (const char*) time->data;
54 memset(&t, 0, sizeof(t));
56 if (time->type == V_ASN1_UTCTIME) /* two digit year */
58 t.tm_year = (str[i] - '0') * 10 + (str[i+1] - '0');
63 else if (time->type == V_ASN1_GENERALIZEDTIME) /* four digit year */
67 + (str[i+1] - '0') * 100
68 + (str[i+2] - '0') * 10
73 t.tm_mon = ((str[i] - '0') * 10 + (str[i+1] - '0')) - 1; // -1 since January is 0 not 1.
74 t.tm_mday = (str[i+2] - '0') * 10 + (str[i+3] - '0');
75 t.tm_hour = (str[i+4] - '0') * 10 + (str[i+5] - '0');
76 t.tm_min = (str[i+6] - '0') * 10 + (str[i+7] - '0');
77 t.tm_sec = (str[i+8] - '0') * 10 + (str[i+9] - '0');
79 /* Note: we did not adjust the time based on time zone information */
84 namespace ValidationCore {
86 class SignatureValidator::ImplSignatureValidator {
88 virtual SignatureValidator::Result check(
90 const std::string &widgetContentPath) = 0;
92 virtual SignatureValidator::Result checkList(
94 const std::string &widgetContentPath,
95 const std::list<std::string>& uriList) = 0;
97 explicit ImplSignatureValidator(bool ocspEnable,
100 : m_complianceModeEnabled(complianceMode)
102 #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL
103 m_ocspEnable = ocspEnable;
104 m_crlEnable = crlEnable;
111 virtual ~ImplSignatureValidator(){ }
113 bool checkRoleURI(const SignatureData &data) {
114 std::string roleURI = data.getRoleURI();
116 if (roleURI.empty()) {
117 LogWarning("URI attribute in Role tag couldn't be empty.");
121 if (roleURI != TOKEN_ROLE_AUTHOR_URI && data.isAuthorSignature()) {
122 LogWarning("URI attribute in Role tag does not "
123 "match with signature filename.");
127 if (roleURI != TOKEN_ROLE_DISTRIBUTOR_URI && !data.isAuthorSignature()) {
128 LogWarning("URI attribute in Role tag does not "
129 "match with signature filename.");
135 bool checkProfileURI(const SignatureData &data) {
136 if (TOKEN_PROFILE_URI != data.getProfileURI()) {
138 "Profile tag contains unsupported value in URI attribute " << data.getProfileURI());
144 bool checkObjectReferences(const SignatureData &data) {
145 ObjectList objectList = data.getObjectList();
146 ObjectList::const_iterator iter;
147 for (iter = objectList.begin(); iter != objectList.end(); ++iter) {
148 if (!data.containObjectReference(*iter)) {
149 LogWarning("Signature does not contain reference for object " << *iter);
156 bool m_complianceModeEnabled;
157 #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL
163 class ImplTizenSignatureValidator : public SignatureValidator::ImplSignatureValidator
166 SignatureValidator::Result check(SignatureData &data,
167 const std::string &widgetContentPath);
169 SignatureValidator::Result checkList(SignatureData &data,
170 const std::string &widgetContentPath,
171 const std::list<std::string>& uriList);
172 explicit ImplTizenSignatureValidator(bool ocspEnable,
175 : ImplSignatureValidator(ocspEnable, crlEnable, complianceMode)
178 virtual ~ImplTizenSignatureValidator() {}
181 SignatureValidator::Result ImplTizenSignatureValidator::check(
183 const std::string &widgetContentPath)
185 bool disregard = false;
187 if (!checkRoleURI(data)) {
188 return SignatureValidator::SIGNATURE_INVALID;
191 if (!checkProfileURI(data)) {
192 return SignatureValidator::SIGNATURE_INVALID;
195 // CertificateList sortedCertificateList = data.getCertList();
197 CertificateCollection collection;
198 collection.load(data.getCertList());
200 // First step - sort certificate
201 if (!collection.sort()) {
202 LogWarning("Certificates do not form valid chain.");
203 return SignatureValidator::SIGNATURE_INVALID_CERT_CHAIN;//SIGNATURE_INVALID;
207 if (collection.empty()) {
208 LogWarning("Certificate list in signature is empty.");
209 return SignatureValidator::SIGNATURE_INVALID_CERT_CHAIN;//SIGNATURE_INVALID;
212 CertificateList sortedCertificateList = collection.getChain();
214 // TODO move it to CertificateCollection
215 // Add root CA and CA certificates (if chain is incomplete)
216 sortedCertificateList =
217 OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList);
219 CertificatePtr root = sortedCertificateList.back();
221 // Is Root CA certificate trusted?
222 CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root);
224 LogDebug("Is root certificate from TIZEN_DEVELOPER domain : " << storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER));
225 LogDebug("Is root certificate from TIZEN_TEST domain : " << storeIdSet.contains(CertStoreId::TIZEN_TEST));
226 LogDebug("Is root certificate from TIZEN_VERIFY domain : " << storeIdSet.contains(CertStoreId::TIZEN_VERIFY));
227 LogDebug("Is root certificate from TIZEN_STORE domain : " << storeIdSet.contains(CertStoreId::TIZEN_STORE));
228 LogDebug("Is root certificate from TIZEN_PUBLIC domain : " << storeIdSet.contains(CertStoreId::VIS_PUBLIC));
229 LogDebug("Is root certificate from TIZEN_PARTNER domain : " << storeIdSet.contains(CertStoreId::VIS_PARTNER));
230 LogDebug("Is root certificate from TIZEN_PLATFORM domain : " << storeIdSet.contains(CertStoreId::VIS_PLATFORM));
232 LogDebug("Visibility level is public : " << storeIdSet.contains(CertStoreId::VIS_PUBLIC));
233 LogDebug("Visibility level is partner : " << storeIdSet.contains(CertStoreId::VIS_PARTNER));
234 LogDebug("Visibility level is platform : " << storeIdSet.contains(CertStoreId::VIS_PLATFORM));
236 if (data.isAuthorSignature())
238 if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
240 LogWarning("author-signature.xml has got unrecognized Root CA "
241 "certificate. Signature will be disregarded.");
247 LogDebug("signaturefile name = " << data.getSignatureFileName());
248 if (storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
250 LogError("distributor has author level siganture! Signature will be disregarded.");
251 return SignatureValidator::SIGNATURE_IN_DISTRIBUTOR_CASE_AUTHOR_CERT;//SIGNATURE_INVALID;
255 if (data.getSignatureNumber() == 1)
257 if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM))
259 LogDebug("Root CA for signature1.xml is correct.");
263 LogWarning("signature1.xml has got unrecognized Root CA "
264 "certificate. Signature will be disregarded.");
270 data.setStorageType(storeIdSet);
271 data.setSortedCertificateList(sortedCertificateList);
273 // We add only Root CA certificate because WAC ensure that the rest
274 // of certificates are present in signature files ;-)
275 XmlSec::XmlSecContext context;
276 context.signatureFile = data.getSignatureFileName();
277 context.certificatePtr = root;
279 // Now we should have full certificate chain.
280 // If the end certificate is not ROOT CA we should disregard signature
281 // but still signature must be valid... Aaaaaa it's so stupid...
282 if (!(root->isSignedBy(root))) {
283 LogWarning("Root CA certificate not found. Chain is incomplete.");
284 // context.allowBrokenChain = true;
287 time_t nowTime = time(NULL);
292 ASN1_TIME* notAfterTime = data.getEndEntityCertificatePtr()->getNotAfterTime();
293 ASN1_TIME* notBeforeTime = data.getEndEntityCertificatePtr()->getNotBeforeTime();
295 if (X509_cmp_time(notBeforeTime, &nowTime) > 0 || X509_cmp_time(notAfterTime, &nowTime) < 0)
298 struct tm ta, tb, tc;
301 t = localtime(&nowTime);
303 return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;
305 memset(&tc, 0, sizeof(tc));
307 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", t->tm_year + 1900, t->tm_mon + 1,t->tm_mday );
308 LogDebug("## System's currentTime : " << msg);
309 fprintf(stderr, "## System's currentTime : %s\n", msg);
311 tb = _ASN1_GetTimeT(notBeforeTime);
312 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tb.tm_year + 1900, tb.tm_mon + 1,tb.tm_mday );
313 LogDebug("## certificate's notBeforeTime : " << msg);
314 fprintf(stderr, "## certificate's notBeforeTime : %s\n", msg);
316 ta = _ASN1_GetTimeT(notAfterTime);
317 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", ta.tm_year + 1900, ta.tm_mon + 1,ta.tm_mday );
318 LogDebug("## certificate's notAfterTime : " << msg);
319 fprintf(stderr, "## certificate's notAfterTime : %s\n", msg);
321 if (storeIdSet.contains(CertStoreId::TIZEN_TEST) || storeIdSet.contains(CertStoreId::TIZEN_VERIFY))
323 LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE");
324 fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n");
325 return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;//SIGNATURE_INVALID;
328 int year = (ta.tm_year - tb.tm_year) / 4;
332 tc.tm_year = tb.tm_year;
333 tc.tm_mon = tb.tm_mon + 1;
334 tc.tm_mday = tb.tm_mday;
338 tc.tm_year = ta.tm_year;
339 tc.tm_mon = ta.tm_mon - 1;
340 tc.tm_mday = ta.tm_mday;
344 tc.tm_year = ta.tm_year;
345 tc.tm_mon = ta.tm_mon;
346 tc.tm_mday = ta.tm_mday -1;
350 tc.tm_year = tb.tm_year;
351 tc.tm_mon = tb.tm_mon;
352 tc.tm_mday = tb.tm_mday +1;
358 tc.tm_year = tb.tm_year + year;
359 tc.tm_mon = (tb.tm_mon + ta.tm_mon )/2;
360 tc.tm_mday = (tb.tm_mday + ta.tm_mday)/2;
363 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tc.tm_year + 1900, tc.tm_mon + 1,tc.tm_mday );
364 LogDebug("## cmp cert with validation time : " << msg);
365 fprintf(stderr, "## cmp cert with validation time : %s\n", msg);
367 time_t outCurrent = mktime(&tc);
368 context.validationTime = outCurrent;
369 fprintf(stderr, "## cmp outCurrent time : %ld\n", outCurrent);
370 //return SignatureValidator::SIGNATURE_INVALID;
374 // WAC 2.0 SP-2066 The wrt must not block widget installation
375 // due to expiration of the author certificate.
377 time_t notAfter = data.getEndEntityCertificatePtr()->getNotAfter();
378 time_t notBefore = data.getEndEntityCertificatePtr()->getNotBefore();
382 if (data.isAuthorSignature())
384 // time_t 2038 year bug exist. So, notAtter() cann't check...
386 if (notAfter < nowTime)
388 context.validationTime = notAfter - TIMET_DAY;
389 LogWarning("Author certificate is expired. notAfter...");
393 if (notBefore > nowTime)
395 LogWarning("Author certificate is expired. notBefore time is greater than system-time.");
397 t = localtime(&nowTime);
399 t = localtime(¬Before);
401 context.validationTime = notBefore + TIMET_DAY;
403 t = localtime(&context.validationTime);
407 // WAC 2.0 SP-2066 The wrt must not block widget installation
408 //context.allowBrokenChain = true;
412 if (!data.isAuthorSignature())
414 if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) {
415 LogWarning("Installation break - invalid package!");
416 return SignatureValidator::SIGNATURE_INVALID_HASH_SIGNATURE;//SIGNATURE_INVALID;
419 data.setReference(context.referenceSet);
420 if (!checkObjectReferences(data)) {
421 LogWarning("Failed to check Object References");
422 return SignatureValidator::SIGNATURE_INVALID_HASH_SIGNATURE;//SIGNATURE_INVALID;
425 (void) widgetContentPath;
427 ReferenceValidator fileValidator(widgetContentPath);
428 if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) {
429 LogWarning("Invalid package - file references broken");
430 return SignatureValidator::SIGNATURE_INVALID_NO_HASH_FILE;//SIGNATURE_INVALID;
435 #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL
436 // It is good time to do OCSP check
437 // ocspCheck will throw an exception on any error.
438 // TODO Probably we should catch this exception and add
439 // some information to SignatureData.
440 if (!m_complianceModeEnabled && !data.isAuthorSignature()) {
441 CertificateCollection coll;
442 coll.load(sortedCertificateList);
445 LogDebug("Collection does not contain chain!");
446 return SignatureValidator::SIGNATURE_INVALID_CERT_CHAIN;//SIGNATURE_INVALID;
449 CertificateVerifier verificator(m_ocspEnable, m_crlEnable);
450 VerificationStatus result = verificator.check(coll);
452 if (result == VERIFICATION_STATUS_REVOKED) {
453 return SignatureValidator::SIGNATURE_REVOKED;
456 if (result == VERIFICATION_STATUS_UNKNOWN ||
457 result == VERIFICATION_STATUS_ERROR)
459 #ifdef _OCSP_POLICY_DISREGARD_UNKNOWN_OR_ERROR_CERTS_
467 LogWarning("Signature is disregard. RootCA is not a member of Tizen");
468 return SignatureValidator::SIGNATURE_INVALID_DISTRIBUTOR_CERT;//SIGNATURE_DISREGARD;
470 return SignatureValidator::SIGNATURE_VERIFIED;
473 SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData &data,
474 const std::string &widgetContentPath,
475 const std::list<std::string>& uriList)
477 if(uriList.size() == 0 )
478 LogWarning("checkList >> no hash");
480 bool disregard = false;
482 if (!checkRoleURI(data)) {
483 return SignatureValidator::SIGNATURE_INVALID;
486 if (!checkProfileURI(data)) {
487 return SignatureValidator::SIGNATURE_INVALID;
490 // CertificateList sortedCertificateList = data.getCertList();
492 CertificateCollection collection;
493 collection.load(data.getCertList());
495 // First step - sort certificate
496 if (!collection.sort()) {
497 LogWarning("Certificates do not form valid chain.");
498 return SignatureValidator::SIGNATURE_INVALID;
502 if (collection.empty()) {
503 LogWarning("Certificate list in signature is empty.");
504 return SignatureValidator::SIGNATURE_INVALID;
507 CertificateList sortedCertificateList = collection.getChain();
509 // TODO move it to CertificateCollection
510 // Add root CA and CA certificates (if chain is incomplete)
511 sortedCertificateList =
512 OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList);
514 CertificatePtr root = sortedCertificateList.back();
516 // Is Root CA certificate trusted?
517 CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root);
519 LogDebug("Is root certificate from TIZEN_DEVELOPER domain : " << storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER));
520 LogDebug("Is root certificate from TIZEN_TEST domain : " << storeIdSet.contains(CertStoreId::TIZEN_TEST));
521 LogDebug("Is root certificate from TIZEN_VERIFY domain : " << storeIdSet.contains(CertStoreId::TIZEN_VERIFY));
522 LogDebug("Is root certificate from TIZEN_PUBLIC domain : " << storeIdSet.contains(CertStoreId::VIS_PUBLIC));
523 LogDebug("Is root certificate from TIZEN_PARTNER domain : " << storeIdSet.contains(CertStoreId::VIS_PARTNER));
524 LogDebug("Is root certificate from TIZEN_PLATFORM domain : " << storeIdSet.contains(CertStoreId::VIS_PLATFORM));
526 LogDebug("Visibility level is public : " << storeIdSet.contains(CertStoreId::VIS_PUBLIC));
527 LogDebug("Visibility level is partner : " << storeIdSet.contains(CertStoreId::VIS_PARTNER));
528 LogDebug("Visibility level is platform : " << storeIdSet.contains(CertStoreId::VIS_PLATFORM));
530 if (data.isAuthorSignature())
532 if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
534 LogWarning("author-signature.xml has got unrecognized Root CA "
535 "certificate. Signature will be disregarded.");
538 LogDebug("Root CA for author signature is correct.");
542 LogDebug("signaturefile name = " << data.getSignatureFileName());
544 if (data.getSignatureNumber() == 1)
546 if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM))
548 LogDebug("Root CA for signature1.xml is correct.");
552 LogWarning("signature1.xml has got unrecognized Root CA "
553 "certificate. Signature will be disregarded.");
559 data.setStorageType(storeIdSet);
560 data.setSortedCertificateList(sortedCertificateList);
562 // We add only Root CA certificate because WAC ensure that the rest
563 // of certificates are present in signature files ;-)
564 XmlSec::XmlSecContext context;
565 context.signatureFile = data.getSignatureFileName();
566 context.certificatePtr = root;
568 // Now we should have full certificate chain.
569 // If the end certificate is not ROOT CA we should disregard signature
570 // but still signature must be valid... Aaaaaa it's so stupid...
571 if (!(root->isSignedBy(root))) {
572 LogWarning("Root CA certificate not found. Chain is incomplete.");
573 // context.allowBrokenChain = true;
576 // WAC 2.0 SP-2066 The wrt must not block widget installation
577 // due to expiration of the author certificate.
578 time_t nowTime = time(NULL);
583 ASN1_TIME* notAfterTime = data.getEndEntityCertificatePtr()->getNotAfterTime();
584 ASN1_TIME* notBeforeTime = data.getEndEntityCertificatePtr()->getNotBeforeTime();
587 if (X509_cmp_time(notBeforeTime, &nowTime) > 0 || X509_cmp_time(notAfterTime, &nowTime) < 0)
590 struct tm ta, tb, tc;
593 t = localtime(&nowTime);
595 return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;
597 memset(&tc, 0, sizeof(tc));
599 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", t->tm_year + 1900, t->tm_mon + 1,t->tm_mday );
600 LogDebug("## System's currentTime : " << msg);
601 fprintf(stderr, "## System's currentTime : %s\n", msg);
603 tb = _ASN1_GetTimeT(notBeforeTime);
604 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tb.tm_year + 1900, tb.tm_mon + 1,tb.tm_mday );
605 LogDebug("## certificate's notBeforeTime : " << msg);
606 fprintf(stderr, "## certificate's notBeforeTime : %s\n", msg);
608 ta = _ASN1_GetTimeT(notAfterTime);
609 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", ta.tm_year + 1900, ta.tm_mon + 1,ta.tm_mday );
610 LogDebug("## certificate's notAfterTime : " << msg);
611 fprintf(stderr, "## certificate's notAfterTime : %s\n", msg);
613 if (storeIdSet.contains(CertStoreId::TIZEN_VERIFY))
615 LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE");
616 fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n");
617 return SignatureValidator::SIGNATURE_INVALID;
620 int year = (ta.tm_year - tb.tm_year) / 4;
621 tc.tm_year = tb.tm_year + year;
622 tc.tm_mon = (tb.tm_mon + ta.tm_mon )/2;
623 tc.tm_mday = (tb.tm_mday + ta.tm_mday)/2;
625 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tc.tm_year + 1900, tc.tm_mon + 1,tc.tm_mday );
626 LogDebug("## cmp cert with validation time : " << msg);
627 fprintf(stderr, "## cmp cert with validation time : %s\n", msg);
629 time_t outCurrent = mktime(&tc);
630 context.validationTime = outCurrent;
631 //return SignatureValidator::SIGNATURE_INVALID;
637 time_t notAfter = data.getEndEntityCertificatePtr()->getNotAfter();
638 time_t notBefore = data.getEndEntityCertificatePtr()->getNotBefore();
642 if (data.isAuthorSignature())
644 // time_t 2038 year bug exist. So, notAtter() cann't check...
646 if (notAfter < nowTime)
648 context.validationTime = notAfter - TIMET_DAY;
649 LogWarning("Author certificate is expired. notAfter...");
653 if (notBefore > nowTime)
655 LogWarning("Author certificate is expired. notBefore time is greater than system-time.");
657 t = localtime(&nowTime);
659 t = localtime(¬Before);
661 context.validationTime = notBefore + TIMET_DAY;
663 t = localtime(&context.validationTime);
667 // WAC 2.0 SP-2066 The wrt must not block widget installation
668 //context.allowBrokenChain = true;
671 if(uriList.size() == 0)
673 if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validateNoHash(&context)) {
674 LogWarning("Installation break - invalid package! >> validateNoHash");
675 return SignatureValidator::SIGNATURE_INVALID;
678 else if(uriList.size() != 0)
680 XmlSecSingleton::Instance().setPartialHashList(uriList);
681 if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validatePartialHash(&context)) {
682 LogWarning("Installation break - invalid package! >> validatePartialHash");
683 return SignatureValidator::SIGNATURE_INVALID;
687 data.setReference(context.referenceSet);
688 //if (!checkObjectReferences(data)) {
689 // return SignatureValidator::SIGNATURE_INVALID;
692 (void) widgetContentPath;
694 ReferenceValidator fileValidator(widgetContentPath);
695 if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) {
696 LogWarning("Invalid package - file references broken");
697 return SignatureValidator::SIGNATURE_INVALID;
701 #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL
702 // It is good time to do OCSP check
703 // ocspCheck will throw an exception on any error.
704 // TODO Probably we should catch this exception and add
705 // some information to SignatureData.
706 if (!m_complianceModeEnabled && !data.isAuthorSignature()) {
707 CertificateCollection coll;
708 coll.load(sortedCertificateList);
711 LogDebug("Collection does not contain chain!");
712 return SignatureValidator::SIGNATURE_INVALID;
715 CertificateVerifier verificator(m_ocspEnable, m_crlEnable);
716 VerificationStatus result = verificator.check(coll);
718 if (result == VERIFICATION_STATUS_REVOKED) {
719 return SignatureValidator::SIGNATURE_REVOKED;
722 if (result == VERIFICATION_STATUS_UNKNOWN ||
723 result == VERIFICATION_STATUS_ERROR)
725 #ifdef _OCSP_POLICY_DISREGARD_UNKNOWN_OR_ERROR_CERTS_
733 LogWarning("Signature is disregard. RootCA is not a member of Tizen.");
734 return SignatureValidator::SIGNATURE_DISREGARD;
736 return SignatureValidator::SIGNATURE_VERIFIED;
739 class ImplWacSignatureValidator : public SignatureValidator::ImplSignatureValidator
742 SignatureValidator::Result check(SignatureData &data,
743 const std::string &widgetContentPath);
745 SignatureValidator::Result checkList(SignatureData &data,
746 const std::string &widgetContentPath,
747 const std::list<std::string>& uriList);
748 explicit ImplWacSignatureValidator(bool ocspEnable,
751 : ImplSignatureValidator(ocspEnable, crlEnable, complianceMode)
754 virtual ~ImplWacSignatureValidator() {}
758 SignatureValidator::Result ImplWacSignatureValidator::checkList(
759 SignatureData & /* data */,
760 const std::string & /* widgetContentPath */,
761 const std::list<std::string>& /* uriList */)
763 return SignatureValidator::SIGNATURE_INVALID;
767 SignatureValidator::Result ImplWacSignatureValidator::check(
769 const std::string &widgetContentPath)
771 bool disregard = false;
773 if (!checkRoleURI(data)) {
774 return SignatureValidator::SIGNATURE_INVALID;
777 if (!checkProfileURI(data)) {
778 return SignatureValidator::SIGNATURE_INVALID;
781 // CertificateList sortedCertificateList = data.getCertList();
783 CertificateCollection collection;
784 collection.load(data.getCertList());
786 // First step - sort certificate
787 if (!collection.sort()) {
788 LogWarning("Certificates do not form valid chain.");
789 return SignatureValidator::SIGNATURE_INVALID;
793 if (collection.empty()) {
794 LogWarning("Certificate list in signature is empty.");
795 return SignatureValidator::SIGNATURE_INVALID;
798 CertificateList sortedCertificateList = collection.getChain();
800 // TODO move it to CertificateCollection
801 // Add root CA and CA certificates (if chain is incomplete)
802 sortedCertificateList =
803 OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList);
805 CertificatePtr root = sortedCertificateList.back();
807 // Is Root CA certificate trusted?
808 CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root);
810 LogDebug("Is root certificate from TIZEN_DEVELOPER domain : " << storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER));
811 LogDebug("Is root certificate from TIZEN_TEST domain : " << storeIdSet.contains(CertStoreId::TIZEN_TEST));
812 LogDebug("Is root certificate from TIZEN_VERIFY domain : " << storeIdSet.contains(CertStoreId::TIZEN_VERIFY));
813 LogDebug("Is root certificate from TIZEN_PUBLIC domain : " << storeIdSet.contains(CertStoreId::VIS_PUBLIC));
814 LogDebug("Is root certificate from TIZEN_PARTNER domain : " << storeIdSet.contains(CertStoreId::VIS_PARTNER));
815 LogDebug("Is root certificate from TIZEN_PLATFORM domain : " << storeIdSet.contains(CertStoreId::VIS_PLATFORM));
817 LogDebug("Visibility level is public : " << storeIdSet.contains(CertStoreId::VIS_PUBLIC));
818 LogDebug("Visibility level is partner : " << storeIdSet.contains(CertStoreId::VIS_PARTNER));
819 LogDebug("Visibility level is platform : " << storeIdSet.contains(CertStoreId::VIS_PLATFORM));
821 if (data.isAuthorSignature())
823 if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
825 LogWarning("author-signature.xml has got unrecognized Root CA "
826 "certificate. Signature will be disregarded.");
830 LogDebug("signaturefile name = " << data.getSignatureFileName());
831 if (storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
833 LogError("distributor has author level siganture! Signature will be disregarded.");
834 return SignatureValidator::SIGNATURE_INVALID;
838 if (data.getSignatureNumber() == 1)
840 if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM))
842 LogDebug("Root CA for signature1.xml is correct.");
846 LogWarning("signature1.xml has got unrecognized Root CA "
847 "certificate. Signature will be disregarded.");
853 data.setStorageType(storeIdSet);
854 data.setSortedCertificateList(sortedCertificateList);
856 // We add only Root CA certificate because WAC ensure that the rest
857 // of certificates are present in signature files ;-)
858 XmlSec::XmlSecContext context;
859 context.signatureFile = data.getSignatureFileName();
860 context.certificatePtr = root;
862 // Now we should have full certificate chain.
863 // If the end certificate is not ROOT CA we should disregard signature
864 // but still signature must be valid... Aaaaaa it's so stupid...
865 if (!(root->isSignedBy(root))) {
866 LogWarning("Root CA certificate not found. Chain is incomplete.");
867 // context.allowBrokenChain = true;
870 time_t nowTime = time(NULL);
871 // WAC 2.0 SP-2066 The wrt must not block widget installation
872 // due to expiration of the author certificate.
876 ASN1_TIME* notAfterTime = data.getEndEntityCertificatePtr()->getNotAfterTime();
877 ASN1_TIME* notBeforeTime = data.getEndEntityCertificatePtr()->getNotBeforeTime();
879 if (X509_cmp_time(notBeforeTime, &nowTime) > 0 || X509_cmp_time(notAfterTime, &nowTime) < 0)
882 struct tm ta, tb, tc;
885 t = localtime(&nowTime);
887 return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;
889 memset(&tc, 0, sizeof(tc));
891 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", t->tm_year + 1900, t->tm_mon + 1,t->tm_mday );
892 LogDebug("## System's currentTime : " << msg);
893 fprintf(stderr, "## System's currentTime : %s\n", msg);
895 tb = _ASN1_GetTimeT(notBeforeTime);
896 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tb.tm_year + 1900, tb.tm_mon + 1,tb.tm_mday );
897 LogDebug("## certificate's notBeforeTime : " << msg);
898 fprintf(stderr, "## certificate's notBeforeTime : %s\n", msg);
900 ta = _ASN1_GetTimeT(notAfterTime);
901 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", ta.tm_year + 1900, ta.tm_mon + 1,ta.tm_mday );
902 LogDebug("## certificate's notAfterTime : " << msg);
903 fprintf(stderr, "## certificate's notAfterTime : %s\n", msg);
905 if (storeIdSet.contains(CertStoreId::TIZEN_VERIFY))
907 LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE");
908 fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n");
909 return SignatureValidator::SIGNATURE_INVALID;
912 int year = (ta.tm_year - tb.tm_year) / 4;
913 tc.tm_year = tb.tm_year + year;
914 tc.tm_mon = (tb.tm_mon + ta.tm_mon )/2;
915 tc.tm_mday = (tb.tm_mday + ta.tm_mday)/2;
917 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tc.tm_year + 1900, tc.tm_mon + 1,tc.tm_mday );
918 LogDebug("## cmp cert with validation time : " << msg);
919 fprintf(stderr, "## cmp cert with validation time : %s\n", msg);
921 time_t outCurrent = mktime(&tc);
922 context.validationTime = outCurrent;
923 //return SignatureValidator::SIGNATURE_INVALID;
929 time_t notAfter = data.getEndEntityCertificatePtr()->getNotAfter();
930 time_t notBefore = data.getEndEntityCertificatePtr()->getNotBefore();
934 if (data.isAuthorSignature())
936 // time_t 2038 year bug exist. So, notAtter() cann't check...
938 if (notAfter < nowTime)
940 context.validationTime = notAfter - TIMET_DAY;
941 LogWarning("Author certificate is expired. notAfter...");
945 if (notBefore > nowTime)
947 LogWarning("Author certificate is expired. notBefore time is greater than system-time.");
949 t = localtime(&nowTime);
951 t = localtime(¬Before);
953 context.validationTime = notBefore + TIMET_DAY;
955 t = localtime(&context.validationTime);
959 if (!data.isAuthorSignature())
961 if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) {
962 LogWarning("Installation break - invalid package!");
963 return SignatureValidator::SIGNATURE_INVALID;
966 data.setReference(context.referenceSet);
968 if (!checkObjectReferences(data)) {
969 return SignatureValidator::SIGNATURE_INVALID;
972 ReferenceValidator fileValidator(widgetContentPath);
973 if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) {
974 LogWarning("Invalid package - file references broken");
975 return SignatureValidator::SIGNATURE_INVALID;
979 #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL
980 // It is good time to do OCSP check
981 // ocspCheck will throw an exception on any error.
982 // TODO Probably we should catch this exception and add
983 // some information to SignatureData.
984 if (!m_complianceModeEnabled && !data.isAuthorSignature()) {
985 CertificateCollection coll;
986 coll.load(sortedCertificateList);
989 LogDebug("Collection does not contain chain!");
990 return SignatureValidator::SIGNATURE_INVALID;
993 CertificateVerifier verificator(m_ocspEnable, m_crlEnable);
994 VerificationStatus result = verificator.check(coll);
996 if (result == VERIFICATION_STATUS_REVOKED) {
997 return SignatureValidator::SIGNATURE_REVOKED;
1000 if (result == VERIFICATION_STATUS_UNKNOWN ||
1001 result == VERIFICATION_STATUS_ERROR)
1003 #ifdef _OCSP_POLICY_DISREGARD_UNKNOWN_OR_ERROR_CERTS_
1011 LogWarning("Signature is disregard. RootCA is not a member of Tizen.");
1012 return SignatureValidator::SIGNATURE_DISREGARD;
1014 return SignatureValidator::SIGNATURE_VERIFIED;
1017 // Implementation of SignatureValidator
1019 SignatureValidator::SignatureValidator(
1023 bool complianceMode)
1026 LogDebug( "appType : " << appType );
1028 if(appType == TIZEN)
1030 m_impl = new ImplTizenSignatureValidator(ocspEnable,crlEnable,complianceMode);
1032 else if(appType == WAC20)
1034 m_impl = new ImplWacSignatureValidator(ocspEnable,crlEnable,complianceMode);
1038 SignatureValidator::~SignatureValidator() {
1042 SignatureValidator::Result SignatureValidator::check(
1043 SignatureData &data,
1044 const std::string &widgetContentPath)
1046 return m_impl->check(data, widgetContentPath);
1049 SignatureValidator::Result SignatureValidator::checkList(
1050 SignatureData &data,
1051 const std::string &widgetContentPath,
1052 const std::list<std::string>& uriList)
1054 return m_impl->checkList(data, widgetContentPath, uriList);
1057 } // namespace ValidationCore