* Created class MYCertificateRequest, factored out of MYCertificateInfo.
authorJens Alfke <jens@mooseyard.com>
Sat Jun 06 15:01:28 2009 -0700 (2009-06-06)
changeset 212c300b15b381
parent 20 df9da0f6b358
child 22 058394513f33
* Created class MYCertificateRequest, factored out of MYCertificateInfo.
* Added method to create a MYIdentity directly from a MYCertificateRequest.
* Added raw modulus+exponent accessor and initializer for MYPublicKey.
* Removed obsolete MYCertGen code, and the MYPrivateKey identity-creation method that used it.
MYASN1Object.h
MYASN1Object.m
MYBERParser.m
MYCertGen.m
MYCertificate-iPhone.m
MYCertificate.h
MYCertificate.m
MYCertificateInfo.h
MYCertificateInfo.m
MYCrypto-iPhone.xcodeproj/project.pbxproj
MYCrypto.xcodeproj/project.pbxproj
MYCryptoTest.m
MYCrypto_Private.h
MYDEREncoder.m
MYKey.m
MYKeychain-iPhone.m
MYOID.m
MYParsedCertificate.h
MYParsedCertificate.m
MYPrivateKey.h
MYPrivateKey.m
MYPublicKey.h
MYPublicKey.m
Tests/selfsigned cert parsed.txt
     1.1 --- a/MYASN1Object.h	Fri Jun 05 08:57:18 2009 -0700
     1.2 +++ b/MYASN1Object.h	Sat Jun 06 15:01:28 2009 -0700
     1.3 @@ -45,6 +45,9 @@
     1.4      The value contains the bytes of the integer, in big-endian order.
     1.5      This is mostly used internally by MYParsedCertificate. */
     1.6  @interface MYASN1BigInteger : MYASN1Object
     1.7 +- (id) initWithSignedData: (NSData*)signedData;
     1.8 +- (id) initWithUnsignedData: (NSData*) unsignedData;
     1.9 +@property (readonly) NSData *signedData, *unsignedData;
    1.10  @end
    1.11  
    1.12  
     2.1 --- a/MYASN1Object.m	Fri Jun 05 08:57:18 2009 -0700
     2.2 +++ b/MYASN1Object.m	Sat Jun 06 15:01:28 2009 -0700
     2.3 @@ -113,6 +113,46 @@
     2.4  
     2.5  @implementation MYASN1BigInteger
     2.6  
     2.7 +- (id) initWithSignedData: (NSData*)signedData {
     2.8 +    // Skip unnecessary leading 00 (if positive) or FF (if negative) bytes:
     2.9 +    const SInt8 *start = signedData.bytes, *last = start + signedData.length - 1;
    2.10 +    const SInt8 *pos = start;
    2.11 +    while (pos<last && ((pos[0]==0 && pos[1]>=0) || (pos[0]==-1 && pos[1]<0)))
    2.12 +        pos++;
    2.13 +    if (pos > start)
    2.14 +        signedData = [NSData dataWithBytes: pos length: last-pos+1];
    2.15 +    return [self initWithTag: 2 ofClass: 0 constructed: NO value: signedData];
    2.16 +}
    2.17 +
    2.18 +- (id) initWithUnsignedData: (NSData*) unsignedData {
    2.19 +    const UInt8 *start = unsignedData.bytes;
    2.20 +    if (*start >= 0x80) {
    2.21 +        // Prefix with 00 byte so high bit isn't misinterpreted as a sign bit:
    2.22 +        NSMutableData *fixedData = [NSMutableData dataWithCapacity: unsignedData.length + 1];
    2.23 +        UInt8 zero = 0;
    2.24 +        [fixedData appendBytes: &zero length: 1];
    2.25 +        [fixedData appendData: unsignedData];
    2.26 +        unsignedData = fixedData;
    2.27 +    }
    2.28 +    return [self initWithSignedData: unsignedData];
    2.29 +}
    2.30 +
    2.31 +- (NSData*) signedData {
    2.32 +    return self.value;
    2.33 +}
    2.34 +
    2.35 +- (NSData*) unsignedData {
    2.36 +    // Strip any leading zero bytes that were inserted for sign-bit padding:
    2.37 +    NSData *data = self.value;
    2.38 +    const UInt8 *start = data.bytes, *last = start + data.length - 1;
    2.39 +    const UInt8 *pos = start;
    2.40 +    while (pos<last && *pos==0)
    2.41 +        pos++;
    2.42 +    if (pos > start)
    2.43 +        data = [NSData dataWithBytes: pos length: last-pos+1];
    2.44 +    return data;
    2.45 +}
    2.46 +
    2.47  @end
    2.48  
    2.49  
    2.50 @@ -158,3 +198,27 @@
    2.51  }
    2.52  
    2.53  @end
    2.54 +
    2.55 +
    2.56 +
    2.57 +/*
    2.58 + Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
    2.59 + 
    2.60 + Redistribution and use in source and binary forms, with or without modification, are permitted
    2.61 + provided that the following conditions are met:
    2.62 + 
    2.63 + * Redistributions of source code must retain the above copyright notice, this list of conditions
    2.64 + and the following disclaimer.
    2.65 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
    2.66 + and the following disclaimer in the documentation and/or other materials provided with the
    2.67 + distribution.
    2.68 + 
    2.69 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
    2.70 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
    2.71 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
    2.72 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    2.73 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
    2.74 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
    2.75 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
    2.76 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2.77 + */
     3.1 --- a/MYBERParser.m	Fri Jun 05 08:57:18 2009 -0700
     3.2 +++ b/MYBERParser.m	Sat Jun 06 15:01:28 2009 -0700
     3.3 @@ -350,3 +350,27 @@
     3.4      dump = [MYASN1Object dump: parsed];
     3.5      CAssert(dump);
     3.6  }
     3.7 +
     3.8 +
     3.9 +
    3.10 +/*
    3.11 + Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
    3.12 + 
    3.13 + Redistribution and use in source and binary forms, with or without modification, are permitted
    3.14 + provided that the following conditions are met:
    3.15 + 
    3.16 + * Redistributions of source code must retain the above copyright notice, this list of conditions
    3.17 + and the following disclaimer.
    3.18 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
    3.19 + and the following disclaimer in the documentation and/or other materials provided with the
    3.20 + distribution.
    3.21 + 
    3.22 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
    3.23 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
    3.24 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
    3.25 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    3.26 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
    3.27 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
    3.28 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
    3.29 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    3.30 + */
     4.1 --- a/MYCertGen.m	Fri Jun 05 08:57:18 2009 -0700
     4.2 +++ b/MYCertGen.m	Sat Jun 06 15:01:28 2009 -0700
     4.3 @@ -495,3 +495,27 @@
     4.4      
     4.5      CAssert([cert setUserTrust: kSecTrustResultProceed]);
     4.6  }
     4.7 +
     4.8 +
     4.9 +
    4.10 +/*
    4.11 + Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
    4.12 + 
    4.13 + Redistribution and use in source and binary forms, with or without modification, are permitted
    4.14 + provided that the following conditions are met:
    4.15 + 
    4.16 + * Redistributions of source code must retain the above copyright notice, this list of conditions
    4.17 + and the following disclaimer.
    4.18 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
    4.19 + and the following disclaimer in the documentation and/or other materials provided with the
    4.20 + distribution.
    4.21 + 
    4.22 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
    4.23 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
    4.24 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
    4.25 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    4.26 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
    4.27 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
    4.28 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
    4.29 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    4.30 + */
     5.1 --- a/MYCertificate-iPhone.m	Fri Jun 05 08:57:18 2009 -0700
     5.2 +++ b/MYCertificate-iPhone.m	Sat Jun 06 15:01:28 2009 -0700
     5.3 @@ -7,6 +7,7 @@
     5.4  //
     5.5  
     5.6  #import "MYCertificate.h"
     5.7 +#import "MYCertificateInfo.h"
     5.8  #import "MYCrypto_Private.h"
     5.9  
    5.10  #if MYCRYPTO_USE_IPHONE_API
    5.11 @@ -37,6 +38,12 @@
    5.12      return self;
    5.13  }
    5.14  
    5.15 +- (void) dealloc
    5.16 +{
    5.17 +    [_info release];
    5.18 +    [super dealloc];
    5.19 +}
    5.20 +
    5.21  
    5.22  - (BOOL)isEqualToCertificate:(MYCertificate*)cert {
    5.23      return [self isEqual: cert] || [self.certificateData isEqual: cert.certificateData];
    5.24 @@ -69,6 +76,21 @@
    5.25      return key;
    5.26  }
    5.27  
    5.28 +- (MYIdentity*) identity {
    5.29 +    return [self.keychain identityWithDigest: self.publicKey.publicKeyDigest];
    5.30 +}
    5.31 +
    5.32 +
    5.33 +- (MYCertificateInfo*) info {
    5.34 +    if (!_info) {
    5.35 +        NSError *error;
    5.36 +        _info = [[MYCertificateInfo alloc] initWithCertificateData: self.certificateData
    5.37 +                                                             error: &error];
    5.38 +        if (!_info)
    5.39 +            Warn(@"Couldn't parse certificate %@: %@", self, error);
    5.40 +    }
    5.41 +    return _info;
    5.42 +}
    5.43  
    5.44  - (NSString*) commonName {
    5.45      CFStringRef name = SecCertificateCopySubjectSummary(_certificateRef);
     6.1 --- a/MYCertificate.h	Fri Jun 05 08:57:18 2009 -0700
     6.2 +++ b/MYCertificate.h	Sat Jun 06 15:01:28 2009 -0700
     6.3 @@ -12,13 +12,14 @@
     6.4  #import <Security/cssmtype.h>
     6.5  #endif
     6.6  
     6.7 -@class MYPublicKey, MYIdentity;
     6.8 +@class MYPublicKey, MYIdentity, MYCertificateInfo;
     6.9  
    6.10  
    6.11  /** An X.509 certificate. */
    6.12  @interface MYCertificate : MYKeychainItem {
    6.13      @private
    6.14      SecCertificateRef _certificateRef;
    6.15 +    MYCertificateInfo *_info;
    6.16  }
    6.17  
    6.18  /** Creates a MYCertificate object for an existing Keychain certificate reference. */
    6.19 @@ -42,7 +43,13 @@
    6.20  /** The certificate's public key. */
    6.21  @property (readonly) MYPublicKey *publicKey;
    6.22  
    6.23 -/** The name of the subject (owner) of the certificate. */
    6.24 +/** The Identity (if any) that this Certificate is part of. */
    6.25 +@property (readonly) MYIdentity *identity;
    6.26 +
    6.27 +/** The metadata of the certificate, like the subject name and expiration date. */
    6.28 +@property (readonly) MYCertificateInfo *info;
    6.29 +
    6.30 +/** The common name of the subject (owner) of the certificate. */
    6.31  @property (readonly) NSString *commonName;
    6.32  
    6.33  
    6.34 @@ -57,9 +64,6 @@
    6.35                            type: (CSSM_CERT_TYPE) type
    6.36                        encoding: (CSSM_CERT_ENCODING) encoding;
    6.37  
    6.38 -/** The Identity (if any) that this Certificate is part of. */
    6.39 -@property (readonly) MYIdentity *identity;
    6.40 -
    6.41  /** The list (if any) of the subject's email addresses. */
    6.42  @property (readonly) NSArray *emailAddresses;
    6.43  
     7.1 --- a/MYCertificate.m	Fri Jun 05 08:57:18 2009 -0700
     7.2 +++ b/MYCertificate.m	Sat Jun 06 15:01:28 2009 -0700
     7.3 @@ -10,6 +10,7 @@
     7.4  #import "MYCrypto_Private.h"
     7.5  #import "MYIdentity.h"
     7.6  #import "MYDigest.h"
     7.7 +#import "MYCertificateInfo.h"
     7.8  #import "MYErrorUtils.h"
     7.9  
    7.10  #if !MYCRYPTO_USE_IPHONE_API
    7.11 @@ -55,6 +56,13 @@
    7.12                                  encoding: CSSM_CERT_ENCODING_BER];
    7.13  }
    7.14  
    7.15 +- (void) dealloc
    7.16 +{
    7.17 +    [_info release];
    7.18 +    [super dealloc];
    7.19 +}
    7.20 +
    7.21 +
    7.22  
    7.23  - (NSString*) description {
    7.24      return $sprintf(@"%@[%@ %@/%p]", 
    7.25 @@ -108,6 +116,17 @@
    7.26      return [[[MYIdentity alloc] initWithCertificateRef: _certificateRef] autorelease];
    7.27  }
    7.28  
    7.29 +- (MYCertificateInfo*) info {
    7.30 +    if (!_info) {
    7.31 +        NSError *error;
    7.32 +        _info = [[MYCertificateInfo alloc] initWithCertificateData: self.certificateData
    7.33 +                                                             error: &error];
    7.34 +        if (!_info)
    7.35 +            Warn(@"Couldn't parse certificate %@: %@", self, error);
    7.36 +    }
    7.37 +    return _info;
    7.38 +}
    7.39 +
    7.40  - (NSString*) commonName {
    7.41      CFStringRef name = NULL;
    7.42      if (!check(SecCertificateCopyCommonName(_certificateRef, &name),
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/MYCertificateInfo.h	Sat Jun 06 15:01:28 2009 -0700
     8.3 @@ -0,0 +1,111 @@
     8.4 +//
     8.5 +//  MYCertificateInfo.h
     8.6 +//  MYCrypto
     8.7 +//
     8.8 +//  Created by Jens Alfke on 6/2/09.
     8.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
    8.10 +//
    8.11 +
    8.12 +#import <Foundation/Foundation.h>
    8.13 +@class MYCertificateName, MYCertificate, MYIdentity, MYPublicKey, MYPrivateKey, MYOID;
    8.14 +
    8.15 +/** A parsed X.509 certificate; provides access to the names and metadata. */
    8.16 +@interface MYCertificateInfo : NSObject 
    8.17 +{
    8.18 +    @private
    8.19 +    NSArray *_root;
    8.20 +}
    8.21 +
    8.22 +/** Initialize by parsing X.509 certificate data.
    8.23 +    (More commonly you'll get an instance via MYCertificate's 'info' property.) */
    8.24 +- (id) initWithCertificateData: (NSData*)data error: (NSError**)outError;
    8.25 +
    8.26 +/** The date/time at which the certificate first becomes valid. */
    8.27 +@property (retain, readonly) NSDate *validFrom;
    8.28 +
    8.29 +/** The date/time at which the certificate expires. */
    8.30 +@property (retain, readonly) NSDate *validTo;
    8.31 +
    8.32 +/** Information about the identity of the owner of this certificate. */
    8.33 +@property (readonly) MYCertificateName *subject;
    8.34 +
    8.35 +/** Information about the identity that signed/authorized this certificate. */
    8.36 +@property (readonly) MYCertificateName *issuer;
    8.37 +
    8.38 +/** Returns YES if the issuer is the same as the subject. (Aka a "self-signed" certificate.) */
    8.39 +@property (readonly) BOOL isRoot;
    8.40 +
    8.41 +@end
    8.42 +
    8.43 +
    8.44 +
    8.45 +@interface MYCertificateRequest : MYCertificateInfo
    8.46 +{
    8.47 +    @private
    8.48 +    MYPublicKey *_publicKey;
    8.49 +}
    8.50 +
    8.51 +/** Initializes a blank instance which can be used to create a new certificate.
    8.52 +    The certificate will not contain anything yet other than the public key.
    8.53 +    The desired attributes should be set, and then the -selfSignWithPrivateKey:error method called. */
    8.54 +- (id) initWithPublicKey: (MYPublicKey*)pubKey;
    8.55 +
    8.56 +/** The date/time at which the certificate first becomes valid. Settable. */
    8.57 +@property (retain) NSDate *validFrom;
    8.58 +
    8.59 +/** The date/time at which the certificate expires. Settable */
    8.60 +@property (retain) NSDate *validTo;
    8.61 +
    8.62 +/** Encodes the certificate request in X.509 format -- this is NOT a certificate!
    8.63 +    It has to be sent to a Certificate Authority to be signed.
    8.64 +    If you want to generate a self-signed certificate, use one of the self-signing methods instead. */
    8.65 +- (NSData*) requestData: (NSError**)outError;
    8.66 +
    8.67 +/** Signs the certificate using the given private key, which must be the counterpart of the
    8.68 +    public key stored in the certificate, and returns the encoded certificate data.
    8.69 +    The subject attributes will be copied to the issuer attributes.
    8.70 +    If no valid date range has been set yet, it will be set to a range of one year starting from
    8.71 +    the current time.
    8.72 +    A unique serial number based on the current time will be set. */
    8.73 +- (NSData*) selfSignWithPrivateKey: (MYPrivateKey*)privateKey error: (NSError**)outError;
    8.74 +
    8.75 +/** Signs the certificate using the given private key, which must be the counterpart of the
    8.76 +    public key stored in the certificate; adds the certificate to the keychain;
    8.77 +    and returns a MYIdentity representing the paired certificate and private key. */
    8.78 +- (MYIdentity*) createSelfSignedIdentityWithPrivateKey: (MYPrivateKey*)privateKey
    8.79 +                                                 error: (NSError**)outError;
    8.80 +@end
    8.81 +
    8.82 +
    8.83 +
    8.84 +/** An X.509 Name structure, describing the subject or issuer of a certificate.
    8.85 +    The properties are settable only if this instance belongs to a MYCertificateRequest;
    8.86 +    otherwise trying to set them will raise an exception. */
    8.87 +@interface MYCertificateName : NSObject
    8.88 +{
    8.89 +    @private
    8.90 +    NSArray *_components;
    8.91 +}
    8.92 +
    8.93 +/** The "common name" (nickname, whatever). */
    8.94 +@property (copy) NSString *commonName;
    8.95 +
    8.96 +/** The given/first name. */
    8.97 +@property (copy) NSString *givenName;
    8.98 +
    8.99 +/** The surname / last name / family name. */
   8.100 +@property (copy) NSString *surname;
   8.101 +
   8.102 +/** A description. */
   8.103 +@property (copy) NSString *nameDescription;
   8.104 +
   8.105 +/** The raw email address. */
   8.106 +@property (copy) NSString *emailAddress;
   8.107 +
   8.108 +/** Lower-level accessor that returns the value associated with the given OID. */
   8.109 +- (NSString*) stringForOID: (MYOID*)oid;
   8.110 +
   8.111 +/** Lower-level accessor that sets the value associated with the given OID. */
   8.112 +- (void) setString: (NSString*)value forOID: (MYOID*)oid;
   8.113 +
   8.114 +@end
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/MYCertificateInfo.m	Sat Jun 06 15:01:28 2009 -0700
     9.3 @@ -0,0 +1,458 @@
     9.4 +//
     9.5 +//  MYCertificateInfo.m
     9.6 +//  MYCrypto
     9.7 +//
     9.8 +//  Created by Jens Alfke on 6/2/09.
     9.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
    9.10 +//
    9.11 +
    9.12 +// References:
    9.13 +// <http://www.columbia.edu/~ariel/ssleay/layman.html> "Layman's Guide To ASN.1/BER/DER"
    9.14 +// <http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt> "X.509 Style Guide"
    9.15 +// <http://en.wikipedia.org/wiki/X.509> Wikipedia article on X.509
    9.16 +
    9.17 +
    9.18 +#import "MYCertificateInfo.h"
    9.19 +#import "MYCrypto.h"
    9.20 +#import "MYASN1Object.h"
    9.21 +#import "MYOID.h"
    9.22 +#import "MYBERParser.h"
    9.23 +#import "MYDEREncoder.h"
    9.24 +#import "MYErrorUtils.h"
    9.25 +
    9.26 +
    9.27 +#define kDefaultExpirationTime (60.0 * 60.0 * 24.0 * 365.0)
    9.28 +
    9.29 +
    9.30 +static id $atIf(NSArray *array, NSUInteger index) {
    9.31 +    return index < array.count ?[array objectAtIndex: index] :nil;
    9.32 +}
    9.33 +
    9.34 +
    9.35 +@interface MYCertificateName ()
    9.36 +- (id) _initWithComponents: (NSArray*)components;
    9.37 +@end
    9.38 +
    9.39 +@interface MYCertificateInfo ()
    9.40 +@property (retain) NSArray *_root;
    9.41 +@end
    9.42 +
    9.43 +
    9.44 +#pragma mark -
    9.45 +@implementation MYCertificateInfo
    9.46 +
    9.47 +
    9.48 +static MYOID *kRSAAlgorithmID, *kRSAWithSHA1AlgorithmID, *kCommonNameOID,
    9.49 +            *kGivenNameOID, *kSurnameOID, *kDescriptionOID, *kEmailOID;
    9.50 +
    9.51 +
    9.52 ++ (void) initialize {
    9.53 +    if (!kEmailOID) {
    9.54 +        kRSAAlgorithmID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 1, 1,}
    9.55 +                                                      count: 7];
    9.56 +        kRSAWithSHA1AlgorithmID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 1, 5}
    9.57 +                                                              count: 7];
    9.58 +        kCommonNameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 3}
    9.59 +                                                     count: 4];
    9.60 +        kGivenNameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 42}
    9.61 +                                                    count: 4];
    9.62 +        kSurnameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 4}
    9.63 +                                                  count: 4];
    9.64 +        kDescriptionOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 13}
    9.65 +                                                count: 7];
    9.66 +        kEmailOID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 9, 1}
    9.67 +                                                count: 7];
    9.68 +    }
    9.69 +}
    9.70 +
    9.71 +
    9.72 +- (id) initWithRoot: (NSArray*)root
    9.73 +{
    9.74 +    self = [super init];
    9.75 +    if (self != nil) {
    9.76 +        _root = [root retain];
    9.77 +    }
    9.78 +    return self;
    9.79 +}
    9.80 +
    9.81 ++ (NSString*) validate: (id)root {
    9.82 +    NSArray *top = $castIf(NSArray,root);
    9.83 +    if (top.count < 3)
    9.84 +        return @"Too few top-level components";
    9.85 +    NSArray *info = $castIf(NSArray, [top objectAtIndex: 0]);
    9.86 +    if (info.count < 7)
    9.87 +        return @"Too few identity components";
    9.88 +    MYASN1Object *version = $castIf(MYASN1Object, [info objectAtIndex: 0]);
    9.89 +    if (!version || version.tag != 0)
    9.90 +        return @"Missing or invalid version";
    9.91 +    NSArray *versionComps = $castIf(NSArray, version.components);
    9.92 +    if (!versionComps || versionComps.count != 1)
    9.93 +        return @"Invalid version";
    9.94 +    NSNumber *versionNum = $castIf(NSNumber, [versionComps objectAtIndex: 0]);
    9.95 +    if (!versionNum || versionNum.intValue < 0 || versionNum.intValue > 2)
    9.96 +        return @"Unrecognized version number";
    9.97 +    return nil;
    9.98 +}
    9.99 +
   9.100 +
   9.101 +- (id) initWithCertificateData: (NSData*)data error: (NSError**)outError;
   9.102 +{
   9.103 +    if (outError) *outError = nil;
   9.104 +    id root = MYBERParse(data,outError);
   9.105 +    NSString *errorMsg = [[self class] validate: root];
   9.106 +    if (errorMsg) {
   9.107 +        if (outError && !*outError)
   9.108 +            *outError = MYError(2, MYASN1ErrorDomain, @"Invalid certificate: %@", errorMsg);
   9.109 +        [self release];
   9.110 +        return nil;
   9.111 +    }
   9.112 +
   9.113 +    return [self initWithRoot: root];
   9.114 +}
   9.115 +
   9.116 +- (void) dealloc
   9.117 +{
   9.118 +    [_root release];
   9.119 +    [super dealloc];
   9.120 +}
   9.121 +
   9.122 +- (BOOL) isEqual: (id)object {
   9.123 +    return [object isKindOfClass: [MYCertificateInfo class]]
   9.124 +        && [_root isEqual: ((MYCertificateInfo*)object)->_root];
   9.125 +}
   9.126 +
   9.127 +- (NSArray*) _info       {return $castIf(NSArray,$atIf(_root,0));}
   9.128 +
   9.129 +- (NSArray*) _validDates {return $castIf(NSArray, [self._info objectAtIndex: 4]);}
   9.130 +
   9.131 +@synthesize _root;
   9.132 +
   9.133 +
   9.134 +- (NSDate*) validFrom       {return $castIf(NSDate, $atIf(self._validDates, 0));}
   9.135 +- (NSDate*) validTo         {return $castIf(NSDate, $atIf(self._validDates, 1));}
   9.136 +
   9.137 +- (MYCertificateName*) subject {
   9.138 +    return [[[MYCertificateName alloc] _initWithComponents: [self._info objectAtIndex: 5]] autorelease];
   9.139 +}
   9.140 +
   9.141 +- (MYCertificateName*) issuer {
   9.142 +    return [[[MYCertificateName alloc] _initWithComponents: [self._info objectAtIndex: 3]] autorelease];
   9.143 +}
   9.144 +
   9.145 +- (BOOL) isSigned           {return [_root count] >= 3;}
   9.146 +
   9.147 +- (BOOL) isRoot {
   9.148 +    id issuer = $atIf(self._info,3);
   9.149 +    return $equal(issuer, $atIf(self._info,5)) || $equal(issuer, $array());
   9.150 +}
   9.151 +
   9.152 +
   9.153 +- (MYPublicKey*) subjectPublicKey {
   9.154 +    NSArray *keyInfo = $cast(NSArray, $atIf(self._info, 6));
   9.155 +    MYOID *keyAlgorithmID = $castIf(MYOID, $atIf($castIf(NSArray,$atIf(keyInfo,0)), 0));
   9.156 +    if (!$equal(keyAlgorithmID, kRSAAlgorithmID))
   9.157 +        return nil;
   9.158 +    MYBitString *keyData = $cast(MYBitString, $atIf(keyInfo, 1));
   9.159 +    if (!keyData) return nil;
   9.160 +    return [[[MYPublicKey alloc] initWithKeyData: keyData.bits] autorelease];
   9.161 +}
   9.162 +
   9.163 +@end
   9.164 +
   9.165 +
   9.166 +
   9.167 +
   9.168 +#pragma mark -
   9.169 +@implementation MYCertificateRequest
   9.170 +
   9.171 +- (id) initWithPublicKey: (MYPublicKey*)publicKey {
   9.172 +    Assert(publicKey);
   9.173 +    id empty = [NSNull null];
   9.174 +    id version = [[MYASN1Object alloc] initWithTag: 0 ofClass: 2 components: $array($object(0))];
   9.175 +    NSArray *root = $array( $marray(version,
   9.176 +                                    empty,       // serial #
   9.177 +                                    $array(kRSAAlgorithmID),
   9.178 +                                    $marray(),
   9.179 +                                    $marray(empty, empty),
   9.180 +                                    $marray(),
   9.181 +                                    $array( $array(kRSAAlgorithmID, empty),
   9.182 +                                           [MYBitString bitStringWithData: publicKey.keyData] ) ) );
   9.183 +    self = [super initWithRoot: root];
   9.184 +    [version release];
   9.185 +    return self;
   9.186 +}
   9.187 +
   9.188 +- (NSDate*) validFrom       {return [super validFrom];}
   9.189 +- (NSDate*) validTo         {return [super validTo];}
   9.190 +
   9.191 +- (void) setValidFrom: (NSDate*)validFrom {
   9.192 +    [(NSMutableArray*)self._validDates replaceObjectAtIndex: 0 withObject: validFrom];
   9.193 +}
   9.194 +
   9.195 +- (void) setValidTo: (NSDate*)validTo {
   9.196 +    [(NSMutableArray*)self._validDates replaceObjectAtIndex: 1 withObject: validTo];
   9.197 +}
   9.198 +
   9.199 +
   9.200 +- (void) fillInValues {
   9.201 +    NSMutableArray *info = (NSMutableArray*)self._info;
   9.202 +    // Set serial number if there isn't one yet:
   9.203 +    if (!$castIf(NSNumber, [info objectAtIndex: 1])) {
   9.204 +        UInt64 serial = floor(CFAbsoluteTimeGetCurrent() * 1000);
   9.205 +        [info replaceObjectAtIndex: 1 withObject: $object(serial)];
   9.206 +    }
   9.207 +    
   9.208 +    // Set up valid date range if there isn't one yet:
   9.209 +    NSDate *validFrom = self.validFrom;
   9.210 +    if (!validFrom)
   9.211 +        validFrom = self.validFrom = [NSDate date];
   9.212 +    NSDate *validTo = self.validTo;
   9.213 +    if (!validTo)
   9.214 +        self.validTo = [validFrom addTimeInterval: kDefaultExpirationTime]; 
   9.215 +}
   9.216 +
   9.217 +
   9.218 +- (NSData*) requestData: (NSError**)outError {
   9.219 +    [self fillInValues];
   9.220 +    return [MYDEREncoder encodeRootObject: self._info error: outError];
   9.221 +}
   9.222 +
   9.223 +
   9.224 +- (NSData*) selfSignWithPrivateKey: (MYPrivateKey*)privateKey 
   9.225 +                             error: (NSError**)outError 
   9.226 +{
   9.227 +    AssertEqual(privateKey.publicKey, _publicKey);  // Keys must form a pair
   9.228 +    
   9.229 +    // Copy subject to issuer:
   9.230 +    NSMutableArray *info = (NSMutableArray*)self._info;
   9.231 +    [info replaceObjectAtIndex: 3 withObject: [info objectAtIndex: 5]];
   9.232 +    
   9.233 +    // Sign the request:
   9.234 +    NSData *dataToSign = [self requestData: outError];
   9.235 +    if (!dataToSign)
   9.236 +        return nil;
   9.237 +    MYBitString *signature = [MYBitString bitStringWithData: [privateKey signData: dataToSign]];
   9.238 +    
   9.239 +    // Generate and encode the certificate:
   9.240 +    NSArray *root = $array(info, 
   9.241 +                           $array(kRSAWithSHA1AlgorithmID, [NSNull null]),
   9.242 +                           signature);
   9.243 +    return [MYDEREncoder encodeRootObject: root error: outError];
   9.244 +}
   9.245 +
   9.246 +
   9.247 +- (MYIdentity*) createSelfSignedIdentityWithPrivateKey: (MYPrivateKey*)privateKey
   9.248 +                                                 error: (NSError**)outError
   9.249 +{
   9.250 +    NSData *certData = [self selfSignWithPrivateKey: privateKey error: outError];
   9.251 +    if (!certData)
   9.252 +        return nil;
   9.253 +    MYCertificate *cert = [privateKey.keychain importCertificate: certData];
   9.254 +    Assert(cert!=nil);
   9.255 +    MYIdentity *identity = cert.identity;
   9.256 +    Assert(identity!=nil);
   9.257 +    return identity;
   9.258 +}
   9.259 +
   9.260 +
   9.261 +@end
   9.262 +
   9.263 +
   9.264 +
   9.265 +#pragma mark -
   9.266 +@implementation MYCertificateName
   9.267 +
   9.268 +- (id) _initWithComponents: (NSArray*)components
   9.269 +{
   9.270 +    self = [super init];
   9.271 +    if (self != nil) {
   9.272 +        _components = [components retain];
   9.273 +    }
   9.274 +    return self;
   9.275 +}
   9.276 +
   9.277 +- (void) dealloc
   9.278 +{
   9.279 +    [_components release];
   9.280 +    [super dealloc];
   9.281 +}
   9.282 +
   9.283 +- (BOOL) isEqual: (id)object {
   9.284 +    return [object isKindOfClass: [MYCertificateName class]]
   9.285 +        && [_components isEqual: ((MYCertificateName*)object)->_components];
   9.286 +}
   9.287 +
   9.288 +- (NSArray*) _pairForOID: (MYOID*)oid {
   9.289 +    for (id nameEntry in _components) {
   9.290 +        for (id pair in $castIf(NSSet,nameEntry)) {
   9.291 +            if ([pair isKindOfClass: [NSArray class]] && [pair count] == 2) {
   9.292 +                if ($equal(oid, [pair objectAtIndex: 0]))
   9.293 +                    return pair;
   9.294 +            }
   9.295 +        }
   9.296 +    }
   9.297 +    return nil;
   9.298 +}
   9.299 +
   9.300 +- (NSString*) stringForOID: (MYOID*)oid {
   9.301 +    return [[self _pairForOID: oid] objectAtIndex: 1];
   9.302 +}
   9.303 +
   9.304 +- (void) setString: (NSString*)value forOID: (MYOID*)oid {
   9.305 +    NSMutableArray *pair = (NSMutableArray*) [self _pairForOID: oid];
   9.306 +    if (pair)
   9.307 +        [pair replaceObjectAtIndex: 1 withObject: value];
   9.308 +    else
   9.309 +        [(NSMutableArray*)_components addObject: [NSSet setWithObject: $marray(oid,value)]];
   9.310 +}
   9.311 +
   9.312 +- (NSString*) commonName    {return [self stringForOID: kCommonNameOID];}
   9.313 +- (NSString*) givenName     {return [self stringForOID: kGivenNameOID];}
   9.314 +- (NSString*) surname       {return [self stringForOID: kSurnameOID];}
   9.315 +- (NSString*) nameDescription {return [self stringForOID: kDescriptionOID];}
   9.316 +- (NSString*) emailAddress  {return [self stringForOID: kEmailOID];}
   9.317 +
   9.318 +- (void) setCommonName: (NSString*)commonName   {[self setString: commonName forOID: kCommonNameOID];}
   9.319 +- (void) setGivenName: (NSString*)givenName     {[self setString: givenName forOID: kGivenNameOID];}
   9.320 +- (void) setSurname: (NSString*)surname         {[self setString: surname forOID: kSurnameOID];}
   9.321 +- (void) setNameDescription: (NSString*)desc    {[self setString: desc forOID: kDescriptionOID];}
   9.322 +- (void) setEmailAddress: (NSString*)email      {[self setString: email forOID: kEmailOID];}
   9.323 +
   9.324 +
   9.325 +@end
   9.326 +
   9.327 +
   9.328 +
   9.329 +#pragma mark -
   9.330 +#pragma mark TEST CASES:
   9.331 +
   9.332 +#if DEBUG
   9.333 +
   9.334 +
   9.335 +static MYCertificateInfo* testCert(NSString *filename, BOOL selfSigned) {
   9.336 +    Log(@"--- Creating MYCertificateInfo from %@", filename);
   9.337 +    NSData *certData = [NSData dataWithContentsOfFile: filename];
   9.338 +    //Log(@"Cert Data =\n%@", certData);
   9.339 +    NSError *error = nil;
   9.340 +    MYCertificateInfo *pcert = [[MYCertificateInfo alloc] initWithCertificateData: certData 
   9.341 +                                                                            error: &error];
   9.342 +    CAssertNil(error);
   9.343 +    CAssert(pcert != nil);
   9.344 +    
   9.345 +    CAssertEq(pcert.isRoot, selfSigned);
   9.346 +        
   9.347 +    Log(@"Subject Public Key = %@", pcert.subjectPublicKey);
   9.348 +    CAssert(pcert.subjectPublicKey);
   9.349 +    MYCertificateName *subject = pcert.subject;
   9.350 +    Log(@"Common Name = %@", subject.commonName);
   9.351 +    Log(@"Given Name  = %@", subject.givenName);
   9.352 +    Log(@"Surname     = %@", subject.surname);
   9.353 +    Log(@"Desc        = %@", subject.nameDescription);
   9.354 +    Log(@"Email       = %@", subject.emailAddress);
   9.355 +    CAssert(subject.commonName);
   9.356 +    
   9.357 +    // Now go through MYCertificate:
   9.358 +    MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData];
   9.359 +    CAssert(cert);
   9.360 +    CAssertEqual(cert.info, pcert);
   9.361 +    
   9.362 +    return pcert;
   9.363 +}
   9.364 +
   9.365 +
   9.366 +TestCase(ParsedCert) {
   9.367 +    testCert(@"../../Tests/selfsigned.cer", YES);
   9.368 +    testCert(@"../../Tests/iphonedev.cer", NO);
   9.369 +}
   9.370 +
   9.371 +
   9.372 +#import "MYCrypto_Private.h"
   9.373 +
   9.374 +TestCase(CreateCert) {
   9.375 +    MYPrivateKey *privateKey = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 512];
   9.376 +    CAssert(privateKey);
   9.377 +    MYIdentity *identity = nil;
   9.378 +    @try{
   9.379 +        MYCertificateRequest *pcert = [[MYCertificateRequest alloc] initWithPublicKey: privateKey.publicKey];
   9.380 +        MYCertificateName *subject = pcert.subject;
   9.381 +        subject.commonName = @"testcase";
   9.382 +        subject.givenName = @"Test";
   9.383 +        subject.surname = @"Case";
   9.384 +        subject.nameDescription = @"Just a test certificate created by MYCrypto";
   9.385 +        subject.emailAddress = @"testcase@example.com";
   9.386 +
   9.387 +        subject = pcert.subject;
   9.388 +        CAssertEqual(subject.commonName, @"testcase");
   9.389 +        CAssertEqual(subject.givenName, @"Test");
   9.390 +        CAssertEqual(subject.surname, @"Case");
   9.391 +        CAssertEqual(subject.nameDescription, @"Just a test certificate created by MYCrypto");
   9.392 +        CAssertEqual(subject.emailAddress, @"testcase@example.com");
   9.393 +        
   9.394 +        Log(@"Signing...");
   9.395 +        NSError *error;
   9.396 +        NSData *certData = [pcert selfSignWithPrivateKey: privateKey error: &error];
   9.397 +        Log(@"Generated cert = \n%@", certData);
   9.398 +        CAssert(certData);
   9.399 +        CAssertNil(error);
   9.400 +        CAssert(certData);
   9.401 +        [certData writeToFile: @"../../Tests/generated.cer" atomically: YES];
   9.402 +        MYCertificateInfo *pcert2 = testCert(@"../../Tests/generated.cer", YES);
   9.403 +        
   9.404 +        Log(@"Verifying Info...");
   9.405 +        MYCertificateName *subject2 = pcert2.subject;
   9.406 +        CAssertEqual(subject2,subject);
   9.407 +        CAssertEqual(subject2.commonName, @"testcase");
   9.408 +        CAssertEqual(subject2.givenName, @"Test");
   9.409 +        CAssertEqual(subject2.surname, @"Case");
   9.410 +        CAssertEqual(subject2.nameDescription, @"Just a test certificate created by MYCrypto");
   9.411 +        CAssertEqual(subject2.emailAddress, @"testcase@example.com");
   9.412 +        
   9.413 +        Log(@"Verifying Signature...");
   9.414 +        MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData];
   9.415 +        Log(@"Loaded %@", cert);
   9.416 +        CAssert(cert);
   9.417 +        MYPublicKey *certKey = cert.publicKey;
   9.418 +        Log(@"Its public key = %@", certKey);
   9.419 +        CAssertEqual(certKey.keyData, privateKey.publicKey.keyData);
   9.420 +        
   9.421 +        Log(@"Creating Identity...");
   9.422 +        identity = [pcert createSelfSignedIdentityWithPrivateKey: privateKey error: &error];
   9.423 +        Log(@"Identity = %@", identity);
   9.424 +        CAssert(identity);
   9.425 +        CAssertNil(error);
   9.426 +        CAssertEqual(identity.keychain, [MYKeychain defaultKeychain]);
   9.427 +        CAssertEqual(identity.privateKey, privateKey);
   9.428 +        CAssert([identity isEqualToCertificate: cert]);
   9.429 +        
   9.430 +        [pcert release];
   9.431 +        
   9.432 +    } @finally {
   9.433 +        [privateKey removeFromKeychain];
   9.434 +        [identity removeFromKeychain];
   9.435 +    }
   9.436 +}
   9.437 +
   9.438 +#endif
   9.439 +
   9.440 +
   9.441 +/*
   9.442 + Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   9.443 + 
   9.444 + Redistribution and use in source and binary forms, with or without modification, are permitted
   9.445 + provided that the following conditions are met:
   9.446 + 
   9.447 + * Redistributions of source code must retain the above copyright notice, this list of conditions
   9.448 + and the following disclaimer.
   9.449 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   9.450 + and the following disclaimer in the documentation and/or other materials provided with the
   9.451 + distribution.
   9.452 + 
   9.453 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   9.454 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   9.455 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   9.456 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   9.457 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   9.458 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   9.459 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   9.460 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   9.461 + */
    10.1 --- a/MYCrypto-iPhone.xcodeproj/project.pbxproj	Fri Jun 05 08:57:18 2009 -0700
    10.2 +++ b/MYCrypto-iPhone.xcodeproj/project.pbxproj	Sat Jun 06 15:01:28 2009 -0700
    10.3 @@ -16,7 +16,6 @@
    10.4  		273392120F8283B8009414D9 /* MYKeychain-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 273392110F8283B8009414D9 /* MYKeychain-iPhone.m */; };
    10.5  		274110090F99234100AD413F /* MYSymmetricKey-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 274110080F99234100AD413F /* MYSymmetricKey-iPhone.m */; };
    10.6  		2748607F0F8D5E0600FE617B /* MYPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 2748607E0F8D5E0600FE617B /* MYPrivateKey.m */; };
    10.7 -		275D9FEE0FD8795300D85A86 /* MYParsedCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 275D9FE40FD8795300D85A86 /* MYParsedCertificate.m */; };
    10.8  		275D9FEF0FD8795300D85A86 /* MYASN1Object.m in Sources */ = {isa = PBXBuildFile; fileRef = 275D9FE60FD8795300D85A86 /* MYASN1Object.m */; };
    10.9  		275D9FF00FD8795300D85A86 /* MYBERParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 275D9FE80FD8795300D85A86 /* MYBERParser.m */; };
   10.10  		275D9FF10FD8795300D85A86 /* MYDEREncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 275D9FEA0FD8795300D85A86 /* MYDEREncoder.m */; };
   10.11 @@ -28,6 +27,7 @@
   10.12  		276FB34B0F856CA400CB326E /* MYCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB34A0F856CA400CB326E /* MYCertificate.m */; };
   10.13  		27A430120F87C6C10063D362 /* MYKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E823110F81D56E0019BE60 /* MYKey.m */; };
   10.14  		27A430140F87C6D50063D362 /* MYSymmetricKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A430130F87C6D50063D362 /* MYSymmetricKey.m */; };
   10.15 +		27CD85DD0FDB1A82006BCB47 /* MYCertificateInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CD85DC0FDB1A82006BCB47 /* MYCertificateInfo.m */; };
   10.16  		27E3A6AA0F91B8B30079D4D9 /* MYCryptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E3A6A70F91B8B30079D4D9 /* MYCryptor.m */; };
   10.17  		27E823240F81D56E0019BE60 /* MYKeychainItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E823150F81D56E0019BE60 /* MYKeychainItem.m */; };
   10.18  		27E823270F81D56E0019BE60 /* MYDigest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E8231C0F81D56E0019BE60 /* MYDigest.m */; };
   10.19 @@ -57,8 +57,6 @@
   10.20  		274110080F99234100AD413F /* MYSymmetricKey-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYSymmetricKey-iPhone.m"; sourceTree = "<group>"; };
   10.21  		2748607D0F8D5DF200FE617B /* MYPrivateKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYPrivateKey.h; sourceTree = "<group>"; };
   10.22  		2748607E0F8D5E0600FE617B /* MYPrivateKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPrivateKey.m; sourceTree = "<group>"; };
   10.23 -		275D9FE30FD8795300D85A86 /* MYParsedCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYParsedCertificate.h; sourceTree = "<group>"; };
   10.24 -		275D9FE40FD8795300D85A86 /* MYParsedCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYParsedCertificate.m; sourceTree = "<group>"; };
   10.25  		275D9FE50FD8795300D85A86 /* MYASN1Object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYASN1Object.h; sourceTree = "<group>"; };
   10.26  		275D9FE60FD8795300D85A86 /* MYASN1Object.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYASN1Object.m; sourceTree = "<group>"; };
   10.27  		275D9FE70FD8795300D85A86 /* MYBERParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYBERParser.h; sourceTree = "<group>"; };
   10.28 @@ -75,6 +73,8 @@
   10.29  		27A430130F87C6D50063D362 /* MYSymmetricKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYSymmetricKey.m; sourceTree = "<group>"; };
   10.30  		27A430150F87C6DB0063D362 /* MYSymmetricKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYSymmetricKey.h; sourceTree = "<group>"; };
   10.31  		27AAD9710F8927DB0064DD7C /* MYCryptoConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCryptoConfig.h; sourceTree = "<group>"; };
   10.32 +		27CD85DB0FDB1A7D006BCB47 /* MYCertificateInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCertificateInfo.h; sourceTree = "<group>"; };
   10.33 +		27CD85DC0FDB1A82006BCB47 /* MYCertificateInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertificateInfo.m; sourceTree = "<group>"; };
   10.34  		27E3A6A60F91B8B30079D4D9 /* MYCryptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCryptor.h; sourceTree = "<group>"; };
   10.35  		27E3A6A70F91B8B30079D4D9 /* MYCryptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCryptor.m; sourceTree = "<group>"; };
   10.36  		27E8230C0F81D56E0019BE60 /* MYCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCertificate.h; sourceTree = "<group>"; };
   10.37 @@ -145,8 +145,8 @@
   10.38  		275D9FE00FD8795300D85A86 /* Certificates */ = {
   10.39  			isa = PBXGroup;
   10.40  			children = (
   10.41 -				275D9FE30FD8795300D85A86 /* MYParsedCertificate.h */,
   10.42 -				275D9FE40FD8795300D85A86 /* MYParsedCertificate.m */,
   10.43 +				27CD85DB0FDB1A7D006BCB47 /* MYCertificateInfo.h */,
   10.44 +				27CD85DC0FDB1A82006BCB47 /* MYCertificateInfo.m */,
   10.45  				275D9FE50FD8795300D85A86 /* MYASN1Object.h */,
   10.46  				275D9FE60FD8795300D85A86 /* MYASN1Object.m */,
   10.47  				275D9FE70FD8795300D85A86 /* MYBERParser.h */,
   10.48 @@ -323,11 +323,11 @@
   10.49  				27059CF30F8F0F9200A8422F /* MYIdentity.m in Sources */,
   10.50  				27E3A6AA0F91B8B30079D4D9 /* MYCryptor.m in Sources */,
   10.51  				274110090F99234100AD413F /* MYSymmetricKey-iPhone.m in Sources */,
   10.52 -				275D9FEE0FD8795300D85A86 /* MYParsedCertificate.m in Sources */,
   10.53  				275D9FEF0FD8795300D85A86 /* MYASN1Object.m in Sources */,
   10.54  				275D9FF00FD8795300D85A86 /* MYBERParser.m in Sources */,
   10.55  				275D9FF10FD8795300D85A86 /* MYDEREncoder.m in Sources */,
   10.56  				275D9FF20FD8795300D85A86 /* MYOID.m in Sources */,
   10.57 +				27CD85DD0FDB1A82006BCB47 /* MYCertificateInfo.m in Sources */,
   10.58  			);
   10.59  			runOnlyForDeploymentPostprocessing = 0;
   10.60  		};
    11.1 --- a/MYCrypto.xcodeproj/project.pbxproj	Fri Jun 05 08:57:18 2009 -0700
    11.2 +++ b/MYCrypto.xcodeproj/project.pbxproj	Sat Jun 06 15:01:28 2009 -0700
    11.3 @@ -39,18 +39,15 @@
    11.4  		2706F1C70F9D3C8A00292CCF /* MYDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 27059D520F8F9BB500A8422F /* MYDecoder.m */; };
    11.5  		2706F1C80F9D3C8B00292CCF /* MYEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 27059D4F0F8F9BB500A8422F /* MYEncoder.h */; };
    11.6  		2706F1C90F9D3C8B00292CCF /* MYEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 27059D500F8F9BB500A8422F /* MYEncoder.m */; };
    11.7 -		2706F1CA0F9D3C9200292CCF /* MYCertGen.h in Headers */ = {isa = PBXBuildFile; fileRef = 27A42ECC0F8689D30063D362 /* MYCertGen.h */; };
    11.8 -		2706F1CB0F9D3C9300292CCF /* MYCertGen.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A42ECD0F8689D30063D362 /* MYCertGen.m */; };
    11.9  		270A7A730FD58FF200770C4D /* MYBERParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 270A7A710FD58FF200770C4D /* MYBERParser.h */; };
   11.10  		270A7A740FD58FF200770C4D /* MYBERParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 270A7A720FD58FF200770C4D /* MYBERParser.m */; };
   11.11  		270A7A750FD58FF200770C4D /* MYBERParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 270A7A720FD58FF200770C4D /* MYBERParser.m */; };
   11.12  		270B879F0F8C565000C56781 /* MYPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 270B879E0F8C565000C56781 /* MYPrivateKey.m */; };
   11.13  		27410FF00F99200A00AD413F /* MYSymmetricKey-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 27410FEF0F99200A00AD413F /* MYSymmetricKey-iPhone.m */; };
   11.14 -		274861D50F8E4B5200FE617B /* MYCertGen.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A42ECD0F8689D30063D362 /* MYCertGen.m */; };
   11.15  		274863A20F8EF39400FE617B /* MYIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 274863A10F8EF39400FE617B /* MYIdentity.m */; };
   11.16 -		275D9D920FD5FB4100D85A86 /* MYParsedCertificate.h in Headers */ = {isa = PBXBuildFile; fileRef = 275D9D900FD5FB4100D85A86 /* MYParsedCertificate.h */; };
   11.17 -		275D9D930FD5FB4100D85A86 /* MYParsedCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 275D9D910FD5FB4100D85A86 /* MYParsedCertificate.m */; };
   11.18 -		275D9D940FD5FB4100D85A86 /* MYParsedCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 275D9D910FD5FB4100D85A86 /* MYParsedCertificate.m */; };
   11.19 +		275DA1270FD980D400D85A86 /* MYCertificateInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 275DA1250FD980D400D85A86 /* MYCertificateInfo.h */; };
   11.20 +		275DA1280FD980D400D85A86 /* MYCertificateInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 275DA1260FD980D400D85A86 /* MYCertificateInfo.m */; };
   11.21 +		275DA1290FD980D400D85A86 /* MYCertificateInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 275DA1260FD980D400D85A86 /* MYCertificateInfo.m */; };
   11.22  		27A42CBF0F8578B40063D362 /* MYCryptoTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A42CBE0F8578B40063D362 /* MYCryptoTest.m */; };
   11.23  		27A42D1E0F8586CE0063D362 /* MYKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E822A10F81C5660019BE60 /* MYKey.m */; };
   11.24  		27A42D420F858ED80063D362 /* MYSymmetricKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A42D410F858ED80063D362 /* MYSymmetricKey.m */; };
   11.25 @@ -111,13 +108,11 @@
   11.26  		2748604D0F8D5C4C00FE617B /* MYCrypto_Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYCrypto_Release.xcconfig; sourceTree = "<group>"; };
   11.27  		274863A00F8EF39400FE617B /* MYIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYIdentity.h; sourceTree = "<group>"; };
   11.28  		274863A10F8EF39400FE617B /* MYIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYIdentity.m; sourceTree = "<group>"; };
   11.29 -		275D9D900FD5FB4100D85A86 /* MYParsedCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYParsedCertificate.h; sourceTree = "<group>"; };
   11.30 -		275D9D910FD5FB4100D85A86 /* MYParsedCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYParsedCertificate.m; sourceTree = "<group>"; };
   11.31 +		275DA1250FD980D400D85A86 /* MYCertificateInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCertificateInfo.h; sourceTree = "<group>"; };
   11.32 +		275DA1260FD980D400D85A86 /* MYCertificateInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertificateInfo.m; sourceTree = "<group>"; };
   11.33  		27A42CBE0F8578B40063D362 /* MYCryptoTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCryptoTest.m; sourceTree = "<group>"; };
   11.34  		27A42D400F858ED80063D362 /* MYSymmetricKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYSymmetricKey.h; sourceTree = "<group>"; };
   11.35  		27A42D410F858ED80063D362 /* MYSymmetricKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYSymmetricKey.m; sourceTree = "<group>"; };
   11.36 -		27A42ECC0F8689D30063D362 /* MYCertGen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCertGen.h; sourceTree = "<group>"; };
   11.37 -		27A42ECD0F8689D30063D362 /* MYCertGen.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertGen.m; sourceTree = "<group>"; };
   11.38  		27AAD97B0F892A0D0064DD7C /* MYCryptoConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCryptoConfig.h; sourceTree = "<group>"; };
   11.39  		27B852F30FCF4EB6005631F9 /* MYASN1Object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYASN1Object.h; sourceTree = "<group>"; };
   11.40  		27B852F40FCF4EB7005631F9 /* MYASN1Object.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYASN1Object.m; sourceTree = "<group>"; };
   11.41 @@ -278,10 +273,8 @@
   11.42  		274861440F8D757600FE617B /* Certificates */ = {
   11.43  			isa = PBXGroup;
   11.44  			children = (
   11.45 -				27A42ECC0F8689D30063D362 /* MYCertGen.h */,
   11.46 -				27A42ECD0F8689D30063D362 /* MYCertGen.m */,
   11.47 -				275D9D900FD5FB4100D85A86 /* MYParsedCertificate.h */,
   11.48 -				275D9D910FD5FB4100D85A86 /* MYParsedCertificate.m */,
   11.49 +				275DA1250FD980D400D85A86 /* MYCertificateInfo.h */,
   11.50 +				275DA1260FD980D400D85A86 /* MYCertificateInfo.m */,
   11.51  				27B852F30FCF4EB6005631F9 /* MYASN1Object.h */,
   11.52  				27B852F40FCF4EB7005631F9 /* MYASN1Object.m */,
   11.53  				270A7A710FD58FF200770C4D /* MYBERParser.h */,
   11.54 @@ -340,13 +333,12 @@
   11.55  				2706F1C40F9D3C8800292CCF /* MYCryptor.h in Headers */,
   11.56  				2706F1C60F9D3C8900292CCF /* MYDecoder.h in Headers */,
   11.57  				2706F1C80F9D3C8B00292CCF /* MYEncoder.h in Headers */,
   11.58 -				2706F1CA0F9D3C9200292CCF /* MYCertGen.h in Headers */,
   11.59  				27FEB3E70FBA63D200290049 /* MYCrypto.h in Headers */,
   11.60  				27B852F60FCF4EB7005631F9 /* MYASN1Object.h in Headers */,
   11.61  				27B852FE0FCF4ECB005631F9 /* MYOID.h in Headers */,
   11.62  				27B855270FD077A6005631F9 /* MYDEREncoder.h in Headers */,
   11.63  				270A7A730FD58FF200770C4D /* MYBERParser.h in Headers */,
   11.64 -				275D9D920FD5FB4100D85A86 /* MYParsedCertificate.h in Headers */,
   11.65 +				275DA1270FD980D400D85A86 /* MYCertificateInfo.h in Headers */,
   11.66  			);
   11.67  			runOnlyForDeploymentPostprocessing = 0;
   11.68  		};
   11.69 @@ -443,12 +435,11 @@
   11.70  				2706F1C50F9D3C8900292CCF /* MYCryptor.m in Sources */,
   11.71  				2706F1C70F9D3C8A00292CCF /* MYDecoder.m in Sources */,
   11.72  				2706F1C90F9D3C8B00292CCF /* MYEncoder.m in Sources */,
   11.73 -				2706F1CB0F9D3C9300292CCF /* MYCertGen.m in Sources */,
   11.74  				27B852F70FCF4EB7005631F9 /* MYASN1Object.m in Sources */,
   11.75  				27B852FF0FCF4ECB005631F9 /* MYOID.m in Sources */,
   11.76  				27B855280FD077A7005631F9 /* MYDEREncoder.m in Sources */,
   11.77  				270A7A740FD58FF200770C4D /* MYBERParser.m in Sources */,
   11.78 -				275D9D930FD5FB4100D85A86 /* MYParsedCertificate.m in Sources */,
   11.79 +				275DA1280FD980D400D85A86 /* MYCertificateInfo.m in Sources */,
   11.80  			);
   11.81  			runOnlyForDeploymentPostprocessing = 0;
   11.82  		};
   11.83 @@ -472,7 +463,6 @@
   11.84  				27A42D1E0F8586CE0063D362 /* MYKey.m in Sources */,
   11.85  				27A42D420F858ED80063D362 /* MYSymmetricKey.m in Sources */,
   11.86  				270B879F0F8C565000C56781 /* MYPrivateKey.m in Sources */,
   11.87 -				274861D50F8E4B5200FE617B /* MYCertGen.m in Sources */,
   11.88  				274863A20F8EF39400FE617B /* MYIdentity.m in Sources */,
   11.89  				27059D530F8F9BB500A8422F /* MYEncoder.m in Sources */,
   11.90  				27059D770F8FA23100A8422F /* MYCrypto+Cocoa.m in Sources */,
   11.91 @@ -482,7 +472,7 @@
   11.92  				27B853000FCF4ECB005631F9 /* MYOID.m in Sources */,
   11.93  				27B855290FD077A7005631F9 /* MYDEREncoder.m in Sources */,
   11.94  				270A7A750FD58FF200770C4D /* MYBERParser.m in Sources */,
   11.95 -				275D9D940FD5FB4100D85A86 /* MYParsedCertificate.m in Sources */,
   11.96 +				275DA1290FD980D400D85A86 /* MYCertificateInfo.m in Sources */,
   11.97  			);
   11.98  			runOnlyForDeploymentPostprocessing = 0;
   11.99  		};
    12.1 --- a/MYCryptoTest.m	Fri Jun 05 08:57:18 2009 -0700
    12.2 +++ b/MYCryptoTest.m	Sat Jun 06 15:01:28 2009 -0700
    12.3 @@ -261,6 +261,14 @@
    12.4      Log(@"Public key = %@ (%u bytes)",pubKeyData,pubKeyData.length);
    12.5      CAssert(pubKeyData);
    12.6      
    12.7 +    NSData *modulus;
    12.8 +    unsigned exponent;
    12.9 +    CAssert([publicKey getModulus: &modulus exponent: &exponent]);
   12.10 +    Log(@"Modulus = %@", modulus);
   12.11 +    Log(@"Exponent = %u", exponent);
   12.12 +    CAssertEq(modulus.length, 2048U/8);
   12.13 +    CAssertEq(exponent,65537U); // this is what CDSA always seems to use
   12.14 +    
   12.15      MYSHA1Digest *pubKeyDigest = publicKey.publicKeyDigest;
   12.16      Log(@"Public key digest = %@",pubKeyDigest);
   12.17      CAssertEqual(pair.publicKeyDigest, pubKeyDigest);
   12.18 @@ -294,7 +302,14 @@
   12.19      CAssertEqual(pub.keyData, pubKeyData);
   12.20      CAssertEqual(pub.publicKeyDigest, pubKeyDigest);
   12.21      CAssert( [pub verifySignature: sig ofData: data] );
   12.22 +    [pub release];
   12.23      Log(@"Verified signature from reconstituted key.");
   12.24 +    
   12.25 +    // Test creating a public key from modulus+exponent:
   12.26 +    Log(@"Reconstituting public key from modulus+exponent...");
   12.27 +    pub = [[MYPublicKey alloc] initWithModulus: modulus exponent: exponent];
   12.28 +    CAssertEqual(pub.keyData, pubKeyData);
   12.29 +    [pub release];
   12.30  }
   12.31  
   12.32  
    13.1 --- a/MYCrypto_Private.h	Fri Jun 05 08:57:18 2009 -0700
    13.2 +++ b/MYCrypto_Private.h	Sat Jun 06 15:01:28 2009 -0700
    13.3 @@ -25,14 +25,15 @@
    13.4  #endif
    13.5  
    13.6  
    13.7 +@interface MYKeychain (Private)
    13.8 +- (MYIdentity*) identityWithDigest: (MYSHA1Digest*)pubKeyDigest;
    13.9  #if TARGET_OS_IPHONE && !MYCRYPTO_USE_IPHONE_API
   13.10 -@interface MYKeychain (Private)
   13.11  - (id) initWithKeychainRef: (SecKeychainRef)keychainRef;
   13.12  @property (readonly) SecKeychainRef keychainRef, keychainRefOrDefault;
   13.13  @property (readonly) CSSM_CSP_HANDLE CSPHandle;
   13.14  @property (readonly) NSString* path;
   13.15 +#endif
   13.16  @end
   13.17 -#endif
   13.18  
   13.19  
   13.20  @interface MYKeychainItem (Private);
    14.1 --- a/MYDEREncoder.m	Fri Jun 05 08:57:18 2009 -0700
    14.2 +++ b/MYDEREncoder.m	Sat Jun 06 15:01:28 2009 -0700
    14.3 @@ -228,7 +228,6 @@
    14.4  
    14.5  - (void) _encodeDate: (NSDate*)date {
    14.6      NSString *dateStr = [MYBERGeneralizedTimeFormatter() stringFromDate: date];
    14.7 -    Log(@"Encoded %@ as '%@'",date,dateStr);//TEMP
    14.8      [self _writeTag: 24 class: 0 constructed: NO data: [dateStr dataUsingEncoding: NSASCIIStringEncoding]];
    14.9  }
   14.10  
   14.11 @@ -363,7 +362,7 @@
   14.12  
   14.13  TestCase(EncodeCert) {
   14.14      NSError *error = nil;
   14.15 -    NSData *cert = [NSData dataWithContentsOfFile: @"../../Tests/selfsigned.cer"];  //TEMP
   14.16 +    NSData *cert = [NSData dataWithContentsOfFile: @"../../Tests/selfsigned.cer"];
   14.17      id certObjects = MYBERParse(cert,&error);
   14.18      CAssertNil(error);
   14.19      Log(@"Decoded as:\n%@", [MYASN1Object dump: certObjects]);
   14.20 @@ -377,3 +376,27 @@
   14.21      [encoded writeToFile: @"../../Tests/selfsigned_reencoded.cer" atomically: YES];
   14.22      CAssertEqual(encoded,cert);
   14.23  }
   14.24 +
   14.25 +
   14.26 +
   14.27 +/*
   14.28 + Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   14.29 + 
   14.30 + Redistribution and use in source and binary forms, with or without modification, are permitted
   14.31 + provided that the following conditions are met:
   14.32 + 
   14.33 + * Redistributions of source code must retain the above copyright notice, this list of conditions
   14.34 + and the following disclaimer.
   14.35 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   14.36 + and the following disclaimer in the documentation and/or other materials provided with the
   14.37 + distribution.
   14.38 + 
   14.39 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   14.40 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   14.41 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   14.42 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   14.43 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   14.44 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   14.45 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   14.46 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   14.47 + */
    15.1 --- a/MYKey.m	Fri Jun 05 08:57:18 2009 -0700
    15.2 +++ b/MYKey.m	Sat Jun 06 15:01:28 2009 -0700
    15.3 @@ -22,10 +22,11 @@
    15.4      return [super initWithKeychainItemRef: (SecKeychainItemRef)key];
    15.5  }
    15.6  
    15.7 -- (id) _initWithKeyData: (NSData*)data
    15.8 +- (id) _initWithKeyData: (NSData*)keyData
    15.9              forKeychain: (SecKeychainRef)keychain {
   15.10 +    Assert(keyData!=nil);
   15.11      SecKeyImportExportParameters params = {};
   15.12 -    SecKeyRef key = importKey(data, self.keyType, keychain, &params);
   15.13 +    SecKeyRef key = importKey(keyData, self.keyType, keychain, &params);
   15.14      if (!key) {
   15.15          [self release];
   15.16          return nil;
    16.1 --- a/MYKeychain-iPhone.m	Fri Jun 05 08:57:18 2009 -0700
    16.2 +++ b/MYKeychain-iPhone.m	Sat Jun 06 15:01:28 2009 -0700
    16.3 @@ -106,6 +106,13 @@
    16.4      return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
    16.5  }
    16.6  
    16.7 +- (MYIdentity*) identityWithDigest: (MYSHA1Digest*)pubKeyDigest {
    16.8 +    return [MYKeyEnumerator firstItemWithQuery:
    16.9 +                $mdict({(id)kSecClass, (id)kSecClassIdentity},
   16.10 +                        {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData},
   16.11 +                        {(id)kSecReturnRef, $true})];
   16.12 +}
   16.13 +
   16.14  - (NSEnumerator*) enumerateIdentities {
   16.15      NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassIdentity},
   16.16                                          {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
    17.1 --- a/MYOID.m	Fri Jun 05 08:57:18 2009 -0700
    17.2 +++ b/MYOID.m	Sat Jun 06 15:01:28 2009 -0700
    17.3 @@ -150,3 +150,27 @@
    17.4      CAssertEqual([[[MYOID alloc] initWithComponents: $components(2,5,4,4) count: 4] DEREncoding],
    17.5                   $data(0x55,0x04,0x04));
    17.6  }
    17.7 +
    17.8 +
    17.9 +
   17.10 +/*
   17.11 + Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   17.12 + 
   17.13 + Redistribution and use in source and binary forms, with or without modification, are permitted
   17.14 + provided that the following conditions are met:
   17.15 + 
   17.16 + * Redistributions of source code must retain the above copyright notice, this list of conditions
   17.17 + and the following disclaimer.
   17.18 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   17.19 + and the following disclaimer in the documentation and/or other materials provided with the
   17.20 + distribution.
   17.21 + 
   17.22 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   17.23 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   17.24 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   17.25 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   17.26 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   17.27 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   17.28 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   17.29 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   17.30 + */
    18.1 --- a/MYParsedCertificate.h	Fri Jun 05 08:57:18 2009 -0700
    18.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.3 @@ -1,110 +0,0 @@
    18.4 -//
    18.5 -//  MYParsedCertificate.h
    18.6 -//  MYCrypto
    18.7 -//
    18.8 -//  Created by Jens Alfke on 6/2/09.
    18.9 -//  Copyright 2009 Jens Alfke. All rights reserved.
   18.10 -//
   18.11 -
   18.12 -#import <Foundation/Foundation.h>
   18.13 -@class MYCertificateName, MYCertificate, MYPublicKey, MYPrivateKey, MYOID;
   18.14 -
   18.15 -/** A parsed X.509 certificate. Can be used to get more info about an existing cert,
   18.16 -    to modify and regenerate a self-signed cert, or to create a new self-signed cert. */
   18.17 -@interface MYParsedCertificate : NSObject 
   18.18 -{
   18.19 -    @private
   18.20 -    NSData *_data;
   18.21 -    NSArray *_root;
   18.22 -    MYCertificate *_issuerCertificate;
   18.23 -}
   18.24 -
   18.25 -/** Initializes an instance by parsing an existing X.509 certificate's data. */
   18.26 -- (id) initWithCertificateData: (NSData*)data error: (NSError**)outError;
   18.27 -
   18.28 -/** The raw data of the certificate. */
   18.29 -@property (readonly) NSData* certificateData;
   18.30 -
   18.31 -/** The date/time at which the certificate first becomes valid. */
   18.32 -@property (retain) NSDate *validFrom;
   18.33 -
   18.34 -/** The date/time at which the certificate expires. */
   18.35 -@property (retain) NSDate *validTo;
   18.36 -
   18.37 -/** Information about the identity of the owner of this certificate. */
   18.38 -@property (readonly) MYCertificateName *subject;
   18.39 -
   18.40 -/** Information about the identity that signed/authorized this certificate. */
   18.41 -@property (readonly) MYCertificateName *issuer;
   18.42 -
   18.43 -/** Returns YES if the issuer is the same as the subject. (Aka a "self-signed" certificate.) */
   18.44 -@property (readonly) BOOL isRoot;
   18.45 -
   18.46 -/** The public key of the subject of the certificate. */
   18.47 -@property (readonly) MYPublicKey *subjectPublicKey;
   18.48 -
   18.49 -/** Associates the certificate to its issuer.
   18.50 -    If the cert is not self-signed, you must manually set this property before validating. */
   18.51 -@property (retain) MYCertificate* issuerCertificate;
   18.52 -
   18.53 -/** Checks that the issuer's signature is valid and hasn't been tampered with.
   18.54 -    If the certificate is root/self-signed, the subjectPublicKey is used to check the signature;
   18.55 -    otherwise, the issuer property needs to have been set and its publicKey will be used. */
   18.56 -- (BOOL) validateSignature;
   18.57 -
   18.58 -
   18.59 -// Generating certificates:
   18.60 -
   18.61 -/** Initializes a blank instance which can be used to create a new certificate.
   18.62 -    The certificate will not contain anything yet other than the public key.
   18.63 -    The desired attributes should be set, and then the -selfSignWithPrivateKey:error method called. */
   18.64 -- (id) initWithPublicKey: (MYPublicKey*)pubKey;
   18.65 -
   18.66 -/** Has the certificate been signed yet? */
   18.67 -@property (readonly) BOOL isSigned;
   18.68 -
   18.69 -/** Signs the certificate using the given private key, which must be the counterpart of the
   18.70 -    public key stored in the certificate.
   18.71 -    The subject attributes will be copied to the issuer attributes.
   18.72 -    If no valid date range has been set yet, it will be set to a range of one year starting from
   18.73 -    the current time.
   18.74 -    A unique serial number based on the current time will be set.
   18.75 -    After this method returns successfully, access the certificateData property to get the
   18.76 -    encoded certificate. */
   18.77 -- (BOOL) selfSignWithPrivateKey: (MYPrivateKey*)privateKey error: (NSError**)outError;
   18.78 -
   18.79 -@end
   18.80 -
   18.81 -
   18.82 -
   18.83 -/** An X.509 Name structure, describing the subject or issuer of a certificate.
   18.84 -    Changing a property value of an instance associated with an already-signed certificate will
   18.85 -    raise an exception. */
   18.86 -@interface MYCertificateName : NSObject
   18.87 -{
   18.88 -    @private
   18.89 -    NSArray *_components;
   18.90 -}
   18.91 -
   18.92 -/** The "common name" (nickname, whatever). */
   18.93 -@property (copy) NSString *commonName;
   18.94 -
   18.95 -/** The given/first name. */
   18.96 -@property (copy) NSString *givenName;
   18.97 -
   18.98 -/** The surname / last name / family name. */
   18.99 -@property (copy) NSString *surname;
  18.100 -
  18.101 -/** A description. */
  18.102 -@property (copy) NSString *nameDescription;
  18.103 -
  18.104 -/** The raw email address. */
  18.105 -@property (copy) NSString *emailAddress;
  18.106 -
  18.107 -/** Lower-level accessor that returns the value associated with the given OID. */
  18.108 -- (NSString*) stringForOID: (MYOID*)oid;
  18.109 -
  18.110 -/** Lower-level accessor that sets the value associated with the given OID. */
  18.111 -- (void) setString: (NSString*)value forOID: (MYOID*)oid;
  18.112 -
  18.113 -@end
    19.1 --- a/MYParsedCertificate.m	Fri Jun 05 08:57:18 2009 -0700
    19.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.3 @@ -1,496 +0,0 @@
    19.4 -//
    19.5 -//  MYParsedCertificate.m
    19.6 -//  MYCrypto
    19.7 -//
    19.8 -//  Created by Jens Alfke on 6/2/09.
    19.9 -//  Copyright 2009 Jens Alfke. All rights reserved.
   19.10 -//
   19.11 -
   19.12 -// References:
   19.13 -// <http://www.columbia.edu/~ariel/ssleay/layman.html> "Layman's Guide To ASN.1/BER/DER"
   19.14 -// <http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt> "X.509 Style Guide"
   19.15 -// <http://en.wikipedia.org/wiki/X.509> Wikipedia article on X.509
   19.16 -
   19.17 -
   19.18 -#import "MYParsedCertificate.h"
   19.19 -#import "MYASN1Object.h"
   19.20 -#import "MYOID.h"
   19.21 -#import "MYBERParser.h"
   19.22 -#import "MYDEREncoder.h"
   19.23 -#import "MYPublicKey.h"
   19.24 -#import "MYPrivateKey.h"
   19.25 -#import "MYCertificate.h"
   19.26 -#import "MYErrorUtils.h"
   19.27 -
   19.28 -
   19.29 -#define kDefaultExpirationTime (60.0 * 60.0 * 24.0 * 365.0)
   19.30 -
   19.31 -
   19.32 -static id $atIf(NSArray *array, NSUInteger index) {
   19.33 -    return index < array.count ?[array objectAtIndex: index] :nil;
   19.34 -}
   19.35 -
   19.36 -
   19.37 -@interface MYCertificateName ()
   19.38 -- (id) _initWithComponents: (NSArray*)components;
   19.39 -@end
   19.40 -
   19.41 -
   19.42 -#pragma mark -
   19.43 -@implementation MYParsedCertificate
   19.44 -
   19.45 -
   19.46 -static MYOID *kRSAAlgorithmID, *kRSAWithSHA1AlgorithmID, *kCommonNameOID,
   19.47 -            *kGivenNameOID, *kSurnameOID, *kDescriptionOID, *kEmailOID;
   19.48 -
   19.49 -
   19.50 -+ (void) initialize {
   19.51 -    if (!kEmailOID) {
   19.52 -        kRSAAlgorithmID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 1, 1,}
   19.53 -                                                      count: 7];
   19.54 -        kRSAWithSHA1AlgorithmID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 1, 5}
   19.55 -                                                              count: 7];
   19.56 -        kCommonNameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 3}
   19.57 -                                                     count: 4];
   19.58 -        kGivenNameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 42}
   19.59 -                                                    count: 4];
   19.60 -        kSurnameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 4}
   19.61 -                                                  count: 4];
   19.62 -        kDescriptionOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 13}
   19.63 -                                                count: 7];
   19.64 -        kEmailOID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 9, 1}
   19.65 -                                                count: 7];
   19.66 -    }
   19.67 -    
   19.68 -}
   19.69 -
   19.70 -+ (NSString*) validate: (id)root {
   19.71 -    NSArray *top = $castIf(NSArray,root);
   19.72 -    if (top.count < 3)
   19.73 -        return @"Too few top-level components";
   19.74 -    NSArray *info = $castIf(NSArray, [top objectAtIndex: 0]);
   19.75 -    if (info.count < 7)
   19.76 -        return @"Too few identity components";
   19.77 -    MYASN1Object *version = $castIf(MYASN1Object, [info objectAtIndex: 0]);
   19.78 -    if (!version || version.tag != 0)
   19.79 -        return @"Missing or invalid version";
   19.80 -    NSArray *versionComps = $castIf(NSArray, version.components);
   19.81 -    if (!versionComps || versionComps.count != 1)
   19.82 -        return @"Invalid version";
   19.83 -    NSNumber *versionNum = $castIf(NSNumber, [versionComps objectAtIndex: 0]);
   19.84 -    if (!versionNum || versionNum.intValue < 0 || versionNum.intValue > 2)
   19.85 -        return @"Unrecognized version number";
   19.86 -    return nil;
   19.87 -}
   19.88 -
   19.89 -
   19.90 -- (id) initWithCertificateData: (NSData*)data error: (NSError**)outError;
   19.91 -{
   19.92 -    self = [super init];
   19.93 -    if (self != nil) {
   19.94 -        if (outError) *outError = nil;
   19.95 -        id root = MYBERParse(data,outError);
   19.96 -        NSString *errorMsg = [[self class] validate: root];
   19.97 -        if (errorMsg) {
   19.98 -            if (!*outError)
   19.99 -                *outError = MYError(2, MYASN1ErrorDomain, @"Invalid certificate: %@", errorMsg);
  19.100 -            [self release];
  19.101 -            return nil;
  19.102 -        }
  19.103 -        _root = [root retain];
  19.104 -        _data = [data copy];
  19.105 -    }
  19.106 -    return self;
  19.107 -}
  19.108 -
  19.109 -- (void) dealloc
  19.110 -{
  19.111 -    
  19.112 -    [_root release];
  19.113 -    [_issuerCertificate release];
  19.114 -    [_data release];
  19.115 -    [super dealloc];
  19.116 -}
  19.117 -
  19.118 -
  19.119 -- (NSArray*) _info       {return $castIf(NSArray,$atIf(_root,0));}
  19.120 -
  19.121 -- (NSArray*) _validDates {return $castIf(NSArray, [self._info objectAtIndex: 4]);}
  19.122 -
  19.123 -@synthesize issuerCertificate=_issuerCertificate, certificateData=_data;
  19.124 -
  19.125 -
  19.126 -- (NSDate*) validFrom       {return $castIf(NSDate, $atIf(self._validDates, 0));}
  19.127 -- (NSDate*) validTo         {return $castIf(NSDate, $atIf(self._validDates, 1));}
  19.128 -
  19.129 -- (MYCertificateName*) subject {
  19.130 -    return [[[MYCertificateName alloc] _initWithComponents: [self._info objectAtIndex: 5]] autorelease];
  19.131 -}
  19.132 -
  19.133 -- (MYCertificateName*) issuer {
  19.134 -    return [[[MYCertificateName alloc] _initWithComponents: [self._info objectAtIndex: 3]] autorelease];
  19.135 -}
  19.136 -
  19.137 -- (BOOL) isSigned           {return [_root count] >= 3;}
  19.138 -
  19.139 -- (BOOL) isRoot {
  19.140 -    id issuer = $atIf(self._info,3);
  19.141 -    return $equal(issuer, $atIf(self._info,5)) || $equal(issuer, $array());
  19.142 -}
  19.143 -
  19.144 -
  19.145 -- (MYPublicKey*) subjectPublicKey {
  19.146 -    NSArray *keyInfo = $cast(NSArray, $atIf(self._info, 6));
  19.147 -    MYOID *keyAlgorithmID = $castIf(MYOID, $atIf($castIf(NSArray,$atIf(keyInfo,0)), 0));
  19.148 -    if (!$equal(keyAlgorithmID, kRSAAlgorithmID))
  19.149 -        return nil;
  19.150 -    MYBitString *keyData = $cast(MYBitString, $atIf(keyInfo, 1));
  19.151 -    if (!keyData) return nil;
  19.152 -    return [[[MYPublicKey alloc] initWithKeyData: keyData.bits] autorelease];
  19.153 -}
  19.154 -
  19.155 -- (MYPublicKey*) issuerPublicKey {
  19.156 -    if (_issuerCertificate)
  19.157 -        return _issuerCertificate.publicKey;
  19.158 -    else if (self.isRoot)
  19.159 -        return self.subjectPublicKey;
  19.160 -    else
  19.161 -        return nil;
  19.162 -}
  19.163 -
  19.164 -- (NSData*) signedData {
  19.165 -    // The root object is a sequence; we want to extract the 1st object of that sequence.
  19.166 -    const UInt8 *certStart = _data.bytes;
  19.167 -    const UInt8 *start = MYBERGetContents(_data, nil);
  19.168 -    if (!start) return nil;
  19.169 -    size_t length = MYBERGetLength([NSData dataWithBytesNoCopy: (void*)start
  19.170 -                                                        length: _data.length - (start-certStart)
  19.171 -                                                  freeWhenDone: NO],
  19.172 -                                   NULL);
  19.173 -    if (length==0)
  19.174 -        return nil;
  19.175 -    return [NSData dataWithBytes: start length: (start + length - certStart)];
  19.176 -}
  19.177 -
  19.178 -- (MYOID*) signatureAlgorithmID {
  19.179 -    return $castIf(MYOID, $atIf($castIf(NSArray,$atIf(_root,1)), 0));
  19.180 -}
  19.181 -
  19.182 -- (NSData*) signature {
  19.183 -    id signature = $atIf(_root,2);
  19.184 -    if ([signature isKindOfClass: [MYBitString class]])
  19.185 -        signature = [signature bits];
  19.186 -    return $castIf(NSData,signature);
  19.187 -}
  19.188 -
  19.189 -- (BOOL) validateSignature {
  19.190 -    if (!$equal(self.signatureAlgorithmID, kRSAWithSHA1AlgorithmID))
  19.191 -        return NO;
  19.192 -    NSData *signedData = self.signedData;
  19.193 -    NSData *signature = self.signature;
  19.194 -    MYPublicKey *pubKey = self.issuerPublicKey;
  19.195 -    if (!signature || !pubKey) return NO;
  19.196 -    return [pubKey verifySignature: signature ofData: signedData];
  19.197 -}
  19.198 -
  19.199 -
  19.200 -#pragma mark -
  19.201 -#pragma mark CERTIFICATE GENERATION:
  19.202 -
  19.203 -
  19.204 -- (id) initWithPublicKey: (MYPublicKey*)pubKey {
  19.205 -    Assert(pubKey);
  19.206 -    self = [super init];
  19.207 -    if (self != nil) {
  19.208 -        id empty = [NSNull null];
  19.209 -        id version = [[MYASN1Object alloc] initWithTag: 0 ofClass: 2 components: $array($object(0))];
  19.210 -        _root = $array( $marray(version,
  19.211 -                                empty,       // serial #
  19.212 -                                $array(kRSAAlgorithmID),
  19.213 -                                $marray(),
  19.214 -                                $marray(empty, empty),
  19.215 -                                $marray(),
  19.216 -                                $array( $array(kRSAAlgorithmID, empty),
  19.217 -                                       [MYBitString bitStringWithData: pubKey.keyData] ) ) );
  19.218 -        [version release];
  19.219 -        [_root retain];
  19.220 -    }
  19.221 -    return self;
  19.222 -}
  19.223 -
  19.224 -
  19.225 -- (void) setValidFrom: (NSDate*)validFrom {
  19.226 -    [(NSMutableArray*)self._validDates replaceObjectAtIndex: 0 withObject: validFrom];
  19.227 -}
  19.228 -
  19.229 -- (void) setValidTo: (NSDate*)validTo {
  19.230 -    [(NSMutableArray*)self._validDates replaceObjectAtIndex: 1 withObject: validTo];
  19.231 -}
  19.232 -
  19.233 -
  19.234 -- (BOOL) selfSignWithPrivateKey: (MYPrivateKey*)privateKey error: (NSError**)outError {
  19.235 -    // Copy subject to issuer:
  19.236 -    NSMutableArray *info = (NSMutableArray*)self._info;
  19.237 -    [info replaceObjectAtIndex: 3 withObject: [info objectAtIndex: 5]];
  19.238 -    
  19.239 -    // Set serial number if there isn't one yet:
  19.240 -    if (!$castIf(NSNumber, [info objectAtIndex: 1])) {
  19.241 -        UInt64 serial = floor(CFAbsoluteTimeGetCurrent() * 1000);
  19.242 -        [info replaceObjectAtIndex: 1 withObject: $object(serial)];
  19.243 -    }
  19.244 -    
  19.245 -    // Set up valid date range if there isn't one yet:
  19.246 -    NSDate *validFrom = self.validFrom;
  19.247 -    if (!validFrom)
  19.248 -        validFrom = self.validFrom = [NSDate date];
  19.249 -    NSDate *validTo = self.validTo;
  19.250 -    if (!validTo)
  19.251 -        self.validTo = [validFrom addTimeInterval: kDefaultExpirationTime]; 
  19.252 -    
  19.253 -    // Append signature to cert structure:
  19.254 -    NSData *dataToSign = [MYDEREncoder encodeRootObject: info error: outError];
  19.255 -    if (!dataToSign)
  19.256 -        return NO;
  19.257 -    setObj(&_root, $array(info, 
  19.258 -                          $array(kRSAWithSHA1AlgorithmID, [NSNull null]),
  19.259 -                          [MYBitString bitStringWithData: [privateKey signData: dataToSign]]));
  19.260 -    
  19.261 -    setObj(&_data, [MYDEREncoder encodeRootObject: _root error: outError]);
  19.262 -    return _data!=nil;
  19.263 -}
  19.264 -
  19.265 -
  19.266 -@end
  19.267 -
  19.268 -
  19.269 -
  19.270 -#pragma mark -
  19.271 -@implementation MYCertificateName
  19.272 -
  19.273 -- (id) _initWithComponents: (NSArray*)components
  19.274 -{
  19.275 -    self = [super init];
  19.276 -    if (self != nil) {
  19.277 -        _components = [components retain];
  19.278 -    }
  19.279 -    return self;
  19.280 -}
  19.281 -
  19.282 -- (void) dealloc
  19.283 -{
  19.284 -    [_components release];
  19.285 -    [super dealloc];
  19.286 -}
  19.287 -
  19.288 -- (BOOL) isEqual: (id)object {
  19.289 -    return [object isKindOfClass: [MYCertificateName class]]
  19.290 -        && [_components isEqual: ((MYCertificateName*)object)->_components];
  19.291 -}
  19.292 -
  19.293 -- (NSArray*) _pairForOID: (MYOID*)oid {
  19.294 -    for (id nameEntry in _components) {
  19.295 -        for (id pair in $castIf(NSSet,nameEntry)) {
  19.296 -            if ([pair isKindOfClass: [NSArray class]] && [pair count] == 2) {
  19.297 -                if ($equal(oid, [pair objectAtIndex: 0]))
  19.298 -                    return pair;
  19.299 -            }
  19.300 -        }
  19.301 -    }
  19.302 -    return nil;
  19.303 -}
  19.304 -
  19.305 -- (NSString*) stringForOID: (MYOID*)oid {
  19.306 -    return [[self _pairForOID: oid] objectAtIndex: 1];
  19.307 -}
  19.308 -
  19.309 -- (void) setString: (NSString*)value forOID: (MYOID*)oid {
  19.310 -    NSMutableArray *pair = (NSMutableArray*) [self _pairForOID: oid];
  19.311 -    if (pair)
  19.312 -        [pair replaceObjectAtIndex: 1 withObject: value];
  19.313 -    else
  19.314 -        [(NSMutableArray*)_components addObject: [NSSet setWithObject: $marray(oid,value)]];
  19.315 -}
  19.316 -
  19.317 -- (NSString*) commonName    {return [self stringForOID: kCommonNameOID];}
  19.318 -- (NSString*) givenName     {return [self stringForOID: kGivenNameOID];}
  19.319 -- (NSString*) surname       {return [self stringForOID: kSurnameOID];}
  19.320 -- (NSString*) nameDescription {return [self stringForOID: kDescriptionOID];}
  19.321 -- (NSString*) emailAddress  {return [self stringForOID: kEmailOID];}
  19.322 -
  19.323 -- (void) setCommonName: (NSString*)commonName   {[self setString: commonName forOID: kCommonNameOID];}
  19.324 -- (void) setGivenName: (NSString*)givenName     {[self setString: givenName forOID: kGivenNameOID];}
  19.325 -- (void) setSurname: (NSString*)surname         {[self setString: surname forOID: kSurnameOID];}
  19.326 -- (void) setNameDescription: (NSString*)desc    {[self setString: desc forOID: kDescriptionOID];}
  19.327 -- (void) setEmailAddress: (NSString*)email      {[self setString: email forOID: kEmailOID];}
  19.328 -
  19.329 -
  19.330 -@end
  19.331 -
  19.332 -
  19.333 -
  19.334 -#pragma mark -
  19.335 -#pragma mark TEST CASES:
  19.336 -
  19.337 -#if DEBUG
  19.338 -
  19.339 -
  19.340 -static MYParsedCertificate* testCert(NSString *filename, BOOL selfSigned) {
  19.341 -    Log(@"--- Creating MYParsedCertificate from %@", filename);
  19.342 -    NSData *certData = [NSData dataWithContentsOfFile: filename];
  19.343 -    //Log(@"Cert Data =\n%@", certData);
  19.344 -    NSError *error = nil;
  19.345 -    MYParsedCertificate *pcert = [[MYParsedCertificate alloc] initWithCertificateData: certData 
  19.346 -                                                                                error: &error];
  19.347 -    CAssertNil(error);
  19.348 -    CAssert(pcert != nil);
  19.349 -    
  19.350 -    CAssertEq(pcert.isRoot, selfSigned);
  19.351 -    
  19.352 -    NSData *signedData = pcert.signedData;
  19.353 -    //Log(@"Signed Data = (length=%x)\n%@", signedData.length, signedData);
  19.354 -    CAssertEqual(signedData, [certData subdataWithRange: NSMakeRange(4,signedData.length)]);
  19.355 -    
  19.356 -    Log(@"AlgID = %@", pcert.signatureAlgorithmID);
  19.357 -    Log(@"Signature = %@", pcert.signature);
  19.358 -    CAssertEqual(pcert.signatureAlgorithmID, kRSAWithSHA1AlgorithmID);
  19.359 -    CAssert(pcert.signature != nil);
  19.360 -    Log(@"Subject Public Key = %@", pcert.subjectPublicKey);
  19.361 -    CAssert(pcert.subjectPublicKey);
  19.362 -    if (selfSigned) {
  19.363 -        Log(@"Issuer Public Key = %@", pcert.issuerPublicKey);
  19.364 -        CAssert(pcert.issuerPublicKey);
  19.365 -        
  19.366 -        CAssert(pcert.validateSignature);
  19.367 -    }
  19.368 -    MYCertificateName *subject = pcert.subject;
  19.369 -    Log(@"Common Name = %@", subject.commonName);
  19.370 -    Log(@"Given Name  = %@", subject.givenName);
  19.371 -    Log(@"Surname     = %@", subject.surname);
  19.372 -    Log(@"Desc        = %@", subject.nameDescription);
  19.373 -    Log(@"Email       = %@", subject.emailAddress);
  19.374 -    return pcert;
  19.375 -}
  19.376 -
  19.377 -
  19.378 -TestCase(ParsedCert) {
  19.379 -    testCert(@"../../Tests/selfsigned.cer", YES);
  19.380 -    testCert(@"../../Tests/iphonedev.cer", NO);
  19.381 -}
  19.382 -
  19.383 -
  19.384 -#import "MYKeychain.h"
  19.385 -
  19.386 -TestCase(CreateCert) {
  19.387 -    MYPrivateKey *privateKey = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 512];
  19.388 -    MYParsedCertificate *pcert = [[MYParsedCertificate alloc] initWithPublicKey: privateKey.publicKey];
  19.389 -    MYCertificateName *subject = pcert.subject;
  19.390 -    subject.commonName = @"testcase";
  19.391 -    subject.givenName = @"Test";
  19.392 -    subject.surname = @"Case";
  19.393 -    subject.nameDescription = @"Just a test certificate created by MYCrypto";
  19.394 -    subject.emailAddress = @"testcase@example.com";
  19.395 -
  19.396 -    subject = pcert.subject;
  19.397 -    CAssertEqual(subject.commonName, @"testcase");
  19.398 -    CAssertEqual(subject.givenName, @"Test");
  19.399 -    CAssertEqual(subject.surname, @"Case");
  19.400 -    CAssertEqual(subject.nameDescription, @"Just a test certificate created by MYCrypto");
  19.401 -    CAssertEqual(subject.emailAddress, @"testcase@example.com");
  19.402 -    
  19.403 -    Log(@"Signing...");
  19.404 -    NSError *error;
  19.405 -    CAssert([pcert selfSignWithPrivateKey: privateKey error: &error]);
  19.406 -    CAssertNil(error);
  19.407 -    NSData *certData = pcert.certificateData;
  19.408 -    Log(@"Generated cert = \n%@", certData);
  19.409 -    CAssert(certData);
  19.410 -    [certData writeToFile: @"../../Tests/generated.cer" atomically: YES];
  19.411 -    MYParsedCertificate *pcert2 = testCert(@"../../Tests/generated.cer", YES);
  19.412 -    
  19.413 -    Log(@"Verifying...");
  19.414 -    MYCertificateName *subject2 = pcert2.subject;
  19.415 -    CAssertEqual(subject2,subject);
  19.416 -    CAssertEqual(subject2.commonName, @"testcase");
  19.417 -    CAssertEqual(subject2.givenName, @"Test");
  19.418 -    CAssertEqual(subject2.surname, @"Case");
  19.419 -    CAssertEqual(subject2.nameDescription, @"Just a test certificate created by MYCrypto");
  19.420 -    CAssertEqual(subject2.emailAddress, @"testcase@example.com");
  19.421 -}
  19.422 -
  19.423 -#endif
  19.424 -
  19.425 -
  19.426 -
  19.427 -
  19.428 -/* Parsed form of selfsigned.cer:
  19.429 - 
  19.430 -Sequence:                           <-- top
  19.431 -    Sequence:                       <-- info
  19.432 -        MYASN1Object[2/0]:          <-- version (tag=0, constructed)
  19.433 -            2                       
  19.434 -        1                           <-- serial number
  19.435 -        Sequence:
  19.436 -            {1 2 840 113549 1 1 1}  <-- algorithm ID
  19.437 -        Sequence:                   <-- issuer
  19.438 -            Set:
  19.439 -                Sequence:
  19.440 -                    {2 5 4 4}
  19.441 -                    Widdershins
  19.442 -            Set:
  19.443 -                Sequence:
  19.444 -                    {1 2 840 113549 1 9 1}
  19.445 -                    waldo@example.com
  19.446 -            Set:
  19.447 -                Sequence:
  19.448 -                    {2 5 4 3}
  19.449 -                    waldo
  19.450 -            Set:
  19.451 -                Sequence:
  19.452 -                    {2 5 4 42}
  19.453 -                    Waldo
  19.454 -            Set:
  19.455 -                Sequence:
  19.456 -                    {2 5 4 13}
  19.457 -                    Just a fictitious person
  19.458 -        Sequence:                       <--validity
  19.459 -            2009-04-12 21:54:35 -0700
  19.460 -            2010-04-13 21:54:35 -0700
  19.461 -        Sequence:                       <-- subject
  19.462 -            Set:
  19.463 -                Sequence:                   <-- surname
  19.464 -                    {2 5 4 4}
  19.465 -                    Widdershins
  19.466 -            Set:
  19.467 -                Sequence:                   <-- email
  19.468 -                    {1 2 840 113549 1 9 1}
  19.469 -                    waldo@example.com
  19.470 -            Set:
  19.471 -                Sequence:                   <-- common name
  19.472 -                    {2 5 4 3}
  19.473 -                    waldo
  19.474 -            Set:
  19.475 -                Sequence:                   <-- first name
  19.476 -                    {2 5 4 42}
  19.477 -                    Waldo
  19.478 -            Set:
  19.479 -                Sequence:                   <-- description
  19.480 -                    {2 5 4 13}
  19.481 -                    Just a fictitious person
  19.482 -        Sequence:                               <-- public key info
  19.483 -            Sequence:
  19.484 -                {1 2 840 113549 1 1 1}          <-- algorithm ID (RSA)
  19.485 -                <null>
  19.486 -            MYBitString<3082010a 02820101 0095713c 360badf2 d8575ebd 278fa26b a2e6d05e 1eb04eaa 9fa6f11b fd341556 038b3077 525c7adb f5aedf3b 249b08e6 7f77af26 7ff2feb8 5f4ccb96 5269dbd2 f01f19b6 55fc4ea3 a85f2ede 11ff80f8 fc23e662 f263f685 06a9ec07 f7ee4249 af184f21 2d9253d8 7f6f7cbc 96e6ba5c abc8f4e7 3bf6100b 06dcf3ee 999d4170 f5dd005d a24a54a1 3edaddd5 0675409d 6728a387 5fa71898 ebf7d93d 4af8742d f9a0e9ad 6dc21cfa fc2d1967 e692575b 56e5376c 8cf008e8 a442d787 6843a92e 9501b144 8a75adef 5e804fec 6d09740d 1ea8442e 67fac3be c5ea3af5 d95d9f95 2c507711 01c45942 28ad1410 23525324 62848476 d987d3c7 d65f9057 daf1e853 77020301 0001>        <-- DER-encoded key
  19.487 -        MYASN1Object[2/3]:
  19.488 -            Sequence:
  19.489 -                Sequence:
  19.490 -                    {2 5 29 15}
  19.491 -                    <030202fc>
  19.492 -                Sequence:
  19.493 -                    {2 5 29 37}
  19.494 -                    <301a0608 2b060105 05070301 06082b06 01050507 03020604 551d2500>
  19.495 -    Sequence:
  19.496 -        {1 2 840 113549 1 1 5}
  19.497 -        <null>
  19.498 -    MYBitString<79c8e789 50a11fcb 7398f5fe 0cfa2595 b2476f53 62dfbea2 70ae3a8b fdaf5a57 39be6101 fc5e0929 e57a0b2b 41e3ab52 f78ef1b5 ecc8848c da7f42aa b57c3df4 df4125a9 db4e6388 197c2a1c e326c1a5 5203b4ef da057b91 4abc43aa 3eeee6aa fe4303c3 0f000175 16b916b5 72f8b74f c682a06f 920e3bbf a16cdad8 fce3f184 adccc61e 8d3b44e5 8bd103f0 46310f6a 992f240a b290354c 04c519c9 22276df6 310ccb8e 942e38f6 555ca40b 71482e52 146a9988 f021c2c0 2d285db5 59d48eaf 7b20559f 068ea1a0 f07fbaee 29284ada 28bf8344 f435f30f 6263f0c9 9c4920ce a1b7c6c0 9cfa3bbb af5a0fee 5b0e94eb 9c57d28b 1bb9c977 be53e4bb b675ffaa>
  19.499 -*/
  19.500 \ No newline at end of file
    20.1 --- a/MYPrivateKey.h	Fri Jun 05 08:57:18 2009 -0700
    20.2 +++ b/MYPrivateKey.h	Sat Jun 06 15:01:28 2009 -0700
    20.3 @@ -49,15 +49,6 @@
    20.4  //@{
    20.5  #if !TARGET_OS_IPHONE
    20.6  
    20.7 -/** Creates a self-signed identity certificate using this key-pair.
    20.8 -    The attributes describe the certificate's metadata, including its expiration date and the
    20.9 -    subject's name. Keys for the dictionary are given below; the only mandatory one is
   20.10 -    kMYIdentityCommonNameKey.
   20.11 -    The resulting identity certificate includes X.509 extended attributes allowing it to be
   20.12 -    used for SSL connections. (Plug: See my MYNetwork library for an easy way to run SSL
   20.13 -    servers and clients.) */
   20.14 -- (MYIdentity*) createSelfSignedIdentityWithAttributes: (NSDictionary*)attributes;
   20.15 -
   20.16  /** Exports the private key as a data blob, so that it can be stored as a backup, or transferred
   20.17      to another computer. Since the key is sensitive, it must be exported in encrypted form
   20.18      using a user-chosen passphrase. This method will display a standard alert panel, run by
   20.19 @@ -94,15 +85,3 @@
   20.20  //@}
   20.21  
   20.22  @end
   20.23 -
   20.24 -
   20.25 -/* Attribute keys for creating identities: */
   20.26 -
   20.27 -#define kMYIdentityCommonNameKey    @"Common Name"      // NSString. Required!
   20.28 -#define kMYIdentityGivenNameKey     @"Given Name"
   20.29 -#define kMYIdentitySurnameKey       @"Surname"
   20.30 -#define kMYIdentityDescriptionKey   @"Description"
   20.31 -#define kMYIdentityEmailAddressKey  @"Email Address"
   20.32 -#define kMYIdentityValidFromKey     @"Valid From"       // NSDate. Defaults to the current date/time
   20.33 -#define kMYIdentityValidToKey       @"Valid To"         // NSDate. Defaults to one year from ValidFrom
   20.34 -#define kMYIdentitySerialNumberKey  @"Serial Number"    // NSNumber. Defaults to 1
    21.1 --- a/MYPrivateKey.m	Fri Jun 05 08:57:18 2009 -0700
    21.2 +++ b/MYPrivateKey.m	Sat Jun 06 15:01:28 2009 -0700
    21.3 @@ -118,11 +118,6 @@
    21.4  }
    21.5  
    21.6  
    21.7 -- (MYIdentity*) createSelfSignedIdentityWithAttributes: (NSDictionary*)attributes {
    21.8 -    return MYIdentityCreateSelfSigned(self, attributes);
    21.9 -}
   21.10 -
   21.11 -
   21.12  #endif
   21.13  
   21.14  
    22.1 --- a/MYPublicKey.h	Fri Jun 05 08:57:18 2009 -0700
    22.2 +++ b/MYPublicKey.h	Sat Jun 06 15:01:28 2009 -0700
    22.3 @@ -48,6 +48,24 @@
    22.4   *  Advanced methods. 
    22.5   */
    22.6  //@{
    22.7 +
    22.8 +/** Initializes a public key directly from its raw RSA modulus and exponent.
    22.9 +    These numbers must come from an existing key-pair generated by the RSA algorithm; 
   22.10 +    you CANNOT just pass in random data and create a working key! (To create a new key pair,
   22.11 +    call -[MYKeychain generateRSAKeyPairOfSize:].)
   22.12 +    @param modulus  RSA modulus, a very large integer represented as a blob of big-endian data.
   22.13 +    @param exponent  RSA exponent, a prime number, commonly 17 or 65537.
   22.14 +*/
   22.15 +- (id) initWithModulus: (NSData*)modulus exponent: (unsigned)exponent;
   22.16 +
   22.17 +/** Retrieves the raw RSA modulus and exponent, which together uniquely specify the key.
   22.18 +    The length of the modulus is the size, in bits, of the key: for example, a 2048-bit key
   22.19 +    has 256 bytes of modulus data.
   22.20 +    @param outModulus  On return, will contain the modulus: a very large positive integer represented
   22.21 +                       as a blob of unsigned big-endian data.
   22.22 +    @param outExponent  On return, will contain the exponent: a prime number, often 17 or 65537. */
   22.23 +- (BOOL) getModulus: (NSData**)outModulus exponent: (unsigned*)outExponent;
   22.24 +
   22.25  #if !TARGET_OS_IPHONE
   22.26  
   22.27  /** Encrypts a session key using this public key. 
    23.1 --- a/MYPublicKey.m	Fri Jun 05 08:57:18 2009 -0700
    23.2 +++ b/MYPublicKey.m	Sat Jun 06 15:01:28 2009 -0700
    23.3 @@ -9,6 +9,9 @@
    23.4  #import "MYPublicKey.h"
    23.5  #import "MYCrypto_Private.h"
    23.6  #import "MYDigest.h"
    23.7 +#import "MYASN1Object.h"
    23.8 +#import "MYDEREncoder.h"
    23.9 +#import "MYBERParser.h"
   23.10  #import "MYErrorUtils.h"
   23.11  #import <CommonCrypto/CommonDigest.h>
   23.12  
   23.13 @@ -17,6 +20,16 @@
   23.14  @implementation MYPublicKey
   23.15  
   23.16  
   23.17 +- (id) initWithModulus: (NSData*)modulus exponent: (unsigned)exponent {
   23.18 +    // An RSA key is encoded in ASN.1 as a sequence of modulus and exponent, both as integers.
   23.19 +    MYASN1BigInteger *modulusInt = [[MYASN1BigInteger alloc] initWithUnsignedData: modulus];
   23.20 +    id asn1 = $array( modulusInt, $object(exponent) );
   23.21 +    [modulusInt release];
   23.22 +    NSData *keyData = [MYDEREncoder encodeRootObject: asn1 error: nil];
   23.23 +    return [self initWithKeyData: keyData];
   23.24 +}
   23.25 +
   23.26 +
   23.27  - (void) dealloc
   23.28  {
   23.29      [_digest release];
   23.30 @@ -52,6 +65,18 @@
   23.31  #endif
   23.32  
   23.33  
   23.34 +- (BOOL) getModulus: (NSData**)outModulus exponent: (unsigned*)outExponent {
   23.35 +    Assert(outModulus!=nil);
   23.36 +    Assert(outExponent!=nil);
   23.37 +    NSArray *asn1 = $castIf(NSArray, MYBERParse(self.keyData, nil));
   23.38 +    if (!asn1 || asn1.count != 2)
   23.39 +        return NO;
   23.40 +    *outModulus = $castIf(MYASN1BigInteger, [asn1 objectAtIndex: 0]).unsignedData;
   23.41 +    *outExponent = $castIf(NSNumber, [asn1 objectAtIndex: 1]).unsignedIntValue;
   23.42 +    return (*outModulus!=nil && *outExponent>=3);
   23.43 +}
   23.44 +
   23.45 +
   23.46  - (NSData*) rawEncryptData: (NSData*)data {
   23.47      return [self _crypt: data operation: YES];
   23.48  }
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/Tests/selfsigned cert parsed.txt	Sat Jun 06 15:01:28 2009 -0700
    24.3 @@ -0,0 +1,88 @@
    24.4 +Parsed form of selfsigned.cer:
    24.5 + 
    24.6 +Sequence:                       <-- top
    24.7 +    Sequence:                       <-- info
    24.8 +        MYASN1Object[2/0]:              <-- version (tag=0, constructed)
    24.9 +            2                       
   24.10 +        1                               <-- serial number
   24.11 +        Sequence:
   24.12 +            {1 2 840 113549 1 1 1}      <-- algorithm ID
   24.13 +        Sequence:                       <-- issuer (same as subject here)
   24.14 +            Set:
   24.15 +                Sequence:
   24.16 +                    {2 5 4 4}
   24.17 +                    Widdershins
   24.18 +            Set:
   24.19 +                Sequence:
   24.20 +                    {1 2 840 113549 1 9 1}
   24.21 +                    waldo@example.com
   24.22 +            Set:
   24.23 +                Sequence:
   24.24 +                    {2 5 4 3}
   24.25 +                    waldo
   24.26 +            Set:
   24.27 +                Sequence:
   24.28 +                    {2 5 4 42}
   24.29 +                    Waldo
   24.30 +            Set:
   24.31 +                Sequence:
   24.32 +                    {2 5 4 13}
   24.33 +                    Just a fictitious person
   24.34 +        Sequence:                       <--validity
   24.35 +            2009-04-12 21:54:35 -0700
   24.36 +            2010-04-13 21:54:35 -0700
   24.37 +        Sequence:                       <-- subject
   24.38 +            Set:
   24.39 +                Sequence:                   <-- surname
   24.40 +                    {2 5 4 4}
   24.41 +                    Widdershins
   24.42 +            Set:
   24.43 +                Sequence:                   <-- email
   24.44 +                    {1 2 840 113549 1 9 1}
   24.45 +                    waldo@example.com
   24.46 +            Set:
   24.47 +                Sequence:                   <-- common name
   24.48 +                    {2 5 4 3}
   24.49 +                    waldo
   24.50 +            Set:
   24.51 +                Sequence:                   <-- first name
   24.52 +                    {2 5 4 42}
   24.53 +                    Waldo
   24.54 +            Set:
   24.55 +                Sequence:                   <-- description
   24.56 +                    {2 5 4 13}
   24.57 +                    Just a fictitious person
   24.58 +        Sequence:                       <-- public key info
   24.59 +            Sequence:
   24.60 +                {1 2 840 113549 1 1 1}      <-- algorithm ID (RSA)
   24.61 +                <null>
   24.62 +            MYBitString<3082010a 02820101 0095713c 360badf2 d8575ebd 278fa26b
   24.63 +            a2e6d05e 1eb04eaa 9fa6f11b fd341556 038b3077 525c7adb f5aedf3b
   24.64 +            249b08e6 7f77af26 7ff2feb8 5f4ccb96 5269dbd2 f01f19b6 55fc4ea3
   24.65 +            a85f2ede 11ff80f8 fc23e662 f263f685 06a9ec07 f7ee4249 af184f21
   24.66 +            2d9253d8 7f6f7cbc 96e6ba5c abc8f4e7 3bf6100b 06dcf3ee 999d4170
   24.67 +            f5dd005d a24a54a1 3edaddd5 0675409d 6728a387 5fa71898 ebf7d93d
   24.68 +            4af8742d f9a0e9ad 6dc21cfa fc2d1967 e692575b 56e5376c 8cf008e8
   24.69 +            a442d787 6843a92e 9501b144 8a75adef 5e804fec 6d09740d 1ea8442e
   24.70 +            67fac3be c5ea3af5 d95d9f95 2c507711 01c45942 28ad1410 23525324
   24.71 +            62848476 d987d3c7 d65f9057 daf1e853 77020301 0001>       <-- DER-encoded public key
   24.72 +        MYASN1Object[2/3]:              <-- extensions
   24.73 +            Sequence:
   24.74 +                Sequence:
   24.75 +                    {2 5 29 15}
   24.76 +                    <030202fc>
   24.77 +                Sequence:
   24.78 +                    {2 5 29 37}
   24.79 +                    <301a0608 2b060105 05070301 06082b06 01050507 03020604 551d2500>
   24.80 +    Sequence:                           <-- signature algorithm ID
   24.81 +        {1 2 840 113549 1 1 5}
   24.82 +        <null>
   24.83 +    MYBitString<79c8e789 50a11fcb 7398f5fe 0cfa2595 b2476f53 62dfbea2 70ae3a8b
   24.84 +    fdaf5a57 39be6101 fc5e0929 e57a0b2b 41e3ab52 f78ef1b5 ecc8848c da7f42aa
   24.85 +    b57c3df4 df4125a9 db4e6388 197c2a1c e326c1a5 5203b4ef da057b91 4abc43aa
   24.86 +    3eeee6aa fe4303c3 0f000175 16b916b5 72f8b74f c682a06f 920e3bbf a16cdad8
   24.87 +    fce3f184 adccc61e 8d3b44e5 8bd103f0 46310f6a 992f240a b290354c 04c519c9
   24.88 +    22276df6 310ccb8e 942e38f6 555ca40b 71482e52 146a9988 f021c2c0 2d285db5
   24.89 +    59d48eaf 7b20559f 068ea1a0 f07fbaee 29284ada 28bf8344 f435f30f 6263f0c9
   24.90 +    9c4920ce a1b7c6c0 9cfa3bbb af5a0fee 5b0e94eb 9c57d28b 1bb9c977 be53e4bb
   24.91 +    b675ffaa>                           <-- signature data