Refactor log system
[platform/core/security/cert-svc.git] / vcore / src / vcore / SignatureValidator.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /*
17  * @file        SignatureValidator.cpp
18  * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
19  * @version     1.0
20  * @brief       Implementatin of tizen signature validation protocol.
21  */
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>
31 #endif
32
33 #include <dpl/log/log.h>
34
35 namespace {
36 const time_t TIMET_DAY = 60 * 60 * 24;
37
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";
44
45 } // namespace anonymouse
46
47
48 static tm _ASN1_GetTimeT(ASN1_TIME* time)
49 {
50     struct tm t;
51     const char* str = (const char*) time->data;
52     size_t i = 0;
53
54     memset(&t, 0, sizeof(t));
55
56     if (time->type == V_ASN1_UTCTIME) /* two digit year */
57     {
58         t.tm_year = (str[i] - '0') * 10 + (str[i+1] - '0');
59         i += 2;
60         if (t.tm_year < 70)
61             t.tm_year += 100;
62     }
63     else if (time->type == V_ASN1_GENERALIZEDTIME) /* four digit year */
64     {
65         t.tm_year =
66             (str[i] - '0') * 1000
67             + (str[i+1] - '0') * 100
68             + (str[i+2] - '0') * 10
69             + (str[i+3] - '0');
70         i += 4;
71         t.tm_year -= 1900;
72     }
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');
78
79     /* Note: we did not adjust the time based on time zone information */
80     return t;
81 }
82
83
84 namespace ValidationCore {
85
86 class SignatureValidator::ImplSignatureValidator {
87 public:
88     virtual SignatureValidator::Result check(
89         SignatureData &data,
90         const std::string &widgetContentPath) = 0;
91
92     virtual SignatureValidator::Result checkList(
93         SignatureData &data,
94         const std::string &widgetContentPath,
95         const std::list<std::string>& uriList) = 0;
96
97     explicit ImplSignatureValidator(bool ocspEnable,
98                   bool crlEnable,
99                   bool complianceMode)
100       : m_complianceModeEnabled(complianceMode)
101     {
102 #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL
103         m_ocspEnable = ocspEnable;
104         m_crlEnable = crlEnable;
105 #else
106         (void) ocspEnable;
107         (void) crlEnable;
108 #endif
109     }
110
111     virtual ~ImplSignatureValidator(){ }
112
113     bool checkRoleURI(const SignatureData &data) {
114         std::string roleURI = data.getRoleURI();
115
116         if (roleURI.empty()) {
117             LogWarning("URI attribute in Role tag couldn't be empty.");
118             return false;
119         }
120
121         if (roleURI != TOKEN_ROLE_AUTHOR_URI && data.isAuthorSignature()) {
122             LogWarning("URI attribute in Role tag does not "
123               "match with signature filename.");
124             return false;
125         }
126
127         if (roleURI != TOKEN_ROLE_DISTRIBUTOR_URI && !data.isAuthorSignature()) {
128             LogWarning("URI attribute in Role tag does not "
129               "match with signature filename.");
130             return false;
131         }
132         return true;
133     }
134
135     bool checkProfileURI(const SignatureData &data) {
136         if (TOKEN_PROFILE_URI != data.getProfileURI()) {
137             LogWarning(
138               "Profile tag contains unsupported value in URI attribute " << data.getProfileURI());
139             return false;
140         }
141         return true;
142     }
143
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);
150                 return false;
151             }
152         }
153         return true;
154     }
155 protected:
156     bool m_complianceModeEnabled;
157 #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL
158     bool m_ocspEnable;
159     bool m_crlEnable;
160 #endif
161 };
162
163 class ImplTizenSignatureValidator : public SignatureValidator::ImplSignatureValidator
164 {
165   public:
166     SignatureValidator::Result check(SignatureData &data,
167             const std::string &widgetContentPath);
168
169     SignatureValidator::Result checkList(SignatureData &data,
170             const std::string &widgetContentPath,
171             const std::list<std::string>& uriList);
172     explicit ImplTizenSignatureValidator(bool ocspEnable,
173                        bool crlEnable,
174                        bool complianceMode)
175       : ImplSignatureValidator(ocspEnable, crlEnable, complianceMode)
176     {}
177
178     virtual ~ImplTizenSignatureValidator() {}
179 };
180
181 SignatureValidator::Result ImplTizenSignatureValidator::check(
182         SignatureData &data,
183         const std::string &widgetContentPath)
184 {
185     bool disregard = false;
186
187     if (!checkRoleURI(data)) {
188         return SignatureValidator::SIGNATURE_INVALID;
189     }
190
191     if (!checkProfileURI(data)) {
192         return SignatureValidator::SIGNATURE_INVALID;
193     }
194
195     //  CertificateList sortedCertificateList = data.getCertList();
196
197     CertificateCollection collection;
198     collection.load(data.getCertList());
199
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;
204     }
205
206     // Check for error
207     if (collection.empty()) {
208         LogWarning("Certificate list in signature is empty.");
209         return SignatureValidator::SIGNATURE_INVALID_CERT_CHAIN;//SIGNATURE_INVALID;
210     }
211
212     CertificateList sortedCertificateList = collection.getChain();
213
214     // TODO move it to CertificateCollection
215     // Add root CA and CA certificates (if chain is incomplete)
216     sortedCertificateList =
217         OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList);
218
219     CertificatePtr root = sortedCertificateList.back();
220
221     // Is Root CA certificate trusted?
222     CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root);
223
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));
231
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));
235
236         if (data.isAuthorSignature())
237         {
238                 if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
239                 {
240                         LogWarning("author-signature.xml has got unrecognized Root CA "
241                                         "certificate. Signature will be disregarded.");
242                         disregard = true;
243                 }
244    }
245    else
246    {
247                 LogDebug("signaturefile name = " << data.getSignatureFileName());
248                 if (storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
249                 {
250                         LogError("distributor has author level siganture! Signature will be disregarded.");
251                         return SignatureValidator::SIGNATURE_IN_DISTRIBUTOR_CASE_AUTHOR_CERT;//SIGNATURE_INVALID;
252                 }
253
254
255       if (data.getSignatureNumber() == 1)
256       {
257          if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM))
258          {
259             LogDebug("Root CA for signature1.xml is correct.");
260          }
261          else
262          {
263             LogWarning("signature1.xml has got unrecognized Root CA "
264                        "certificate. Signature will be disregarded.");
265             disregard = true;
266          }
267       }
268    }
269
270     data.setStorageType(storeIdSet);
271     data.setSortedCertificateList(sortedCertificateList);
272
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;
278
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;
285     }
286
287     time_t nowTime = time(NULL);
288
289 #define CHECK_TIME
290 #ifdef CHECK_TIME
291
292     ASN1_TIME* notAfterTime = data.getEndEntityCertificatePtr()->getNotAfterTime();
293     ASN1_TIME* notBeforeTime = data.getEndEntityCertificatePtr()->getNotBeforeTime();
294
295     if (X509_cmp_time(notBeforeTime, &nowTime) > 0  || X509_cmp_time(notAfterTime, &nowTime) < 0)
296     {
297       struct tm *t;
298       struct tm ta, tb, tc;
299       char msg[1024];
300
301       t = localtime(&nowTime);
302       if (!t)
303           return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;
304
305       memset(&tc, 0, sizeof(tc));
306
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);
310
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);
315
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);
320
321       if (storeIdSet.contains(CertStoreId::TIZEN_TEST) || storeIdSet.contains(CertStoreId::TIZEN_VERIFY))
322       {
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;
326       }
327
328       int year = (ta.tm_year - tb.tm_year) / 4;
329
330       if(year == 0)
331       {
332           tc.tm_year = tb.tm_year; 
333           tc.tm_mon = tb.tm_mon + 1;
334           tc.tm_mday = tb.tm_mday;
335
336           if(tc.tm_mon == 12)
337           {
338               tc.tm_year = ta.tm_year;       
339               tc.tm_mon = ta.tm_mon - 1;
340               tc.tm_mday = ta.tm_mday;
341               
342               if(tc.tm_mon < 0)
343               {
344                  tc.tm_year = ta.tm_year;
345                  tc.tm_mon = ta.tm_mon;
346                  tc.tm_mday = ta.tm_mday -1;
347
348                  if(tc.tm_mday == 0)
349                  {
350                     tc.tm_year = tb.tm_year;                
351                     tc.tm_mon = tb.tm_mon;
352                     tc.tm_mday = tb.tm_mday +1;
353                  }
354               }
355           }          
356       }
357       else{
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;  
361       }
362
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);
366
367       time_t outCurrent = mktime(&tc);
368       context.validationTime = outCurrent;
369       fprintf(stderr, "## cmp outCurrent time : %ld\n", outCurrent);
370       //return SignatureValidator::SIGNATURE_INVALID;
371     }
372
373 #endif
374     // WAC 2.0 SP-2066 The wrt must not block widget installation
375     // due to expiration of the author certificate.
376 #if 0
377     time_t notAfter = data.getEndEntityCertificatePtr()->getNotAfter();
378     time_t notBefore = data.getEndEntityCertificatePtr()->getNotBefore();
379
380     struct tm *t;
381
382     if (data.isAuthorSignature())
383         {
384        // time_t 2038 year bug exist. So, notAtter() cann't check...
385        /*
386        if (notAfter < nowTime)
387        {
388           context.validationTime = notAfter - TIMET_DAY;
389           LogWarning("Author certificate is expired. notAfter...");
390        }
391        */
392
393        if (notBefore > nowTime)
394        {
395           LogWarning("Author certificate is expired. notBefore time is greater than system-time.");
396
397           t = localtime(&nowTime);
398
399           t = localtime(&notBefore);
400
401           context.validationTime = notBefore + TIMET_DAY;
402
403           t = localtime(&context.validationTime);
404       }
405     }
406 #endif
407     // WAC 2.0 SP-2066 The wrt must not block widget installation
408     //context.allowBrokenChain = true;
409
410     // end
411
412         if (!data.isAuthorSignature())
413         {
414                 if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) {
415                         LogWarning("Installation break - invalid package!");
416                         return SignatureValidator::SIGNATURE_INVALID_HASH_SIGNATURE;//SIGNATURE_INVALID;
417                 }
418
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;
423                 }
424
425     (void) widgetContentPath;
426   /*
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;
431     }
432  */
433         }
434
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);
443
444         if (!coll.sort()) {
445             LogDebug("Collection does not contain chain!");
446             return SignatureValidator::SIGNATURE_INVALID_CERT_CHAIN;//SIGNATURE_INVALID;
447         }
448
449         CertificateVerifier verificator(m_ocspEnable, m_crlEnable);
450         VerificationStatus result = verificator.check(coll);
451
452         if (result == VERIFICATION_STATUS_REVOKED) {
453             return SignatureValidator::SIGNATURE_REVOKED;
454         }
455
456         if (result == VERIFICATION_STATUS_UNKNOWN ||
457             result == VERIFICATION_STATUS_ERROR)
458         {
459             #ifdef _OCSP_POLICY_DISREGARD_UNKNOWN_OR_ERROR_CERTS_
460             disregard = true;
461             #endif
462         }
463     }
464 #endif
465
466     if (disregard) {
467         LogWarning("Signature is disregard. RootCA is not a member of Tizen");
468         return SignatureValidator::SIGNATURE_INVALID_DISTRIBUTOR_CERT;//SIGNATURE_DISREGARD;
469     }
470     return SignatureValidator::SIGNATURE_VERIFIED;
471 }
472
473 SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData &data,
474             const std::string &widgetContentPath,
475             const std::list<std::string>& uriList)
476 {
477     if(uriList.size() == 0 )
478        LogWarning("checkList >> no hash");
479
480     bool disregard = false;
481    
482     if (!checkRoleURI(data)) {
483         return SignatureValidator::SIGNATURE_INVALID;
484     }
485
486     if (!checkProfileURI(data)) {
487         return SignatureValidator::SIGNATURE_INVALID;
488     }
489
490     //  CertificateList sortedCertificateList = data.getCertList();
491
492     CertificateCollection collection;
493     collection.load(data.getCertList());
494
495     // First step - sort certificate
496     if (!collection.sort()) {
497         LogWarning("Certificates do not form valid chain.");
498         return SignatureValidator::SIGNATURE_INVALID;
499     }
500
501     // Check for error
502     if (collection.empty()) {
503         LogWarning("Certificate list in signature is empty.");
504         return SignatureValidator::SIGNATURE_INVALID;
505     }
506
507     CertificateList sortedCertificateList = collection.getChain();
508
509     // TODO move it to CertificateCollection
510     // Add root CA and CA certificates (if chain is incomplete)
511     sortedCertificateList =
512         OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList);
513
514     CertificatePtr root = sortedCertificateList.back();
515
516     // Is Root CA certificate trusted?
517     CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root);
518
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));
525
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));
529
530     if (data.isAuthorSignature())
531     {
532      if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
533      {
534             LogWarning("author-signature.xml has got unrecognized Root CA "
535                        "certificate. Signature will be disregarded.");
536             disregard = true;
537      }
538       LogDebug("Root CA for author signature is correct.");
539    }
540    else
541    {
542         LogDebug("signaturefile name = " << data.getSignatureFileName());
543
544       if (data.getSignatureNumber() == 1)
545       {
546          if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM))
547          {
548             LogDebug("Root CA for signature1.xml is correct.");
549          }
550          else
551          {
552             LogWarning("signature1.xml has got unrecognized Root CA "
553                        "certificate. Signature will be disregarded.");
554             disregard = true;
555          }
556       }
557    }
558
559     data.setStorageType(storeIdSet);
560     data.setSortedCertificateList(sortedCertificateList);
561
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;
567
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;
574     }
575
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);
579
580 #define CHECK_TIME
581 #ifdef CHECK_TIME
582
583     ASN1_TIME* notAfterTime = data.getEndEntityCertificatePtr()->getNotAfterTime();
584     ASN1_TIME* notBeforeTime = data.getEndEntityCertificatePtr()->getNotBeforeTime();
585
586   
587         if (X509_cmp_time(notBeforeTime, &nowTime) > 0  || X509_cmp_time(notAfterTime, &nowTime) < 0)
588         {
589       struct tm *t;
590       struct tm ta, tb, tc;
591       char msg[1024];
592
593       t = localtime(&nowTime);
594       if (!t)
595           return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;
596
597       memset(&tc, 0, sizeof(tc));
598
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);
602
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);
607
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);
612
613       if (storeIdSet.contains(CertStoreId::TIZEN_VERIFY))
614       {
615          LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE");
616          fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n");
617          return SignatureValidator::SIGNATURE_INVALID;
618       }
619
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;
624
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);
628
629       time_t outCurrent = mktime(&tc);
630       context.validationTime = outCurrent;
631       //return SignatureValidator::SIGNATURE_INVALID;
632     }
633
634 #endif
635
636 #if 0
637     time_t notAfter = data.getEndEntityCertificatePtr()->getNotAfter();
638     time_t notBefore = data.getEndEntityCertificatePtr()->getNotBefore();
639
640     struct tm *t;
641
642     if (data.isAuthorSignature())
643     {
644        // time_t 2038 year bug exist. So, notAtter() cann't check...
645        /*
646        if (notAfter < nowTime)
647        {
648           context.validationTime = notAfter - TIMET_DAY;
649           LogWarning("Author certificate is expired. notAfter...");
650        }
651        */
652
653        if (notBefore > nowTime)
654        {
655           LogWarning("Author certificate is expired. notBefore time is greater than system-time.");
656
657           t = localtime(&nowTime);
658
659           t = localtime(&notBefore);
660
661           context.validationTime = notBefore + TIMET_DAY;
662
663           t = localtime(&context.validationTime);
664       }
665     }
666 #endif
667     // WAC 2.0 SP-2066 The wrt must not block widget installation
668     //context.allowBrokenChain = true;
669
670     // end
671    if(uriList.size() == 0)
672    {
673      if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validateNoHash(&context)) {
674         LogWarning("Installation break - invalid package! >> validateNoHash");
675         return SignatureValidator::SIGNATURE_INVALID;
676      }
677    }
678    else if(uriList.size() != 0)
679    {
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;
684      }
685    }
686
687    data.setReference(context.referenceSet);
688    //if (!checkObjectReferences(data)) {
689    //     return SignatureValidator::SIGNATURE_INVALID;
690   // }
691
692    (void) widgetContentPath;
693   /*
694     ReferenceValidator fileValidator(widgetContentPath);
695     if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) {
696         LogWarning("Invalid package - file references broken");
697         return SignatureValidator::SIGNATURE_INVALID;
698     }
699  */
700
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);
709
710         if (!coll.sort()) {
711             LogDebug("Collection does not contain chain!");
712             return SignatureValidator::SIGNATURE_INVALID;
713         }
714
715         CertificateVerifier verificator(m_ocspEnable, m_crlEnable);
716         VerificationStatus result = verificator.check(coll);
717
718         if (result == VERIFICATION_STATUS_REVOKED) {
719             return SignatureValidator::SIGNATURE_REVOKED;
720         }
721
722         if (result == VERIFICATION_STATUS_UNKNOWN ||
723             result == VERIFICATION_STATUS_ERROR)
724         {
725             #ifdef _OCSP_POLICY_DISREGARD_UNKNOWN_OR_ERROR_CERTS_
726             disregard = true;
727             #endif
728         }
729     }
730 #endif
731
732     if (disregard) {
733         LogWarning("Signature is disregard. RootCA is not a member of Tizen.");
734         return SignatureValidator::SIGNATURE_DISREGARD;
735     }
736     return SignatureValidator::SIGNATURE_VERIFIED;
737 }
738
739 class ImplWacSignatureValidator : public SignatureValidator::ImplSignatureValidator
740 {
741   public:
742     SignatureValidator::Result check(SignatureData &data,
743             const std::string &widgetContentPath);
744
745     SignatureValidator::Result checkList(SignatureData &data,
746             const std::string &widgetContentPath,
747             const std::list<std::string>& uriList);
748     explicit ImplWacSignatureValidator(bool ocspEnable,
749                      bool crlEnable,
750                      bool complianceMode)
751       : ImplSignatureValidator(ocspEnable, crlEnable, complianceMode)
752     {}
753
754     virtual ~ImplWacSignatureValidator() {}
755 };
756
757
758 SignatureValidator::Result ImplWacSignatureValidator::checkList(
759         SignatureData & /* data */,
760         const std::string & /* widgetContentPath */,
761         const std::list<std::string>& /* uriList */)
762 {
763     return SignatureValidator::SIGNATURE_INVALID;
764 }
765
766
767 SignatureValidator::Result ImplWacSignatureValidator::check(
768     SignatureData &data,
769     const std::string &widgetContentPath)
770 {
771     bool disregard = false;
772
773     if (!checkRoleURI(data)) {
774         return SignatureValidator::SIGNATURE_INVALID;
775     }
776
777     if (!checkProfileURI(data)) {
778         return SignatureValidator::SIGNATURE_INVALID;
779     }
780
781     //  CertificateList sortedCertificateList = data.getCertList();
782
783     CertificateCollection collection;
784     collection.load(data.getCertList());
785
786     // First step - sort certificate
787     if (!collection.sort()) {
788         LogWarning("Certificates do not form valid chain.");
789         return SignatureValidator::SIGNATURE_INVALID;
790     }
791
792     // Check for error
793     if (collection.empty()) {
794         LogWarning("Certificate list in signature is empty.");
795         return SignatureValidator::SIGNATURE_INVALID;
796     }
797
798     CertificateList sortedCertificateList = collection.getChain();
799
800     // TODO move it to CertificateCollection
801     // Add root CA and CA certificates (if chain is incomplete)
802     sortedCertificateList =
803         OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList);
804
805     CertificatePtr root = sortedCertificateList.back();
806
807     // Is Root CA certificate trusted?
808     CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root);
809
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));
816
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));
820
821         if (data.isAuthorSignature())
822         {
823                 if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
824                 {
825                         LogWarning("author-signature.xml has got unrecognized Root CA "
826                                         "certificate. Signature will be disregarded.");
827                         disregard = true;
828                 }
829         } else {
830         LogDebug("signaturefile name = " << data.getSignatureFileName());
831                 if (storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
832                 {
833                         LogError("distributor has author level siganture! Signature will be disregarded.");
834                         return SignatureValidator::SIGNATURE_INVALID;
835                 }
836
837
838        if (data.getSignatureNumber() == 1)
839        {
840           if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM))
841           {
842              LogDebug("Root CA for signature1.xml is correct.");
843           }
844           else
845           {
846           LogWarning("signature1.xml has got unrecognized Root CA "
847                         "certificate. Signature will be disregarded.");
848              disregard = true;
849           }
850        }
851     }
852
853     data.setStorageType(storeIdSet);
854     data.setSortedCertificateList(sortedCertificateList);
855
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;
861
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;
868     }
869
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.
873 #define CHECK_TIME
874 #ifdef CHECK_TIME
875
876     ASN1_TIME* notAfterTime = data.getEndEntityCertificatePtr()->getNotAfterTime();
877     ASN1_TIME* notBeforeTime = data.getEndEntityCertificatePtr()->getNotBeforeTime();
878
879         if (X509_cmp_time(notBeforeTime, &nowTime) > 0  || X509_cmp_time(notAfterTime, &nowTime) < 0)
880         {
881       struct tm *t;
882       struct tm ta, tb, tc;
883       char msg[1024];
884
885       t = localtime(&nowTime);
886       if (!t)
887           return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;
888
889       memset(&tc, 0, sizeof(tc));
890
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);
894
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);
899
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);
904
905       if (storeIdSet.contains(CertStoreId::TIZEN_VERIFY))
906       {
907          LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE");
908          fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n");
909          return SignatureValidator::SIGNATURE_INVALID;
910       }
911
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;
916
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);
920
921       time_t outCurrent = mktime(&tc);
922       context.validationTime = outCurrent;
923       //return SignatureValidator::SIGNATURE_INVALID;
924     }
925   
926 #endif
927
928 #if 0
929     time_t notAfter = data.getEndEntityCertificatePtr()->getNotAfter();
930     time_t notBefore = data.getEndEntityCertificatePtr()->getNotBefore();
931
932     struct tm *t;
933
934     if (data.isAuthorSignature())
935     {
936       // time_t 2038 year bug exist. So, notAtter() cann't check...
937       /*
938       if (notAfter < nowTime)
939       {
940          context.validationTime = notAfter - TIMET_DAY;
941          LogWarning("Author certificate is expired. notAfter...");
942       }
943       */
944
945     if (notBefore > nowTime)
946     {
947        LogWarning("Author certificate is expired. notBefore time is greater than system-time.");
948
949        t = localtime(&nowTime);
950
951        t = localtime(&notBefore);
952
953        context.validationTime = notBefore + TIMET_DAY;
954
955        t = localtime(&context.validationTime);
956     }
957    }
958 #endif
959         if (!data.isAuthorSignature())
960         {
961                 if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) {
962                         LogWarning("Installation break - invalid package!");
963                         return SignatureValidator::SIGNATURE_INVALID;
964                 }
965
966                 data.setReference(context.referenceSet);
967
968                 if (!checkObjectReferences(data)) {
969                         return SignatureValidator::SIGNATURE_INVALID;
970                 }
971
972                 ReferenceValidator fileValidator(widgetContentPath);
973                 if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) {
974                         LogWarning("Invalid package - file references broken");
975                         return SignatureValidator::SIGNATURE_INVALID;
976                 }
977         }
978
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);
987
988         if (!coll.sort()) {
989             LogDebug("Collection does not contain chain!");
990             return SignatureValidator::SIGNATURE_INVALID;
991         }
992
993         CertificateVerifier verificator(m_ocspEnable, m_crlEnable);
994         VerificationStatus result = verificator.check(coll);
995
996         if (result == VERIFICATION_STATUS_REVOKED) {
997             return SignatureValidator::SIGNATURE_REVOKED;
998         }
999
1000         if (result == VERIFICATION_STATUS_UNKNOWN ||
1001             result == VERIFICATION_STATUS_ERROR)
1002         {
1003            #ifdef _OCSP_POLICY_DISREGARD_UNKNOWN_OR_ERROR_CERTS_
1004             disregard = true;
1005             #endif
1006         }
1007     }
1008 #endif
1009
1010     if (disregard) {
1011         LogWarning("Signature is disregard. RootCA is not a member of Tizen.");
1012         return SignatureValidator::SIGNATURE_DISREGARD;
1013     }
1014     return SignatureValidator::SIGNATURE_VERIFIED;
1015 }
1016
1017 // Implementation of SignatureValidator
1018
1019 SignatureValidator::SignatureValidator(
1020     AppType appType,
1021     bool ocspEnable,
1022     bool crlEnable,
1023     bool complianceMode)
1024   : m_impl(0)
1025 {
1026     LogDebug( "appType : " << appType );
1027
1028     if(appType == TIZEN)
1029     {
1030      m_impl = new ImplTizenSignatureValidator(ocspEnable,crlEnable,complianceMode);
1031     }
1032     else if(appType == WAC20)
1033     {
1034      m_impl = new ImplWacSignatureValidator(ocspEnable,crlEnable,complianceMode);
1035     }
1036 }
1037
1038 SignatureValidator::~SignatureValidator() {
1039     delete m_impl;
1040 }
1041
1042 SignatureValidator::Result SignatureValidator::check(
1043     SignatureData &data,
1044     const std::string &widgetContentPath)
1045 {
1046     return m_impl->check(data, widgetContentPath);
1047 }
1048
1049 SignatureValidator::Result SignatureValidator::checkList(
1050     SignatureData &data,
1051     const std::string &widgetContentPath,
1052     const std::list<std::string>& uriList)
1053 {
1054     return m_impl->checkList(data, widgetContentPath, uriList);
1055 }
1056
1057 } // namespace ValidationCore
1058