]> git.saurik.com Git - apple/security.git/blob - AppleCSP/AppleCSP/deriveKey.cpp
2b416a44a22778da7b71622895af588c0f7e723d
[apple/security.git] / AppleCSP / AppleCSP / deriveKey.cpp
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 File: deriveKey.cpp
21
22 Contains: CSSM_DeriveKey functions
23
24 Copyright: (C) 2000 by Apple Computer, Inc., all rights reserved
25
26 Written by: Doug Mitchell <dmitch@apple.com>
27 */
28
29 #include <PBKDF2/HMACSHA1.h>
30 #include <PBKDF2/pbkdf2.h>
31 #include "AppleCSPSession.h"
32 #include "AppleCSPUtils.h"
33 #include "cspdebugging.h"
34 #include <Security/context.h>
35 #include <Security/utilities.h>
36 #include <DiffieHellman/DH_exchange.h>
37
38 /* minimum legal values */
39 #define PBKDF2_MIN_SALT 8 /* bytes */
40 #define PBKDF2_MIN_ITER_CNT 1000 /* iteration count */
41
42 #define ALLOW_ZERO_PASSWORD 1
43
44 void AppleCSPSession::DeriveKey_PBKDF2(
45 const Context &context,
46 const CssmData &Param,
47 CSSM_DATA *keyData)
48 {
49 /* validate algorithm-specific arguments */
50
51 /* Param must point to a CSSM_PKCS5_PBKDF2_PARAMS */
52 if(Param.Length != sizeof(CSSM_PKCS5_PBKDF2_PARAMS)) {
53 errorLog0("DeriveKey_PBKDF2: Param wrong size\n");
54 CssmError::throwMe(CSSMERR_CSP_INVALID_INPUT_POINTER);
55 }
56 const CSSM_PKCS5_PBKDF2_PARAMS *pbkdf2Params =
57 reinterpret_cast<const CSSM_PKCS5_PBKDF2_PARAMS *>(Param.Data);
58 if(pbkdf2Params == NULL) {
59 errorLog0("DeriveKey_PBKDF2: null Param.Data\n");
60 CssmError::throwMe(CSSMERR_CSP_INVALID_DATA);
61 }
62
63 uint32 passphraseLen = pbkdf2Params->Passphrase.Length;
64 uint8 *passphrase = pbkdf2Params->Passphrase.Data;
65
66 #if !ALLOW_ZERO_PASSWORD
67 /* passphrase required */
68 if(passphrase == NULL) {
69 errorLog0("DeriveKey_PBKDF2: null Passphrase\n");
70 CssmError::throwMe(CSSMERR_CSP_INVALID_DATA);
71 }
72 if(passphraseLen == 0) {
73 /* FIXME - enforce minimum length? */
74 errorLog0("DeriveKey_PBKDF2: zero length passphrase\n");
75 CssmError::throwMe(CSSMERR_CSP_INVALID_INPUT_POINTER);
76 }
77 #endif /* ALLOW_ZERO_PASSWORD */
78
79 if(pbkdf2Params->PseudoRandomFunction !=
80 CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1) {
81 errorLog0("DeriveKey_PBKDF2: invalid PRF\n");
82 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
83 }
84
85 /* salt, from context, required */
86 CssmData salt = context.get<CssmData>(CSSM_ATTRIBUTE_SALT,
87 CSSMERR_CSP_MISSING_ATTR_SALT);
88 if((salt.Data == NULL) || (salt.Length < PBKDF2_MIN_SALT)){
89 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SALT);
90 }
91
92 /* iteration count, from context, required */
93 uint32 iterCount = context.getInt(CSSM_ATTRIBUTE_ITERATION_COUNT,
94 CSSMERR_CSP_MISSING_ATTR_ITERATION_COUNT);
95 if(iterCount < PBKDF2_MIN_ITER_CNT) {
96 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ITERATION_COUNT);
97 }
98
99 /*
100 * allocate a temp buffer, length
101 * = MAX (hLen, saltLen + 4) + 2 * hLen
102 * = MAX (kSHA1DigestSize, saltLen + 4) + 2 * kSHA1DigestSize
103 */
104 uint32 tempLen = salt.Length + 4;
105 if(tempLen < kSHA1DigestSize) {
106 tempLen = kSHA1DigestSize;
107 }
108 tempLen += (2 * kSHA1DigestSize);
109 CSSM_DATA tempData = {0, NULL};
110 setUpData(tempData, tempLen, privAllocator);
111
112 /* go */
113 pbkdf2 (hmacsha1,
114 kSHA1DigestSize,
115 passphrase, passphraseLen,
116 salt.Data, salt.Length,
117 iterCount,
118 keyData->Data, keyData->Length,
119 tempData.Data);
120 freeData(&tempData, privAllocator, false);
121 }
122
123 /*
124 * Member function initially declared for CSPAbstractPluginSession;
125 * we're overriding the null version in CSPFullPluginSession.
126 *
127 * Currently we only support one derive key algorithm -
128 * CSSM_ALGID_PKCS5_PBKDF2, with PRF CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1
129 * PRF. We'll generate any type of key (for now).
130 */
131 void AppleCSPSession::DeriveKey(
132 CSSM_CC_HANDLE CCHandle,
133 const Context &context,
134 CssmData &Param,
135 uint32 KeyUsage,
136 uint32 KeyAttr,
137 const CssmData *KeyLabel,
138 const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
139 CssmKey &DerivedKey)
140 {
141 /* validate input args, common to all algorithms */
142 switch(context.algorithm()) {
143 case CSSM_ALGID_PKCS5_PBKDF2:
144 case CSSM_ALGID_DH:
145 break;
146 /* maybe more here, later */
147 default:
148 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
149 }
150 DerivedKey.KeyData.Data = NULL;
151 DerivedKey.KeyData.Length = 0;
152 cspKeyStorage keyStorage = cspParseKeyAttr(CKT_Session, KeyAttr);
153 cspValidateKeyUsageBits(CKT_Session, KeyUsage);
154
155 /* outgoing key type, required (though any algorithm is OK) */
156 uint32 keyType = context.getInt(CSSM_ATTRIBUTE_KEY_TYPE,
157 CSSMERR_CSP_MISSING_ATTR_KEY_TYPE);
158
159 /* outgoing key size, required - any nonzero value is OK */
160 uint32 reqKeySize = context.getInt(
161 CSSM_ATTRIBUTE_KEY_LENGTH,
162 CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH);
163
164 /* cook up a place to put the key data */
165 uint32 keySizeInBytes = (reqKeySize + 7) / 8;
166 SymmetricBinaryKey *binKey = NULL;
167 CSSM_DATA_PTR keyData = NULL;
168
169 switch(keyStorage) {
170 case CKS_None:
171 /* no way */
172 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
173 case CKS_Ref:
174 /* cook up a symmetric binary key */
175 binKey = new SymmetricBinaryKey(reqKeySize);
176 keyData = &binKey->mKeyData;
177 break;
178 case CKS_Data:
179 /* key bytes --> caller's cssmKey */
180 keyData = &DerivedKey.KeyData;
181 setUpData(*keyData, keySizeInBytes,
182 normAllocator);
183 break;
184 }
185
186 /* break off to algorithm-specific code, whose job it is
187 * to fill in keyData->Data with keyData->Length bytes */
188 switch(context.algorithm()) {
189 case CSSM_ALGID_PKCS5_PBKDF2:
190 DeriveKey_PBKDF2(context,
191 Param,
192 keyData);
193 break;
194 case CSSM_ALGID_DH:
195 DeriveKey_DH(context,
196 Param,
197 keyData,
198 *this);
199 break;
200 /* maybe more here, later */
201 default:
202 assert(0);
203 }
204
205 /* set up outgoing header */
206 KeyAttr &= ~KEY_ATTR_RETURN_MASK;
207 CSSM_KEYHEADER &hdr = DerivedKey.KeyHeader;
208 setKeyHeader(hdr,
209 plugin.myGuid(),
210 keyType,
211 CSSM_KEYCLASS_SESSION_KEY,
212 KeyAttr,
213 KeyUsage);
214 hdr.LogicalKeySizeInBits = reqKeySize;
215
216 if(keyStorage == CKS_Ref) {
217 /* store and convert to ref key */
218 addRefKey(*binKey, DerivedKey);
219 }
220 else {
221 /* Raw data */
222 hdr.BlobType = CSSM_KEYBLOB_RAW;
223 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
224 }
225 }
226