e965ecc6a9df0f6231fefa3a8f8969a4981bbb32
[framework/web/wrt-commons.git] / modules / 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 #include <libxml/parser.h>
17 #include <libxml/c14n.h>
18 #include <openssl/asn1.h>
19
20 #include <dpl/log/log.h>
21
22 #include "CertificateVerifier.h"
23 #include "OCSPCertMgrUtil.h"
24 #include "Certificate.h"
25 #include "ReferenceValidator.h"
26 #include "SignatureValidator.h"
27 #include "SSLContainers.h"
28 #include "ValidatorCommon.h"
29 #include "ValidatorFactories.h"
30 #include "XmlsecAdapter.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 } // namespace anonymouse
42
43 namespace ValidationCore {
44
45 SignatureValidator::SignatureValidator(bool ocspEnable,
46                                        bool crlEnable,
47                                        bool complianceMode) :
48     m_ocspEnable(ocspEnable),
49     m_crlEnable(crlEnable),
50     m_complianceModeEnabled(complianceMode)
51 {
52 }
53
54 SignatureValidator::~SignatureValidator()
55 {
56 }
57
58 bool SignatureValidator::checkRoleURI(const SignatureData &data)
59 {
60     std::string roleURI = data.getRoleURI();
61
62     if (roleURI.empty()) {
63         LogWarning("URI attribute in Role tag couldn't be empty.");
64         return false;
65     }
66
67     if (roleURI != TOKEN_ROLE_AUTHOR_URI && data.isAuthorSignature()) {
68         LogWarning("URI attribute in Role tag does not "
69                    "match with signature filename.");
70         return false;
71     }
72
73     if (roleURI != TOKEN_ROLE_DISTRIBUTOR_URI && !data.isAuthorSignature()) {
74         LogWarning("URI attribute in Role tag does not "
75                    "match with signature filename.");
76         return false;
77     }
78     return true;
79 }
80
81 bool SignatureValidator::checkProfileURI(const SignatureData &data)
82 {
83     if (TOKEN_PROFILE_URI != data.getProfileURI()) {
84         LogWarning(
85             "Profile tag contains unsupported value in URI attribute(" <<
86             data.getProfileURI() << ").");
87         return false;
88     }
89     return true;
90 }
91
92 bool SignatureValidator::checkObjectReferences(const SignatureData &data)
93 {
94     ObjectList objectList = data.getObjectList();
95     ObjectList::const_iterator iter;
96     for (iter = objectList.begin(); iter != objectList.end(); ++iter) {
97         if (!data.containObjectReference(*iter)) {
98             LogWarning("Signature does not contain reference for object " <<
99                        *iter);
100             return false;
101         }
102     }
103     return true;
104 }
105
106 SignatureValidator::Result SignatureValidator::check(
107         SignatureData &data,
108         const std::string &widgetContentPath)
109 {
110     bool disregard = false;
111
112     if (!checkRoleURI(data)) {
113         return SIGNATURE_INVALID;
114     }
115
116     if (!checkProfileURI(data)) {
117         return SIGNATURE_INVALID;
118     }
119
120     //  CertificateList sortedCertificateList = data.getCertList();
121
122     CertificateCollection collection;
123     collection.load(data.getCertList());
124
125     // First step - sort certificate
126     if (!collection.sort()) {
127         LogWarning("Certificates do not form valid chain.");
128         return SIGNATURE_INVALID;
129     }
130
131     // Check for error
132     if (collection.empty()) {
133         LogWarning("Certificate list in signature is empty.");
134         return SIGNATURE_INVALID;
135     }
136
137     CertificateList sortedCertificateList = collection.getChain();
138
139     // TODO move it to CertificateCollection
140     // Add root CA and CA certificates (if chain is incomplete)
141     sortedCertificateList =
142         OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList);
143
144     CertificatePtr root = sortedCertificateList.back();
145
146     // Is Root CA certificate trusted?
147     CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root);
148
149     // WAC chapter 3.2.1 - verified definition
150     if (data.isAuthorSignature()) {
151         if (!storeIdSet.contains(CertStoreId::WAC_PUBLISHER)) {
152             LogWarning("Author signature has got unrecognized Root CA "
153                        "certificate. Signature will be disregarded.");
154             disregard = true;
155         }
156         LogDebug("Root CA for author signature is correct.");
157     } else {
158         if (!storeIdSet.contains(CertStoreId::DEVELOPER) &&
159             !storeIdSet.contains(CertStoreId::WAC_ROOT) &&
160             !storeIdSet.contains(CertStoreId::WAC_MEMBER))
161         {
162             LogWarning("Distiributor signature has got unrecognized Root CA "
163                        "certificate. Signature will be disregarded.");
164             disregard = true;
165         }
166         LogDebug("Root CA for distributor signature is correct.");
167     }
168
169     data.setStorageType(storeIdSet);
170     data.setSortedCertificateList(sortedCertificateList);
171
172     // We add only Root CA certificate because WAC ensure that the rest
173     // of certificates are present in signature files ;-)
174     XmlSec::XmlSecContext context;
175     context.signatureFile = data.getSignatureFileName();
176     context.certificatePtr = root;
177
178     // Now we should have full certificate chain.
179     // If the end certificate is not ROOT CA we should disregard signature
180     // but still signature must be valid... Aaaaaa it's so stupid...
181     if (!(root->isSignedBy(root))) {
182         LogWarning("Root CA certificate not found. Chain is incomplete.");
183         context.allowBrokenChain = true;
184     }
185
186     // WAC 2.0 SP-2066 The wrt must not block widget installation
187     // due to expiration of the author certificate.
188     time_t notAfter = data.getEndEntityCertificatePtr()->getNotAfter();
189     bool expired = notAfter < time(NULL);
190     if (data.isAuthorSignature() && expired) {
191         context.validationTime = notAfter - TIMET_DAY;
192     }
193     // end
194
195     if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) {
196         LogWarning("Installation break - invalid package!");
197         return SIGNATURE_INVALID;
198     }
199
200     data.setReference(context.referenceSet);
201
202     if (!checkObjectReferences(data)) {
203         return SIGNATURE_INVALID;
204     }
205
206     ReferenceValidator fileValidator(widgetContentPath);
207     if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) {
208         LogWarning("Invalid package - file references broken");
209         return SIGNATURE_INVALID;
210     }
211
212     // It is good time to do OCSP check
213     // ocspCheck will throw an exception on any error.
214     // TODO Probably we should catch this exception and add
215     // some information to SignatureData.
216     if (!m_complianceModeEnabled && !data.isAuthorSignature()) {
217         CertificateCollection coll;
218         coll.load(sortedCertificateList);
219
220         if (!coll.sort()) {
221             LogDebug("Collection does not contain chain!");
222             return SIGNATURE_INVALID;
223         }
224
225         CertificateVerifier verificator(m_ocspEnable, m_crlEnable);
226         VerificationStatus result = verificator.check(coll);
227
228         if (result == VERIFICATION_STATUS_REVOKED) {
229             return SIGNATURE_REVOKED;
230         }
231
232         if (result == VERIFICATION_STATUS_UNKNOWN ||
233             result == VERIFICATION_STATUS_ERROR)
234         {
235             disregard = true;
236         }
237     }
238
239     if (disregard) {
240         LogWarning("Signature is disregard.");
241         return SIGNATURE_DISREGARD;
242     }
243     return SIGNATURE_VERIFIED;
244 }
245
246 std::string SignatureValidator::FingerprintToColonHex(
247         const Certificate::Fingerprint &fingerprint)
248 {
249     std::string outString;
250
251     char buff[8];
252
253     for (size_t i = 0; i < fingerprint.size(); ++i) {
254         snprintf(buff,
255                  sizeof(buff),
256                  "%02X:",
257                  static_cast<unsigned int>(fingerprint[i]));
258         outString += buff;
259     }
260
261     // remove trailing ":"
262     outString.erase(outString.end() - 1);
263     return outString;
264 }
265 } // namespace ValidationCore