jens@17
|
1 |
//
|
jens@21
|
2 |
// MYCertificateInfo.m
|
jens@17
|
3 |
// MYCrypto
|
jens@17
|
4 |
//
|
jens@17
|
5 |
// Created by Jens Alfke on 6/2/09.
|
jens@17
|
6 |
// Copyright 2009 Jens Alfke. All rights reserved.
|
jens@17
|
7 |
//
|
jens@17
|
8 |
|
jens@17
|
9 |
// References:
|
jens@20
|
10 |
// <http://www.columbia.edu/~ariel/ssleay/layman.html> "Layman's Guide To ASN.1/BER/DER"
|
jens@20
|
11 |
// <http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt> "X.509 Style Guide"
|
jens@20
|
12 |
// <http://en.wikipedia.org/wiki/X.509> Wikipedia article on X.509
|
jens@17
|
13 |
|
jens@17
|
14 |
|
jens@21
|
15 |
#import "MYCertificateInfo.h"
|
jens@21
|
16 |
#import "MYCrypto.h"
|
jens@17
|
17 |
#import "MYASN1Object.h"
|
jens@17
|
18 |
#import "MYOID.h"
|
jens@17
|
19 |
#import "MYBERParser.h"
|
jens@17
|
20 |
#import "MYDEREncoder.h"
|
jens@17
|
21 |
#import "MYErrorUtils.h"
|
jens@17
|
22 |
|
jens@17
|
23 |
|
jens@19
|
24 |
#define kDefaultExpirationTime (60.0 * 60.0 * 24.0 * 365.0)
|
jens@19
|
25 |
|
jens@19
|
26 |
|
jens@17
|
27 |
static id $atIf(NSArray *array, NSUInteger index) {
|
jens@17
|
28 |
return index < array.count ?[array objectAtIndex: index] :nil;
|
jens@17
|
29 |
}
|
jens@17
|
30 |
|
jens@17
|
31 |
|
jens@20
|
32 |
@interface MYCertificateName ()
|
jens@20
|
33 |
- (id) _initWithComponents: (NSArray*)components;
|
jens@20
|
34 |
@end
|
jens@20
|
35 |
|
jens@21
|
36 |
@interface MYCertificateInfo ()
|
jens@21
|
37 |
@property (retain) NSArray *_root;
|
jens@21
|
38 |
@end
|
jens@21
|
39 |
|
jens@20
|
40 |
|
jens@20
|
41 |
#pragma mark -
|
jens@21
|
42 |
@implementation MYCertificateInfo
|
jens@17
|
43 |
|
jens@17
|
44 |
|
jens@19
|
45 |
static MYOID *kRSAAlgorithmID, *kRSAWithSHA1AlgorithmID, *kCommonNameOID,
|
jens@19
|
46 |
*kGivenNameOID, *kSurnameOID, *kDescriptionOID, *kEmailOID;
|
jens@17
|
47 |
|
jens@17
|
48 |
|
jens@17
|
49 |
+ (void) initialize {
|
jens@19
|
50 |
if (!kEmailOID) {
|
jens@19
|
51 |
kRSAAlgorithmID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 1, 1,}
|
jens@19
|
52 |
count: 7];
|
jens@19
|
53 |
kRSAWithSHA1AlgorithmID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 1, 5}
|
jens@19
|
54 |
count: 7];
|
jens@19
|
55 |
kCommonNameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 3}
|
jens@19
|
56 |
count: 4];
|
jens@19
|
57 |
kGivenNameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 42}
|
jens@19
|
58 |
count: 4];
|
jens@19
|
59 |
kSurnameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 4}
|
jens@19
|
60 |
count: 4];
|
jens@19
|
61 |
kDescriptionOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 13}
|
jens@19
|
62 |
count: 7];
|
jens@19
|
63 |
kEmailOID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 9, 1}
|
jens@19
|
64 |
count: 7];
|
jens@17
|
65 |
}
|
jens@21
|
66 |
}
|
jens@21
|
67 |
|
jens@21
|
68 |
|
jens@21
|
69 |
- (id) initWithRoot: (NSArray*)root
|
jens@21
|
70 |
{
|
jens@21
|
71 |
self = [super init];
|
jens@21
|
72 |
if (self != nil) {
|
jens@21
|
73 |
_root = [root retain];
|
jens@21
|
74 |
}
|
jens@21
|
75 |
return self;
|
jens@17
|
76 |
}
|
jens@17
|
77 |
|
jens@17
|
78 |
+ (NSString*) validate: (id)root {
|
jens@17
|
79 |
NSArray *top = $castIf(NSArray,root);
|
jens@17
|
80 |
if (top.count < 3)
|
jens@17
|
81 |
return @"Too few top-level components";
|
jens@17
|
82 |
NSArray *info = $castIf(NSArray, [top objectAtIndex: 0]);
|
jens@17
|
83 |
if (info.count < 7)
|
jens@17
|
84 |
return @"Too few identity components";
|
jens@17
|
85 |
MYASN1Object *version = $castIf(MYASN1Object, [info objectAtIndex: 0]);
|
jens@17
|
86 |
if (!version || version.tag != 0)
|
jens@17
|
87 |
return @"Missing or invalid version";
|
jens@17
|
88 |
NSArray *versionComps = $castIf(NSArray, version.components);
|
jens@17
|
89 |
if (!versionComps || versionComps.count != 1)
|
jens@17
|
90 |
return @"Invalid version";
|
jens@17
|
91 |
NSNumber *versionNum = $castIf(NSNumber, [versionComps objectAtIndex: 0]);
|
jens@17
|
92 |
if (!versionNum || versionNum.intValue < 0 || versionNum.intValue > 2)
|
jens@17
|
93 |
return @"Unrecognized version number";
|
jens@17
|
94 |
return nil;
|
jens@17
|
95 |
}
|
jens@17
|
96 |
|
jens@17
|
97 |
|
jens@17
|
98 |
- (id) initWithCertificateData: (NSData*)data error: (NSError**)outError;
|
jens@17
|
99 |
{
|
jens@21
|
100 |
if (outError) *outError = nil;
|
jens@21
|
101 |
id root = MYBERParse(data,outError);
|
jens@21
|
102 |
NSString *errorMsg = [[self class] validate: root];
|
jens@21
|
103 |
if (errorMsg) {
|
jens@21
|
104 |
if (outError && !*outError)
|
jens@21
|
105 |
*outError = MYError(2, MYASN1ErrorDomain, @"Invalid certificate: %@", errorMsg);
|
jens@21
|
106 |
[self release];
|
jens@21
|
107 |
return nil;
|
jens@17
|
108 |
}
|
jens@21
|
109 |
|
jens@21
|
110 |
return [self initWithRoot: root];
|
jens@17
|
111 |
}
|
jens@17
|
112 |
|
jens@17
|
113 |
- (void) dealloc
|
jens@17
|
114 |
{
|
jens@17
|
115 |
[_root release];
|
jens@17
|
116 |
[super dealloc];
|
jens@17
|
117 |
}
|
jens@17
|
118 |
|
jens@21
|
119 |
- (BOOL) isEqual: (id)object {
|
jens@21
|
120 |
return [object isKindOfClass: [MYCertificateInfo class]]
|
jens@21
|
121 |
&& [_root isEqual: ((MYCertificateInfo*)object)->_root];
|
jens@21
|
122 |
}
|
jens@17
|
123 |
|
jens@19
|
124 |
- (NSArray*) _info {return $castIf(NSArray,$atIf(_root,0));}
|
jens@17
|
125 |
|
jens@19
|
126 |
- (NSArray*) _validDates {return $castIf(NSArray, [self._info objectAtIndex: 4]);}
|
jens@17
|
127 |
|
jens@21
|
128 |
@synthesize _root;
|
jens@19
|
129 |
|
jens@19
|
130 |
|
jens@19
|
131 |
- (NSDate*) validFrom {return $castIf(NSDate, $atIf(self._validDates, 0));}
|
jens@19
|
132 |
- (NSDate*) validTo {return $castIf(NSDate, $atIf(self._validDates, 1));}
|
jens@20
|
133 |
|
jens@20
|
134 |
- (MYCertificateName*) subject {
|
jens@20
|
135 |
return [[[MYCertificateName alloc] _initWithComponents: [self._info objectAtIndex: 5]] autorelease];
|
jens@20
|
136 |
}
|
jens@20
|
137 |
|
jens@20
|
138 |
- (MYCertificateName*) issuer {
|
jens@20
|
139 |
return [[[MYCertificateName alloc] _initWithComponents: [self._info objectAtIndex: 3]] autorelease];
|
jens@20
|
140 |
}
|
jens@19
|
141 |
|
jens@19
|
142 |
- (BOOL) isSigned {return [_root count] >= 3;}
|
jens@19
|
143 |
|
jens@19
|
144 |
- (BOOL) isRoot {
|
jens@19
|
145 |
id issuer = $atIf(self._info,3);
|
jens@19
|
146 |
return $equal(issuer, $atIf(self._info,5)) || $equal(issuer, $array());
|
jens@19
|
147 |
}
|
jens@19
|
148 |
|
jens@19
|
149 |
|
jens@17
|
150 |
- (MYPublicKey*) subjectPublicKey {
|
jens@19
|
151 |
NSArray *keyInfo = $cast(NSArray, $atIf(self._info, 6));
|
jens@17
|
152 |
MYOID *keyAlgorithmID = $castIf(MYOID, $atIf($castIf(NSArray,$atIf(keyInfo,0)), 0));
|
jens@17
|
153 |
if (!$equal(keyAlgorithmID, kRSAAlgorithmID))
|
jens@17
|
154 |
return nil;
|
jens@17
|
155 |
MYBitString *keyData = $cast(MYBitString, $atIf(keyInfo, 1));
|
jens@17
|
156 |
if (!keyData) return nil;
|
jens@17
|
157 |
return [[[MYPublicKey alloc] initWithKeyData: keyData.bits] autorelease];
|
jens@17
|
158 |
}
|
jens@17
|
159 |
|
jens@21
|
160 |
@end
|
jens@17
|
161 |
|
jens@17
|
162 |
|
jens@17
|
163 |
|
jens@17
|
164 |
|
jens@19
|
165 |
#pragma mark -
|
jens@21
|
166 |
@implementation MYCertificateRequest
|
jens@19
|
167 |
|
jens@21
|
168 |
- (id) initWithPublicKey: (MYPublicKey*)publicKey {
|
jens@21
|
169 |
Assert(publicKey);
|
jens@21
|
170 |
id empty = [NSNull null];
|
jens@21
|
171 |
id version = [[MYASN1Object alloc] initWithTag: 0 ofClass: 2 components: $array($object(0))];
|
jens@21
|
172 |
NSArray *root = $array( $marray(version,
|
jens@21
|
173 |
empty, // serial #
|
jens@21
|
174 |
$array(kRSAAlgorithmID),
|
jens@21
|
175 |
$marray(),
|
jens@21
|
176 |
$marray(empty, empty),
|
jens@21
|
177 |
$marray(),
|
jens@21
|
178 |
$array( $array(kRSAAlgorithmID, empty),
|
jens@21
|
179 |
[MYBitString bitStringWithData: publicKey.keyData] ) ) );
|
jens@21
|
180 |
self = [super initWithRoot: root];
|
jens@21
|
181 |
[version release];
|
jens@19
|
182 |
return self;
|
jens@19
|
183 |
}
|
jens@19
|
184 |
|
jens@21
|
185 |
- (NSDate*) validFrom {return [super validFrom];}
|
jens@21
|
186 |
- (NSDate*) validTo {return [super validTo];}
|
jens@19
|
187 |
|
jens@19
|
188 |
- (void) setValidFrom: (NSDate*)validFrom {
|
jens@19
|
189 |
[(NSMutableArray*)self._validDates replaceObjectAtIndex: 0 withObject: validFrom];
|
jens@19
|
190 |
}
|
jens@19
|
191 |
|
jens@19
|
192 |
- (void) setValidTo: (NSDate*)validTo {
|
jens@19
|
193 |
[(NSMutableArray*)self._validDates replaceObjectAtIndex: 1 withObject: validTo];
|
jens@19
|
194 |
}
|
jens@19
|
195 |
|
jens@19
|
196 |
|
jens@21
|
197 |
- (void) fillInValues {
|
jens@19
|
198 |
NSMutableArray *info = (NSMutableArray*)self._info;
|
jens@19
|
199 |
// Set serial number if there isn't one yet:
|
jens@19
|
200 |
if (!$castIf(NSNumber, [info objectAtIndex: 1])) {
|
jens@19
|
201 |
UInt64 serial = floor(CFAbsoluteTimeGetCurrent() * 1000);
|
jens@19
|
202 |
[info replaceObjectAtIndex: 1 withObject: $object(serial)];
|
jens@19
|
203 |
}
|
jens@19
|
204 |
|
jens@19
|
205 |
// Set up valid date range if there isn't one yet:
|
jens@19
|
206 |
NSDate *validFrom = self.validFrom;
|
jens@19
|
207 |
if (!validFrom)
|
jens@19
|
208 |
validFrom = self.validFrom = [NSDate date];
|
jens@19
|
209 |
NSDate *validTo = self.validTo;
|
jens@19
|
210 |
if (!validTo)
|
jens@19
|
211 |
self.validTo = [validFrom addTimeInterval: kDefaultExpirationTime];
|
jens@21
|
212 |
}
|
jens@21
|
213 |
|
jens@21
|
214 |
|
jens@21
|
215 |
- (NSData*) requestData: (NSError**)outError {
|
jens@21
|
216 |
[self fillInValues];
|
jens@21
|
217 |
return [MYDEREncoder encodeRootObject: self._info error: outError];
|
jens@21
|
218 |
}
|
jens@21
|
219 |
|
jens@21
|
220 |
|
jens@21
|
221 |
- (NSData*) selfSignWithPrivateKey: (MYPrivateKey*)privateKey
|
jens@21
|
222 |
error: (NSError**)outError
|
jens@21
|
223 |
{
|
jens@21
|
224 |
AssertEqual(privateKey.publicKey, _publicKey); // Keys must form a pair
|
jens@19
|
225 |
|
jens@21
|
226 |
// Copy subject to issuer:
|
jens@21
|
227 |
NSMutableArray *info = (NSMutableArray*)self._info;
|
jens@21
|
228 |
[info replaceObjectAtIndex: 3 withObject: [info objectAtIndex: 5]];
|
jens@21
|
229 |
|
jens@21
|
230 |
// Sign the request:
|
jens@21
|
231 |
NSData *dataToSign = [self requestData: outError];
|
jens@19
|
232 |
if (!dataToSign)
|
jens@21
|
233 |
return nil;
|
jens@21
|
234 |
MYBitString *signature = [MYBitString bitStringWithData: [privateKey signData: dataToSign]];
|
jens@19
|
235 |
|
jens@21
|
236 |
// Generate and encode the certificate:
|
jens@21
|
237 |
NSArray *root = $array(info,
|
jens@21
|
238 |
$array(kRSAWithSHA1AlgorithmID, [NSNull null]),
|
jens@21
|
239 |
signature);
|
jens@21
|
240 |
return [MYDEREncoder encodeRootObject: root error: outError];
|
jens@21
|
241 |
}
|
jens@21
|
242 |
|
jens@21
|
243 |
|
jens@21
|
244 |
- (MYIdentity*) createSelfSignedIdentityWithPrivateKey: (MYPrivateKey*)privateKey
|
jens@21
|
245 |
error: (NSError**)outError
|
jens@21
|
246 |
{
|
jens@21
|
247 |
NSData *certData = [self selfSignWithPrivateKey: privateKey error: outError];
|
jens@21
|
248 |
if (!certData)
|
jens@21
|
249 |
return nil;
|
jens@21
|
250 |
MYCertificate *cert = [privateKey.keychain importCertificate: certData];
|
jens@21
|
251 |
Assert(cert!=nil);
|
jens@21
|
252 |
MYIdentity *identity = cert.identity;
|
jens@21
|
253 |
Assert(identity!=nil);
|
jens@21
|
254 |
return identity;
|
jens@19
|
255 |
}
|
jens@19
|
256 |
|
jens@19
|
257 |
|
jens@17
|
258 |
@end
|
jens@17
|
259 |
|
jens@17
|
260 |
|
jens@17
|
261 |
|
jens@20
|
262 |
#pragma mark -
|
jens@20
|
263 |
@implementation MYCertificateName
|
jens@20
|
264 |
|
jens@20
|
265 |
- (id) _initWithComponents: (NSArray*)components
|
jens@20
|
266 |
{
|
jens@20
|
267 |
self = [super init];
|
jens@20
|
268 |
if (self != nil) {
|
jens@20
|
269 |
_components = [components retain];
|
jens@20
|
270 |
}
|
jens@20
|
271 |
return self;
|
jens@20
|
272 |
}
|
jens@20
|
273 |
|
jens@20
|
274 |
- (void) dealloc
|
jens@20
|
275 |
{
|
jens@20
|
276 |
[_components release];
|
jens@20
|
277 |
[super dealloc];
|
jens@20
|
278 |
}
|
jens@20
|
279 |
|
jens@20
|
280 |
- (BOOL) isEqual: (id)object {
|
jens@20
|
281 |
return [object isKindOfClass: [MYCertificateName class]]
|
jens@20
|
282 |
&& [_components isEqual: ((MYCertificateName*)object)->_components];
|
jens@20
|
283 |
}
|
jens@20
|
284 |
|
jens@20
|
285 |
- (NSArray*) _pairForOID: (MYOID*)oid {
|
jens@20
|
286 |
for (id nameEntry in _components) {
|
jens@20
|
287 |
for (id pair in $castIf(NSSet,nameEntry)) {
|
jens@20
|
288 |
if ([pair isKindOfClass: [NSArray class]] && [pair count] == 2) {
|
jens@20
|
289 |
if ($equal(oid, [pair objectAtIndex: 0]))
|
jens@20
|
290 |
return pair;
|
jens@20
|
291 |
}
|
jens@20
|
292 |
}
|
jens@20
|
293 |
}
|
jens@20
|
294 |
return nil;
|
jens@20
|
295 |
}
|
jens@20
|
296 |
|
jens@20
|
297 |
- (NSString*) stringForOID: (MYOID*)oid {
|
jens@20
|
298 |
return [[self _pairForOID: oid] objectAtIndex: 1];
|
jens@20
|
299 |
}
|
jens@20
|
300 |
|
jens@20
|
301 |
- (void) setString: (NSString*)value forOID: (MYOID*)oid {
|
jens@20
|
302 |
NSMutableArray *pair = (NSMutableArray*) [self _pairForOID: oid];
|
jens@20
|
303 |
if (pair)
|
jens@20
|
304 |
[pair replaceObjectAtIndex: 1 withObject: value];
|
jens@20
|
305 |
else
|
jens@20
|
306 |
[(NSMutableArray*)_components addObject: [NSSet setWithObject: $marray(oid,value)]];
|
jens@20
|
307 |
}
|
jens@20
|
308 |
|
jens@20
|
309 |
- (NSString*) commonName {return [self stringForOID: kCommonNameOID];}
|
jens@20
|
310 |
- (NSString*) givenName {return [self stringForOID: kGivenNameOID];}
|
jens@20
|
311 |
- (NSString*) surname {return [self stringForOID: kSurnameOID];}
|
jens@20
|
312 |
- (NSString*) nameDescription {return [self stringForOID: kDescriptionOID];}
|
jens@20
|
313 |
- (NSString*) emailAddress {return [self stringForOID: kEmailOID];}
|
jens@20
|
314 |
|
jens@20
|
315 |
- (void) setCommonName: (NSString*)commonName {[self setString: commonName forOID: kCommonNameOID];}
|
jens@20
|
316 |
- (void) setGivenName: (NSString*)givenName {[self setString: givenName forOID: kGivenNameOID];}
|
jens@20
|
317 |
- (void) setSurname: (NSString*)surname {[self setString: surname forOID: kSurnameOID];}
|
jens@20
|
318 |
- (void) setNameDescription: (NSString*)desc {[self setString: desc forOID: kDescriptionOID];}
|
jens@20
|
319 |
- (void) setEmailAddress: (NSString*)email {[self setString: email forOID: kEmailOID];}
|
jens@20
|
320 |
|
jens@20
|
321 |
|
jens@20
|
322 |
@end
|
jens@20
|
323 |
|
jens@20
|
324 |
|
jens@20
|
325 |
|
jens@20
|
326 |
#pragma mark -
|
jens@20
|
327 |
#pragma mark TEST CASES:
|
jens@17
|
328 |
|
jens@19
|
329 |
#if DEBUG
|
jens@19
|
330 |
|
jens@19
|
331 |
|
jens@21
|
332 |
static MYCertificateInfo* testCert(NSString *filename, BOOL selfSigned) {
|
jens@21
|
333 |
Log(@"--- Creating MYCertificateInfo from %@", filename);
|
jens@19
|
334 |
NSData *certData = [NSData dataWithContentsOfFile: filename];
|
jens@19
|
335 |
//Log(@"Cert Data =\n%@", certData);
|
jens@19
|
336 |
NSError *error = nil;
|
jens@21
|
337 |
MYCertificateInfo *pcert = [[MYCertificateInfo alloc] initWithCertificateData: certData
|
jens@21
|
338 |
error: &error];
|
jens@19
|
339 |
CAssertNil(error);
|
jens@19
|
340 |
CAssert(pcert != nil);
|
jens@19
|
341 |
|
jens@19
|
342 |
CAssertEq(pcert.isRoot, selfSigned);
|
jens@21
|
343 |
|
jens@19
|
344 |
Log(@"Subject Public Key = %@", pcert.subjectPublicKey);
|
jens@19
|
345 |
CAssert(pcert.subjectPublicKey);
|
jens@20
|
346 |
MYCertificateName *subject = pcert.subject;
|
jens@20
|
347 |
Log(@"Common Name = %@", subject.commonName);
|
jens@20
|
348 |
Log(@"Given Name = %@", subject.givenName);
|
jens@20
|
349 |
Log(@"Surname = %@", subject.surname);
|
jens@20
|
350 |
Log(@"Desc = %@", subject.nameDescription);
|
jens@20
|
351 |
Log(@"Email = %@", subject.emailAddress);
|
jens@21
|
352 |
CAssert(subject.commonName);
|
jens@21
|
353 |
|
jens@21
|
354 |
// Now go through MYCertificate:
|
jens@21
|
355 |
MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData];
|
jens@21
|
356 |
CAssert(cert);
|
jens@21
|
357 |
CAssertEqual(cert.info, pcert);
|
jens@21
|
358 |
|
jens@19
|
359 |
return pcert;
|
jens@19
|
360 |
}
|
jens@19
|
361 |
|
jens@19
|
362 |
|
jens@17
|
363 |
TestCase(ParsedCert) {
|
jens@17
|
364 |
testCert(@"../../Tests/selfsigned.cer", YES);
|
jens@17
|
365 |
testCert(@"../../Tests/iphonedev.cer", NO);
|
jens@19
|
366 |
}
|
jens@19
|
367 |
|
jens@19
|
368 |
|
jens@21
|
369 |
#import "MYCrypto_Private.h"
|
jens@19
|
370 |
|
jens@19
|
371 |
TestCase(CreateCert) {
|
jens@19
|
372 |
MYPrivateKey *privateKey = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 512];
|
jens@21
|
373 |
CAssert(privateKey);
|
jens@21
|
374 |
MYIdentity *identity = nil;
|
jens@21
|
375 |
@try{
|
jens@21
|
376 |
MYCertificateRequest *pcert = [[MYCertificateRequest alloc] initWithPublicKey: privateKey.publicKey];
|
jens@21
|
377 |
MYCertificateName *subject = pcert.subject;
|
jens@21
|
378 |
subject.commonName = @"testcase";
|
jens@21
|
379 |
subject.givenName = @"Test";
|
jens@21
|
380 |
subject.surname = @"Case";
|
jens@21
|
381 |
subject.nameDescription = @"Just a test certificate created by MYCrypto";
|
jens@21
|
382 |
subject.emailAddress = @"testcase@example.com";
|
jens@19
|
383 |
|
jens@21
|
384 |
subject = pcert.subject;
|
jens@21
|
385 |
CAssertEqual(subject.commonName, @"testcase");
|
jens@21
|
386 |
CAssertEqual(subject.givenName, @"Test");
|
jens@21
|
387 |
CAssertEqual(subject.surname, @"Case");
|
jens@21
|
388 |
CAssertEqual(subject.nameDescription, @"Just a test certificate created by MYCrypto");
|
jens@21
|
389 |
CAssertEqual(subject.emailAddress, @"testcase@example.com");
|
jens@21
|
390 |
|
jens@21
|
391 |
Log(@"Signing...");
|
jens@21
|
392 |
NSError *error;
|
jens@21
|
393 |
NSData *certData = [pcert selfSignWithPrivateKey: privateKey error: &error];
|
jens@21
|
394 |
Log(@"Generated cert = \n%@", certData);
|
jens@21
|
395 |
CAssert(certData);
|
jens@21
|
396 |
CAssertNil(error);
|
jens@21
|
397 |
CAssert(certData);
|
jens@21
|
398 |
[certData writeToFile: @"../../Tests/generated.cer" atomically: YES];
|
jens@21
|
399 |
MYCertificateInfo *pcert2 = testCert(@"../../Tests/generated.cer", YES);
|
jens@21
|
400 |
|
jens@21
|
401 |
Log(@"Verifying Info...");
|
jens@21
|
402 |
MYCertificateName *subject2 = pcert2.subject;
|
jens@21
|
403 |
CAssertEqual(subject2,subject);
|
jens@21
|
404 |
CAssertEqual(subject2.commonName, @"testcase");
|
jens@21
|
405 |
CAssertEqual(subject2.givenName, @"Test");
|
jens@21
|
406 |
CAssertEqual(subject2.surname, @"Case");
|
jens@21
|
407 |
CAssertEqual(subject2.nameDescription, @"Just a test certificate created by MYCrypto");
|
jens@21
|
408 |
CAssertEqual(subject2.emailAddress, @"testcase@example.com");
|
jens@21
|
409 |
|
jens@21
|
410 |
Log(@"Verifying Signature...");
|
jens@21
|
411 |
MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData];
|
jens@21
|
412 |
Log(@"Loaded %@", cert);
|
jens@21
|
413 |
CAssert(cert);
|
jens@21
|
414 |
MYPublicKey *certKey = cert.publicKey;
|
jens@21
|
415 |
Log(@"Its public key = %@", certKey);
|
jens@21
|
416 |
CAssertEqual(certKey.keyData, privateKey.publicKey.keyData);
|
jens@21
|
417 |
|
jens@21
|
418 |
Log(@"Creating Identity...");
|
jens@21
|
419 |
identity = [pcert createSelfSignedIdentityWithPrivateKey: privateKey error: &error];
|
jens@21
|
420 |
Log(@"Identity = %@", identity);
|
jens@21
|
421 |
CAssert(identity);
|
jens@21
|
422 |
CAssertNil(error);
|
jens@21
|
423 |
CAssertEqual(identity.keychain, [MYKeychain defaultKeychain]);
|
jens@21
|
424 |
CAssertEqual(identity.privateKey, privateKey);
|
jens@21
|
425 |
CAssert([identity isEqualToCertificate: cert]);
|
jens@21
|
426 |
|
jens@21
|
427 |
[pcert release];
|
jens@21
|
428 |
|
jens@21
|
429 |
} @finally {
|
jens@21
|
430 |
[privateKey removeFromKeychain];
|
jens@21
|
431 |
[identity removeFromKeychain];
|
jens@21
|
432 |
}
|
jens@19
|
433 |
}
|
jens@19
|
434 |
|
jens@19
|
435 |
#endif
|
jens@19
|
436 |
|
jens@17
|
437 |
|
jens@21
|
438 |
/*
|
jens@21
|
439 |
Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
|
jens@17
|
440 |
|
jens@21
|
441 |
Redistribution and use in source and binary forms, with or without modification, are permitted
|
jens@21
|
442 |
provided that the following conditions are met:
|
jens@21
|
443 |
|
jens@21
|
444 |
* Redistributions of source code must retain the above copyright notice, this list of conditions
|
jens@21
|
445 |
and the following disclaimer.
|
jens@21
|
446 |
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
jens@21
|
447 |
and the following disclaimer in the documentation and/or other materials provided with the
|
jens@21
|
448 |
distribution.
|
jens@21
|
449 |
|
jens@21
|
450 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
jens@21
|
451 |
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
jens@21
|
452 |
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
|
jens@21
|
453 |
BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
jens@21
|
454 |
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
jens@21
|
455 |
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
jens@21
|
456 |
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
jens@21
|
457 |
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
jens@21
|
458 |
*/
|