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 3/21/09.
6 // Copyright 2009 Jens Alfke. All rights reserved.
10 #import "MYCrypto_Private.h"
12 #import "MYErrorUtils.h"
14 #if !MYCRYPTO_USE_IPHONE_API
21 - (id) initWithKeyRef: (SecKeyRef)key {
22 return [super initWithKeychainItemRef: (SecKeychainItemRef)key];
25 - (id) _initWithKeyData: (NSData*)keyData
26 forKeychain: (SecKeychainRef)keychain {
28 SecKeyImportExportParameters params = {};
29 SecKeyRef key = importKey(keyData, self.keyClass, keychain, ¶ms);
34 self = [self initWithKeyRef: key];
39 - (id) initWithKeyData: (NSData*)data {
40 return [self _initWithKeyData: data forKeychain: nil];
44 - (NSString*) description {
45 return $sprintf(@"%@[%@ /%p]", [self class], (self.name ?:@""), self.keychainItemRef);
48 - (SecExternalItemType) keyClass {
49 AssertAbstractMethod();
52 #if MYCRYPTO_USE_IPHONE_API
53 - (SecExternalItemType) keyType {
58 - (SecKeyRef) keyRef {
59 return (SecKeyRef) self.keychainItemRef;
62 - (const CSSM_KEY*) cssmKey {
63 const CSSM_KEY *cssmKey = NULL;
64 Assert(check(SecKeyGetCSSMKey(self.keyRef, &cssmKey), @"SecKeyGetCSSMKey"),
65 @"Failed to get CSSM_KEY");
69 - (const CSSM_CSP_HANDLE) cssmCSPHandle {
70 CSSM_CSP_HANDLE cspHandle = 0;
71 Assert(check(SecKeyGetCSPHandle(self.keyRef, &cspHandle), @"SecKeyGetCSPHandle"),
72 @"Failed to get CSSM_CSP_HANDLE");
76 - (CSSM_ALGORITHMS) cssmAlgorithm {
77 return self.cssmKey->KeyHeader.AlgorithmId;
80 - (const CSSM_ACCESS_CREDENTIALS*) cssmCredentialsForOperation: (CSSM_ACL_AUTHORIZATION_TAG)operation
81 type: (SecCredentialType)type
82 error: (NSError**)outError
84 const CSSM_ACCESS_CREDENTIALS *credentials = NULL;
85 OSStatus err = SecKeyGetCredentials(self.keyRef,
89 if (!MYReturnError(outError, err,NSOSStatusErrorDomain, @"Couldn't get credentials for key"))
94 - (SecExternalFormat) _externalFormat {
95 return kSecFormatRawKey;
99 CFDataRef data = NULL;
100 if (check(SecKeychainItemExport(self.keyRef, self._externalFormat, 0, NULL, &data),
101 @"SecKeychainItemExport"))
102 return [(id)CFMakeCollectable(data) autorelease];
108 return [self stringValueOfAttribute: kSecKeyPrintName];
111 - (void) setName: (NSString*)name {
112 [self setValue: name ofAttribute: kSecKeyPrintName];
115 - (NSString*) comment {
116 return [self stringValueOfAttribute: kSecKeyApplicationTag];
119 - (void) setComment: (NSString*)comment {
120 [self setValue: comment ofAttribute: kSecKeyApplicationTag];
123 - (NSString*) alias {
124 return [self stringValueOfAttribute: kSecKeyAlias];
127 - (void) setAlias: (NSString*)alias {
128 [self setValue: alias ofAttribute: kSecKeyAlias];
133 #pragma mark UTILITY FUNCTIONS:
136 SecKeyRef importKey(NSData *data,
137 SecExternalItemType type,
138 SecKeychainRef keychain,
139 SecKeyImportExportParameters *params) {
140 SecExternalFormat inputFormat = (type==kSecItemTypeSessionKey) ?kSecFormatRawKey :kSecFormatUnknown;
141 CFArrayRef items = NULL;
143 params->version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
144 params->flags |= kSecKeyImportOnlyOne;
145 params->keyAttributes |= CSSM_KEYATTR_EXTRACTABLE;
147 params->keyAttributes |= CSSM_KEYATTR_PERMANENT;
148 if (type==kSecItemTypeSessionKey)
149 params->keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT;
150 else if (type==kSecItemTypePublicKey)
151 params->keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP;
152 else if (type==kSecItemTypePrivateKey)
153 params->keyUsage = CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN;
155 if (!check(SecKeychainItemImport((CFDataRef)data, NULL, &inputFormat, &type,
156 0, params, keychain, &items),
157 @"SecKeychainItemImport"))
159 if (!items || CFArrayGetCount(items) != 1)
161 SecKeyRef key = (SecKeyRef)CFRetain(CFArrayGetValueAtIndex(items,0));
163 return key; // caller must CFRelease
167 - (MYSHA1Digest*) _keyDigest {
168 MYSHA1Digest *digest = nil;
169 CSSM_DATA *keyDigest = NULL;
170 CSSM_CC_HANDLE context = [self _createPassThroughContext];
172 if (checkcssm(CSSM_CSP_PassThrough(context, CSSM_APPLECSP_KEYDIGEST, NULL, (void**)&keyDigest),
173 @"CSSM_CSP_PassThrough")) {
174 if (keyDigest && keyDigest->Data) {
175 digest = [[[MYSHA1Digest alloc] initWithRawDigest: keyDigest->Data
176 length: keyDigest->Length] autorelease];
179 SecKeyRef keyRef = self.keyRef;
180 // Note - CSSM_CSP_PassThrough fails on a couple of private keys I've seen; it seems to
181 // be ones that are either expired or don't have a matching public key at all (?)
182 Warn(@"Failed to get digest of SecKeyRef %p (name='%@' appTag='%@')",
186 NSData *digestData = [[self class] _getAttribute: kSecKeyLabel
187 ofItem: (SecKeychainItemRef)keyRef];
189 digest = (MYSHA1Digest*) [MYSHA1Digest digestFromDigestData: digestData];
191 Warn(@"Digest property of key %p was invalid SHA-1: %@", keyRef,digestData);
194 CSSM_DeleteContext(context);
200 /** Asymmetric encryption/decryption; used by MYPublicKey and MYPrivateKey. */
201 - (NSData*) _crypt: (NSData*)data operation: (BOOL)operation {
203 const CSSM_ACCESS_CREDENTIALS *credentials;
204 credentials = [self cssmCredentialsForOperation: (operation ?CSSM_ACL_AUTHORIZATION_ENCRYPT
205 :CSSM_ACL_AUTHORIZATION_DECRYPT)
206 type: kSecCredentialTypeDefault
211 CSSM_CC_HANDLE ccHandle;
212 if (!checkcssm(CSSM_CSP_CreateAsymmetricContext(self.cssmCSPHandle,
218 @"CSSM_CSP_CreateAsymmetricContext"))
221 CSSM_DATA original = {data.length, (void*)data.bytes};
222 CSSM_DATA result = {};
226 ok = checkcssm(CSSM_EncryptData(ccHandle, &original, 1, &result, 1, &outputLength, &result),
227 @"CSSM_EncryptData");
229 ok = checkcssm(CSSM_DecryptData(ccHandle, &original, 1, &result, 1, &outputLength, &result),
230 @"CSSM_DecryptData");
231 CSSM_DeleteContext(ccHandle);
232 return ok ?[NSData dataWithBytesNoCopy: result.Data length: outputLength freeWhenDone: YES] :nil;
236 - (CSSM_CC_HANDLE) _createSignatureContext: (CSSM_ALGORITHMS)algorithm {
237 const CSSM_ACCESS_CREDENTIALS *credentials;
238 credentials = [self cssmCredentialsForOperation: CSSM_ACL_AUTHORIZATION_SIGN
239 type: kSecCredentialTypeDefault
242 CSSM_CC_HANDLE ccHandle = 0;
243 if (checkcssm(CSSM_CSP_CreateSignatureContext(self.cssmCSPHandle,
248 @"CSSM_CSP_CreateSignatureContext") )
254 - (CSSM_CC_HANDLE) _createPassThroughContext
256 CSSM_CC_HANDLE ccHandle = 0;
257 if (checkcssm(CSSM_CSP_CreatePassThroughContext(self.cssmCSPHandle, self.cssmKey, &ccHandle),
258 @"CSSM_CSP_CreatePassThroughContext") )
267 #endif MYCRYPTO_USE_IPHONE_API
272 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
274 Redistribution and use in source and binary forms, with or without modification, are permitted
275 provided that the following conditions are met:
277 * Redistributions of source code must retain the above copyright notice, this list of conditions
278 and the following disclaimer.
279 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
280 and the following disclaimer in the documentation and/or other materials provided with the
283 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
284 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
285 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
286 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
287 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
288 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
289 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
290 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.