MYDEREncoder.m
changeset 19 f6c91b9da05b
parent 18 a06e44b9b898
child 20 df9da0f6b358
     1.1 --- a/MYDEREncoder.m	Wed Jun 03 17:22:42 2009 -0700
     1.2 +++ b/MYDEREncoder.m	Thu Jun 04 18:36:30 2009 -0700
     1.3 @@ -19,6 +19,7 @@
     1.4  @interface MYDEREncoder ()
     1.5  - (void) _encode: (id)object;
     1.6  @property (retain) NSError *error;
     1.7 +@property BOOL _forcePrintableStrings;
     1.8  @end
     1.9  
    1.10  
    1.11 @@ -46,9 +47,15 @@
    1.12  {
    1.13      [_rootObject release];
    1.14      [_output release];
    1.15 +    [_error release];
    1.16      [super dealloc];
    1.17  }
    1.18  
    1.19 +- (id) copyWithZone: (NSZone*)zone {
    1.20 +    MYDEREncoder *copy = [[[self class] alloc] init];
    1.21 +    copy->_forcePrintableStrings = _forcePrintableStrings;
    1.22 +    return copy;
    1.23 +}
    1.24  
    1.25  
    1.26  static unsigned sizeOfUnsignedInt (UInt64 n) {
    1.27 @@ -185,11 +192,22 @@
    1.28  
    1.29  
    1.30  - (void) _encodeString: (NSString*)string {
    1.31 +    static NSMutableCharacterSet *kNotPrintableCharSet;
    1.32 +    if (!kNotPrintableCharSet) {
    1.33 +        kNotPrintableCharSet = [[NSMutableCharacterSet characterSetWithCharactersInString: @" '()+,-./:=?"] retain];
    1.34 +        [kNotPrintableCharSet formUnionWithCharacterSet: [NSCharacterSet alphanumericCharacterSet]];
    1.35 +        [kNotPrintableCharSet invert];
    1.36 +    }
    1.37      NSData *data = [string dataUsingEncoding: NSASCIIStringEncoding];
    1.38 -    if (data)
    1.39 -        [self _writeTag: 19 class: 0 constructed: NO data: data];
    1.40 -    else
    1.41 +    if (data) {
    1.42 +        unsigned tag = 19; // printablestring (a silly arbitrary subset of ASCII defined by ASN.1)
    1.43 +        if (!_forcePrintableStrings && [string rangeOfCharacterFromSet: kNotPrintableCharSet].length > 0)
    1.44 +            tag = 20; // IA5string (full 7-bit ASCII)
    1.45 +        [self _writeTag: tag class: 0 constructed: NO data: data];
    1.46 +    } else {
    1.47 +        // fall back to UTF-8:
    1.48          [self _writeTag: 12 class: 0 constructed: NO data: [string dataUsingEncoding: NSUTF8StringEncoding]];
    1.49 +    }
    1.50  }
    1.51  
    1.52  
    1.53 @@ -209,7 +227,7 @@
    1.54  
    1.55  
    1.56  - (void) _encodeCollection: (id)collection tag: (unsigned)tag class: (unsigned)tagClass {
    1.57 -    MYDEREncoder *subEncoder = [[[self class] alloc] init];
    1.58 +    MYDEREncoder *subEncoder = [self copy];
    1.59      for (id object in collection)
    1.60          [subEncoder _encode: object];
    1.61      [self _writeTag: tag class: tagClass constructed: YES data: subEncoder.output];
    1.62 @@ -268,7 +286,7 @@
    1.63      return _output;
    1.64  }
    1.65  
    1.66 -@synthesize error=_error;
    1.67 +@synthesize error=_error, _forcePrintableStrings;
    1.68  
    1.69  
    1.70  @end
    1.71 @@ -342,11 +360,13 @@
    1.72      id certObjects = MYBERParse(cert,&error);
    1.73      CAssertNil(error);
    1.74      Log(@"Decoded as:\n%@", [MYASN1Object dump: certObjects]);
    1.75 -    NSData *encoded = [MYDEREncoder encodeRootObject: certObjects error: &error];
    1.76 +    MYDEREncoder *encoder = [[MYDEREncoder alloc] initWithRootObject: certObjects];
    1.77 +    encoder._forcePrintableStrings = YES;       // hack for compatibility with the way CDSA writes ASN.1
    1.78 +    NSData *encoded = encoder.output;
    1.79      CAssertNil(error);
    1.80      id reDecoded = MYBERParse(encoded, &error);
    1.81      CAssertNil(error);
    1.82      Log(@"Re-decoded as:\n%@", [MYASN1Object dump: reDecoded]);
    1.83 -    [encoded writeToFile: @"../../Tests/iphonedev_reencoded.cer" atomically: YES];
    1.84 +    [encoded writeToFile: @"../../Tests/selfsigned_reencoded.cer" atomically: YES];
    1.85      CAssertEqual(encoded,cert);
    1.86  }