/* 
 * Obtain blob suitable for hashing in CSSM_APPLECSP_KEYDIGEST 
 * passthrough.
 */
bool RSAKeyInfoProvider::getHashableBlob(
	Allocator 	&allocator,
	CssmData		&blob)			// blob to hash goes here
{
	/*
	 * The optimized case, a raw key in the "proper" format already.
	 * Only public keys in PKCS1 format fit this bill. 
	 */
	assert(mKey.blobType() == CSSM_KEYBLOB_RAW);
	bool useAsIs = false;
	
	switch(mKey.keyClass()) {
		case CSSM_KEYCLASS_PUBLIC_KEY:
			if(mKey.blobFormat() == CSSM_KEYBLOB_RAW_FORMAT_PKCS1) {
				useAsIs = true;
			}
			break;
		case CSSM_KEYCLASS_PRIVATE_KEY:
			break;
		default:
			/* shouldn't be here */
			assert(0);
			CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
	}
	if(useAsIs) {
		const CssmData &keyBlob = CssmData::overlay(mKey.KeyData);
		copyCssmData(keyBlob, blob, allocator);
		return true;
	}
	
	/* caller converts to binary and proceeds */
	return false;
}
void copyData(
	const CSSM_DATA		&src,
	CSSM_DATA			&dst,
	Allocator		&allocator)
{
	copyCssmData(CssmData::overlay(src), 
		CssmData::overlay(dst), 
		allocator);
}
/* 
 * Obtain blob suitable for hashing in CSSM_APPLECSP_KEYDIGEST 
 * passthrough.
 */
bool SymmetricKeyInfoProvider::getHashableBlob(
	Allocator 	&allocator,
	CssmData		&blob)			// blob to hash goes here
{
	/*
	 * This is trivial: the raw key is already in the "proper" format.
	 */
	assert(mKey.blobType() == CSSM_KEYBLOB_RAW);
	const CssmData &keyBlob = CssmData::overlay(mKey.KeyData);
	copyCssmData(keyBlob, blob, allocator);
	return true;
}
/*
 * Generate keygen parameters, stash them in a context attr array for later use
 * when actually generating the keys.
 */
