1.1 --- a/MYKey-iPhone.m Tue Jun 02 13:16:28 2009 -0700
1.2 +++ b/MYKey-iPhone.m Sun Jun 07 21:53:56 2009 -0700
1.3 @@ -19,6 +19,45 @@
1.4 @implementation MYKey
1.5
1.6
1.7 ++ (SecKeyRef) _addKeyWithInfo: (NSMutableDictionary*)info {
1.8 + if (![info objectForKey: (id)kSecAttrApplicationTag]) {
1.9 + // Every keychain item has to have a unique tag, apparently, or you'll get spurious
1.10 + // duplicate-item errors. If none was given, make up a random one:
1.11 + UInt8 tag[16];
1.12 + Assert(check(SecRandomCopyBytes(kSecRandomDefault, sizeof(tag), tag), @"SecRandomCopyBytes"));
1.13 + [info setObject: [NSData dataWithBytes: tag length: sizeof(tag)]
1.14 + forKey: (id)kSecAttrApplicationTag];
1.15 + }
1.16 + CFDataRef keyPersistentRef;
1.17 + SecKeyRef key;
1.18 + OSStatus err = SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&keyPersistentRef);
1.19 + if (err==errSecDuplicateItem) {
1.20 + // it's already in the keychain -- get a reference to it:
1.21 + [info removeObjectForKey: (id)kSecReturnPersistentRef];
1.22 + [info setObject: $true forKey: (id)kSecReturnRef];
1.23 + if (check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&key),
1.24 + @"SecItemCopyMatching"))
1.25 + return key;
1.26 + } else if (check(err, @"SecItemAdd")) {
1.27 + // It was added
1.28 + if ([[info objectForKey: (id)kSecReturnPersistentRef] boolValue]) {
1.29 + // now get its SecKeyRef:
1.30 + info = $mdict({(id)kSecValuePersistentRef, (id)keyPersistentRef},
1.31 + {(id)kSecReturnRef, $true});
1.32 + err = SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&key);
1.33 + CFRelease(keyPersistentRef);
1.34 + if (check(err,@"SecItemCopyMatching")) {
1.35 + Assert(key!=nil);
1.36 + return key;
1.37 + }
1.38 + } else {
1.39 + return (SecKeyRef)keyPersistentRef;
1.40 + }
1.41 + }
1.42 + return NULL;
1.43 +}
1.44 +
1.45 +
1.46 - (id) initWithKeyRef: (SecKeyRef)key {
1.47 return [super initWithKeychainItemRef: (SecKeychainItemRef)key];
1.48 }
1.49 @@ -27,45 +66,65 @@
1.50 - (id) _initWithKeyData: (NSData*)data
1.51 forKeychain: (SecKeychainRef)keychain
1.52 {
1.53 - NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
1.54 - {(id)kSecAttrKeyClass, (id)self.keyType},
1.55 - {(id)kSecValueData, data},
1.56 - {(id)kSecAttrIsPermanent, $object(keychain!=nil)},
1.57 - {(id)kSecReturnRef, $true} );
1.58 - SecKeyRef key;
1.59 - if (!check(SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&key), @"SecItemAdd"))
1.60 + NSMutableDictionary *info = $mdict({(id)kSecClass, (id)kSecClassKey},
1.61 + {(id)kSecAttrKeyType, (id)self.keyType},
1.62 + {(id)kSecValueData, data},
1.63 + {(id)kSecAttrIsPermanent, (keychain ?$true :$false)},
1.64 + {(id)kSecReturnPersistentRef, $true} );
1.65 + SecKeyRef key = [[self class] _addKeyWithInfo: info];
1.66 + if (!key) {
1.67 + [self release];
1.68 return nil;
1.69 - else
1.70 - return [self initWithKeyRef: (SecKeyRef)key];
1.71 + }
1.72 + self = [self initWithKeyRef: (SecKeyRef)key];
1.73 + if (self) {
1.74 + if (!keychain)
1.75 + _keyData = [data copy];
1.76 + }
1.77 + return self;
1.78 }
1.79
1.80 - (id) initWithKeyData: (NSData*)data {
1.81 return [self _initWithKeyData: data forKeychain: nil];
1.82 }
1.83
1.84 +- (void) dealloc
1.85 +{
1.86 + [_keyData release];
1.87 + [super dealloc];
1.88 +}
1.89
1.90 -- (SecExternalItemType) keyType {
1.91 +
1.92 +- (SecExternalItemType) keyClass {
1.93 AssertAbstractMethod();
1.94 }
1.95
1.96 +- (SecExternalItemType) keyType {
1.97 + return NULL;
1.98 +}
1.99
1.100 - (NSData*) keyData {
1.101 - NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
1.102 - {(id)kSecAttrKeyClass, (id)self.keyType},
1.103 - {(id)kSecMatchItemList, $array((id)self.keyRef)},
1.104 + if (_keyData)
1.105 + return _keyData;
1.106 +
1.107 + NSDictionary *info = $dict( {(id)kSecValueRef, (id)self.keyRef},
1.108 {(id)kSecReturnData, $true} );
1.109 CFDataRef data;
1.110 if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching"))
1.111 return nil;
1.112 - else
1.113 + else {
1.114 + Assert(data!=NULL);
1.115 return [(id)CFMakeCollectable(data) autorelease];
1.116 -
1.117 + }
1.118 // The format of this data is not documented. There's been some reverse-engineering:
1.119 // https://devforums.apple.com/message/32089#32089
1.120 // Apparently it is a DER-formatted sequence of a modulus followed by an exponent.
1.121 // This can be converted to OpenSSL format by wrapping it in some additional DER goop.
1.122 }
1.123
1.124 +- (MYSHA1Digest*) _keyDigest {
1.125 + return [self.keyData my_SHA1Digest];
1.126 +}
1.127
1.128 - (SecKeyRef) keyRef {
1.129 return (SecKeyRef) self.keychainItemRef;
1.130 @@ -73,13 +132,12 @@
1.131
1.132
1.133 - (id) _attribute: (CFTypeRef)attribute {
1.134 - NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
1.135 - {(id)kSecAttrKeyClass, (id)self.keyType},
1.136 - {(id)kSecMatchItemList, $array((id)self.keyRef)},
1.137 - {(id)kSecReturnAttributes, $true} );
1.138 + NSDictionary *info = $dict({(id)kSecValueRef, (id)self.keyRef},
1.139 + {(id)kSecReturnAttributes, $true});
1.140 CFDictionaryRef attrs = NULL;
1.141 if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs), @"SecItemCopyMatching"))
1.142 return nil;
1.143 + Log(@"_attribute: %@ of %@ %p", attribute, [self class], self.keyRef);//TEMP
1.144 CFTypeRef rawValue = CFDictionaryGetValue(attrs,attribute);
1.145 id value = rawValue ?[[(id)CFMakeCollectable(rawValue) retain] autorelease] :nil;
1.146 CFRelease(attrs);
1.147 @@ -90,7 +148,7 @@
1.148 if (!value)
1.149 value = (id)[NSNull null];
1.150 NSDictionary *query = $dict( {(id)kSecClass, (id)kSecClassKey},
1.151 - {(id)kSecAttrKeyClass, (id)self.keyType},
1.152 + {(id)kSecAttrKeyClass, (id)self.keyClass},
1.153 {(id)kSecMatchItemList, self._itemList} );
1.154 NSDictionary *attrs = $dict( {(id)attribute, value} );
1.155 return check(SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attrs), @"SecItemUpdate");