Permalink
Browse files

Added ASN1 BitString support

now separate from data handling so that we can preserve the unused bits info and query individual bits
  • Loading branch information...
1 parent 1328a20 commit d737f7d7100cff70158ad10d552393396817f4c0 @odrobnik odrobnik committed Mar 10, 2013
View
30 Core/Source/DTASN1BitString.h
@@ -0,0 +1,30 @@
+//
+// DTASN1BitString.h
+// DTFoundation
+//
+// Created by Oliver Drobnik on 3/10/13.
+// Copyright (c) 2013 Cocoanetics. All rights reserved.
+//
+
+
+/**
+ Represents a string of bits.
+ */
+@interface DTASN1BitString : NSObject
+
+/**
+ The designated initializer
+ */
+- (id)initWithData:(NSData *)data unusedBits:(NSUInteger)unusedBits;
+
+/**
+ Returns the bit value of the bit at the given index whereas the index is numbering the individual bits.
+ */
+- (BOOL)valueOfBitAtIndex:(NSUInteger)index;
+
+/**
+ The number of bits at the end of the data chunk that are not used
+ */
+@property (nonatomic, assign) NSUInteger unusedBits;
+
+@end
View
82 Core/Source/DTASN1BitString.m
@@ -0,0 +1,82 @@
+//
+// DTASN1BitString.m
+// DTFoundation
+//
+// Created by Oliver Drobnik on 3/10/13.
+// Copyright (c) 2013 Cocoanetics. All rights reserved.
+//
+
+#import "DTASN1BitString.h"
+
+@implementation DTASN1BitString
+{
+ NSUInteger _unusedBits;
+ NSData *_data;
+}
+
+
+- (id)initWithData:(NSData *)data unusedBits:(NSUInteger)unusedBits
+{
+ self = [super init];
+
+ if (self)
+ {
+ _data = [data copy];
+ _unusedBits = unusedBits;
+ }
+
+ return self;
+}
+
+- (NSString *)description
+{
+ unsigned char *b = (unsigned char*) [_data bytes];
+ int size = (int)[_data length];
+ unsigned char byte;
+ int i, j;
+
+ NSMutableString *tmpString = [NSMutableString string];
+
+ for (i=size-1;i>=0;i--)
+ {
+ int octetUnusedBits = 0;
+
+ if (i==0)
+ {
+ octetUnusedBits = (int)_unusedBits;
+ }
+
+ for (j=7;j>=octetUnusedBits;j--)
+ {
+ byte = b[i] & (1<<j);
+ byte >>= j;
+ [tmpString appendFormat:@"%u", byte];
+ }
+ }
+
+ return tmpString;
+}
+
+- (BOOL)valueOfBitAtIndex:(NSUInteger)index
+{
+ NSUInteger numberOfBits = [_data length]*8 - _unusedBits;
+
+ if (index>=numberOfBits)
+ {
+ return NO;
+ }
+
+ NSUInteger charIndex = index/8;
+ NSUInteger bitIndexInChar = index%8;
+
+ unsigned char *b = (unsigned char*) [_data bytes];
+ unsigned char byte = b[charIndex];
+
+ return (((byte >> (7-bitIndexInChar))&1) == 1);
+}
+
+#pragma mark - Properties
+
+@synthesize unusedBits = _unusedBits;
+
+@end
View
14 Core/Source/DTASN1Parser.h
@@ -40,7 +40,7 @@ typedef enum
} DTASN1Type;
-@class DTASN1Parser;
+@class DTASN1Parser, DTASN1BitString;
/** The DTASN1ParserDelegate protocol defines the optional methods implemented by delegates of DTASN1Parser objects.
*/
@@ -140,16 +140,24 @@ typedef enum
- (void)parser:(DTASN1Parser *)parser foundString:(NSString *)string;
/**
- Sent by a parser object to provide its delegate with the data encoded in the current element.
+ Sent by a parser object to provide its delegate with the octet string encoded in the current element.
- Both bit strings and octet strings are provided via this method. Also Integer data that is longer than 32 bits is provided this way.
+ Integer data that is longer than 32 bits is also provided this way.
@param parser A parser object.
@param data A data object representing the contents of the current element.
*/
- (void)parser:(DTASN1Parser *)parser foundData:(NSData *)data;
/**
+ Sent by a parser object to provide its delegate with the bit string encoded in the current element.
+
+ @param parser A parser object.
+ @param bitString A bit string object representing the contents of the current element.
+ */
+- (void)parser:(DTASN1Parser *)parser foundBitString:(DTASN1BitString *)bitString;
+
+/**
Sent by a parser object to provide its delegate with number values encoded in the current element.
Note that number values that are longer than supported by the system are provided as Data instead.
View
20 Core/Source/DTASN1Parser.m
@@ -7,6 +7,7 @@
//
#import "DTASN1Parser.h"
+#import "DTASN1BitString.h"
@implementation DTASN1Parser
{
@@ -31,6 +32,7 @@ @implementation DTASN1Parser
unsigned int delegateSupportsString:1;
unsigned int delegateSupportsInteger:1;
unsigned int delegateSupportsData:1;
+ unsigned int delegateSupportsBitString:1;
unsigned int delegateSupportsNumber:1;
unsigned int delegateSupportsNull:1;
unsigned int delegateSupportsError:1;
@@ -212,23 +214,18 @@ - (BOOL)_parseValueWithTag:(NSUInteger)tag dataRange:(NSRange)dataRange
case DTASN1TypeBitString:
{
- if (_delegateFlags.delegateSupportsData)
+ if (_delegateFlags.delegateSupportsBitString)
{
char *buffer = malloc(dataRange.length);
[_data getBytes:buffer range:dataRange];
// primitive encoding
NSUInteger unusedBits = buffer[0];
- if (unusedBits>0)
- {
- [self _parseErrorEncountered:@"Encountered bit string with unused bits > 0, not implemented"];
- free(buffer);
- return NO;
- }
-
NSData *data = [NSData dataWithBytes:buffer+1 length:dataRange.length-1];
- [_delegate parser:self foundData:data];
+ DTASN1BitString *bitstring = [[DTASN1BitString alloc] initWithData:data unusedBits:unusedBits];
+
+ [_delegate parser:self foundBitString:bitstring];
free(buffer);
}
@@ -579,6 +576,11 @@ - (void)setDelegate:(__unsafe_unretained id<DTASN1ParserDelegate>)delegate;
_delegateFlags.delegateSupportsData = YES;
}
+ if ([_delegate respondsToSelector:@selector(parser:foundBitString:)])
+ {
+ _delegateFlags.delegateSupportsBitString = YES;
+ }
+
if ([_delegate respondsToSelector:@selector(parser:foundNumber:)])
{
_delegateFlags.delegateSupportsNumber = YES;
View
6 Core/Source/DTASN1Serialization.m
@@ -139,10 +139,14 @@ - (void)parser:(DTASN1Parser *)parser foundData:(NSData *)data
[self _addObjectToCurrentContainer:data];
}
+- (void)parser:(DTASN1Parser *)parser foundBitString:(DTASN1BitString *)bitString
+{
+ [self _addObjectToCurrentContainer:bitString];
+}
+
- (void)parser:(DTASN1Parser *)parser foundNumber:(NSNumber *)number
{
[self _addObjectToCurrentContainer:number];
}
-
@end
View
16 DTFoundation.xcodeproj/project.pbxproj
@@ -176,6 +176,12 @@
A779A38816EB850D001BD056 /* DTASN1Serialization.m in Sources */ = {isa = PBXBuildFile; fileRef = A779A38316EB850D001BD056 /* DTASN1Serialization.m */; };
A779A38916EB850D001BD056 /* DTASN1Serialization.m in Sources */ = {isa = PBXBuildFile; fileRef = A779A38316EB850D001BD056 /* DTASN1Serialization.m */; };
A779A38C16EB8BFB001BD056 /* DTASN1SerializationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A779A38B16EB8BFB001BD056 /* DTASN1SerializationTest.m */; };
+ A779A39F16EC816A001BD056 /* DTASN1BitString.h in Headers */ = {isa = PBXBuildFile; fileRef = A779A39D16EC8169001BD056 /* DTASN1BitString.h */; };
+ A779A3A016EC816A001BD056 /* DTASN1BitString.h in Headers */ = {isa = PBXBuildFile; fileRef = A779A39D16EC8169001BD056 /* DTASN1BitString.h */; };
+ A779A3A116EC816A001BD056 /* DTASN1BitString.h in Headers */ = {isa = PBXBuildFile; fileRef = A779A39D16EC8169001BD056 /* DTASN1BitString.h */; };
+ A779A3A216EC816A001BD056 /* DTASN1BitString.m in Sources */ = {isa = PBXBuildFile; fileRef = A779A39E16EC8169001BD056 /* DTASN1BitString.m */; };
+ A779A3A316EC816A001BD056 /* DTASN1BitString.m in Sources */ = {isa = PBXBuildFile; fileRef = A779A39E16EC8169001BD056 /* DTASN1BitString.m */; };
+ A779A3A416EC816A001BD056 /* DTASN1BitString.m in Sources */ = {isa = PBXBuildFile; fileRef = A779A39E16EC8169001BD056 /* DTASN1BitString.m */; };
A77D5BFA16E4961A00A45C28 /* DTBase64Coding.h in Headers */ = {isa = PBXBuildFile; fileRef = A77D5BF816E4961A00A45C28 /* DTBase64Coding.h */; };
A77D5BFB16E4961A00A45C28 /* DTBase64Coding.h in Headers */ = {isa = PBXBuildFile; fileRef = A77D5BF816E4961A00A45C28 /* DTBase64Coding.h */; };
A77D5BFC16E4961A00A45C28 /* DTBase64Coding.h in Headers */ = {isa = PBXBuildFile; fileRef = A77D5BF816E4961A00A45C28 /* DTBase64Coding.h */; };
@@ -452,6 +458,8 @@
A779A38316EB850D001BD056 /* DTASN1Serialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTASN1Serialization.m; sourceTree = "<group>"; };
A779A38A16EB8BFB001BD056 /* DTASN1SerializationTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTASN1SerializationTest.h; sourceTree = "<group>"; };
A779A38B16EB8BFB001BD056 /* DTASN1SerializationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTASN1SerializationTest.m; sourceTree = "<group>"; };
+ A779A39D16EC8169001BD056 /* DTASN1BitString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTASN1BitString.h; sourceTree = "<group>"; };
+ A779A39E16EC8169001BD056 /* DTASN1BitString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTASN1BitString.m; sourceTree = "<group>"; };
A77D5BF816E4961A00A45C28 /* DTBase64Coding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTBase64Coding.h; sourceTree = "<group>"; };
A77D5BF916E4961A00A45C28 /* DTBase64Coding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTBase64Coding.m; sourceTree = "<group>"; };
A77D5C0016E4B1D300A45C28 /* DTBase64CodingTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTBase64CodingTest.h; sourceTree = "<group>"; };
@@ -862,6 +870,8 @@
isa = PBXGroup;
children = (
A7556F63162EEF6700A69F63 /* DTScripting */,
+ A779A39D16EC8169001BD056 /* DTASN1BitString.h */,
+ A779A39E16EC8169001BD056 /* DTASN1BitString.m */,
A760F52A14F24B9F00AD1B0E /* DTASN1Parser.h */,
A760F52B14F24B9F00AD1B0E /* DTASN1Parser.m */,
A779A38216EB850D001BD056 /* DTASN1Serialization.h */,
@@ -1033,6 +1043,7 @@
A70ECD6D16E0A389004E9623 /* UIColor+DTDebug.h in Headers */,
A77D5BFB16E4961A00A45C28 /* DTBase64Coding.h in Headers */,
A779A38516EB850D001BD056 /* DTASN1Serialization.h in Headers */,
+ A779A3A016EC816A001BD056 /* DTASN1BitString.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1058,6 +1069,7 @@
A777831116CA47F60048BED1 /* DTObjectBlockExecutor.h in Headers */,
A77D5BFC16E4961A00A45C28 /* DTBase64Coding.h in Headers */,
A779A38616EB850D001BD056 /* DTASN1Serialization.h in Headers */,
+ A779A3A116EC816A001BD056 /* DTASN1BitString.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1112,6 +1124,7 @@
A70ECD6C16E0A389004E9623 /* UIColor+DTDebug.h in Headers */,
A77D5BFA16E4961A00A45C28 /* DTBase64Coding.h in Headers */,
A779A38416EB850D001BD056 /* DTASN1Serialization.h in Headers */,
+ A779A39F16EC816A001BD056 /* DTASN1BitString.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1461,6 +1474,7 @@
A70ECD6F16E0A389004E9623 /* UIColor+DTDebug.m in Sources */,
A77D5BFE16E4961A00A45C28 /* DTBase64Coding.m in Sources */,
A779A38816EB850D001BD056 /* DTASN1Serialization.m in Sources */,
+ A779A3A316EC816A001BD056 /* DTASN1BitString.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1494,6 +1508,7 @@
A777831516CA49C80048BED1 /* NSObject+DTRuntime.m in Sources */,
A77D5BFF16E4961A00A45C28 /* DTBase64Coding.m in Sources */,
A779A38916EB850D001BD056 /* DTASN1Serialization.m in Sources */,
+ A779A3A416EC816A001BD056 /* DTASN1BitString.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1549,6 +1564,7 @@
A70ECD6E16E0A389004E9623 /* UIColor+DTDebug.m in Sources */,
A77D5BFD16E4961A00A45C28 /* DTBase64Coding.m in Sources */,
A779A38716EB850D001BD056 /* DTASN1Serialization.m in Sources */,
+ A779A3A216EC816A001BD056 /* DTASN1BitString.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
15 Test/Source/DTASN1SerializationTest.m
@@ -19,7 +19,20 @@ - (void)testDeserialization
NSData *data = [DTBase64Coding dataByDecodingString:string];
id object = [DTASN1Serialization objectWithData:data];
- NSLog(@"%@", object);
+
+ STAssertNotNil(object, @"Should be able to decode as array");
+ STAssertTrue([object isKindOfClass:[NSArray class]], @"Decoded object should be an array");
+}
+
+- (void)testBitString
+{
+ NSString *string = @"AwIFoA==";
+ NSData *data = [DTBase64Coding dataByDecodingString:string];
+
+ id object = [DTASN1Serialization objectWithData:data];
+
+ NSString *asString = [object description];
+ STAssertTrue([@"101" isEqualToString:asString], @"Result should be 101");
}
@end

0 comments on commit d737f7d

Please sign in to comment.