/*
 * Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved.
 * 
 * @APPLE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
 
/*******************************************************************
 * 
 * SecPkcs12.h
 *
 * This module is an implementation of the logic required to create 
 * and parse PKCS12 "blobs", known as PFXs in PKCS12 lingo. The user
 * of this module need not know anything about the details of 
 * PKCS12 PFX construction. All one needs to know at this level
 * is that a PKCS12 PFX is a collection of the following items:
 *
 * -- Zero or more certificates
 * -- Zero or more Certficate Revocation Lists (CRLs)
 * -- Zero or more private keys. (If this number is zero, using this
 *    module is probably not what you want to do)
 * -- Zero or more other opaque types, not understood or parsed
 *    by this module.
 *
 * Each individual component of a PFX contains zero or more
 * attributes; commonly the only two such attributes used in 
 * the PKCS12 world are "FriendlyName", a Unicode string, and 
 * "LocalKeyId", an opaque data blob which serves solely to tie
 * a specific cert to a specific key in the context of this specific
 * PFX.
 * 
 * Individual components of a PKCS12 PFX are typically encrypted with
 * a key derived from a user-supplied passphrase. The entire PFX
 * is protected with a MAC whose key is also derived from a user-
 * supplied passphrase. Typically these two passphrases are identical
 * but they don't have to be. 
 *
 * There are a number of options and modes which, while described in 
 * the PKCS12 spec and provided for in the interface in this file,
 * are rarely if ever used. The following is a description of the 
 * actual, typical, real-world use of this module.
 *
 * Decoding a PKCS12 blob
 * ----------------------
 *
 * 1. App creates a SecPkcs12CoderRef via SecPkcs12CoderCreate().
 * 
 * 2. App specifies supplies a (small) number of options such as
 *    passphrase(s) and SecKeychainRefs. 
 * 
 * 3. App calls SecPkcs12Decode(), providing the raw PKCS12 PFX 
 *    blob which is to be decoded. This performs all of the actual 
 *    decoding and decryption.
 *
 * 4. At this point the app optionally obtains the resulting 
 *    components by a set of calls which return individual 
 *    certs, CRLS, and keys.
 *
 * 5. Also, per the configuration performed in step 2, individual 
 *    components (certs, keys) found in the PFX have been added 
 *    to a specified keychain, rendering step 4 superfluous. 
 *
 *
 * Creating a PKCS12 blob
 * ----------------------
 *
 * 1. App creates a SecPkcs12CoderRef via SecPkcs12CoderCreate().
 *
 * 2. App specifies supplies a (small) number of options such as
 *    passphrase(s).
 * 
 * 3. App makes a set of calls which add individual components such 
 *    as certs, CRLs, and private keys. A high-level call, 
 *    SecPkcs12ExportKeychainItems(), allow the specification of 
 *    all components to be exported at once.
 *
 * 4. App calls SecPkcs12Encode(), which does all of the required
 *    encryption and encoding. The result is an exportable PKCS12
 *    PFX blob. 
 */
 
#ifndef	_SEC_PKCS12_H_
#define _SEC_PKCS12_H_

#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Opaque handle for a PKCS12 encoder/decoder.
 */
typedef void 	*SecPkcs12CoderRef;

#pragma mark --- SecPkcs12CoderRef create/destroy ---

/*
 * Basic SecPkcs12CoderRef create/destroy.
 */
OSStatus SecPkcs12CoderCreate(
	SecPkcs12CoderRef	*coder);		// RETURNED
	
/*
 * Destroy object created in SecPkcs12CoderCreate.
 */
OSStatus SecPkcs12CoderRelease(
	SecPkcs12CoderRef	coder);	

#pragma mark --- High-level API ---

