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.
9 #import "MYPublicKey.h"
10 #import "MYCrypto_Private.h"
12 #import "MYASN1Object.h"
13 #import "MYDEREncoder.h"
14 #import "MYBERParser.h"
15 #import "MYErrorUtils.h"
16 #import <CommonCrypto/CommonDigest.h>
20 @implementation MYPublicKey
23 - (id) initWithModulus: (NSData*)modulus exponent: (unsigned)exponent {
24 // An RSA key is encoded in ASN.1 as a sequence of modulus and exponent, both as integers.
25 MYASN1BigInteger *modulusInt = [[MYASN1BigInteger alloc] initWithUnsignedData: modulus];
26 id asn1 = $array( modulusInt, $object(exponent) );
28 NSData *keyData = [MYDEREncoder encodeRootObject: asn1 error: nil];
29 return [self initWithKeyData: keyData];
38 - (SecExternalItemType) keyClass {
39 #if MYCRYPTO_USE_IPHONE_API
40 return kSecAttrKeyClassPublic;
42 return kSecItemTypePublicKey;
46 #if MYCRYPTO_USE_IPHONE_API
47 - (SecExternalItemType) keyType {
48 return kSecAttrKeyTypeRSA;
53 return self.publicKeyDigest.hash;
56 - (NSString*) description {
57 return $sprintf(@"%@[%@]", [self class], self.publicKeyDigest.abbreviatedHexString);
60 - (MYSHA1Digest*) publicKeyDigest {
62 _digest = [[self _keyDigest] retain];
66 #if !MYCRYPTO_USE_IPHONE_API
67 - (SecExternalFormat) _externalFormat {
68 return kSecFormatBSAFE;
73 - (BOOL) getModulus: (NSData**)outModulus exponent: (unsigned*)outExponent {
74 Assert(outModulus!=nil);
75 Assert(outExponent!=nil);
76 NSArray *asn1 = $castIf(NSArray, MYBERParse(self.keyData, nil));
77 if (!asn1 || asn1.count != 2)
79 *outModulus = $castIf(MYASN1BigInteger, [asn1 objectAtIndex: 0]).unsignedData;
80 *outExponent = $castIf(NSNumber, [asn1 objectAtIndex: 1]).unsignedIntValue;
81 return (*outModulus!=nil && *outExponent>=3);
85 - (NSData*) rawEncryptData: (NSData*)data {
86 return [self _crypt: data operation: YES];
90 - (BOOL) verifySignature: (NSData*)signature ofData: (NSData*)data {
94 #if MYCRYPTO_USE_IPHONE_API
95 uint8_t digest[CC_SHA1_DIGEST_LENGTH];
96 CC_SHA1(data.bytes,data.length, digest);
97 OSStatus err = SecKeyRawVerify(self.keyRef, kSecPaddingPKCS1SHA1,
98 digest,sizeof(digest), //data.bytes, data.length,
99 signature.bytes, signature.length);
103 CSSM_CC_HANDLE ccHandle = [self _createSignatureContext: CSSM_ALGID_SHA1WithRSA];
104 if (!ccHandle) return NO;
105 CSSM_DATA original = {data.length, (void*)data.bytes};
106 CSSM_DATA sig = {signature.length, (void*)signature.bytes};
107 CSSM_RETURN cssmErr = CSSM_VerifyData(ccHandle, &original, 1, CSSM_ALGID_NONE, &sig);
108 CSSM_DeleteContext(ccHandle);
109 if (cssmErr == CSSM_OK)
111 if (cssmErr != CSSMERR_CSP_VERIFY_FAILED)
112 Warn(@"CSSM error verifying signature: %u", MYErrorName(MYCSSMErrorDomain,cssmErr));
118 #if !TARGET_OS_IPHONE
119 - (CSSM_WRAP_KEY*) _unwrappedCSSMKey {
120 const CSSM_KEY *key = self.cssmKey;
122 if (key->KeyHeader.BlobType == CSSM_KEYBLOB_WRAPPED) {
123 Warn(@"Key is already wrapped.\n");
127 if (key->KeyHeader.KeyClass != CSSM_KEYCLASS_PUBLIC_KEY)
128 Warn(@"Warning: Null wrapping a non-public key - this is a dangerous operation.\n");
130 const CSSM_ACCESS_CREDENTIALS* credentials;
131 credentials = [self cssmCredentialsForOperation: CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
132 type: kSecCredentialTypeDefault error: nil];
133 CSSM_CC_HANDLE ccHandle;
134 if (!checkcssm(CSSM_CSP_CreateSymmetricContext(self.cssmCSPHandle,
135 CSSM_ALGID_NONE, CSSM_ALGMODE_WRAP,
137 CSSM_PADDING_NONE, NULL,
139 @"CSSM_CSP_CreateSymmetricContext"))
142 CSSM_WRAP_KEY *result = malloc(sizeof(CSSM_WRAP_KEY));
143 if (!checkcssm(CSSM_WrapKey(ccHandle, credentials, key, NULL, result),
148 CSSM_DeleteContext(ccHandle);
153 - (NSData*) wrapSessionKey: (MYSymmetricKey*)sessionKey {
154 const CSSM_ACCESS_CREDENTIALS* credentials;
155 credentials = [self cssmCredentialsForOperation: CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
156 type: kSecCredentialTypeDefault error: nil];
157 CSSM_CSP_HANDLE cspHandle = self.cssmCSPHandle;
159 if (!checkcssm(CSSM_CSP_CreateAsymmetricContext(cspHandle,
165 @"CSSM_CSP_CreateAsymmetricContext"))
169 NSData *result = nil;
170 CSSM_WRAP_KEY wrappedKey = {};
171 CSSM_DATA descriptiveData = {};
172 if (checkcssm(CSSM_WrapKey(ctx, credentials, sessionKey.cssmKey, &descriptiveData, &wrappedKey),
174 // ...and copy the wrapped key data to the result NSData:
175 result = [NSData dataWithBytes: wrappedKey.KeyData.Data length: wrappedKey.KeyData.Length];
176 CSSM_FreeKey(cspHandle, credentials, &wrappedKey, NO);
178 // Finally, delete the context
179 CSSM_DeleteContext(ctx);
192 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
194 Redistribution and use in source and binary forms, with or without modification, are permitted
195 provided that the following conditions are met:
197 * Redistributions of source code must retain the above copyright notice, this list of conditions
198 and the following disclaimer.
199 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
200 and the following disclaimer in the documentation and/or other materials provided with the
203 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
204 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
205 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
206 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
207 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
208 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
209 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
210 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.