MYKeychain-iPhone.m
changeset 27 d0aadddb9c64
parent 24 6856e071d25a
     1.1 --- a/MYKeychain-iPhone.m	Tue Jun 09 23:58:03 2009 -0700
     1.2 +++ b/MYKeychain-iPhone.m	Tue Jul 21 10:13:08 2009 -0700
     1.3 @@ -14,6 +14,20 @@
     1.4  #if MYCRYPTO_USE_IPHONE_API
     1.5  
     1.6  
     1.7 +// from cssmtype.h:
     1.8 +enum {
     1.9 +    CSSM_CERT_UNKNOWN =					0x00,
    1.10 +    CSSM_CERT_X_509v1 =					0x01,
    1.11 +    CSSM_CERT_X_509v2 =					0x02,
    1.12 +    CSSM_CERT_X_509v3 =					0x03,
    1.13 +
    1.14 +    CSSM_CERT_ENCODING_UNKNOWN =		0x00,
    1.15 +    CSSM_CERT_ENCODING_CUSTOM =			0x01,
    1.16 +    CSSM_CERT_ENCODING_BER =			0x02,
    1.17 +    CSSM_CERT_ENCODING_DER =			0x03,
    1.18 +};
    1.19 +
    1.20 +
    1.21  @interface MYKeyEnumerator : NSEnumerator
    1.22  {
    1.23      CFArrayRef _results;
    1.24 @@ -98,7 +112,7 @@
    1.25  - (MYIdentity*) identityWithDigest: (MYSHA1Digest*)pubKeyDigest {
    1.26      return [MYKeyEnumerator firstItemWithQuery:
    1.27                  $mdict({(id)kSecClass, (id)kSecClassIdentity},
    1.28 -                        {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData})];
    1.29 +                       {(id)kSecAttrApplicationLabel/*kSecAttrPublicKeyHash*/, pubKeyDigest.asData})];
    1.30  }
    1.31  
    1.32  - (NSEnumerator*) enumerateIdentities {
    1.33 @@ -122,6 +136,50 @@
    1.34  #pragma mark IMPORT:
    1.35  
    1.36  
    1.37 ++ (CFTypeRef) _addItemWithInfo: (NSMutableDictionary*)info {
    1.38 +    // Generally SecItemAdd will fail (return paramErr) if asked to return a regular ref.
    1.39 +    // As a workaround ask for a persistent ref instead, then convert that to regular ref.
    1.40 +    if (![[info objectForKey: (id)kSecReturnRef] boolValue])
    1.41 +        [info setObject: $true forKey: (id)kSecReturnPersistentRef];
    1.42 +    
    1.43 +    CFDataRef itemPersistentRef;
    1.44 +    CFTypeRef item;
    1.45 +    OSStatus err = SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&itemPersistentRef);
    1.46 +    if (err==errSecDuplicateItem) {
    1.47 +        Log(@"_addItemWithInfo: Keychain claims it's a dup, so look for existing item");
    1.48 +        // it's already in the keychain -- get a reference to it:
    1.49 +		[info removeObjectForKey: (id)kSecReturnPersistentRef];
    1.50 +		[info setObject: $true forKey: (id)kSecReturnRef];
    1.51 +		if (check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&item), 
    1.52 +                  @"SecItemCopyMatching")) {
    1.53 +            if (!item)
    1.54 +                Warn(@"_addItemWithInfo: Couldn't find supposedly-duplicate item, info=%@",info);
    1.55 +            Log(@"_addItemWithInfo: SecItemAdd found item; ref=%@", item);//TEMP
    1.56 +            return item;
    1.57 +        }
    1.58 +    } else if (check(err, @"SecItemAdd")) {
    1.59 +        // It was added
    1.60 +        if ([[info objectForKey: (id)kSecReturnPersistentRef] boolValue]) {
    1.61 +            // now get its item ref:
    1.62 +            Log(@"SecItemAdd added item; persistenRef=%@", itemPersistentRef);//TEMP
    1.63 +            info = $mdict({(id)kSecValuePersistentRef, (id)itemPersistentRef},
    1.64 +            {(id)kSecReturnRef, $true});
    1.65 +            err = SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&item);
    1.66 +            CFRelease(itemPersistentRef);
    1.67 +            if (check(err,@"SecItemCopyMatching")) {
    1.68 +                Assert(item!=nil);
    1.69 +                return item;
    1.70 +            }
    1.71 +        } else {
    1.72 +            Log(@"SecItemAdd added item; ref=%@", itemPersistentRef);//TEMP
    1.73 +            return (CFTypeRef)itemPersistentRef;
    1.74 +        }
    1.75 +    }
    1.76 +    Log(@"SecItemAdd failed: info = %@", info); // for help in debugging, dump the input dict
    1.77 +    return NULL;
    1.78 +}
    1.79 +
    1.80 +
    1.81  - (MYPublicKey*) importPublicKey: (NSData*)keyData {
    1.82      return [[[MYPublicKey alloc] _initWithKeyData: keyData 
    1.83                                        forKeychain: self]
    1.84 @@ -131,13 +189,25 @@
    1.85  - (MYCertificate*) importCertificate: (NSData*)data
    1.86  {
    1.87      Assert(data);
    1.88 -    NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassCertificate},
    1.89 -                                {(id)kSecValueData, data},
    1.90 -                                {(id)kSecReturnRef, $true} );
    1.91 -    SecCertificateRef cert;
    1.92 -    if (!check(SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&cert), @"SecItemAdd"))
    1.93 +    
    1.94 +#if 1
    1.95 +    SecCertificateRef cert0 = SecCertificateCreateWithData(NULL, (CFDataRef)data);
    1.96 +    if (!cert0)
    1.97          return nil;
    1.98 -    return [[[MYCertificate alloc] initWithCertificateRef: cert] autorelease];
    1.99 +    NSMutableDictionary *info = $mdict( {(id)kSecClass, (id)kSecClassCertificate},
   1.100 +                                        {(id)kSecValueRef, (id)cert0});
   1.101 +#else
   1.102 +    NSMutableDictionary *info = $mdict( {(id)kSecClass, (id)kSecClassCertificate},
   1.103 +                                        {(id)kSecAttrCertificateType, $object(CSSM_CERT_X_509v3)},
   1.104 +                                        {(id)kSecAttrCertificateEncoding, $object(CSSM_CERT_ENCODING_BER)},
   1.105 +                                        {(id)kSecValueData, data} );
   1.106 +#endif
   1.107 +    SecCertificateRef cert = (SecCertificateRef) [[self class] _addItemWithInfo: info];
   1.108 +    if (!cert)
   1.109 +        return nil;
   1.110 +    MYCertificate *myCert = [[[MYCertificate alloc] initWithCertificateRef: cert] autorelease];
   1.111 +    AssertEqual(data, myCert.certificateData);  //TEMP for debugging
   1.112 +    return myCert;
   1.113  }
   1.114  
   1.115  
   1.116 @@ -157,6 +227,21 @@
   1.117  }
   1.118  
   1.119  
   1.120 +#pragma mark -
   1.121 +#pragma mark REMOVING:
   1.122 +
   1.123 +
   1.124 +- (BOOL) removeAllCertificates {
   1.125 +    NSDictionary *query = $dict({(id)kSecClass, (id)kSecClassCertificate});
   1.126 +    return check(SecItemDelete((CFDictionaryRef)query),  @"SecItemDelete");
   1.127 +}
   1.128 +
   1.129 +- (BOOL) removeAllKeys {
   1.130 +    NSDictionary *query = $dict({(id)kSecClass, (id)kSecClassKey});
   1.131 +    return check(SecItemDelete((CFDictionaryRef)query), @"SecItemDelete");
   1.132 +}
   1.133 +
   1.134 +
   1.135  @end
   1.136  
   1.137  
   1.138 @@ -190,7 +275,7 @@
   1.139              [self release];
   1.140              return nil;
   1.141          }
   1.142 -        Log(@"Enumerator results = %@", _results);//TEMP
   1.143 +        //Log(@"Enumerator results = %@", _results);
   1.144          
   1.145          if (_results && CFEqual(limit,kSecMatchLimitOne)) {
   1.146              // If you ask for only one, it gives you the object back instead of an array:
   1.147 @@ -225,7 +310,7 @@
   1.148      // when you try to use them for anything. As a workaround, detect these early on before
   1.149      // even creating a MYPublicKey:
   1.150      NSDictionary *info = $dict({(id)kSecValueRef, (id)itemRef},
   1.151 -    {(id)kSecReturnAttributes, $true});
   1.152 +                               {(id)kSecReturnAttributes, $true});
   1.153      CFDictionaryRef attrs = NULL;
   1.154      OSStatus err = SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs);
   1.155      if (attrs) CFRelease(attrs);