sync with master
[platform/framework/native/appfw.git] / src / io / FIo_SecureRegistry.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 /**
19  * @file        FIo_SecureRegistry.cpp
20  * @brief       This is the implementation file for _SecureRegistry class.
21  */
22 #include <unique_ptr.h>
23 #include <FBaseInteger.h>
24 #include <FBaseDouble.h>
25 #include <FBaseFloat.h>
26 #include <FBaseUuId.h>
27 #include <FBaseByteBuffer.h>
28 #include <FBaseColIEnumerator.h>
29 #include <FBaseUtilStringTokenizer.h>
30 #include <FBaseResult.h>
31 #include <FIoFile.h>
32 #include <FIoRegistry.h>
33 #include <FIo_SecureRegistry.h>
34 #include <FBase_StringConverter.h>
35 #include <FBaseSysLog.h>
36 #include <FIo_FileImpl.h>
37 #include <FIo_SecureIoUtil.h>
38
39 using namespace std;
40 using namespace Tizen::Base;
41 using namespace Tizen::Base::Utility;
42 using namespace Tizen::Base::Collection;
43
44 namespace Tizen { namespace Io
45 {
46
47 static const wchar_t* _CIPHER_INFORMATRION = L"CBC/128/PKCS7PADDING";
48
49 static result
50 _SaveLengthOfFile(void* pFileSecure)
51 {
52         int length = 0;
53         byte legnthOfFile[SECURE_IO_LOF_SIZE] = {0, 0, 0, 0};
54         _FileImpl* pFile = reinterpret_cast< _FileImpl* >(pFileSecure);
55         result r = pFile->Seek(FILESEEKPOSITION_END, 0);
56
57         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Seek file has failed.", GetErrorMessage(r));
58
59         length = pFile->Tell();
60         SysTryReturn(NID_IO, length != -1, r = GetLastResult(), GetLastResult(), "[%s] Tell file has failed.", GetErrorMessage(GetLastResult()));
61
62         r = pFile->Seek(FILESEEKPOSITION_BEGIN, SECURE_REG_HEADER_STRING_SIZE + SECURE_IO_10_BYTES);
63         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Seek file has failed.", GetErrorMessage(r));
64
65         if (sizeof(length) != SECURE_IO_LOF_SIZE)
66         {
67                 memcpy(legnthOfFile + SECURE_IO_LOF_SIZE - sizeof(length), &length, sizeof(length));
68         }
69         else
70         {
71                 memcpy(legnthOfFile, &length, SECURE_IO_LOF_SIZE);
72         }
73
74         r = pFile->Write(legnthOfFile, SECURE_IO_LOF_SIZE);
75         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Write file has failed.", GetErrorMessage(r));
76
77         return r;
78 }
79
80 _SecureRegistry::_SecureRegistry(void)
81         : __pSecretKey(null)
82 {
83 }
84
85 _SecureRegistry::~_SecureRegistry(void)
86 {
87         if (_write == true && _FileImpl::IsFileExist(_regPath) == true && _update == true)
88         {
89                 this->Flush();
90         }
91
92         _sectionList.RemoveAll(true);
93
94         delete __pSecretKey;
95         __pSecretKey = null;
96 }
97
98 result
99 _SecureRegistry::Construct(const String& regPath, const char* pOpenMode, const ByteBuffer* pSecretKey)
100 {
101         SysAssertf(_constructed == false, "Already constructed. Calling Construct() twice or more on a same instance is not allowed for this class\n");
102         SysTryReturnResult(NID_IO, !(pSecretKey != null && (pSecretKey->GetRemaining() <= 0)), E_INVALID_ARG,
103                                            "A key is not valid to encrypt or decrypt a registry file");
104
105         bool isValidOpenMode = this->VerifyRegistryOpenMode(pOpenMode);
106         SysTryReturnResult(NID_IO, isValidOpenMode == true, E_INVALID_ARG, "The specified openMode is invalid. (%s)", pOpenMode);
107
108         int length = 0;
109         byte* pRegCont = null;
110         ByteBuffer registryContent;
111         unique_ptr< ByteBuffer > pDecryptedRegBuffer(null);
112         result r = Load(regPath, pOpenMode);
113
114         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Registry file read is failed.", GetErrorMessage(r));
115
116         unique_ptr< ByteBuffer > pKey(_SecureIoUtil::GetSecureKeyN(pSecretKey));
117         SysTryReturnResult(NID_IO, !(pKey != null && (pKey->GetRemaining() < ONE_BLOCK_SIZE)), E_INVALID_ARG, "Failed to get a key.");
118
119         if (_pBuffer == null)
120         {
121                 _constructed = true;
122                 //Save registry file path and file open mode
123                 _regPath.Clear();
124                 _regPath.Append(regPath);
125                 __pSecretKey = pKey.release();
126                 return E_SUCCESS;
127         }
128
129         r = _SecureIoUtil::CheckSecureRegistryHeader(&_pBuffer, &_length, regPath, true);
130         SysTryCatch(NID_IO, (!IsFailed(r)), , r, "[%s] Failed to check registry header.", GetErrorMessage(r));
131
132         length = _length;
133         pRegCont = _pBuffer;
134
135         pRegCont = pRegCont + SECURE_REG_HEADER_SIZE_V1;
136         length -= SECURE_REG_HEADER_SIZE_V1;
137
138         SysTryReturnResult(NID_IO, length > 0, E_SUCCESS, "Only header, no data to parse.");
139
140         r = registryContent.Construct(length);
141         SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to construct byte buffer.", GetErrorMessage(r));
142
143         r = registryContent.SetArray((byte*) pRegCont, 0, length);
144         SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to set array elements.", GetErrorMessage(r));
145
146         registryContent.Flip();
147
148         pDecryptedRegBuffer = unique_ptr< ByteBuffer >(_SecureIoUtil::DoCipherAesN(_CIPHER_INFORMATRION, registryContent, *pKey.get(), Tizen::Security::Crypto::CIPHER_DECRYPT));
149         SysTryCatch(NID_IO, pDecryptedRegBuffer != null, r = E_IO, E_IO, "[E_IO] Failed to decrypt registry data.");
150
151         delete[] _pBuffer;
152         _pBuffer = null;
153         _length = 0;
154
155         length = pDecryptedRegBuffer->GetRemaining();
156
157         _pBuffer = new (std::nothrow) byte[length + 1];
158         SysTryCatch(NID_IO, _pBuffer, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
159
160         r = pDecryptedRegBuffer->GetArray(_pBuffer, 0, length);
161         SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to get array elements.", GetErrorMessage(r));
162
163         _pBuffer[length] = 0;
164         _length = length;
165
166         r = Parse();
167         SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to parse registry.", GetErrorMessage(r));
168
169         _constructed = true;
170         //Save registry file path and file open mode
171         _regPath.Clear();
172         _regPath.Append(regPath);
173
174         __pSecretKey = pKey.release();
175
176         return r;
177
178 CATCH:
179
180         if (IsFailed(r))
181         {
182                 delete[] _pBuffer;
183                 _pBuffer = null;
184
185                 _length = 0;
186         }
187
188         return r;
189 }
190
191 result
192 _SecureRegistry::Flush(void)
193 {
194         SysAssertf(_constructed == true, "Not yet constructed. Construct() should be called before use.\n");
195         SysAssertf(!(__pSecretKey == null || (__pSecretKey != null && __pSecretKey->GetRemaining() < ONE_BLOCK_SIZE)),
196                            "_SecureRegistry is not constructed.");
197
198         int dataSize = 0;
199         int length = 0;
200         byte nameIndex = 0;
201         byte regHeader[SECURE_REG_HEADER_SIZE_V1];
202         byte reservedValue[SECURE_IO_STATIC_BIN_LEN] = {0xCA, 0xFE, 0xBE, 0xBE, 0xDA, 0xEF, 0xEB, 0xEB};
203         ByteBuffer regBuffer;
204         String replicaFileName;
205         String fileOpenMode(L"w+");
206         bool fileExists = false;
207         result r = PrepareToWrite();
208         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Registry data make is failed.", GetErrorMessage(r));
209
210         SysTryReturnResult(NID_IO, (_pBuffer && _length > 0), E_SUCCESS, "Buffer length 0, Nothing to write, so success!");
211
212         fileExists = _FileImpl::IsFileExist(_regPath);
213
214         replicaFileName = _SecureIoUtil::MakeRegistryReplica(_regPath, &nameIndex);
215         SysTryReturn(NID_IO, GetLastResult() == E_SUCCESS, GetLastResult(), GetLastResult(), "[%s] Failed to make registry replica.", GetErrorMessage(GetLastResult()));
216
217         unique_ptr< _FileImpl > pFileImpl(new (std::nothrow) _FileImpl());
218         SysTryReturnResult(NID_IO, pFileImpl != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
219
220         r = pFileImpl->Construct(_regPath, fileOpenMode, false, null);
221         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Constructing the file has failed.", GetErrorMessage(r));
222
223         if (fileExists && _SecureIoUtil::IsEmpty(_regPath) == false)
224         {
225                 r = _SecureIoUtil::SetRegistryFlag(pFileImpl.get(), FLAG_STATE_CTF);
226                 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags in registry header.", GetErrorMessage(r));
227
228                 r = pFileImpl->Truncate(SECURE_REG_HEADER_SIZE_V1);
229                 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to trucate registry file.", GetErrorMessage(r));
230         }
231
232         length = _length;
233
234         r = regBuffer.Construct(length);
235         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Propagated.", GetErrorMessage(r));
236
237         r = regBuffer.SetArray((byte*) _pBuffer, 0, length);
238         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Propagated.", GetErrorMessage(r));
239
240         regBuffer.Flip();
241
242         unique_ptr< ByteBuffer > pEncryptedData(_SecureIoUtil::DoCipherAesN(_CIPHER_INFORMATRION, regBuffer, *__pSecretKey, Tizen::Security::Crypto::CIPHER_ENCRYPT));
243         SysTryReturn(NID_IO, pEncryptedData != null, E_IO, E_IO, "[E_IO] Failed to encrypt data.");
244
245         r = pFileImpl->Seek(FILESEEKPOSITION_BEGIN, 0);
246         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Seek file has failed.", GetErrorMessage(r));
247
248         memcpy(regHeader, SECURE_REG_HEADER_STRING, SECURE_REG_HEADER_STRING_SIZE);
249         memcpy(regHeader + SECURE_REG_HEADER_STRING_SIZE, reservedValue, SECURE_IO_STATIC_BIN_LEN);
250         regHeader[SECURE_REG_HEADER_STRING_SIZE + SECURE_IO_STATIC_BIN_LEN] = 1;
251         regHeader[SECURE_REG_HEADER_STRING_SIZE + SECURE_IO_STATIC_BIN_LEN + 1] = nameIndex;
252         memset(regHeader + SECURE_REG_HEADER_STRING_SIZE + SECURE_IO_STATIC_BIN_LEN + SECURE_IO_2_BYTES, 0, SECURE_IO_LOF_SIZE);
253         memset(regHeader + SECURE_REG_HEADER_STRING_SIZE + SECURE_IO_STATIC_BIN_LEN + SECURE_IO_2_BYTES + SECURE_IO_LOF_SIZE, 0, SECURE_IO_LOF_SIZE);
254
255         r = pFileImpl->Write(regHeader, SECURE_REG_HEADER_SIZE_V1);
256         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to write secure header to registry file!", GetErrorMessage(r));
257
258         r = pFileImpl->Write(*pEncryptedData);
259         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to write secure header to registry file!", GetErrorMessage(r));
260
261         r = pFileImpl->Flush();
262         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to flush the registry.", GetErrorMessage(r));
263
264         pFileImpl.reset(null);
265
266         //reopen file to update LOF and replica flag.
267         pFileImpl = unique_ptr< _FileImpl >(new (std::nothrow) _FileImpl());
268         SysTryReturnResult(NID_IO, pFileImpl != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
269
270         r = pFileImpl->Construct(_regPath, L"r+", false, null);
271         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Constructing the file has failed.", GetErrorMessage(r));
272
273         r = _SecureIoUtil::SetRegistryFlag(pFileImpl.get(), FLAG_STATE_CVF_CTF);
274         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags to registry header.", GetErrorMessage(r));
275
276         r = _SaveLengthOfFile(pFileImpl.get());
277         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set length to registry header.", GetErrorMessage(r));
278
279         r = pFileImpl->Seek(FILESEEKPOSITION_BEGIN, 0);
280         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Seek file has failed.", GetErrorMessage(r));
281
282         memset(regHeader, 0, sizeof(regHeader));
283         dataSize = pFileImpl->Read(regHeader, SECURE_REG_HEADER_SIZE_V1);
284
285         if (dataSize < SECURE_REG_HEADER_SIZE_V1)
286         {
287                 r = GetLastResult();
288                 SysLog(NID_IO, "[%s]Failed to read secure header", GetErrorMessage(r));
289                 return r;
290         }
291
292         if (_FileImpl::IsFileExist(replicaFileName))
293         {
294                 r = _FileImpl::Remove(replicaFileName);
295                 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s]Failed to delete replica file.", GetErrorMessage(r));
296         }
297
298         r = _SecureIoUtil::DeleteRegistryReplica(regHeader, _regPath);
299         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to delete replica file.", GetErrorMessage(r));
300
301         r = _SecureIoUtil::SetRegistryFlag(pFileImpl.get(), FLAG_STATE_CVF);
302         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags in registry file.", GetErrorMessage(r));
303
304         return r;
305 }
306
307 }} // Tizen::Io