Whew! MYParsedCertificate can now generate certs from scratch. Also added improvements and fixes to the BER/DER codecs.
1.1 --- a/MYASN1Object.h Wed Jun 03 17:22:42 2009 -0700
1.2 +++ b/MYASN1Object.h Thu Jun 04 18:36:30 2009 -0700
1.3 @@ -9,8 +9,9 @@
1.4 #import <Foundation/Foundation.h>
1.5
1.6
1.7 -/** A generic ASN.1 data value. The BER parser instantiates these to represent parsed values that
1.8 - it doesn't know how to represent otherwise. */
1.9 +/* A generic ASN.1 data value. The BER parser instantiates these to represent parsed values that
1.10 + it doesn't know how to represent otherwise.
1.11 + This is mostly used internally by MYParsedCertificate. */
1.12 @interface MYASN1Object : NSObject
1.13 {
1.14 @private
1.15 @@ -40,22 +41,26 @@
1.16 @end
1.17
1.18
1.19 -/** An ASN.1 "big" (arbitrary-length) integer.
1.20 - The value contains the bytes of the integer, in big-endian order. */
1.21 +/* An ASN.1 "big" (arbitrary-length) integer.
1.22 + The value contains the bytes of the integer, in big-endian order.
1.23 + This is mostly used internally by MYParsedCertificate. */
1.24 @interface MYASN1BigInteger : MYASN1Object
1.25 @end
1.26
1.27
1.28 -/** An ordered string of bits, as used in ASN.1.
1.29 +/* An ordered string of bits, as used in ASN.1.
1.30 This differs from NSData in that it need not occupy a whole number of bytes;
1.31 - that is, the number of bits need not be a multiple of 8. */
1.32 + that is, the number of bits need not be a multiple of 8.
1.33 + This is mostly used internally by MYParsedCertificate. */
1.34 @interface MYBitString : NSObject
1.35 {
1.36 + @private
1.37 NSData *_bits;
1.38 NSUInteger _bitCount;
1.39 }
1.40
1.41 - (id)initWithBits: (NSData*)bits count: (NSUInteger)bitCount;
1.42 ++ (MYBitString*) bitStringWithData: (NSData*)bits;
1.43
1.44 @property (readonly, nonatomic) NSData *bits;
1.45 @property (readonly, nonatomic) NSUInteger bitCount;
2.1 --- a/MYASN1Object.m Wed Jun 03 17:22:42 2009 -0700
2.2 +++ b/MYASN1Object.m Thu Jun 04 18:36:30 2009 -0700
2.3 @@ -61,6 +61,15 @@
2.4 return $sprintf(@"%@[%hhu/%u/%u, %u bytes]", self.class, _tagClass,(unsigned)_constructed,_tag, _value.length);
2.5 }
2.6
2.7 +- (BOOL) isEqual: (id)object {
2.8 + return [object isKindOfClass: [MYASN1Object class]]
2.9 + && _tag==[object tag]
2.10 + && _tagClass==[object tagClass]
2.11 + && _constructed==[object constructed]
2.12 + && $equal(_value,[object value])
2.13 + && $equal(_components,[object components]);
2.14 +}
2.15 +
2.16 static void dump(id object, NSMutableString *output, NSString *indent) {
2.17 if ([object isKindOfClass: [MYASN1Object class]]) {
2.18 MYASN1Object *asn1Obj = object;
2.19 @@ -108,8 +117,7 @@
2.20 @implementation MYBitString
2.21
2.22
2.23 -- (id)initWithBits: (NSData*)bits count: (unsigned)bitCount;
2.24 -{
2.25 +- (id)initWithBits: (NSData*)bits count: (unsigned)bitCount {
2.26 Assert(bits);
2.27 Assert(bitCount <= 8*bits.length);
2.28 self = [super init];
2.29 @@ -120,6 +128,10 @@
2.30 return self;
2.31 }
2.32
2.33 ++ (MYBitString*) bitStringWithData: (NSData*)bits {
2.34 + return [[[self alloc] initWithBits: bits count: 8*bits.length] autorelease];
2.35 +}
2.36 +
2.37 - (void) dealloc
2.38 {
2.39 [_bits release];
2.40 @@ -132,4 +144,14 @@
2.41 return $sprintf(@"%@%@", [self class], _bits);
2.42 }
2.43
2.44 +- (unsigned) hash {
2.45 + return _bits.hash ^ _bitCount;
2.46 +}
2.47 +
2.48 +- (BOOL) isEqual: (id)object {
2.49 + return [object isKindOfClass: [MYBitString class]]
2.50 + && _bitCount==[object bitCount]
2.51 + && [_bits isEqual: [object bits]];
2.52 +}
2.53 +
2.54 @end
3.1 --- a/MYBERParser.h Wed Jun 03 17:22:42 2009 -0700
3.2 +++ b/MYBERParser.h Thu Jun 04 18:36:30 2009 -0700
3.3 @@ -6,13 +6,14 @@
3.4 // Copyright 2009 Jens Alfke. All rights reserved.
3.5 //
3.6
3.7 -#import <Cocoa/Cocoa.h>
3.8 +#import <Foundation/Foundation.h>
3.9
3.10
3.11 #define MYASN1ErrorDomain @"MYASN1ErrorDomain"
3.12
3.13
3.14 -/** Parses a block of BER-formatted data into an object tree. */
3.15 +/** Parses a block of BER-formatted data into an object tree.
3.16 + This is mostly used internally by MYParsedCertificate. */
3.17 id MYBERParse (NSData *ber, NSError **outError);
3.18
3.19 size_t MYBERGetLength (NSData *ber, NSError **outError);
4.1 --- a/MYBERParser.m Wed Jun 03 17:22:42 2009 -0700
4.2 +++ b/MYBERParser.m Thu Jun 04 18:36:30 2009 -0700
4.3 @@ -194,7 +194,15 @@
4.4 return readStringOrDie(input,length,NSUTF8StringEncoding);
4.5 case 18: // numeric string
4.6 case 19: // printable string:
4.7 - return readStringOrDie(input,length,NSASCIIStringEncoding);
4.8 + case 22: // IA5 string:
4.9 + case 20: // T61 string:
4.10 + {
4.11 + NSString *string = readStringOrDie(input,length,NSASCIIStringEncoding);
4.12 + if (string)
4.13 + return string;
4.14 + else
4.15 + break; // if decoding fails, fall back to generic MYASN1Object
4.16 + }
4.17 case 23: // UTC time:
4.18 case 24: // Generalized time:
4.19 return parseDate(readStringOrDie(input,length,NSASCIIStringEncoding), header.tag);
4.20 @@ -328,9 +336,7 @@
4.21
4.22 MYCertificate *myCert = [[MYCertificate alloc] initWithCertificateData: cert];
4.23 CAssert(myCert);
4.24 - const CSSM_KEY *pubKey = myCert.publicKey.cssmKey;
4.25 - CSSM_DATA pubKeyData = pubKey->KeyData;
4.26 - id parsedPubKey = MYBERParse([NSData dataWithBytes: pubKeyData.Data length: pubKeyData.Length],NULL);
4.27 + id parsedPubKey = MYBERParse(myCert.publicKey.keyData, NULL);
4.28 Log(@"Parsed public key:\n%@", [MYASN1Object dump: parsedPubKey]);
4.29
4.30 cert = [NSData dataWithContentsOfFile: @"../../Tests/iphonedev.cer"];
5.1 --- a/MYCrypto-iPhone.xcodeproj/project.pbxproj Wed Jun 03 17:22:42 2009 -0700
5.2 +++ b/MYCrypto-iPhone.xcodeproj/project.pbxproj Thu Jun 04 18:36:30 2009 -0700
5.3 @@ -16,6 +16,11 @@
5.4 273392120F8283B8009414D9 /* MYKeychain-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 273392110F8283B8009414D9 /* MYKeychain-iPhone.m */; };
5.5 274110090F99234100AD413F /* MYSymmetricKey-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 274110080F99234100AD413F /* MYSymmetricKey-iPhone.m */; };
5.6 2748607F0F8D5E0600FE617B /* MYPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 2748607E0F8D5E0600FE617B /* MYPrivateKey.m */; };
5.7 + 275D9FEE0FD8795300D85A86 /* MYParsedCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 275D9FE40FD8795300D85A86 /* MYParsedCertificate.m */; };
5.8 + 275D9FEF0FD8795300D85A86 /* MYASN1Object.m in Sources */ = {isa = PBXBuildFile; fileRef = 275D9FE60FD8795300D85A86 /* MYASN1Object.m */; };
5.9 + 275D9FF00FD8795300D85A86 /* MYBERParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 275D9FE80FD8795300D85A86 /* MYBERParser.m */; };
5.10 + 275D9FF10FD8795300D85A86 /* MYDEREncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 275D9FEA0FD8795300D85A86 /* MYDEREncoder.m */; };
5.11 + 275D9FF20FD8795300D85A86 /* MYOID.m in Sources */ = {isa = PBXBuildFile; fileRef = 275D9FEC0FD8795300D85A86 /* MYOID.m */; };
5.12 276FB13F0F84090900CB326E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 276FB13E0F84090900CB326E /* Security.framework */; };
5.13 276FB16E0F84152B00CB326E /* MYCryptoTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB16D0F84152B00CB326E /* MYCryptoTest.m */; };
5.14 276FB3190F856AA700CB326E /* MYPublicKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB3180F856AA700CB326E /* MYPublicKey.m */; };
5.15 @@ -23,7 +28,6 @@
5.16 276FB34B0F856CA400CB326E /* MYCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB34A0F856CA400CB326E /* MYCertificate.m */; };
5.17 27A430120F87C6C10063D362 /* MYKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E823110F81D56E0019BE60 /* MYKey.m */; };
5.18 27A430140F87C6D50063D362 /* MYSymmetricKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A430130F87C6D50063D362 /* MYSymmetricKey.m */; };
5.19 - 27B8522D0FCEE6F9005631F9 /* MYASN1.m in Sources */ = {isa = PBXBuildFile; fileRef = 27B8522C0FCEE6F9005631F9 /* MYASN1.m */; };
5.20 27E3A6AA0F91B8B30079D4D9 /* MYCryptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E3A6A70F91B8B30079D4D9 /* MYCryptor.m */; };
5.21 27E823240F81D56E0019BE60 /* MYKeychainItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E823150F81D56E0019BE60 /* MYKeychainItem.m */; };
5.22 27E823270F81D56E0019BE60 /* MYDigest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E8231C0F81D56E0019BE60 /* MYDigest.m */; };
5.23 @@ -53,6 +57,16 @@
5.24 274110080F99234100AD413F /* MYSymmetricKey-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYSymmetricKey-iPhone.m"; sourceTree = "<group>"; };
5.25 2748607D0F8D5DF200FE617B /* MYPrivateKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYPrivateKey.h; sourceTree = "<group>"; };
5.26 2748607E0F8D5E0600FE617B /* MYPrivateKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPrivateKey.m; sourceTree = "<group>"; };
5.27 + 275D9FE30FD8795300D85A86 /* MYParsedCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYParsedCertificate.h; sourceTree = "<group>"; };
5.28 + 275D9FE40FD8795300D85A86 /* MYParsedCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYParsedCertificate.m; sourceTree = "<group>"; };
5.29 + 275D9FE50FD8795300D85A86 /* MYASN1Object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYASN1Object.h; sourceTree = "<group>"; };
5.30 + 275D9FE60FD8795300D85A86 /* MYASN1Object.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYASN1Object.m; sourceTree = "<group>"; };
5.31 + 275D9FE70FD8795300D85A86 /* MYBERParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYBERParser.h; sourceTree = "<group>"; };
5.32 + 275D9FE80FD8795300D85A86 /* MYBERParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYBERParser.m; sourceTree = "<group>"; };
5.33 + 275D9FE90FD8795300D85A86 /* MYDEREncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYDEREncoder.h; sourceTree = "<group>"; };
5.34 + 275D9FEA0FD8795300D85A86 /* MYDEREncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYDEREncoder.m; sourceTree = "<group>"; };
5.35 + 275D9FEB0FD8795300D85A86 /* MYOID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYOID.h; sourceTree = "<group>"; };
5.36 + 275D9FEC0FD8795300D85A86 /* MYOID.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYOID.m; sourceTree = "<group>"; };
5.37 276FB13E0F84090900CB326E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
5.38 276FB16D0F84152B00CB326E /* MYCryptoTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCryptoTest.m; sourceTree = "<group>"; };
5.39 276FB3180F856AA700CB326E /* MYPublicKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPublicKey.m; sourceTree = "<group>"; };
5.40 @@ -61,8 +75,6 @@
5.41 27A430130F87C6D50063D362 /* MYSymmetricKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYSymmetricKey.m; sourceTree = "<group>"; };
5.42 27A430150F87C6DB0063D362 /* MYSymmetricKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYSymmetricKey.h; sourceTree = "<group>"; };
5.43 27AAD9710F8927DB0064DD7C /* MYCryptoConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCryptoConfig.h; sourceTree = "<group>"; };
5.44 - 27B8522B0FCEE6F9005631F9 /* MYASN1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYASN1.h; sourceTree = "<group>"; };
5.45 - 27B8522C0FCEE6F9005631F9 /* MYASN1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYASN1.m; sourceTree = "<group>"; };
5.46 27E3A6A60F91B8B30079D4D9 /* MYCryptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCryptor.h; sourceTree = "<group>"; };
5.47 27E3A6A70F91B8B30079D4D9 /* MYCryptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCryptor.m; sourceTree = "<group>"; };
5.48 27E8230C0F81D56E0019BE60 /* MYCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCertificate.h; sourceTree = "<group>"; };
5.49 @@ -130,6 +142,23 @@
5.50 name = Products;
5.51 sourceTree = "<group>";
5.52 };
5.53 + 275D9FE00FD8795300D85A86 /* Certificates */ = {
5.54 + isa = PBXGroup;
5.55 + children = (
5.56 + 275D9FE30FD8795300D85A86 /* MYParsedCertificate.h */,
5.57 + 275D9FE40FD8795300D85A86 /* MYParsedCertificate.m */,
5.58 + 275D9FE50FD8795300D85A86 /* MYASN1Object.h */,
5.59 + 275D9FE60FD8795300D85A86 /* MYASN1Object.m */,
5.60 + 275D9FE70FD8795300D85A86 /* MYBERParser.h */,
5.61 + 275D9FE80FD8795300D85A86 /* MYBERParser.m */,
5.62 + 275D9FE90FD8795300D85A86 /* MYDEREncoder.h */,
5.63 + 275D9FEA0FD8795300D85A86 /* MYDEREncoder.m */,
5.64 + 275D9FEB0FD8795300D85A86 /* MYOID.h */,
5.65 + 275D9FEC0FD8795300D85A86 /* MYOID.m */,
5.66 + );
5.67 + name = Certificates;
5.68 + sourceTree = "<group>";
5.69 + };
5.70 27E3A6A10F91B8B30079D4D9 /* Encryption */ = {
5.71 isa = PBXGroup;
5.72 children = (
5.73 @@ -142,8 +171,6 @@
5.74 27E8230B0F81D56E0019BE60 /* Source */ = {
5.75 isa = PBXGroup;
5.76 children = (
5.77 - 27B8522B0FCEE6F9005631F9 /* MYASN1.h */,
5.78 - 27B8522C0FCEE6F9005631F9 /* MYASN1.m */,
5.79 27AAD9710F8927DB0064DD7C /* MYCryptoConfig.h */,
5.80 27E8230C0F81D56E0019BE60 /* MYCertificate.h */,
5.81 276FB34A0F856CA400CB326E /* MYCertificate.m */,
5.82 @@ -198,6 +225,7 @@
5.83 children = (
5.84 27E8230B0F81D56E0019BE60 /* Source */,
5.85 27E3A6A10F91B8B30079D4D9 /* Encryption */,
5.86 + 275D9FE00FD8795300D85A86 /* Certificates */,
5.87 27E8232B0F81D5760019BE60 /* MYUtilities */,
5.88 080E96DDFE201D6D7F000001 /* iPhone */,
5.89 29B97323FDCFA39411CA2CEA /* Frameworks */,
5.90 @@ -295,7 +323,11 @@
5.91 27059CF30F8F0F9200A8422F /* MYIdentity.m in Sources */,
5.92 27E3A6AA0F91B8B30079D4D9 /* MYCryptor.m in Sources */,
5.93 274110090F99234100AD413F /* MYSymmetricKey-iPhone.m in Sources */,
5.94 - 27B8522D0FCEE6F9005631F9 /* MYASN1.m in Sources */,
5.95 + 275D9FEE0FD8795300D85A86 /* MYParsedCertificate.m in Sources */,
5.96 + 275D9FEF0FD8795300D85A86 /* MYASN1Object.m in Sources */,
5.97 + 275D9FF00FD8795300D85A86 /* MYBERParser.m in Sources */,
5.98 + 275D9FF10FD8795300D85A86 /* MYDEREncoder.m in Sources */,
5.99 + 275D9FF20FD8795300D85A86 /* MYOID.m in Sources */,
5.100 );
5.101 runOnlyForDeploymentPostprocessing = 0;
5.102 };
6.1 --- a/MYCrypto.xcodeproj/project.pbxproj Wed Jun 03 17:22:42 2009 -0700
6.2 +++ b/MYCrypto.xcodeproj/project.pbxproj Thu Jun 04 18:36:30 2009 -0700
6.3 @@ -278,10 +278,10 @@
6.4 274861440F8D757600FE617B /* Certificates */ = {
6.5 isa = PBXGroup;
6.6 children = (
6.7 + 27A42ECC0F8689D30063D362 /* MYCertGen.h */,
6.8 + 27A42ECD0F8689D30063D362 /* MYCertGen.m */,
6.9 275D9D900FD5FB4100D85A86 /* MYParsedCertificate.h */,
6.10 275D9D910FD5FB4100D85A86 /* MYParsedCertificate.m */,
6.11 - 27A42ECC0F8689D30063D362 /* MYCertGen.h */,
6.12 - 27A42ECD0F8689D30063D362 /* MYCertGen.m */,
6.13 27B852F30FCF4EB6005631F9 /* MYASN1Object.h */,
6.14 27B852F40FCF4EB7005631F9 /* MYASN1Object.m */,
6.15 270A7A710FD58FF200770C4D /* MYBERParser.h */,
7.1 --- a/MYDEREncoder.h Wed Jun 03 17:22:42 2009 -0700
7.2 +++ b/MYDEREncoder.h Thu Jun 04 18:36:30 2009 -0700
7.3 @@ -11,9 +11,11 @@
7.4
7.5 @interface MYDEREncoder : NSObject
7.6 {
7.7 + @private
7.8 id _rootObject;
7.9 NSMutableData *_output;
7.10 NSError *_error;
7.11 + BOOL _forcePrintableStrings;
7.12 }
7.13
7.14 - (id) initWithRootObject: (id)object;
8.1 --- a/MYDEREncoder.m Wed Jun 03 17:22:42 2009 -0700
8.2 +++ b/MYDEREncoder.m Thu Jun 04 18:36:30 2009 -0700
8.3 @@ -19,6 +19,7 @@
8.4 @interface MYDEREncoder ()
8.5 - (void) _encode: (id)object;
8.6 @property (retain) NSError *error;
8.7 +@property BOOL _forcePrintableStrings;
8.8 @end
8.9
8.10
8.11 @@ -46,9 +47,15 @@
8.12 {
8.13 [_rootObject release];
8.14 [_output release];
8.15 + [_error release];
8.16 [super dealloc];
8.17 }
8.18
8.19 +- (id) copyWithZone: (NSZone*)zone {
8.20 + MYDEREncoder *copy = [[[self class] alloc] init];
8.21 + copy->_forcePrintableStrings = _forcePrintableStrings;
8.22 + return copy;
8.23 +}
8.24
8.25
8.26 static unsigned sizeOfUnsignedInt (UInt64 n) {
8.27 @@ -185,11 +192,22 @@
8.28
8.29
8.30 - (void) _encodeString: (NSString*)string {
8.31 + static NSMutableCharacterSet *kNotPrintableCharSet;
8.32 + if (!kNotPrintableCharSet) {
8.33 + kNotPrintableCharSet = [[NSMutableCharacterSet characterSetWithCharactersInString: @" '()+,-./:=?"] retain];
8.34 + [kNotPrintableCharSet formUnionWithCharacterSet: [NSCharacterSet alphanumericCharacterSet]];
8.35 + [kNotPrintableCharSet invert];
8.36 + }
8.37 NSData *data = [string dataUsingEncoding: NSASCIIStringEncoding];
8.38 - if (data)
8.39 - [self _writeTag: 19 class: 0 constructed: NO data: data];
8.40 - else
8.41 + if (data) {
8.42 + unsigned tag = 19; // printablestring (a silly arbitrary subset of ASCII defined by ASN.1)
8.43 + if (!_forcePrintableStrings && [string rangeOfCharacterFromSet: kNotPrintableCharSet].length > 0)
8.44 + tag = 20; // IA5string (full 7-bit ASCII)
8.45 + [self _writeTag: tag class: 0 constructed: NO data: data];
8.46 + } else {
8.47 + // fall back to UTF-8:
8.48 [self _writeTag: 12 class: 0 constructed: NO data: [string dataUsingEncoding: NSUTF8StringEncoding]];
8.49 + }
8.50 }
8.51
8.52
8.53 @@ -209,7 +227,7 @@
8.54
8.55
8.56 - (void) _encodeCollection: (id)collection tag: (unsigned)tag class: (unsigned)tagClass {
8.57 - MYDEREncoder *subEncoder = [[[self class] alloc] init];
8.58 + MYDEREncoder *subEncoder = [self copy];
8.59 for (id object in collection)
8.60 [subEncoder _encode: object];
8.61 [self _writeTag: tag class: tagClass constructed: YES data: subEncoder.output];
8.62 @@ -268,7 +286,7 @@
8.63 return _output;
8.64 }
8.65
8.66 -@synthesize error=_error;
8.67 +@synthesize error=_error, _forcePrintableStrings;
8.68
8.69
8.70 @end
8.71 @@ -342,11 +360,13 @@
8.72 id certObjects = MYBERParse(cert,&error);
8.73 CAssertNil(error);
8.74 Log(@"Decoded as:\n%@", [MYASN1Object dump: certObjects]);
8.75 - NSData *encoded = [MYDEREncoder encodeRootObject: certObjects error: &error];
8.76 + MYDEREncoder *encoder = [[MYDEREncoder alloc] initWithRootObject: certObjects];
8.77 + encoder._forcePrintableStrings = YES; // hack for compatibility with the way CDSA writes ASN.1
8.78 + NSData *encoded = encoder.output;
8.79 CAssertNil(error);
8.80 id reDecoded = MYBERParse(encoded, &error);
8.81 CAssertNil(error);
8.82 Log(@"Re-decoded as:\n%@", [MYASN1Object dump: reDecoded]);
8.83 - [encoded writeToFile: @"../../Tests/iphonedev_reencoded.cer" atomically: YES];
8.84 + [encoded writeToFile: @"../../Tests/selfsigned_reencoded.cer" atomically: YES];
8.85 CAssertEqual(encoded,cert);
8.86 }
9.1 --- a/MYOID.h Wed Jun 03 17:22:42 2009 -0700
9.2 +++ b/MYOID.h Thu Jun 04 18:36:30 2009 -0700
9.3 @@ -6,10 +6,11 @@
9.4 // Copyright 2009 Jens Alfke. All rights reserved.
9.5 //
9.6
9.7 -#import <Cocoa/Cocoa.h>
9.8 +#import <Foundation/Foundation.h>
9.9
9.10
9.11 -/** An ASN.1 Object-ID, which is a sequence of integer components that define namespaces. */
9.12 +/* An ASN.1 Object-ID, which is a sequence of integer components that define namespaces.
9.13 + This is mostly used internally by MYParsedCertificate. */
9.14 @interface MYOID : NSObject <NSCopying>
9.15 {
9.16 NSData *_data;
10.1 --- a/MYParsedCertificate.h Wed Jun 03 17:22:42 2009 -0700
10.2 +++ b/MYParsedCertificate.h Thu Jun 04 18:36:30 2009 -0700
10.3 @@ -7,23 +7,79 @@
10.4 //
10.5
10.6 #import <Foundation/Foundation.h>
10.7 -@class MYCertificate, MYOID;
10.8 +@class MYCertificate, MYPublicKey, MYPrivateKey, MYOID;
10.9
10.10 /** A parsed X.509 certificate. Can be used to get more info about an existing cert,
10.11 or to modify a self-signed cert and regenerate it. */
10.12 @interface MYParsedCertificate : NSObject
10.13 {
10.14 + @private
10.15 NSData *_data;
10.16 - id _root;
10.17 + NSArray *_root;
10.18 MYCertificate *_issuer;
10.19 }
10.20
10.21 -+ (MYOID*) RSAWithSHA1AlgorithmID;
10.22 -
10.23 +/** Initializes an instance by parsing an existing X.509 certificate's data. */
10.24 - (id) initWithCertificateData: (NSData*)data error: (NSError**)outError;
10.25
10.26 +/** The raw data of the certificate. */
10.27 +@property (readonly) NSData* certificateData;
10.28 +
10.29 +/** The date/time at which the certificate first becomes valid. */
10.30 +@property (retain) NSDate *validFrom;
10.31 +
10.32 +/** The date/time at which the certificate expires. */
10.33 +@property (retain) NSDate *validTo;
10.34 +
10.35 +/** The "common name" (nickname, whatever) of the subject/owner of the certificate. */
10.36 +@property (copy) NSString *commonName;
10.37 +
10.38 +/** The given/first name of the subject/owner of the certificate. */
10.39 +@property (copy) NSString *givenName;
10.40 +
10.41 +/** The surname / last name / family name of the subject/owner of the certificate. */
10.42 +@property (copy) NSString *surname;
10.43 +
10.44 +/** A description of the subject/owner of the certificate. */
10.45 +@property (copy) NSString *description;
10.46 +
10.47 +/** The raw email address of the subject of the certificate. */
10.48 +@property (copy) NSString *emailAddress;
10.49 +
10.50 +/** The public key of the subject of the certificate. */
10.51 +@property (readonly) MYPublicKey *subjectPublicKey;
10.52 +
10.53 +/** Returns YES if the issuer is the same as the subject. (Aka a "self-signed" certificate.) */
10.54 +@property (readonly) BOOL isRoot;
10.55 +
10.56 /** Associates the certificate to its issuer.
10.57 - If the cert is not self-signed, you must manually set this property before verifying. */
10.58 + If the cert is not self-signed, you must manually set this property before validating. */
10.59 @property (retain) MYCertificate* issuer;
10.60
10.61 +/** Checks that the issuer's signature is valid and hasn't been tampered with.
10.62 + If the certificate is root/self-signed, the subjectPublicKey is used to check the signature;
10.63 + otherwise, the issuer property needs to have been set and its publicKey will be used. */
10.64 +- (BOOL) validateSignature;
10.65 +
10.66 +
10.67 +// Generating certificates:
10.68 +
10.69 +/** Initializes a blank instance which can be used to create a new certificate.
10.70 + The certificate will not contain anything yet other than the public key.
10.71 + The desired attributes should be set, and then the -selfSignWithPrivateKey:error method called. */
10.72 +- (id) initWithPublicKey: (MYPublicKey*)pubKey;
10.73 +
10.74 +/** Has the certificate been signed yet? */
10.75 +@property (readonly) BOOL isSigned;
10.76 +
10.77 +/** Signs the certificate using the given private key, which must be the counterpart of the
10.78 + public key stored in the certificate.
10.79 + The subject attributes will be copied to the issuer attributes.
10.80 + If no valid date range has been set yet, it will be set to a range of one year starting from
10.81 + the current time.
10.82 + A unique serial number based on the current time will be set.
10.83 + After this method returns successfully, access the certificateData property to get the
10.84 + encoded certificate. */
10.85 +- (BOOL) selfSignWithPrivateKey: (MYPrivateKey*)privateKey error: (NSError**)outError;
10.86 +
10.87 @end
11.1 --- a/MYParsedCertificate.m Wed Jun 03 17:22:42 2009 -0700
11.2 +++ b/MYParsedCertificate.m Thu Jun 04 18:36:30 2009 -0700
11.3 @@ -7,6 +7,7 @@
11.4 //
11.5
11.6 // References:
11.7 +// <http://www.columbia.edu/~ariel/ssleay/layman.html>
11.8 // <http://en.wikipedia.org/wiki/X.509>
11.9 // <http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt>
11.10
11.11 @@ -17,10 +18,14 @@
11.12 #import "MYBERParser.h"
11.13 #import "MYDEREncoder.h"
11.14 #import "MYPublicKey.h"
11.15 +#import "MYPrivateKey.h"
11.16 #import "MYCertificate.h"
11.17 #import "MYErrorUtils.h"
11.18
11.19
11.20 +#define kDefaultExpirationTime (60.0 * 60.0 * 24.0 * 365.0)
11.21 +
11.22 +
11.23 static id $atIf(NSArray *array, NSUInteger index) {
11.24 return index < array.count ?[array objectAtIndex: index] :nil;
11.25 }
11.26 @@ -29,24 +34,30 @@
11.27 @implementation MYParsedCertificate
11.28
11.29
11.30 -static MYOID *kRSAAlgorithmID, *kRSAWithSHA1AlgorithmID;
11.31 +static MYOID *kRSAAlgorithmID, *kRSAWithSHA1AlgorithmID, *kCommonNameOID,
11.32 + *kGivenNameOID, *kSurnameOID, *kDescriptionOID, *kEmailOID;
11.33
11.34
11.35 + (void) initialize {
11.36 - if (!kRSAAlgorithmID) {
11.37 - UInt32 components[7] = {1, 2, 840, 113549, 1, 1, 1,};
11.38 - kRSAAlgorithmID = [[MYOID alloc] initWithComponents: components count: 7];
11.39 + if (!kEmailOID) {
11.40 + kRSAAlgorithmID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 1, 1,}
11.41 + count: 7];
11.42 + kRSAWithSHA1AlgorithmID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 1, 5}
11.43 + count: 7];
11.44 + kCommonNameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 3}
11.45 + count: 4];
11.46 + kGivenNameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 42}
11.47 + count: 4];
11.48 + kSurnameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 4}
11.49 + count: 4];
11.50 + kDescriptionOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 13}
11.51 + count: 7];
11.52 + kEmailOID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 9, 1}
11.53 + count: 7];
11.54 }
11.55 - if (!kRSAWithSHA1AlgorithmID) {
11.56 - UInt32 components[7] = {1, 2, 840, 113549, 1, 1, 5};
11.57 - kRSAWithSHA1AlgorithmID = [[MYOID alloc] initWithComponents: components count: 7];
11.58 - }
11.59 +
11.60 }
11.61
11.62 -+ (MYOID*) RSAAlgorithmID {return kRSAAlgorithmID;}
11.63 -+ (MYOID*) RSAWithSHA1AlgorithmID {return kRSAWithSHA1AlgorithmID;}
11.64 -
11.65 -
11.66 + (NSString*) validate: (id)root {
11.67 NSArray *top = $castIf(NSArray,root);
11.68 if (top.count < 3)
11.69 @@ -91,48 +102,71 @@
11.70
11.71 [_root release];
11.72 [_issuer release];
11.73 + [_data release];
11.74 [super dealloc];
11.75 }
11.76
11.77
11.78 -@synthesize issuer=_issuer;
11.79 +- (NSArray*) _info {return $castIf(NSArray,$atIf(_root,0));}
11.80
11.81 +- (NSArray*) _validDates {return $castIf(NSArray, [self._info objectAtIndex: 4]);}
11.82
11.83 -- (NSArray*) info {return $castIf(NSArray,$atIf(_root,0));}
11.84 -
11.85 -- (BOOL) isSelfSigned {
11.86 - id issuer = $atIf(self.info,3);
11.87 - id subject = $atIf(self.info,5);
11.88 - return $equal(issuer,subject);
11.89 +- (NSArray*) _pairForOID: (MYOID*)oid atInfoIndex: (unsigned)infoIndex {
11.90 + NSArray *names = $castIf(NSArray, $atIf(self._info, infoIndex));
11.91 + for (id nameEntry in names) {
11.92 + for (id pair in $castIf(NSSet,nameEntry)) {
11.93 + if ([pair isKindOfClass: [NSArray class]] && [pair count] == 2) {
11.94 + if ($equal(oid, [pair objectAtIndex: 0]))
11.95 + return pair;
11.96 + }
11.97 + }
11.98 + }
11.99 + return nil;
11.100 }
11.101
11.102 +- (NSString*) _stringForOID: (MYOID*)oid atInfoIndex: (unsigned)infoIndex {
11.103 + return [[self _pairForOID: oid atInfoIndex: infoIndex] objectAtIndex: 1];
11.104 +}
11.105 +
11.106 +
11.107 +@synthesize issuer=_issuer, certificateData=_data;
11.108 +
11.109 +
11.110 +- (NSDate*) validFrom {return $castIf(NSDate, $atIf(self._validDates, 0));}
11.111 +- (NSDate*) validTo {return $castIf(NSDate, $atIf(self._validDates, 1));}
11.112 +- (NSString*) commonName {return [self _stringForOID: kCommonNameOID atInfoIndex: 5];}
11.113 +- (NSString*) givenName {return [self _stringForOID: kGivenNameOID atInfoIndex: 5];}
11.114 +- (NSString*) surname {return [self _stringForOID: kSurnameOID atInfoIndex: 5];}
11.115 +- (NSString*) description {return [self _stringForOID: kDescriptionOID atInfoIndex: 5];}
11.116 +- (NSString*) emailAddress {return [self _stringForOID: kEmailOID atInfoIndex: 5];}
11.117 +
11.118 +- (BOOL) isSigned {return [_root count] >= 3;}
11.119 +
11.120 +- (BOOL) isRoot {
11.121 + id issuer = $atIf(self._info,3);
11.122 + return $equal(issuer, $atIf(self._info,5)) || $equal(issuer, $array());
11.123 +}
11.124 +
11.125 +
11.126 - (MYPublicKey*) subjectPublicKey {
11.127 - NSArray *keyInfo = $cast(NSArray, $atIf(self.info, 6));
11.128 + NSArray *keyInfo = $cast(NSArray, $atIf(self._info, 6));
11.129 MYOID *keyAlgorithmID = $castIf(MYOID, $atIf($castIf(NSArray,$atIf(keyInfo,0)), 0));
11.130 if (!$equal(keyAlgorithmID, kRSAAlgorithmID))
11.131 return nil;
11.132 MYBitString *keyData = $cast(MYBitString, $atIf(keyInfo, 1));
11.133 if (!keyData) return nil;
11.134 return [[[MYPublicKey alloc] initWithKeyData: keyData.bits] autorelease];
11.135 - /*
11.136 - NSArray *keyParts = $castIf(NSArray, MYBERParse(keyData, nil));
11.137 - if (!keyParts) return nil;
11.138 - MYBitString *modulus = $castIf(MYBitString, $atIf(keyParts,0));
11.139 - int exponent = [$castIf(NSNumber, $atIf(keyParts,1)) intValue];
11.140 - if (!modulus || exponent<3) return nil;
11.141 - */
11.142 }
11.143
11.144 - (MYPublicKey*) issuerPublicKey {
11.145 if (_issuer)
11.146 return _issuer.publicKey;
11.147 - else if (self.isSelfSigned)
11.148 + else if (self.isRoot)
11.149 return self.subjectPublicKey;
11.150 else
11.151 return nil;
11.152 }
11.153
11.154 -
11.155 - (NSData*) signedData {
11.156 // The root object is a sequence; we want to extract the 1st object of that sequence.
11.157 const UInt8 *certStart = _data.bytes;
11.158 @@ -159,7 +193,7 @@
11.159 }
11.160
11.161 - (BOOL) validateSignature {
11.162 - if (!$equal(self.signatureAlgorithmID, [MYParsedCertificate RSAWithSHA1AlgorithmID]))
11.163 + if (!$equal(self.signatureAlgorithmID, kRSAWithSHA1AlgorithmID))
11.164 return NO;
11.165 NSData *signedData = self.signedData;
11.166 NSData *signature = self.signature;
11.167 @@ -169,45 +203,191 @@
11.168 }
11.169
11.170
11.171 +#pragma mark -
11.172 +#pragma mark CERTIFICATE GENERATION:
11.173 +
11.174 +
11.175 +- (id) initWithPublicKey: (MYPublicKey*)pubKey {
11.176 + Assert(pubKey);
11.177 + self = [super init];
11.178 + if (self != nil) {
11.179 + id empty = [NSNull null];
11.180 + id version = [[MYASN1Object alloc] initWithTag: 0 ofClass: 2 components: $array($object(0))];
11.181 + _root = $array( $marray(version,
11.182 + empty, // serial #
11.183 + $array(kRSAAlgorithmID),
11.184 + $marray(),
11.185 + $marray(empty, empty),
11.186 + $marray(),
11.187 + $array( $array(kRSAAlgorithmID, empty),
11.188 + [MYBitString bitStringWithData: pubKey.keyData] ) ) );
11.189 + [version release];
11.190 + [_root retain];
11.191 + }
11.192 + return self;
11.193 +}
11.194 +
11.195 +
11.196 +- (void) _setString: (NSString*)value forOID: (MYOID*)oid atInfoIndex: (unsigned)infoIndex {
11.197 + NSMutableArray *pair = (NSMutableArray*) [self _pairForOID: oid atInfoIndex: infoIndex];
11.198 + if (pair) {
11.199 + [pair replaceObjectAtIndex: 1 withObject: value];
11.200 + } else {
11.201 + NSMutableArray *names = $castIf(NSMutableArray, $atIf(self._info, infoIndex));
11.202 + [names addObject: [NSSet setWithObject: $marray(oid,value)]];
11.203 + }
11.204 +}
11.205 +
11.206 +
11.207 +- (void) setValidFrom: (NSDate*)validFrom {
11.208 + [(NSMutableArray*)self._validDates replaceObjectAtIndex: 0 withObject: validFrom];
11.209 +}
11.210 +
11.211 +- (void) setValidTo: (NSDate*)validTo {
11.212 + [(NSMutableArray*)self._validDates replaceObjectAtIndex: 1 withObject: validTo];
11.213 +}
11.214 +
11.215 +- (void) setCommonName: (NSString*)commonName {
11.216 + [self _setString: commonName forOID: kCommonNameOID atInfoIndex: 5];
11.217 +}
11.218 +
11.219 +- (void) setGivenName: (NSString*)givenName {
11.220 + [self _setString: givenName forOID: kGivenNameOID atInfoIndex: 5];
11.221 +}
11.222 +
11.223 +- (void) setSurname: (NSString*)surname {
11.224 + [self _setString: surname forOID: kSurnameOID atInfoIndex: 5];
11.225 +}
11.226 +
11.227 +- (void) setDescription: (NSString*)description {
11.228 + [self _setString: description forOID: kDescriptionOID atInfoIndex: 5];
11.229 +}
11.230 +
11.231 +- (void) setEmailAddress: (NSString*)emailAddress {
11.232 + [self _setString: emailAddress forOID: kEmailOID atInfoIndex: 5];
11.233 +}
11.234 +
11.235 +
11.236 +- (BOOL) selfSignWithPrivateKey: (MYPrivateKey*)privateKey error: (NSError**)outError {
11.237 + // Copy subject to issuer:
11.238 + NSMutableArray *info = (NSMutableArray*)self._info;
11.239 + [info replaceObjectAtIndex: 3 withObject: [info objectAtIndex: 5]];
11.240 +
11.241 + // Set serial number if there isn't one yet:
11.242 + if (!$castIf(NSNumber, [info objectAtIndex: 1])) {
11.243 + UInt64 serial = floor(CFAbsoluteTimeGetCurrent() * 1000);
11.244 + [info replaceObjectAtIndex: 1 withObject: $object(serial)];
11.245 + }
11.246 +
11.247 + // Set up valid date range if there isn't one yet:
11.248 + NSDate *validFrom = self.validFrom;
11.249 + if (!validFrom)
11.250 + validFrom = self.validFrom = [NSDate date];
11.251 + NSDate *validTo = self.validTo;
11.252 + if (!validTo)
11.253 + self.validTo = [validFrom addTimeInterval: kDefaultExpirationTime];
11.254 +
11.255 + // Append signature to cert structure:
11.256 + NSData *dataToSign = [MYDEREncoder encodeRootObject: info error: outError];
11.257 + if (!dataToSign)
11.258 + return NO;
11.259 + setObj(&_root, $array(info,
11.260 + $array(kRSAWithSHA1AlgorithmID, [NSNull null]),
11.261 + [MYBitString bitStringWithData: [privateKey signData: dataToSign]]));
11.262 +
11.263 + setObj(&_data, [MYDEREncoder encodeRootObject: _root error: outError]);
11.264 + return _data!=nil;
11.265 +}
11.266 +
11.267 +
11.268 @end
11.269
11.270
11.271
11.272
11.273 +#if DEBUG
11.274 +
11.275 +
11.276 +static MYParsedCertificate* testCert(NSString *filename, BOOL selfSigned) {
11.277 + Log(@"--- Creating MYParsedCertificate from %@", filename);
11.278 + NSData *certData = [NSData dataWithContentsOfFile: filename];
11.279 + //Log(@"Cert Data =\n%@", certData);
11.280 + NSError *error = nil;
11.281 + MYParsedCertificate *pcert = [[MYParsedCertificate alloc] initWithCertificateData: certData
11.282 + error: &error];
11.283 + CAssertNil(error);
11.284 + CAssert(pcert != nil);
11.285 +
11.286 + CAssertEq(pcert.isRoot, selfSigned);
11.287 +
11.288 + NSData *signedData = pcert.signedData;
11.289 + //Log(@"Signed Data = (length=%x)\n%@", signedData.length, signedData);
11.290 + CAssertEqual(signedData, [certData subdataWithRange: NSMakeRange(4,signedData.length)]);
11.291 +
11.292 + Log(@"AlgID = %@", pcert.signatureAlgorithmID);
11.293 + Log(@"Signature = %@", pcert.signature);
11.294 + CAssertEqual(pcert.signatureAlgorithmID, kRSAWithSHA1AlgorithmID);
11.295 + CAssert(pcert.signature != nil);
11.296 + Log(@"Subject Public Key = %@", pcert.subjectPublicKey);
11.297 + CAssert(pcert.subjectPublicKey);
11.298 + if (selfSigned) {
11.299 + Log(@"Issuer Public Key = %@", pcert.issuerPublicKey);
11.300 + CAssert(pcert.issuerPublicKey);
11.301 +
11.302 + CAssert(pcert.validateSignature);
11.303 + }
11.304 + Log(@"Common Name = %@", pcert.commonName);
11.305 + Log(@"Given Name = %@", pcert.givenName);
11.306 + Log(@"Surname = %@", pcert.surname);
11.307 + Log(@"Desc = %@", pcert.description);
11.308 + Log(@"Email = %@", pcert.emailAddress);
11.309 + return pcert;
11.310 +}
11.311 +
11.312 +
11.313 TestCase(ParsedCert) {
11.314 - auto void testCert(NSString *filename, BOOL selfSigned);
11.315 testCert(@"../../Tests/selfsigned.cer", YES);
11.316 testCert(@"../../Tests/iphonedev.cer", NO);
11.317 - auto void testCert(NSString *filename, BOOL selfSigned) {
11.318 - Log(@"--- Creating MYParsedCertificate from %@", filename);
11.319 - NSData *certData = [NSData dataWithContentsOfFile: filename];
11.320 - //Log(@"Cert Data =\n%@", certData);
11.321 - NSError *error = nil;
11.322 - MYParsedCertificate *pcert = [[MYParsedCertificate alloc] initWithCertificateData: certData
11.323 - error: &error];
11.324 - CAssertNil(error);
11.325 - CAssert(pcert != nil);
11.326 -
11.327 - CAssertEq(pcert.isSelfSigned, selfSigned);
11.328 -
11.329 - NSData *signedData = pcert.signedData;
11.330 - //Log(@"Signed Data = (length=%x)\n%@", signedData.length, signedData);
11.331 - CAssertEqual(signedData, [certData subdataWithRange: NSMakeRange(4,signedData.length)]);
11.332 -
11.333 - Log(@"AlgID = %@", pcert.signatureAlgorithmID);
11.334 - Log(@"Signature = %@", pcert.signature);
11.335 - CAssertEqual(pcert.signatureAlgorithmID, [MYParsedCertificate RSAWithSHA1AlgorithmID]);
11.336 - CAssert(pcert.signature != nil);
11.337 - Log(@"Subject Public Key = %@", pcert.subjectPublicKey);
11.338 - CAssert(pcert.subjectPublicKey);
11.339 - if (selfSigned) {
11.340 - Log(@"Issuer Public Key = %@", pcert.issuerPublicKey);
11.341 - CAssert(pcert.issuerPublicKey);
11.342 -
11.343 - CAssert(pcert.validateSignature);
11.344 - }
11.345 - }
11.346 -}
11.347 +}
11.348 +
11.349 +
11.350 +#import "MYKeychain.h"
11.351 +
11.352 +TestCase(CreateCert) {
11.353 + MYPrivateKey *privateKey = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 512];
11.354 + MYParsedCertificate *pcert = [[MYParsedCertificate alloc] initWithPublicKey: privateKey.publicKey];
11.355 + pcert.commonName = @"testcase";
11.356 + pcert.givenName = @"Test";
11.357 + pcert.surname = @"Case";
11.358 + pcert.description = @"Just a test certificate created by MYCrypto";
11.359 + pcert.emailAddress = @"testcase@example.com";
11.360 +
11.361 + CAssertEqual(pcert.commonName, @"testcase");
11.362 + CAssertEqual(pcert.givenName, @"Test");
11.363 + CAssertEqual(pcert.surname, @"Case");
11.364 + CAssertEqual(pcert.description, @"Just a test certificate created by MYCrypto");
11.365 + CAssertEqual(pcert.emailAddress, @"testcase@example.com");
11.366 +
11.367 + Log(@"Signing...");
11.368 + NSError *error;
11.369 + CAssert([pcert selfSignWithPrivateKey: privateKey error: &error]);
11.370 + CAssertNil(error);
11.371 + NSData *certData = pcert.certificateData;
11.372 + Log(@"Generated cert = \n%@", certData);
11.373 + CAssert(certData);
11.374 + [certData writeToFile: @"../../Tests/generated.cer" atomically: YES];
11.375 + MYParsedCertificate *pcert2 = testCert(@"../../Tests/generated.cer", YES);
11.376 +
11.377 + Log(@"Verifying...");
11.378 + CAssertEqual(pcert2.commonName, @"testcase");
11.379 + CAssertEqual(pcert2.givenName, @"Test");
11.380 + CAssertEqual(pcert2.surname, @"Case");
11.381 + CAssertEqual(pcert2.description, @"Just a test certificate created by MYCrypto");
11.382 + CAssertEqual(pcert2.emailAddress, @"testcase@example.com");
11.383 +}
11.384 +
11.385 +#endif
11.386 +
11.387
11.388
11.389
11.390 @@ -215,8 +395,8 @@
11.391
11.392 Sequence: <-- top
11.393 Sequence: <-- info
11.394 - MYASN1Object[2/0]: <-- version (int, constructed)
11.395 - 2
11.396 + MYASN1Object[2/0]: <-- version (tag=0, constructed)
11.397 + 2
11.398 1 <-- serial number
11.399 Sequence:
11.400 {1 2 840 113549 1 1 1} <-- algorithm ID
11.401 @@ -246,23 +426,23 @@
11.402 2010-04-13 21:54:35 -0700
11.403 Sequence: <-- subject
11.404 Set:
11.405 - Sequence:
11.406 + Sequence: <-- surname
11.407 {2 5 4 4}
11.408 Widdershins
11.409 Set:
11.410 - Sequence:
11.411 + Sequence: <-- email
11.412 {1 2 840 113549 1 9 1}
11.413 waldo@example.com
11.414 Set:
11.415 - Sequence:
11.416 + Sequence: <-- common name
11.417 {2 5 4 3}
11.418 waldo
11.419 Set:
11.420 - Sequence:
11.421 + Sequence: <-- first name
11.422 {2 5 4 42}
11.423 Waldo
11.424 Set:
11.425 - Sequence:
11.426 + Sequence: <-- description
11.427 {2 5 4 13}
11.428 Just a fictitious person
11.429 Sequence: <-- public key info