/ SecurityTool / macOS / srCdsaUtils.cpp
srCdsaUtils.cpp
  1  /*
  2   * Copyright (c) 2001,2003-2012,2014 Apple Inc. All Rights Reserved.
  3   *
  4   * @APPLE_LICENSE_HEADER_START@
  5   * 
  6   * This file contains Original Code and/or Modifications of Original Code
  7   * as defined in and that are subject to the Apple Public Source License
  8   * Version 2.0 (the 'License'). You may not use this file except in
  9   * compliance with the License. Please obtain a copy of the License at
 10   * http://www.opensource.apple.com/apsl/ and read it before using this
 11   * file.
 12   * 
 13   * The Original Code and all software distributed under the License are
 14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 18   * Please see the License for the specific language governing rights and
 19   * limitations under the License.
 20   * 
 21   * @APPLE_LICENSE_HEADER_END@
 22   *
 23   * srCdsaUtils.cpp -- common CDSA access utilities
 24   */
 25  
 26  #include "srCdsaUtils.h"
 27  #include <stdlib.h>
 28  #include <stdio.h>
 29  #include <Security/SecCertificate.h>
 30  #include <Security/cssmapple.h>				/* for cssmPerror() */
 31  #include <Security/oidsalg.h>				/* for cssmPerror() */
 32  #include <strings.h>
 33  
 34  static CSSM_VERSION vers = {2, 0};
 35  static const CSSM_GUID testGuid = { 0xFADE, 0, 0, { 1,2,3,4,5,6,7,0 }};
 36  
 37  /*
 38   * Standard app-level memory functions required by CDSA.
 39   */
 40  void * srAppMalloc (CSSM_SIZE size, void *allocRef) {
 41  	return( malloc(size) );
 42  }
 43  
 44  void srAppFree (void *mem_ptr, void *allocRef) {
 45  	free(mem_ptr);
 46   	return;
 47  }
 48  
 49  void * srAppRealloc (void *ptr, CSSM_SIZE size, void *allocRef) {
 50  	return( realloc( ptr, size ) );
 51  }
 52  
 53  void * srAppCalloc (uint32 num, CSSM_SIZE size, void *allocRef) {
 54  	return( calloc( num, size ) );
 55  }
 56  
 57  static CSSM_API_MEMORY_FUNCS memFuncs = {
 58  	srAppMalloc,
 59  	srAppFree,
 60  	srAppRealloc,
 61   	srAppCalloc,
 62   	NULL
 63   };
 64  
 65  CSSM_BOOL srCompareCssmData(const CSSM_DATA *d1,
 66  	const CSSM_DATA *d2)
 67  {
 68  	if(d1->Length != d2->Length) {
 69  		return CSSM_FALSE;
 70  	}
 71  	if(memcmp(d1->Data, d2->Data, d1->Length)) {
 72  		return CSSM_FALSE;
 73  	}
 74  	return CSSM_TRUE;
 75  }
 76  
 77  /*
 78   * Init CSSM; returns CSSM_FALSE on error. Reusable.
 79   */
 80  static CSSM_BOOL cssmInitd = CSSM_FALSE;
 81  
 82  CSSM_BOOL srCssmStartup()
 83  {
 84  	CSSM_RETURN  crtn;
 85      CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
 86  
 87  	if(cssmInitd) {
 88  		return CSSM_TRUE;
 89  	}
 90  	crtn = CSSM_Init (&vers,
 91  		CSSM_PRIVILEGE_SCOPE_NONE,
 92  		&testGuid,
 93  		CSSM_KEY_HIERARCHY_NONE,
 94  		&pvcPolicy,
 95  		NULL /* reserved */);
 96  	if(crtn != CSSM_OK)
 97  	{
 98  		srPrintError("CSSM_Init", crtn);
 99  		return CSSM_FALSE;
100  	}
101  	else {
102  		cssmInitd = CSSM_TRUE;
103  		return CSSM_TRUE;
104  	}
105  }
106  
107  /*
108   * Attach to CSP. Returns zero on error.
109   */
110  CSSM_CSP_HANDLE srCspStartup(
111  	CSSM_BOOL bareCsp)		// true ==> CSP, false ==> CSP/DL
112  {
113  	CSSM_CSP_HANDLE cspHand;
114  	CSSM_RETURN		crtn;
115  	const CSSM_GUID *guid;
116  
117  	/* common CSSM init */
118  	if(srCssmStartup() == CSSM_FALSE) {
119  		return 0;
120  	}
121  	if(bareCsp) {
122  		guid = &gGuidAppleCSP;
123  	}
124  	else {
125  		guid = &gGuidAppleCSPDL;
126  	}
127  	crtn = CSSM_ModuleLoad(guid,
128  		CSSM_KEY_HIERARCHY_NONE,
129  		NULL,			// eventHandler
130  		NULL);			// AppNotifyCallbackCtx
131  	if(crtn) {
132  		srPrintError("CSSM_ModuleLoad()", crtn);
133  		return 0;
134  	}
135  	crtn = CSSM_ModuleAttach (guid,
136  		&vers,
137  		&memFuncs,			// memFuncs
138  		0,					// SubserviceID
139  		CSSM_SERVICE_CSP,
140  		0,					// AttachFlags
141  		CSSM_KEY_HIERARCHY_NONE,
142  		NULL,				// FunctionTable
143  		0,					// NumFuncTable
144  		NULL,				// reserved
145  		&cspHand);
146  	if(crtn) {
147  		srPrintError("CSSM_ModuleAttach()", crtn);
148  		return 0;
149  	}
150  	return cspHand;
151  }
152  
153  /* Attach to DL side of CSPDL */
154  CSSM_DL_HANDLE srDlStartup()
155  {
156  	CSSM_DL_HANDLE 	dlHand = 0;
157  	CSSM_RETURN		crtn;
158  
159  	if(srCssmStartup() == CSSM_FALSE) {
160  		return 0;
161  	}
162  	crtn = CSSM_ModuleLoad(&gGuidAppleCSPDL,
163  		CSSM_KEY_HIERARCHY_NONE,
164  		NULL,			// eventHandler
165  		NULL);			// AppNotifyCallbackCtx
166  	if(crtn) {
167  		srPrintError("CSSM_ModuleLoad(Apple CSPDL)", crtn);
168  		return 0;
169  	}
170  	crtn = CSSM_ModuleAttach (&gGuidAppleCSPDL,
171  		&vers,
172  		&memFuncs,			// memFuncs
173  		0,					// SubserviceID
174  		CSSM_SERVICE_DL,
175  		0,					// AttachFlags
176  		CSSM_KEY_HIERARCHY_NONE,
177  		NULL,				// FunctionTable
178  		0,					// NumFuncTable
179  		NULL,				// reserved
180  		&dlHand);
181  	if(crtn) {
182  		srPrintError("CSSM_ModuleAttach(Apple CSPDL)", crtn);
183  		return 0;
184  	}
185  	return dlHand;
186  }
187  
188  CSSM_CL_HANDLE srClStartup()
189  {
190  	CSSM_CL_HANDLE clHand;
191  	CSSM_RETURN crtn;
192  
193  	if(srCssmStartup() == CSSM_FALSE) {
194  		return 0;
195  	}
196  	crtn = CSSM_ModuleLoad(&gGuidAppleX509CL,
197  		CSSM_KEY_HIERARCHY_NONE,
198  		NULL,			// eventHandler
199  		NULL);			// AppNotifyCallbackCtx
200  	if(crtn) {
201  		srPrintError("CSSM_ModuleLoad(AppleCL)", crtn);
202  		return 0;
203  	}
204  	crtn = CSSM_ModuleAttach (&gGuidAppleX509CL,
205  		&vers,
206  		&memFuncs,				// memFuncs
207  		0,						// SubserviceID
208  		CSSM_SERVICE_CL,		// SubserviceFlags - Where is this used?
209  		0,						// AttachFlags
210  		CSSM_KEY_HIERARCHY_NONE,
211  		NULL,					// FunctionTable
212  		0,						// NumFuncTable
213  		NULL,					// reserved
214  		&clHand);
215  	if(crtn) {
216  		srPrintError("CSSM_ModuleAttach(AppleCL)", crtn);
217  		return 0;
218  	}
219  	else {
220  		return clHand;
221  	}
222  }
223  
224  CSSM_TP_HANDLE srTpStartup()
225  {
226  	CSSM_TP_HANDLE tpHand;
227  	CSSM_RETURN crtn;
228  
229  	if(srCssmStartup() == CSSM_FALSE) {
230  		return 0;
231  	}
232  	crtn = CSSM_ModuleLoad(&gGuidAppleX509TP,
233  		CSSM_KEY_HIERARCHY_NONE,
234  		NULL,			// eventHandler
235  		NULL);			// AppNotifyCallbackCtx
236  	if(crtn) {
237  		srPrintError("CSSM_ModuleLoad(AppleTP)", crtn);
238  		return 0;
239  	}
240  	crtn = CSSM_ModuleAttach (&gGuidAppleX509TP,
241  		&vers,
242  		&memFuncs,				// memFuncs
243  		0,						// SubserviceID
244  		CSSM_SERVICE_TP,		// SubserviceFlags
245  		0,						// AttachFlags
246  		CSSM_KEY_HIERARCHY_NONE,
247  		NULL,					// FunctionTable
248  		0,						// NumFuncTable
249  		NULL,					// reserved
250  		&tpHand);
251  	if(crtn) {
252  		srPrintError("CSSM_ModuleAttach(AppleTP)", crtn);
253  		return 0;
254  	}
255  	else {
256  		return tpHand;
257  	}
258  }
259  
260  /*
261   * Given a context specified via a CSSM_CC_HANDLE, add a new
262   * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
263   * AttributeLength, and an untyped pointer.
264   */
265  static CSSM_RETURN srAddContextAttribute(CSSM_CC_HANDLE CCHandle,
266  	uint32 AttributeType,
267  	uint32 AttributeLength,
268  	const void *AttributePtr)
269  {
270  	CSSM_CONTEXT_ATTRIBUTE		newAttr;
271  	CSSM_RETURN					crtn;
272  
273  	newAttr.AttributeType     = AttributeType;
274  	newAttr.AttributeLength   = AttributeLength;
275  	newAttr.Attribute.Data    = (CSSM_DATA_PTR)AttributePtr;
276  	crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
277  	if(crtn) {
278  		srPrintError("CSSM_UpdateContextAttributes", crtn);
279  	}
280  	return crtn;
281  }
282  
283  
284  /*
285   * Derive symmetric key.
286   * Note in the X CSP, we never return an IV.
287   */
288  CSSM_RETURN srCspDeriveKey(CSSM_CSP_HANDLE cspHand,
289  		uint32				keyAlg,			// CSSM_ALGID_RC5, etc.
290  		const char 			*keyLabel,
291  		unsigned 			keyLabelLen,
292  		uint32 				keyUsage,		// CSSM_KEYUSE_ENCRYPT, etc.
293  		uint32 				keySizeInBits,
294  		CSSM_DATA_PTR		password,		// in PKCS-5 lingo
295  		CSSM_DATA_PTR		salt,			// ditto
296  		uint32				iterationCnt,	// ditto
297  		CSSM_KEY_PTR		key)
298  {
299  	CSSM_RETURN					crtn;
300  	CSSM_CC_HANDLE 				ccHand;
301  	uint32						keyAttr;
302  	CSSM_DATA					dummyLabel;
303  	CSSM_PKCS5_PBKDF2_PARAMS 	pbeParams;
304  	CSSM_DATA					pbeData;
305  	CSSM_ACCESS_CREDENTIALS		creds;
306  
307  	memset(key, 0, sizeof(CSSM_KEY));
308  	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
309  	crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
310  		CSSM_ALGID_PKCS5_PBKDF2,
311  		keyAlg,
312  		keySizeInBits,
313  		&creds,
314  		NULL,			// BaseKey
315  		iterationCnt,
316  		salt,
317  		NULL,			// seed
318  		&ccHand);
319  	if(crtn) {
320  		srPrintError("CSSM_CSP_CreateDeriveKeyContext", crtn);
321  		return crtn;
322  	}
323  	keyAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF |
324  			  CSSM_KEYATTR_SENSITIVE;
325  	dummyLabel.Length = keyLabelLen;
326  	dummyLabel.Data = (uint8 *)keyLabel;
327  
328  	/* passing in password is pretty strange....*/
329  	pbeParams.Passphrase = *password;
330  	pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
331  	pbeData.Data = (uint8 *)&pbeParams;
332  	pbeData.Length = sizeof(pbeParams);
333  	crtn = CSSM_DeriveKey(ccHand,
334  		&pbeData,
335  		keyUsage,
336  		keyAttr,
337  		&dummyLabel,
338  		NULL,			// cred and acl
339  		key);
340  	if(crtn) {
341  		srPrintError("CSSM_DeriveKey", crtn);
342  		return crtn;
343  	}
344  	crtn = CSSM_DeleteContext(ccHand);
345  	if(crtn) {
346  		srPrintError("CSSM_DeleteContext", crtn);
347  	}
348  	return crtn;
349  }
350  
351  /*
352   * Generate key pair of arbitrary algorithm.
353   */
354  
355  /* CSP DL currently does not perform DSA generate params; let CSP do it implicitly */
356  #define DO_DSA_GEN_PARAMS		0
357  
358  CSSM_RETURN srCspGenKeyPair(CSSM_CSP_HANDLE cspHand,
359  	CSSM_DL_DB_HANDLE *dlDbHand,	// optional
360  	uint32 algorithm,
361  	const char *keyLabel,
362  	unsigned keyLabelLen,
363  	uint32 keySize,					// in bits
364  	CSSM_KEY_PTR pubKey,			// mallocd by caller
365  	CSSM_KEYUSE pubKeyUsage,		// CSSM_KEYUSE_ENCRYPT, etc.
366  	CSSM_KEYATTR_FLAGS pubAttrs,	// CSSM_KEYATTR_EXTRACTABLE, etc.
367  	CSSM_KEY_PTR privKey,			// mallocd by caller
368  	CSSM_KEYUSE privKeyUsage,		// CSSM_KEYUSE_DECRYPT, etc.
369  	CSSM_KEYATTR_FLAGS privAttrs)	// CSSM_KEYATTR_EXTRACTABLE, etc.
370  {
371  	CSSM_RETURN				crtn;
372  	CSSM_RETURN				ocrtn;
373  	CSSM_CC_HANDLE 			ccHand;
374  	CSSM_DATA				keyLabelData;
375  
376  	keyLabelData.Data        = (uint8 *)keyLabel;
377  	keyLabelData.Length      = keyLabelLen;
378  	memset(pubKey, 0, sizeof(CSSM_KEY));
379  	memset(privKey, 0, sizeof(CSSM_KEY));
380  
381  	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
382  		algorithm,
383  		keySize,
384  		NULL,					// Seed
385  		NULL,					// Salt
386  		NULL,					// StartDate
387  		NULL,					// EndDate
388  		NULL,					// Params
389  		&ccHand);
390  	if(crtn) {
391  		srPrintError("CSSM_CSP_CreateKeyGenContext", crtn);
392  		return crtn;
393  	}
394  
395  	/* post-context-create algorithm-specific stuff */
396  	switch(algorithm) {
397  		#if DO_DSA_GEN_PARAMS
398  		case CSSM_ALGID_DSA:
399  			/*
400  			 * extra step - generate params - this just adds some
401  			 * info to the context
402  			 */
403  			{
404  				CSSM_DATA dummy = {0, NULL};
405  				crtn = CSSM_GenerateAlgorithmParams(ccHand,
406  					keySize, &dummy);
407  				if(crtn) {
408  					srPrintError("CSSM_GenerateAlgorithmParams", crtn);
409  					CSSM_DeleteContext(ccHand);
410  					return crtn;
411  				}
412  				srAppFree(dummy.Data, NULL);
413  			}
414  			break;
415  		#endif	/* DO_DSA_GEN_PARAMS */
416  		default:
417  			break;
418  	}
419  
420  	/* optionally specify DL/DB storage location */
421  	if(dlDbHand) {
422  		crtn = srAddContextAttribute(ccHand,
423  			CSSM_ATTRIBUTE_DL_DB_HANDLE,
424  			sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE),
425  			dlDbHand);
426  		if(crtn) {
427  			CSSM_DeleteContext(ccHand);
428  			return crtn;
429  		}
430  	}
431  	ocrtn = CSSM_GenerateKeyPair(ccHand,
432  		pubKeyUsage,
433  		pubAttrs,
434  		&keyLabelData,
435  		pubKey,
436  		privKeyUsage,
437  		privAttrs,
438  		&keyLabelData,			// same labels
439  		NULL,					// CredAndAclEntry
440  		privKey);
441  	if(ocrtn) {
442  		srPrintError("CSSM_GenerateKeyPair", ocrtn);
443  	}
444  	crtn = CSSM_DeleteContext(ccHand);
445  	if(crtn) {
446  		srPrintError("CSSM_DeleteContext", crtn);
447  		if(ocrtn == CSSM_OK) {
448  			/* error on CSSM_GenerateKeyPair takes precedence */
449  			ocrtn = crtn;
450  		}
451  	}
452  	return ocrtn;
453  }
454  
455  
456  /*
457   * Add a certificate to an open Keychain.
458   */
459  CSSM_RETURN srAddCertToKC(
460  	SecKeychainRef		keychain,
461  	const CSSM_DATA		*cert,
462  	CSSM_CERT_TYPE		certType,
463  	CSSM_CERT_ENCODING	certEncoding,
464  	const char			*printName,		// C string
465  	const CSSM_DATA		*keyLabel)		// ??
466  {
467  	SecCertificateRef certificate;
468  
469  	OSStatus rslt = SecCertificateCreateFromData(cert, certType, certEncoding, &certificate);
470  	if (!rslt)
471  	{
472  		rslt = SecCertificateAddToKeychain(certificate, keychain);
473  		CFRelease(certificate);
474  	}
475  
476  	return rslt;
477  }
478  
479  /*
480   * Convert a CSSM_DATA_PTR, referring to a DER-encoded int, to an
481   * unsigned.
482   */
483  unsigned srDER_ToInt(const CSSM_DATA *DER_Data)
484  {
485  	uint32		rtn = 0;
486  	unsigned	i = 0;
487  
488  	while(i < DER_Data->Length) {
489  		rtn |= DER_Data->Data[i];
490  		if(++i == DER_Data->Length) {
491  			break;
492  		}
493  		rtn <<= 8;
494  	}
495  	return rtn;
496  }
497  
498  /*
499   * Log CSSM error.
500   */
501  void srPrintError(const char *op, CSSM_RETURN err)
502  {
503  	cssmPerror(op, err);
504  }
505  
506  /*
507   * Convert a CFString into a C string as safely as we can. Caller must
508   * free the result.
509   */
510  char *srCfStrToCString(
511  	CFStringRef cfStr)
512  {
513  	CFIndex len = CFStringGetLength(cfStr) + 1;
514  	char *cstr = (char *)malloc(len);
515  	if(cstr == NULL) {
516  		return NULL;
517  	}
518  	if(!CFStringGetCString(cfStr, cstr, len, kCFStringEncodingASCII)) {
519  		printf("***CFStringGetCString error\n");
520  		free(cstr);
521  		return NULL;
522  	}
523  	return cstr;
524  }
525