MYCertificate now checks validity of self-signed certs loaded from the keychain (because the Security framework doesn't validate self-signed certs.)
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];
37 #if MYCRYPTO_USE_IPHONE_API
39 self.isPersistent = NO;
45 - (id) initWithKeyData: (NSData*)data {
46 return [self _initWithKeyData: data forKeychain: nil];
50 - (NSString*) description {
51 return $sprintf(@"%@[%@ /%p]", [self class], (self.name ?:@""), self.keychainItemRef);
54 - (SecExternalItemType) keyClass {
55 AssertAbstractMethod();
58 #if MYCRYPTO_USE_IPHONE_API
59 - (SecExternalItemType) keyType {
64 - (SecKeyRef) keyRef {
65 return (SecKeyRef) self.keychainItemRef;
68 - (const CSSM_KEY*) cssmKey {
69 const CSSM_KEY *cssmKey = NULL;
70 Assert(check(SecKeyGetCSSMKey(self.keyRef, &cssmKey), @"SecKeyGetCSSMKey"),
71 @"Failed to get CSSM_KEY");
75 - (const CSSM_CSP_HANDLE) cssmCSPHandle {
76 CSSM_CSP_HANDLE cspHandle = 0;
77 Assert(check(SecKeyGetCSPHandle(self.keyRef, &cspHandle), @"SecKeyGetCSPHandle"),
78 @"Failed to get CSSM_CSP_HANDLE");
82 - (CSSM_ALGORITHMS) cssmAlgorithm {
83 return self.cssmKey->KeyHeader.AlgorithmId;
86 - (const CSSM_ACCESS_CREDENTIALS*) cssmCredentialsForOperation: (CSSM_ACL_AUTHORIZATION_TAG)operation
87 type: (SecCredentialType)type
88 error: (NSError**)outError
90 const CSSM_ACCESS_CREDENTIALS *credentials = NULL;
91 OSStatus err = SecKeyGetCredentials(self.keyRef,
95 if (!MYReturnError(outError, err,NSOSStatusErrorDomain, @"Couldn't get credentials for key"))
100 - (SecExternalFormat) _externalFormat {
101 return kSecFormatRawKey;
104 - (NSData*) keyData {
105 CFDataRef data = NULL;
106 if (check(SecKeychainItemExport(self.keyRef, self._externalFormat, 0, NULL, &data),
107 @"SecKeychainItemExport"))
108 return [(id)CFMakeCollectable(data) autorelease];
113 - (unsigned) keySizeInBits {
114 const CSSM_KEY *key = self.cssmKey;
116 return key->KeyHeader.LogicalKeySizeInBits;
120 return [self stringValueOfAttribute: kSecKeyPrintName];
123 - (void) setName: (NSString*)name {
124 [self setValue: name ofAttribute: kSecKeyPrintName];
127 - (NSString*) comment {
128 return [self stringValueOfAttribute: kSecKeyApplicationTag];
131 - (void) setComment: (NSString*)comment {
132 [self setValue: comment ofAttribute: kSecKeyApplicationTag];
135 - (NSString*) alias {
136 return [self stringValueOfAttribute: kSecKeyAlias];
139 - (void) setAlias: (NSString*)alias {
140 [self setValue: alias ofAttribute: kSecKeyAlias];
145 #pragma mark UTILITY FUNCTIONS:
148 SecKeyRef importKey(NSData *data,
149 SecExternalItemType type,
150 SecKeychainRef keychain,
151 SecKeyImportExportParameters *params) {
152 SecExternalFormat inputFormat = (type==kSecItemTypeSessionKey) ?kSecFormatRawKey :kSecFormatUnknown;
153 CFArrayRef items = NULL;
155 params->version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
156 params->flags |= kSecKeyImportOnlyOne;
157 params->keyAttributes |= CSSM_KEYATTR_EXTRACTABLE;
159 params->keyAttributes |= CSSM_KEYATTR_PERMANENT;
160 if (type==kSecItemTypeSessionKey)
161 params->keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT;
162 else if (type==kSecItemTypePublicKey)
163 params->keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP;
164 else if (type==kSecItemTypePrivateKey)
165 params->keyUsage = CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN;
167 if (!check(SecKeychainItemImport((CFDataRef)data, NULL, &inputFormat, &type,
168 0, params, keychain, &items),
169 @"SecKeychainItemImport"))
171 if (!items || CFArrayGetCount(items) != 1)
173 SecKeyRef key = (SecKeyRef)CFRetain(CFArrayGetValueAtIndex(items,0));
175 return key; // caller must CFRelease
179 - (MYSHA1Digest*) _keyDigest {
180 MYSHA1Digest *digest = nil;
181 CSSM_DATA *keyDigest = NULL;
182 CSSM_CC_HANDLE context = [self _createPassThroughContext];
184 if (checkcssm(CSSM_CSP_PassThrough(context, CSSM_APPLECSP_KEYDIGEST, NULL, (void**)&keyDigest),
185 @"CSSM_CSP_PassThrough")) {
186 if (keyDigest && keyDigest->Data) {
187 digest = [[[MYSHA1Digest alloc] initWithRawDigest: keyDigest->Data
188 length: keyDigest->Length] autorelease];
191 SecKeyRef keyRef = self.keyRef;
192 // Note - CSSM_CSP_PassThrough fails on a couple of private keys I've seen; it seems to
193 // be ones that are either expired or don't have a matching public key at all (?)
194 Warn(@"Failed to get digest of SecKeyRef %p (name='%@' appTag='%@')",
198 NSData *digestData = [[self class] _getAttribute: kSecKeyLabel
199 ofItem: (SecKeychainItemRef)keyRef];
201 digest = (MYSHA1Digest*) [MYSHA1Digest digestFromDigestData: digestData];
203 Warn(@"Digest property of key %p was invalid SHA-1: %@", keyRef,digestData);
206 CSSM_DeleteContext(context);
212 /** Asymmetric encryption/decryption; used by MYPublicKey and MYPrivateKey. */
213 - (NSData*) _crypt: (NSData*)data operation: (BOOL)operation {
215 const CSSM_ACCESS_CREDENTIALS *credentials;
216 credentials = [self cssmCredentialsForOperation: (operation ?CSSM_ACL_AUTHORIZATION_ENCRYPT
217 :CSSM_ACL_AUTHORIZATION_DECRYPT)
218 type: kSecCredentialTypeDefault
223 CSSM_CC_HANDLE ccHandle;
224 if (!checkcssm(CSSM_CSP_CreateAsymmetricContext(self.cssmCSPHandle,
230 @"CSSM_CSP_CreateAsymmetricContext"))
233 CSSM_DATA original = {data.length, (void*)data.bytes};
234 CSSM_DATA result = {};
238 ok = checkcssm(CSSM_EncryptData(ccHandle, &original, 1, &result, 1, &outputLength, &result),
239 @"CSSM_EncryptData");
241 ok = checkcssm(CSSM_DecryptData(ccHandle, &original, 1, &result, 1, &outputLength, &result),
242 @"CSSM_DecryptData");
243 CSSM_DeleteContext(ccHandle);
244 return ok ?[NSData dataWithBytesNoCopy: result.Data length: outputLength freeWhenDone: YES] :nil;
248 - (CSSM_CC_HANDLE) _createSignatureContext: (CSSM_ALGORITHMS)algorithm {
249 const CSSM_ACCESS_CREDENTIALS *credentials;
250 credentials = [self cssmCredentialsForOperation: CSSM_ACL_AUTHORIZATION_SIGN
251 type: kSecCredentialTypeDefault
254 CSSM_CC_HANDLE ccHandle = 0;
255 if (checkcssm(CSSM_CSP_CreateSignatureContext(self.cssmCSPHandle,
260 @"CSSM_CSP_CreateSignatureContext") )
266 - (CSSM_CC_HANDLE) _createPassThroughContext
268 CSSM_CC_HANDLE ccHandle = 0;
269 if (checkcssm(CSSM_CSP_CreatePassThroughContext(self.cssmCSPHandle, self.cssmKey, &ccHandle),
270 @"CSSM_CSP_CreatePassThroughContext") )
279 #endif MYCRYPTO_USE_IPHONE_API
284 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
286 Redistribution and use in source and binary forms, with or without modification, are permitted
287 provided that the following conditions are met:
289 * Redistributions of source code must retain the above copyright notice, this list of conditions
290 and the following disclaimer.
291 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
292 and the following disclaimer in the documentation and/or other materials provided with the
295 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
296 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
297 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
298 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
299 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
300 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
301 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
302 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.