Changed the X.509 version number in generated certs from 1 to 3, so that SecCertificateCreateFromData on iPhone will accept them. :-/
5 // Created by Jens Alfke on 4/4/09.
6 // Copyright 2009 Jens Alfke. All rights reserved.
10 #import "MYCrypto_Private.h"
12 #if MYCRYPTO_USE_IPHONE_API
15 #import "MYErrorUtils.h"
22 + (SecKeyRef) _addKeyWithInfo: (NSMutableDictionary*)info {
23 if (![info objectForKey: (id)kSecAttrApplicationTag]) {
24 // Every keychain item has to have a unique tag, apparently, or you'll get spurious
25 // duplicate-item errors. If none was given, make up a random one:
27 Assert(check(SecRandomCopyBytes(kSecRandomDefault, sizeof(tag), tag), @"SecRandomCopyBytes"));
28 [info setObject: [NSData dataWithBytes: tag length: sizeof(tag)]
29 forKey: (id)kSecAttrApplicationTag];
31 CFDataRef keyPersistentRef;
33 OSStatus err = SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&keyPersistentRef);
34 if (err==errSecDuplicateItem) {
35 // it's already in the keychain -- get a reference to it:
36 [info removeObjectForKey: (id)kSecReturnPersistentRef];
37 [info setObject: $true forKey: (id)kSecReturnRef];
38 if (check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&key),
39 @"SecItemCopyMatching"))
41 } else if (check(err, @"SecItemAdd")) {
43 if ([[info objectForKey: (id)kSecReturnPersistentRef] boolValue]) {
44 // now get its SecKeyRef:
45 info = $mdict({(id)kSecValuePersistentRef, (id)keyPersistentRef},
46 {(id)kSecReturnRef, $true});
47 err = SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&key);
48 CFRelease(keyPersistentRef);
49 if (check(err,@"SecItemCopyMatching")) {
54 return (SecKeyRef)keyPersistentRef;
61 - (id) initWithKeyRef: (SecKeyRef)key {
62 return [self initWithKeychainItemRef: (SecKeychainItemRef)key];
66 - (id) _initWithKeyData: (NSData*)data
67 forKeychain: (SecKeychainRef)keychain
69 NSMutableDictionary *info = $mdict({(id)kSecClass, (id)kSecClassKey},
70 {(id)kSecAttrKeyType, (id)self.keyType},
71 {(id)kSecValueData, data},
72 {(id)kSecAttrIsPermanent, (keychain ?$true :$false)},
73 {(id)kSecReturnPersistentRef, $true} );
74 SecKeyRef key = [[self class] _addKeyWithInfo: info];
79 self = [self initWithKeyRef: (SecKeyRef)key];
82 _keyData = [data copy];
87 - (id) initWithKeyData: (NSData*)data {
88 return [self _initWithKeyData: data forKeychain: nil];
98 - (SecExternalItemType) keyClass {
99 AssertAbstractMethod();
102 - (SecExternalItemType) keyType {
106 - (NSData*) keyData {
110 NSDictionary *info = $dict( {(id)kSecValueRef, (id)self.keyRef},
111 {(id)kSecReturnData, $true} );
113 if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching"))
117 _keyData = NSMakeCollectable(data);
120 // The format of this data is not documented. There's been some reverse-engineering:
121 // https://devforums.apple.com/message/32089#32089
122 // Apparently it is a DER-formatted sequence of a modulus followed by an exponent.
123 // This can be converted to OpenSSL format by wrapping it in some additional DER goop.
126 - (MYSHA1Digest*) _keyDigest {
127 return [self.keyData my_SHA1Digest];
130 - (SecKeyRef) keyRef {
131 return (SecKeyRef) self.keychainItemRef;
135 - (id) _attribute: (CFTypeRef)attribute {
136 NSDictionary *info = $dict({(id)kSecValueRef, (id)self.keyRef},
137 {(id)kSecReturnAttributes, $true});
138 CFDictionaryRef attrs = NULL;
139 if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs), @"SecItemCopyMatching"))
141 Log(@"_attribute: %@ of %@ %p", attribute, [self class], self.keyRef);//TEMP
142 CFTypeRef rawValue = CFDictionaryGetValue(attrs,attribute);
143 id value = rawValue ?[[(id)CFMakeCollectable(rawValue) retain] autorelease] :nil;
148 - (BOOL) setValue: (NSString*)value ofAttribute: (SecKeychainAttrType)attribute {
150 value = (id)[NSNull null];
151 NSDictionary *query = $dict( {(id)kSecValueRef, (id)self.keyRef} );
152 NSDictionary *attrs = $dict( {(id)attribute, value} );
153 return check(SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attrs), @"SecItemUpdate");
158 return [self _attribute: kSecAttrLabel];
161 - (void) setName: (NSString*)name {
162 [self setValue: name ofAttribute: kSecAttrLabel];
165 - (NSString*) alias {
166 return [self _attribute: kSecAttrApplicationTag];
169 - (void) setAlias: (NSString*)alias {
170 [self setValue: alias ofAttribute: kSecAttrApplicationTag];
176 /** Asymmetric encryption/decryption; used by MYPublicKey and MYPrivateKey. */
177 - (NSData*) _crypt: (NSData*)data operation: (BOOL)operation {
179 size_t dataLength = data.length;
180 SecKeyRef key = self.keyRef;
181 size_t outputLength = MAX(dataLength, SecKeyGetBlockSize(key));
182 void *outputBuf = malloc(outputLength);
183 if (!outputBuf) return nil;
186 err = SecKeyEncrypt(key, kSecPaddingNone,//PKCS1,
187 data.bytes, dataLength,
188 outputBuf, &outputLength);
190 err = SecKeyDecrypt(key, kSecPaddingNone,//PKCS1,
191 data.bytes, dataLength,
192 outputBuf, &outputLength);
195 Warn(@"%scrypting failed (%i)", (operation ?"En" :"De"), err);
196 // Note: One of the errors I've seen is -9809, which is errSSLCrypto (SecureTransport.h)
199 return [NSData dataWithBytesNoCopy: outputBuf length: outputLength freeWhenDone: YES];
206 #endif MYCRYPTO_USE_IPHONE_API
211 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
213 Redistribution and use in source and binary forms, with or without modification, are permitted
214 provided that the following conditions are met:
216 * Redistributions of source code must retain the above copyright notice, this list of conditions
217 and the following disclaimer.
218 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
219 and the following disclaimer in the documentation and/or other materials provided with the
222 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
223 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
224 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
225 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
226 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
227 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
228 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
229 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.