A snapshot taken during the long, agonizing crawl toward getting everything running on iPhone.
5 // Created by Jens Alfke on 3/26/09.
6 // Copyright 2009 Jens Alfke. All rights reserved.
9 #import "MYCertificate.h"
10 #import "MYCrypto_Private.h"
11 #import "MYIdentity.h"
13 #import "MYCertificateInfo.h"
14 #import "MYErrorUtils.h"
16 #if !MYCRYPTO_USE_IPHONE_API
19 @implementation MYCertificate
22 /** Creates a MYCertificate object for an existing Keychain certificate reference. */
23 - (id) initWithCertificateRef: (SecCertificateRef)certificateRef {
24 self = [super initWithKeychainItemRef: (SecKeychainItemRef)certificateRef];
26 _certificateRef = certificateRef; // superclass has already CFRetained it
31 + (MYCertificate*) certificateWithCertificateRef: (SecCertificateRef)certificateRef {
32 return [[[self alloc] initWithCertificateRef: certificateRef] autorelease];
35 /** Creates a MYCertificate object from exported key data, but does not add it to any keychain. */
36 - (id) initWithCertificateData: (NSData*)data
37 type: (CSSM_CERT_TYPE) type
38 encoding: (CSSM_CERT_ENCODING) encoding
41 CSSM_DATA cssmData = {.Data=(void*)data.bytes, .Length=data.length};
42 SecCertificateRef certificateRef = NULL;
43 if (!check(SecCertificateCreateFromData(&cssmData, type, encoding, &certificateRef),
44 @"SecCertificateCreateFromData")) {
48 self = [self initWithCertificateRef: certificateRef];
49 CFRelease(certificateRef);
53 - (id) initWithCertificateData: (NSData*)data {
54 return [self initWithCertificateData: data
55 type: CSSM_CERT_X_509v3
56 encoding: CSSM_CERT_ENCODING_BER];
67 - (NSString*) description {
68 return $sprintf(@"%@[%@ %@/%p]",
71 self.certificateData.my_SHA1Digest.abbreviatedHexString,
76 - (BOOL)isEqualToCertificate:(MYCertificate*)cert {
77 return [self isEqual: cert] || [self.certificateData isEqual: cert.certificateData];
81 + (MYCertificate*) preferredCertificateForName: (NSString*)name {
82 SecCertificateRef certRef = NULL;
83 if (!check(SecCertificateCopyPreference((CFStringRef)name, 0, &certRef),
84 @"SecCertificateCopyPreference"))
86 return [[[MYCertificate alloc] initWithCertificateRef: certRef] autorelease];
89 - (BOOL) setPreferredCertificateForName: (NSString*)name {
90 return check(SecCertificateSetPreference(_certificateRef, (CFStringRef)name, 0, NULL),
91 @"SecCertificateSetPreference");
95 @synthesize certificateRef=_certificateRef;
97 - (NSData*) certificateData {
99 if (!check(SecCertificateGetData(_certificateRef, &cssmData),
100 @"SecCertificateGetData"))
102 return [NSData dataWithBytes: cssmData.Data length: cssmData.Length];
105 - (MYPublicKey*) publicKey {
106 SecKeyRef keyRef = NULL;
107 if (!check(SecCertificateCopyPublicKey(_certificateRef, &keyRef),
108 @"SecCertificateCopyPublicKey") || !keyRef)
110 MYPublicKey *key = [[[MYPublicKey alloc] initWithKeyRef: keyRef] autorelease];
115 - (MYIdentity*) identity {
116 return [[[MYIdentity alloc] initWithCertificateRef: _certificateRef] autorelease];
119 - (MYCertificateInfo*) info {
122 _info = [[MYCertificateInfo alloc] initWithCertificateData: self.certificateData
125 Warn(@"Couldn't parse certificate %@: %@", self, error);
130 - (NSString*) commonName {
131 CFStringRef name = NULL;
132 if (!check(SecCertificateCopyCommonName(_certificateRef, &name),
133 @"SecCertificateCopyCommonName") || !name)
135 return [(id)CFMakeCollectable(name) autorelease];
138 - (NSArray*) emailAddresses {
139 CFArrayRef addrs = NULL;
140 if (!check(SecCertificateCopyEmailAddresses(_certificateRef, &addrs),
141 @"SecCertificateCopyEmailAddresses") || !addrs)
143 return [(id)CFMakeCollectable(addrs) autorelease];
148 #pragma mark TRUST/POLICY STUFF:
151 + (SecPolicyRef) policyForOID: (CSSM_OID) policyOID {
152 SecPolicySearchRef search;
153 if (!check(SecPolicySearchCreate(CSSM_CERT_X_509v3, &policyOID, NULL, &search),
154 @"SecPolicySearchCreate"))
156 SecPolicyRef policy = NULL;
157 if (!check(SecPolicySearchCopyNext(search, &policy), @"SecPolicySearchCopyNext"))
163 + (SecPolicyRef) X509Policy {
164 static SecPolicyRef sX509Policy = NULL;
166 sX509Policy = [self policyForOID: CSSMOID_APPLE_X509_BASIC];
170 + (SecPolicyRef) SSLPolicy {
171 static SecPolicyRef sSSLPolicy = NULL;
173 sSSLPolicy = [self policyForOID: CSSMOID_APPLE_TP_SSL];
177 + (SecPolicyRef) SMIMEPolicy {
178 static SecPolicyRef sSMIMEPolicy = NULL;
180 sSMIMEPolicy = [self policyForOID: CSSMOID_APPLE_TP_SMIME];
185 - (CSSM_CERT_TYPE) certificateType {
186 CSSM_CERT_TYPE type = CSSM_CERT_UNKNOWN;
187 if (!check(SecCertificateGetType(_certificateRef, &type), @"SecCertificateGetType"))
188 type = CSSM_CERT_UNKNOWN;
192 - (NSArray*) trustSettings {
193 CFArrayRef settings = NULL;
194 OSStatus err = SecTrustSettingsCopyTrustSettings(_certificateRef, kSecTrustSettingsDomainUser,
196 if (err == errSecItemNotFound || !check(err,@"SecTrustSettingsCopyTrustSettings") || !settings)
198 return [(id)CFMakeCollectable(settings) autorelease];
202 - (BOOL) setUserTrust: (SecTrustUserSetting)trustSetting
204 if (trustSetting == kSecTrustResultProceed) {
205 return check(SecTrustSettingsSetTrustSettings(_certificateRef,
206 kSecTrustSettingsDomainUser, nil),
207 @"SecTrustSettingsSetTrustSettings");
208 } else if (trustSetting == kSecTrustResultDeny) {
209 OSStatus err = SecTrustSettingsRemoveTrustSettings(_certificateRef,
210 kSecTrustSettingsDomainUser);
211 return err == errSecItemNotFound || check(err, @"SecTrustSettingsRemoveTrustSettings");
220 NSString* MYPolicyGetName( SecPolicyRef policy ) {
224 SecPolicyGetOID(policy, &oid);
225 return $sprintf(@"SecPolicy[%@]", OIDAsString(oid));
228 NSString* MYTrustResultDescribe( SecTrustResultType result ) {
229 static NSString* const kTrustResultNames[kSecTrustResultOtherError+1] = {
235 @"RecoverableTrustFailure",
236 @"FatalTrustFailure",
239 if (result>=0 && result <=kSecTrustResultOtherError)
240 return kTrustResultNames[result];
242 return $sprintf(@"(Unknown trust result %i)", result);
246 NSString* MYTrustDescribe( SecTrustRef trust ) {
247 SecTrustResultType result;
248 CFArrayRef certChain=NULL;
249 CSSM_TP_APPLE_EVIDENCE_INFO* statusChain;
250 OSStatus err = SecTrustGetResult(trust, &result, &certChain, &statusChain);
253 desc = $sprintf(@"SecTrust[%p, err=%@]", trust, MYErrorName(NSOSStatusErrorDomain, err));
255 desc = $sprintf(@"SecTrust[%@, %u in chain]",
256 MYTrustResultDescribe(result),
257 CFArrayGetCount(certChain));
258 if (certChain) CFRelease(certChain);
263 // Taken from Keychain.framework
264 NSString* OIDAsString(const CSSM_OID oid) {
265 if ((NULL == oid.Data) || (0 >= oid.Length)) {
268 NSMutableString *result = [NSMutableString stringWithCapacity:(4 * oid.Length)];
271 for (i = 0; i < oid.Length; ++i) {
272 [result appendFormat:@"%s%hhu", ((0 == i) ? "" : ", "), oid.Data[i]];
282 Log(@"X.509 policy = %@", MYPolicyGetName([MYCertificate X509Policy]));
283 Log(@" SSL policy = %@", MYPolicyGetName([MYCertificate SSLPolicy]));
284 Log(@"SMIME policy = %@", MYPolicyGetName([MYCertificate SMIMEPolicy]));
285 for (MYCertificate *cert in [[MYKeychain defaultKeychain] enumerateCertificates]) {
286 NSArray *settings = cert.trustSettings;
288 Log(@"---- %@ = %@", cert, settings);
293 #endif !MYCRYPTO_USE_IPHONE_API
298 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
300 Redistribution and use in source and binary forms, with or without modification, are permitted
301 provided that the following conditions are met:
303 * Redistributions of source code must retain the above copyright notice, this list of conditions
304 and the following disclaimer.
305 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
306 and the following disclaimer in the documentation and/or other materials provided with the
309 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
310 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
311 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
312 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
313 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
314 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
315 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
316 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.