Factored out the name accessors of MYParsedCertificate into a new class MYCertificateName, so that both subject and issuer can be accessed. A bit of other cleanup too.
5 // Created by Jens Alfke on 3/26/09.
6 // Copyright 2009 Jens Alfke. All rights reserved.
9 #import "MYKeychainItem.h"
10 #import "MYCrypto_Private.h"
11 #import "MYErrorUtils.h"
14 NSString* const MYCSSMErrorDomain = @"CSSMErrorDomain";
17 @implementation MYKeychainItem
20 - (id) initWithKeychainItemRef: (MYKeychainItemRef)itemRef;
22 Assert(itemRef!=NULL);
32 @synthesize keychainItemRef=_itemRef;
36 if (_itemRef) CFRelease(_itemRef);
42 if (_itemRef) CFRelease(_itemRef);
46 - (id) copyWithZone: (NSZone*)zone {
47 // As keys are immutable, it's not necessary to make copies of them. This makes it more efficient
48 // to use instances as NSDictionary keys or store them in NSSets.
52 - (BOOL) isEqual: (id)obj {
53 return (obj == self) ||
54 ([obj isKindOfClass: [MYKeychainItem class]] && CFEqual(_itemRef, [obj keychainItemRef]));
58 return CFHash(_itemRef);
61 - (NSString*) description {
62 return $sprintf(@"%@[%p]", [self class], _itemRef); //FIX: Can we do anything better?
66 - (NSArray*) _itemList {
67 return $array((id)_itemRef);
70 #if MYCRYPTO_USE_IPHONE_API
71 - (CFDictionaryRef) asQuery {
72 return (CFDictionaryRef) $dict( {(id)kSecClass, (id)kSecClassKey},//FIX
73 {(id)kSecMatchItemList, self._itemList} );
78 - (MYKeychain*) keychain {
79 #if MYCRYPTO_USE_IPHONE_API
80 return [MYKeychain defaultKeychain];
82 MYKeychain *keychain = nil;
83 SecKeychainRef keychainRef = NULL;
84 if (check(SecKeychainItemCopyKeychain((SecKeychainItemRef)_itemRef, &keychainRef), @"SecKeychainItemCopyKeychain")) {
86 keychain = [[[MYKeychain alloc] initWithKeychainRef: keychainRef] autorelease];
87 CFRelease(keychainRef);
94 - (BOOL) removeFromKeychain {
96 #if MYCRYPTO_USE_IPHONE_API
97 err = SecItemDelete(self.asQuery);
99 err = SecKeychainItemDelete((SecKeychainItemRef)_itemRef);
100 if (err==errSecInvalidItemRef)
101 return YES; // result for an item that's not in a keychain
103 return err==errSecItemNotFound || check(err, @"SecKeychainItemDelete");
108 #pragma mark DATA / METADATA ACCESSORS:
111 - (NSData*) _getContents: (OSStatus*)outError {
112 NSData *contents = nil;
113 #if MYCRYPTO_USE_IPHONE_API
117 *outError = SecKeychainItemCopyAttributesAndData(_itemRef, NULL, NULL, NULL, &length, &bytes);
118 if (!*outError && bytes) {
119 contents = [NSData dataWithBytes: bytes length: length];
120 SecKeychainItemFreeAttributesAndData(NULL, bytes);
126 + (NSData*) _getAttribute: (SecKeychainAttrType)attr ofItem: (MYKeychainItemRef)item {
128 #if MYCRYPTO_USE_IPHONE_API
129 NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
130 {(id)kSecMatchItemList, $array((id)item)},
131 {(id)kSecReturnAttributes, $true} );
132 CFDictionaryRef attrs;
133 if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs), @"SecItemCopyMatching"))
135 CFTypeRef rawValue = CFDictionaryGetValue(attrs,attr);
136 value = rawValue ?[[(id)CFMakeCollectable(rawValue) retain] autorelease] :nil;
140 UInt32 format = kSecFormatUnknown;
141 SecKeychainAttributeInfo info = {.count=1, .tag=(UInt32*)&attr, .format=&format};
142 SecKeychainAttributeList *list = NULL;
144 if (check(SecKeychainItemCopyAttributesAndData((SecKeychainItemRef)item, &info,
145 NULL, &list, NULL, NULL),
146 @"SecKeychainItemCopyAttributesAndData")) {
148 if (list->count == 1)
149 value = [NSData dataWithBytes: list->attr->data
150 length: list->attr->length];
151 else if (list->count > 1)
152 Warn(@"Multiple values for keychain item attribute");
153 SecKeychainItemFreeAttributesAndData(list, NULL);
160 + (NSString*) _getStringAttribute: (SecKeychainAttrType)attr ofItem: (MYKeychainItemRef)item {
161 NSData *value = [self _getAttribute: attr ofItem: item];
162 if (!value) return nil;
163 const char *bytes = value.bytes;
164 size_t length = value.length;
165 if (length>0 && bytes[length-1] == 0)
166 length--; // Some values are null-terminated!?
167 NSString *str = [[NSString alloc] initWithBytes: bytes length: length
168 encoding: NSUTF8StringEncoding];
170 Warn(@"MYKeychainItem: Couldn't decode attr value as string");
171 return [str autorelease];
174 - (NSString*) stringValueOfAttribute: (SecKeychainAttrType)attr {
175 return [[self class] _getStringAttribute: attr ofItem: _itemRef];
179 + (BOOL) _setAttribute: (SecKeychainAttrType)attr ofItem: (MYKeychainItemRef)item
180 stringValue: (NSString*)stringValue
182 #if MYCRYPTO_USE_IPHONE_API
183 id value = stringValue ?(id)stringValue :(id)[NSNull null];
184 NSDictionary *query = $dict({(id)kSecClass, (id)kSecClassKey},
185 {(id)kSecAttrKeyType, (id)attr},
186 {(id)kSecMatchItemList, $array((id)item)});
187 NSDictionary *attrs = $dict({(id)attr, value});
188 return check(SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attrs), @"SecItemUpdate");
191 NSData *data = [stringValue dataUsingEncoding: NSUTF8StringEncoding];
192 SecKeychainAttribute attribute = {.tag=attr, .length=data.length, .data=(void*)data.bytes};
193 SecKeychainAttributeList list = {.count=1, .attr=&attribute};
194 return check(SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)item, &list, 0, NULL),
195 @"SecKeychainItemModifyAttributesAndData");
199 - (BOOL) setValue: (NSString*)valueStr ofAttribute: (SecKeychainAttrType)attr {
200 return [[self class] _setAttribute: attr ofItem: _itemRef stringValue: valueStr];
209 BOOL check(OSStatus err, NSString *what) {
211 #if !MYCRYPTO_USE_IPHONE_API
212 if (err < -2000000000)
213 return checkcssm(err,what);
215 Warn(@"MYCrypto error, %@: %@", what, MYErrorName(NSOSStatusErrorDomain,err));
221 #if !MYCRYPTO_USE_IPHONE_API
222 BOOL checkcssm(CSSM_RETURN err, NSString *what) {
223 if (err != CSSM_OK) {
224 Warn(@"MYCrypto error, %@: %@", what, MYErrorName(MYCSSMErrorDomain,err));
234 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
236 Redistribution and use in source and binary forms, with or without modification, are permitted
237 provided that the following conditions are met:
239 * Redistributions of source code must retain the above copyright notice, this list of conditions
240 and the following disclaimer.
241 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
242 and the following disclaimer in the documentation and/or other materials provided with the
245 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
246 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
247 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
248 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
249 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
250 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
251 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
252 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.