MYPublicKey.m
author Jens Alfke <jens@mooseyard.com>
Wed Jun 10 09:02:18 2009 -0700 (2009-06-10)
changeset 25 38c3c3923e1f
parent 23 39fec79de6e8
child 26 d9c2a06d4e4e
permissions -rw-r--r--
Changed the X.509 version number in generated certs from 1 to 3, so that SecCertificateCreateFromData on iPhone will accept them. :-/
     1 //
     2 //  MYPublicKey.m
     3 //  MYCrypto
     4 //
     5 //  Created by Jens Alfke on 3/21/09.
     6 //  Copyright 2009 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #import "MYPublicKey.h"
    10 #import "MYCrypto_Private.h"
    11 #import "MYDigest.h"
    12 #import "MYASN1Object.h"
    13 #import "MYDEREncoder.h"
    14 #import "MYBERParser.h"
    15 #import "MYErrorUtils.h"
    16 #import <CommonCrypto/CommonDigest.h>
    17 
    18 
    19 #pragma mark -
    20 @implementation MYPublicKey
    21 
    22 
    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) );
    27     [modulusInt release];
    28     NSData *keyData = [MYDEREncoder encodeRootObject: asn1 error: nil];
    29     return [self initWithKeyData: keyData];
    30 }
    31 
    32 - (void) dealloc
    33 {
    34     [_digest release];
    35     [super dealloc];
    36 }
    37 
    38 - (SecExternalItemType) keyClass {
    39 #if MYCRYPTO_USE_IPHONE_API
    40     return kSecAttrKeyClassPublic;
    41 #else
    42     return kSecItemTypePublicKey;
    43 #endif
    44 }
    45 
    46 #if MYCRYPTO_USE_IPHONE_API
    47 - (SecExternalItemType) keyType {
    48     return kSecAttrKeyTypeRSA;
    49 }
    50 #endif
    51 
    52 - (NSUInteger)hash {
    53     return self.publicKeyDigest.hash;
    54 }
    55 
    56 - (NSString*) description {
    57     return $sprintf(@"%@[%@]", [self class], self.publicKeyDigest.abbreviatedHexString);
    58 }
    59 
    60 - (MYSHA1Digest*) publicKeyDigest {
    61     if (!_digest)
    62         _digest = [[self _keyDigest] retain];
    63     return _digest;
    64 }
    65 
    66 #if !MYCRYPTO_USE_IPHONE_API
    67 - (SecExternalFormat) _externalFormat {
    68     return kSecFormatBSAFE;
    69 }
    70 #endif
    71 
    72 
    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)
    78         return NO;
    79     *outModulus = $castIf(MYASN1BigInteger, [asn1 objectAtIndex: 0]).unsignedData;
    80     *outExponent = $castIf(NSNumber, [asn1 objectAtIndex: 1]).unsignedIntValue;
    81     return (*outModulus!=nil && *outExponent>=3);
    82 }
    83 
    84 
    85 - (NSData*) rawEncryptData: (NSData*)data {
    86     return [self _crypt: data operation: YES];
    87 }
    88 
    89 
    90 - (BOOL) verifySignature: (NSData*)signature ofData: (NSData*)data {
    91     Assert(data);
    92     Assert(signature);
    93     
    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);
   100     return err==noErr;
   101     
   102 #else
   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)
   110         return YES;
   111     if (cssmErr != CSSMERR_CSP_VERIFY_FAILED)
   112         Warn(@"CSSM error verifying signature: %u", MYErrorName(MYCSSMErrorDomain,cssmErr));
   113     return NO;
   114 #endif
   115 }
   116 
   117 
   118 #if !TARGET_OS_IPHONE
   119 - (CSSM_WRAP_KEY*) _unwrappedCSSMKey {
   120     const CSSM_KEY *key = self.cssmKey;
   121     
   122     if (key->KeyHeader.BlobType == CSSM_KEYBLOB_WRAPPED) {
   123         Warn(@"Key is already wrapped.\n");
   124         return NULL;
   125     }
   126     
   127     if (key->KeyHeader.KeyClass != CSSM_KEYCLASS_PUBLIC_KEY)
   128         Warn(@"Warning: Null wrapping a non-public key - this is a dangerous operation.\n");
   129     
   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, 
   136                                                    NULL, NULL, NULL, 
   137                                                    CSSM_PADDING_NONE, NULL, 
   138                                                    &ccHandle),
   139                    @"CSSM_CSP_CreateSymmetricContext"))
   140         return NULL;
   141                    
   142     CSSM_WRAP_KEY *result = malloc(sizeof(CSSM_WRAP_KEY));
   143     if (!checkcssm(CSSM_WrapKey(ccHandle, credentials, key, NULL, result),
   144                       @"CSSM_WrapKey")) {
   145         free(result);
   146         result = NULL;
   147     }
   148     CSSM_DeleteContext(ccHandle);
   149     return result;
   150 }
   151 
   152 
   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;
   158     CSSM_CC_HANDLE ctx;
   159     if (!checkcssm(CSSM_CSP_CreateAsymmetricContext(cspHandle,
   160                                                     self.cssmAlgorithm,
   161                                                     credentials, 
   162                                                     self.cssmKey,
   163                                                     CSSM_PADDING_PKCS1,
   164                                                     &ctx), 
   165                    @"CSSM_CSP_CreateAsymmetricContext"))
   166         return nil;
   167         
   168     // Now wrap the key:
   169     NSData *result = nil;
   170     CSSM_WRAP_KEY wrappedKey = {};
   171     CSSM_DATA descriptiveData = {};
   172     if (checkcssm(CSSM_WrapKey(ctx, credentials, sessionKey.cssmKey, &descriptiveData, &wrappedKey),
   173                   @"CSSM_WrapKey")) {
   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);
   177     }
   178     // Finally, delete the context
   179     CSSM_DeleteContext(ctx);
   180     return result;
   181 }
   182 
   183 
   184 #endif
   185 
   186 
   187 @end
   188 
   189 
   190 
   191 /*
   192  Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   193  
   194  Redistribution and use in source and binary forms, with or without modification, are permitted
   195  provided that the following conditions are met:
   196  
   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
   201  distribution.
   202  
   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.
   211  */