MYCertGen.m
author Jens Alfke <jens@mooseyard.com>
Wed Jul 01 14:19:13 2009 -0700 (2009-07-01)
changeset 26 d9c2a06d4e4e
parent 21 2c300b15b381
permissions -rw-r--r--
Whew, lots and lots of changes accumulated over the past few weeks. Mostly fixes for bugs I discovered while retrofitting Cloudy to use MYCrypto.
snej@4
     1
//
snej@4
     2
//  MYCertGen.m
snej@4
     3
//  MYCrypto
snej@4
     4
//
snej@4
     5
//  Created by Jens Alfke on 4/3/09.
snej@4
     6
//  Copyright 2009 Jens Alfke. All rights reserved.
snej@4
     7
//
snej@4
     8
jens@22
     9
//  NOTE: This module has been replaced by MYCertificateInfo, which isn't dependent on
jens@22
    10
//  CSSM APIs that aren't available on iPhone.
jens@22
    11
snej@4
    12
//  Derived from ...
snej@4
    13
snej@4
    14
//
snej@4
    15
//  CertificateGeneration.m
snej@4
    16
//  Keychain
snej@4
    17
//
snej@4
    18
//  Created by Wade Tregaskis on Tue May 27 2003.
snej@4
    19
//
snej@4
    20
//  Copyright (c) 2003 - 2007, Wade Tregaskis.  All rights reserved.
snej@4
    21
//  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
snej@4
    22
//    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
snej@4
    23
//    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
snej@4
    24
//    * Neither the name of Wade Tregaskis nor the names of any other contributors may be used to endorse or promote products derived from this software without specific prior written permission.
snej@4
    25
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
snej@4
    26
snej@4
    27
#import "MYCertGen.h"
snej@4
    28
#import "MYCrypto_Private.h"
snej@4
    29
#import "MYIdentity.h"
snej@4
    30
#import <Security/Security.h>
snej@4
    31
snej@4
    32
snej@4
    33
snej@4
    34
static CSSM_X509_NAME* createNameList( NSDictionary *name );
snej@4
    35
static CSSM_X509_TIME* timeForNSDate(NSDate *date);
snej@4
    36
snej@4
    37
static NSData* NSDataFromDataNoCopy(CSSM_DATA data, BOOL freeWhenDone);
snej@4
    38
snej@4
    39
static BOOL intToDER(uint32_t theInt, CSSM_DATA *data);
snej@4
    40
snej@4
    41
snej@4
    42
snej@4
    43
NSData* MYCertificateCreateTemplate(const CSSM_X509_NAME *subject, const CSSM_X509_NAME *issuer,
snej@4
    44
                                    NSDate *validFrom, NSDate *validTo,
snej@4
    45
                                    uint32_t serialNumber,
snej@4
    46
                                    const CSSM_X509_EXTENSION **extensions, unsigned nExtensions,
snej@4
    47
                                    MYPublicKey *publicKey,
snej@4
    48
                                    const CSSM_X509_ALGORITHM_IDENTIFIER *signingAlgorithm,
snej@4
    49
                                    CSSM_CL_HANDLE clHandle) 