/*
 * Keychain associated with encode/decode. 
 * Client must call exactly one of { SecPkcs12SetKeychain(),
 * SecPkcs12SetCspHandle() } for both encoding and decoding. 
 * If SecPkcs12SetCspHandle() is used, components which are
 * obtained during decode are ephemeral (i.e., they are not 
 * stored anywhere and only have a lifetime which is the same as
 * the lifetime of the SecPkcs12CoderRef). 
 */
OSStatus SecPkcs12SetKeychain(
	SecPkcs12CoderRef		coder,
	SecKeychainRef			keychain);
	
/* 
 * Required iff SecPkcs12SetKeychain() is not called.
 */
OSStatus SecPkcs12SetCspHandle(
	SecPkcs12CoderRef		coder,
	CSSM_CSP_HANDLE			cspHandle);


/*
 * PKCS12 allows for separate passphrases for encryption and for
 * verification (via MAC). Typically, in the real world, one
 * passphrase is used for both; we provide the means to set them
 * separately.
 *
 * Passphrases can be specified directly as CFStringRefs, or as 
 * CSSM_KEYs which represent secure passphrases obtained by the 
 * SecurityServer. This latter method is preferred since the 
 * plaintext passphrase never appears in the app's address space.
 * Passphrases expressed in this manner are referred to as 
 * PassKeys.
 *
 * If one passphrase is to be used for both encryption and 
 * verification, use one of these two function to set it.
 */
OSStatus SecPkcs12SetMACPassphrase(
	SecPkcs12CoderRef	coder,
	CFStringRef			passphrase);
	
OSStatus SecPkcs12SetMACPassKey(
	SecPkcs12CoderRef	coder,
	const CSSM_KEY		*passKey);
	
/*
 * Specify separate passphrase for encrypt/decrypt.
 */
OSStatus SecPkcs12SetCryptPassphrase(
	SecPkcs12CoderRef	coder,
	CFStringRef			passphrase);
 
OSStatus SecPkcs12SetCryptPassKey(
	SecPkcs12CoderRef	coder,
	const CSSM_KEY		*passKey);
 
/*
 * Prior to decoding a PFX, client can specify whether individual
 * components (certificates, CRLs, and keys) get stored in the 
 * keychain specified via SecPkcs12SetKeychain().
 */
enum {
	kSecImportCertificates	= 0x0001,
	kSecImportCRLs			= 0x0002,
	kSecImportKeys			= 0x0004,
};

typedef UInt32 SecPkcs12ImportFlags;

OSStatus SecPkcs12SetImportToKeychain(
	SecPkcs12CoderRef			coder,
	SecPkcs12ImportFlags		flags);

OSStatus SecPkcs12GetImportToKeychain(
	SecPkcs12CoderRef			coder,
	SecPkcs12ImportFlags		*flags);		// RETURNED
	
/*
 * Specify individual SecKeychainItemRef to export, prior to encoding.
 * The items argument is a CFArray containing any number of each 
 * of the following SecKeychainItemRef objects:
 *
 *		SecKeyRef
 *		SecCertificateRef
 *		...and others, in the future.
 */
OSStatus SecPkcs12ExportKeychainItems(
	SecPkcs12CoderRef			coder,
	CFArrayRef					items);

/*
 * Parse and decode.
 */
OSStatus SecPkcs12Decode(
	SecPkcs12CoderRef		coder,
	CFDataRef				pfx);
	
/* 
 * This the final step to create an encoded PKCS12 PFX blob.
 * This called after initial configuration of the SecPkcs12CoderRef,
 * and either specifying items to export via either 
 * SecPkcs12ExportKeychainItems() or some number of SecPkcs12Add* 
 * function calls, described below.
 *
 * The result is a DER-encoded PFX in PKCS12 lingo.
 */
OSStatus SecPkcs12Encode(
	SecPkcs12CoderRef		coder,
	CFDataRef				*pfx);			// RETURNED


