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>
30 #include <dpl/log/log.h>
33 const time_t TIMET_DAY = 60 * 60 * 24;
35 const std::string TOKEN_ROLE_AUTHOR_URI =
36 "http://www.w3.org/ns/widgets-digsig#role-author";
37 const std::string TOKEN_ROLE_DISTRIBUTOR_URI =
38 "http://www.w3.org/ns/widgets-digsig#role-distributor";
39 const std::string TOKEN_PROFILE_URI =
40 "http://www.w3.org/ns/widgets-digsig#profile";
42 } // namespace anonymouse
45 static tm _ASN1_GetTimeT(ASN1_TIME* time)
48 const char* str = (const char*) time->data;
51 memset(&t, 0, sizeof(t));
53 if (time->type == V_ASN1_UTCTIME) /* two digit year */
55 t.tm_year = (str[i] - '0') * 10 + (str[i+1] - '0');
60 else if (time->type == V_ASN1_GENERALIZEDTIME) /* four digit year */
64 + (str[i+1] - '0') * 100
65 + (str[i+2] - '0') * 10
70 t.tm_mon = ((str[i] - '0') * 10 + (str[i+1] - '0')) - 1; // -1 since January is 0 not 1.
71 t.tm_mday = (str[i+2] - '0') * 10 + (str[i+3] - '0');
72 t.tm_hour = (str[i+4] - '0') * 10 + (str[i+5] - '0');
73 t.tm_min = (str[i+6] - '0') * 10 + (str[i+7] - '0');
74 t.tm_sec = (str[i+8] - '0') * 10 + (str[i+9] - '0');
76 /* Note: we did not adjust the time based on time zone information */
81 namespace ValidationCore {
83 class SignatureValidator::ImplSignatureValidator {
85 virtual SignatureValidator::Result check(
87 const std::string &widgetContentPath) = 0;
89 virtual SignatureValidator::Result checkList(
91 const std::string &widgetContentPath,
92 const std::list<std::string>& uriList) = 0;
94 explicit ImplSignatureValidator(bool ocspEnable,
97 : m_complianceModeEnabled(complianceMode)
103 virtual ~ImplSignatureValidator(){ }
105 bool checkRoleURI(const SignatureData &data) {
106 std::string roleURI = data.getRoleURI();
108 if (roleURI.empty()) {
109 LogWarning("URI attribute in Role tag couldn't be empty.");
113 if (roleURI != TOKEN_ROLE_AUTHOR_URI && data.isAuthorSignature()) {
114 LogWarning("URI attribute in Role tag does not "
115 "match with signature filename.");
119 if (roleURI != TOKEN_ROLE_DISTRIBUTOR_URI && !data.isAuthorSignature()) {
120 LogWarning("URI attribute in Role tag does not "
121 "match with signature filename.");
127 bool checkProfileURI(const SignatureData &data) {
128 if (TOKEN_PROFILE_URI != data.getProfileURI()) {
130 "Profile tag contains unsupported value in URI attribute " << data.getProfileURI());
136 bool checkObjectReferences(const SignatureData &data) {
137 ObjectList objectList = data.getObjectList();
138 ObjectList::const_iterator iter;
139 for (iter = objectList.begin(); iter != objectList.end(); ++iter) {
140 if (!data.containObjectReference(*iter)) {
141 LogWarning("Signature does not contain reference for object " << *iter);
148 bool m_complianceModeEnabled;
151 class ImplTizenSignatureValidator : public SignatureValidator::ImplSignatureValidator
154 SignatureValidator::Result check(SignatureData &data,
155 const std::string &widgetContentPath);
157 SignatureValidator::Result checkList(SignatureData &data,
158 const std::string &widgetContentPath,
159 const std::list<std::string>& uriList);
160 explicit ImplTizenSignatureValidator(bool ocspEnable,
163 : ImplSignatureValidator(ocspEnable, crlEnable, complianceMode)
166 virtual ~ImplTizenSignatureValidator() {}
169 SignatureValidator::Result ImplTizenSignatureValidator::check(
171 const std::string &widgetContentPath)
173 bool disregard = false;
175 if (!checkRoleURI(data)) {
176 return SignatureValidator::SIGNATURE_INVALID;
179 if (!checkProfileURI(data)) {
180 return SignatureValidator::SIGNATURE_INVALID;
183 // CertificateList sortedCertificateList = data.getCertList();
185 CertificateCollection collection;
186 collection.load(data.getCertList());
188 // First step - sort certificate
189 if (!collection.sort()) {
190 LogWarning("Certificates do not form valid chain.");
191 return SignatureValidator::SIGNATURE_INVALID_CERT_CHAIN;//SIGNATURE_INVALID;
195 if (collection.empty()) {
196 LogWarning("Certificate list in signature is empty.");
197 return SignatureValidator::SIGNATURE_INVALID_CERT_CHAIN;//SIGNATURE_INVALID;
200 CertificateList sortedCertificateList = collection.getChain();
202 // TODO move it to CertificateCollection
203 // Add root CA and CA certificates (if chain is incomplete)
204 sortedCertificateList =
205 OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList);
207 CertificatePtr root = sortedCertificateList.back();
209 // Is Root CA certificate trusted?
210 CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root);
212 LogDebug("Is root certificate from TIZEN_DEVELOPER domain : " << storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER));
213 LogDebug("Is root certificate from TIZEN_TEST domain : " << storeIdSet.contains(CertStoreId::TIZEN_TEST));
214 LogDebug("Is root certificate from TIZEN_VERIFY domain : " << storeIdSet.contains(CertStoreId::TIZEN_VERIFY));
215 LogDebug("Is root certificate from TIZEN_STORE domain : " << storeIdSet.contains(CertStoreId::TIZEN_STORE));
216 LogDebug("Is root certificate from TIZEN_PUBLIC domain : " << storeIdSet.contains(CertStoreId::VIS_PUBLIC));
217 LogDebug("Is root certificate from TIZEN_PARTNER domain : " << storeIdSet.contains(CertStoreId::VIS_PARTNER));
218 LogDebug("Is root certificate from TIZEN_PLATFORM domain : " << storeIdSet.contains(CertStoreId::VIS_PLATFORM));
220 LogDebug("Visibility level is public : " << storeIdSet.contains(CertStoreId::VIS_PUBLIC));
221 LogDebug("Visibility level is partner : " << storeIdSet.contains(CertStoreId::VIS_PARTNER));
222 LogDebug("Visibility level is platform : " << storeIdSet.contains(CertStoreId::VIS_PLATFORM));
224 if (data.isAuthorSignature())
226 if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
228 LogWarning("author-signature.xml has got unrecognized Root CA "
229 "certificate. Signature will be disregarded.");
235 LogDebug("signaturefile name = " << data.getSignatureFileName());
236 if (storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
238 LogError("distributor has author level siganture! Signature will be disregarded.");
239 return SignatureValidator::SIGNATURE_IN_DISTRIBUTOR_CASE_AUTHOR_CERT;//SIGNATURE_INVALID;
243 if (data.getSignatureNumber() == 1)
245 if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM))
247 LogDebug("Root CA for signature1.xml is correct.");
251 LogWarning("signature1.xml has got unrecognized Root CA "
252 "certificate. Signature will be disregarded.");
258 data.setStorageType(storeIdSet);
259 data.setSortedCertificateList(sortedCertificateList);
261 // We add only Root CA certificate because WAC ensure that the rest
262 // of certificates are present in signature files ;-)
263 XmlSec::XmlSecContext context;
264 context.signatureFile = data.getSignatureFileName();
265 context.certificatePtr = root;
267 // Now we should have full certificate chain.
268 // If the end certificate is not ROOT CA we should disregard signature
269 // but still signature must be valid... Aaaaaa it's so stupid...
270 if (!(root->isSignedBy(root))) {
271 LogWarning("Root CA certificate not found. Chain is incomplete.");
272 // context.allowBrokenChain = true;
275 time_t nowTime = time(NULL);
280 ASN1_TIME* notAfterTime = data.getEndEntityCertificatePtr()->getNotAfterTime();
281 ASN1_TIME* notBeforeTime = data.getEndEntityCertificatePtr()->getNotBeforeTime();
283 if (X509_cmp_time(notBeforeTime, &nowTime) > 0 || X509_cmp_time(notAfterTime, &nowTime) < 0)
286 struct tm ta, tb, tc;
289 t = localtime(&nowTime);
291 return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;
293 memset(&tc, 0, sizeof(tc));
295 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", t->tm_year + 1900, t->tm_mon + 1,t->tm_mday );
296 LogDebug("## System's currentTime : " << msg);
297 fprintf(stderr, "## System's currentTime : %s\n", msg);
299 tb = _ASN1_GetTimeT(notBeforeTime);
300 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tb.tm_year + 1900, tb.tm_mon + 1,tb.tm_mday );
301 LogDebug("## certificate's notBeforeTime : " << msg);
302 fprintf(stderr, "## certificate's notBeforeTime : %s\n", msg);
304 ta = _ASN1_GetTimeT(notAfterTime);
305 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", ta.tm_year + 1900, ta.tm_mon + 1,ta.tm_mday );
306 LogDebug("## certificate's notAfterTime : " << msg);
307 fprintf(stderr, "## certificate's notAfterTime : %s\n", msg);
309 if (storeIdSet.contains(CertStoreId::TIZEN_TEST) || storeIdSet.contains(CertStoreId::TIZEN_VERIFY))
311 LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE");
312 fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n");
313 return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;//SIGNATURE_INVALID;
316 int year = (ta.tm_year - tb.tm_year) / 4;
320 tc.tm_year = tb.tm_year;
321 tc.tm_mon = tb.tm_mon + 1;
322 tc.tm_mday = tb.tm_mday;
326 tc.tm_year = ta.tm_year;
327 tc.tm_mon = ta.tm_mon - 1;
328 tc.tm_mday = ta.tm_mday;
332 tc.tm_year = ta.tm_year;
333 tc.tm_mon = ta.tm_mon;
334 tc.tm_mday = ta.tm_mday -1;
338 tc.tm_year = tb.tm_year;
339 tc.tm_mon = tb.tm_mon;
340 tc.tm_mday = tb.tm_mday +1;
346 tc.tm_year = tb.tm_year + year;
347 tc.tm_mon = (tb.tm_mon + ta.tm_mon )/2;
348 tc.tm_mday = (tb.tm_mday + ta.tm_mday)/2;
351 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tc.tm_year + 1900, tc.tm_mon + 1,tc.tm_mday );
352 LogDebug("## cmp cert with validation time : " << msg);
353 fprintf(stderr, "## cmp cert with validation time : %s\n", msg);
355 time_t outCurrent = mktime(&tc);
356 context.validationTime = outCurrent;
357 fprintf(stderr, "## cmp outCurrent time : %ld\n", outCurrent);
358 //return SignatureValidator::SIGNATURE_INVALID;
362 // WAC 2.0 SP-2066 The wrt must not block widget installation
363 // due to expiration of the author certificate.
365 time_t notAfter = data.getEndEntityCertificatePtr()->getNotAfter();
366 time_t notBefore = data.getEndEntityCertificatePtr()->getNotBefore();
370 if (data.isAuthorSignature())
372 // time_t 2038 year bug exist. So, notAtter() cann't check...
374 if (notAfter < nowTime)
376 context.validationTime = notAfter - TIMET_DAY;
377 LogWarning("Author certificate is expired. notAfter...");
381 if (notBefore > nowTime)
383 LogWarning("Author certificate is expired. notBefore time is greater than system-time.");
385 t = localtime(&nowTime);
387 t = localtime(¬Before);
389 context.validationTime = notBefore + TIMET_DAY;
391 t = localtime(&context.validationTime);
395 // WAC 2.0 SP-2066 The wrt must not block widget installation
396 //context.allowBrokenChain = true;
400 if (!data.isAuthorSignature())
402 if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) {
403 LogWarning("Installation break - invalid package!");
404 return SignatureValidator::SIGNATURE_INVALID_HASH_SIGNATURE;//SIGNATURE_INVALID;
407 data.setReference(context.referenceSet);
408 if (!checkObjectReferences(data)) {
409 LogWarning("Failed to check Object References");
410 return SignatureValidator::SIGNATURE_INVALID_HASH_SIGNATURE;//SIGNATURE_INVALID;
413 (void) widgetContentPath;
415 ReferenceValidator fileValidator(widgetContentPath);
416 if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) {
417 LogWarning("Invalid package - file references broken");
418 return SignatureValidator::SIGNATURE_INVALID_NO_HASH_FILE;//SIGNATURE_INVALID;
424 LogWarning("Signature is disregard. RootCA is not a member of Tizen");
425 return SignatureValidator::SIGNATURE_INVALID_DISTRIBUTOR_CERT;//SIGNATURE_DISREGARD;
427 return SignatureValidator::SIGNATURE_VERIFIED;
430 SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData &data,
431 const std::string &widgetContentPath,
432 const std::list<std::string>& uriList)
434 if(uriList.size() == 0 )
435 LogWarning("checkList >> no hash");
437 bool disregard = false;
439 if (!checkRoleURI(data)) {
440 return SignatureValidator::SIGNATURE_INVALID;
443 if (!checkProfileURI(data)) {
444 return SignatureValidator::SIGNATURE_INVALID;
447 // CertificateList sortedCertificateList = data.getCertList();
449 CertificateCollection collection;
450 collection.load(data.getCertList());
452 // First step - sort certificate
453 if (!collection.sort()) {
454 LogWarning("Certificates do not form valid chain.");
455 return SignatureValidator::SIGNATURE_INVALID;
459 if (collection.empty()) {
460 LogWarning("Certificate list in signature is empty.");
461 return SignatureValidator::SIGNATURE_INVALID;
464 CertificateList sortedCertificateList = collection.getChain();
466 // TODO move it to CertificateCollection
467 // Add root CA and CA certificates (if chain is incomplete)
468 sortedCertificateList =
469 OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList);
471 CertificatePtr root = sortedCertificateList.back();
473 // Is Root CA certificate trusted?
474 CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root);
476 LogDebug("Is root certificate from TIZEN_DEVELOPER domain : " << storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER));
477 LogDebug("Is root certificate from TIZEN_TEST domain : " << storeIdSet.contains(CertStoreId::TIZEN_TEST));
478 LogDebug("Is root certificate from TIZEN_VERIFY domain : " << storeIdSet.contains(CertStoreId::TIZEN_VERIFY));
479 LogDebug("Is root certificate from TIZEN_PUBLIC domain : " << storeIdSet.contains(CertStoreId::VIS_PUBLIC));
480 LogDebug("Is root certificate from TIZEN_PARTNER domain : " << storeIdSet.contains(CertStoreId::VIS_PARTNER));
481 LogDebug("Is root certificate from TIZEN_PLATFORM domain : " << storeIdSet.contains(CertStoreId::VIS_PLATFORM));
483 LogDebug("Visibility level is public : " << storeIdSet.contains(CertStoreId::VIS_PUBLIC));
484 LogDebug("Visibility level is partner : " << storeIdSet.contains(CertStoreId::VIS_PARTNER));
485 LogDebug("Visibility level is platform : " << storeIdSet.contains(CertStoreId::VIS_PLATFORM));
487 if (data.isAuthorSignature())
489 if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
491 LogWarning("author-signature.xml has got unrecognized Root CA "
492 "certificate. Signature will be disregarded.");
495 LogDebug("Root CA for author signature is correct.");
499 LogDebug("signaturefile name = " << data.getSignatureFileName());
501 if (data.getSignatureNumber() == 1)
503 if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM))
505 LogDebug("Root CA for signature1.xml is correct.");
509 LogWarning("signature1.xml has got unrecognized Root CA "
510 "certificate. Signature will be disregarded.");
516 data.setStorageType(storeIdSet);
517 data.setSortedCertificateList(sortedCertificateList);
519 // We add only Root CA certificate because WAC ensure that the rest
520 // of certificates are present in signature files ;-)
521 XmlSec::XmlSecContext context;
522 context.signatureFile = data.getSignatureFileName();
523 context.certificatePtr = root;
525 // Now we should have full certificate chain.
526 // If the end certificate is not ROOT CA we should disregard signature
527 // but still signature must be valid... Aaaaaa it's so stupid...
528 if (!(root->isSignedBy(root))) {
529 LogWarning("Root CA certificate not found. Chain is incomplete.");
530 // context.allowBrokenChain = true;
533 // WAC 2.0 SP-2066 The wrt must not block widget installation
534 // due to expiration of the author certificate.
535 time_t nowTime = time(NULL);
540 ASN1_TIME* notAfterTime = data.getEndEntityCertificatePtr()->getNotAfterTime();
541 ASN1_TIME* notBeforeTime = data.getEndEntityCertificatePtr()->getNotBeforeTime();
544 if (X509_cmp_time(notBeforeTime, &nowTime) > 0 || X509_cmp_time(notAfterTime, &nowTime) < 0)
547 struct tm ta, tb, tc;
550 t = localtime(&nowTime);
552 return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;
554 memset(&tc, 0, sizeof(tc));
556 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", t->tm_year + 1900, t->tm_mon + 1,t->tm_mday );
557 LogDebug("## System's currentTime : " << msg);
558 fprintf(stderr, "## System's currentTime : %s\n", msg);
560 tb = _ASN1_GetTimeT(notBeforeTime);
561 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tb.tm_year + 1900, tb.tm_mon + 1,tb.tm_mday );
562 LogDebug("## certificate's notBeforeTime : " << msg);
563 fprintf(stderr, "## certificate's notBeforeTime : %s\n", msg);
565 ta = _ASN1_GetTimeT(notAfterTime);
566 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", ta.tm_year + 1900, ta.tm_mon + 1,ta.tm_mday );
567 LogDebug("## certificate's notAfterTime : " << msg);
568 fprintf(stderr, "## certificate's notAfterTime : %s\n", msg);
570 if (storeIdSet.contains(CertStoreId::TIZEN_VERIFY))
572 LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE");
573 fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n");
574 return SignatureValidator::SIGNATURE_INVALID;
577 int year = (ta.tm_year - tb.tm_year) / 4;
578 tc.tm_year = tb.tm_year + year;
579 tc.tm_mon = (tb.tm_mon + ta.tm_mon )/2;
580 tc.tm_mday = (tb.tm_mday + ta.tm_mday)/2;
582 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tc.tm_year + 1900, tc.tm_mon + 1,tc.tm_mday );
583 LogDebug("## cmp cert with validation time : " << msg);
584 fprintf(stderr, "## cmp cert with validation time : %s\n", msg);
586 time_t outCurrent = mktime(&tc);
587 context.validationTime = outCurrent;
588 //return SignatureValidator::SIGNATURE_INVALID;
594 time_t notAfter = data.getEndEntityCertificatePtr()->getNotAfter();
595 time_t notBefore = data.getEndEntityCertificatePtr()->getNotBefore();
599 if (data.isAuthorSignature())
601 // time_t 2038 year bug exist. So, notAtter() cann't check...
603 if (notAfter < nowTime)
605 context.validationTime = notAfter - TIMET_DAY;
606 LogWarning("Author certificate is expired. notAfter...");
610 if (notBefore > nowTime)
612 LogWarning("Author certificate is expired. notBefore time is greater than system-time.");
614 t = localtime(&nowTime);
616 t = localtime(¬Before);
618 context.validationTime = notBefore + TIMET_DAY;
620 t = localtime(&context.validationTime);
624 // WAC 2.0 SP-2066 The wrt must not block widget installation
625 //context.allowBrokenChain = true;
628 if(uriList.size() == 0)
630 if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validateNoHash(&context)) {
631 LogWarning("Installation break - invalid package! >> validateNoHash");
632 return SignatureValidator::SIGNATURE_INVALID;
635 else if(uriList.size() != 0)
637 XmlSecSingleton::Instance().setPartialHashList(uriList);
638 if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validatePartialHash(&context)) {
639 LogWarning("Installation break - invalid package! >> validatePartialHash");
640 return SignatureValidator::SIGNATURE_INVALID;
644 data.setReference(context.referenceSet);
645 //if (!checkObjectReferences(data)) {
646 // return SignatureValidator::SIGNATURE_INVALID;
649 (void) widgetContentPath;
651 ReferenceValidator fileValidator(widgetContentPath);
652 if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) {
653 LogWarning("Invalid package - file references broken");
654 return SignatureValidator::SIGNATURE_INVALID;
659 LogWarning("Signature is disregard. RootCA is not a member of Tizen.");
660 return SignatureValidator::SIGNATURE_DISREGARD;
662 return SignatureValidator::SIGNATURE_VERIFIED;
665 class ImplWacSignatureValidator : public SignatureValidator::ImplSignatureValidator
668 SignatureValidator::Result check(SignatureData &data,
669 const std::string &widgetContentPath);
671 SignatureValidator::Result checkList(SignatureData &data,
672 const std::string &widgetContentPath,
673 const std::list<std::string>& uriList);
674 explicit ImplWacSignatureValidator(bool ocspEnable,
677 : ImplSignatureValidator(ocspEnable, crlEnable, complianceMode)
680 virtual ~ImplWacSignatureValidator() {}
684 SignatureValidator::Result ImplWacSignatureValidator::checkList(
685 SignatureData & /* data */,
686 const std::string & /* widgetContentPath */,
687 const std::list<std::string>& /* uriList */)
689 return SignatureValidator::SIGNATURE_INVALID;
693 SignatureValidator::Result ImplWacSignatureValidator::check(
695 const std::string &widgetContentPath)
697 bool disregard = false;
699 if (!checkRoleURI(data)) {
700 return SignatureValidator::SIGNATURE_INVALID;
703 if (!checkProfileURI(data)) {
704 return SignatureValidator::SIGNATURE_INVALID;
707 // CertificateList sortedCertificateList = data.getCertList();
709 CertificateCollection collection;
710 collection.load(data.getCertList());
712 // First step - sort certificate
713 if (!collection.sort()) {
714 LogWarning("Certificates do not form valid chain.");
715 return SignatureValidator::SIGNATURE_INVALID;
719 if (collection.empty()) {
720 LogWarning("Certificate list in signature is empty.");
721 return SignatureValidator::SIGNATURE_INVALID;
724 CertificateList sortedCertificateList = collection.getChain();
726 // TODO move it to CertificateCollection
727 // Add root CA and CA certificates (if chain is incomplete)
728 sortedCertificateList =
729 OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList);
731 CertificatePtr root = sortedCertificateList.back();
733 // Is Root CA certificate trusted?
734 CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root);
736 LogDebug("Is root certificate from TIZEN_DEVELOPER domain : " << storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER));
737 LogDebug("Is root certificate from TIZEN_TEST domain : " << storeIdSet.contains(CertStoreId::TIZEN_TEST));
738 LogDebug("Is root certificate from TIZEN_VERIFY domain : " << storeIdSet.contains(CertStoreId::TIZEN_VERIFY));
739 LogDebug("Is root certificate from TIZEN_PUBLIC domain : " << storeIdSet.contains(CertStoreId::VIS_PUBLIC));
740 LogDebug("Is root certificate from TIZEN_PARTNER domain : " << storeIdSet.contains(CertStoreId::VIS_PARTNER));
741 LogDebug("Is root certificate from TIZEN_PLATFORM domain : " << storeIdSet.contains(CertStoreId::VIS_PLATFORM));
743 LogDebug("Visibility level is public : " << storeIdSet.contains(CertStoreId::VIS_PUBLIC));
744 LogDebug("Visibility level is partner : " << storeIdSet.contains(CertStoreId::VIS_PARTNER));
745 LogDebug("Visibility level is platform : " << storeIdSet.contains(CertStoreId::VIS_PLATFORM));
747 if (data.isAuthorSignature())
749 if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
751 LogWarning("author-signature.xml has got unrecognized Root CA "
752 "certificate. Signature will be disregarded.");
756 LogDebug("signaturefile name = " << data.getSignatureFileName());
757 if (storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
759 LogError("distributor has author level siganture! Signature will be disregarded.");
760 return SignatureValidator::SIGNATURE_INVALID;
764 if (data.getSignatureNumber() == 1)
766 if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM))
768 LogDebug("Root CA for signature1.xml is correct.");
772 LogWarning("signature1.xml has got unrecognized Root CA "
773 "certificate. Signature will be disregarded.");
779 data.setStorageType(storeIdSet);
780 data.setSortedCertificateList(sortedCertificateList);
782 // We add only Root CA certificate because WAC ensure that the rest
783 // of certificates are present in signature files ;-)
784 XmlSec::XmlSecContext context;
785 context.signatureFile = data.getSignatureFileName();
786 context.certificatePtr = root;
788 // Now we should have full certificate chain.
789 // If the end certificate is not ROOT CA we should disregard signature
790 // but still signature must be valid... Aaaaaa it's so stupid...
791 if (!(root->isSignedBy(root))) {
792 LogWarning("Root CA certificate not found. Chain is incomplete.");
793 // context.allowBrokenChain = true;
796 time_t nowTime = time(NULL);
797 // WAC 2.0 SP-2066 The wrt must not block widget installation
798 // due to expiration of the author certificate.
802 ASN1_TIME* notAfterTime = data.getEndEntityCertificatePtr()->getNotAfterTime();
803 ASN1_TIME* notBeforeTime = data.getEndEntityCertificatePtr()->getNotBeforeTime();
805 if (X509_cmp_time(notBeforeTime, &nowTime) > 0 || X509_cmp_time(notAfterTime, &nowTime) < 0)
808 struct tm ta, tb, tc;
811 t = localtime(&nowTime);
813 return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;
815 memset(&tc, 0, sizeof(tc));
817 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", t->tm_year + 1900, t->tm_mon + 1,t->tm_mday );
818 LogDebug("## System's currentTime : " << msg);
819 fprintf(stderr, "## System's currentTime : %s\n", msg);
821 tb = _ASN1_GetTimeT(notBeforeTime);
822 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tb.tm_year + 1900, tb.tm_mon + 1,tb.tm_mday );
823 LogDebug("## certificate's notBeforeTime : " << msg);
824 fprintf(stderr, "## certificate's notBeforeTime : %s\n", msg);
826 ta = _ASN1_GetTimeT(notAfterTime);
827 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", ta.tm_year + 1900, ta.tm_mon + 1,ta.tm_mday );
828 LogDebug("## certificate's notAfterTime : " << msg);
829 fprintf(stderr, "## certificate's notAfterTime : %s\n", msg);
831 if (storeIdSet.contains(CertStoreId::TIZEN_VERIFY))
833 LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE");
834 fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n");
835 return SignatureValidator::SIGNATURE_INVALID;
838 int year = (ta.tm_year - tb.tm_year) / 4;
839 tc.tm_year = tb.tm_year + year;
840 tc.tm_mon = (tb.tm_mon + ta.tm_mon )/2;
841 tc.tm_mday = (tb.tm_mday + ta.tm_mday)/2;
843 snprintf(msg, sizeof(msg), "Year: %d, month: %d, day : %d", tc.tm_year + 1900, tc.tm_mon + 1,tc.tm_mday );
844 LogDebug("## cmp cert with validation time : " << msg);
845 fprintf(stderr, "## cmp cert with validation time : %s\n", msg);
847 time_t outCurrent = mktime(&tc);
848 context.validationTime = outCurrent;
849 //return SignatureValidator::SIGNATURE_INVALID;
855 time_t notAfter = data.getEndEntityCertificatePtr()->getNotAfter();
856 time_t notBefore = data.getEndEntityCertificatePtr()->getNotBefore();
860 if (data.isAuthorSignature())
862 // time_t 2038 year bug exist. So, notAtter() cann't check...
864 if (notAfter < nowTime)
866 context.validationTime = notAfter - TIMET_DAY;
867 LogWarning("Author certificate is expired. notAfter...");
871 if (notBefore > nowTime)
873 LogWarning("Author certificate is expired. notBefore time is greater than system-time.");
875 t = localtime(&nowTime);
877 t = localtime(¬Before);
879 context.validationTime = notBefore + TIMET_DAY;
881 t = localtime(&context.validationTime);
885 if (!data.isAuthorSignature())
887 if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) {
888 LogWarning("Installation break - invalid package!");
889 return SignatureValidator::SIGNATURE_INVALID;
892 data.setReference(context.referenceSet);
894 if (!checkObjectReferences(data)) {
895 return SignatureValidator::SIGNATURE_INVALID;
898 ReferenceValidator fileValidator(widgetContentPath);
899 if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) {
900 LogWarning("Invalid package - file references broken");
901 return SignatureValidator::SIGNATURE_INVALID;
906 LogWarning("Signature is disregard. RootCA is not a member of Tizen.");
907 return SignatureValidator::SIGNATURE_DISREGARD;
909 return SignatureValidator::SIGNATURE_VERIFIED;
912 // Implementation of SignatureValidator
914 SignatureValidator::SignatureValidator(
921 LogDebug( "appType : " << appType );
925 m_impl = new ImplTizenSignatureValidator(ocspEnable,crlEnable,complianceMode);
927 else if(appType == WAC20)
929 m_impl = new ImplWacSignatureValidator(ocspEnable,crlEnable,complianceMode);
933 SignatureValidator::~SignatureValidator() {
937 SignatureValidator::Result SignatureValidator::check(
939 const std::string &widgetContentPath)
941 return m_impl->check(data, widgetContentPath);
944 SignatureValidator::Result SignatureValidator::checkList(
946 const std::string &widgetContentPath,
947 const std::list<std::string>& uriList)
949 return m_impl->checkList(data, widgetContentPath, uriList);
952 } // namespace ValidationCore