snej@4
    50
{
snej@4
    51
    CAssert(subject);
snej@4
    52
    CAssert(issuer);
snej@4
    53
    CAssert(publicKey);
snej@4
    54
    CAssert(signingAlgorithm);
snej@4
    55
    CAssert(clHandle);
snej@4
    56
snej@4
    57
    const CSSM_KEY *cssmPubKey = publicKey.cssmKey;
snej@4
    58
    if (cssmPubKey->KeyHeader.BlobType != CSSM_KEYBLOB_RAW) {
snej@4
    59
        cssmPubKey = publicKey._unwrappedCSSMKey;
snej@4
    60
        if (!cssmPubKey) {
snej@4
    61
            Warn(@"MYCertificateCreateTemplate: unable to unwrap public key %@", publicKey);
snej@4
    62
            return nil;
snej@4
    63
        }
snej@4
    64
    }
snej@4
    65
snej@4
    66
    uint32_t numberOfFields = 5; // always requires at least 5 user-supplied fields
snej@4
    67
    if (serialNumber)
snej@4
    68
        ++numberOfFields;
snej@4
    69
    if (validFrom)
snej@4
    70
        ++numberOfFields;
snej@4
    71
    if (validTo)
snej@4
    72
        ++numberOfFields;
snej@4
    73
    numberOfFields += nExtensions;
snej@4
    74
    
snej@4
    75
    CSSM_FIELD fields[numberOfFields];
snej@4
    76
snej@4
    77
    // now we fill in the fields appropriately
snej@4
    78
    
snej@4
    79
    uint32_t index = 0;
snej@4
    80
    fields[index].FieldOid = CSSMOID_X509V1Version;
snej@4
    81
    intToDER(2, &(fields[index++].FieldValue));
snej@4
    82
snej@4
    83
    if (serialNumber) {
snej@4
    84
        fields[index].FieldOid = CSSMOID_X509V1SerialNumber;
snej@4
    85
        intToDER(serialNumber, &fields[index].FieldValue);
snej@4
    86
        index++;
snej@4
    87
    }
snej@4
    88
snej@4
    89
    fields[index].FieldOid = CSSMOID_X509V1IssuerNameCStruct;
snej@4
    90
    fields[index].FieldValue.Data = (uint8_t*)issuer;
snej@4
    91
    fields[index++].FieldValue.Length = sizeof(CSSM_X509_NAME);
snej@4
    92
snej@4
    93
    fields[index].FieldOid = CSSMOID_X509V1SubjectNameCStruct;
snej@4
    94
    fields[index].FieldValue.Data = (uint8_t*)subject;
snej@4
    95
    fields[index++].FieldValue.Length = sizeof(CSSM_X509_NAME);
snej@4
    96
snej@4
    97
    if (validFrom) {
snej@4
    98
        fields[index].FieldOid = CSSMOID_X509V1ValidityNotBefore;
snej@4
    99
        fields[index].FieldValue.Data = (uint8_t*)timeForNSDate(validFrom);
snej@4
   100
        fields[index++].FieldValue.Length = sizeof(CSSM_X509_TIME);
snej@4
   101
    }
snej@4
   102
    
snej@4
   103
    if (validTo) {
snej@4
   104
        fields[index].FieldOid = CSSMOID_X509V1ValidityNotAfter;
snej@4
   105
        fields[index].FieldValue.Data = (uint8_t*)timeForNSDate(validTo);
snej@4
   106
        fields[index++].FieldValue.Length = sizeof(CSSM_X509_TIME);
snej@4
   107
    }
snej@4
   108
    
snej@4
   109
    fields[index].FieldOid = CSSMOID_CSSMKeyStruct;
snej@4
   110
    fields[index].FieldValue.Data = (uint8_t*)cssmPubKey;
snej@4
   111
    fields[index++].FieldValue.Length = sizeof(CSSM_KEY);
snej@4
   112
snej@4
   113
    fields[index].FieldOid = CSSMOID_X509V1SignatureAlgorithmTBS;
snej@4
   114
    fields[index].FieldValue.Data = (uint8_t*)signingAlgorithm;
snej@4
   115
    fields[index++].FieldValue.Length = sizeof(CSSM_X509_ALGORITHM_IDENTIFIER);
snej@4
   116
    
snej@4
   117
    for (unsigned i=0; i<nExtensions; i++) {
snej@4
   118
        fields[index].FieldOid = extensions[i]->extnId;
snej@4
   119
        fields[index].FieldValue.Data = (uint8_t*)extensions[i];
snej@4
   120
        fields[index++].FieldValue.Length = sizeof(CSSM_X509_EXTENSION);
snej@4
   121
    }
snej@4
   122
    CAssert(index == numberOfFields);
snej@4
   123
    
snej@4
   124
    CSSM_DATA result = {};
snej@4
   125
    checkcssm(CSSM_CL_CertCreateTemplate(clHandle, numberOfFields, fields, &result),
snej@4
   126
              @"CSSM_CL_CertCreateTemplate");
snej@4
   127
    return NSDataFromDataNoCopy(result, YES);
snej@4
   128
}
snej@4
   129
