1/*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19/*
20 * DH_utils.cpp
21 */
22
23#include "DH_utils.h"
24#include "DH_keys.h"
25#include <opensslUtils/opensslAsn1.h>
26#include <security_utilities/logging.h>
27#include <security_utilities/debugging.h>
28#include <opensslUtils/opensslUtils.h>
29#include <openssl/bn.h>
30#include <openssl/dh.h>
31#include <openssl/err.h>
32
33#define dhMiscDebug(args...)	secdebug("dhMisc", ## args)
34
35/*
36 * Given a Context:
37 * -- obtain CSSM key with specified attr (there must only be one)
38 * -- validate keyClass per caller's specification
39 * -- validate keyUsage
40 * -- convert to DH *, allocating the DH key if necessary
41 */
42DH *contextToDhKey(
43	const Context		&context,
44	AppleCSPSession 	&session,
45	CSSM_ATTRIBUTE_TYPE	attr,		  // CSSM_ATTRIBUTE_KEY for private key
46									  // CSSM_ATTRIBUTE_PUBLIC_KEY for public key
47	CSSM_KEYCLASS		keyClass,	  // CSSM_KEYCLASS_{PUBLIC,PRIVATE}_KEY
48	CSSM_KEYUSE			usage,		  // CSSM_KEYUSE_ENCRYPT, CSSM_KEYUSE_SIGN, etc.
49	bool				&mallocdKey)  // RETURNED
50{
51    CssmKey *cssmKey = context.get<CssmKey>(attr);
52	if(cssmKey == NULL) {
53		return NULL;
54	}
55	const CSSM_KEYHEADER &hdr = cssmKey->KeyHeader;
56	if(hdr.AlgorithmId != CSSM_ALGID_DH) {
57		CssmError::throwMe(CSSMERR_CSP_ALGID_MISMATCH);
58	}
59	if(hdr.KeyClass != keyClass) {
60		CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
61	}
62	cspValidateIntendedKeyUsage(&hdr, usage);
63	cspVerifyKeyTimes(hdr);
64	return cssmKeyToDh(*cssmKey, session, mallocdKey);
65}
66
67/*
68 * Convert a CssmKey to an DH * key. May result in the
69 * creation of a new DH (when cssmKey is a raw key); allocdKey is true
70 * in that case in which case the caller generally has to free the allocd key).
71 */
72DH *cssmKeyToDh(
73	const CssmKey	&cssmKey,
74	AppleCSPSession	&session,
75	bool			&allocdKey)		// RETURNED
76{
77	DH *dhKey = NULL;
78	allocdKey = false;
79
80	const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader;
81	if(hdr->AlgorithmId != CSSM_ALGID_DH) {
82		// someone else's key (should never happen)
83		CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
84	}
85	switch(hdr->BlobType) {
86		case CSSM_KEYBLOB_RAW:
87			dhKey = rawCssmKeyToDh(cssmKey);
88			cspDhDebug("cssmKeyToDh, raw, dhKey %p", dhKey);
89			allocdKey = true;
90			break;
91		case CSSM_KEYBLOB_REFERENCE:
92		{
93			BinaryKey &binKey = session.lookupRefKey(cssmKey);
94			DHBinaryKey *dhBinKey = dynamic_cast<DHBinaryKey *>(&binKey);
95			/* this cast failing means that this is some other
96			 * kind of binary key */
97			if(dhBinKey == NULL) {
98				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
99			}
100			assert(dhBinKey->mDhKey != NULL);
101			dhKey = dhBinKey->mDhKey;
102			cspDhDebug("cssmKeyToDh, ref, dhKey %p", dhKey);
103			break;
104		}
105		default:
106			CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
107	}
108	return dhKey;
109}
110
111/*
112 * Convert a raw CssmKey to a newly alloc'd DH key.
113 */
114DH *rawCssmKeyToDh(
115	const CssmKey	&cssmKey)
116{
117	const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader;
118	bool isPub = false;
119
120	if(hdr->AlgorithmId != CSSM_ALGID_DH) {
121		// someone else's key (should never happen)
122		CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
123	}
124	assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
125	/* validate and figure out what we're dealing with */
126	switch(hdr->KeyClass) {
127		case CSSM_KEYCLASS_PUBLIC_KEY:
128			switch(hdr->Format) {
129				case CSSM_KEYBLOB_RAW_FORMAT_PKCS3:
130				case CSSM_KEYBLOB_RAW_FORMAT_X509:
131					break;
132				/* openssh real soon now */
133				case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH:
134				default:
135					CssmError::throwMe(
136						CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT);
137			}
138			isPub = true;
139			break;
140		case CSSM_KEYCLASS_PRIVATE_KEY:
141			switch(hdr->Format) {
142				case CSSM_KEYBLOB_RAW_FORMAT_PKCS3:	// default
143				case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:	// SMIME style
144					break;
145				/* openssh real soon now */
146				case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH:
147				default:
148					CssmError::throwMe(
149						CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT);
150			}
151			isPub = false;
152			break;
153		default:
154			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
155	}
156
157	CSSM_RETURN crtn;
158
159	DH *dhKey = DH_new();
160	if(dhKey == NULL) {
161		crtn = CSSMERR_CSP_MEMORY_ERROR;
162	}
163    else
164    {
165        if(isPub) {
166            crtn = DHPublicKeyDecode(dhKey, hdr->Format,
167                cssmKey.KeyData.Data, (unsigned)cssmKey.KeyData.Length);
168        }
169        else {
170            crtn = DHPrivateKeyDecode(dhKey, hdr->Format,
171                cssmKey.KeyData.Data, (unsigned)cssmKey.KeyData.Length);
172        }
173    }
174
175	if(crtn) {
176        if (dhKey != NULL) {
177            DH_free(dhKey);
178        }
179
180        CssmError::throwMe(crtn);
181	}
182	cspDhDebug("rawCssmKeyToDh, dhKey %p", dhKey);
183	return dhKey;
184}
185
186