Fix internal tests
[platform/core/security/cert-svc.git] / vcore / vcore / ReferenceValidator.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  * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
18  * @file        ReferenceValidator.cpp
19  * @version     1.0
20  * @brief       Compare signature reference list and list of widget file.
21  */
22 #include <vcore/ReferenceValidator.h>
23
24 #include <dirent.h>
25 #include <errno.h>
26 #include <fstream>
27 #include <memory>
28
29 #include <pcrecpp.h>
30
31 #include <dpl/log/log.h>
32
33 namespace {
34
35 const char *SPECIAL_SYMBOL_CURRENT_DIR = ".";
36 const char *SPECIAL_SYMBOL_UPPER_DIR = "..";
37 const char *SPECIAL_SYMBOL_AUTHOR_SIGNATURE_FILE = "author-signature.xml";
38 const char *REGEXP_DISTRIBUTOR_SIGNATURE = "^signature[1-9][0-9]*\\.xml";
39
40 const char MARK_ENCODED_CHAR = '%';
41
42 } // namespace anonymous
43
44 namespace ValidationCore {
45
46 class ReferenceValidator::Impl
47 {
48   public:
49     Impl(const std::string &dirpath)
50       : m_dirpath(dirpath)
51       , m_signatureRegexp(REGEXP_DISTRIBUTOR_SIGNATURE)
52     {}
53
54     virtual ~Impl(){}
55
56     Result checkReferences(const SignatureData &signatureData){
57         const ReferenceSet &refSet = signatureData.getReferenceSet();
58         ReferenceSet refDecoded;
59
60         try {
61             for (auto it = refSet.begin(); it != refSet.end(); ++it) {
62                 if (std::string::npos != it->find(MARK_ENCODED_CHAR))
63                     refDecoded.insert(decodeProcent(*it));
64                 else
65                     refDecoded.insert(*it);
66             }
67         } catch (Result &) {
68             return ERROR_DECODING_URL;
69         }
70         return dfsCheckDirectories(
71             refDecoded,
72             std::string(),
73             signatureData.isAuthorSignature());
74     }
75
76   private:
77     int hexToInt(char hex);
78     std::string decodeProcent(const std::string &path);
79
80     Result dfsCheckDirectories(
81         const ReferenceSet &referenceSet,
82         const std::string &directory,
83         bool isAuthorSignature);
84
85     inline bool isDistributorSignature(const char *cstring) const
86     {
87         return m_signatureRegexp.FullMatch(cstring);
88     }
89
90     std::string m_dirpath;
91     pcrecpp::RE m_signatureRegexp;
92 };
93
94 int ReferenceValidator::Impl::hexToInt(char a) {
95     if (a >= '0' && a <= '9') return a-'0';
96     if (a >= 'A' && a <= 'F') return a-'A' + 10;
97     if (a >= 'a' && a <= 'f') return a-'a' + 10;
98     LogError("Symbol '" << a << "' is out of scope.");
99     throw ERROR_DECODING_URL;
100 }
101
102 std::string ReferenceValidator::Impl::decodeProcent(const std::string &path) {
103     std::vector<int> input(path.begin(), path.end());
104     std::vector<char> output;
105     try {
106         size_t i = 0;
107         while(i<input.size()) {
108             if (MARK_ENCODED_CHAR == input[i]) {
109                 if (i+2 >= input.size())
110                     throw ERROR_DECODING_URL;
111
112                 int result = hexToInt(input[i+1])*16 + hexToInt(input[i+2]);
113
114                 // RFC 1738 - octets 80 to FF are not allowed
115                 if (result >= 128)
116                     throw ERROR_DECODING_URL;
117
118                 output.push_back(static_cast<char>(result));
119                 i+=3;
120             } else {
121                 output.push_back(static_cast<char>(input[i]));
122                 ++i;
123             }
124         }
125     } catch (Result &) {
126         LogError("Error while decoding url path : " << path);
127         throw ERROR_DECODING_URL;
128     }
129     return std::string(output.begin(), output.end());
130 }
131
132 ReferenceValidator::Result ReferenceValidator::Impl::dfsCheckDirectories(
133     const ReferenceSet &referenceSet,
134     const std::string &directory,
135     bool isAuthorSignature)
136 {
137     DIR *dp;
138     struct dirent *dirp;
139     std::string currentDir = m_dirpath;
140     if (!directory.empty()) {
141         currentDir += "/";
142         currentDir += directory;
143     }
144
145     if ((dp = opendir(currentDir.c_str())) == NULL) {
146         LogError("Error opening directory : " << currentDir);
147         return ERROR_OPENING_DIR;
148     }
149
150     for (errno = 0; (dirp = readdir(dp)) != NULL; errno = 0) {
151         if (!strcmp(dirp->d_name, SPECIAL_SYMBOL_CURRENT_DIR)) {
152             continue;
153         }
154
155         if (!strcmp(dirp->d_name, SPECIAL_SYMBOL_UPPER_DIR)) {
156             continue;
157         }
158
159         if (currentDir == m_dirpath && dirp->d_type == DT_REG &&
160             !strcmp(dirp->d_name, SPECIAL_SYMBOL_AUTHOR_SIGNATURE_FILE) &&
161             isAuthorSignature)
162         {
163             continue;
164         }
165
166         if (currentDir == m_dirpath && dirp->d_type == DT_REG &&
167             isDistributorSignature(dirp->d_name)) {
168             continue;
169         }
170
171         if (dirp->d_type == DT_DIR) {
172             LogDebug("Open directory : " << (directory + dirp->d_name));
173             std::string tmp_directory = directory + dirp->d_name + "/";
174             Result result = dfsCheckDirectories(referenceSet,
175                                                 tmp_directory,
176                                                 isAuthorSignature);
177             if (result != NO_ERROR) {
178                 closedir(dp);
179                 return result;
180             }
181         } else if (dirp->d_type == DT_REG) {
182             if (referenceSet.end() ==
183                 referenceSet.find(directory + dirp->d_name))
184             {
185                 LogDebug("Found file : " << (directory + dirp->d_name));
186                 LogError("Unknown ERROR_REFERENCE_NOT_FOUND.");
187                 closedir(dp);
188                 return ERROR_REFERENCE_NOT_FOUND;
189             }
190         } else {
191             LogError("Unknown file type.");
192             closedir(dp);
193             return ERROR_UNSUPPORTED_FILE_TYPE;
194         }
195     }
196
197     if (errno != 0) {
198         closedir(dp);
199         return ERROR_READING_DIR;
200     }
201
202     closedir(dp);
203
204     return NO_ERROR;
205 }
206
207 ReferenceValidator::ReferenceValidator(const std::string &dirpath)
208   : m_impl(new Impl(dirpath))
209 {}
210
211 ReferenceValidator::~ReferenceValidator(){
212     delete m_impl;
213 }
214
215 ReferenceValidator::Result ReferenceValidator::checkReferences(
216     const SignatureData &signatureData)
217 {
218     return m_impl->checkReferences(signatureData);
219 }
220
221 } // ValidationCore