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"
12 #import "MYErrorUtils.h"
14 #if !MYCRYPTO_USE_IPHONE_API
17 @implementation MYCertificate
20 /** Creates a MYCertificate object for an existing Keychain certificate reference. */
21 - (id) initWithCertificateRef: (SecCertificateRef)certificateRef {
22 self = [super initWithKeychainItemRef: (SecKeychainItemRef)certificateRef];
24 _certificateRef = certificateRef; // superclass has already CFRetained it
29 + (MYCertificate*) certificateWithCertificateRef: (SecCertificateRef)certificateRef {
30 return [[[self alloc] initWithCertificateRef: certificateRef] autorelease];
33 /** Creates a MYCertificate object from exported key data, but does not add it to any keychain. */
34 - (id) initWithCertificateData: (NSData*)data
35 type: (CSSM_CERT_TYPE) type
36 encoding: (CSSM_CERT_ENCODING) encoding
39 CSSM_DATA cssmData = {.Data=(void*)data.bytes, .Length=data.length};
40 SecCertificateRef certificateRef = NULL;
41 if (!check(SecCertificateCreateFromData(&cssmData, type, encoding, &certificateRef),
42 @"SecCertificateCreateFromData")) {
46 self = [self initWithCertificateRef: certificateRef];
47 CFRelease(certificateRef);
51 - (id) initWithCertificateData: (NSData*)data {
52 return [self initWithCertificateData: data
53 type: CSSM_CERT_X_509v3
54 encoding: CSSM_CERT_ENCODING_BER];
58 - (NSString*) description {
59 return $sprintf(@"%@[%@ %@/%p]",
62 self.certificateData.my_SHA1Digest.abbreviatedHexString,
67 - (BOOL)isEqualToCertificate:(MYCertificate*)cert {
68 return [self isEqual: cert] || [self.certificateData isEqual: cert.certificateData];
72 + (MYCertificate*) preferredCertificateForName: (NSString*)name {
73 SecCertificateRef certRef = NULL;
74 if (!check(SecCertificateCopyPreference((CFStringRef)name, 0, &certRef),
75 @"SecCertificateCopyPreference"))
77 return [[[MYCertificate alloc] initWithCertificateRef: certRef] autorelease];
80 - (BOOL) setPreferredCertificateForName: (NSString*)name {
81 return check(SecCertificateSetPreference(_certificateRef, (CFStringRef)name, 0, NULL),
82 @"SecCertificateSetPreference");
86 @synthesize certificateRef=_certificateRef;
88 - (NSData*) certificateData {
90 if (!check(SecCertificateGetData(_certificateRef, &cssmData),
91 @"SecCertificateGetData"))
93 return [NSData dataWithBytes: cssmData.Data length: cssmData.Length];
96 - (MYPublicKey*) publicKey {
97 SecKeyRef keyRef = NULL;
98 if (!check(SecCertificateCopyPublicKey(_certificateRef, &keyRef),
99 @"SecCertificateCopyPublicKey") || !keyRef)
101 MYPublicKey *key = [[[MYPublicKey alloc] initWithKeyRef: keyRef] autorelease];
106 - (NSString*) commonName {
107 CFStringRef name = NULL;
108 if (!check(SecCertificateCopyCommonName(_certificateRef, &name),
109 @"SecCertificateCopyCommonName") || !name)
111 return [(id)CFMakeCollectable(name) autorelease];
114 - (NSArray*) emailAddresses {
115 CFArrayRef addrs = NULL;
116 if (!check(SecCertificateCopyEmailAddresses(_certificateRef, &addrs),
117 @"SecCertificateCopyEmailAddresses") || !addrs)
119 return [(id)CFMakeCollectable(addrs) autorelease];
124 #pragma mark TRUST/POLICY STUFF:
127 + (SecPolicyRef) policyForOID: (CSSM_OID) policyOID {
128 SecPolicySearchRef search;
129 if (!check(SecPolicySearchCreate(CSSM_CERT_X_509v3, &policyOID, NULL, &search),
130 @"SecPolicySearchCreate"))
132 SecPolicyRef policy = NULL;
133 if (!check(SecPolicySearchCopyNext(search, &policy), @"SecPolicySearchCopyNext"))
139 + (SecPolicyRef) X509Policy {
140 static SecPolicyRef sX509Policy = NULL;
142 sX509Policy = [self policyForOID: CSSMOID_APPLE_X509_BASIC];
146 + (SecPolicyRef) SSLPolicy {
147 static SecPolicyRef sSSLPolicy = NULL;
149 sSSLPolicy = [self policyForOID: CSSMOID_APPLE_TP_SSL];
153 + (SecPolicyRef) SMIMEPolicy {
154 static SecPolicyRef sSMIMEPolicy = NULL;
156 sSMIMEPolicy = [self policyForOID: CSSMOID_APPLE_TP_SMIME];
161 - (CSSM_CERT_TYPE) certificateType {
162 CSSM_CERT_TYPE type = CSSM_CERT_UNKNOWN;
163 if (!check(SecCertificateGetType(_certificateRef, &type), @"SecCertificateGetType"))
164 type = CSSM_CERT_UNKNOWN;
168 - (NSArray*) trustSettings {
169 CFArrayRef settings = NULL;
170 OSStatus err = SecTrustSettingsCopyTrustSettings(_certificateRef, kSecTrustSettingsDomainUser,
172 if (err == errSecItemNotFound || !check(err,@"SecTrustSettingsCopyTrustSettings") || !settings)
174 return [(id)CFMakeCollectable(settings) autorelease];
178 - (BOOL) setUserTrust: (SecTrustUserSetting)trustSetting
180 if (trustSetting == kSecTrustResultProceed) {
181 return check(SecTrustSettingsSetTrustSettings(_certificateRef,
182 kSecTrustSettingsDomainUser, nil),
183 @"SecTrustSettingsSetTrustSettings");
184 } else if (trustSetting == kSecTrustResultDeny) {
185 OSStatus err = SecTrustSettingsRemoveTrustSettings(_certificateRef,
186 kSecTrustSettingsDomainUser);
187 return err == errSecItemNotFound || check(err, @"SecTrustSettingsRemoveTrustSettings");
196 NSString* MYPolicyGetName( SecPolicyRef policy ) {
200 SecPolicyGetOID(policy, &oid);
201 return $sprintf(@"SecPolicy[%@]", OIDAsString(oid));
204 NSString* MYTrustResultDescribe( SecTrustResultType result ) {
205 static NSString* const kTrustResultNames[kSecTrustResultOtherError+1] = {
211 @"RecoverableTrustFailure",
212 @"FatalTrustFailure",
215 if (result>=0 && result <=kSecTrustResultOtherError)
216 return kTrustResultNames[result];
218 return $sprintf(@"(Unknown trust result %i)", result);
222 NSString* MYTrustDescribe( SecTrustRef trust ) {
223 SecTrustResultType result;
224 CFArrayRef certChain=NULL;
225 CSSM_TP_APPLE_EVIDENCE_INFO* statusChain;
226 OSStatus err = SecTrustGetResult(trust, &result, &certChain, &statusChain);
229 desc = $sprintf(@"SecTrust[%p, err=%@]", trust, MYErrorName(NSOSStatusErrorDomain, err));
231 desc = $sprintf(@"SecTrust[%@, %u in chain]",
232 MYTrustResultDescribe(result),
233 CFArrayGetCount(certChain));
234 if (certChain) CFRelease(certChain);
239 // Taken from Keychain.framework
240 NSString* OIDAsString(const CSSM_OID oid) {
241 if ((NULL == oid.Data) || (0 >= oid.Length)) {
244 NSMutableString *result = [NSMutableString stringWithCapacity:(4 * oid.Length)];
247 for (i = 0; i < oid.Length; ++i) {
248 [result appendFormat:@"%s%hhu", ((0 == i) ? "" : ", "), oid.Data[i]];
258 Log(@"X.509 policy = %@", MYPolicyGetName([MYCertificate X509Policy]));
259 Log(@" SSL policy = %@", MYPolicyGetName([MYCertificate SSLPolicy]));
260 Log(@"SMIME policy = %@", MYPolicyGetName([MYCertificate SMIMEPolicy]));
261 for (MYCertificate *cert in [[MYKeychain defaultKeychain] enumerateCertificates]) {
262 NSArray *settings = cert.trustSettings;
264 Log(@"---- %@ = %@", cert, settings);
269 #endif !MYCRYPTO_USE_IPHONE_API
274 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
276 Redistribution and use in source and binary forms, with or without modification, are permitted
277 provided that the following conditions are met:
279 * Redistributions of source code must retain the above copyright notice, this list of conditions
280 and the following disclaimer.
281 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
282 and the following disclaimer in the documentation and/or other materials provided with the
285 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
286 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
287 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
288 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
289 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
290 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
291 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
292 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.