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