MYKeychain-iPhone.m
author Jens Alfke <jens@mooseyard.com>
Thu Jun 04 18:36:30 2009 -0700 (2009-06-04)
changeset 19 f6c91b9da05b
parent 3 1dfe820d7ebe
child 21 2c300b15b381
permissions -rw-r--r--
Whew! MYParsedCertificate can now generate certs from scratch. Also added improvements and fixes to the BER/DER codecs.
snej@0
     1
//
snej@0
     2
//  MYKeychain-iPhone.m
snej@0
     3
//  MYCrypto-iPhone
snej@0
     4
//
snej@0
     5
//  Created by Jens Alfke on 3/31/09.
snej@0
     6
//  Copyright 2009 Jens Alfke. All rights reserved.
snej@0
     7
//
snej@0
     8
snej@0
     9
#import "MYCrypto_Private.h"
snej@0
    10
#import "MYDigest.h"
snej@5
    11
#import "MYIdentity.h"
snej@5
    12
snej@0
    13
snej@2
    14
#if MYCRYPTO_USE_IPHONE_API
snej@0
    15
snej@0
    16
snej@0
    17
@interface MYKeyEnumerator : NSEnumerator
snej@0
    18
{
snej@0
    19
    CFArrayRef _results;
snej@0
    20
    CFTypeRef _itemClass;
snej@0
    21
    CFIndex _index;
snej@0
    22
}
snej@0
    23
snej@0
    24
- (id) initWithQuery: (NSMutableDictionary*)query;
snej@0
    25
+ (id) firstItemWithQuery: (NSMutableDictionary*)query;
snej@0
    26
@end
snej@0
    27
snej@0
    28
snej@0
    29
snej@0
    30
@implementation MYKeychain
snej@0
    31
snej@0
    32
snej@0
    33
+ (MYKeychain*) allKeychains
snej@0
    34
{
snej@0
    35
    // iPhone only has a single keychain.
snej@0
    36
    return [self defaultKeychain];
snej@0
    37
}
snej@0
    38
snej@0
    39
+ (MYKeychain*) defaultKeychain
snej@0
    40
{
snej@0
    41
    static MYKeychain *sDefaultKeychain;
snej@0
    42
    @synchronized(self) {
snej@0
    43
        if (!sDefaultKeychain) {
snej@0
    44
            sDefaultKeychain = [[self alloc] init];
snej@0
    45
        }
snej@0
    46
    }
snej@0
    47
    return sDefaultKeychain;
snej@0
    48
}
snej@0
    49
snej@0
    50
snej@0
    51
- (id) copyWithZone: (NSZone*)zone {
snej@0
    52
    // It's not necessary to make copies of Keychain objects. This makes it more efficient
snej@0
    53
    // to use instances as NSDictionary keys or store them in NSSets.
snej@0
    54
    return [self retain];
snej@0
    55
}
snej@0
    56
snej@0
    57
snej@0
    58
snej@0
    59
#pragma mark -
snej@0
    60
#pragma mark SEARCHING:
snej@0
    61
snej@0
    62
snej@0
    63
- (MYPublicKey*) publicKeyWithDigest: (MYSHA1Digest*)pubKeyDigest {
snej@0
    64
    return [MYKeyEnumerator firstItemWithQuery:
snej@0
    65
                $mdict({(id)kSecClass, (id)kSecClassKey},
snej@0
    66
                      {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData},
snej@0
    67
                      {(id)kSecReturnRef, $true})];
snej@0
    68
}   
snej@0
    69
snej@0
    70
- (NSEnumerator*) enumeratePublicKeys {
snej@0
    71
    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
snej@0
    72
                                {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPublic},
snej@0
    73
                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
snej@0
    74
                                {(id)kSecReturnRef, $true});
snej@0
    75
    return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
snej@0
    76
}
snej@0
    77
snej@0
    78
snej@3
    79
- (MYPrivateKey*) privateKeyWithDigest: (MYSHA1Digest*)pubKeyDigest {
snej@0
    80
    return [MYKeyEnumerator firstItemWithQuery:
snej@0
    81
                $mdict({(id)kSecClass, (id)kSecClassKey},
snej@0
    82
                      {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate},
snej@0
    83
                      {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData},
snej@0
    84
                      {(id)kSecReturnRef, $true})];
snej@0
    85
}
snej@0
    86
