2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
32 #include <security_cdsa_utilities/Schema.h>
33 #include <security_cdsa_utilities/KeySchema.h>
34 #include "cssmdatetime.h"
36 #include "StorageManager.h"
37 #include <Security/SecKeychainItemPriv.h>
40 using namespace KeychainCore
;
41 using namespace CssmClient
;
42 using namespace CSSMDateTimeUtils
;
44 using namespace KeySchema
;
46 // define a table of our attributes for easy lookup
47 static const CSSM_DB_ATTRIBUTE_INFO
* gKeyAttributeLookupTable
[] =
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
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()),
61 mMutex(Mutex::recursive
)
63 recordType(Schema::recordTypeFor(itemClass
));
65 if (!attrList
) // No additional selectionPredicates: we are done
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
)
73 const CSSM_DB_ATTRIBUTE_INFO
*temp
;
75 if (attr
->tag
<' ') // ok, is this a key schema? Handle differently, just because we can...
77 temp
= gKeyAttributeLookupTable
[attr
->tag
];
81 temp
= &Schema::attributeInfo(attr
->tag
);
83 const CssmDbAttributeInfo
&info
= *temp
;
84 void *buf
= attr
->data
;
85 UInt32 length
= attr
->length
;
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
)
93 if (length
== sizeof(UInt32
))
95 MacSecondsToTimeString(*reinterpret_cast<const UInt32
*>(buf
),
100 else if (length
== sizeof(SInt64
))
102 MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64
*>(buf
),
108 add(dbOperator
,info
, CssmData(buf
,length
));
112 KCCursorImpl::KCCursorImpl(const StorageManager::KeychainList
&searchList
, const SecKeychainAttributeList
*attrList
) :
113 mSearchList(searchList
),
114 mCurrent(mSearchList
.begin()),
116 mMutex(Mutex::recursive
)
118 if (!attrList
) // No additional selectionPredicates: we are done
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
)
127 if (attr
->tag
!=kSecClassItemAttr
) // a regular attribute
129 const CssmDbAttributeInfo
&info
= Schema::attributeInfo(attr
->tag
);
130 void *buf
= attr
->data
;
131 UInt32 length
= attr
->length
;
132 uint8 timeString
[16];
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
)
139 if (length
== sizeof(UInt32
))
141 MacSecondsToTimeString(*reinterpret_cast<const UInt32
*>(buf
),
146 else if (length
== sizeof(SInt64
))
148 MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64
*>(buf
),
154 add(CSSM_DB_EQUAL
,info
, CssmData(buf
,length
));
159 // the class attribute
160 if (foundClassAttribute
|| attr
->length
!= sizeof(SecItemClass
))
161 MacOSError::throwMe(errSecParam
); // We have 2 different 'clas' attributes
163 recordType(Schema::recordTypeFor(*reinterpret_cast<SecItemClass
*>(attr
->data
)));
164 foundClassAttribute
=true;
168 KCCursorImpl::~KCCursorImpl() throw()
172 //static ModuleNexus<Mutex> gActivationMutex;
175 KCCursorImpl::next(Item
&item
)
177 StLock
<Mutex
>_(mMutex
);
178 DbAttributes dbAttributes
;
179 DbUniqueRecord uniqueId
;
186 if (mCurrent
== mSearchList
.end())
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
);
193 // No more keychains to search so we are done.
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);
206 catch(const CommonError
&err
)
212 Keychain
&kc
= *mCurrent
;
213 Mutex
* mutex
= kc
->getKeychainMutex();
214 StLock
<Mutex
> _(*mutex
);
219 // Clear out existing attributes first!
220 // (the previous iteration may have left attributes from a different schema)
221 dbAttributes
.clear();
223 gotRecord
= mDbCursor
->next(&dbAttributes
, NULL
, uniqueId
);
226 catch(const CommonError
&err
)
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();
233 dbAttributes
.invalidate();
237 // Catch all other errors
238 status
= errSecItemNotFound
;
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.
247 mDbCursor
= DbCursor();
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
)
256 // Filter out group keys at this layer
257 if (dbAttributes
.recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
259 bool groupKey
= false;
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
)
268 CssmDbAttributeData
*label
= dbAttributes
.find(KeySchema::Label
);
272 if (attrData
.length() > 4 && !memcmp(attrData
.data(), "ssgp", 4))
277 dbAttributes
.invalidate();
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
);
298 bool KCCursorImpl::mayDelete()
300 if (mDbCursor
.get() != NULL
)
302 return mDbCursor
->isIdle();