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