snej@3
    87
- (NSEnumerator*) enumeratePrivateKeys {
snej@0
    88
    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
snej@0
    89
                                {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate},
snej@0
    90
                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
snej@0
    91
                                {(id)kSecReturnRef, $true});
snej@0
    92
    return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
snej@0
    93
}
snej@0
    94
snej@0
    95
- (MYCertificate*) certificateWithDigest: (MYSHA1Digest*)pubKeyDigest {
snej@0
    96
    return [MYKeyEnumerator firstItemWithQuery:
snej@0
    97
                $mdict({(id)kSecClass, (id)kSecClassCertificate},
snej@0
    98
                      {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData},
snej@0
    99
                      {(id)kSecReturnRef, $true})];
snej@0
   100
}
snej@0
   101
snej@0
   102
- (NSEnumerator*) enumerateCertificates {
snej@0
   103
    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassCertificate},
snej@0
   104
                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
snej@0
   105
                                {(id)kSecReturnRef, $true});
snej@0
   106
    return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
snej@0
   107
}
snej@0
   108
snej@5
   109
- (NSEnumerator*) enumerateIdentities {
snej@5
   110
    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassIdentity},
snej@5
   111
                                        {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
snej@5
   112
                                        {(id)kSecReturnRef, $true});
snej@5
   113
    return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
snej@5
   114
}
snej@5
   115
snej@0
   116
- (NSEnumerator*) enumerateSymmetricKeys {
snej@0
   117
    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
snej@0
   118
                                {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
snej@0
   119
                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
snej@0
   120
                                {(id)kSecReturnRef, $true});
snej@0
   121
    return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
snej@0
   122
}
snej@0
   123
snej@0
   124
- (NSEnumerator*) symmetricKeysWithAlias: (NSString*)alias {
snej@0
   125
    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
snej@0
   126
                                {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
snej@0
   127
                                {(id)kSecAttrApplicationTag, alias},
snej@0
   128
                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
snej@0
   129
                                {(id)kSecReturnRef, $true});
snej@0
   130
    return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
snej@0
   131
}
snej@0
   132
snej@0
   133
snej@0
   134
#pragma mark -
snej@0
   135
#pragma mark IMPORT:
snej@0
   136
snej@0
   137
snej@0
   138
- (MYPublicKey*) importPublicKey: (NSData*)keyData {
snej@0
   139
    return [[[MYPublicKey alloc] _initWithKeyData: keyData 
snej@0
   140
                                      forKeychain: self]
snej@0
   141
            autorelease];
snej@0
   142
}
snej@0
   143
snej@0
   144
- (MYCertificate*) importCertificate: (NSData*)data
snej@0
   145
{
snej@0
   146
    Assert(data);
snej@0
   147
    NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassCertificate},
snej@0
   148
                                {(id)kSecValueData, data},
snej@0
   149
                                {(id)kSecReturnRef, $true} );
snej@0
   150
    SecCertificateRef cert;
snej@0
   151
    if (!check(SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&cert), @"SecItemAdd"))
snej@0
   152
        return nil;
snej@0
   153
    return [[[MYCertificate alloc] initWithCertificateRef: cert] autorelease];
snej@0
   154
}
snej@0
   155
snej@0
   156
snej@0
   157
#pragma mark -
snej@0
   158
#pragma mark GENERATION:
snej@0
   159
snej@0
   160
snej@0
   161
