MYCertificateTest.m
author Jens Alfke <jens@mooseyard.com>
Tue Jul 21 10:13:08 2009 -0700 (2009-07-21)
changeset 27 d0aadddb9c64
permissions -rw-r--r--
MYCertificate now checks validity of self-signed certs loaded from the keychain (because the Security framework doesn't validate self-signed certs.)
jens@26
     1
//
jens@26
     2
//  MYCertificateTest.m
jens@26
     3
//  MYCrypto-iPhone
jens@26
     4
//
jens@26
     5
//  Created by Jens Alfke on 6/15/09.
jens@26
     6
//  Copyright 2009 Jens Alfke. All rights reserved.
jens@26
     7
//
jens@26
     8
jens@26
     9
#import "MYCertificateInfo.h"
jens@26
    10
#import "MYCrypto.h"
jens@26
    11
#import "MYCrypto_Private.h"
jens@26
    12
jens@26
    13
jens@26
    14
#if DEBUG
jens@26
    15
jens@26
    16
jens@26
    17
static MYCertificateInfo* testCertData(NSData *certData, BOOL selfSigned) {
jens@26
    18
    //Log(@"Cert Data =\n%@", certData);
jens@26
    19
    CAssert(certData!=nil);
jens@26
    20
    NSError *error = nil;
jens@26
    21
    MYCertificateInfo *pcert = [[MYCertificateInfo alloc] initWithCertificateData: certData 
jens@26
    22
                                                                            error: &error];
jens@26
    23
    CAssertNil(error);
jens@26
    24
    CAssert(pcert != nil);
jens@26
    25
    
jens@26
    26
    CAssertEq(pcert.isRoot, selfSigned);
jens@26
    27
        
jens@26
    28
    MYCertificateName *subject = pcert.subject;
jens@26
    29
    Log(@"Common Name = %@", subject.commonName);
jens@26
    30
    Log(@"Given Name  = %@", subject.givenName);
jens@26
    31
    Log(@"Surname     = %@", subject.surname);
jens@26
    32
    Log(@"Desc        = %@", subject.nameDescription);
jens@26
    33
    Log(@"Email       = %@", subject.emailAddress);
jens@26
    34
    CAssert(subject.commonName);
jens@26
    35
    
jens@26
    36
    MYPublicKey *pcertKey = pcert.subjectPublicKey;
jens@26
    37
    Log(@"Subject Public Key = %@", pcertKey);
jens@26
    38
    CAssert(pcertKey);
jens@26
    39
    
jens@26
    40
    // Now go through MYCertificate:
jens@26
    41
    Log(@"Creating a MYCertificate from the data...");
jens@26
    42
    MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData];
jens@26
    43
    Log(@"MYCertificate = %@", cert);
jens@26
    44
    CAssert(cert);
jens@26
    45
    CAssertEqual(cert.info, pcert);
jens@26
    46
    Log(@"Trust = %@", MYTrustResultDescribe([cert evaluateTrust]));
jens@26
    47
    
jens@26
    48
    MYPublicKey *certKey = cert.publicKey;
jens@26
    49
    Log(@"MYCertificate public key = ", certKey);
jens@26
    50
    CAssertEqual(certKey.keyData, pcert.subjectPublicKey.keyData);
jens@26
    51
    [cert release];
jens@26
    52
    /*TEMP
jens@26
    53
    Log(@"Adding to keychain...");
jens@26
    54
    cert = [[MYKeychain defaultKeychain] importCertificate: certData];
jens@26
    55
    Log(@"Imported as %@", cert);
jens@26
    56
    //CAssert(cert);
jens@26
    57
    if (cert) {
jens@26
    58
        Log(@"Removing from keychain...");
jens@26
    59
        CAssert([cert removeFromKeychain]);
jens@26
    60
    }
jens@26
    61
    */
jens@26
    62
    return pcert;
jens@26
    63
}
jens@26
    64
