jens@16
|
1 |
//
|
jens@16
|
2 |
// MYDEREncoder.m
|
jens@16
|
3 |
// MYCrypto
|
jens@16
|
4 |
//
|
jens@16
|
5 |
// Created by Jens Alfke on 5/29/09.
|
jens@16
|
6 |
// Copyright 2009 Jens Alfke. All rights reserved.
|
jens@16
|
7 |
//
|
jens@16
|
8 |
|
jens@20
|
9 |
// Reference:
|
jens@20
|
10 |
// <http://www.columbia.edu/~ariel/ssleay/layman.html> "Layman's Guide To ASN.1/BER/DER"
|
jens@20
|
11 |
|
jens@16
|
12 |
#import "MYDEREncoder.h"
|
jens@16
|
13 |
#import "MYASN1Object.h"
|
jens@16
|
14 |
#import "MYBERParser.h"
|
jens@16
|
15 |
#import "MYOID.h"
|
jens@16
|
16 |
#import "MYErrorUtils.h"
|
jens@16
|
17 |
|
jens@16
|
18 |
|
jens@16
|
19 |
#define MYDEREncoderException @"MYDEREncoderException"
|
jens@16
|
20 |
|
jens@16
|
21 |
|
jens@16
|
22 |
@interface MYDEREncoder ()
|
jens@16
|
23 |
- (void) _encode: (id)object;
|
jens@16
|
24 |
@property (retain) NSError *error;
|
jens@20
|
25 |
|
jens@20
|
26 |
/* Forces use of PrintableString tag for ASCII strings that contain characters not valid
|
jens@20
|
27 |
for that encoding (notably '@'). Provided to get byte-for-byte compatibility with certs
|
jens@20
|
28 |
generated by CDSA, for test cases that check this. */
|
jens@19
|
29 |
@property BOOL _forcePrintableStrings;
|
jens@16
|
30 |
@end
|
jens@16
|
31 |
|
jens@16
|
32 |
|
jens@16
|
33 |
@implementation MYDEREncoder
|
jens@16
|
34 |
|
jens@16
|
35 |
|
jens@16
|
36 |
- (id) initWithRootObject: (id)rootObject
|
jens@16
|
37 |
{
|
jens@16
|
38 |
self = [super init];
|
jens@16
|
39 |
if (self != nil) {
|
jens@16
|
40 |
_rootObject = [rootObject retain];
|
jens@16
|
41 |
}
|
jens@16
|
42 |
return self;
|
jens@16
|
43 |
}
|
jens@16
|
44 |
|
jens@16
|
45 |
+ (NSData*) encodeRootObject: (id)rootObject error: (NSError**)outError {
|
jens@16
|
46 |
MYDEREncoder *encoder = [[self alloc] initWithRootObject: rootObject];
|
jens@16
|
47 |
NSData *output = [encoder.output copy];
|
jens@16
|
48 |
if (outError) *outError = [[encoder.error retain] autorelease];
|
jens@16
|
49 |
[encoder release];
|
jens@16
|
50 |
return [output autorelease];
|
jens@16
|
51 |
}
|
jens@16
|
52 |
|
jens@16
|
53 |
- (void) dealloc
|
jens@16
|
54 |
{
|
jens@16
|
55 |
[_rootObject release];
|
jens@16
|
56 |
[_output release];
|
jens@19
|
57 |
[_error release];
|
jens@16
|
58 |
[super dealloc];
|
jens@16
|
59 |
}
|
jens@16
|
60 |
|
jens@19
|
61 |
- (id) copyWithZone: (NSZone*)zone {
|
jens@19
|
62 |
MYDEREncoder *copy = [[[self class] alloc] init];
|
jens@19
|
63 |
copy->_forcePrintableStrings = _forcePrintableStrings;
|
jens@19
|
64 |
return copy;
|
jens@19
|
65 |
}
|
jens@16
|
66 |
|
jens@16
|
67 |
|
jens@16
|
68 |
static unsigned sizeOfUnsignedInt (UInt64 n) {
|
jens@16
|
69 |
unsigned bytes = 0;
|
jens@16
|
70 |
for (; n; n >>= 8)
|
jens@16
|
71 |
bytes++;
|
jens@16
|
72 |
return bytes;
|
jens@16
|
73 |
}
|
jens@16
|
74 |
|
jens@16
|
75 |
static unsigned encodeUnsignedInt (UInt64 n, UInt8 buf[], BOOL padHighBit) {
|
jens@16
|
76 |
unsigned size = MAX(1U, sizeOfUnsignedInt(n));
|
jens@16
|
77 |
UInt64 bigEndian = NSSwapHostLongLongToBig(n);
|
jens@16
|
78 |
const UInt8* src = (UInt8*)&bigEndian + (8-size);
|
jens@16
|
79 |
UInt8 *dst = &buf[0];
|
jens@16
|
80 |
if (padHighBit && (*src & 0x80)) {
|
jens@16
|
81 |
*dst++ = 0;
|
jens@16
|
82 |
size++;
|
jens@16
|
83 |
}
|
jens@16
|
84 |
memcpy(dst, src, size);
|
jens@16
|
85 |
return size;
|
jens@16
|
86 |
}
|
jens@16
|
87 |
|
jens@16
|
88 |
static unsigned encodeSignedInt (SInt64 n, UInt8 buf[]) {
|
jens@16
|
89 |
if (n >= 0)
|
jens@16
|
90 |
return encodeUnsignedInt(n, buf, YES);
|
jens@16
|
91 |
else {
|
jens@16
|
92 |
unsigned size = MAX(1U, sizeOfUnsignedInt(~n));
|
jens@16
|
93 |
UInt64 bigEndian = NSSwapHostLongLongToBig(n);
|
jens@16
|
94 |
const UInt8* src = (UInt8*)&bigEndian + (8-size);
|
jens@16
|
95 |
UInt8 *dst = &buf[0];
|
jens@16
|
96 |
if (!(*src & 0x80)) {
|
jens@16
|
97 |
*dst++ = 0xFF;
|
jens@16
|
98 |
size++;
|
jens@16
|
99 |
}
|
jens@16
|
100 |
memcpy(dst, src, size);
|
jens@16
|
101 |
return size;
|
jens@16
|
102 |
}
|
jens@16
|
103 |
}
|
jens@16
|
104 |
|
jens@16
|
105 |
|
jens@16
|
106 |
- (void) _writeTag: (unsigned)tag
|
jens@16
|
107 |
class: (unsigned)tagClass
|
jens@16
|
108 |
constructed: (BOOL) constructed
|
jens@16
|
109 |
length: (size_t)length
|
jens@16
|
110 |
{
|
jens@16
|
111 |
struct {
|
jens@16
|
112 |
unsigned tag :5;
|
jens@16
|
113 |
unsigned isConstructed :1;
|
jens@16
|
114 |
unsigned tagClass :2;
|
jens@16
|
115 |
unsigned length :7;
|
jens@16
|
116 |
unsigned isLengthLong :1;
|
jens@16
|
117 |
UInt8 extraLength[9];
|
jens@16
|
118 |
} header;
|
jens@16
|
119 |
size_t headerSize = 2;
|
jens@16
|
120 |
|
jens@16
|
121 |
header.tag = tag;
|
jens@16
|
122 |
header.isConstructed = constructed;
|
jens@16
|
123 |
header.tagClass = tagClass;
|
jens@16
|
124 |
if (length < 128) {
|
jens@16
|
125 |
header.isLengthLong = NO;
|
jens@16
|
126 |
header.length = length;
|
jens@16
|
127 |
} else {
|
jens@16
|
128 |
header.isLengthLong = YES;
|
jens@16
|
129 |
header.length = encodeUnsignedInt(length, header.extraLength, NO);
|
jens@16
|
130 |
headerSize += header.length;
|
jens@16
|
131 |
}
|
jens@16
|
132 |
[_output appendBytes: &header length: headerSize];
|
jens@16
|
133 |
}
|
jens@16
|
134 |
|
jens@16
|
135 |
- (void) _writeTag: (unsigned)tag
|
jens@16
|
136 |
class: (unsigned)tagClass
|
jens@16
|
137 |
constructed: (BOOL) constructed
|
jens@16
|
138 |
bytes: (const void*)bytes
|
jens@16
|
139 |
length: (size_t)length
|
jens@16
|
140 |
{
|
jens@16
|
141 |
[self _writeTag: tag class: tagClass constructed: constructed length: length];
|
jens@16
|
142 |
[_output appendBytes: bytes length: length];
|
jens@16
|
143 |
}
|
jens@16
|
144 |
|
jens@16
|
145 |
- (void) _writeTag: (unsigned)tag
|
jens@16
|
146 |
class: (unsigned)tagClass
|
jens@16
|
147 |
constructed: (BOOL) constructed
|
jens@16
|
148 |
data: (NSData*)data
|
jens@16
|
149 |
{
|
jens@16
|
150 |
Assert(data);
|
jens@16
|
151 |
[self _writeTag: tag class: tagClass constructed: constructed bytes: data.bytes length: data.length];
|
jens@16
|
152 |
}
|
jens@16
|
153 |
|
jens@16
|
154 |
|
jens@16
|
155 |
- (void) _encodeNumber: (NSNumber*)number {
|
jens@16
|
156 |
// Special-case detection of booleans by pointer equality, because otherwise they appear
|
jens@16
|
157 |
// identical to 0 and 1:
|
jens@16
|
158 |
if (number==$true || number==$false) {
|
jens@16
|
159 |
UInt8 value = number==$true ?0xFF :0x00;
|
jens@16
|
160 |
[self _writeTag: 1 class: 0 constructed: NO bytes: &value length: 1];
|
jens@16
|
161 |
return;
|
jens@16
|
162 |
}
|
jens@16
|
163 |
|
jens@16
|
164 |
const char *type = number.objCType;
|
jens@16
|
165 |
if (strlen(type) == 1) {
|
jens@16
|
166 |
switch(type[0]) {
|
jens@16
|
167 |
case 'c':
|
jens@16
|
168 |
case 'i':
|
jens@16
|
169 |
case 's':
|
jens@16
|
170 |
case 'l':
|
jens@16
|
171 |
case 'q':
|
jens@16
|
172 |
{ // Signed integers:
|
jens@16
|
173 |
UInt8 buf[9];
|
jens@16
|
174 |
size_t size = encodeSignedInt(number.longLongValue, buf);
|
jens@16
|
175 |
[self _writeTag: 2 class: 0 constructed: NO bytes: buf length: size];
|
jens@16
|
176 |
return;
|
jens@16
|
177 |
}
|
jens@16
|
178 |
case 'C':
|
jens@16
|
179 |
case 'I':
|
jens@16
|
180 |
case 'S':
|
jens@16
|
181 |
case 'L':
|
jens@16
|
182 |
case 'Q':
|
jens@16
|
183 |
{ // Unsigned integers:
|
jens@16
|
184 |
UInt8 buf[9];
|
jens@16
|
185 |
size_t size = encodeUnsignedInt(number.unsignedLongLongValue, buf, YES);
|
jens@16
|
186 |
[self _writeTag: 2 class: 0 constructed: NO bytes: buf length: size];
|
jens@16
|
187 |
return;
|
jens@16
|
188 |
}
|
jens@16
|
189 |
case 'B':
|
jens@16
|
190 |
{ // bool
|
jens@16
|
191 |
UInt8 value = number.boolValue ?0xFF :0x00;
|
jens@16
|
192 |
[self _writeTag: 1 class: 0 constructed: NO bytes: &value length: 1];
|
jens@16
|
193 |
return;
|
jens@16
|
194 |
}
|
jens@16
|
195 |
}
|
jens@16
|
196 |
}
|
jens@16
|
197 |
[NSException raise: MYDEREncoderException format: @"Can't DER-encode value %@ (typecode=%s)", number,type];
|
jens@16
|
198 |
}
|
jens@16
|
199 |
|
jens@16
|
200 |
|
jens@16
|
201 |
- (void) _encodeString: (NSString*)string {
|
jens@19
|
202 |
static NSMutableCharacterSet *kNotPrintableCharSet;
|
jens@19
|
203 |
if (!kNotPrintableCharSet) {
|
jens@19
|
204 |
kNotPrintableCharSet = [[NSMutableCharacterSet characterSetWithCharactersInString: @" '()+,-./:=?"] retain];
|
jens@19
|
205 |
[kNotPrintableCharSet formUnionWithCharacterSet: [NSCharacterSet alphanumericCharacterSet]];
|
jens@19
|
206 |
[kNotPrintableCharSet invert];
|
jens@19
|
207 |
}
|
jens@16
|
208 |
NSData *data = [string dataUsingEncoding: NSASCIIStringEncoding];
|
jens@19
|
209 |
if (data) {
|
jens@19
|
210 |
unsigned tag = 19; // printablestring (a silly arbitrary subset of ASCII defined by ASN.1)
|
jens@19
|
211 |
if (!_forcePrintableStrings && [string rangeOfCharacterFromSet: kNotPrintableCharSet].length > 0)
|
jens@19
|
212 |
tag = 20; // IA5string (full 7-bit ASCII)
|
jens@19
|
213 |
[self _writeTag: tag class: 0 constructed: NO data: data];
|
jens@19
|
214 |
} else {
|
jens@19
|
215 |
// fall back to UTF-8:
|
jens@16
|
216 |
[self _writeTag: 12 class: 0 constructed: NO data: [string dataUsingEncoding: NSUTF8StringEncoding]];
|
jens@19
|
217 |
}
|
jens@16
|
218 |
}
|
jens@16
|
219 |
|
jens@16
|
220 |
|
jens@16
|
221 |
- (void) _encodeBitString: (MYBitString*)bitString {
|
jens@16
|
222 |
NSUInteger bitCount = bitString.bitCount;
|
jens@16
|
223 |
[self _writeTag: 3 class: 0 constructed: NO length: 1 + (bitCount/8)];
|
jens@16
|
224 |
UInt8 unused = (8 - (bitCount % 8)) % 8;
|
jens@16
|
225 |
[_output appendBytes: &unused length: 1];
|
jens@16
|
226 |
[_output appendBytes: bitString.bits.bytes length: bitCount/8];
|
jens@16
|
227 |
}
|
jens@16
|
228 |
|
jens@16
|
229 |
- (void) _encodeDate: (NSDate*)date {
|
jens@16
|
230 |
NSString *dateStr = [MYBERGeneralizedTimeFormatter() stringFromDate: date];
|
jens@16
|
231 |
[self _writeTag: 24 class: 0 constructed: NO data: [dateStr dataUsingEncoding: NSASCIIStringEncoding]];
|
jens@16
|
232 |
}
|
jens@16
|
233 |
|
jens@16
|
234 |
|
jens@16
|
235 |
- (void) _encodeCollection: (id)collection tag: (unsigned)tag class: (unsigned)tagClass {
|
jens@19
|
236 |
MYDEREncoder *subEncoder = [self copy];
|
jens@16
|
237 |
for (id object in collection)
|
jens@16
|
238 |
[subEncoder _encode: object];
|
jens@16
|
239 |
[self _writeTag: tag class: tagClass constructed: YES data: subEncoder.output];
|
jens@16
|
240 |
[subEncoder release];
|
jens@16
|
241 |
}
|
jens@16
|
242 |
|
jens@16
|
243 |
|
jens@16
|
244 |
- (void) _encode: (id)object {
|
jens@16
|
245 |
if (!_output)
|
jens@16
|
246 |
_output = [[NSMutableData alloc] initWithCapacity: 1024];
|
jens@16
|
247 |
if ([object isKindOfClass: [NSNumber class]]) {
|
jens@16
|
248 |
[self _encodeNumber: object];
|
jens@16
|
249 |
} else if ([object isKindOfClass: [NSData class]]) {
|
jens@16
|
250 |
[self _writeTag: 4 class: 0 constructed: NO data: object];
|
jens@16
|
251 |
} else if ([object isKindOfClass: [MYBitString class]]) {
|
jens@16
|
252 |
[self _encodeBitString: object];
|
jens@16
|
253 |
} else if ([object isKindOfClass: [NSString class]]) {
|
jens@16
|
254 |
[self _encodeString: object];
|
jens@16
|
255 |
} else if ([object isKindOfClass: [NSDate class]]) {
|
jens@16
|
256 |
[self _encodeDate: object];
|
jens@16
|
257 |
} else if ([object isKindOfClass: [NSNull class]]) {
|
jens@16
|
258 |
[self _writeTag: 5 class: 0 constructed: NO bytes: NULL length: 0];
|
jens@16
|
259 |
} else if ([object isKindOfClass: [NSArray class]]) {
|
jens@16
|
260 |
[self _encodeCollection: object tag: 16 class: 0];
|
jens@16
|
261 |
} else if ([object isKindOfClass: [NSSet class]]) {
|
jens@16
|
262 |
[self _encodeCollection: object tag: 17 class: 0];
|
jens@16
|
263 |
} else if ([object isKindOfClass: [MYOID class]]) {
|
jens@16
|
264 |
[self _writeTag: 6 class: 0 constructed: NO data: [object DEREncoding]];
|
jens@16
|
265 |
} else if ([object isKindOfClass: [MYASN1Object class]]) {
|
jens@16
|
266 |
MYASN1Object *asn = object;
|
jens@16
|
267 |
if (asn.components)
|
jens@16
|
268 |
[self _encodeCollection: asn.components tag: asn.tag class: asn.tagClass];
|
jens@16
|
269 |
else
|
jens@16
|
270 |
[self _writeTag: asn.tag
|
jens@16
|
271 |
class: asn.tagClass
|
jens@16
|
272 |
constructed: asn.constructed
|
jens@16
|
273 |
data: asn.value];
|
jens@16
|
274 |
} else {
|
jens@16
|
275 |
[NSException raise: MYDEREncoderException format: @"Can't DER-encode a %@", [object class]];
|
jens@16
|
276 |
}
|
jens@16
|
277 |
}
|
jens@16
|
278 |
|
jens@16
|
279 |
|
jens@16
|
280 |
- (NSData*) output {
|
jens@16
|
281 |
if (!_output && !_error) {
|
jens@16
|
282 |
@try{
|
jens@16
|
283 |
[self _encode: _rootObject];
|
jens@16
|
284 |
}@catch (NSException *x) {
|
jens@16
|
285 |
if ($equal(x.name, MYDEREncoderException)) {
|
jens@16
|
286 |
self.error = MYError(2,MYASN1ErrorDomain, @"%@", x.reason);
|
jens@16
|
287 |
return nil;
|
jens@16
|
288 |
} else
|
jens@16
|
289 |
@throw(x);
|
jens@16
|
290 |
}
|
jens@16
|
291 |
}
|
jens@16
|
292 |
return _output;
|
jens@16
|
293 |
}
|
jens@16
|
294 |
|
jens@19
|
295 |
@synthesize error=_error, _forcePrintableStrings;
|
jens@16
|
296 |
|
jens@16
|
297 |
|
jens@16
|
298 |
@end
|
jens@16
|
299 |
|
jens@16
|
300 |
|
jens@16
|
301 |
|
jens@16
|
302 |
#define $data(BYTES...) ({const uint8_t bytes[] = {BYTES}; [NSData dataWithBytes: bytes length: sizeof(bytes)];})
|
jens@16
|
303 |
|
jens@16
|
304 |
TestCase(DEREncoder) {
|
jens@16
|
305 |
CAssertEqual([MYDEREncoder encodeRootObject: [NSNull null] error: nil],
|
jens@16
|
306 |
$data(0x05, 0x00));
|
jens@16
|
307 |
CAssertEqual([MYDEREncoder encodeRootObject: $true error: nil],
|
jens@16
|
308 |
$data(0x01, 0x01, 0xFF));
|
jens@16
|
309 |
CAssertEqual([MYDEREncoder encodeRootObject: $false error: nil],
|
jens@16
|
310 |
$data(0x01, 0x01, 0x00));
|
jens@16
|
311 |
|
jens@16
|
312 |
// Integers:
|
jens@16
|
313 |
CAssertEqual([MYDEREncoder encodeRootObject: $object(0) error: nil],
|
jens@16
|
314 |
$data(0x02, 0x01, 0x00));
|
jens@16
|
315 |
CAssertEqual([MYDEREncoder encodeRootObject: $object(1) error: nil],
|
jens@16
|
316 |
$data(0x02, 0x01, 0x01));
|
jens@16
|
317 |
CAssertEqual([MYDEREncoder encodeRootObject: $object(-1) error: nil],
|
jens@16
|
318 |
$data(0x02, 0x01, 0xFF));
|
jens@16
|
319 |
CAssertEqual([MYDEREncoder encodeRootObject: $object(72) error: nil],
|
jens@16
|
320 |
$data(0x02, 0x01, 0x48));
|
jens@16
|
321 |
CAssertEqual([MYDEREncoder encodeRootObject: $object(-128) error: nil],
|
jens@16
|
322 |
$data(0x02, 0x01, 0x80));
|
jens@16
|
323 |
CAssertEqual([MYDEREncoder encodeRootObject: $object(128) error: nil],
|
jens@16
|
324 |
$data(0x02, 0x02, 0x00, 0x80));
|
jens@16
|
325 |
CAssertEqual([MYDEREncoder encodeRootObject: $object(255) error: nil],
|
jens@16
|
326 |
$data(0x02, 0x02, 0x00, 0xFF));
|
jens@16
|
327 |
CAssertEqual([MYDEREncoder encodeRootObject: $object(-256) error: nil],
|
jens@16
|
328 |
$data(0x02, 0x02, 0xFF, 0x00));
|
jens@16
|
329 |
CAssertEqual([MYDEREncoder encodeRootObject: $object(12345) error: nil],
|
jens@16
|
330 |
$data(0x02, 0x02, 0x30,0x39));
|
jens@16
|
331 |
CAssertEqual([MYDEREncoder encodeRootObject: $object(-12345) error: nil],
|
jens@16
|
332 |
$data(0x02, 0x02, 0xCF, 0xC7));
|
jens@16
|
333 |
CAssertEqual([MYDEREncoder encodeRootObject: $object(123456789) error: nil],
|
jens@16
|
334 |
$data(0x02, 0x04, 0x07, 0x5B, 0xCD, 0x15));
|
jens@16
|
335 |
CAssertEqual([MYDEREncoder encodeRootObject: $object(-123456789) error: nil],
|
jens@16
|
336 |
$data(0x02, 0x04, 0xF8, 0xA4, 0x32, 0xEB));
|
jens@16
|
337 |
CAssertEqual([MYDEREncoder encodeRootObject: $object(-123456789) error: nil],
|
jens@16
|
338 |
$data(0x02, 0x04, 0xF8, 0xA4, 0x32, 0xEB));
|
jens@16
|
339 |
|
jens@16
|
340 |
// Strings:
|
jens@16
|
341 |
CAssertEqual([MYDEREncoder encodeRootObject: @"hello" error: nil],
|
jens@16
|
342 |
$data(0x13, 0x05, 'h', 'e', 'l', 'l', 'o'));
|
jens@16
|
343 |
CAssertEqual([MYDEREncoder encodeRootObject: @"thérè" error: nil],
|
jens@16
|
344 |
$data(0x0C, 0x07, 't', 'h', 0xC3, 0xA9, 'r', 0xC3, 0xA8));
|
jens@16
|
345 |
|
jens@16
|
346 |
// Dates:
|
jens@16
|
347 |
CAssertEqual([MYDEREncoder encodeRootObject: [NSDate dateWithTimeIntervalSinceReferenceDate: 265336576]
|
jens@16
|
348 |
error: nil],
|
jens@16
|
349 |
$data(0x18, 0x0F, '2', '0', '0', '9', '0', '5', '3', '0', '0', '0', '3', '6', '1', '6', 'Z'));
|
jens@16
|
350 |
|
jens@16
|
351 |
// Sequences:
|
jens@16
|
352 |
CAssertEqual([MYDEREncoder encodeRootObject: $array($object(72), $true) error: nil],
|
jens@16
|
353 |
$data(0x30, 0x06, 0x02, 0x01, 0x48, 0x01, 0x01, 0xFF));
|
jens@16
|
354 |
CAssertEqual([MYDEREncoder encodeRootObject: $array( $array($object(72), $true),
|
jens@16
|
355 |
$array($object(72), $true))
|
jens@16
|
356 |
error: nil],
|
jens@16
|
357 |
$data(0x30, 0x10,
|
jens@16
|
358 |
0x30, 0x06, 0x02, 0x01, 0x48, 0x01, 0x01, 0xFF,
|
jens@16
|
359 |
0x30, 0x06, 0x02, 0x01, 0x48, 0x01, 0x01, 0xFF));
|
jens@16
|
360 |
}
|
jens@16
|
361 |
|
jens@16
|
362 |
|
jens@16
|
363 |
TestCase(EncodeCert) {
|
jens@16
|
364 |
NSError *error = nil;
|
jens@21
|
365 |
NSData *cert = [NSData dataWithContentsOfFile: @"../../Tests/selfsigned.cer"];
|
jens@16
|
366 |
id certObjects = MYBERParse(cert,&error);
|
jens@16
|
367 |
CAssertNil(error);
|
jens@16
|
368 |
Log(@"Decoded as:\n%@", [MYASN1Object dump: certObjects]);
|
jens@19
|
369 |
MYDEREncoder *encoder = [[MYDEREncoder alloc] initWithRootObject: certObjects];
|
jens@19
|
370 |
encoder._forcePrintableStrings = YES; // hack for compatibility with the way CDSA writes ASN.1
|
jens@19
|
371 |
NSData *encoded = encoder.output;
|
jens@16
|
372 |
CAssertNil(error);
|
jens@16
|
373 |
id reDecoded = MYBERParse(encoded, &error);
|
jens@16
|
374 |
CAssertNil(error);
|
jens@16
|
375 |
Log(@"Re-decoded as:\n%@", [MYASN1Object dump: reDecoded]);
|
jens@19
|
376 |
[encoded writeToFile: @"../../Tests/selfsigned_reencoded.cer" atomically: YES];
|
jens@16
|
377 |
CAssertEqual(encoded,cert);
|
jens@16
|
378 |
}
|
jens@21
|
379 |
|
jens@21
|
380 |
|
jens@21
|
381 |
|
jens@21
|
382 |
/*
|
jens@21
|
383 |
Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
|
jens@21
|
384 |
|
jens@21
|
385 |
Redistribution and use in source and binary forms, with or without modification, are permitted
|
jens@21
|
386 |
provided that the following conditions are met:
|
jens@21
|
387 |
|
jens@21
|
388 |
* Redistributions of source code must retain the above copyright notice, this list of conditions
|
jens@21
|
389 |
and the following disclaimer.
|
jens@21
|
390 |
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
jens@21
|
391 |
and the following disclaimer in the documentation and/or other materials provided with the
|
jens@21
|
392 |
distribution.
|
jens@21
|
393 |
|
jens@21
|
394 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
jens@21
|
395 |
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
jens@21
|
396 |
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
|
jens@21
|
397 |
BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
jens@21
|
398 |
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
jens@21
|
399 |
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
jens@21
|
400 |
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
jens@21
|
401 |
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
jens@21
|
402 |
*/
|