snej@4
   130
snej@4
   131
NSData* MYCertificateSign(NSData *certificateTemplate, 
snej@4
   132
                          MYPrivateKey *privateKey, 
snej@4
   133
                          CSSM_ALGORITHMS signingAlgorithmID,
snej@4
   134
                          CSSM_CL_HANDLE cssmCLHandle) 
snej@4
   135
{
snej@4
   136
snej@4
   137
    CAssert(certificateTemplate.length);
snej@4
   138
    CAssert(privateKey);
snej@4
   139
        
snej@4
   140
    NSData *signedCertificate = nil;
snej@4
   141
    CSSM_CC_HANDLE ccHandle = [privateKey _createSignatureContext: signingAlgorithmID];
snej@4
   142
    if (ccHandle) {
snej@4
   143
        CSSM_DATA rawCert = {certificateTemplate.length, (void*)certificateTemplate.bytes};
snej@4
   144
        CSSM_DATA signedResult = {};
snej@4
   145
        if (checkcssm(CSSM_CL_CertSign(cssmCLHandle, ccHandle, &rawCert, NULL, 0, &signedResult),
snej@4
   146
                      @"CSSM_CL_CertSign")) {
snej@4
   147
            signedCertificate = NSDataFromDataNoCopy(signedResult, YES);
snej@4
   148
            checkcssm(CSSM_DeleteContext(ccHandle), @"CSSM_DeleteContext");
snej@4
   149
        }
snej@4
   150
    }
snej@4
   151
    return signedCertificate;
snej@4
   152
}
snej@4
   153
snej@4
   154
snej@4
   155
MYCertificate* MYCertificateCreateSelfSigned(MYPrivateKey *privateKey,
snej@4
   156
                                             NSDictionary *attributes )