/*
 * Opaque handle for optional attributes associated with any 
 * component of a SecPkcs12CoderRef.
 *
 * The use of SecPkcs12AttrsRefs is optional and in fact, in the real 
 * world, rare. Their appearance in this API is just for completeness
 * and to allow access to all "legal" PKCS12 options. 
 *
 * We define the type here to allow use elsewhere in this
 * interface; actual SecPkcs12AttrsRef manipulation functions
 * are described later in this header. 
 */
typedef void 	*SecPkcs12AttrsRef;

#pragma mark --- Decoder Functions ---

/*
 * Subsequent to decoding, obtain the components.
 * These functions can also be used as "getter" functions while encoding.
 *
 * Certificates:
 */
OSStatus SecPkcs12CertificateCount(
	SecPkcs12CoderRef		coder,
	CFIndex					*numCerts);		// RETURNED
	
OSStatus SecPkcs12CopyCertificate(
	SecPkcs12CoderRef		coder,
	CFIndex					certNum,
	SecCertificateRef		*cert,			// RETURNED
	CFStringRef				*friendlyName,	// optional, RETURNED
	CFDataRef				*localKeyId,	// optional, RETURNED
	SecPkcs12AttrsRef		*attrs);		// optional, RETURNED
	
/*
 * CRLs. The might change if a SecCrl type is defined elsewhere.
 * We'll typedef it here to preserve the semantics of this function.
 */
typedef CFDataRef	SecCrlRef;

OSStatus SecPkcs12CrlCount(
	SecPkcs12CoderRef		coder,
	CFIndex					*numCrls);		// RETURNED
	
OSStatus SecPkcs12CopyCrl(
	SecPkcs12CoderRef		coder,
	CFIndex					crlNum,
	SecCrlRef				*crl,			// RETURNED
	CFStringRef				*friendlyName,	// optional, RETURNED
	CFDataRef				*localKeyId,	// optional, RETURNED
	SecPkcs12AttrsRef		*attrs);		// optional, RETURNED
 
/*
 * Private keys.
 */
OSStatus SecPkcs12PrivateKeyCount(
	SecPkcs12CoderRef		coder,
	CFIndex					*numKeys);		// RETURNED
	
/* currently not implemented : use SecPkcs12GetCssmPrivateKey() */
OSStatus SecPkcs12CopyPrivateKey(
	SecPkcs12CoderRef		coder,
	CFIndex					keyNum,
	SecKeyRef				*privateKey,	// RETURNED
	CFStringRef				*friendlyName,	// optional, RETURNED
	CFDataRef				*localKeyId,	// optional, RETURNED
	SecPkcs12AttrsRef		*attrs);		// optional, RETURNED

/*
 * The CSSM_KEY_PTR returned by this function has a lifetime 
 * which is the same as the SecPkcs12CoderRef which created it.
 */
OSStatus SecPkcs12GetCssmPrivateKey(
	SecPkcs12CoderRef		coder,
	CFIndex					keyNum,
	CSSM_KEY_PTR			*privateKey,	// RETURNED
	CFStringRef				*friendlyName,	// optional, RETURNED
	CFDataRef				*localKeyId,	// optional, RETURNED
	SecPkcs12AttrsRef		*attrs);		// optional, RETURNED

/*
 * Catch-all for other components not currently understood
 * or supported by this library. An "opaque blob" component 
 * is identified by an OID and is obtained as an opaque data 
 * blob.
 */
OSStatus SecPkcs12OpaqueBlobCount(
	SecPkcs12CoderRef		coder,
	CFIndex					*numBlobs);		// RETURNED
	
OSStatus SecPkcs12CopyOpaqueBlob(
	SecPkcs12CoderRef		coder,
	CFIndex					blobNum,
	CFDataRef				*blobOid,		// RETURNED
	CFDataRef				*opaqueBlob,	// RETURNED
	CFStringRef				*friendlyName,	// optional, RETURNED
	CFDataRef				*localKeyId,	// optional, RETURNED
	SecPkcs12AttrsRef		*attrs);		// optional, RETURNED

