/*
 *  PCKeychain
 *
 *  Requires Mac OS X 10.2 or higher and linking to Security.framework.
 *
 *	-------------------------------------------------------------------
 */

#import <Foundation/Foundation.h>
#import <Security/Security.h>
#import <SecurityInterface/SFCertificateTrustPanel.h>

@class PCPrivateKey;
@class PCTrust;

extern NSString* const kPasswordInKeychain;

//  PCKeychain* matching keys
extern NSString* const kPCKeychainService;  // NSString
extern NSString* const kPCKeychainUsername; // NSString
extern NSString* const kPCKeychainServer;   // NSString
extern NSString* const kPCKeychainPort;     // NSNumber (unsigned int)		
extern NSString* const kPCKeychainProtocol; // NSNumber (SecProtocolType, which is a FourCharCode which is an unsigned int)


enum {
	TrustEvaluationNeedsUserFeedback = -1,
	TrustEvaluationUntrusted = 0,
	TrustEvaluationTrusted = 1
};
typedef NSInteger PCTrustEvaluation;


@interface PCKeychain : NSObject
{
	__strong CFTypeRef iRef;
}

+ (PCKeychain*)defaultKeychain; // actually the user's default keychain search list

- (id)initWithKeychainOrArray:(CFTypeRef)keychainOrArray;

// Supply a dictionary with the PCKeychain* matching keys you wish to match against. Returns NSArray of PCKeychainItem.
- (NSArray*)internetPasswordItemsMatchingAttributes:(NSDictionary*)matchingAttributes;

- (NSArray*)privateKeys; // NSArray of PCPrivateKey

- (NSString*)passwordForUsername:(NSString*)username serverAddress:(NSString*)serverAddress secProtocol:(SecProtocolType)protocol error:(NSError**)outError;
- (NSString*)passwordForAccountName:(NSString*)accountName service:(NSString*)service error:(NSError**)outError;

- (BOOL)savePassword:(NSString*)password forUsername:(NSString*)username serverAddress:(NSString*)serverAddress secProtocol:(SecProtocolType)protocol error:(NSError**)outError;
- (BOOL)savePassword:(NSString*)password forAccountName:(NSString*)accountName service:(NSString*)service error:(NSError**)outError;

- (PCPrivateKey*)importPrivateKey:(NSData*)externalRepresentation withUsername:(NSString*)username serverAddress:(NSString*)serverAddress secProtocol:(SecProtocolType)protocol error:(NSError**)outError;
- (NSData*)exportPrivateKeyWithUsername:(NSString*)username serverAddress:(NSString*)serverAddress secProtocol:(SecProtocolType)protocol error:(NSError**)outError;

- (BOOL)addCertificate:(CFTypeRef)certificate error:(NSError**)outError; // accepts a SecCertificate or a PCCertificate

@end


@interface PCKeychainItem : NSObject
{
@private
	__strong SecKeychainItemRef iRef;
}

@property(nonatomic, copy) NSData* itemData;
@property(nonatomic, copy) NSString* address;
@property(nonatomic, copy) NSString* username;
@property(nonatomic, copy) NSString* password; // itemData interpreted as UTF-8
@property(nonatomic, retain) NSNumber* port;
@property(nonatomic) SecProtocolType secProtocol;

- (id)initWithSecKeychainItem:(SecKeychainItemRef)item;

- (NSString*)description;

- (SecKeychainItemRef)secKeychainItem;

- (BOOL)setPassword:(NSString*)password error:(NSError**)outError;

@end


@interface PCPrivateKey : PCKeychainItem
{
}

@property(nonatomic, copy) NSString* comments; // kSecKeyApplicationTag
@property(nonatomic, copy) NSString* name; // kSecKeyPrintName

- (id)initWithSecKey:(SecKeyRef)key;
- (id)initWithKeyData:(NSData*)data forKeychain:(PCKeychain*)keychain alertPrompt:(NSString*)alertPrompt error:(NSError**)outError;

- (NSData*)keyData:(NSError**)outError;

- (SecKeyRef)secKey;
- (const CSSM_KEY*)cssmKey;
- (CSSM_CSP_HANDLE)cspHandle;
- (CSSM_KEYATTR_FLAGS)keyAttributes;
- (NSData*)keyDigest; // NSData of CSSM_APPLECSP_KEYDIGEST

@end


@interface PCCertificate : PCKeychainItem
{
}

@property(nonatomic, readonly) NSString* commonName;

- (id)initWithSecCertificate:(SecCertificateRef)certificate;
- (id)initWithData:(NSData*)data;

- (SecCertificateRef)secCertificate;
- (NSData*)data;

@end


@interface PCTrust : NSObject
{
@private
	__strong SecTrustRef iRef;
	PCCertificate* iCertificate;
	NSString* iHost;
}

// since there's no way to recover the "input certificate" for a chain, the certificates used to create the trust must also be supplied
- (id)initWithSecTrust:(SecTrustRef)trust secCertificates:(CFArrayRef)secCertificates host:(NSString*)host;
- (id)initWithCertificateOrArray:(CFTypeRef)certificateOrArray host:(NSString*)host; // accepts a SecCertificate or a PCCertificate (or a homogeneous array thereof)
- (id)initWithCertificateOrArray:(CFTypeRef)certificateOrArray host:(NSString*)host secPolicies:(CFTypeRef)secPolicies;

- (SecTrustRef)secTrust;
- (NSString*)host;

- (PCTrustEvaluation)evaluate;

- (void)beginCertificateSheetForWindow:(NSWindow*)window modalDelegate:(id)delegate didEndSelector:(SEL)didEndSelector contextInfo:(void*)contextInfo showGroup:(BOOL)showGroup;
- (void)beginEvaluationSheetForWindow:(NSWindow*)window modalDelegate:(id)delegate didEndSelector:(SEL)didEndSelector contextInfo:(void*)contextInfo message:(NSString*)message;

@end
