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*)data
26 forKeychain: (SecKeychainRef)keychain {
27 SecKeyImportExportParameters params = {};
28 SecKeyRef key = importKey(data, self.keyType, keychain, ¶ms);
33 self = [self initWithKeyRef: key];
38 - (id) initWithKeyData: (NSData*)data {
39 return [self _initWithKeyData: data forKeychain: nil];
43 - (NSString*) description {
44 return $sprintf(@"%@[%@ /%p]", [self class], (self.name ?:@""), self.keychainItemRef);
47 - (SecExternalItemType) keyType {
48 AssertAbstractMethod();
52 - (SecKeyRef) keyRef {
53 return (SecKeyRef) self.keychainItemRef;
56 - (const CSSM_KEY*) cssmKey {
57 const CSSM_KEY *cssmKey = NULL;
58 Assert(check(SecKeyGetCSSMKey(self.keyRef, &cssmKey), @"SecKeyGetCSSMKey"),
59 @"Failed to get CSSM_KEY");
63 - (const CSSM_CSP_HANDLE) cssmCSPHandle {
64 CSSM_CSP_HANDLE cspHandle = 0;
65 Assert(check(SecKeyGetCSPHandle(self.keyRef, &cspHandle), @"SecKeyGetCSPHandle"),
66 @"Failed to get CSSM_CSP_HANDLE");
70 - (const CSSM_ACCESS_CREDENTIALS*) cssmCredentialsForOperation: (CSSM_ACL_AUTHORIZATION_TAG)operation
71 type: (SecCredentialType)type
72 error: (NSError**)outError
74 const CSSM_ACCESS_CREDENTIALS *credentials = NULL;
75 OSStatus err = SecKeyGetCredentials(self.keyRef,
79 if (!MYReturnError(outError, err,NSOSStatusErrorDomain, @"Couldn't get credentials for key"))
84 - (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM {
85 CFDataRef data = NULL;
86 if (check(SecKeychainItemExport(self.keyRef, format, (withPEM ?kSecItemPemArmour :0), NULL, &data),
87 @"SecKeychainItemExport"))
88 return [(id)CFMakeCollectable(data) autorelease];
94 return [self exportKeyInFormat: kSecFormatRawKey withPEM: NO];
98 return [self stringValueOfAttribute: kSecKeyPrintName];
101 - (void) setName: (NSString*)name {
102 [self setValue: name ofAttribute: kSecKeyPrintName];
105 - (NSString*) comment {
106 return [self stringValueOfAttribute: kSecKeyApplicationTag];
109 - (void) setComment: (NSString*)comment {
110 [self setValue: comment ofAttribute: kSecKeyApplicationTag];
113 - (NSString*) alias {
114 return [self stringValueOfAttribute: kSecKeyAlias];
117 - (void) setAlias: (NSString*)alias {
118 [self setValue: alias ofAttribute: kSecKeyAlias];
123 #pragma mark UTILITY FUNCTIONS:
126 SecKeyRef importKey(NSData *data,
127 SecExternalItemType type,
128 SecKeychainRef keychain,
129 SecKeyImportExportParameters *params) {
130 SecExternalFormat inputFormat = (type==kSecItemTypeSessionKey) ?kSecFormatRawKey :kSecFormatOpenSSL;
131 CFArrayRef items = NULL;
133 params->version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
134 params->flags |= kSecKeyImportOnlyOne;
135 params->keyAttributes |= CSSM_KEYATTR_EXTRACTABLE;
137 params->keyAttributes |= CSSM_KEYATTR_PERMANENT;
138 if (type==kSecItemTypeSessionKey)
139 params->keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT;
140 else if (type==kSecItemTypePublicKey)
141 params->keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY;
142 else if (type==kSecItemTypePrivateKey)
143 params->keyUsage = CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN;
145 if (!check(SecKeychainItemImport((CFDataRef)data, NULL, &inputFormat, &type,
146 0, params, keychain, &items),
147 @"SecKeychainItemImport"))
149 if (!items || CFArrayGetCount(items) != 1)
151 SecKeyRef key = (SecKeyRef)CFRetain(CFArrayGetValueAtIndex(items,0));
153 return key; // caller must CFRelease
157 - (MYSHA1Digest*) _keyDigest {
158 MYSHA1Digest *digest = nil;
159 CSSM_DATA *keyDigest = NULL;
160 CSSM_CC_HANDLE context = [self _createPassThroughContext];
162 if (checkcssm(CSSM_CSP_PassThrough(context, CSSM_APPLECSP_KEYDIGEST, NULL, (void**)&keyDigest),
163 @"CSSM_CSP_PassThrough")) {
164 if (keyDigest && keyDigest->Data) {
165 digest = [[[MYSHA1Digest alloc] initWithRawDigest: keyDigest->Data
166 length: keyDigest->Length] autorelease];
169 SecKeyRef keyRef = self.keyRef;
170 // Note - CSSM_CSP_PassThrough fails on a couple of private keys I've seen; it seems to
171 // be ones that are either expired or don't have a matching public key at all (?)
172 Warn(@"Failed to get digest of SecKeyRef %p (name='%@' appTag='%@')",
176 NSData *digestData = [[self class] _getAttribute: kSecKeyLabel
177 ofItem: (SecKeychainItemRef)keyRef];
179 digest = (MYSHA1Digest*) [MYSHA1Digest digestFromDigestData: digestData];
181 Warn(@"Digest property of key %p was invalid SHA-1: %@", keyRef,digestData);
184 CSSM_DeleteContext(context);
190 /** Asymmetric encryption/decryption; used by MYPublicKey and MYPrivateKey. */
191 - (NSData*) _crypt: (NSData*)data operation: (BOOL)operation {
193 const CSSM_ACCESS_CREDENTIALS *credentials;
194 credentials = [self cssmCredentialsForOperation: (operation ?CSSM_ACL_AUTHORIZATION_ENCRYPT
195 :CSSM_ACL_AUTHORIZATION_DECRYPT)
196 type: kSecCredentialTypeDefault
201 CSSM_CC_HANDLE ccHandle;
202 if (!checkcssm(CSSM_CSP_CreateAsymmetricContext(self.cssmCSPHandle,
208 @"CSSM_CSP_CreateAsymmetricContext"))
211 CSSM_DATA original = {data.length, (void*)data.bytes};
212 CSSM_DATA result = {};
216 ok = checkcssm(CSSM_EncryptData(ccHandle, &original, 1, &result, 1, &outputLength, &result),
217 @"CSSM_EncryptData");
219 ok = checkcssm(CSSM_DecryptData(ccHandle, &original, 1, &result, 1, &outputLength, &result),
220 @"CSSM_DecryptData");
221 CSSM_DeleteContext(ccHandle);
222 return ok ?[NSData dataWithBytesNoCopy: result.Data length: outputLength freeWhenDone: YES] :nil;
226 - (CSSM_CC_HANDLE) _createSignatureContext: (CSSM_ALGORITHMS)algorithm {
227 const CSSM_ACCESS_CREDENTIALS *credentials;
228 credentials = [self cssmCredentialsForOperation: CSSM_ACL_AUTHORIZATION_SIGN
229 type: kSecCredentialTypeDefault
232 CSSM_CC_HANDLE ccHandle = 0;
233 if (checkcssm(CSSM_CSP_CreateSignatureContext(self.cssmCSPHandle,
238 @"CSSM_CSP_CreateSignatureContext") )
244 - (CSSM_CC_HANDLE) _createPassThroughContext
246 CSSM_CC_HANDLE ccHandle = 0;
247 if (checkcssm(CSSM_CSP_CreatePassThroughContext(self.cssmCSPHandle, self.cssmKey, &ccHandle),
248 @"CSSM_CSP_CreatePassThroughContext") )
257 #endif MYCRYPTO_USE_IPHONE_API
262 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
264 Redistribution and use in source and binary forms, with or without modification, are permitted
265 provided that the following conditions are met:
267 * Redistributions of source code must retain the above copyright notice, this list of conditions
268 and the following disclaimer.
269 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
270 and the following disclaimer in the documentation and/or other materials provided with the
273 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
274 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
275 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
276 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
277 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
278 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
279 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
280 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.