2 * Copyright (c) 2003-2004 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
7 * obtain a copy of the License at http://www.apple.com/publicsource and
8 * read it before using this file.
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
12 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
13 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
15 * Please see the License for the specific language governing rights and
16 * limitations under the License.
20 * p12Crypto.cpp - PKCS12 Crypto routines. App space reference version.
22 * Created 2/28/03 by Doug Mitchell.
25 #include "p12Crypto.h"
27 #include <security_pkcs12/pkcs12Utils.h>
28 #include <security_cdsa_utils/cuCdsaUtils.h>
29 #include <Security/cssmapple.h>
32 * Free memory via specified plugin's app-level allocator
34 static void appFreeCssmMemory(
38 CSSM_API_MEMORY_FUNCS memFuncs
;
39 CSSM_RETURN crtn
= CSSM_GetAPIMemoryFunctions(hand
, &memFuncs
);
41 cssmPerror("CSSM_GetAPIMemoryFunctions", crtn
);
42 /* oh well, leak and continue */
45 memFuncs
.free_func(p
, memFuncs
.AllocRef
);
49 * Given appropriate P12-style parameters, cook up a CSSM_KEY.
50 * Eventually this will use DeriveKey; for now we do it ourself.
52 CSSM_RETURN
p12KeyGen_app(
53 CSSM_CSP_HANDLE cspHand
,
55 bool isForEncr
, // true: en/decrypt false: MAC
56 CSSM_ALGORITHMS keyAlg
,
57 CSSM_ALGORITHMS pbeHashAlg
, // SHA1, MD5 only
60 const CSSM_DATA
&salt
,
61 const CSSM_DATA
&pwd
, // unicode, double null terminated
62 CSSM_DATA
&iv
, // referent is optional
63 SecNssCoder
&coder
) // for mallocing KeyData
65 memset(&key
, 0, sizeof(CSSM_KEY
));
66 unsigned keyBytes
= (keySizeInBits
+ 7) / 8;
67 coder
.allocItem(key
.KeyData
, keyBytes
);
68 CSSM_RETURN crtn
= p12PbeGen_app(pwd
,
69 salt
.Data
, salt
.Length
,
71 isForEncr
? PBE_ID_Key
: PBE_ID_Mac
,
74 (unsigned char *)key
.KeyData
.Data
,
77 cuPrintError("p12PbeGen(key)", crtn
);
81 /* fill in the blanks */
82 CSSM_KEYHEADER
&hdr
= key
.KeyHeader
;
83 hdr
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
85 hdr
.BlobType
= CSSM_KEYBLOB_RAW
;
86 hdr
.AlgorithmId
= keyAlg
;
87 hdr
.Format
= CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
;
88 hdr
.KeyClass
= CSSM_KEYCLASS_SESSION_KEY
;
89 hdr
.KeyUsage
= CSSM_KEYUSE_ANY
;
90 /* start/end date unknown, leave zero */
91 hdr
.WrapAlgorithmId
= CSSM_ALGID_NONE
;
92 hdr
.WrapMode
= CSSM_ALGMODE_NONE
;
93 hdr
.LogicalKeySizeInBits
= keySizeInBits
;
95 /* P12 style IV derivation, optional */
97 crtn
= p12PbeGen_app(pwd
,
98 salt
.Data
, salt
.Length
,
105 cuPrintError("p12PbeGen (IV)", crtn
);
114 * Decrypt (typically, an encrypted P7 ContentInfo contents or
115 * a P12 ShroudedKeyBag).
117 CSSM_RETURN
p12Decrypt_app(
118 CSSM_CSP_HANDLE cspHand
,
119 const CSSM_DATA
&cipherText
,
120 CSSM_ALGORITHMS keyAlg
,
121 CSSM_ALGORITHMS encrAlg
,
122 CSSM_ALGORITHMS pbeHashAlg
, // SHA1, MD5 only
123 uint32 keySizeInBits
,
124 uint32 blockSizeInBytes
, // for IV
125 CSSM_PADDING padding
, // CSSM_PADDING_PKCS7, etc.
126 CSSM_ENCRYPT_MODE mode
, // CSSM_ALGMODE_CBCPadIV8, etc.
128 const CSSM_DATA
&salt
,
129 const CSSM_DATA
&pwd
, // unicode, double null terminated
130 SecNssCoder
&coder
, // for mallocing KeyData and plainText
131 CSSM_DATA
&plainText
)
135 CSSM_CC_HANDLE ccHand
= 0;
137 /* P12 style IV derivation, optional */
138 CSSM_DATA iv
= {0, NULL
};
139 CSSM_DATA_PTR ivPtr
= NULL
;
140 if(blockSizeInBytes
) {
141 coder
.allocItem(iv
, blockSizeInBytes
);
145 /* P12 style key derivation */
146 crtn
= p12KeyGen_app(cspHand
, ckey
, true, keyAlg
, pbeHashAlg
,
147 keySizeInBits
, iterCount
, salt
, pwd
, iv
, coder
);
153 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
158 ivPtr
, // InitVector, optional
163 cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn
);
167 /* go - CSP mallocs ptext and rem data */
168 CSSM_DATA ourPtext
= {0, NULL
};
169 CSSM_DATA remData
= {0, NULL
};
170 uint32 bytesDecrypted
;
171 crtn
= CSSM_DecryptData(ccHand
,
179 cuPrintError("CSSM_EncryptData", crtn
);
182 coder
.allocCopyItem(ourPtext
, plainText
);
183 plainText
.Length
= bytesDecrypted
;
185 /* plaintext copied into coder space; free the memory allocated
187 appFreeCssmMemory(cspHand
, ourPtext
.Data
);
189 /* an artifact of CSPFUllPLuginSession - this never contains
190 * valid data but sometimes gets mallocds */
192 appFreeCssmMemory(cspHand
, remData
.Data
);
194 CSSM_DeleteContext(ccHand
);
199 * Calculate the MAC for a PFX. Caller is either going compare
200 * the result against an existing PFX's MAC or drop the result into
201 * a newly created PFX.
203 CSSM_RETURN
p12GenMac_app(
204 CSSM_CSP_HANDLE cspHand
,
205 const CSSM_DATA
&ptext
, // e.g., NSS_P12_DecodedPFX.derAuthSaafe
206 CSSM_ALGORITHMS alg
, // better be SHA1!
208 const CSSM_DATA
&salt
,
209 const CSSM_DATA
&pwd
, // unicode, double null terminated
210 SecNssCoder
&coder
, // for mallocing macData
211 CSSM_DATA
&macData
) // RETURNED
215 /* P12 style key derivation */
216 unsigned keySizeInBits
;
217 CSSM_ALGORITHMS hmacAlg
;
219 case CSSM_ALGID_SHA1
:
221 hmacAlg
= CSSM_ALGID_SHA1HMAC
;
224 /* not even sure if this is legal in p12 world... */
226 hmacAlg
= CSSM_ALGID_MD5HMAC
;
229 return CSSMERR_CSP_INVALID_ALGORITHM
;
232 CSSM_DATA iv
= {0, NULL
};
233 crtn
= p12KeyGen_app(cspHand
, macKey
, false, hmacAlg
, alg
,
234 keySizeInBits
, iterCount
, salt
, pwd
, iv
, coder
);
239 /* prealloc the mac data */
240 coder
.allocItem(macData
, keySizeInBits
/ 8);
241 CSSM_CC_HANDLE ccHand
= 0;
242 crtn
= CSSM_CSP_CreateMacContext(cspHand
, hmacAlg
, &macKey
, &ccHand
);
244 cuPrintError("CSSM_CSP_CreateMacContext", crtn
);
248 crtn
= CSSM_GenerateMac (ccHand
, &ptext
, 1, &macData
);
250 cuPrintError("CSSM_GenerateMac", crtn
);
252 CSSM_DeleteContext(ccHand
);
257 * Verify MAC on an existing PFX.
259 CSSM_RETURN
p12VerifyMac_app(
260 const NSS_P12_DecodedPFX
&pfx
,
261 CSSM_CSP_HANDLE cspHand
,
262 const CSSM_DATA
&pwd
, // unicode, double null terminated
263 SecNssCoder
&coder
) // for temp mallocs
265 if(pfx
.macData
== NULL
) {
266 return CSSMERR_CSP_INVALID_SIGNATURE
;
268 NSS_P12_MacData
&macData
= *pfx
.macData
;
269 NSS_P7_DigestInfo
&digestInfo
= macData
.mac
;
270 CSSM_OID
&algOid
= digestInfo
.digestAlgorithm
.algorithm
;
271 CSSM_ALGORITHMS macAlg
;
272 if(!cssmOidToAlg(&algOid
, &macAlg
)) {
273 return CSSMERR_CSP_INVALID_ALGORITHM
;
275 uint32 iterCount
= 0;
276 CSSM_DATA
&citer
= macData
.iterations
;
277 if(!p12DataToInt(citer
, iterCount
)) {
278 return CSSMERR_CSP_INVALID_ATTR_ROUNDS
;
281 /* optional, default 1 */
286 * In classic fashion, the PKCS12 spec now says:
288 * When password integrity mode is used to secure a PFX PDU,
289 * an SHA-1 HMAC is computed on the BER-encoding of the contents
290 * of the content field of the authSafe field in the PFX PDU.
295 CSSM_RETURN crtn
= p12GenMac_app(cspHand
, *pfx
.authSafe
.content
.data
,
296 macAlg
, iterCount
, macData
.macSalt
, pwd
, coder
, genMac
);
300 if(nssCompareCssmData(&genMac
, &digestInfo
.digest
)) {
304 return CSSMERR_CSP_VERIFY_FAILED
;