snej@4
   157
{
snej@4
   158
    // Extract attributes:
snej@4
   159
    NSMutableDictionary *subject = [[attributes mutableCopy] autorelease];
snej@4
   160
snej@4
   161
    unsigned serialNumber = [[attributes objectForKey: @"Serial Number"] unsignedIntValue];
snej@4
   162
    [subject removeObjectForKey: @"Serial Number"];
snej@4
   163
snej@4
   164
    NSDate *validFrom = [attributes objectForKey: @"Valid From"];
snej@4
   165
    [subject removeObjectForKey: @"Valid From"];
snej@4
   166
    NSDate *validTo = [attributes objectForKey: @"Valid To"];
snej@4
   167
    [subject removeObjectForKey: @"Valid To"];
snej@4
   168
    
snej@4
   169
    if (!serialNumber)
snej@4
   170
        serialNumber = 1;
snej@4
   171
    if (!validFrom)
snej@4
   172
        validFrom = [NSCalendarDate date];
snej@4
   173
    if (!validTo)
snej@4
   174
        validTo = [validFrom addTimeInterval: 60*60*24*366];
snej@4
   175
    
snej@4
   176
    const CSSM_X509_NAME *subjectStruct = createNameList(subject);
snej@4
   177
snej@4
   178
    // Create the key-usage extensions for the cert:    
snej@4
   179
    UInt8 keyUsageBits[2] = {0x00,0xFC};
snej@4
   180
    // that's binary 111111000; see http://tools.ietf.org/html/rfc3280#section-4.2.1.3
snej@4
   181
    CSSM_X509_EXTENSION keyUsage = {
snej@4
   182
        CSSMOID_KeyUsage, 
snej@8
   183
        false,      // non-critical
snej@4
   184
        CSSM_X509_DATAFORMAT_PARSED,
snej@4
   185
        {.parsedValue = &keyUsageBits}
snej@4
   186
    };
snej@4
   187
    
snej@4
   188
    // See http://tools.ietf.org/html/rfc3280#section-4.2.1.13
snej@4
   189
    struct ExtendedUsageList {
snej@4
   190
        UInt32 count;
snej@4
   191
        const CSSM_OID *oids;
snej@4
   192
    };
snej@8
   193
    CSSM_OID usageOids[3] = {CSSMOID_ServerAuth, CSSMOID_ClientAuth, CSSMOID_ExtendedKeyUsageAny};
snej@8
   194
    struct ExtendedUsageList extUsageBits = {3, usageOids};
snej@4
   195
    CSSM_X509_EXTENSION extendedKeyUsage = {
snej@4
   196
        CSSMOID_ExtendedKeyUsage,
snej@8
   197
        false,      // non-critical
snej@4
   198
        CSSM_X509_DATAFORMAT_PARSED,
snej@4
   199
        {.parsedValue = &extUsageBits}
snej@4
   200
    };
snej@4
   201
    
snej@4
   202
    const CSSM_X509_EXTENSION* extensions[2] = {&keyUsage, &extendedKeyUsage};
snej@4
   203
    
snej@4
   204
    CSSM_X509_ALGORITHM_IDENTIFIER algorithmID = {.algorithm=CSSMOID_RSA};
snej@4
   205
    CSSM_CL_HANDLE cssmCLHandle = getCLHandle();
snej@4
   206
snej@4
   207
    // Now create the certificate request and sign it:
snej@4
   208
    NSData *template, *signedCertificate = nil;
snej@4
   209
    
snej@4
   210
    template = MYCertificateCreateTemplate(subjectStruct, subjectStruct, // issuer==subject (self-signed) 
snej@4
   211
                                           validFrom, validTo, 
snej@4
   212
                                           serialNumber, 
snej@4
   213
                                           extensions, 2,
snej@4
   214
                                           privateKey.publicKey, 
snej@4
   215
                                           &algorithmID, 
snej@4
   216
                                           cssmCLHandle);
snej@4
   217
    if (!template)
snej@4
   218
        return nil;
snej@4
   219
    
snej@4
   220
    signedCertificate = MYCertificateSign(template, 
snej@4
   221
                                          privateKey, 
snej@4
   222
                                          CSSM_ALGID_SHA1WithRSA, 
snej@4
   223
                                          cssmCLHandle);
snej@4
   224
    if (!signedCertificate)
snej@4
   225
        return nil;
snej@4
   226
    
snej@4
   227
    return [[[MYCertificate alloc] initWithCertificateData: signedCertificate 
snej@4
   228
                                                      type: CSSM_CERT_UNKNOWN 
snej@4
   229
                                                  encoding: CSSM_CERT_ENCODING_UNKNOWN] autorelease];
snej@4
   230
}
snej@4
   231
snej@4
   232
snej@4
   233
snej@4
   234
MYIdentity* MYIdentityCreateSelfSigned(MYPrivateKey *privateKey,
snej@4
   235
                                       NSDictionary *attributes )
snej@4
   236
{
snej@4
   237
    MYCertificate *cert = MYCertificateCreateSelfSigned(privateKey, attributes);
snej@4
   238
    if (!cert)
snej@4
   239
        return nil;
snej@4
   240
    if (![privateKey.keychain addCertificate: cert])
snej@4
   241
        return nil;
snej@4
   242
    MYIdentity *identity = [[[MYIdentity alloc] initWithCertificateRef: cert.certificateRef] autorelease];
snej@4
   243
    CAssert(identity);
snej@4
   244
    return identity;
snej@4
   245
}
snej@4
   246
snej@4
   247
snej@4
   248
snej@4
   249
#pragma mark -
snej@4
   250
#pragma mark HELPER FUNCTIONS:
snej@4
   251
snej@4
   252
snej@4
   253
