MYCertificate.m
changeset 25 38c3c3923e1f
parent 21 2c300b15b381
child 26 d9c2a06d4e4e
     1.1 --- a/MYCertificate.m	Sat Jun 06 15:01:28 2009 -0700
     1.2 +++ b/MYCertificate.m	Wed Jun 10 09:02:18 2009 -0700
     1.3 @@ -13,8 +13,6 @@
     1.4  #import "MYCertificateInfo.h"
     1.5  #import "MYErrorUtils.h"
     1.6  
     1.7 -#if !MYCRYPTO_USE_IPHONE_API
     1.8 -
     1.9  
    1.10  @implementation MYCertificate
    1.11  
    1.12 @@ -34,28 +32,51 @@
    1.13  
    1.14  /** Creates a MYCertificate object from exported key data, but does not add it to any keychain. */
    1.15  - (id) initWithCertificateData: (NSData*)data
    1.16 +#if !MYCRYPTO_USE_IPHONE_API
    1.17                            type: (CSSM_CERT_TYPE) type
    1.18                        encoding: (CSSM_CERT_ENCODING) encoding
    1.19 +#endif
    1.20  {
    1.21      Assert(data);
    1.22 +    SecCertificateRef certificateRef = NULL;
    1.23 +#if MYCRYPTO_USE_IPHONE_API
    1.24 +    certificateRef = SecCertificateCreateWithData(NULL, (CFDataRef)data);
    1.25 +#else
    1.26      CSSM_DATA cssmData = {.Data=(void*)data.bytes, .Length=data.length};
    1.27 -    SecCertificateRef certificateRef = NULL;
    1.28      if (!check(SecCertificateCreateFromData(&cssmData, type, encoding, &certificateRef),
    1.29 -        @"SecCertificateCreateFromData")) {
    1.30 +               @"SecCertificateCreateFromData"))
    1.31 +        certificateRef = NULL;
    1.32 +#endif
    1.33 +    if (!certificateRef) {
    1.34          [self release];
    1.35          return nil;
    1.36      }
    1.37      self = [self initWithCertificateRef: certificateRef];
    1.38      CFRelease(certificateRef);
    1.39 +    
    1.40 +    // If the cert is self-signed, verify its signature. Apple's frameworks don't do this,
    1.41 +    // even the SecTrust API; if the signature doesn't verify, they just assume it could be
    1.42 +    // signed by a different cert. Seems like a bad decision to me, so I'll add the check:
    1.43 +    MYCertificateInfo *info = self.info;
    1.44 +    if (info.isRoot) {
    1.45 +        Log(@"Verifying self-signed certificate %@ ...", self);
    1.46 +        if (![info verifySignatureWithKey: self.publicKey]) {
    1.47 +            Log(@"Self-signed cert failed signature verification (%@)", self);
    1.48 +            [self release];
    1.49 +            return nil;
    1.50 +        }
    1.51 +    }
    1.52 +    
    1.53      return self;
    1.54  }
    1.55  
    1.56 +#if !MYCRYPTO_USE_IPHONE_API
    1.57  - (id) initWithCertificateData: (NSData*)data {
    1.58      return [self initWithCertificateData: data 
    1.59                                      type: CSSM_CERT_X_509v3 
    1.60                                  encoding: CSSM_CERT_ENCODING_BER];
    1.61  }
    1.62 -
    1.63 +#endif
    1.64  - (void) dealloc
    1.65  {
    1.66      [_info release];
    1.67 @@ -78,6 +99,7 @@
    1.68  }
    1.69  
    1.70  
    1.71 +#if !TARGET_OS_IPHONE
    1.72  + (MYCertificate*) preferredCertificateForName: (NSString*)name {
    1.73      SecCertificateRef certRef = NULL;
    1.74      if (!check(SecCertificateCopyPreference((CFStringRef)name, 0, &certRef),
    1.75 @@ -90,23 +112,49 @@
    1.76      return check(SecCertificateSetPreference(_certificateRef, (CFStringRef)name, 0, NULL),
    1.77                   @"SecCertificateSetPreference");
    1.78  }
    1.79 +#endif TARGET_OS_IPHONE
    1.80  
    1.81  
    1.82  @synthesize certificateRef=_certificateRef;
    1.83  
    1.84  - (NSData*) certificateData {
    1.85 +#if MYCRYPTO_USE_IPHONE_API
    1.86 +    CFDataRef data = SecCertificateCopyData(_certificateRef);
    1.87 +    return data ?[(id)CFMakeCollectable(data) autorelease] :nil;
    1.88 +#else
    1.89      CSSM_DATA cssmData;
    1.90      if (!check(SecCertificateGetData(_certificateRef, &cssmData),
    1.91                 @"SecCertificateGetData"))
    1.92          return nil;
    1.93      return [NSData dataWithBytes: cssmData.Data length: cssmData.Length];
    1.94 +#endif
    1.95  }
    1.96  
    1.97  - (MYPublicKey*) publicKey {
    1.98      SecKeyRef keyRef = NULL;
    1.99 +#if MYCRYPTO_USE_IPHONE_API
   1.100 +    SecTrustRef trust = NULL;
   1.101 +    SecPolicyRef policy = SecPolicyCreateBasicX509();
   1.102 +    OSStatus err = SecTrustCreateWithCertificates((CFArrayRef)$array((id)_certificateRef),
   1.103 +                                                  policy,
   1.104 +                                                  &trust);
   1.105 +    CFRelease(policy);
   1.106 +    if (!check(err,@"SecTrustCreateWithCertificates"))
   1.107 +        return nil;
   1.108 +    SecTrustResultType result;
   1.109 +    if (!check(SecTrustEvaluate(trust, &result), @"SecTrustEvaluate")) {
   1.110 +        CFRelease(trust);
   1.111 +        return nil;
   1.112 +    }
   1.113 +    keyRef = SecTrustCopyPublicKey(trust);
   1.114 +    CFRelease(trust);
   1.115 +#else
   1.116      if (!check(SecCertificateCopyPublicKey(_certificateRef, &keyRef),
   1.117                 @"SecCertificateCopyPublicKey") || !keyRef)
   1.118          return nil;
   1.119 +#endif
   1.120 +    if (!keyRef)
   1.121 +        return nil;
   1.122      MYPublicKey *key = [[[MYPublicKey alloc] initWithKeyRef: keyRef] autorelease];
   1.123      CFRelease(keyRef);
   1.124      return key;
   1.125 @@ -129,18 +177,27 @@
   1.126  
   1.127  - (NSString*) commonName {
   1.128      CFStringRef name = NULL;
   1.129 +#if MYCRYPTO_USE_IPHONE_API
   1.130 +    name = SecCertificateCopySubjectSummary(_certificateRef);
   1.131 +#else
   1.132      if (!check(SecCertificateCopyCommonName(_certificateRef, &name),
   1.133 -               @"SecCertificateCopyCommonName") || !name)
   1.134 +               @"SecCertificateCopyCommonName"))
   1.135          return nil;
   1.136 -    return [(id)CFMakeCollectable(name) autorelease];
   1.137 +#endif
   1.138 +    return name ?[NSMakeCollectable(name) autorelease] :nil;
   1.139  }
   1.140  
   1.141  - (NSArray*) emailAddresses {
   1.142 +#if MYCRYPTO_USE_IPHONE_API
   1.143 +    NSString *email = self.info.subject.emailAddress;
   1.144 +    return email ?$array(email) :nil;
   1.145 +#else
   1.146      CFArrayRef addrs = NULL;
   1.147      if (!check(SecCertificateCopyEmailAddresses(_certificateRef, &addrs),
   1.148                 @"SecCertificateCopyEmailAddresses") || !addrs)
   1.149          return nil;
   1.150      return [(id)CFMakeCollectable(addrs) autorelease];
   1.151 +#endif
   1.152  }
   1.153  
   1.154  
   1.155 @@ -148,6 +205,37 @@
   1.156  #pragma mark TRUST/POLICY STUFF:
   1.157  
   1.158  
   1.159 +- (SecTrustResultType) evaluateTrustWithPolicy: (SecPolicyRef)policy {
   1.160 +    SecTrustRef trust;
   1.161 +    if (!check(SecTrustCreateWithCertificates((CFArrayRef)$array((id)_certificateRef), policy, &trust), 
   1.162 +               @"SecTrustCreateWithCertificates"))
   1.163 +        return kSecTrustResultOtherError;
   1.164 +    SecTrustResultType result;
   1.165 +    if (!check(SecTrustEvaluate(trust, &result), @"SecTrustEvaluate"))
   1.166 +        result = kSecTrustResultOtherError;
   1.167 +    
   1.168 +#if 0
   1.169 +    // This is just to log details:
   1.170 +    CSSM_TP_APPLE_EVIDENCE_INFO *status;
   1.171 +    CFArrayRef certChain;
   1.172 +    if (check(SecTrustGetResult(trust, &result, &certChain, &status), @"SecTrustGetResult")) {
   1.173 +        Log(@"evaluateTrust: result=%@, bits=%X, certChain=%@", MYTrustResultDescribe(result),status->StatusBits, certChain);
   1.174 +        for (unsigned i=0; i<status->NumStatusCodes; i++)
   1.175 +            Log(@"    #%i: %X", i, status->StatusCodes[i]);
   1.176 +        CFRelease(certChain);
   1.177 +    }
   1.178 +#endif
   1.179 +    
   1.180 +    CFRelease(trust);
   1.181 +    return result;
   1.182 +}
   1.183 +
   1.184 +- (SecTrustResultType) evaluateTrust {
   1.185 +    return [self evaluateTrustWithPolicy: [[self class] X509Policy]];
   1.186 +}
   1.187 +
   1.188 +
   1.189 +#if !MYCRYPTO_USE_IPHONE_API
   1.190  + (SecPolicyRef) policyForOID: (CSSM_OID) policyOID {
   1.191      SecPolicySearchRef search;
   1.192      if (!check(SecPolicySearchCreate(CSSM_CERT_X_509v3, &policyOID, NULL, &search),
   1.193 @@ -159,29 +247,41 @@
   1.194      CFRelease(search);
   1.195      return policy;
   1.196  }
   1.197 +#endif
   1.198  
   1.199  + (SecPolicyRef) X509Policy {
   1.200      static SecPolicyRef sX509Policy = NULL;
   1.201 -    if (!sX509Policy)
   1.202 +    if (!sX509Policy) {
   1.203 +#if MYCRYPTO_USE_IPHONE_API
   1.204 +        sX509Policy = SecPolicyCreateBasicX509();
   1.205 +#else
   1.206          sX509Policy = [self policyForOID: CSSMOID_APPLE_X509_BASIC];
   1.207 +#endif
   1.208 +    }
   1.209      return sX509Policy;
   1.210  }
   1.211  
   1.212  + (SecPolicyRef) SSLPolicy {
   1.213      static SecPolicyRef sSSLPolicy = NULL;
   1.214 -    if (!sSSLPolicy)
   1.215 +    if (!sSSLPolicy) {
   1.216 +#if MYCRYPTO_USE_IPHONE_API
   1.217 +        sSSLPolicy = SecPolicyCreateSSL(NO,NULL);
   1.218 +#else
   1.219          sSSLPolicy = [self policyForOID: CSSMOID_APPLE_TP_SSL];
   1.220 +#endif
   1.221 +    }
   1.222      return sSSLPolicy;
   1.223  }
   1.224  
   1.225 +#if !TARGET_OS_IPHONE
   1.226  + (SecPolicyRef) SMIMEPolicy {
   1.227      static SecPolicyRef sSMIMEPolicy = NULL;
   1.228 -    if (!sSMIMEPolicy)
   1.229 +    if (!sSMIMEPolicy) {
   1.230          sSMIMEPolicy = [self policyForOID: CSSMOID_APPLE_TP_SMIME];
   1.231 +    }
   1.232      return sSMIMEPolicy;
   1.233  }
   1.234  
   1.235 -
   1.236  - (CSSM_CERT_TYPE) certificateType {
   1.237      CSSM_CERT_TYPE type = CSSM_CERT_UNKNOWN;
   1.238      if (!check(SecCertificateGetType(_certificateRef, &type), @"SecCertificateGetType"))
   1.239 @@ -212,19 +312,12 @@
   1.240      } else
   1.241          return paramErr;
   1.242  }
   1.243 +#endif
   1.244  
   1.245  
   1.246  @end
   1.247  
   1.248  
   1.249 -NSString* MYPolicyGetName( SecPolicyRef policy ) {
   1.250 -    if (!policy)
   1.251 -        return @"(null)";
   1.252 -    CSSM_OID oid = {};
   1.253 -    SecPolicyGetOID(policy, &oid);
   1.254 -    return $sprintf(@"SecPolicy[%@]", OIDAsString(oid));
   1.255 -}
   1.256 -
   1.257  NSString* MYTrustResultDescribe( SecTrustResultType result ) {
   1.258      static NSString* const kTrustResultNames[kSecTrustResultOtherError+1] = {
   1.259          @"Invalid",
   1.260 @@ -243,6 +336,15 @@
   1.261  }
   1.262  
   1.263  
   1.264 +#if !TARGET_OS_IPHONE
   1.265 +NSString* MYPolicyGetName( SecPolicyRef policy ) {
   1.266 +    if (!policy)
   1.267 +        return @"(null)";
   1.268 +    CSSM_OID oid = {};
   1.269 +    SecPolicyGetOID(policy, &oid);
   1.270 +    return $sprintf(@"SecPolicy[%@]", OIDAsString(oid));
   1.271 +}
   1.272 +
   1.273  NSString* MYTrustDescribe( SecTrustRef trust ) {
   1.274      SecTrustResultType result;
   1.275      CFArrayRef certChain=NULL;
   1.276 @@ -275,9 +377,10 @@
   1.277          return result;
   1.278      }
   1.279  }
   1.280 +#endif
   1.281  
   1.282  
   1.283 -
   1.284 +#if !TARGET_OS_IPHONE
   1.285  TestCase(Trust) {
   1.286      Log(@"X.509 policy = %@", MYPolicyGetName([MYCertificate X509Policy]));
   1.287      Log(@"  SSL policy = %@", MYPolicyGetName([MYCertificate SSLPolicy]));
   1.288 @@ -288,9 +391,7 @@
   1.289              Log(@"---- %@ = %@", cert, settings);
   1.290      }
   1.291  }
   1.292 -
   1.293 -
   1.294 -#endif !MYCRYPTO_USE_IPHONE_API
   1.295 +#endif
   1.296  
   1.297  
   1.298