jens@26
    65
static NSData* readTestFile(NSString *filename) {
jens@26
    66
#if TARGET_OS_IPHONE
jens@26
    67
    filename = [[NSBundle mainBundle] pathForResource: filename ofType: @"cer"];
jens@26
    68
#else
jens@26
    69
    filename = [[@"../../Tests/" stringByAppendingPathComponent: filename]
jens@26
    70
                stringByAppendingPathExtension: @"cer"];
jens@26
    71
#endif
jens@26
    72
    Log(@"--- Testing certificate file %@", filename);
jens@26
    73
    NSData *data = [NSData dataWithContentsOfFile: filename];
jens@26
    74
    CAssert(data, @"Couldn't read file %@", filename);
jens@26
    75
    return data;
jens@26
    76
}
jens@26
    77
jens@26
    78
static MYCertificateInfo* testCert(NSString *filename, BOOL selfSigned) {
jens@26
    79
    return testCertData(readTestFile(filename), selfSigned);
jens@26
    80
}
jens@26
    81
jens@26
    82
jens@26
    83
TestCase(ParsedCert) {
jens@26
    84
    testCert(@"selfsigned", YES);
jens@26
    85
    testCert(@"iphonedev", NO);
jens@26
    86
    
jens@26
    87
    // Now test a self-signed cert with a bad signature:
jens@26
    88
    MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: readTestFile(@"selfsigned_altered")];
jens@26
    89
    Log(@"MYCertificate = %@", cert);
jens@26
    90
    CAssertNil(cert);
jens@26
    91
}
jens@26
    92
jens@26
    93
jens@26
    94
#import "MYCrypto_Private.h"
jens@26
    95
jens@26
    96
TestCase(CreateCert) {
jens@26
    97
    MYPrivateKey *privateKey = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 512];
jens@26
    98
    CAssert(privateKey);
jens@26
    99
    Log(@"---- Generated key-pair with %@, %@", privateKey.publicKey, privateKey);
jens@26
   100
    MYIdentity *identity = nil;
jens@26
   101
    @try{
jens@26
   102
        MYCertificateRequest *pcert = [[MYCertificateRequest alloc] initWithPublicKey: privateKey.publicKey];
jens@26
   103
        MYCertificateName *subject = pcert.subject;
jens@26
   104
        subject.commonName = @"testcase";
jens@26
   105
        subject.givenName = @"Test";
jens@26
   106
        subject.surname = @"Case";
jens@26
   107
        subject.nameDescription = @"Just a test certificate created by MYCrypto";
jens@26
   108
        subject.emailAddress = @"testcase@example.com";
jens@26
   109
jens@26
   110
        subject = pcert.subject;
jens@26
   111
        CAssertEqual(subject.commonName, @"testcase");
jens@26
   112
        CAssertEqual(subject.givenName, @"Test");
jens@26
   113
        CAssertEqual(subject.surname, @"Case");
jens@26
   114
        CAssertEqual(subject.nameDescription, @"Just a test certificate created by MYCrypto");
jens@26
   115
        CAssertEqual(subject.emailAddress, @"testcase@example.com");
jens@26
   116
        
jens@26
   117
        CAssertEqual(pcert.subjectPublicKey.keyData, privateKey.publicKey.keyData);
jens@26
   118
        
jens@26
   119
        Log(@"---- Signing...");
jens@26
   120
        NSError *error;
jens@26
   121
        NSData *certData = [pcert selfSignWithPrivateKey: privateKey error: &error];
jens@26
   122
        Log(@"Generated cert = \n%@", certData);
jens@26
   123
        CAssert(certData);
jens@26
   124
        CAssertNil(error);
jens@26
   125
        CAssert(certData);
jens@26
   126
        MYCertificateInfo *pcert2 = testCertData(certData, YES);
jens@26
   127
        
jens@26
   128
        Log(@"---- Verifying Info...");
jens@26
   129
        MYCertificateName *subject2 = pcert2.subject;
jens@26
   130
        CAssertEqual(subject2,subject);
jens@26
   131
        CAssertEqual(subject2.commonName, @"testcase");
jens@26
   132
        CAssertEqual(subject2.givenName, @"Test");
jens@26
   133
        CAssertEqual(subject2.surname, @"Case");
jens@26
   134
        CAssertEqual(subject2.nameDescription, @"Just a test certificate created by MYCrypto");
jens@26
   135
        CAssertEqual(subject2.emailAddress, @"testcase@example.com");
jens@26
   136
                
jens@26
   137
        Log(@"---- Creating MYCertificate object...");
jens@26
   138
        MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData];
