blob: 9ece1e8d587789938323ff9a0c04d72c882439e7 [file] [log] [blame]
/* 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 <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#import <SecurityInterface/SFCertificateTrustPanel.h>
#import <SecurityInterface/SFChooseIdentityPanel.h>
#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