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