jens@26
   139
        Log(@"Loaded %@", cert);
jens@26
   140
        CAssert(cert);
jens@26
   141
        MYPublicKey *certKey = cert.publicKey;
jens@26
   142
        Log(@"Its public key has name %@", certKey.name);//TEMP
jens@26
   143
        Log(@"Its public key = %@", certKey);
jens@26
   144
        CAssertEqual(certKey.keyData, privateKey.publicKey.keyData);
jens@26
   145
        Log(@"X.509 trust = %@", MYTrustResultDescribe([cert evaluateTrust]));
jens@26
   146
        Log(@"SSL trust = %@", MYTrustResultDescribe([cert evaluateTrustWithPolicy: [MYCertificate SSLPolicy]]));
jens@26
   147
        
jens@26
   148
        Log(@"---- Adding cert to keychain...");
jens@26
   149
        MYCertificate *addedCert = [[MYKeychain defaultKeychain] importCertificate: certData];
jens@26
   150
        Log(@"Imported as %@", addedCert);
jens@26
   151
        //CAssert(addedCert);
jens@26
   152
        if (addedCert)
jens@26
   153
            CAssert([addedCert removeFromKeychain]);
jens@26
   154
        
jens@26
   155
        Log(@"---- Creating Identity...");
jens@26
   156
        identity = [pcert createSelfSignedIdentityWithPrivateKey: privateKey error: &error];
jens@26
   157
        Log(@"Identity = %@", identity);
jens@26
   158
        CAssert(identity);
jens@26
   159
        CAssertNil(error);
jens@26
   160
        CAssertEqual(identity.keychain, [MYKeychain defaultKeychain]);
jens@26
   161
        CAssertEqual(identity.privateKey.publicKeyDigest, privateKey.publicKeyDigest);
jens@26
   162
        CAssert([identity isEqualToCertificate: cert]);
jens@26
   163
        
jens@26
   164
        [pcert release];
jens@26
   165
        
jens@26
   166
    } @finally {
jens@26
   167
        // [privateKey removeFromKeychain];
jens@26
   168
        // [identity removeFromKeychain];
jens@26
   169
        // Currently I'm leaving them in, so the EnumerateXXX tests can chew on them later.
jens@26
   170
    }
jens@26
   171
}
jens@26
   172
jens@26
   173
#endif
jens@26
   174
jens@26
   175
jens@26
   176
/*
jens@26
   177
 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
jens@26
   178
 
jens@26
   179
 Redistribution and use in source and binary forms, with or without modification, are permitted
jens@26
   180
 provided that the following conditions are met:
jens@26
   181
 
jens@26
   182
 * Redistributions of source code must retain the above copyright notice, this list of conditions
jens@26
   183
 and the following disclaimer.
jens@26
   184
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
jens@26
   185
 and the following disclaimer in the documentation and/or other materials provided with the
jens@26
   186
 distribution.
jens@26
   187
 
jens@26
   188
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
jens@26
   189
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
jens@26
   190
 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
jens@26
   191
 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
jens@26
   192
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
jens@26
   193
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
jens@26
   194
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
jens@26
   195
 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jens@26
   196
 */