MYKey-iPhone.m
changeset 23 39fec79de6e8
parent 16 c409dbc4f068
child 24 6856e071d25a
     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");