static void* mallocAutoreleased( size_t size ) {
snej@4
   254
    NSMutableData *data = [NSMutableData dataWithLength: size];
snej@4
   255
    return data.mutableBytes;
snej@4
   256
}
snej@4
   257
snej@4
   258
#define callocAutoreleasedArray(TYPE,N)  (TYPE*)mallocAutoreleased( sizeof(TYPE) * (N) )
snej@4
   259
snej@4
   260
snej@4
   261
/*
snej@4
   262
    CSSM_X509_NAME:
snej@4
   263
        uint32 numberOfRDNs;
snej@4
   264
        CSSM_X509_RDN_PTR RelativeDistinguishedName:
snej@4
   265
            uint32 numberOfPairs;
snej@4
   266
            CSSM_X509_TYPE_VALUE_PAIR_PTR AttributeTypeAndValue:
snej@4
   267
                CSSM_OID type;
snej@4
   268
                CSSM_BER_TAG valueType; // The Tag to be used when this value is BER encoded 
snej@4
   269
                CSSM_DATA value;
snej@4
   270
*/
snej@4
   271
snej@4
   272
snej@4
   273
static CSSM_X509_NAME* createNameList( NSDictionary *name ) {
snej@4
   274
    static NSArray *sNameKeys;
snej@4
   275
    static CSSM_OID sNameOIDs[7];
snej@4
   276
    if (!sNameKeys) {
snej@4
   277
        sNameKeys = [$array(@"Common Name", @"Surname",  @"Description", @"Name", @"Given Name", 
snej@4
   278
                            @"Email Address", @"Unstructured Name") retain];
snej@4
   279
        sNameOIDs[0] = CSSMOID_CommonName;
snej@4
   280
        sNameOIDs[1] = CSSMOID_Surname;
snej@4
   281
        sNameOIDs[2] = CSSMOID_Description;
snej@4
   282
        sNameOIDs[3] = CSSMOID_Name;
snej@4
   283
        sNameOIDs[4] = CSSMOID_GivenName;
snej@4
   284
        sNameOIDs[5] = CSSMOID_EmailAddress;
snej@4
   285
        sNameOIDs[6] = CSSMOID_UnstructuredName;
snej@4
   286
    }
snej@4
   287
    
snej@4
   288
    unsigned n = name.count;
snej@4
   289
    CAssert(n>0);
snej@4
   290
    CSSM_X509_RDN *rdns = callocAutoreleasedArray(CSSM_X509_RDN, name.count);
snej@4
   291
    CSSM_X509_RDN *rdn = &rdns[0];
snej@4
   292
    CSSM_X509_TYPE_VALUE_PAIR *pairs = callocAutoreleasedArray(CSSM_X509_TYPE_VALUE_PAIR, n);
snej@4
   293
    CSSM_X509_TYPE_VALUE_PAIR *pair = &pairs[0];
snej@4
   294
    for (NSString *key in name) {
snej@4
   295
        NSString *value = [name objectForKey: key];
snej@4
   296
        unsigned index = [sNameKeys indexOfObject: key];
snej@4
   297
        CAssert(index!=NSNotFound, @"X509 name key '%@' not supported'", key);
snej@4
   298
        rdn->numberOfPairs = 1;
snej@4
   299
        rdn->AttributeTypeAndValue = pair;
snej@4
   300
        pair->type = sNameOIDs[index];
snej@4
   301
        pair->valueType = BER_TAG_PRINTABLE_STRING;
snej@4
   302
        pair->value.Data = (void*) value.UTF8String;
snej@4
   303
        pair->value.Length = strlen((char*)pair->value.Data);
snej@4
   304
        rdn++;
snej@4
   305
        pair++;
snej@4
   306
    }
snej@4
   307
    CSSM_X509_NAME *outName = callocAutoreleasedArray(CSSM_X509_NAME,1);
snej@4
   308
    outName->numberOfRDNs = n;
snej@4
   309
    outName->RelativeDistinguishedName = rdns;
snej@4
   310
    return outName;
snej@4
   311
}
snej@4
   312
