MYOID.m
author Jens Alfke <jens@mooseyard.com>
Thu Jun 04 18:36:30 2009 -0700 (2009-06-04)
changeset 19 f6c91b9da05b
child 21 2c300b15b381
permissions -rw-r--r--
Whew! MYParsedCertificate can now generate certs from scratch. Also added improvements and fixes to the BER/DER codecs.
     1 //
     2 //  MYOID.m
     3 //  MYCrypto
     4 //
     5 //  Created by Jens Alfke on 5/28/09.
     6 //  Copyright 2009 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #import "MYOID.h"
    10 
    11 
    12 @implementation MYOID
    13 
    14 
    15 - (id) initWithComponents: (const UInt32*)components count: (unsigned)count
    16 {
    17     self = [super init];
    18     if (self != nil) {
    19         _data = [[NSData alloc] initWithBytes: components length: count*sizeof(UInt32)];
    20     }
    21     return self;
    22 }
    23 
    24 - (id) initWithBEREncoding: (NSData*)encoding
    25 {
    26     self = [super init];
    27     if (self != nil) {
    28         size_t len = encoding.length;
    29         const UInt8 *src = encoding.bytes;
    30         const UInt8 *end = src+len;
    31         NSMutableData *data = [NSMutableData dataWithLength: (len+1)*sizeof(UInt32)];
    32         UInt32* dst = data.mutableBytes;
    33         
    34         if (len >= 2) {
    35             *dst++ = *src / 40;
    36             *dst++ = *src % 40;
    37             src++; 
    38         }
    39         while (src < end) {
    40             UInt32 component = 0;
    41             UInt8 byte;
    42             do{
    43                 if (src >= end) {
    44                     [self release];
    45                     return nil;
    46                 }
    47                 byte = *src++;
    48                 component = (component << 7) | (byte & 0x7F);
    49             }while (byte & 0x80);
    50             *dst++ = component;
    51         }
    52         data.length = (UInt8*)dst - (UInt8*)data.mutableBytes;
    53         _data = [data copy];
    54     }
    55     return self;
    56 }
    57 
    58 + (MYOID*) OIDWithEncoding: (NSData*)encoding {
    59     return [[[self alloc] initWithBEREncoding: encoding] autorelease];
    60 }
    61 
    62 
    63 - (id) copyWithZone: (NSZone*)zone {
    64     return [self retain];
    65 }
    66 
    67 - (void) dealloc
    68 {
    69     [_data release];
    70     [super dealloc];
    71 }
    72 
    73 
    74 - (NSString*) description {
    75     NSMutableString *desc = [NSMutableString stringWithString: @"{"];
    76     const UInt32* components = self.components;
    77     unsigned count = self.componentCount;
    78     for (unsigned i=0; i<count; i++) {
    79         if (i>0)
    80             [desc appendString: @" "];
    81         [desc appendFormat: @"%u", components[i]];
    82     }
    83     [desc appendString: @"}"];
    84     return desc;
    85 }
    86 
    87 
    88 - (NSData*) componentData       {return _data;}
    89 - (const UInt32*) components    {return (const UInt32*)_data.bytes;}
    90 - (unsigned) componentCount     {return _data.length / sizeof(UInt32);}
    91 
    92 - (NSUInteger)hash {
    93     return _data.hash;
    94 }
    95 
    96 - (BOOL)isEqual:(id)object {
    97     return [object isKindOfClass: [MYOID class]] && [_data isEqual: [object componentData]];
    98 }
    99 
   100 
   101 - (NSData*) DEREncoding {
   102     unsigned count = self.componentCount;
   103     UInt8 encoding[5*count]; // worst-case size
   104     const UInt32 *src=self.components, *end=src+count;
   105     UInt8 *dst = encoding;
   106     if (count >= 2 && src[0]<=3 && src[1]<40) {
   107         // Weird collapsing of 1st two components into one byte:
   108         *dst++ = src[0]*40 + src[1];
   109         src += 2;
   110     }
   111     while (src<end) {
   112         UInt32 component = *src++;
   113         // Write the component in 7-bit groups, most significant first:
   114         BOOL any = NO;
   115         for (int shift=28; shift>=0; shift -= 7) {
   116             UInt8 byte = (component >> shift) & 0x7F;
   117             if (byte || any) {
   118                 if (any)
   119                     dst[-1] |= 0x80;
   120                 *dst++ = byte;
   121                 any = YES;
   122             }
   123         }
   124     }
   125     return [NSData dataWithBytes: encoding length: dst-encoding];
   126 }
   127 
   128 
   129 @end
   130 
   131 
   132 
   133 #define $data(BYTES...)    ({const uint8_t bytes[] = {BYTES}; [NSData dataWithBytes: bytes length: sizeof(bytes)];})
   134 
   135 #define $components(INTS...)    ({const UInt32 components[] = {INTS}; components;})
   136 
   137 TestCase(OID) {
   138     CAssertEqual([[MYOID OIDWithEncoding: $data(0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01)] description],
   139                  @"{1 2 840 113549 1 1 1}");
   140     CAssertEqual([[MYOID OIDWithEncoding: $data(0x55,0x04,0x04)] description],
   141                  @"{2 5 4 4}");
   142     CAssertEqual([[MYOID OIDWithEncoding: $data(0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x01)] description],
   143                  @"{1 2 840 113549 1 9 1}");
   144 
   145     CAssertEqual([[[MYOID alloc] initWithComponents: $components(1,2,840,113549,1,1,1) count: 7] description],
   146                  @"{1 2 840 113549 1 1 1}");
   147 
   148     CAssertEqual([[[MYOID alloc] initWithComponents: $components(1,2,840,113549,1,1,1) count: 7] DEREncoding],
   149                  $data(0x2a, 0x86, 0x48, 0x86,  0xf7, 0x0d, 0x01, 0x01,  0x01));
   150     CAssertEqual([[[MYOID alloc] initWithComponents: $components(2,5,4,4) count: 4] DEREncoding],
   151                  $data(0x55,0x04,0x04));
   152 }