#pragma mark --- Encoder Functions ---

/*
 * Add individual components. "Getter" functions are available
 * as described above (under "Functions used for decoding").
 */
OSStatus SecPkcs12AddCertificate(
	SecPkcs12CoderRef		coder,
	SecCertificateRef		cert,			
	CFStringRef				friendlyName,	// optional
	CFDataRef				localKeyId,		// optional
	SecPkcs12AttrsRef		attrs);			// optional
	
OSStatus SecPkcs12AddCrl(
	SecPkcs12CoderRef		coder,
	SecCrlRef				crl,			
	CFStringRef				friendlyName,	// optional
	CFDataRef				localKeyId,		// optional
	SecPkcs12AttrsRef		attrs);			// optional
	
OSStatus SecPkcs12AddPrivateKey(
	SecPkcs12CoderRef		coder,
	SecKeyRef				privateKey,			
	CFStringRef				friendlyName,	// optional
	CFDataRef				localKeyId,		// optional
	SecPkcs12AttrsRef		attrs);			// optional

OSStatus SecPkcs12AddOpaqueBlob(
	SecPkcs12CoderRef		coder,
	CFDataRef				blobOid,	
	CFDataRef				opaqueBlob,
	CFStringRef				friendlyName,	// optional
	CFDataRef				localKeyId,		// optional
	SecPkcs12AttrsRef		attrs);			// optional


#pragma mark --- Optional Functions ---

/************************************************************
 *** Optional, rarely used SecPkcs12CoderRef manipulation ***
 ************************************************************/
 
/***
 *** SecPkcs12AttrsRef manipulation. Optional and in fact expected to 
 *** be rarely used, if ever. 
 ***/
 
/*
 * A SecPkcs12AttrsRef is an opaque handle referring to an aribtrary
 * collection of OID/value pairs which can be attached to any 
 * component of a SecPkcs12CoderRef. OIDs and values are expressed
 * as CFDataRefs. Each OID can have associated with it an arbitrary 
 * number of values. 
 */
 
/*
 * Create/destroy.
 */
OSStatus SecPkcs12AttrsCreate(
	SecPkcs12AttrsRef	*attrs);		// RETURNED

OSStatus SecPkcs12AttrsRelease(
	SecPkcs12AttrsRef	attrs);

/*
 * Add an OID/value set to an existing SecPkcs12AttrsRef.
 * Values are a CFArray containing an arbitrary number of 
 * CFDataRefs. 
 */
OSStatus SecPkcs12AttrsAddAttr(
	SecPkcs12AttrsRef	attrs,
	CFDataRef			attrOid,
	CFArrayRef			attrValues);	// an array of CFDataRefs
	
OSStatus SecPkcs12AttrCount(
	SecPkcs12AttrsRef	attrs,
	CFIndex				*numAttrs);		// RETURNED

/* 
 * Obtain n'th oid/value set from an existing SecPkcs12AttrsRef.
 */
OSStatus SecPkcs12AttrsGetAttr(
	SecPkcs12AttrsRef	attrs,
	CFIndex				attrNum,
	CFDataRef			*attrOid,		// RETURNED
	CFArrayRef			*attrValues);	// RETURNED
	
/***
 *** Integrity and Privacy Modes
 ***/
 
/*
 * PKCS12 allows for two different modes for each of {privacy,
 * integrity}. Each of these can be implemented via password
 * or public key. Per the PKCS12 spec, all four combinations
 * of these modes are legal. In the current version of this
 * library, only password privacy and integrity modes are 
 * implemented. These functions are defined here for the 
 * completeness of the API and need never be called by users of
 * the current implementation.
 */
typedef enum {
	kSecPkcs12ModeUnknown,		// uninitialized
	kSecPkcs12ModePassword,
	kSecPkcs12ModePublicKey
} SecPkcs12Mode;
 
OSStatus SecPkcs12SetIntegrityMode(
	SecPkcs12CoderRef	coder,
	SecPkcs12Mode		mode);
	
