MYPublicKey.m
author Jens Alfke <jens@mooseyard.com>
Fri Aug 07 11:24:53 2009 -0700 (2009-08-07)
changeset 28 54b373aa65ab
parent 24 6856e071d25a
permissions -rw-r--r--
Fixed iPhone OS build. (issue 3)
     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 @interface MYPublicKey ()
    20 @property (retain) MYCertificate *certificate;
    21 @end
    22 
    23 
    24 #pragma mark -
    25 @implementation MYPublicKey
    26 
    27 
    28 - (id) initWithModulus: (NSData*)modulus exponent: (unsigned)exponent {
    29     // An RSA key is encoded in ASN.1 as a sequence of modulus and exponent, both as integers.
    30     MYASN1BigInteger *modulusInt = [[MYASN1BigInteger alloc] initWithUnsignedData: modulus];
    31     id asn1 = $array( modulusInt, $object(exponent) );
    32     [modulusInt release];
    33     NSData *keyData = [MYDEREncoder encodeRootObject: asn1 error: nil];
    34     return [self initWithKeyData: keyData];
    35 }
    36 
    37 - (void) dealloc
    38 {
    39     [_digest release];
    40     [super dealloc];
    41 }
    42 
    43 @synthesize certificate=_certificate;
    44 
    45 - (SecExternalItemType) keyClass {
    46 #if MYCRYPTO_USE_IPHONE_API
    47     return kSecAttrKeyClassPublic;
    48 #else
    49     return kSecItemTypePublicKey;
    50 #endif
    51 }
    52 
    53 #if MYCRYPTO_USE_IPHONE_API
    54 - (SecExternalItemType) keyType {
    55     return kSecAttrKeyTypeRSA;
    56 }
    57 #endif
    58 
    59 - (NSUInteger)hash {
    60     return self.publicKeyDigest.hash;
    61 }
    62 
    63 - (NSString*) description {
    64     return $sprintf(@"%@[%@]", [self class], self.publicKeyDigest.abbreviatedHexString);
    65 }
    66 
    67 - (MYSHA1Digest*) publicKeyDigest {
    68     if (!_digest)
    69         _digest = [[self _keyDigest] retain];
    70     return _digest;
    71 }
    72 
    73 #if MYCRYPTO_USE_IPHONE_API
    74 - (NSData*) keyData {
    75     if (_certificate) {
    76         return _certificate.info.subjectPublicKeyData;
    77     } else {
    78         return [super keyData];
    79     }
    80 }
    81 #endif
    82 
    83 #if !MYCRYPTO_USE_IPHONE_API
    84 - (SecExternalFormat) _externalFormat {
    85     return kSecFormatBSAFE;
    86 }
    87 #endif
    88 
    89 
    90 - (BOOL) getModulus: (NSData**)outModulus exponent: (unsigned*)outExponent {
    91     Assert(outModulus!=nil);
    92     Assert(outExponent!=nil);
    93     NSArray *asn1 = $castIf(NSArray, MYBERParse(self.keyData, nil));
    94     if (!asn1 || asn1.count != 2)
    95         return NO;
    96     *outModulus = $castIf(MYASN1BigInteger, [asn1 objectAtIndex: 0]).unsignedData;
    97     *outExponent = $castIf(NSNumber, [asn1 objectAtIndex: 1]).unsignedIntValue;
    98     return (*outModulus!=nil && *outExponent>=3);
    99 }
   100 
   101 
   102 - (NSData*) rawEncryptData: (NSData*)data {
   103     return [self _crypt: data operation: YES];
   104 }
   105 
   106 
   107 - (BOOL) verifySignature: (NSData*)signature ofData: (NSData*)data {
   108     Assert(data);
   109     Assert(signature);
   110     
   111 #if MYCRYPTO_USE_IPHONE_API
   112     uint8_t digest[CC_SHA1_DIGEST_LENGTH];
   113     CC_SHA1(data.bytes,data.length, digest);
   114     OSStatus err = SecKeyRawVerify(self.keyRef, kSecPaddingPKCS1SHA1,
   115                                    digest,sizeof(digest), //data.bytes, data.length,
   116                                    signature.bytes, signature.length);
   117     return err==noErr;
   118     
   119 #else
   120     CSSM_CC_HANDLE ccHandle = [self _createSignatureContext: CSSM_ALGID_SHA1WithRSA];
   121     if (!ccHandle) return NO;
   122     CSSM_DATA original = {data.length, (void*)data.bytes};
   123     CSSM_DATA sig = {signature.length, (void*)signature.bytes};
   124     CSSM_RETURN cssmErr = CSSM_VerifyData(ccHandle, &original, 1, CSSM_ALGID_NONE, &sig);
   125     CSSM_DeleteContext(ccHandle);
   126     if (cssmErr == CSSM_OK)
   127         return YES;
   128     if (cssmErr != CSSMERR_CSP_VERIFY_FAILED)
   129         Warn(@"CSSM error verifying signature: %u", MYErrorName(MYCSSMErrorDomain,cssmErr));
   130     return NO;
   131 #endif
   132 }
   133 
   134 
   135 #if !TARGET_OS_IPHONE
   136 - (CSSM_WRAP_KEY*) _unwrappedCSSMKey {
   137     const CSSM_KEY *key = self.cssmKey;
   138     
   139     if (key->KeyHeader.BlobType == CSSM_KEYBLOB_WRAPPED) {
   140         Warn(@"Key is already wrapped.\n");
   141         return NULL;
   142     }
   143     
   144     if (key->KeyHeader.KeyClass != CSSM_KEYCLASS_PUBLIC_KEY)
   145         Warn(@"Warning: Null wrapping a non-public key - this is a dangerous operation.\n");
   146     
   147     const CSSM_ACCESS_CREDENTIALS* credentials;
   148     credentials = [self cssmCredentialsForOperation: CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
   149                                                type: kSecCredentialTypeDefault error: nil];
   150     CSSM_CC_HANDLE ccHandle;
   151     if (!checkcssm(CSSM_CSP_CreateSymmetricContext(self.cssmCSPHandle, 
   152                                                    CSSM_ALGID_NONE, CSSM_ALGMODE_WRAP, 
   153                                                    NULL, NULL, NULL, 
   154                                                    CSSM_PADDING_NONE, NULL, 
   155                                                    &ccHandle),
   156                    @"CSSM_CSP_CreateSymmetricContext"))
   157         return NULL;
   158                    
   159     CSSM_WRAP_KEY *result = malloc(sizeof(CSSM_WRAP_KEY));
   160     if (!checkcssm(CSSM_WrapKey(ccHandle, credentials, key, NULL, result),
   161                       @"CSSM_WrapKey")) {
   162         free(result);
   163         result = NULL;
   164     }
   165     CSSM_DeleteContext(ccHandle);
   166     return result;
   167 }
   168 
   169 
   170 - (NSData*) wrapSessionKey: (MYSymmetricKey*)sessionKey {
   171     const CSSM_ACCESS_CREDENTIALS* credentials;
   172     credentials = [self cssmCredentialsForOperation: CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
   173                                                type: kSecCredentialTypeDefault error: nil];
   174     CSSM_CSP_HANDLE cspHandle = self.cssmCSPHandle;
   175     CSSM_CC_HANDLE ctx;
   176     if (!checkcssm(CSSM_CSP_CreateAsymmetricContext(cspHandle,
   177                                                     self.cssmAlgorithm,
   178                                                     credentials, 
   179                                                     self.cssmKey,
   180                                                     CSSM_PADDING_PKCS1,
   181                                                     &ctx), 
   182                    @"CSSM_CSP_CreateAsymmetricContext"))
   183         return nil;
   184         
   185     // Now wrap the key:
   186     NSData *result = nil;
   187     CSSM_WRAP_KEY wrappedKey = {};
   188     CSSM_DATA descriptiveData = {};
   189     if (checkcssm(CSSM_WrapKey(ctx, credentials, sessionKey.cssmKey, &descriptiveData, &wrappedKey),
   190                   @"CSSM_WrapKey")) {
   191         // ...and copy the wrapped key data to the result NSData:
   192         result = [NSData dataWithBytes: wrappedKey.KeyData.Data length: wrappedKey.KeyData.Length];
   193         CSSM_FreeKey(cspHandle, credentials, &wrappedKey, NO);
   194     }
   195     // Finally, delete the context
   196     CSSM_DeleteContext(ctx);
   197     return result;
   198 }
   199 
   200 
   201 #endif
   202 
   203 
   204 @end
   205 
   206 
   207 
   208 /*
   209  Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   210  
   211  Redistribution and use in source and binary forms, with or without modification, are permitted
   212  provided that the following conditions are met:
   213  
   214  * Redistributions of source code must retain the above copyright notice, this list of conditions
   215  and the following disclaimer.
   216  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   217  and the following disclaimer in the documentation and/or other materials provided with the
   218  distribution.
   219  
   220  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   221  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   222  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   223  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   224  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   225   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   226  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   227  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   228  */