- (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
snej@0
   162
                                     algorithm: (CCAlgorithm)algorithm
snej@0
   163
{
snej@0
   164
    return [MYSymmetricKey _generateSymmetricKeyOfSize: keySizeInBits
snej@0
   165
                                             algorithm: algorithm inKeychain: self];
snej@0
   166
}
snej@0
   167
snej@3
   168
- (MYPrivateKey*) generateRSAKeyPairOfSize: (unsigned)keySize {
snej@3
   169
    return [MYPrivateKey _generateRSAKeyPairOfSize: keySize inKeychain: self];
snej@0
   170
}
snej@0
   171
snej@0
   172
snej@0
   173
@end
snej@0
   174
snej@0
   175
snej@0
   176
snej@0
   177
#pragma mark -
snej@0
   178
@implementation MYKeyEnumerator
snej@0
   179
snej@0
   180
- (id) initWithQuery: (NSMutableDictionary*)query {
snej@0
   181
    self = [super init];
snej@0
   182
    if (self) {
snej@0
   183
        if (![query objectForKey: (id)kSecMatchLimit])
snej@0
   184
            [query setObject: (id)kSecMatchLimitAll forKey: (id)kSecMatchLimit];
snej@0
   185
        OSStatus err = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef*)&_results);
snej@0
   186
        if (err && err != errSecItemNotFound) {
snej@0
   187
            check(err,@"SecItemCopyMatching");
snej@0
   188
            [self release];
snej@0
   189
            return nil;
snej@0
   190
        }
snej@0
   191
        if (_results) CFRetain(_results);
snej@0
   192
        _itemClass = (CFTypeRef)[query objectForKey: (id)kSecClass];
snej@0
   193
        if (_itemClass == kSecClassKey)
snej@0
   194
            _itemClass = (CFTypeRef)[query objectForKey: (id)kSecAttrKeyClass];
snej@0
   195
        if (_itemClass) CFRetain(_itemClass);
snej@0
   196
    }
snej@0
   197
    return self;
snej@0
   198
}
snej@0
   199
snej@0
   200
+ (id) firstItemWithQuery: (NSMutableDictionary*)query {
snej@0
   201
    MYKeyEnumerator *e = [[self alloc] initWithQuery: query];
snej@0
   202
    MYKeychainItem *item = e.nextObject;
snej@0
   203
    [e release];
snej@0
   204
    return item;
snej@0
   205
}    
snej@0
   206
snej@0
   207
- (void) dealloc
snej@0
   208
{
snej@0
   209
    if (_itemClass) CFRelease(_itemClass);
snej@0
   210
    if (_results) CFRelease(_results);
snej@0
   211
    [super dealloc];
snej@0
   212
}
snej@0
   213
snej@0
   214
snej@0
   215
- (id) nextObject {
snej@0
   216
    if (!_results)
snej@0
   217
        return nil;
snej@0
   218
    MYKeychainItem *next = nil;
snej@2
   219
    while (next==nil && _index < CFArrayGetCount(_results)) {
snej@2
   220
        CFTypeRef found = CFArrayGetValueAtIndex(_results, _index++); 
snej@0
   221
        if (_itemClass == kSecAttrKeyClassPrivate) {
snej@3
   222
            next = [[MYPrivateKey alloc] initWithKeyRef: (SecKeyRef)found];
snej@0
   223
        } else if (_itemClass == kSecAttrKeyClassPublic) {
snej@0
   224
            next = [[[MYPublicKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease];
snej@0
   225
        } else if (_itemClass == kSecAttrKeyClassSymmetric) {
snej@0
   226
            next = [[[MYSymmetricKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease];
snej@0
   227
        } else if (_itemClass == kSecClassCertificate) {
snej@0
   228
            next = [[[MYCertificate alloc] initWithCertificateRef: (SecCertificateRef)found] autorelease];
snej@5
   229
        } else if (_itemClass == kSecClassIdentity) {
snej@5
   230
            next = [[[MYIdentity alloc] initWithIdentityRef: (SecIdentityRef)found] autorelease];
snej@0
   231
        }
snej@0
   232
        CFRelease(found);
snej@0
   233
    }
snej@0
   234
    return next;
snej@0
   235
}
snej@0
   236
snej@0
   237
snej@0
   238
@end
snej@0
   239
snej@2
   240
#endif MYCRYPTO_USE_IPHONE_API
snej@0
   241
snej@0
   242
snej@0
   243
/*
snej@0
   244
 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
snej@0
   245
 
snej@0
   246
 Redistribution and use in source and binary forms, with or without modification, are permitted
snej@0
   247
 provided that the following conditions are met:
snej@0
   248
 
snej@0
   249
 * Redistributions of source code must retain the above copyright notice, this list of conditions
snej@0
   250
 and the following disclaimer.
snej@0
   251
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
snej@0
   252
 and the following disclaimer in the documentation and/or other materials provided with the
snej@0
   253
 distribution.
snej@0
   254
 
snej@0
   255
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
snej@0
   256
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
snej@0
   257
 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
snej@0
   258
 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
snej@0
   259
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
snej@0
   260
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
snej@0
   261
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
snej@0
   262
 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
snej@0
   263
 */