349b9054bf3cb81b4c188604b9a84087424f560f
[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
30 #include <dpl/log/log.h>
31
32 namespace {
33 const time_t TIMET_DAY = 60 * 60 * 24;
34
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";
41
42 } // namespace anonymouse
43
44
45 static tm _ASN1_GetTimeT(ASN1_TIME* time)
46 {
47     struct tm t;
48     const char* str = (const char*) time->data;
49     size_t i = 0;
50
51     memset(&t, 0, sizeof(t));
52
53     if (time->type == V_ASN1_UTCTIME) /* two digit year */
54     {
55         t.tm_year = (str[i] - '0') * 10 + (str[i+1] - '0');
56         i += 2;
57         if (t.tm_year < 70)
58             t.tm_year += 100;
59     }
60     else if (time->type == V_ASN1_GENERALIZEDTIME) /* four digit year */
61     {
62         t.tm_year =
63             (str[i] - '0') * 1000
64             + (str[i+1] - '0') * 100
65             + (str[i+2] - '0') * 10
66             + (str[i+3] - '0');
67         i += 4;
68         t.tm_year -= 1900;
69     }
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');
75
76     /* Note: we did not adjust the time based on time zone information */
77     return t;
78 }
79
80
81 namespace ValidationCore {
82
83 class SignatureValidator::ImplSignatureValidator {
84 public:
85     virtual SignatureValidator::Result check(
86         SignatureData &data,
87         const std::string &widgetContentPath) = 0;
88
89     virtual SignatureValidator::Result checkList(
90         SignatureData &data,
91         const std::string &widgetContentPath,
92         const std::list<std::string>& uriList) = 0;
93
94     explicit ImplSignatureValidator(bool ocspEnable,
95                   bool crlEnable,
96                   bool complianceMode)
97       : m_complianceModeEnabled(complianceMode)
98     {
99         (void) ocspEnable;
100         (void) crlEnable;
101     }
102
103     virtual ~ImplSignatureValidator(){ }
104
105     bool checkRoleURI(const SignatureData &data) {
106         std::string roleURI = data.getRoleURI();
107
108         if (roleURI.empty()) {
109             LogWarning("URI attribute in Role tag couldn't be empty.");
110             return false;
111         }
112
113         if (roleURI != TOKEN_ROLE_AUTHOR_URI && data.isAuthorSignature()) {
114             LogWarning("URI attribute in Role tag does not "
115               "match with signature filename.");
116             return false;
117         }
118
119         if (roleURI != TOKEN_ROLE_DISTRIBUTOR_URI && !data.isAuthorSignature()) {
120             LogWarning("URI attribute in Role tag does not "
121               "match with signature filename.");
122             return false;
123         }
124         return true;
125     }
126
127     bool checkProfileURI(const SignatureData &data) {
128         if (TOKEN_PROFILE_URI != data.getProfileURI()) {
129             LogWarning(
130               "Profile tag contains unsupported value in URI attribute " << data.getProfileURI());
131             return false;
132         }
133         return true;
134     }
135
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);
142                 return false;
143             }
144         }
145         return true;
146     }
147 protected:
148     bool m_complianceModeEnabled;
149 };
150
151 class ImplTizenSignatureValidator : public SignatureValidator::ImplSignatureValidator
152 {
153   public:
154     SignatureValidator::Result check(SignatureData &data,
155             const std::string &widgetContentPath);
156
157     SignatureValidator::Result checkList(SignatureData &data,
158             const std::string &widgetContentPath,
159             const std::list<std::string>& uriList);
160     explicit ImplTizenSignatureValidator(bool ocspEnable,
161                        bool crlEnable,
162                        bool complianceMode)
163       : ImplSignatureValidator(ocspEnable, crlEnable, complianceMode)
164     {}
165
166     virtual ~ImplTizenSignatureValidator() {}
167 };
168
169 SignatureValidator::Result ImplTizenSignatureValidator::check(
170         SignatureData &data,
171         const std::string &widgetContentPath)
172 {
173     bool disregard = false;
174
175     if (!checkRoleURI(data)) {
176         return SignatureValidator::SIGNATURE_INVALID;
177     }
178
179     if (!checkProfileURI(data)) {
180         return SignatureValidator::SIGNATURE_INVALID;
181     }
182
183     //  CertificateList sortedCertificateList = data.getCertList();
184
185     CertificateCollection collection;
186     collection.load(data.getCertList());
187
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;
192     }
193
194     // Check for error
195     if (collection.empty()) {
196         LogWarning("Certificate list in signature is empty.");
197         return SignatureValidator::SIGNATURE_INVALID_CERT_CHAIN;//SIGNATURE_INVALID;
198     }
199
200     CertificateList sortedCertificateList = collection.getChain();
201
202     // TODO move it to CertificateCollection
203     // Add root CA and CA certificates (if chain is incomplete)
204     sortedCertificateList =
205         OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList);
206
207     CertificatePtr root = sortedCertificateList.back();
208
209     // Is Root CA certificate trusted?
210     CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root);
211
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));
219
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));
223
224         if (data.isAuthorSignature())
225         {
226                 if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
227                 {
228                         LogWarning("author-signature.xml has got unrecognized Root CA "
229                                         "certificate. Signature will be disregarded.");
230                         disregard = true;
231                 }
232    }
233    else
234    {
235                 LogDebug("signaturefile name = " << data.getSignatureFileName());
236                 if (storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
237                 {
238                         LogError("distributor has author level siganture! Signature will be disregarded.");
239                         return SignatureValidator::SIGNATURE_IN_DISTRIBUTOR_CASE_AUTHOR_CERT;//SIGNATURE_INVALID;
240                 }
241
242
243       if (data.getSignatureNumber() == 1)
244       {
245          if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM))
246          {
247             LogDebug("Root CA for signature1.xml is correct.");
248          }
249          else
250          {
251             LogWarning("signature1.xml has got unrecognized Root CA "
252                        "certificate. Signature will be disregarded.");
253             disregard = true;
254          }
255       }
256    }
257
258     data.setStorageType(storeIdSet);
259     data.setSortedCertificateList(sortedCertificateList);
260
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;
266
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;
273     }
274
275     time_t nowTime = time(NULL);
276
277 #define CHECK_TIME
278 #ifdef CHECK_TIME
279
280     ASN1_TIME* notAfterTime = data.getEndEntityCertificatePtr()->getNotAfterTime();
281     ASN1_TIME* notBeforeTime = data.getEndEntityCertificatePtr()->getNotBeforeTime();
282
283     if (X509_cmp_time(notBeforeTime, &nowTime) > 0  || X509_cmp_time(notAfterTime, &nowTime) < 0)
284     {
285       struct tm *t;
286       struct tm ta, tb, tc;
287       char msg[1024];
288
289       t = localtime(&nowTime);
290       if (!t)
291           return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;
292
293       memset(&tc, 0, sizeof(tc));
294
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);
298
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);
303
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);
308
309       if (storeIdSet.contains(CertStoreId::TIZEN_TEST) || storeIdSet.contains(CertStoreId::TIZEN_VERIFY))
310       {
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;
314       }
315
316       int year = (ta.tm_year - tb.tm_year) / 4;
317
318       if(year == 0)
319       {
320           tc.tm_year = tb.tm_year; 
321           tc.tm_mon = tb.tm_mon + 1;
322           tc.tm_mday = tb.tm_mday;
323
324           if(tc.tm_mon == 12)
325           {
326               tc.tm_year = ta.tm_year;       
327               tc.tm_mon = ta.tm_mon - 1;
328               tc.tm_mday = ta.tm_mday;
329               
330               if(tc.tm_mon < 0)
331               {
332                  tc.tm_year = ta.tm_year;
333                  tc.tm_mon = ta.tm_mon;
334                  tc.tm_mday = ta.tm_mday -1;
335
336                  if(tc.tm_mday == 0)
337                  {
338                     tc.tm_year = tb.tm_year;                
339                     tc.tm_mon = tb.tm_mon;
340                     tc.tm_mday = tb.tm_mday +1;
341                  }
342               }
343           }          
344       }
345       else{
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;  
349       }
350
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);
354
355       time_t outCurrent = mktime(&tc);
356       context.validationTime = outCurrent;
357       fprintf(stderr, "## cmp outCurrent time : %ld\n", outCurrent);
358       //return SignatureValidator::SIGNATURE_INVALID;
359     }
360
361 #endif
362     // WAC 2.0 SP-2066 The wrt must not block widget installation
363     // due to expiration of the author certificate.
364 #if 0
365     time_t notAfter = data.getEndEntityCertificatePtr()->getNotAfter();
366     time_t notBefore = data.getEndEntityCertificatePtr()->getNotBefore();
367
368     struct tm *t;
369
370     if (data.isAuthorSignature())
371         {
372        // time_t 2038 year bug exist. So, notAtter() cann't check...
373        /*
374        if (notAfter < nowTime)
375        {
376           context.validationTime = notAfter - TIMET_DAY;
377           LogWarning("Author certificate is expired. notAfter...");
378        }
379        */
380
381        if (notBefore > nowTime)
382        {
383           LogWarning("Author certificate is expired. notBefore time is greater than system-time.");
384
385           t = localtime(&nowTime);
386
387           t = localtime(&notBefore);
388
389           context.validationTime = notBefore + TIMET_DAY;
390
391           t = localtime(&context.validationTime);
392       }
393     }
394 #endif
395     // WAC 2.0 SP-2066 The wrt must not block widget installation
396     //context.allowBrokenChain = true;
397
398     // end
399
400         if (!data.isAuthorSignature())
401         {
402                 if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) {
403                         LogWarning("Installation break - invalid package!");
404                         return SignatureValidator::SIGNATURE_INVALID_HASH_SIGNATURE;//SIGNATURE_INVALID;
405                 }
406
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;
411                 }
412
413     (void) widgetContentPath;
414   /*
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;
419     }
420  */
421         }
422
423     if (disregard) {
424         LogWarning("Signature is disregard. RootCA is not a member of Tizen");
425         return SignatureValidator::SIGNATURE_INVALID_DISTRIBUTOR_CERT;//SIGNATURE_DISREGARD;
426     }
427     return SignatureValidator::SIGNATURE_VERIFIED;
428 }
429
430 SignatureValidator::Result ImplTizenSignatureValidator::checkList(SignatureData &data,
431             const std::string &widgetContentPath,
432             const std::list<std::string>& uriList)
433 {
434     if(uriList.size() == 0 )
435        LogWarning("checkList >> no hash");
436
437     bool disregard = false;
438    
439     if (!checkRoleURI(data)) {
440         return SignatureValidator::SIGNATURE_INVALID;
441     }
442
443     if (!checkProfileURI(data)) {
444         return SignatureValidator::SIGNATURE_INVALID;
445     }
446
447     //  CertificateList sortedCertificateList = data.getCertList();
448
449     CertificateCollection collection;
450     collection.load(data.getCertList());
451
452     // First step - sort certificate
453     if (!collection.sort()) {
454         LogWarning("Certificates do not form valid chain.");
455         return SignatureValidator::SIGNATURE_INVALID;
456     }
457
458     // Check for error
459     if (collection.empty()) {
460         LogWarning("Certificate list in signature is empty.");
461         return SignatureValidator::SIGNATURE_INVALID;
462     }
463
464     CertificateList sortedCertificateList = collection.getChain();
465
466     // TODO move it to CertificateCollection
467     // Add root CA and CA certificates (if chain is incomplete)
468     sortedCertificateList =
469         OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList);
470
471     CertificatePtr root = sortedCertificateList.back();
472
473     // Is Root CA certificate trusted?
474     CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root);
475
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));
482
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));
486
487     if (data.isAuthorSignature())
488     {
489      if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
490      {
491             LogWarning("author-signature.xml has got unrecognized Root CA "
492                        "certificate. Signature will be disregarded.");
493             disregard = true;
494      }
495       LogDebug("Root CA for author signature is correct.");
496    }
497    else
498    {
499         LogDebug("signaturefile name = " << data.getSignatureFileName());
500
501       if (data.getSignatureNumber() == 1)
502       {
503          if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM))
504          {
505             LogDebug("Root CA for signature1.xml is correct.");
506          }
507          else
508          {
509             LogWarning("signature1.xml has got unrecognized Root CA "
510                        "certificate. Signature will be disregarded.");
511             disregard = true;
512          }
513       }
514    }
515
516     data.setStorageType(storeIdSet);
517     data.setSortedCertificateList(sortedCertificateList);
518
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;
524
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;
531     }
532
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);
536
537 #define CHECK_TIME
538 #ifdef CHECK_TIME
539
540     ASN1_TIME* notAfterTime = data.getEndEntityCertificatePtr()->getNotAfterTime();
541     ASN1_TIME* notBeforeTime = data.getEndEntityCertificatePtr()->getNotBeforeTime();
542
543   
544         if (X509_cmp_time(notBeforeTime, &nowTime) > 0  || X509_cmp_time(notAfterTime, &nowTime) < 0)
545         {
546       struct tm *t;
547       struct tm ta, tb, tc;
548       char msg[1024];
549
550       t = localtime(&nowTime);
551       if (!t)
552           return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;
553
554       memset(&tc, 0, sizeof(tc));
555
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);
559
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);
564
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);
569
570       if (storeIdSet.contains(CertStoreId::TIZEN_VERIFY))
571       {
572          LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE");
573          fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n");
574          return SignatureValidator::SIGNATURE_INVALID;
575       }
576
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;
581
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);
585
586       time_t outCurrent = mktime(&tc);
587       context.validationTime = outCurrent;
588       //return SignatureValidator::SIGNATURE_INVALID;
589     }
590
591 #endif
592
593 #if 0
594     time_t notAfter = data.getEndEntityCertificatePtr()->getNotAfter();
595     time_t notBefore = data.getEndEntityCertificatePtr()->getNotBefore();
596
597     struct tm *t;
598
599     if (data.isAuthorSignature())
600     {
601        // time_t 2038 year bug exist. So, notAtter() cann't check...
602        /*
603        if (notAfter < nowTime)
604        {
605           context.validationTime = notAfter - TIMET_DAY;
606           LogWarning("Author certificate is expired. notAfter...");
607        }
608        */
609
610        if (notBefore > nowTime)
611        {
612           LogWarning("Author certificate is expired. notBefore time is greater than system-time.");
613
614           t = localtime(&nowTime);
615
616           t = localtime(&notBefore);
617
618           context.validationTime = notBefore + TIMET_DAY;
619
620           t = localtime(&context.validationTime);
621       }
622     }
623 #endif
624     // WAC 2.0 SP-2066 The wrt must not block widget installation
625     //context.allowBrokenChain = true;
626
627     // end
628    if(uriList.size() == 0)
629    {
630      if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validateNoHash(&context)) {
631         LogWarning("Installation break - invalid package! >> validateNoHash");
632         return SignatureValidator::SIGNATURE_INVALID;
633      }
634    }
635    else if(uriList.size() != 0)
636    {
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;
641      }
642    }
643
644    data.setReference(context.referenceSet);
645    //if (!checkObjectReferences(data)) {
646    //     return SignatureValidator::SIGNATURE_INVALID;
647   // }
648
649    (void) widgetContentPath;
650   /*
651     ReferenceValidator fileValidator(widgetContentPath);
652     if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) {
653         LogWarning("Invalid package - file references broken");
654         return SignatureValidator::SIGNATURE_INVALID;
655     }
656  */
657
658     if (disregard) {
659         LogWarning("Signature is disregard. RootCA is not a member of Tizen.");
660         return SignatureValidator::SIGNATURE_DISREGARD;
661     }
662     return SignatureValidator::SIGNATURE_VERIFIED;
663 }
664
665 class ImplWacSignatureValidator : public SignatureValidator::ImplSignatureValidator
666 {
667   public:
668     SignatureValidator::Result check(SignatureData &data,
669             const std::string &widgetContentPath);
670
671     SignatureValidator::Result checkList(SignatureData &data,
672             const std::string &widgetContentPath,
673             const std::list<std::string>& uriList);
674     explicit ImplWacSignatureValidator(bool ocspEnable,
675                      bool crlEnable,
676                      bool complianceMode)
677       : ImplSignatureValidator(ocspEnable, crlEnable, complianceMode)
678     {}
679
680     virtual ~ImplWacSignatureValidator() {}
681 };
682
683
684 SignatureValidator::Result ImplWacSignatureValidator::checkList(
685         SignatureData & /* data */,
686         const std::string & /* widgetContentPath */,
687         const std::list<std::string>& /* uriList */)
688 {
689     return SignatureValidator::SIGNATURE_INVALID;
690 }
691
692
693 SignatureValidator::Result ImplWacSignatureValidator::check(
694     SignatureData &data,
695     const std::string &widgetContentPath)
696 {
697     bool disregard = false;
698
699     if (!checkRoleURI(data)) {
700         return SignatureValidator::SIGNATURE_INVALID;
701     }
702
703     if (!checkProfileURI(data)) {
704         return SignatureValidator::SIGNATURE_INVALID;
705     }
706
707     //  CertificateList sortedCertificateList = data.getCertList();
708
709     CertificateCollection collection;
710     collection.load(data.getCertList());
711
712     // First step - sort certificate
713     if (!collection.sort()) {
714         LogWarning("Certificates do not form valid chain.");
715         return SignatureValidator::SIGNATURE_INVALID;
716     }
717
718     // Check for error
719     if (collection.empty()) {
720         LogWarning("Certificate list in signature is empty.");
721         return SignatureValidator::SIGNATURE_INVALID;
722     }
723
724     CertificateList sortedCertificateList = collection.getChain();
725
726     // TODO move it to CertificateCollection
727     // Add root CA and CA certificates (if chain is incomplete)
728     sortedCertificateList =
729         OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList);
730
731     CertificatePtr root = sortedCertificateList.back();
732
733     // Is Root CA certificate trusted?
734     CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root);
735
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));
742
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));
746
747         if (data.isAuthorSignature())
748         {
749                 if (!storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
750                 {
751                         LogWarning("author-signature.xml has got unrecognized Root CA "
752                                         "certificate. Signature will be disregarded.");
753                         disregard = true;
754                 }
755         } else {
756         LogDebug("signaturefile name = " << data.getSignatureFileName());
757                 if (storeIdSet.contains(CertStoreId::TIZEN_DEVELOPER))
758                 {
759                         LogError("distributor has author level siganture! Signature will be disregarded.");
760                         return SignatureValidator::SIGNATURE_INVALID;
761                 }
762
763
764        if (data.getSignatureNumber() == 1)
765        {
766           if (storeIdSet.contains(CertStoreId::VIS_PUBLIC) || storeIdSet.contains(CertStoreId::VIS_PARTNER) || storeIdSet.contains(CertStoreId::VIS_PLATFORM))
767           {
768              LogDebug("Root CA for signature1.xml is correct.");
769           }
770           else
771           {
772           LogWarning("signature1.xml has got unrecognized Root CA "
773                         "certificate. Signature will be disregarded.");
774              disregard = true;
775           }
776        }
777     }
778
779     data.setStorageType(storeIdSet);
780     data.setSortedCertificateList(sortedCertificateList);
781
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;
787
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;
794     }
795
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.
799 #define CHECK_TIME
800 #ifdef CHECK_TIME
801
802     ASN1_TIME* notAfterTime = data.getEndEntityCertificatePtr()->getNotAfterTime();
803     ASN1_TIME* notBeforeTime = data.getEndEntityCertificatePtr()->getNotBeforeTime();
804
805         if (X509_cmp_time(notBeforeTime, &nowTime) > 0  || X509_cmp_time(notAfterTime, &nowTime) < 0)
806         {
807       struct tm *t;
808       struct tm ta, tb, tc;
809       char msg[1024];
810
811       t = localtime(&nowTime);
812       if (!t)
813           return SignatureValidator::SIGNATURE_INVALID_CERT_TIME;
814
815       memset(&tc, 0, sizeof(tc));
816
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);
820
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);
825
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);
830
831       if (storeIdSet.contains(CertStoreId::TIZEN_VERIFY))
832       {
833          LogDebug("## TIZEN_VERIFY : check certificate Time : FALSE");
834          fprintf(stderr, "## TIZEN_VERIFY : check certificate Time : FALSE\n");
835          return SignatureValidator::SIGNATURE_INVALID;
836       }
837
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;
842
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);
846
847       time_t outCurrent = mktime(&tc);
848       context.validationTime = outCurrent;
849       //return SignatureValidator::SIGNATURE_INVALID;
850     }
851   
852 #endif
853
854 #if 0
855     time_t notAfter = data.getEndEntityCertificatePtr()->getNotAfter();
856     time_t notBefore = data.getEndEntityCertificatePtr()->getNotBefore();
857
858     struct tm *t;
859
860     if (data.isAuthorSignature())
861     {
862       // time_t 2038 year bug exist. So, notAtter() cann't check...
863       /*
864       if (notAfter < nowTime)
865       {
866          context.validationTime = notAfter - TIMET_DAY;
867          LogWarning("Author certificate is expired. notAfter...");
868       }
869       */
870
871     if (notBefore > nowTime)
872     {
873        LogWarning("Author certificate is expired. notBefore time is greater than system-time.");
874
875        t = localtime(&nowTime);
876
877        t = localtime(&notBefore);
878
879        context.validationTime = notBefore + TIMET_DAY;
880
881        t = localtime(&context.validationTime);
882     }
883    }
884 #endif
885         if (!data.isAuthorSignature())
886         {
887                 if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) {
888                         LogWarning("Installation break - invalid package!");
889                         return SignatureValidator::SIGNATURE_INVALID;
890                 }
891
892                 data.setReference(context.referenceSet);
893
894                 if (!checkObjectReferences(data)) {
895                         return SignatureValidator::SIGNATURE_INVALID;
896                 }
897
898                 ReferenceValidator fileValidator(widgetContentPath);
899                 if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) {
900                         LogWarning("Invalid package - file references broken");
901                         return SignatureValidator::SIGNATURE_INVALID;
902                 }
903         }
904
905     if (disregard) {
906         LogWarning("Signature is disregard. RootCA is not a member of Tizen.");
907         return SignatureValidator::SIGNATURE_DISREGARD;
908     }
909     return SignatureValidator::SIGNATURE_VERIFIED;
910 }
911
912 // Implementation of SignatureValidator
913
914 SignatureValidator::SignatureValidator(
915     AppType appType,
916     bool ocspEnable,
917     bool crlEnable,
918     bool complianceMode)
919   : m_impl(0)
920 {
921     LogDebug( "appType : " << appType );
922
923     if(appType == TIZEN)
924     {
925      m_impl = new ImplTizenSignatureValidator(ocspEnable,crlEnable,complianceMode);
926     }
927     else if(appType == WAC20)
928     {
929      m_impl = new ImplWacSignatureValidator(ocspEnable,crlEnable,complianceMode);
930     }
931 }
932
933 SignatureValidator::~SignatureValidator() {
934     delete m_impl;
935 }
936
937 SignatureValidator::Result SignatureValidator::check(
938     SignatureData &data,
939     const std::string &widgetContentPath)
940 {
941     return m_impl->check(data, widgetContentPath);
942 }
943
944 SignatureValidator::Result SignatureValidator::checkList(
945     SignatureData &data,
946     const std::string &widgetContentPath,
947     const std::list<std::string>& uriList)
948 {
949     return m_impl->checkList(data, widgetContentPath, uriList);
950 }
951
952 } // namespace ValidationCore
953