2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
22 Contains: CSSM_DeriveKey functions
24 Copyright: (C) 2000 by Apple Computer, Inc., all rights reserved
26 Written by: Doug Mitchell <dmitch@apple.com>
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>
38 /* minimum legal values */
39 #define PBKDF2_MIN_SALT 8 /* bytes */
40 #define PBKDF2_MIN_ITER_CNT 1000 /* iteration count */
42 #define ALLOW_ZERO_PASSWORD 1
44 void AppleCSPSession::DeriveKey_PBKDF2(
45 const Context
&context
,
46 const CssmData
&Param
,
49 /* validate algorithm-specific arguments */
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
);
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
);
63 uint32 passphraseLen
= pbkdf2Params
->Passphrase
.Length
;
64 uint8
*passphrase
= pbkdf2Params
->Passphrase
.Data
;
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
);
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
);
77 #endif /* ALLOW_ZERO_PASSWORD */
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
);
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
);
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
);
100 * allocate a temp buffer, length
101 * = MAX (hLen, saltLen + 4) + 2 * hLen
102 * = MAX (kSHA1DigestSize, saltLen + 4) + 2 * kSHA1DigestSize
104 uint32 tempLen
= salt
.Length
+ 4;
105 if(tempLen
< kSHA1DigestSize
) {
106 tempLen
= kSHA1DigestSize
;
108 tempLen
+= (2 * kSHA1DigestSize
);
109 CSSM_DATA tempData
= {0, NULL
};
110 setUpData(tempData
, tempLen
, privAllocator
);
115 passphrase
, passphraseLen
,
116 salt
.Data
, salt
.Length
,
118 keyData
->Data
, keyData
->Length
,
120 freeData(&tempData
, privAllocator
, false);
124 * Member function initially declared for CSPAbstractPluginSession;
125 * we're overriding the null version in CSPFullPluginSession.
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).
131 void AppleCSPSession::DeriveKey(
132 CSSM_CC_HANDLE CCHandle
,
133 const Context
&context
,
137 const CssmData
*KeyLabel
,
138 const CSSM_RESOURCE_CONTROL_CONTEXT
*CredAndAclEntry
,
141 /* validate input args, common to all algorithms */
142 switch(context
.algorithm()) {
143 case CSSM_ALGID_PKCS5_PBKDF2
:
146 /* maybe more here, later */
148 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
150 DerivedKey
.KeyData
.Data
= NULL
;
151 DerivedKey
.KeyData
.Length
= 0;
152 cspKeyStorage keyStorage
= cspParseKeyAttr(CKT_Session
, KeyAttr
);
153 cspValidateKeyUsageBits(CKT_Session
, KeyUsage
);
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
);
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
);
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
;
172 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
174 /* cook up a symmetric binary key */
175 binKey
= new SymmetricBinaryKey(reqKeySize
);
176 keyData
= &binKey
->mKeyData
;
179 /* key bytes --> caller's cssmKey */
180 keyData
= &DerivedKey
.KeyData
;
181 setUpData(*keyData
, keySizeInBytes
,
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
,
195 DeriveKey_DH(context
,
200 /* maybe more here, later */
205 /* set up outgoing header */
206 KeyAttr
&= ~KEY_ATTR_RETURN_MASK
;
207 CSSM_KEYHEADER
&hdr
= DerivedKey
.KeyHeader
;
211 CSSM_KEYCLASS_SESSION_KEY
,
214 hdr
.LogicalKeySizeInBits
= reqKeySize
;
216 if(keyStorage
== CKS_Ref
) {
217 /* store and convert to ref key */
218 addRefKey(*binKey
, DerivedKey
);
222 hdr
.BlobType
= CSSM_KEYBLOB_RAW
;
223 hdr
.Format
= CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
;