snej@4
   313
snej@4
   314
#pragma mark -
snej@4
   315
#pragma mark HELPER FUNCTIONS (from Keychain.framework)
snej@4
   316
snej@4
   317
snej@4
   318
static CSSM_X509_TIME* timeForNSDate(NSDate *date) {
snej@4
   319
    CAssert(date);
snej@4
   320
    
snej@4
   321
    NSCalendarDate *dateGMT = [NSCalendarDate dateWithTimeIntervalSinceReferenceDate: 
snej@4
   322
                                                            date.timeIntervalSinceReferenceDate];
snej@4
   323
    [dateGMT setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
snej@4
   324
    
snej@4
   325
    /* RFC 2549:
snej@4
   326
     
snej@4
   327
     4.1.2.5.2  GeneralizedTime
snej@4
   328
     
snej@4
   329
     The generalized time type, GeneralizedTime, is a standard ASN.1 type
snej@4
   330
     for variable precision representation of time.  Optionally, the
snej@4
   331
     GeneralizedTime field can include a representation of the time
snej@4
   332
     differential between local and Greenwich Mean Time.
snej@4
   333
     
snej@4
   334
     For the purposes of this profile, GeneralizedTime values MUST be
snej@4
   335
     expressed Greenwich Mean Time (Zulu) and MUST include seconds (i.e.,
snej@4
   336
     times are YYYYMMDDHHMMSSZ), even where the number of seconds is zero.
snej@4
   337
     GeneralizedTime values MUST NOT include fractional seconds. */
snej@4
   338
    
snej@4
   339
    CSSM_X509_TIME *result = mallocAutoreleased(sizeof(CSSM_X509_TIME));
snej@4
   340
    result->timeType = BER_TAG_GENERALIZED_TIME;
snej@4
   341
    result->time.Length = 15;
snej@4
   342
    result->time.Data = mallocAutoreleased(16);
snej@4
   343
    [[dateGMT descriptionWithCalendarFormat:@"%Y%m%d%H%M%SZ"] getCString: (char*)(result->time.Data)
snej@4
   344
                                                               maxLength: 16 
snej@4
   345
                                                                encoding: NSASCIIStringEncoding];
snej@4
   346
    return result;
snej@4
   347
}
snej@4
   348
snej@4
   349
snej@4
   350
static NSData* NSDataFromDataNoCopy(CSSM_DATA data, BOOL freeWhenDone) {
snej@4
   351
    if (data.Data)
snej@4
   352
        return [NSData dataWithBytesNoCopy:data.Data length:data.Length freeWhenDone: freeWhenDone];
snej@4
   353
    else
snej@4
   354
        return nil;
snej@4
   355
}
snej@4
   356
snej@4
   357
snej@4
   358
static BOOL intToDER(uint32_t theInt, CSSM_DATA *data) {
snej@4
   359
    CAssert(data);
snej@4
   360
    data->Length = 0;
snej@4
   361
    
snej@4
   362
    if (theInt < 0x100) {
snej@4
   363
        data->Data = (uint8_t*)malloc(1);
snej@4
   364
        
snej@4
   365
        if (NULL != data->Data) {
snej@4
   366
            data->Length = 1;
snej@4
   367
snej@4
   368
            data->Data[0] = (unsigned char)(theInt);
snej@4
   369
        }
snej@4
   370
    } else if (theInt < 0x10000) {
snej@4
   371
        data->Data = (uint8_t*)malloc(2);
snej@4
   372
        
snej@4
   373
        if (NULL != data->Data) {
snej@4
   374
            data->Length = 2;
snej@4
   375
snej@4
   376
            data->Data[0] = (unsigned char)(theInt >> 8);
snej@4
   377
            data->Data[1] = (unsigned char)(theInt);
snej@4
   378
        }
snej@4
   379
    } else if (theInt < 0x1000000) {
snej@4
   380
        data->Data = (uint8_t*)malloc(3);
snej@4
   381
        
snej@4
   382
        if (NULL != data->Data) {
snej@4
   383
            data->Length = 3;
snej@4
   384
snej@4
   385
            data->Data[0] = (unsigned char)(theInt >> 16);
snej@4
   386
            data->Data[1] = (unsigned char)(theInt >> 8);
snej@4
   387
            data->Data[2] = (unsigned char)(theInt);
snej@4
   388
        }
snej@4
   389
    } else {
snej@4
   390
        data->Data = (uint8_t*)malloc(4);
snej@4
   391
        
snej@4
   392
        if (NULL != data->Data) {
snej@4
   393
            data->Length = 4;
snej@4
   394
snej@4
   395
            data->Data[0] = (unsigned char)(theInt >> 24);
snej@4
   396
            data->Data[1] = (unsigned char)(theInt >> 16);
snej@4
   397
            data->Data[2] = (unsigned char)(theInt >> 8);
snej@4
   398
            data->Data[3] = (unsigned char)(theInt);
snej@4
   399
        }
snej@4
   400
    }
snej@4
   401
    
snej@4
   402
    return (NULL != data->Data);
snej@4
   403
}
snej@4
   404
snej@4
   405
snej@4
   406
snej@4
   407
#pragma mark -
snej@4
   408
#pragma mark HELPER FUNCTIONS (from Apple's source code):
snej@4
   409
snej@4
   410
snej@4
   411
// From Apple's cuCdsaUtils.cpp, in libsecurity_cdsa_utils:
snej@4
   412
snej@4
   413
snej@4
   414
/*
snej@4
   415
 * Standard app-level memory functions required by CDSA.
snej@4
   416
 */
snej@4
   417
static void * cuAppMalloc (CSSM_SIZE size, void *allocRef)             {return( malloc(size) );}
snej@4
   418
static void   cuAppFree (void *mem_ptr, void *allocRef)                {free(mem_ptr);}
snej@4
   419
static void * cuAppRealloc (void *ptr, CSSM_SIZE size, void *allocRef) {return( realloc( ptr, size ) );}
snej@4
   420
static void * cuAppCalloc (uint32 num, CSSM_SIZE size, void *allocRef) {return( calloc( num, size ) );}
snej@4
   421
snej@4
   422
static CSSM_VERSION vers = {2, 0};
snej@4
   423
static CSSM_API_MEMORY_FUNCS memFuncs = {
snej@4
   424
    cuAppMalloc,
snej@4
   425
    cuAppFree,
snej@4
   426
    cuAppRealloc,
snej@4
   427
    cuAppCalloc,
snej@4
   428
    NULL
snej@4
   429
};
snej@4
   430
snej@4
   431
static CSSM_CL_HANDLE cuClStartup()
snej@4
   432
{
snej@4
   433
	CSSM_CL_HANDLE clHand;
snej@4
   434
	
snej@4
   435
	if (!checkcssm(CSSM_ModuleLoad(&gGuidAppleX509CL,
snej@4
   436
                                   CSSM_KEY_HIERARCHY_NONE,
snej@4
   437
                                   NULL,			// eventHandler
snej@4
   438
                                   NULL), @"CSSM_ModuleLoad"))
snej@4
   439
        return 0;
snej@4
   440
    if (!checkcssm(CSSM_ModuleAttach(&gGuidAppleX509CL,
snej@4
   441
                                     &vers,
snej@4
   442
                                     &memFuncs,				// memFuncs
snej@4
   443
                                     0,						// SubserviceID
snej@4
   444
                                     CSSM_SERVICE_CL,		// SubserviceFlags - Where is this used?
snej@4
   445
                                     0,						// AttachFlags
snej@4
   446
                                     CSSM_KEY_HIERARCHY_NONE,
snej@4
   447
                                     NULL,					// FunctionTable
snej@4
   448
                                     0,						// NumFuncTable
snej@4
   449
                                     NULL,					// reserved
snej@4
   450
                                     &clHand), @"CSSM_ModuleAttach"))
snej@4
   451
        return 0;
snej@4
   452
    return clHand;
snej@4
   453
}
snej@4
   454
        
snej@4
   455
CSSM_CL_HANDLE getCLHandle() {
snej@4
   456
    static CSSM_CL_HANDLE sCLHandle = 0;
snej@4
   457
    if (!sCLHandle)
snej@4
   458
        sCLHandle = cuClStartup();
snej@4
   459
    return sCLHandle;
snej@4
   460
}
snej@4
   461
snej@4
   462
snej@4
   463
#pragma mark -
snej@4
   464
#pragma mark TEST CASE:
snej@4
   465
snej@4
   466
snej@4
   467
TestCase(MYCertGen) {
snej@4
   468
    CSSM_CL_HANDLE cl = getCLHandle();
snej@4
   469
    Log(@"CSSM_CL_HANDLE = %p", cl);
snej@4
   470
    CAssert(cl);
snej@4
   471
    
snej@8
   472
    Log(@"Generating a key pair...");
snej@8
   473
    MYPrivateKey *privateKey = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 2048];
snej@8
   474
    Log(@"Key-pair = { %@, %@ }", privateKey, privateKey.publicKey);
snej@4
   475
    
snej@4
   476
    Log(@"...creating cert...");
snej@4
   477
    
snej@4
   478
    MYCertificate *cert = MYCertificateCreateSelfSigned(privateKey,
snej@4
   479
                                                      $dict(
snej@4
   480
                                                          {@"Common Name", @"waldo"},
snej@4
   481
                                                          {@"Given Name", @"Waldo"},
snej@4
   482
                                                          {@"Surname", @"Widdershins"},
snej@4
   483
                                                          {@"Email Address", @"waldo@example.com"},
snej@4
   484
                                                          {@"Description", @"Just a fictitious person"},
snej@4
   485
                                                      ));
snej@4
   486
    Log(@"Cert = %@", cert);
snej@4
   487
    CAssert(cert);
snej@8
   488
    [cert.certificateData writeToFile: @"/tmp/MYCryptoTest.cer" atomically: NO];
snej@4
   489
    
snej@4
   490
    Log(@"Cert name = %@", cert.commonName);
snej@4
   491
    Log(@"Cert email = %@", cert.emailAddresses);
snej@4
   492
    Log(@"Cert pub key = %@", cert.publicKey);
snej@4
   493
    CAssertEqual(cert.commonName, @"waldo");
snej@4
   494
    CAssertEqual(cert.emailAddresses, $array(@"waldo@example.com"));
snej@4
   495
    CAssertEqual(cert.publicKey.publicKeyDigest, privateKey.publicKeyDigest);
snej@4
   496
    
snej@8
   497
    CAssert([[MYKeychain defaultKeychain] addCertificate: cert]);
snej@8
   498
    
snej@8
   499
    CAssert([cert setUserTrust: kSecTrustResultProceed]);
snej@4
   500
}
jens@21
   501
jens@21
   502
jens@21
   503
jens@21
   504
/*
jens@21
   505
 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
jens@21
   506
 
jens@21
   507
 Redistribution and use in source and binary forms, with or without modification, are permitted
jens@21
   508
 provided that the following conditions are met:
jens@21
   509
 
jens@21
   510
 * Redistributions of source code must retain the above copyright notice, this list of conditions
jens@21
   511
 and the following disclaimer.
jens@21
   512
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
jens@21
   513
 and the following disclaimer in the documentation and/or other materials provided with the
jens@21
   514
 distribution.
jens@21
   515
 
jens@21
   516
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
jens@21
   517
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
jens@21
   518
 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
jens@21
   519
 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
jens@21
   520
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
jens@21
   521
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
jens@21
   522
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
jens@21
   523
 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jens@21
   524
 */