void DSAKeyPairGenContext::generate(
	const Context &context, 
	uint32 bitSize,
    CssmData &params,
    uint32 &attrCount, 
	Context::Attr * &attrs)
{
	void *seed = NULL;
	unsigned seedLen = 0;

	/* optional seed from context */
	CssmData *seedData = context.get<CssmData>(CSSM_ATTRIBUTE_SEED);
	if(seedData) {
		seed = seedData->data();
		seedLen = (unsigned)seedData->length();
	}

	/* generate the params, temp alloc from SecNssCoder  */
	NSS_DSAAlgParams algParams;
	SecNssCoder coder;
	dsaGenParams(bitSize, seed, seedLen, algParams, coder);
	
	/*
	 * Here comes the fun part. 
	 * We "return" the DER encoding of these generated params in two ways:
	 * 1. Copy out to app via the params argument, mallocing if Data ptr is NULL.
	 *    The app must free this. 
	 * 2. Cook up a 1-element Context::attr array containing one ALG_PARAM attr,
	 *    a CSSM_DATA_PTR containing the DER encoding. We have to save a ptr to
	 *    this attr array and free it, the CSSM_DATA it points to, and the DER
	 *    encoding *that* points to, in our destructor. 
	 *
	 * First, DER encode.
	 */
	CssmAutoData aDerData(session());
	DSAEncodeAlgParams(algParams, aDerData);

	/* copy/release that into a mallocd CSSM_DATA. */
	CSSM_DATA_PTR derData = (CSSM_DATA_PTR)session().malloc(sizeof(CSSM_DATA));
	*derData = aDerData.release();
	
	/* stuff that into a one-element Attr array which we keep after returning */
	freeGenAttrs();
	mGenAttrs = (Context::Attr *)session().malloc(sizeof(Context::Attr));
	mGenAttrs->AttributeType   = CSSM_ATTRIBUTE_ALG_PARAMS;
	mGenAttrs->AttributeLength = sizeof(CSSM_DATA);
	mGenAttrs->Attribute.Data  = derData;

	/* and "return" this stuff */
	copyCssmData(CssmData::overlay(*derData), params, session());
	attrCount = 1;
	attrs = mGenAttrs;
}
/* cook up a Binary key */
void SymmetricKeyInfoProvider::CssmKeyToBinary(
	CssmKey				*paramKey,	// ignored
	CSSM_KEYATTR_FLAGS	&attrFlags,	// IN/OUT
	BinaryKey 			**binKey)
{
	CASSERT(mKey.keyClass() == CSSM_KEYCLASS_SESSION_KEY);
	SymmetricBinaryKey *symBinKey = new SymmetricBinaryKey(
		mKey.KeyHeader.LogicalKeySizeInBits);
	copyCssmData(mKey, 
		symBinKey->mKeyData, 
		symBinKey->mAllocator);
	*binKey = symBinKey;
}
void SymmetricBinaryKey::generateKeyBlob(
	Allocator 		&allocator,
	CssmData			&blob,
	CSSM_KEYBLOB_FORMAT	&format,	// CSSM_KEYBLOB_RAW_FORMAT_PKCS1, etc.
	AppleCSPSession		&session,
	const CssmKey		*paramKey,	/* optional, unused here */
	CSSM_KEYATTR_FLAGS 	&attrFlags)	/* IN/OUT */
{
	switch(format) {
		case CSSM_KEYBLOB_RAW_FORMAT_NONE:			// default
		case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING:	// the one we can do
		case CSSM_KEYBLOB_RAW_FORMAT_DIGEST:		// same thing
			break;
		default:
			CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SYMMETRIC_KEY_FORMAT);
	}
	copyCssmData(mKeyData, blob, allocator);
	format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
}
Beispiel #7
0
/*
 * Obtain blob suitable for hashing in CSSM_APPLECSP_KEYDIGEST
 * passthrough.
 */
