]> git.saurik.com Git - apple/security.git/blob - Security/libsecurity_keychain/lib/KCCursor.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_keychain / lib / KCCursor.cpp
1 /*
2 * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 //
26 // KCCursor.cpp
27 //
28
29 #include "KCCursor.h"
30
31 #include "Item.h"
32 #include <security_cdsa_utilities/Schema.h>
33 #include <security_cdsa_utilities/KeySchema.h>
34 #include "cssmdatetime.h"
35 #include "Globals.h"
36 #include "StorageManager.h"
37 #include <Security/SecKeychainItemPriv.h>
38 #include <SecBase.h>
39
40 using namespace KeychainCore;
41 using namespace CssmClient;
42 using namespace CSSMDateTimeUtils;
43
44 using namespace KeySchema;
45
46 // define a table of our attributes for easy lookup
47 static const CSSM_DB_ATTRIBUTE_INFO* gKeyAttributeLookupTable[] =
48 {
49 &KeyClass, &PrintName, &Alias, &Permanent, &Private, &Modifiable, &Label, &ApplicationTag, &KeyCreator,
50 &KeyType, &KeySizeInBits, &EffectiveKeySize, &StartDate, &EndDate, &Sensitive, &AlwaysSensitive, &Extractable,
51 &NeverExtractable, &Encrypt, &Decrypt, &Derive, &Sign, &Verify, &SignRecover, &VerifyRecover, &Wrap, &Unwrap
52 };
53
54 //
55 // KCCursorImpl
56 //
57 KCCursorImpl::KCCursorImpl(const StorageManager::KeychainList &searchList, SecItemClass itemClass, const SecKeychainAttributeList *attrList, CSSM_DB_CONJUNCTIVE dbConjunctive, CSSM_DB_OPERATOR dbOperator) :
58 mSearchList(searchList),
59 mCurrent(mSearchList.begin()),
60 mAllFailed(true),
61 mMutex(Mutex::recursive)
62 {
63 recordType(Schema::recordTypeFor(itemClass));
64
65 if (!attrList) // No additional selectionPredicates: we are done
66 return;
67
68 conjunctive(dbConjunctive);
69 const SecKeychainAttribute *end=&attrList->attr[attrList->count];
70 // Add all the attrs in attrs list to the cursor.
71 for (const SecKeychainAttribute *attr=attrList->attr; attr != end; ++attr)
72 {
73 const CSSM_DB_ATTRIBUTE_INFO *temp;
74
75 if (attr->tag <' ') // ok, is this a key schema? Handle differently, just because we can...
76 {
77 temp = gKeyAttributeLookupTable[attr->tag];
78 }
79 else
80 {
81 temp = &Schema::attributeInfo(attr->tag);
82 }
83 const CssmDbAttributeInfo &info = *temp;
84 void *buf = attr->data;
85 UInt32 length = attr->length;
86 uint8 timeString[16];
87
88 // XXX This code is duplicated in NewItemImpl::setAttribute()
89 // Convert a 4 or 8 byte TIME_DATE to a CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
90 // style attribute value.
91 if (info.format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE)
92 {
93 if (length == sizeof(UInt32))
94 {
95 MacSecondsToTimeString(*reinterpret_cast<const UInt32 *>(buf),
96 16, &timeString);
97 buf = &timeString;
98 length = 16;
99 }
100 else if (length == sizeof(SInt64))
101 {
102 MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64 *>(buf),
103 16, &timeString);
104 buf = &timeString;
105 length = 16;
106 }
107 }
108 add(dbOperator ,info, CssmData(buf,length));
109 }
110 }
111
112 KCCursorImpl::KCCursorImpl(const StorageManager::KeychainList &searchList, const SecKeychainAttributeList *attrList) :
113 mSearchList(searchList),
114 mCurrent(mSearchList.begin()),
115 mAllFailed(true),
116 mMutex(Mutex::recursive)
117 {
118 if (!attrList) // No additional selectionPredicates: we are done
119 return;
120
121 conjunctive(CSSM_DB_AND);
122 bool foundClassAttribute=false;
123 const SecKeychainAttribute *end=&attrList->attr[attrList->count];
124 // Add all the attrs in attrs list to the cursor.
125 for (const SecKeychainAttribute *attr=attrList->attr; attr != end; ++attr)
126 {
127 if (attr->tag!=kSecClassItemAttr) // a regular attribute
128 {
129 const CssmDbAttributeInfo &info = Schema::attributeInfo(attr->tag);
130 void *buf = attr->data;
131 UInt32 length = attr->length;
132 uint8 timeString[16];
133
134 // XXX This code is duplicated in NewItemImpl::setAttribute()
135 // Convert a 4 or 8 byte TIME_DATE to a CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
136 // style attribute value.
137 if (info.format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE)
138 {
139 if (length == sizeof(UInt32))
140 {
141 MacSecondsToTimeString(*reinterpret_cast<const UInt32 *>(buf),
142 16, &timeString);
143 buf = &timeString;
144 length = 16;
145 }
146 else if (length == sizeof(SInt64))
147 {
148 MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64 *>(buf),
149 16, &timeString);
150 buf = &timeString;
151 length = 16;
152 }
153 }
154 add(CSSM_DB_EQUAL,info, CssmData(buf,length));
155
156 continue;
157 }
158
159 // the class attribute
160 if (foundClassAttribute || attr->length != sizeof(SecItemClass))
161 MacOSError::throwMe(errSecParam); // We have 2 different 'clas' attributes
162
163 recordType(Schema::recordTypeFor(*reinterpret_cast<SecItemClass *>(attr->data)));
164 foundClassAttribute=true;
165 }
166 }
167
168 KCCursorImpl::~KCCursorImpl() throw()
169 {
170 }
171
172 //static ModuleNexus<Mutex> gActivationMutex;
173
174 bool
175 KCCursorImpl::next(Item &item)
176 {
177 StLock<Mutex>_(mMutex);
178 DbAttributes dbAttributes;
179 DbUniqueRecord uniqueId;
180 OSStatus status = 0;
181
182 for (;;)
183 {
184 while (!mDbCursor)
185 {
186 if (mCurrent == mSearchList.end())
187 {
188 // If we got always failed when calling mDbCursor->next return the error from
189 // the last call to mDbCursor->next now
190 if (mAllFailed && status)
191 CssmError::throwMe(status);
192
193 // No more keychains to search so we are done.
194 return false;
195 }
196
197 try
198 {
199 // StLock<Mutex> _(gActivationMutex()); // force serialization of cursor creation
200 Keychain &kc = *mCurrent;
201 Mutex* mutex = kc->getKeychainMutex();
202 StLock<Mutex> _(*mutex);
203 (*mCurrent)->database()->activate();
204 mDbCursor = DbCursor((*mCurrent)->database(), *this);
205 }
206 catch(const CommonError &err)
207 {
208 ++mCurrent;
209 }
210 }
211
212 Keychain &kc = *mCurrent;
213 Mutex* mutex = kc->getKeychainMutex();
214 StLock<Mutex> _(*mutex);
215
216 bool gotRecord;
217 try
218 {
219 // Clear out existing attributes first!
220 // (the previous iteration may have left attributes from a different schema)
221 dbAttributes.clear();
222
223 gotRecord = mDbCursor->next(&dbAttributes, NULL, uniqueId);
224 mAllFailed = false;
225 }
226 catch(const CommonError &err)
227 {
228 // Catch the last error we get and move on to the next keychain
229 // This error will be returned when we reach the end of our keychain list
230 // iff all calls to KCCursorImpl::next failed
231 status = err.osStatus();
232 gotRecord = false;
233 dbAttributes.invalidate();
234 }
235 catch(...)
236 {
237 // Catch all other errors
238 status = errSecItemNotFound;
239 gotRecord = false;
240 }
241
242 // If we did not get a record from the current keychain or the current
243 // keychain did not exist skip to the next keychain in the list.
244 if (!gotRecord)
245 {
246 ++mCurrent;
247 mDbCursor = DbCursor();
248 continue;
249 }
250
251 // If doing a search for all records, skip the db blob added by the CSPDL
252 if (dbAttributes.recordType() == CSSM_DL_DB_RECORD_METADATA &&
253 mDbCursor->recordType() == CSSM_DL_DB_RECORD_ANY)
254 continue;
255
256 // Filter out group keys at this layer
257 if (dbAttributes.recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
258 {
259 bool groupKey = false;
260 try
261 {
262 // fetch the key label attribute, if it exists
263 dbAttributes.add(KeySchema::Label);
264 Db db((*mCurrent)->database());
265 CSSM_RETURN getattr_result = CSSM_DL_DataGetFromUniqueRecordId(db->handle(), uniqueId, &dbAttributes, NULL);
266 if (getattr_result == CSSM_OK)
267 {
268 CssmDbAttributeData *label = dbAttributes.find(KeySchema::Label);
269 CssmData attrData;
270 if (label)
271 attrData = *label;
272 if (attrData.length() > 4 && !memcmp(attrData.data(), "ssgp", 4))
273 groupKey = true;
274 }
275 else
276 {
277 dbAttributes.invalidate();
278 }
279 }
280 catch (...) {}
281
282 if (groupKey)
283 continue;
284 }
285
286 break;
287 }
288
289 // Go though Keychain since item might already exist.
290 Keychain &kc = *mCurrent;
291 StLock<Mutex> _mutexLocker(*kc->getKeychainMutex());
292 item = (*mCurrent)->item(dbAttributes.recordType(), uniqueId);
293 return true;
294 }
295
296
297
298 bool KCCursorImpl::mayDelete()
299 {
300 if (mDbCursor.get() != NULL)
301 {
302 return mDbCursor->isIdle();
303 }
304 else
305 {
306 return true;
307 }
308 }