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