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@26
|
10 |
// <http://tools.ietf.org/html/rfc3280> "RFC 3280: Internet X.509 Certificate Profile"
|
jens@20
|
11 |
// <http://www.columbia.edu/~ariel/ssleay/layman.html> "Layman's Guide To ASN.1/BER/DER"
|
jens@20
|
12 |
// <http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt> "X.509 Style Guide"
|
jens@20
|
13 |
// <http://en.wikipedia.org/wiki/X.509> Wikipedia article on X.509
|
jens@17
|
14 |
|
jens@17
|
15 |
|
jens@21
|
16 |
#import "MYCertificateInfo.h"
|
jens@21
|
17 |
#import "MYCrypto.h"
|
jens@17
|
18 |
#import "MYASN1Object.h"
|
jens@17
|
19 |
#import "MYOID.h"
|
jens@17
|
20 |
#import "MYBERParser.h"
|
jens@17
|
21 |
#import "MYDEREncoder.h"
|
jens@17
|
22 |
#import "MYErrorUtils.h"
|
jens@17
|
23 |
|
jens@17
|
24 |
|
jens@25
|
25 |
#define kDefaultExpirationTime (60.0 * 60.0 * 24.0 * 365.0) /* that's 1 year */
|
jens@19
|
26 |
|
jens@25
|
27 |
/* X.509 version number to generate. Even though my code doesn't (yet) add any of the post-v1
|
jens@25
|
28 |
metadata, it's necessary to write v3 or the resulting certs won't be accepted on some platforms,
|
jens@25
|
29 |
notably iPhone OS.
|
jens@25
|
30 |
"This field is used mainly for marketing purposes to claim that software is X.509v3 compliant
|
jens@25
|
31 |
(even when it isn't)." --Peter Gutmann */
|
jens@25
|
32 |
#define kCertRequestVersionNumber 3
|
jens@19
|
33 |
|
jens@25
|
34 |
|
jens@25
|
35 |
/* "Safe" NSArray accessor -- returns nil if out of range. */
|
jens@17
|
36 |
static id $atIf(NSArray *array, NSUInteger index) {
|
jens@17
|
37 |
return index < array.count ?[array objectAtIndex: index] :nil;
|
jens@17
|
38 |
}
|
jens@17
|
39 |
|
jens@17
|
40 |
|
jens@20
|
41 |
@interface MYCertificateName ()
|
jens@20
|
42 |
- (id) _initWithComponents: (NSArray*)components;
|
jens@20
|
43 |
@end
|
jens@20
|
44 |
|
jens@21
|
45 |
@interface MYCertificateInfo ()
|
jens@21
|
46 |
@property (retain) NSArray *_root;
|
jens@21
|
47 |
@end
|
jens@21
|
48 |
|
jens@20
|
49 |
|
jens@20
|
50 |
#pragma mark -
|
jens@21
|
51 |
@implementation MYCertificateInfo
|
jens@17
|
52 |
|
jens@17
|
53 |
|
jens@19
|
54 |
static MYOID *kRSAAlgorithmID, *kRSAWithSHA1AlgorithmID, *kCommonNameOID,
|
jens@25
|
55 |
*kGivenNameOID, *kSurnameOID, *kDescriptionOID, *kEmailOID;
|
jens@17
|
56 |
|
jens@17
|
57 |
|
jens@17
|
58 |
+ (void) initialize {
|
jens@19
|
59 |
if (!kEmailOID) {
|
jens@19
|
60 |
kRSAAlgorithmID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 1, 1,}
|
jens@19
|
61 |
count: 7];
|
jens@19
|
62 |
kRSAWithSHA1AlgorithmID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 1, 5}
|
jens@19
|
63 |
count: 7];
|
jens@19
|
64 |
kCommonNameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 3}
|
jens@19
|
65 |
count: 4];
|
jens@19
|
66 |
kGivenNameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 42}
|
jens@19
|
67 |
count: 4];
|
jens@19
|
68 |
kSurnameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 4}
|
jens@19
|
69 |
count: 4];
|
jens@19
|
70 |
kDescriptionOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 13}
|
jens@26
|
71 |
count: 4];
|
jens@19
|
72 |
kEmailOID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 9, 1}
|
jens@19
|
73 |
count: 7];
|
jens@17
|
74 |
}
|
jens@21
|
75 |
}
|
jens@21
|
76 |
|
jens@21
|
77 |
|
jens@21
|
78 |
- (id) initWithRoot: (NSArray*)root
|
jens@21
|
79 |
{
|
jens@21
|
80 |
self = [super init];
|
jens@21
|
81 |
if (self != nil) {
|
jens@21
|
82 |
_root = [root retain];
|
jens@21
|
83 |
}
|
jens@21
|
84 |
return self;
|
jens@17
|
85 |
}
|
jens@17
|
86 |
|
jens@17
|
87 |
+ (NSString*) validate: (id)root {
|
jens@17
|
88 |
NSArray *top = $castIf(NSArray,root);
|
jens@17
|
89 |
if (top.count < 3)
|
jens@17
|
90 |
return @"Too few top-level components";
|
jens@17
|
91 |
NSArray *info = $castIf(NSArray, [top objectAtIndex: 0]);
|
jens@17
|
92 |
if (info.count < 7)
|
jens@17
|
93 |
return @"Too few identity components";
|
jens@17
|
94 |
MYASN1Object *version = $castIf(MYASN1Object, [info objectAtIndex: 0]);
|
jens@17
|
95 |
if (!version || version.tag != 0)
|
jens@17
|
96 |
return @"Missing or invalid version";
|
jens@17
|
97 |
NSArray *versionComps = $castIf(NSArray, version.components);
|
jens@17
|
98 |
if (!versionComps || versionComps.count != 1)
|
jens@17
|
99 |
return @"Invalid version";
|
jens@17
|
100 |
NSNumber *versionNum = $castIf(NSNumber, [versionComps objectAtIndex: 0]);
|
jens@17
|
101 |
if (!versionNum || versionNum.intValue < 0 || versionNum.intValue > 2)
|
jens@17
|
102 |
return @"Unrecognized version number";
|
jens@17
|
103 |
return nil;
|
jens@17
|
104 |
}
|
jens@17
|
105 |
|
jens@17
|
106 |
|
jens@17
|
107 |
- (id) initWithCertificateData: (NSData*)data error: (NSError**)outError;
|
jens@17
|
108 |
{
|
jens@21
|
109 |
if (outError) *outError = nil;
|
jens@21
|
110 |
id root = MYBERParse(data,outError);
|
jens@21
|
111 |
NSString *errorMsg = [[self class] validate: root];
|
jens@21
|
112 |
if (errorMsg) {
|
jens@21
|
113 |
if (outError && !*outError)
|
jens@21
|
114 |
*outError = MYError(2, MYASN1ErrorDomain, @"Invalid certificate: %@", errorMsg);
|
jens@21
|
115 |
[self release];
|
jens@21
|
116 |
return nil;
|
jens@17
|
117 |
}
|
jens@21
|
118 |
|
jens@24
|
119 |
self = [self initWithRoot: root];
|
jens@24
|
120 |
if (self) {
|
jens@24
|
121 |
_data = [data copy];
|
jens@24
|
122 |
}
|
jens@24
|
123 |
return self;
|
jens@17
|
124 |
}
|
jens@17
|
125 |
|
jens@17
|
126 |
- (void) dealloc
|
jens@17
|
127 |
{
|
jens@17
|
128 |
[_root release];
|
jens@24
|
129 |
[_data release];
|
jens@17
|
130 |
[super dealloc];
|
jens@17
|
131 |
}
|
jens@17
|
132 |
|
jens@21
|
133 |
- (BOOL) isEqual: (id)object {
|
jens@21
|
134 |
return [object isKindOfClass: [MYCertificateInfo class]]
|
jens@21
|
135 |
&& [_root isEqual: ((MYCertificateInfo*)object)->_root];
|
jens@21
|
136 |
}
|
jens@17
|
137 |
|
jens@19
|
138 |
- (NSArray*) _info {return $castIf(NSArray,$atIf(_root,0));}
|
jens@17
|
139 |
|
jens@19
|
140 |
- (NSArray*) _validDates {return $castIf(NSArray, [self._info objectAtIndex: 4]);}
|
jens@17
|
141 |
|
jens@21
|
142 |
@synthesize _root;
|
jens@19
|
143 |
|
jens@19
|
144 |
|
jens@19
|
145 |
- (NSDate*) validFrom {return $castIf(NSDate, $atIf(self._validDates, 0));}
|
jens@19
|
146 |
- (NSDate*) validTo {return $castIf(NSDate, $atIf(self._validDates, 1));}
|
jens@20
|
147 |
|
jens@20
|
148 |
- (MYCertificateName*) subject {
|
jens@20
|
149 |
return [[[MYCertificateName alloc] _initWithComponents: [self._info objectAtIndex: 5]] autorelease];
|
jens@20
|
150 |
}
|
jens@20
|
151 |
|
jens@20
|
152 |
- (MYCertificateName*) issuer {
|
jens@20
|
153 |
return [[[MYCertificateName alloc] _initWithComponents: [self._info objectAtIndex: 3]] autorelease];
|
jens@20
|
154 |
}
|
jens@19
|
155 |
|
jens@19
|
156 |
- (BOOL) isSigned {return [_root count] >= 3;}
|
jens@19
|
157 |
|
jens@19
|
158 |
- (BOOL) isRoot {
|
jens@19
|
159 |
id issuer = $atIf(self._info,3);
|
jens@19
|
160 |
return $equal(issuer, $atIf(self._info,5)) || $equal(issuer, $array());
|
jens@19
|
161 |
}
|
jens@19
|
162 |
|
jens@19
|
163 |
|
jens@26
|
164 |
- (NSData*) subjectPublicKeyData {
|
jens@19
|
165 |
NSArray *keyInfo = $cast(NSArray, $atIf(self._info, 6));
|
jens@17
|
166 |
MYOID *keyAlgorithmID = $castIf(MYOID, $atIf($castIf(NSArray,$atIf(keyInfo,0)), 0));
|
jens@17
|
167 |
if (!$equal(keyAlgorithmID, kRSAAlgorithmID))
|
jens@17
|
168 |
return nil;
|
jens@26
|
169 |
return $cast(MYBitString, $atIf(keyInfo, 1)).bits;
|
jens@26
|
170 |
}
|
jens@26
|
171 |
|
jens@26
|
172 |
- (MYPublicKey*) subjectPublicKey {
|
jens@26
|
173 |
NSData *keyData = self.subjectPublicKeyData;
|
jens@17
|
174 |
if (!keyData) return nil;
|
jens@26
|
175 |
return [[[MYPublicKey alloc] initWithKeyData: keyData] autorelease];
|
jens@17
|
176 |
}
|
jens@17
|
177 |
|
jens@24
|
178 |
- (NSData*) signedData {
|
jens@24
|
179 |
if (!_data)
|
jens@24
|
180 |
return nil;
|
jens@24
|
181 |
// The root object is a sequence; we want to extract the 1st object of that sequence.
|
jens@24
|
182 |
const UInt8 *certStart = _data.bytes;
|
jens@24
|
183 |
const UInt8 *start = MYBERGetContents(_data, nil);
|
jens@24
|
184 |
if (!start) return nil;
|
jens@24
|
185 |
size_t length = MYBERGetLength([NSData dataWithBytesNoCopy: (void*)start
|
jens@24
|
186 |
length: _data.length - (start-certStart)
|
jens@24
|
187 |
freeWhenDone: NO],
|
jens@24
|
188 |
NULL);
|
jens@24
|
189 |
if (length==0)
|
jens@24
|
190 |
return nil;
|
jens@24
|
191 |
return [NSData dataWithBytes: start length: (start + length - certStart)];
|
jens@24
|
192 |
}
|
jens@24
|
193 |
|
jens@24
|
194 |
- (MYOID*) signatureAlgorithmID {
|
jens@24
|
195 |
return $castIf(MYOID, $atIf($castIf(NSArray,$atIf(_root,1)), 0));
|
jens@24
|
196 |
}
|
jens@24
|
197 |
|
jens@24
|
198 |
- (NSData*) signature {
|
jens@24
|
199 |
id signature = $atIf(_root,2);
|
jens@24
|
200 |
if ([signature isKindOfClass: [MYBitString class]])
|
jens@24
|
201 |
signature = [signature bits];
|
jens@24
|
202 |
return $castIf(NSData,signature);
|
jens@24
|
203 |
}
|
jens@24
|
204 |
|
jens@24
|
205 |
- (BOOL) verifySignatureWithKey: (MYPublicKey*)issuerPublicKey {
|
jens@24
|
206 |
if (!$equal(self.signatureAlgorithmID, kRSAWithSHA1AlgorithmID))
|
jens@24
|
207 |
return NO;
|
jens@24
|
208 |
NSData *signedData = self.signedData;
|
jens@24
|
209 |
NSData *signature = self.signature;
|
jens@24
|
210 |
return signedData && signature && [issuerPublicKey verifySignature: signature ofData: signedData];
|
jens@24
|
211 |
}
|
jens@24
|
212 |
|
jens@24
|
213 |
|
jens@21
|
214 |
@end
|
jens@17
|
215 |
|
jens@17
|
216 |
|
jens@17
|
217 |
|
jens@17
|
218 |
|
jens@19
|
219 |
#pragma mark -
|
jens@21
|
220 |
@implementation MYCertificateRequest
|
jens@19
|
221 |
|
jens@21
|
222 |
- (id) initWithPublicKey: (MYPublicKey*)publicKey {
|
jens@21
|
223 |
Assert(publicKey);
|
jens@21
|
224 |
id empty = [NSNull null];
|
jens@25
|
225 |
id version = [[MYASN1Object alloc] initWithTag: 0
|
jens@25
|
226 |
ofClass: 2
|
jens@25
|
227 |
components: $array($object(kCertRequestVersionNumber - 1))];
|
jens@21
|
228 |
NSArray *root = $array( $marray(version,
|
jens@21
|
229 |
empty, // serial #
|
jens@21
|
230 |
$array(kRSAAlgorithmID),
|
jens@21
|
231 |
$marray(),
|
jens@21
|
232 |
$marray(empty, empty),
|
jens@21
|
233 |
$marray(),
|
jens@21
|
234 |
$array( $array(kRSAAlgorithmID, empty),
|
jens@21
|
235 |
[MYBitString bitStringWithData: publicKey.keyData] ) ) );
|
jens@21
|
236 |
self = [super initWithRoot: root];
|
jens@21
|
237 |
[version release];
|
jens@23
|
238 |
if (self) {
|
jens@23
|
239 |
_publicKey = publicKey.retain;
|
jens@23
|
240 |
}
|
jens@19
|
241 |
return self;
|
jens@19
|
242 |
}
|
jens@23
|
243 |
|
jens@23
|
244 |
- (void) dealloc
|
jens@23
|
245 |
{
|
jens@23
|
246 |
[_publicKey release];
|
jens@23
|
247 |
[super dealloc];
|
jens@23
|
248 |
}
|
jens@23
|
249 |
|
jens@19
|
250 |
|
jens@21
|
251 |
- (NSDate*) validFrom {return [super validFrom];}
|
jens@21
|
252 |
- (NSDate*) validTo {return [super validTo];}
|
jens@19
|
253 |
|
jens@19
|
254 |
- (void) setValidFrom: (NSDate*)validFrom {
|
jens@19
|
255 |
[(NSMutableArray*)self._validDates replaceObjectAtIndex: 0 withObject: validFrom];
|
jens@19
|
256 |
}
|
jens@19
|
257 |
|
jens@19
|
258 |
- (void) setValidTo: (NSDate*)validTo {
|
jens@19
|
259 |
[(NSMutableArray*)self._validDates replaceObjectAtIndex: 1 withObject: validTo];
|
jens@19
|
260 |
}
|
jens@19
|
261 |
|
jens@19
|
262 |
|
jens@21
|
263 |
- (void) fillInValues {
|
jens@19
|
264 |
NSMutableArray *info = (NSMutableArray*)self._info;
|
jens@19
|
265 |
// Set serial number if there isn't one yet:
|
jens@19
|
266 |
if (!$castIf(NSNumber, [info objectAtIndex: 1])) {
|
jens@19
|
267 |
UInt64 serial = floor(CFAbsoluteTimeGetCurrent() * 1000);
|
jens@19
|
268 |
[info replaceObjectAtIndex: 1 withObject: $object(serial)];
|
jens@19
|
269 |
}
|
jens@19
|
270 |
|
jens@19
|
271 |
// Set up valid date range if there isn't one yet:
|
jens@19
|
272 |
NSDate *validFrom = self.validFrom;
|
jens@19
|
273 |
if (!validFrom)
|
jens@19
|
274 |
validFrom = self.validFrom = [NSDate date];
|
jens@19
|
275 |
NSDate *validTo = self.validTo;
|
jens@19
|
276 |
if (!validTo)
|
jens@19
|
277 |
self.validTo = [validFrom addTimeInterval: kDefaultExpirationTime];
|
jens@21
|
278 |
}
|
jens@21
|
279 |
|
jens@21
|
280 |
|
jens@21
|
281 |
- (NSData*) requestData: (NSError**)outError {
|
jens@21
|
282 |
[self fillInValues];
|
jens@21
|
283 |
return [MYDEREncoder encodeRootObject: self._info error: outError];
|
jens@21
|
284 |
}
|
jens@21
|
285 |
|
jens@21
|
286 |
|
jens@21
|
287 |
- (NSData*) selfSignWithPrivateKey: (MYPrivateKey*)privateKey
|
jens@21
|
288 |
error: (NSError**)outError
|
jens@21
|
289 |
{
|
jens@21
|
290 |
AssertEqual(privateKey.publicKey, _publicKey); // Keys must form a pair
|
jens@19
|
291 |
|
jens@21
|
292 |
// Copy subject to issuer:
|
jens@21
|
293 |
NSMutableArray *info = (NSMutableArray*)self._info;
|
jens@21
|
294 |
[info replaceObjectAtIndex: 3 withObject: [info objectAtIndex: 5]];
|
jens@21
|
295 |
|
jens@21
|
296 |
// Sign the request:
|
jens@21
|
297 |
NSData *dataToSign = [self requestData: outError];
|
jens@19
|
298 |
if (!dataToSign)
|
jens@21
|
299 |
return nil;
|
jens@21
|
300 |
MYBitString *signature = [MYBitString bitStringWithData: [privateKey signData: dataToSign]];
|
jens@19
|
301 |
|
jens@21
|
302 |
// Generate and encode the certificate:
|
jens@21
|
303 |
NSArray *root = $array(info,
|
jens@21
|
304 |
$array(kRSAWithSHA1AlgorithmID, [NSNull null]),
|
jens@21
|
305 |
signature);
|
jens@21
|
306 |
return [MYDEREncoder encodeRootObject: root error: outError];
|
jens@21
|
307 |
}
|
jens@21
|
308 |
|
jens@21
|
309 |
|
jens@21
|
310 |
- (MYIdentity*) createSelfSignedIdentityWithPrivateKey: (MYPrivateKey*)privateKey
|
jens@21
|
311 |
error: (NSError**)outError
|
jens@21
|
312 |
{
|
jens@23
|
313 |
Assert(privateKey.keychain!=nil);
|
jens@21
|
314 |
NSData *certData = [self selfSignWithPrivateKey: privateKey error: outError];
|
jens@21
|
315 |
if (!certData)
|
jens@21
|
316 |
return nil;
|
jens@21
|
317 |
MYCertificate *cert = [privateKey.keychain importCertificate: certData];
|
jens@21
|
318 |
Assert(cert!=nil);
|
jens@23
|
319 |
Assert(cert.keychain!=nil);
|
jens@23
|
320 |
AssertEqual(cert.publicKey.keyData, _publicKey.keyData);
|
jens@21
|
321 |
MYIdentity *identity = cert.identity;
|
jens@21
|
322 |
Assert(identity!=nil);
|
jens@21
|
323 |
return identity;
|
jens@19
|
324 |
}
|
jens@19
|
325 |
|
jens@19
|
326 |
|
jens@17
|
327 |
@end
|
jens@17
|
328 |
|
jens@17
|
329 |
|
jens@17
|
330 |
|
jens@20
|
331 |
#pragma mark -
|
jens@20
|
332 |
@implementation MYCertificateName
|
jens@20
|
333 |
|
jens@20
|
334 |
- (id) _initWithComponents: (NSArray*)components
|
jens@20
|
335 |
{
|
jens@20
|
336 |
self = [super init];
|
jens@20
|
337 |
if (self != nil) {
|
jens@20
|
338 |
_components = [components retain];
|
jens@20
|
339 |
}
|
jens@20
|
340 |
return self;
|
jens@20
|
341 |
}
|
jens@20
|
342 |
|
jens@20
|
343 |
- (void) dealloc
|
jens@20
|
344 |
{
|
jens@20
|
345 |
[_components release];
|
jens@20
|
346 |
[super dealloc];
|
jens@20
|
347 |
}
|
jens@20
|
348 |
|
jens@20
|
349 |
- (BOOL) isEqual: (id)object {
|
jens@20
|
350 |
return [object isKindOfClass: [MYCertificateName class]]
|
jens@20
|
351 |
&& [_components isEqual: ((MYCertificateName*)object)->_components];
|
jens@20
|
352 |
}
|
jens@20
|
353 |
|
jens@20
|
354 |
- (NSArray*) _pairForOID: (MYOID*)oid {
|
jens@20
|
355 |
for (id nameEntry in _components) {
|
jens@20
|
356 |
for (id pair in $castIf(NSSet,nameEntry)) {
|
jens@20
|
357 |
if ([pair isKindOfClass: [NSArray class]] && [pair count] == 2) {
|
jens@20
|
358 |
if ($equal(oid, [pair objectAtIndex: 0]))
|
jens@20
|
359 |
return pair;
|
jens@20
|
360 |
}
|
jens@20
|
361 |
}
|
jens@20
|
362 |
}
|
jens@20
|
363 |
return nil;
|
jens@20
|
364 |
}
|
jens@20
|
365 |
|
jens@20
|
366 |
- (NSString*) stringForOID: (MYOID*)oid {
|
jens@20
|
367 |
return [[self _pairForOID: oid] objectAtIndex: 1];
|
jens@20
|
368 |
}
|
jens@20
|
369 |
|
jens@20
|
370 |
- (void) setString: (NSString*)value forOID: (MYOID*)oid {
|
jens@20
|
371 |
NSMutableArray *pair = (NSMutableArray*) [self _pairForOID: oid];
|
jens@26
|
372 |
if (pair) {
|
jens@26
|
373 |
if (value)
|
jens@26
|
374 |
[pair replaceObjectAtIndex: 1 withObject: value];
|
jens@26
|
375 |
else
|
jens@26
|
376 |
Assert(NO,@"-setString:forOID: removing strings is unimplemented");//FIX
|
jens@26
|
377 |
} else {
|
jens@26
|
378 |
if (value)
|
jens@26
|
379 |
[(NSMutableArray*)_components addObject: [NSSet setWithObject: $marray(oid,value)]];
|
jens@26
|
380 |
}
|
jens@20
|
381 |
}
|
jens@20
|
382 |
|
jens@20
|
383 |
- (NSString*) commonName {return [self stringForOID: kCommonNameOID];}
|
jens@20
|
384 |
- (NSString*) givenName {return [self stringForOID: kGivenNameOID];}
|
jens@20
|
385 |
- (NSString*) surname {return [self stringForOID: kSurnameOID];}
|
jens@20
|
386 |
- (NSString*) nameDescription {return [self stringForOID: kDescriptionOID];}
|
jens@20
|
387 |
- (NSString*) emailAddress {return [self stringForOID: kEmailOID];}
|
jens@20
|
388 |
|
jens@20
|
389 |
- (void) setCommonName: (NSString*)commonName {[self setString: commonName forOID: kCommonNameOID];}
|
jens@20
|
390 |
- (void) setGivenName: (NSString*)givenName {[self setString: givenName forOID: kGivenNameOID];}
|
jens@20
|
391 |
- (void) setSurname: (NSString*)surname {[self setString: surname forOID: kSurnameOID];}
|
jens@20
|
392 |
- (void) setNameDescription: (NSString*)desc {[self setString: desc forOID: kDescriptionOID];}
|
jens@20
|
393 |
- (void) setEmailAddress: (NSString*)email {[self setString: email forOID: kEmailOID];}
|
jens@20
|
394 |
|
jens@20
|
395 |
|
jens@20
|
396 |
@end
|
jens@20
|
397 |
|
jens@20
|
398 |
|
jens@21
|
399 |
/*
|
jens@21
|
400 |
Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
|
jens@17
|
401 |
|
jens@21
|
402 |
Redistribution and use in source and binary forms, with or without modification, are permitted
|
jens@21
|
403 |
provided that the following conditions are met:
|
jens@21
|
404 |
|
jens@21
|
405 |
* Redistributions of source code must retain the above copyright notice, this list of conditions
|
jens@21
|
406 |
and the following disclaimer.
|
jens@21
|
407 |
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
jens@21
|
408 |
and the following disclaimer in the documentation and/or other materials provided with the
|
jens@21
|
409 |
distribution.
|
jens@21
|
410 |
|
jens@21
|
411 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
jens@21
|
412 |
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
jens@21
|
413 |
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
|
jens@21
|
414 |
BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
jens@21
|
415 |
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
jens@21
|
416 |
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
jens@21
|
417 |
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
jens@21
|
418 |
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
jens@21
|
419 |
*/
|