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