/*
 * Copyright (c) 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@
 *
 * SecExternalRep.h - private classes representing external representations of
 *					  SecKeychainItemRefs, used by SecImportExport.h
 */

#ifndef	_SECURITY_SEC_EXTERNAL_REP_H_
#define _SECURITY_SEC_EXTERNAL_REP_H_

#include "SecImportExport.h"

/*
 * mechanism to limit private key import
 */
typedef enum {
	PIS_NoLimit,			// no limit
	PIS_AllowOne,			// allow import of at most one
	PIS_NoMore				// found one, no more allowed
} ImpPrivKeyImportState;

namespace Security
{

namespace KeychainCore
{

/*
 * When exporting, each instance of this represents one keychain item we're
 * exporting. Note that SecIdentityRefs are represented by two of these - one
 * for the cert, one for the key.
 */
class SecExportRep
{
protected:
	SecExportRep(
		CFTypeRef						kcItemRef);

public:
	/* default constructor throws */
	SecExportRep();
	
	/*
	 * Gleans SecExternalItemType from incoming type, throws MacOSError if
	 * incoming type is bogus, and vends an instance of a suitable subclass.
	 * Vended object holds a reference to kcItem for its lifetime. 
	 */
	static SecExportRep *vend(	
		CFTypeRef						kcItemRef);
		
	virtual ~SecExportRep();
	
	/* 
	 * Append external representation to CFData.
	 * Implemented in subclass.
	 */
	virtual OSStatus exportRep(
		SecExternalFormat					format,	
		SecItemImportExportFlags			flags,	
		const SecKeyImportExportParameters	*keyParams,		// optional 
		CFMutableDataRef					outData,		// data appended here
		const char							**pemHeader);	// e.g., "X509 CERTIFICATE"
		
	/* member variables are read-only to the public */
	SecKeychainItemRef	kcItem()		{ return mKcItem; }
	SecExternalItemType	externType()	{ return mExternType; }
	CFArrayRef pemParamLines()			{ return mPemParamLines; }
	
protected:
	SecKeychainItemRef		mKcItem;
	SecExternalItemType		mExternType;		// inferred in vend()
	CFArrayRef				mPemParamLines;		// optional PEM header strings
	
};

/* 
 * Class representing one item we're importing from external representation.
 * Normally represents the one "thing" the app has provided to 
 * SecKeychainItemImport(), but when importing in kSecFormatPEMSequence
 * format, the inpus is parsed into separate components, each of which 
 * gets one instance of this class. 
 */
class SecImportRep
{
private:
	/* no default constructor */
	SecImportRep() { }
	
public:
	/*
	 * Between constructor and the importRep() call, we're a placeholder to 
	 * allow our owner to keep track of what is in an incoming pile of bits. 
	 * We keep a reference to the incoming CFDataRef for our lifetime. 
	 */
	SecImportRep(
		CFDataRef						external,
		SecExternalItemType				externType,		// may be unknown 
		SecExternalFormat				externFormat,   // may be unknown
		CSSM_ALGORITHMS					keyAlg,		// may be unknown, CSSM_ALGID_NONE
		CFArrayRef						pemParamLines = NULL);

	~SecImportRep();
	
	/* 
	 * Convert to one or more SecKeychainItemRefs and/or import to keychain.
	 * Both mExternType and mExternFormat must be valid at this point. 
	 * Any conversion requiring unwrapping rerquires either a keychain
	 * into which the unwrapped items will be imported) or a CSPDL handle (in 
	 * which case the resulting items are floating and ephemeral). 
	 * If we create a SecKeychainItemRefs, the only ref count held on
	 * return will be that held by outArray. 
	 *
	 * Incoming CSP handle is required; by convention it must be derived from
	 * importKeychain if importKeychain is present. 
	 */
	OSStatus importRep(
		SecKeychainRef						importKeychain,		// optional
		CSSM_CSP_HANDLE						cspHand,			// required
		SecItemImportExportFlags			flags,
		const SecKeyImportExportParameters	*keyParams,			// optional 
		ImpPrivKeyImportState				&keyImportState,	// IN/OUT
		CFMutableArrayRef					outArray);			// optional, append here 
		
private:
	/* implemented in SecWrappedKeys.cpp */
	OSStatus importWrappedKeyOpenssl(
		SecKeychainRef						importKeychain, // optional
		CSSM_CSP_HANDLE						cspHand,		// required
		SecItemImportExportFlags			flags,
		const SecKeyImportExportParameters	*keyParams,		// optional 
		CFMutableArrayRef					outArray);		// optional, append here 

public:
	/* Just keep these public, it simplifies things */
	CFDataRef				mExternal;	
	SecExternalItemType		mExternType;	
	SecExternalFormat		mExternFormat;
	CSSM_ALGORITHMS			mKeyAlg;
	CFArrayRef				mPemParamLines;		// optional PEM header strings
};

} // end namespace KeychainCore

} // end namespace Security

extern "C" {

/* implemented in SecWrappedKeys.cpp */
OSStatus impExpWrappedKeyOpenSslExport(
	SecKeyRef							secKey,
	SecItemImportExportFlags			flags,		
	const SecKeyImportExportParameters	*keyParams,		// optional 
	CFMutableDataRef					outData,		// output appended here
	const char							**pemHeader,	// RETURNED
	CFArrayRef							*pemParamLines);// RETURNED

}

#endif	/* _SECURITY_SEC_IMPORT_EXPORT_H_ */
