MYCertificate.m
author Jens Alfke <jens@mooseyard.com>
Fri Jun 05 08:57:18 2009 -0700 (2009-06-05)
changeset 20 df9da0f6b358
parent 14 3af1d1c0ceb5
child 21 2c300b15b381
permissions -rw-r--r--
Factored out the name accessors of MYParsedCertificate into a new class MYCertificateName, so that both subject and issuer can be accessed. A bit of other cleanup too.
     1 //
     2 //  MYCertificate.m
     3 //  MYCrypto
     4 //
     5 //  Created by Jens Alfke on 3/26/09.
     6 //  Copyright 2009 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #import "MYCertificate.h"
    10 #import "MYCrypto_Private.h"
    11 #import "MYIdentity.h"
    12 #import "MYDigest.h"
    13 #import "MYErrorUtils.h"
    14 
    15 #if !MYCRYPTO_USE_IPHONE_API
    16 
    17 
    18 @implementation MYCertificate
    19 
    20 
    21 /** Creates a MYCertificate object for an existing Keychain certificate reference. */
    22 - (id) initWithCertificateRef: (SecCertificateRef)certificateRef {
    23     self = [super initWithKeychainItemRef: (SecKeychainItemRef)certificateRef];
    24     if (self) {
    25         _certificateRef = certificateRef;     // superclass has already CFRetained it
    26     }
    27     return self;
    28 }
    29 
    30 + (MYCertificate*) certificateWithCertificateRef: (SecCertificateRef)certificateRef {
    31     return [[[self alloc] initWithCertificateRef: certificateRef] autorelease];
    32 }
    33 
    34 /** Creates a MYCertificate object from exported key data, but does not add it to any keychain. */
    35 - (id) initWithCertificateData: (NSData*)data
    36                           type: (CSSM_CERT_TYPE) type
    37                       encoding: (CSSM_CERT_ENCODING) encoding
    38 {
    39     Assert(data);
    40     CSSM_DATA cssmData = {.Data=(void*)data.bytes, .Length=data.length};
    41     SecCertificateRef certificateRef = NULL;
    42     if (!check(SecCertificateCreateFromData(&cssmData, type, encoding, &certificateRef),
    43         @"SecCertificateCreateFromData")) {
    44         [self release];
    45         return nil;
    46     }
    47     self = [self initWithCertificateRef: certificateRef];
    48     CFRelease(certificateRef);
    49     return self;
    50 }
    51 
    52 - (id) initWithCertificateData: (NSData*)data {
    53     return [self initWithCertificateData: data 
    54                                     type: CSSM_CERT_X_509v3 
    55                                 encoding: CSSM_CERT_ENCODING_BER];
    56 }
    57 
    58 
    59 - (NSString*) description {
    60     return $sprintf(@"%@[%@ %@/%p]", 
    61                     [self class],
    62                     self.commonName,
    63                     self.certificateData.my_SHA1Digest.abbreviatedHexString,
    64                     _certificateRef);
    65 }
    66 
    67 
    68 - (BOOL)isEqualToCertificate:(MYCertificate*)cert {
    69     return [self isEqual: cert] || [self.certificateData isEqual: cert.certificateData];
    70 }
    71 
    72 
    73 + (MYCertificate*) preferredCertificateForName: (NSString*)name {
    74     SecCertificateRef certRef = NULL;
    75     if (!check(SecCertificateCopyPreference((CFStringRef)name, 0, &certRef),
    76                @"SecCertificateCopyPreference"))
    77         return nil;
    78     return [[[MYCertificate alloc] initWithCertificateRef: certRef] autorelease];
    79 }
    80 
    81 - (BOOL) setPreferredCertificateForName: (NSString*)name {
    82     return check(SecCertificateSetPreference(_certificateRef, (CFStringRef)name, 0, NULL),
    83                  @"SecCertificateSetPreference");
    84 }
    85 
    86 
    87 @synthesize certificateRef=_certificateRef;
    88 
    89 - (NSData*) certificateData {
    90     CSSM_DATA cssmData;
    91     if (!check(SecCertificateGetData(_certificateRef, &cssmData),
    92                @"SecCertificateGetData"))
    93         return nil;
    94     return [NSData dataWithBytes: cssmData.Data length: cssmData.Length];
    95 }
    96 
    97 - (MYPublicKey*) publicKey {
    98     SecKeyRef keyRef = NULL;
    99     if (!check(SecCertificateCopyPublicKey(_certificateRef, &keyRef),
   100                @"SecCertificateCopyPublicKey") || !keyRef)
   101         return nil;
   102     MYPublicKey *key = [[[MYPublicKey alloc] initWithKeyRef: keyRef] autorelease];
   103     CFRelease(keyRef);
   104     return key;
   105 }
   106 
   107 - (MYIdentity*) identity {
   108     return [[[MYIdentity alloc] initWithCertificateRef: _certificateRef] autorelease];
   109 }
   110 
   111 - (NSString*) commonName {
   112     CFStringRef name = NULL;
   113     if (!check(SecCertificateCopyCommonName(_certificateRef, &name),
   114                @"SecCertificateCopyCommonName") || !name)
   115         return nil;
   116     return [(id)CFMakeCollectable(name) autorelease];
   117 }
   118 
   119 - (NSArray*) emailAddresses {
   120     CFArrayRef addrs = NULL;
   121     if (!check(SecCertificateCopyEmailAddresses(_certificateRef, &addrs),
   122                @"SecCertificateCopyEmailAddresses") || !addrs)
   123         return nil;
   124     return [(id)CFMakeCollectable(addrs) autorelease];
   125 }
   126 
   127 
   128 #pragma mark -
   129 #pragma mark TRUST/POLICY STUFF:
   130 
   131 
   132 + (SecPolicyRef) policyForOID: (CSSM_OID) policyOID {
   133     SecPolicySearchRef search;
   134     if (!check(SecPolicySearchCreate(CSSM_CERT_X_509v3, &policyOID, NULL, &search),
   135            @"SecPolicySearchCreate"))
   136         return nil;
   137     SecPolicyRef policy = NULL;
   138     if (!check(SecPolicySearchCopyNext(search, &policy), @"SecPolicySearchCopyNext"))
   139         policy = NULL;
   140     CFRelease(search);
   141     return policy;
   142 }
   143 
   144 + (SecPolicyRef) X509Policy {
   145     static SecPolicyRef sX509Policy = NULL;
   146     if (!sX509Policy)
   147         sX509Policy = [self policyForOID: CSSMOID_APPLE_X509_BASIC];
   148     return sX509Policy;
   149 }
   150 
   151 + (SecPolicyRef) SSLPolicy {
   152     static SecPolicyRef sSSLPolicy = NULL;
   153     if (!sSSLPolicy)
   154         sSSLPolicy = [self policyForOID: CSSMOID_APPLE_TP_SSL];
   155     return sSSLPolicy;
   156 }
   157 
   158 + (SecPolicyRef) SMIMEPolicy {
   159     static SecPolicyRef sSMIMEPolicy = NULL;
   160     if (!sSMIMEPolicy)
   161         sSMIMEPolicy = [self policyForOID: CSSMOID_APPLE_TP_SMIME];
   162     return sSMIMEPolicy;
   163 }
   164 
   165 
   166 - (CSSM_CERT_TYPE) certificateType {
   167     CSSM_CERT_TYPE type = CSSM_CERT_UNKNOWN;
   168     if (!check(SecCertificateGetType(_certificateRef, &type), @"SecCertificateGetType"))
   169         type = CSSM_CERT_UNKNOWN;
   170     return type;
   171 }
   172 
   173 - (NSArray*) trustSettings {
   174     CFArrayRef settings = NULL;
   175     OSStatus err = SecTrustSettingsCopyTrustSettings(_certificateRef, kSecTrustSettingsDomainUser, 
   176                                                      &settings);
   177     if (err == errSecItemNotFound || !check(err,@"SecTrustSettingsCopyTrustSettings") || !settings)
   178         return nil;
   179     return [(id)CFMakeCollectable(settings) autorelease];
   180 }
   181         
   182 
   183 - (BOOL) setUserTrust: (SecTrustUserSetting)trustSetting
   184 {
   185     if (trustSetting == kSecTrustResultProceed) {
   186         return check(SecTrustSettingsSetTrustSettings(_certificateRef, 
   187                                                       kSecTrustSettingsDomainUser, nil),
   188                      @"SecTrustSettingsSetTrustSettings");
   189     } else if (trustSetting == kSecTrustResultDeny) {
   190         OSStatus err = SecTrustSettingsRemoveTrustSettings(_certificateRef, 
   191                                                            kSecTrustSettingsDomainUser);
   192         return err == errSecItemNotFound || check(err, @"SecTrustSettingsRemoveTrustSettings");
   193     } else
   194         return paramErr;
   195 }
   196 
   197 
   198 @end
   199 
   200 
   201 NSString* MYPolicyGetName( SecPolicyRef policy ) {
   202     if (!policy)
   203         return @"(null)";
   204     CSSM_OID oid = {};
   205     SecPolicyGetOID(policy, &oid);
   206     return $sprintf(@"SecPolicy[%@]", OIDAsString(oid));
   207 }
   208 
   209 NSString* MYTrustResultDescribe( SecTrustResultType result ) {
   210     static NSString* const kTrustResultNames[kSecTrustResultOtherError+1] = {
   211         @"Invalid",
   212         @"Proceed",
   213         @"Confirm",
   214         @"Deny",
   215         @"Unspecified",
   216         @"RecoverableTrustFailure",
   217         @"FatalTrustFailure",
   218         @"OtherError"
   219     };
   220     if (result>=0 && result <=kSecTrustResultOtherError)
   221         return kTrustResultNames[result];
   222     else
   223         return $sprintf(@"(Unknown trust result %i)", result);
   224 }
   225 
   226 
   227 NSString* MYTrustDescribe( SecTrustRef trust ) {
   228     SecTrustResultType result;
   229     CFArrayRef certChain=NULL;
   230     CSSM_TP_APPLE_EVIDENCE_INFO* statusChain;
   231     OSStatus err = SecTrustGetResult(trust, &result, &certChain, &statusChain);
   232     NSString *desc;
   233     if (err)
   234         desc = $sprintf(@"SecTrust[%p, err=%@]", trust, MYErrorName(NSOSStatusErrorDomain, err));
   235     else
   236         desc = $sprintf(@"SecTrust[%@, %u in chain]", 
   237                         MYTrustResultDescribe(result),
   238                         CFArrayGetCount(certChain));
   239     if (certChain) CFRelease(certChain);
   240     return desc;
   241 }
   242 
   243 
   244 // Taken from Keychain.framework
   245 NSString* OIDAsString(const CSSM_OID oid) {
   246     if ((NULL == oid.Data) || (0 >= oid.Length)) {
   247         return nil;
   248     } else {
   249         NSMutableString *result = [NSMutableString stringWithCapacity:(4 * oid.Length)];
   250         unsigned int i;
   251         
   252         for (i = 0; i < oid.Length; ++i) {
   253             [result appendFormat:@"%s%hhu", ((0 == i) ? "" : ", "), oid.Data[i]];
   254         }
   255         
   256         return result;
   257     }
   258 }
   259 
   260 
   261 
   262 TestCase(Trust) {
   263     Log(@"X.509 policy = %@", MYPolicyGetName([MYCertificate X509Policy]));
   264     Log(@"  SSL policy = %@", MYPolicyGetName([MYCertificate SSLPolicy]));
   265     Log(@"SMIME policy = %@", MYPolicyGetName([MYCertificate SMIMEPolicy]));
   266     for (MYCertificate *cert in [[MYKeychain defaultKeychain] enumerateCertificates]) {
   267         NSArray *settings = cert.trustSettings;
   268         if (settings)
   269             Log(@"---- %@ = %@", cert, settings);
   270     }
   271 }
   272 
   273 
   274 #endif !MYCRYPTO_USE_IPHONE_API
   275 
   276 
   277 
   278 /*
   279  Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   280  
   281  Redistribution and use in source and binary forms, with or without modification, are permitted
   282  provided that the following conditions are met:
   283  
   284  * Redistributions of source code must retain the above copyright notice, this list of conditions
   285  and the following disclaimer.
   286  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   287  and the following disclaimer in the documentation and/or other materials provided with the
   288  distribution.
   289  
   290  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   291  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   292  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   293  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   294  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   295   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   296  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   297  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   298  */