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