bool CryptKit::FEEKeyInfoProvider::getHashableBlob(
    Allocator 	&allocator,
    CssmData		&blob)			// blob to hash goes here
{
    /*
     * The optimized case, a raw key in the "proper" format already.
     * Currently this is:
     * FEE public key in default/NONE form (which happens to be DER)
     */
    assert(mKey.blobType() == CSSM_KEYBLOB_RAW);
    if((mKey.algorithm() == CSSM_ALGID_FEE) &&
            (mKey.blobFormat() == CSSM_KEYBLOB_RAW_FORMAT_NONE) &&
            (mKey.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY)) {
        const CssmData &keyBlob = CssmData::overlay(mKey.KeyData);
        copyCssmData(keyBlob, blob, allocator);
        return true;
    }

    /* caller converts to binary and proceeds */
    return false;
}
void AppleCSPSession::WrapKey(
		CSSM_CC_HANDLE CCHandle,
		const Context &Context,
        const AccessCredentials &AccessCred,
        const CssmKey &UnwrappedKey,
        const CssmData *DescriptiveData,
        CssmKey &WrappedKey,
		CSSM_PRIVILEGE Privilege)
{
	CssmKey::Header 		&wrappedHdr   = WrappedKey.header();
	bool 					isNullWrap = false;
	CssmKey					*wrappingKey = NULL;
	CSSM_KEYBLOB_FORMAT		wrapFormat;
	
	switch(UnwrappedKey.keyClass()) {
		case CSSM_KEYCLASS_PUBLIC_KEY:
		case CSSM_KEYCLASS_PRIVATE_KEY:
		case CSSM_KEYCLASS_SESSION_KEY:
			break;
		default:
			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
	}

	/* wrapping key only required for non-NULL wrap */
	wrappingKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_KEY);
	if(wrappingKey == NULL) {
		if((Context.algorithm() == CSSM_ALGID_NONE) &&
		   (Context.type() == CSSM_ALGCLASS_SYMMETRIC)) {
				// NULL wrap, OK
				isNullWrap = true;
		}
		else {
			errorLog0("WrapKey: missing wrapping key\n");
			CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_KEY);
		}
	}
	
	/*
	 * Validate misc. params as best we can
	 */
	if(isNullWrap) {
		wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_NONE;
	}
	else {
		/*
		 * Can only wrap session and private keys. 
		 */
		#if		!ALLOW_PUB_KEY_WRAP
		if(UnwrappedKey.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY) {
			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
		}
		#endif	/* ALLOW_PUB_KEY_WRAP */
		cspValidateIntendedKeyUsage(&wrappingKey->KeyHeader, CSSM_KEYUSE_WRAP);
		cspVerifyKeyTimes(wrappingKey->KeyHeader);
		
		/*
		 * make sure wrapping key type matches context
		 */
		CSSM_CONTEXT_TYPE wrapType;
		switch(wrappingKey->KeyHeader.KeyClass) {
			case CSSM_KEYCLASS_PUBLIC_KEY:
			case CSSM_KEYCLASS_PRIVATE_KEY:
				wrapType = CSSM_ALGCLASS_ASYMMETRIC;
				break;
			case CSSM_KEYCLASS_SESSION_KEY:
				wrapType = CSSM_ALGCLASS_SYMMETRIC;
				break;
			default:
				errorLog0("WrapKey: bad class of wrappingKey\n");
				CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY);
		}
		if(wrapType != Context.type()) {
			errorLog0("WrapKey: mismatch wrappingKey/contextType\n");
			CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);
		}
		if(Context.algorithm() == CSSM_ALGID_NONE) {
			errorLog0("WrapKey: null wrap alg, non-null key\n");
			CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
		}

		/*
		 * Get optional wrap format, set default per incoming keys
		 * Note: no such atrribute ==> 0 ==> FORMAT_NONE, which we
		 * take to mean "use the default".
		 */
		wrapFormat = Context.getInt(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT);
		if(wrapFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) {
			/* figure out a default based on unwrapped key */
			switch(UnwrappedKey.keyClass()) {
				case CSSM_KEYCLASS_SESSION_KEY:
					wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7;
					break;
				case CSSM_KEYCLASS_PUBLIC_KEY:
					wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM; 
					break;
				case CSSM_KEYCLASS_PRIVATE_KEY:
					switch(UnwrappedKey.algorithm()) {
						case CSSM_ALGID_FEE:
							wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM; 
							break;
						default:
							wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8; 
							break;
					}
					break;
				default:
					/* NOT REACHED - checked above */
					break;
			}
		}		/* no format present or FORMAT_NONE */
	}
	
	/* make sure we have a valid format here */
	switch(wrapFormat) {
		case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7:
			if(UnwrappedKey.keyClass() != CSSM_KEYCLASS_SESSION_KEY) {
				/* this wrapping style only for symmetric keys */
				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
			}
			break;
		case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8:
		case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSL:
			if(UnwrappedKey.keyClass() != CSSM_KEYCLASS_PRIVATE_KEY) {
				/* these wrapping styles only for private keys */
				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
			}
			break;
		case CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM:
			/* no restrictions (well AES can't be the wrap alg but that will 
			 * be caught later */
			break;
		case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1:
			/* RSA private key, reference format, only */
			if(UnwrappedKey.keyClass() != CSSM_KEYCLASS_PRIVATE_KEY) {
				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
			}
			if(UnwrappedKey.algorithm() != CSSM_ALGID_RSA) {
				CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
			}
			if(UnwrappedKey.blobType() != CSSM_KEYBLOB_REFERENCE) {
				CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
			}
			break;
		case CSSM_KEYBLOB_WRAPPED_FORMAT_NONE:
			if(isNullWrap) {
				/* only time this is OK */
				break;
			}
			/* else fall thru */
		default:
			dprintf1("KeyWrap: invalid wrapFormat (%d)\n", (int)wrapFormat);
			CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_WRAPPED_KEY_FORMAT);
	}
	/* get the blob to be wrappped */
	CssmData rawBlob;
	bool allocdRawBlob = false;
	CSSM_KEYBLOB_FORMAT rawFormat;
	
	/* 
	 * Outgoing same as incoming unless a partial key is completed during 
	 * generateKeyBlob()
	 */
	const CssmKey::Header &unwrappedHdr = UnwrappedKey.header();
	CSSM_KEYATTR_FLAGS unwrappedKeyAttrFlags = unwrappedHdr.KeyAttr;
	
	switch(UnwrappedKey.blobType()) {
		case CSSM_KEYBLOB_RAW:
			/* 
			 * Trivial case - we already have the blob.
			 * This op - wrapping a raw key - is not supported for the 
			 * CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1 format since that doesn't
			 * operate on a key blob.
			 */
			rawBlob = CssmData::overlay(UnwrappedKey.KeyData);
			rawFormat = UnwrappedKey.blobFormat();
			break;
		case CSSM_KEYBLOB_REFERENCE:
			/* get binary key, then get blob from it */
			{
				BinaryKey &binKey = lookupRefKey(UnwrappedKey);
				
				/*
				 * Subsequent tests for extractability: don't trust the 
				 * caller's header; use the one in the BinaryKey.
				 */
				CSSM_KEYATTR_FLAGS keyAttr = binKey.mKeyHeader.KeyAttr;
				if(!(keyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
					/* this key not extractable in any form */
					CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
				}
				
				/* 
				 * CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1: we're ready to roll; 
				 * all we need is the reference key.
				 */
				if(wrapFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1) {
					break;
				}
				
				/*
				 * Null wrap - prevent caller from obtaining 
				 * clear bits if CSSM_KEYATTR_SENSITIVE
				 */
				if(isNullWrap && (keyAttr & CSSM_KEYATTR_SENSITIVE)) {
					CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
				}

				/*
				 * Special case for PKCS8 and openssl: need to get blob of a specific
				 * algorithm-dependent format. Caller can override our 
				 * preference with a 
				 * CSSM_ATTRIBUTE_{PRIVATE,PUBLIC,SESSION}_KEY_FORMAT 
				 * context attribute. 
				 */
				rawFormat = requestedKeyFormat(Context, UnwrappedKey);
				if(rawFormat == CSSM_KEYBLOB_RAW_FORMAT_NONE) {
					CSSM_ALGORITHMS keyAlg = binKey.mKeyHeader.AlgorithmId;
					switch(wrapFormat) {
						case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8:
							rawFormat = pkcs8RawKeyFormat(keyAlg);
							break;
						case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSL:
							rawFormat = opensslRawKeyFormat(keyAlg);
							break;
						default:
							/* punt and take default for key type */
							break;
					}
				}
	
				/* 
				 * DescriptiveData for encoding, currently only used for 
				 * SSH1 keys.
				 */
				if((DescriptiveData != NULL) && (DescriptiveData->Length != 0)) {
					binKey.descData(*DescriptiveData);
				}
				
				/* optional parameter-bearing key */
				CssmKey *paramKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_PARAM_KEY);
				binKey.generateKeyBlob(privAllocator,
					rawBlob,
					rawFormat,
					*this,
					paramKey,
					unwrappedKeyAttrFlags);
			}
			allocdRawBlob = true;		// remember - we need to free
			break;
			
		default:
			errorLog0("WrapKey: bad unwrappedKey BlobType\n");
			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
	}

	/*
	 * Prepare outgoing header.
	 */
	setKeyHeader(wrappedHdr,
		plugin.myGuid(),
		unwrappedHdr.algorithm(),		// same as incoming 
		unwrappedHdr.keyClass(),		// same as incoming
		unwrappedKeyAttrFlags,
		unwrappedHdr.KeyUsage);
	wrappedHdr.LogicalKeySizeInBits = unwrappedHdr.LogicalKeySizeInBits;
	wrappedHdr.WrapAlgorithmId = Context.algorithm(); 	// true for null 
														// and non-Null 
	wrappedHdr.StartDate = unwrappedHdr.StartDate;
	wrappedHdr.EndDate = unwrappedHdr.EndDate;
	wrappedHdr.Format = wrapFormat;
	if(isNullWrap) {
		wrappedHdr.BlobType = CSSM_KEYBLOB_RAW;
	}
	else {
		wrappedHdr.BlobType = CSSM_KEYBLOB_WRAPPED;
	}
	
	/* 
	 * special cases - break out here for Apple Custom and OpenSSHv1  
	 */
	if(!isNullWrap) {
		switch(wrapFormat) {
			case CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM:
				try {
					WrapKeyCms(CCHandle,
						Context,
						AccessCred,
						UnwrappedKey,
						rawBlob,
						allocdRawBlob,
						DescriptiveData,
						WrappedKey,
						Privilege);
				}
				catch(...) {
					if(allocdRawBlob) {
						freeCssmData(rawBlob, privAllocator);
					}
					throw;
				}
				if(allocdRawBlob) {
					freeCssmData(rawBlob, privAllocator);
				}
				return;
			case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1:
			{
				/*
				 * 1. We don't have to worry about allocdRawBlob since this 
				 *    operation only works on reference keys and we did not
				 *    obtain the raw blob from the BinaryKey. 
				 * 2. This is a redundant lookupRefKey, I know, but since
				 *    that returns a reference, it would just be too messy to have
				 *    the previous call be in the same scope as this.
				 */
				BinaryKey &binKey = lookupRefKey(UnwrappedKey);
				WrapKeyOpenSSH1(CCHandle,
					Context,
					AccessCred,
					binKey,
					rawBlob,
					allocdRawBlob,
					DescriptiveData,
					WrappedKey,
					Privilege);
				return;
			}
			default:
				/* proceed to encrypt blob */
				break;
		}
	}	/* !isNullWrap */

	
	/*
	 * Generate wrapped blob. Careful, we need to conditionally free
	 * rawBlob on error.
	 */
	CssmData encryptedBlob;
	CssmData remData;
	WrappedKey.KeyData.Data = NULL;		// ignore possible incoming KeyData
	WrappedKey.KeyData.Length = 0;
	
	try {
		if(isNullWrap) {
			/* copy raw blob to caller's wrappedKey */
			copyCssmData(rawBlob, 
				CssmData::overlay(WrappedKey.KeyData), 
				normAllocator);
			wrappedHdr.Format   = rawFormat; 
		}
		else {
			/* encrypt rawBlob using caller's context, then encode to
			 * WrappedKey.KeyData */
			CSSM_SIZE bytesEncrypted;
			EncryptData(CCHandle,
				Context,
				&rawBlob,			// ClearBufs[]
				1,					// ClearBufCount
				&encryptedBlob,		// CipherBufs[],
				1,					// CipherBufCount,
				bytesEncrypted,
				remData,
				Privilege);
	
			// I'm not 100% sure about this....
			assert(remData.Length == 0);
			encryptedBlob.Length = bytesEncrypted;
			WrappedKey.KeyData = encryptedBlob;
			wrappedHdr.BlobType = CSSM_KEYBLOB_WRAPPED;
			// OK to be zero or not present 
			wrappedHdr.WrapMode = Context.getInt(
				CSSM_ATTRIBUTE_MODE);
		}
	}
	catch (...) {
		errorLog0("WrapKey: EncryptData() threw exception\n");
		if(allocdRawBlob) {
			freeCssmData(rawBlob, privAllocator);
		}
		freeCssmData(remData,normAllocator);
		throw;
	}
	if(allocdRawBlob) {
		freeCssmData(rawBlob, privAllocator);
	}
	freeCssmData(remData, normAllocator);
}