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.
16 #include <libxml/parser.h>
17 #include <libxml/c14n.h>
18 #include <openssl/asn1.h>
20 #include <dpl/log/log.h>
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"
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";
41 } // namespace anonymouse
43 namespace ValidationCore {
45 SignatureValidator::SignatureValidator(bool ocspEnable,
47 bool complianceMode) :
48 m_ocspEnable(ocspEnable),
49 m_crlEnable(crlEnable),
50 m_complianceModeEnabled(complianceMode)
54 SignatureValidator::~SignatureValidator()
58 bool SignatureValidator::checkRoleURI(const SignatureData &data)
60 std::string roleURI = data.getRoleURI();
62 if (roleURI.empty()) {
63 LogWarning("URI attribute in Role tag couldn't be empty.");
67 if (roleURI != TOKEN_ROLE_AUTHOR_URI && data.isAuthorSignature()) {
68 LogWarning("URI attribute in Role tag does not "
69 "match with signature filename.");
73 if (roleURI != TOKEN_ROLE_DISTRIBUTOR_URI && !data.isAuthorSignature()) {
74 LogWarning("URI attribute in Role tag does not "
75 "match with signature filename.");
81 bool SignatureValidator::checkProfileURI(const SignatureData &data)
83 if (TOKEN_PROFILE_URI != data.getProfileURI()) {
85 "Profile tag contains unsupported value in URI attribute(" <<
86 data.getProfileURI() << ").");
92 bool SignatureValidator::checkObjectReferences(const SignatureData &data)
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 " <<
106 SignatureValidator::Result SignatureValidator::check(
108 const std::string &widgetContentPath)
110 bool disregard = false;
112 if (!checkRoleURI(data)) {
113 return SIGNATURE_INVALID;
116 if (!checkProfileURI(data)) {
117 return SIGNATURE_INVALID;
120 // CertificateList sortedCertificateList = data.getCertList();
122 CertificateCollection collection;
123 collection.load(data.getCertList());
125 // First step - sort certificate
126 if (!collection.sort()) {
127 LogWarning("Certificates do not form valid chain.");
128 return SIGNATURE_INVALID;
132 if (collection.empty()) {
133 LogWarning("Certificate list in signature is empty.");
134 return SIGNATURE_INVALID;
137 CertificateList sortedCertificateList = collection.getChain();
139 // TODO move it to CertificateCollection
140 // Add root CA and CA certificates (if chain is incomplete)
141 sortedCertificateList =
142 OCSPCertMgrUtil::completeCertificateChain(sortedCertificateList);
144 CertificatePtr root = sortedCertificateList.back();
146 // Is Root CA certificate trusted?
147 CertStoreId::Set storeIdSet = createCertificateIdentifier().find(root);
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.");
156 LogDebug("Root CA for author signature is correct.");
158 if (!storeIdSet.contains(CertStoreId::DEVELOPER) &&
159 !storeIdSet.contains(CertStoreId::WAC_ROOT) &&
160 !storeIdSet.contains(CertStoreId::WAC_MEMBER))
162 LogWarning("Distiributor signature has got unrecognized Root CA "
163 "certificate. Signature will be disregarded.");
166 LogDebug("Root CA for distributor signature is correct.");
169 data.setStorageType(storeIdSet);
170 data.setSortedCertificateList(sortedCertificateList);
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;
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;
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;
195 if (XmlSec::NO_ERROR != XmlSecSingleton::Instance().validate(&context)) {
196 LogWarning("Installation break - invalid package!");
197 return SIGNATURE_INVALID;
200 data.setReference(context.referenceSet);
202 if (!checkObjectReferences(data)) {
203 return SIGNATURE_INVALID;
206 ReferenceValidator fileValidator(widgetContentPath);
207 if (ReferenceValidator::NO_ERROR != fileValidator.checkReferences(data)) {
208 LogWarning("Invalid package - file references broken");
209 return SIGNATURE_INVALID;
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);
221 LogDebug("Collection does not contain chain!");
222 return SIGNATURE_INVALID;
225 CertificateVerifier verificator(m_ocspEnable, m_crlEnable);
226 VerificationStatus result = verificator.check(coll);
228 if (result == VERIFICATION_STATUS_REVOKED) {
229 return SIGNATURE_REVOKED;
232 if (result == VERIFICATION_STATUS_UNKNOWN ||
233 result == VERIFICATION_STATUS_ERROR)
240 LogWarning("Signature is disregard.");
241 return SIGNATURE_DISREGARD;
243 return SIGNATURE_VERIFIED;
246 std::string SignatureValidator::FingerprintToColonHex(
247 const Certificate::Fingerprint &fingerprint)
249 std::string outString;
253 for (size_t i = 0; i < fingerprint.size(); ++i) {
257 static_cast<unsigned int>(fingerprint[i]));
261 // remove trailing ":"
262 outString.erase(outString.end() - 1);
265 } // namespace ValidationCore