/* Copyright 2013 Justin Erenkrantz and Greg Stein * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import #import #import #import #import "serf.h" @interface MacOSXSSL_Buckets : NSObject { } + (OSStatus) evaluate:(SecTrustRef)trust trustResult:(SecTrustResultType *)trustResult; + (apr_status_t) showTrustCertificateDialog:(SecTrustRef)trust message:(const char *)message ok_button:(const char *)ok_button cancel_button:(const char *)cancel_button; @end @implementation MacOSXSSL_Buckets /* Evaluate the trust object asynchronously. When the results are received, store them in the provided resultPtr address. */ + (OSStatus) evaluate:(SecTrustRef)trust trustResult:(SecTrustResultType *)resultPtr { dispatch_queue_t queue; OSStatus osstatus; SecTrustCallback block = ^(SecTrustRef trust, SecTrustResultType trustResult) { *resultPtr = trustResult; }; queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0l); osstatus = SecTrustEvaluateAsync(trust, queue, block); return osstatus; } + (apr_status_t) showTrustCertificateDialog:(SecTrustRef)trust message:(const char *)message ok_button:(const char *)ok_button cancel_button:(const char *)cancel_button { NSString *MessageLbl = [[NSString alloc] initWithUTF8String:message]; NSString *OkButtonLbl = [[NSString alloc] initWithUTF8String:ok_button]; NSString *CancelButtonLbl; NSApplication *app; SFCertificateTrustPanel *panel; NSInteger result; if (cancel_button) CancelButtonLbl = [[NSString alloc] initWithUTF8String:cancel_button]; app = [NSApplication sharedApplication]; panel = [SFCertificateTrustPanel sharedCertificateTrustPanel]; /* Put the dialog in front of the application, and give it the focus. */ [app setActivationPolicy:NSApplicationActivationPolicyRegular]; [app activateIgnoringOtherApps:YES]; [panel setShowsHelp:YES]; [panel setDefaultButtonTitle:OkButtonLbl]; if (cancel_button) [panel setAlternateButtonTitle:CancelButtonLbl]; result = [panel runModalForTrust:trust message:MessageLbl]; [panel release]; [MessageLbl release]; [OkButtonLbl release]; if (cancel_button) [CancelButtonLbl release]; if (result) return APR_SUCCESS; else return SERF_ERROR_SSL_USER_DENIED_CERT; } + (OSStatus) showSelectIdentityDialog:(SecIdentityRef *)identity message:(const char *)message ok_button:(const char *)ok_button cancel_button:(const char *)cancel_button { NSString *MessageLbl = [[NSString alloc] initWithUTF8String:message]; NSString *OkButtonLbl = [[NSString alloc] initWithUTF8String:ok_button]; NSString *CancelButtonLbl; NSApplication *app; SFChooseIdentityPanel *panel; NSArray *identities; NSDictionary *query; NSInteger result; OSStatus osstatus; if (cancel_button) CancelButtonLbl = [[NSString alloc] initWithUTF8String:cancel_button]; /* Find all matching identities in the keychains. Note: SecIdentityRef items are not stored on the keychain but generated when needed if both a certificate and matching private key are available on the keychain. */ query = [NSDictionary dictionaryWithObjectsAndKeys: (id)kSecClassIdentity, (id)kSecClass, (id)kCFBooleanTrue, (id)kSecAttrCanSign, (id)kSecMatchLimitAll, (id)kSecMatchLimit, (id)kCFBooleanTrue, (id)kSecReturnRef, nil]; osstatus = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&identities); [query release]; if (osstatus != noErr) return osstatus; /* TODO: filter on matching certificates. How?? Distinguished names? */ /* Found the identities, now let the user choose. */ app = [NSApplication sharedApplication]; panel = [SFChooseIdentityPanel sharedChooseIdentityPanel]; /* Put the dialog in front of the application, and give it the focus. */ [app setActivationPolicy:NSApplicationActivationPolicyRegular]; [app activateIgnoringOtherApps:YES]; [panel setShowsHelp:YES]; [panel setDefaultButtonTitle:OkButtonLbl]; if (cancel_button) [panel setAlternateButtonTitle:CancelButtonLbl]; result = [panel runModalForIdentities:identities message:MessageLbl]; if (result) { *identity = [panel identity]; } else { *identity = nil; } [identities autorelease]; [MessageLbl release]; [OkButtonLbl release]; if (cancel_button) [CancelButtonLbl release]; [panel release]; return noErr; } @end