OSStatus SecPkcs12GetIntegrityMode(
	SecPkcs12CoderRef	coder,
	SecPkcs12Mode		*mode);			// RETURNED
	
OSStatus SecPkcs12SetPrivacyMode(
	SecPkcs12CoderRef	coder,
	SecPkcs12Mode		mode);
	
OSStatus SecPkcs12GetPrivacyMode(
	SecPkcs12CoderRef	coder,
	SecPkcs12Mode		*mode);			// RETURNED
	
/***
 *** Encryption algorithms
 ***/

/*
 * Each individual component of a PKCS12 PFX can be encrypted with
 * a different encryption algorithm. Typically, Certs and CRLs are 
 * all encrypted with one weak algorithm, and private keys are 
 * encrypted with a stronger algorithm. 
 *
 * The following functions allow the app to specify, during encoding,
 * the encryption algorithms to use for the different kinds of 
 * components. These are optional; this library provides appropriate
 * defaults for these algorithms.
 */
OSStatus SecPkcs12SetKeyEncryptionAlg(
	SecPkcs12CoderRef	coder,
	CFDataRef			encryptionAlg);
	
OSStatus SecPkcs12SetCertCrlEncryptionAlg(
	SecPkcs12CoderRef	coder,
	CFDataRef			encryptionAlg);
	
/*
 * Along with an encryption algorithm is an iteration count used for
 * deriving keys. All of these are optional; reasonable defaults
 * are provided. 
 *
 * NOTE: salt is not visible at this API. During encoding, 
 * random values of salt are generated by this module.
 */
OSStatus SecPkcs12SetKeyEncryptionIterCount(
	SecPkcs12CoderRef	coder,
	unsigned			iterCount);

OSStatus SecPkcs12SetCertCrlEncryptionIterCount(
	SecPkcs12CoderRef	coder,
	unsigned			iterCount);

OSStatus SecPkcs12SetMacIterCount(
	SecPkcs12CoderRef	coder,
	unsigned			iterCount);

/*
 * "Getter" versions of the above. During decryption, the values
 * returned here refer to the *first* such element found (e.g.,
 * the encryption algorithm for the first key). 
 */
OSStatus SecPkcs12CopyKeyEncryptionAlg(
	SecPkcs12CoderRef	coder,
	CFDataRef			*encryptionAlg);		// RETURNED
	
OSStatus SecPkcs12CopyCertCrlEncryptionAlg(
	SecPkcs12CoderRef	coder,
	CFDataRef			*encryptionAlg);		// RETURNED
	
OSStatus SecPkcs12CopyKeyEncryptionIterCount(
	SecPkcs12CoderRef	coder,
	unsigned			*iterCount);			// RETURNED

OSStatus SecPkcs12CopyCertCrlEncryptionIterCount(
	SecPkcs12CoderRef	coder,
	unsigned			*iterCount);			// RETURNED
	
OSStatus SecPkcs12CopyMacIterCount(
	SecPkcs12CoderRef	coder,
	unsigned			*iterCount);			// RETURNED
	
/*
 * Avoid importing multiple private keys. Primarily for use by 
 * SecKeychainItemImport(). Behavior depends on the foundOneKey
 * argument, which indicates whether the current high-level import
 * has already imported at least one key. If foundOneKey is true,
 * SecPkcs12Decode() will return errSecMultiplePrivKeys upon
 * the detection of *any* private keys in the incoming PFX.
 * If foundOneKey is false, SecPkcs12Decode() will return 
 * errSecMultiplePrivKeys if more than one private key is 
 * found in the incoming PFX.
 */
OSStatus SecPkcs12LimitPrivateKeyImport(
	SecPkcs12CoderRef	coder,
	bool				foundOneKey);
	
#ifdef __cplusplus
}
#endif

#endif	/* _SEC_PKCS12_H_ */

