1/*
2 * Copyright (c) 2003,2005 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
7 * obtain a copy of the License at http://www.apple.com/publicsource and
8 * read it before 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
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.
17 */
18
19/*
20 * pkcs12Utils.cpp - standalone copies of utility functions from libsecurity_pkcs12
21 */
22
23#include "pkcs12Utils.h"
24#include <string.h>
25#include <Security/oidsalg.h>
26#include <security_asn1/nssUtils.h>
27
28/* CSSM_DATA --> uint32. Returns true if OK. */
29bool p12DataToInt(
30	const CSSM_DATA &cdata,
31	uint32 &u)
32{
33	if((cdata.Length == 0) || (cdata.Data == NULL)) {
34		/* default/not present */
35		u = 0;
36		return true;
37	}
38	uint32 len = cdata.Length;
39	if(len > sizeof(uint32)) {
40		return false;
41	}
42
43	uint32 rtn = 0;
44	uint8 *cp = cdata.Data;
45	for(uint32 i=0; i<len; i++) {
46		rtn = (rtn << 8) | *cp++;
47	}
48	u = rtn;
49	return true;
50}
51
52/*
53 * OIDS for P12 and PKCS5 v1.5 (PBES1) encrypt and decrypt map to the following
54 * attributes.
55 */
56typedef struct {
57	const CSSM_OID		*oid;
58	CSSM_ALGORITHMS		keyAlg;		// e.g., CSSM_ALGID_DES
59	CSSM_ALGORITHMS		encrAlg;	// e.g., CSSM_ALGID_3DES_3KEY_EDE
60	CSSM_ALGORITHMS		pbeHashAlg;	// SHA1 or MD5
61	uint32				keySizeInBits;
62	uint32				blockSizeInBytes;	// for IV, optional
63	CSSM_PADDING		padding;	// CSSM_PADDING_PKCS7, etc.
64	CSSM_ENCRYPT_MODE	mode;		// CSSM_ALGMODE_CBCPadIV8, etc.
65	PKCS_Which			pkcs;		// PW_PKCS12 (for this module) or PW_PKCS5_v1_5
66} PKCSOidInfo;
67
68static const PKCSOidInfo pkcsOidInfos[] = {
69	/* PKCS12 first, the ones this module uses */
70	{
71		&CSSMOID_PKCS12_pbeWithSHAAnd128BitRC4,
72		CSSM_ALGID_RC4,
73		CSSM_ALGID_RC4,
74		CSSM_ALGID_SHA1,
75		128,
76		0,					// RC4 is a stream cipher
77		CSSM_PADDING_NONE,
78		CSSM_ALGMODE_NONE,
79		PW_PKCS12
80	},
81	{
82		&CSSMOID_PKCS12_pbeWithSHAAnd40BitRC4,
83		CSSM_ALGID_RC4,
84		CSSM_ALGID_RC4,
85		CSSM_ALGID_SHA1,
86		40,
87		0,					// RC4 is a stream cipher
88		CSSM_PADDING_NONE,
89		CSSM_ALGMODE_NONE,
90		PW_PKCS12
91	},
92	{
93		&CSSMOID_PKCS12_pbeWithSHAAnd3Key3DESCBC,
94		CSSM_ALGID_3DES_3KEY,
95		CSSM_ALGID_3DES_3KEY_EDE,
96		CSSM_ALGID_SHA1,
97		64 * 3,
98		8,
99		CSSM_PADDING_PKCS7,
100		CSSM_ALGMODE_CBCPadIV8,
101		PW_PKCS12
102	},
103	{
104		&CSSMOID_PKCS12_pbeWithSHAAnd2Key3DESCBC,
105		CSSM_ALGID_3DES_2KEY,
106		CSSM_ALGID_3DES_2KEY_EDE,
107		CSSM_ALGID_SHA1,
108		64 * 2,
109		8,
110		CSSM_PADDING_PKCS7,
111		CSSM_ALGMODE_CBCPadIV8,
112		PW_PKCS12
113	},
114	{
115		&CSSMOID_PKCS12_pbeWithSHAAnd128BitRC2CBC,
116		CSSM_ALGID_RC2,
117		CSSM_ALGID_RC2,
118		CSSM_ALGID_SHA1,
119		128,
120		8,
121		CSSM_PADDING_PKCS7,
122		CSSM_ALGMODE_CBCPadIV8,
123		PW_PKCS12
124	},
125	{
126		&CSSMOID_PKCS12_pbewithSHAAnd40BitRC2CBC,
127		CSSM_ALGID_RC2,
128		CSSM_ALGID_RC2,
129		CSSM_ALGID_SHA1,
130		40,
131		8,
132		CSSM_PADDING_PKCS7,
133		CSSM_ALGMODE_CBCPadIV8,
134		PW_PKCS12
135	},
136
137	/* PKCS5 v1.5, used for SecImportExport module */
138	{
139		&CSSMOID_PKCS5_pbeWithMD2AndDES,
140		CSSM_ALGID_DES,
141		CSSM_ALGID_DES,
142		CSSM_ALGID_MD2,
143		64,
144		8,
145		CSSM_PADDING_PKCS7,
146		CSSM_ALGMODE_CBCPadIV8,
147		PW_PKCS5_v1_5
148	},
149	{
150		&CSSMOID_PKCS5_pbeWithMD2AndRC2,
151		CSSM_ALGID_RC2,
152		CSSM_ALGID_RC2,
153		CSSM_ALGID_MD2,
154		64,
155		8,
156		CSSM_PADDING_PKCS7,
157		CSSM_ALGMODE_CBCPadIV8,
158		PW_PKCS5_v1_5
159	},
160	{
161		&CSSMOID_PKCS5_pbeWithMD5AndDES,
162		CSSM_ALGID_DES,
163		CSSM_ALGID_DES,
164		CSSM_ALGID_MD5,
165		64,
166		8,
167		CSSM_PADDING_PKCS7,
168		CSSM_ALGMODE_CBCPadIV8,
169		PW_PKCS5_v1_5
170	},
171	{
172		&CSSMOID_PKCS5_pbeWithMD5AndRC2,
173		CSSM_ALGID_RC2,
174		CSSM_ALGID_RC2,
175		CSSM_ALGID_MD5,
176		64,
177		8,
178		CSSM_PADDING_PKCS7,
179		CSSM_ALGMODE_CBCPadIV8,
180		PW_PKCS5_v1_5
181	},
182	{
183		&CSSMOID_PKCS5_pbeWithSHA1AndDES,
184		CSSM_ALGID_DES,
185		CSSM_ALGID_DES,
186		CSSM_ALGID_SHA1,
187		64,
188		8,
189		CSSM_PADDING_PKCS7,
190		CSSM_ALGMODE_CBCPadIV8,
191		PW_PKCS5_v1_5
192	},
193	{
194		&CSSMOID_PKCS5_pbeWithSHA1AndRC2,
195		CSSM_ALGID_RC2,
196		CSSM_ALGID_RC2,
197		CSSM_ALGID_SHA1,
198		64,
199		8,
200		CSSM_PADDING_PKCS7,
201		CSSM_ALGMODE_CBCPadIV8,
202		PW_PKCS5_v1_5
203	},
204
205	/* finally one for PKCS5 v2.0, which has its own means of
206	 * cooking up all the parameters */
207	{
208		&CSSMOID_PKCS5_PBES2,
209		CSSM_ALGID_NONE,
210		CSSM_ALGID_NONE,
211		CSSM_ALGID_NONE,
212		0, 0, 0, 0,
213		PW_PKCS5_v2
214	}
215};
216
217#define NUM_PKCS_OID_INFOS (sizeof(pkcsOidInfos) / sizeof(pkcsOidInfos[1]))
218
219/* map an OID to the components */
220/* returns false if OID not found */
221
222/*
223 * NOTE: as of March 8 2004 this is also used by the SecImportExport
224 * module...not just PKCS12!
225 */
226bool pkcsOidToParams(
227	const CSSM_OID 		*oid,
228	CSSM_ALGORITHMS		&keyAlg,		// e.g., CSSM_ALGID_DES
229	CSSM_ALGORITHMS		&encrAlg,		// e.g., CSSM_ALGID_3DES_3KEY_EDE
230	CSSM_ALGORITHMS		&pbeHashAlg,	// SHA1 or MD5
231	uint32				&keySizeInBits,
232	uint32				&blockSizeInBytes,	// for IV, optional
233	CSSM_PADDING		&padding,		// CSSM_PADDING_PKCS7, etc.
234	CSSM_ENCRYPT_MODE	&mode,			// CSSM_ALGMODE_CBCPadIV8, etc.
235	PKCS_Which			&pkcs)			// PW_PKCS5_v1_5 or PW_PKCS12
236{
237	const PKCSOidInfo *info = pkcsOidInfos;
238	pkcs = PW_None;
239
240	for(unsigned dex=0; dex<NUM_PKCS_OID_INFOS; dex++) {
241		if(nssCompareCssmData(oid, info->oid)) {
242			keyAlg 			 = info->keyAlg;
243			encrAlg 		 = info->encrAlg;
244			pbeHashAlg 		 = info->pbeHashAlg;
245			keySizeInBits 	 = info->keySizeInBits;
246			blockSizeInBytes = info->blockSizeInBytes;
247			padding			 = info->padding;
248			mode 			 = info->mode;
249			pkcs			 = info->pkcs;
250			return true;
251		}
252		info++;
253	}
254	return false;
255}
256
257/*
258 * Enum to string mappper.
259 * Maybe DEBUG only.
260 */
261/*
262 * Each type of attribute has a name/value pair in a table of these:
263 */
264typedef struct {
265	unsigned		value;
266	const char 		*name;
267} p12NameValuePair;
268
269/* declare one entry in a table of p12NameValuePair */
270#define NVP(attr)		{attr, #attr}
271
272/* the NULL entry which terminates all p12NameValuePair tables */
273#define NVP_END		{0, NULL}
274
275static const p12NameValuePair p7CITypeNames[] =
276{
277	NVP(CT_None),
278	NVP(CT_Data),
279	NVP(CT_SignedData),
280	NVP(CT_EnvData),
281	NVP(CT_SignedEnvData),
282	NVP(CT_DigestData),
283	NVP(CT_EncryptedData),
284	NVP_END
285};
286
287static const p12NameValuePair p12BagTypeNames[] =
288{
289	NVP(BT_None),
290	NVP(BT_KeyBag),
291	NVP(BT_ShroudedKeyBag),
292	NVP(BT_CertBag),
293	NVP(BT_CrlBag),
294	NVP(BT_SecretBag),
295	NVP(BT_SafeContentsBag),
296	NVP_END
297};
298
299static const char *typeToStr(
300	unsigned type,
301	const p12NameValuePair *table)
302{
303	while(table->name) {
304		if(table->value == type) {
305			return table->name;
306		}
307		table++;
308	}
309	return "Unknown";
310}
311
312const char *p12BagTypeStr(
313	NSS_P12_SB_Type type)
314{
315	return typeToStr(type, p12BagTypeNames);
316}
317
318const char *p7ContentInfoTypeStr(
319	NSS_P7_CI_Type type)
320{
321	return typeToStr(type, p7CITypeNames);
322}
323