2 * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 * SecImportExportUtils.cpp - misc. utilities for import/export module
26 #include "SecImportExportUtils.h"
27 #include "SecImportExportAgg.h"
28 #include "SecImportExportCrypto.h"
29 #include "SecIdentityPriv.h"
31 #include <security_cdsa_utils/cuCdsaUtils.h>
32 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
34 #pragma mark --- Debug support ---
38 const char *impExpExtFormatStr(
39 SecExternalFormat format
)
42 case kSecFormatUnknown
: return "kSecFormatUnknown";
43 case kSecFormatOpenSSL
: return "kSecFormatOpenSSL";
44 case kSecFormatSSH
: return "kSecFormatSSH";
45 case kSecFormatBSAFE
: return "kSecFormatBSAFE";
46 case kSecFormatRawKey
: return "kSecFormatRawKey";
47 case kSecFormatWrappedPKCS8
: return "kSecFormatWrappedPKCS8";
48 case kSecFormatWrappedOpenSSL
: return "kSecFormatWrappedOpenSSL";
49 case kSecFormatWrappedSSH
: return "kSecFormatWrappedSSH";
50 case kSecFormatWrappedLSH
: return "kSecFormatWrappedLSH";
51 case kSecFormatX509Cert
: return "kSecFormatX509Cert";
52 case kSecFormatPEMSequence
: return "kSecFormatPEMSequence";
53 case kSecFormatPKCS7
: return "kSecFormatPKCS7";
54 case kSecFormatPKCS12
: return "kSecFormatPKCS12";
55 case kSecFormatNetscapeCertSequence
: return "kSecFormatNetscapeCertSequence";
56 default: return "UNKNOWN FORMAT ENUM";
60 const char *impExpExtItemTypeStr(
61 SecExternalItemType itemType
)
64 case kSecItemTypeUnknown
: return "kSecItemTypeUnknown";
65 case kSecItemTypePrivateKey
: return "kSecItemTypePrivateKey";
66 case kSecItemTypePublicKey
: return "kSecItemTypePublicKey";
67 case kSecItemTypeSessionKey
: return "kSecItemTypeSessionKey";
68 case kSecItemTypeCertificate
: return "kSecItemTypeCertificate";
69 case kSecItemTypeAggregate
: return "kSecItemTypeAggregate";
70 default: return "UNKNOWN ITEM TYPE ENUM";
76 * Parse file extension and attempt to map it to format and type. Returns true
79 bool impExpImportParseFileExten(
81 SecExternalFormat
*inputFormat
, // RETURNED
82 SecExternalItemType
*itemType
) // RETURNED
85 /* nothing to work with */
88 if(CFStringHasSuffix(fstr
, CFSTR(".cer")) ||
89 CFStringHasSuffix(fstr
, CFSTR(".crt"))) {
90 *inputFormat
= kSecFormatX509Cert
;
91 *itemType
= kSecItemTypeCertificate
;
92 SecImpInferDbg("Inferring kSecFormatX509Cert from file name");
95 if(CFStringHasSuffix(fstr
, CFSTR(".p12")) ||
96 CFStringHasSuffix(fstr
, CFSTR(".pfx"))) {
97 *inputFormat
= kSecFormatPKCS12
;
98 *itemType
= kSecItemTypeAggregate
;
99 SecImpInferDbg("Inferring kSecFormatPKCS12 from file name");
103 /* Get extension, look for key indicators as substrings */
104 CFURLRef url
= CFURLCreateWithString(NULL
, fstr
, NULL
);
106 SecImpInferDbg("impExpImportParseFileExten: error creating URL");
109 CFStringRef exten
= CFURLCopyPathExtension(url
);
112 /* no extension, app probably passed in only an extension */
118 cfr
= CFStringFind(exten
, CFSTR("p7"), kCFCompareCaseInsensitive
);
119 if(cfr
.length
!= 0) {
120 *inputFormat
= kSecFormatPKCS7
;
121 *itemType
= kSecItemTypeAggregate
;
122 SecImpInferDbg("Inferring kSecFormatPKCS7 from file name");
126 cfr
= CFStringFind(exten
, CFSTR("p8"), kCFCompareCaseInsensitive
);
127 if(cfr
.length
!= 0) {
128 *inputFormat
= kSecFormatWrappedPKCS8
;
129 *itemType
= kSecItemTypePrivateKey
;
130 SecImpInferDbg("Inferring kSecFormatPKCS8 from file name");
138 /* do a [NSString stringByDeletingPathExtension] equivalent */
139 CFStringRef
impExpImportDeleteExtension(
142 CFDataRef fileStrData
= CFStringCreateExternalRepresentation(NULL
, fileStr
,
143 kCFStringEncodingUTF8
, 0);
144 if(fileStrData
== NULL
) {
148 CFURLRef urlRef
= CFURLCreateFromFileSystemRepresentation(NULL
,
149 CFDataGetBytePtr(fileStrData
), CFDataGetLength(fileStrData
), false);
151 CFRelease(fileStrData
);
154 CFURLRef rtnUrl
= CFURLCreateCopyDeletingPathExtension(NULL
, urlRef
);
155 CFStringRef rtnStr
= NULL
;
158 rtnStr
= CFURLGetString(rtnUrl
);
162 CFRelease(fileStrData
);
166 #pragma mark --- mapping of external format to CDSA formats ---
169 * For the record, here is the mapping of SecExternalFormat, algorithm, and key
170 * class to CSSM-style key format (CSSM_KEYBLOB_FORMAT -
171 * CSSM_KEYBLOB_RAW_FORMAT_X509, etc). The entries in the table are the
172 * last component of a CSSM_KEYBLOB_FORMAT. Format kSecFormatUnknown means
173 * "default for specified class and algorithm", which is currently the
174 * same as kSecFormatOpenSSL.
178 * ---------------- ---------------- ----------------
179 * SecExternalFormat priv pub priv pub priv pub
180 * ----------------- ------- ------- ------- ------- ------- -------
181 * kSecFormatOpenSSL PKCS1 X509 OPENSSL X509 PKCS3 X509
182 * kSecFormatBSAFE PKCS8 PKCS1 FIPS186 FIPS186 PKCS8 not supported
183 * kSecFormatUnknown PKCS1 X509 OPENSSL X509 PKCS3 X509
184 * kSecFormatSSH SSH SSH n/s n/s n/s n/s
185 * kSecFormatSSHv2 n/s SSH2 n/s SSH2 n/s n/s
187 * The only external format supported for ECDSA and ECDH keys is kSecFormatOpenSSL,
188 * which translates to OPENSSL for private keys and X509 for public keys.
191 /* Arrays expressing the above table. */
193 /* l.s. dimension is pub/priv for one alg */
195 CSSM_KEYBLOB_FORMAT priv
;
196 CSSM_KEYBLOB_FORMAT pub
;
200 * indices into array of algForms defining all algs' formats for a given
203 #define SIE_ALG_RSA 0
204 #define SIE_ALG_DSA 1
206 #define SIE_ALG_ECDSA 3
207 #define SIE_ALG_LAST SIE_ALG_ECDSA
208 #define SIE_NUM_ALGS (SIE_ALG_LAST + 1)
210 /* kSecFormatOpenSSL */
211 static algForms opensslAlgForms
[SIE_NUM_ALGS
] =
213 { CSSM_KEYBLOB_RAW_FORMAT_PKCS1
, CSSM_KEYBLOB_RAW_FORMAT_X509
}, // RSA
214 { CSSM_KEYBLOB_RAW_FORMAT_OPENSSL
, CSSM_KEYBLOB_RAW_FORMAT_X509
}, // DSA
215 { CSSM_KEYBLOB_RAW_FORMAT_PKCS3
, CSSM_KEYBLOB_RAW_FORMAT_X509
}, // D-H
216 { CSSM_KEYBLOB_RAW_FORMAT_OPENSSL
, CSSM_KEYBLOB_RAW_FORMAT_X509
}, // ECDSA
219 /* kSecFormatBSAFE */
220 static algForms bsafeAlgForms
[SIE_NUM_ALGS
] =
222 { CSSM_KEYBLOB_RAW_FORMAT_PKCS8
, CSSM_KEYBLOB_RAW_FORMAT_PKCS1
}, // RSA
223 { CSSM_KEYBLOB_RAW_FORMAT_FIPS186
, CSSM_KEYBLOB_RAW_FORMAT_FIPS186
}, // DSA
224 { CSSM_KEYBLOB_RAW_FORMAT_PKCS8
, CSSM_KEYBLOB_RAW_FORMAT_NONE
}, // D-H
225 { CSSM_KEYBLOB_RAW_FORMAT_NONE
, CSSM_KEYBLOB_RAW_FORMAT_NONE
}, // ECDSA not supported
228 /* kSecFormatSSH (v1) */
229 static algForms ssh1AlgForms
[SIE_NUM_ALGS
] =
231 { CSSM_KEYBLOB_RAW_FORMAT_OPENSSH
, CSSM_KEYBLOB_RAW_FORMAT_OPENSSH
}, // RSA only
232 { CSSM_KEYBLOB_RAW_FORMAT_NONE
, CSSM_KEYBLOB_RAW_FORMAT_NONE
}, // DSA not supported
233 { CSSM_KEYBLOB_RAW_FORMAT_NONE
, CSSM_KEYBLOB_RAW_FORMAT_NONE
}, // D-H not supported
234 { CSSM_KEYBLOB_RAW_FORMAT_NONE
, CSSM_KEYBLOB_RAW_FORMAT_NONE
}, // ECDSA not supported
237 /* kSecFormatSSHv2 */
238 static algForms ssh2AlgForms
[SIE_NUM_ALGS
] =
240 { CSSM_KEYBLOB_RAW_FORMAT_NONE
, CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2
}, // RSA - public only
241 { CSSM_KEYBLOB_RAW_FORMAT_NONE
, CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2
}, // DSA - public only
242 { CSSM_KEYBLOB_RAW_FORMAT_NONE
, CSSM_KEYBLOB_RAW_FORMAT_NONE
}, // D-H not supported
243 { CSSM_KEYBLOB_RAW_FORMAT_NONE
, CSSM_KEYBLOB_RAW_FORMAT_NONE
}, // ECDSA not supported
247 * This routine performs a lookup into the above 3-dimensional array to
248 * map {algorithm, class, SecExternalFormat} to a CSSM_KEYBLOB_FORMAT.
249 * Returns errSecUnsupportedFormat in the rare appropriate case.
251 OSStatus
impExpKeyForm(
252 SecExternalFormat externForm
,
253 SecExternalItemType itemType
,
255 CSSM_KEYBLOB_FORMAT
*cssmForm
, // RETURNED
256 CSSM_KEYCLASS
*cssmClass
) // RETRUNED
258 if(itemType
== kSecItemTypeSessionKey
) {
259 /* special trivial case */
260 /* FIXME ensure caller hasn't specified bogus format */
261 *cssmForm
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
262 *cssmClass
= CSSM_KEYCLASS_SESSION_KEY
;
265 if(externForm
== kSecFormatUnknown
) {
266 /* default is openssl */
267 externForm
= kSecFormatOpenSSL
;
273 algDex
= SIE_ALG_RSA
;
276 algDex
= SIE_ALG_DSA
;
281 case CSSM_ALGID_ECDSA
:
282 algDex
= SIE_ALG_ECDSA
;
285 return CSSMERR_CSP_INVALID_ALGORITHM
;
287 const algForms
*forms
;
289 case kSecFormatOpenSSL
:
290 forms
= opensslAlgForms
;
292 case kSecFormatBSAFE
:
293 forms
= bsafeAlgForms
;
296 forms
= ssh1AlgForms
;
298 case kSecFormatSSHv2
:
299 forms
= ssh2AlgForms
;
302 return errSecUnsupportedFormat
;
304 CSSM_KEYBLOB_FORMAT form
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
306 case kSecItemTypePrivateKey
:
307 form
= forms
[algDex
].priv
;
308 *cssmClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
310 case kSecItemTypePublicKey
:
311 form
= forms
[algDex
].pub
;
312 *cssmClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
315 return errSecUnsupportedFormat
;
317 if(form
== CSSM_KEYBLOB_RAW_FORMAT_NONE
) {
318 /* not in the tables - abort */
319 return errSecUnsupportedFormat
;
328 * Given a raw key blob and zero to three known parameters (type, format,
329 * algorithm), figure out all parameters. Used for private and public keys.
331 static bool impExpGuessKeyParams(
333 SecExternalFormat
*externForm
, // IN/OUT
334 SecExternalItemType
*itemType
, // IN/OUT
335 CSSM_ALGORITHMS
*keyAlg
) // IN/OUT
337 /* CSSM alg list: RSA, DSA, DH, ECDSA */
338 CSSM_ALGORITHMS minAlg
= CSSM_ALGID_RSA
;
339 CSSM_ALGORITHMS maxAlg
= CSSM_ALGID_ECDSA
;
340 SecExternalFormat minForm
= kSecFormatOpenSSL
; // then SSH, BSAFE, then...
341 SecExternalFormat maxForm
= kSecFormatSSHv2
;
342 SecExternalItemType minType
= kSecItemTypePrivateKey
; // just two
343 SecExternalItemType maxType
= kSecItemTypePublicKey
;
345 switch(*externForm
) {
346 case kSecFormatUnknown
:
347 break; // run through all formats
348 case kSecFormatOpenSSL
:
350 case kSecFormatSSHv2
:
351 case kSecFormatBSAFE
:
352 minForm
= maxForm
= *externForm
; // just test this one
358 case kSecItemTypeUnknown
:
360 case kSecItemTypePrivateKey
:
361 case kSecItemTypePublicKey
:
362 minType
= maxType
= *itemType
;
368 case CSSM_ALGID_NONE
:
373 case CSSM_ALGID_ECDSA
:
374 minAlg
= maxAlg
= *keyAlg
;
380 CSSM_ALGORITHMS theAlg
;
381 SecExternalFormat theForm
;
382 SecExternalItemType theType
;
383 CSSM_CSP_HANDLE cspHand
= cuCspStartup(CSSM_TRUE
);
385 return CSSMERR_CSSM_ADDIN_LOAD_FAILED
;
389 * Iterate through all set of enabled {alg, type, format}.
390 * We do not assume that any of the enums are sequential hence this
391 * odd iteration algorithm....
394 for(theAlg
=minAlg
; ; ) {
395 for(theForm
=minForm
; ; ) {
396 for(theType
=minType
; ; ) {
398 /* do super lightweight null unwrap to parse */
399 OSStatus ortn
= impExpImportRawKey(keyData
,
400 theForm
, theType
, theAlg
,
404 NULL
, // no key params
405 NULL
, // no printName
406 NULL
); // no returned items
408 *externForm
= theForm
;
415 /* next type or break if we're done */
416 if(theType
== maxType
) {
419 else switch(theType
) {
420 case kSecItemTypePrivateKey
:
421 theType
= kSecItemTypePublicKey
;
428 } /* for each class/type */
430 /* next format or break if we're done */
431 if(theForm
== maxForm
) {
434 else switch(theForm
) {
435 case kSecFormatOpenSSL
:
436 theForm
= kSecFormatSSH
;
439 theForm
= kSecFormatBSAFE
;
441 case kSecFormatBSAFE
:
442 theForm
= kSecFormatSSHv2
;
449 } /* for each format */
451 /* next alg or break if we're done */
452 if(theAlg
== maxAlg
) {
455 else switch(theAlg
) {
457 theAlg
= CSSM_ALGID_DSA
;
460 theAlg
= CSSM_ALGID_DH
;
463 theAlg
= CSSM_ALGID_ECDSA
;
466 /* i.e. CSSM_ALGID_ECDSA, we already broke at theAlg == maxAlg */
473 cuCspDetachUnload(cspHand
, CSSM_TRUE
);
478 * Guess an incoming blob's type, format and (for keys only) algorithm
479 * by examining its contents. Returns true on success, in which case
480 * *inputFormat, *itemType, and *keyAlg are all valid. Caller optionally
481 * passes in valid values any number of these as a clue.
483 bool impExpImportGuessByExamination(
485 SecExternalFormat
*inputFormat
, // may be kSecFormatUnknown on entry
486 SecExternalItemType
*itemType
, // may be kSecItemTypeUnknown on entry
487 CSSM_ALGORITHMS
*keyAlg
) // CSSM_ALGID_NONE - unknown
489 if( ( (*inputFormat
== kSecFormatUnknown
) ||
490 (*inputFormat
== kSecFormatX509Cert
)
492 ( (*itemType
== kSecItemTypeUnknown
) ||
493 (*itemType
== kSecItemTypeCertificate
) ) ) {
495 * See if it parses as a cert
497 CSSM_CL_HANDLE clHand
= cuClStartup();
499 return CSSMERR_CSSM_ADDIN_LOAD_FAILED
;
501 CSSM_HANDLE cacheHand
;
503 CSSM_DATA cdata
= { CFDataGetLength(inData
),
504 (uint8
*)CFDataGetBytePtr(inData
) };
505 crtn
= CSSM_CL_CertCache(clHand
, &cdata
, &cacheHand
);
507 if(crtn
== CSSM_OK
) {
508 *inputFormat
= kSecFormatX509Cert
;
509 *itemType
= kSecItemTypeCertificate
;
510 SecImpInferDbg("Inferred kSecFormatX509Cert via CL");
511 CSSM_CL_CertAbortCache(clHand
, cacheHand
);
514 cuClDetachUnload(clHand
);
519 /* TBD: need way to inquire of P12 lib if this is a valid-looking PFX */
521 if( ( (*inputFormat
== kSecFormatUnknown
) ||
522 (*inputFormat
== kSecFormatNetscapeCertSequence
)
524 ( (*itemType
== kSecItemTypeUnknown
) ||
525 (*itemType
== kSecItemTypeAggregate
) ) ) {
526 /* See if it's a netscape cert sequence */
527 CSSM_RETURN crtn
= impExpNetscapeCertImport(inData
, 0, NULL
, NULL
, NULL
);
528 if(crtn
== CSSM_OK
) {
529 *inputFormat
= kSecFormatNetscapeCertSequence
;
530 *itemType
= kSecItemTypeAggregate
;
531 SecImpInferDbg("Inferred netscape-cert-sequence by decoding");
536 /* See if it's a key */
537 return impExpGuessKeyParams(inData
, inputFormat
, itemType
, keyAlg
);
540 #pragma mark --- Key Import support ---
543 * Given a context specified via a CSSM_CC_HANDLE, add a new
544 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
545 * AttributeLength, and an untyped pointer.
547 CSSM_RETURN
impExpAddContextAttribute(CSSM_CC_HANDLE CCHandle
,
548 uint32 AttributeType
,
549 uint32 AttributeLength
,
550 const void *AttributePtr
)
552 CSSM_CONTEXT_ATTRIBUTE newAttr
;
554 newAttr
.AttributeType
= AttributeType
;
555 newAttr
.AttributeLength
= AttributeLength
;
556 newAttr
.Attribute
.Data
= (CSSM_DATA_PTR
)AttributePtr
;
557 return CSSM_UpdateContextAttributes(CCHandle
, 1, &newAttr
);
561 * Free memory via specified plugin's app-level allocator
563 void impExpFreeCssmMemory(
567 CSSM_API_MEMORY_FUNCS memFuncs
;
568 CSSM_RETURN crtn
= CSSM_GetAPIMemoryFunctions(hand
, &memFuncs
);
572 memFuncs
.free_func(p
, memFuncs
.AllocRef
);
576 * Calculate digest of any CSSM_KEY. Unlike older implementations
577 * of this logic, you can actually calculate the public key hash
578 * on any class of key, any format, raw CSP or CSPDL (though if
579 * you're using the CSPDL, the key has to be a reference key
580 * in that CSPDL session).
582 * Caller must free keyDigest->Data using impExpFreeCssmMemory() since
583 * this is allocated by the CSP's app-specified allocator.
585 CSSM_RETURN
impExpKeyDigest(
586 CSSM_CSP_HANDLE cspHand
,
588 CSSM_DATA_PTR keyDigest
) // contents allocd and RETURNED
590 CSSM_DATA_PTR localDigest
;
591 CSSM_CC_HANDLE ccHand
;
593 CSSM_RETURN crtn
= CSSM_CSP_CreatePassThroughContext(cspHand
,
599 crtn
= CSSM_CSP_PassThrough(ccHand
,
600 CSSM_APPLECSP_KEYDIGEST
,
602 (void **)&localDigest
);
604 SecImpExpDbg("CSSM_CSP_PassThrough(KEY_DIGEST) failure");
608 * Give caller the Data referent and we'll free the
609 * CSSM_DATA struct itswelf.
611 *keyDigest
= *localDigest
;
612 impExpFreeCssmMemory(cspHand
, localDigest
);
614 CSSM_DeleteContext(ccHand
);
620 * Given a CFTypeRef passphrase which may be a CFDataRef or a CFStringRef,
621 * return a refcounted CFStringRef suitable for use with the PKCS12 library.
622 * PKCS12 passphrases in CFData format must be UTF8 encoded.
624 OSStatus
impExpPassphraseToCFString(
626 CFStringRef
*passout
) // may be the same as passin, but refcounted
628 if(CFGetTypeID(passin
) == CFStringGetTypeID()) {
629 CFStringRef passInStr
= (CFStringRef
)passin
;
631 *passout
= passInStr
;
634 else if(CFGetTypeID(passin
) == CFDataGetTypeID()) {
635 CFDataRef cfData
= (CFDataRef
)passin
;
636 CFIndex len
= CFDataGetLength(cfData
);
637 CFStringRef cfStr
= CFStringCreateWithBytes(NULL
,
638 CFDataGetBytePtr(cfData
), len
, kCFStringEncodingUTF8
, true);
640 SecImpExpDbg("Passphrase not in UTF8 format");
647 SecImpExpDbg("Passphrase not CFData or CFString");
653 * Given a CFTypeRef passphrase which may be a CFDataRef or a CFStringRef,
654 * return a refcounted CFDataRef whose bytes are suitable for use with
655 * PKCS5 (v1.5 and v2.0) key derivation.
657 OSStatus
impExpPassphraseToCFData(
659 CFDataRef
*passout
) // may be the same as passin, but refcounted
661 if(CFGetTypeID(passin
) == CFDataGetTypeID()) {
662 CFDataRef passInData
= (CFDataRef
)passin
;
663 CFRetain(passInData
);
664 *passout
= passInData
;
667 else if(CFGetTypeID(passin
) == CFStringGetTypeID()) {
668 CFStringRef passInStr
= (CFStringRef
)passin
;
670 outData
= CFStringCreateExternalRepresentation(NULL
,
672 kCFStringEncodingUTF8
,
673 0); // lossByte 0 ==> no loss allowed
674 if(outData
== NULL
) {
675 /* Well try with lossy conversion */
676 SecImpExpDbg("Trying lossy conversion of CFString passphrase to UTF8");
677 outData
= CFStringCreateExternalRepresentation(NULL
,
679 kCFStringEncodingUTF8
,
681 if(outData
== NULL
) {
682 SecImpExpDbg("Failure on conversion of CFString passphrase to UTF8");
683 /* what do we do now, Batman? */
691 SecImpExpDbg("Passphrase not CFData or CFString");
697 * Add a CFString to a crypto context handle.
699 static CSSM_RETURN
impExpAddStringAttr(
700 CSSM_CC_HANDLE ccHand
,
702 CSSM_ATTRIBUTE_TYPE attrType
)
704 /* CFStrings are passed as external rep in UTF8 encoding by convention */
706 outData
= CFStringCreateExternalRepresentation(NULL
,
707 str
, kCFStringEncodingUTF8
, 0); // lossByte 0 ==> no loss allowed
708 if(outData
== NULL
) {
709 SecImpExpDbg("impExpAddStringAttr: bad string format");
714 attrData
.Data
= (uint8
*)CFDataGetBytePtr(outData
);
715 attrData
.Length
= CFDataGetLength(outData
);
716 CSSM_RETURN crtn
= impExpAddContextAttribute(ccHand
, attrType
, sizeof(CSSM_DATA
),
720 SecImpExpDbg("impExpAddStringAttr: CSSM_UpdateContextAttributes error");
726 * Generate a secure passphrase key. Caller must eventually CSSM_FreeKey the result.
728 static CSSM_RETURN
impExpCreatePassKey(
729 const SecKeyImportExportParameters
*keyParams
, // required
730 CSSM_CSP_HANDLE cspHand
, // MUST be CSPDL
731 impExpVerifyPhrase verifyPhrase
, // for secure passphrase
732 CSSM_KEY_PTR
*passKey
) // mallocd and RETURNED
735 CSSM_CC_HANDLE ccHand
;
737 CSSM_DATA dummyLabel
;
738 CSSM_KEY_PTR ourKey
= NULL
;
740 SecImpExpDbg("Generating secure passphrase key");
741 ourKey
= (CSSM_KEY_PTR
)malloc(sizeof(CSSM_KEY
));
745 memset(ourKey
, 0, sizeof(CSSM_KEY
));
747 crtn
= CSSM_CSP_CreateKeyGenContext(cspHand
,
748 CSSM_ALGID_SECURE_PASSPHRASE
,
749 4, // keySizeInBits must be non zero
757 SecImpExpDbg("impExpCreatePassKey: CSSM_CSP_CreateKeyGenContext error");
760 /* subsequent errors to errOut: */
762 /* additional context attributes specific to this type of key gen */
763 assert(keyParams
!= NULL
); // or we wouldn't be here
764 if(keyParams
->alertTitle
!= NULL
) {
765 crtn
= impExpAddStringAttr(ccHand
, keyParams
->alertTitle
,
766 CSSM_ATTRIBUTE_ALERT_TITLE
);
771 if(keyParams
->alertPrompt
!= NULL
) {
772 crtn
= impExpAddStringAttr(ccHand
, keyParams
->alertPrompt
,
773 CSSM_ATTRIBUTE_PROMPT
);
778 verifyAttr
= (verifyPhrase
== VP_Export
) ? 1 : 0;
779 crtn
= impExpAddContextAttribute(ccHand
, CSSM_ATTRIBUTE_VERIFY_PASSPHRASE
,
780 sizeof(uint32
), (const void *)verifyAttr
);
782 SecImpExpDbg("impExpCreatePassKey: CSSM_UpdateContextAttributes error");
786 dummyLabel
.Data
= (uint8
*)"Secure Passphrase";
787 dummyLabel
.Length
= strlen((char *)dummyLabel
.Data
);
789 crtn
= CSSM_GenerateKey(ccHand
,
791 CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_SENSITIVE
,
796 SecImpExpDbg("impExpCreatePassKey: CSSM_GenerateKey error");
799 CSSM_DeleteContext(ccHand
);
800 if(crtn
== CSSM_OK
) {
803 else if(ourKey
!= NULL
) {
810 * Obtain passphrase, given a SecKeyImportExportParameters.
812 * Passphrase comes from one of two places: app-specified, in
813 * SecKeyImportExportParameters.passphrase (either as CFStringRef
814 * or CFDataRef); or via the secure passphrase mechanism.
816 * Passphrase is returned in AT MOST one of two forms:
818 * -- Secure passphrase is returned as a CSSM_KEY_PTR, which the
819 * caller must CSSM_FreeKey later as well as free()ing the actual
821 * -- CFTypeRef for app-supplied passphrases. This can be one of
824 * -- CFStringRef, for use with P12
825 * -- CFDataRef, for more general use (e.g. for PKCS5).
827 * In either case the caller must CFRelease the result.
829 OSStatus
impExpPassphraseCommon(
830 const SecKeyImportExportParameters
*keyParams
,
831 CSSM_CSP_HANDLE cspHand
, // MUST be CSPDL, for passKey generation
832 impExpPassphraseForm phraseForm
,
833 impExpVerifyPhrase verifyPhrase
, // for secure passphrase
834 CFTypeRef
*phrase
, // RETURNED, or
835 CSSM_KEY_PTR
*passKey
) // mallocd and RETURNED
837 assert(keyParams
!= NULL
);
839 /* Give precedence to secure passphrase */
840 if(keyParams
->flags
& kSecKeySecurePassphrase
) {
841 assert(passKey
!= NULL
);
842 return impExpCreatePassKey(keyParams
, cspHand
, verifyPhrase
, passKey
);
844 else if(keyParams
->passphrase
!= NULL
) {
847 assert(phrase
!= NULL
);
850 ortn
= impExpPassphraseToCFString(keyParams
->passphrase
,
851 (CFStringRef
*)&phraseOut
);
854 ortn
= impExpPassphraseToCFData(keyParams
->passphrase
,
855 (CFDataRef
*)&phraseOut
);
858 /* only called internally */
868 return errSecPassphraseRequired
;
872 CSSM_KEYATTR_FLAGS
ConvertArrayToKeyAttributes(SecKeyRef aKey
, CFArrayRef usage
)
874 CSSM_KEYATTR_FLAGS result
= CSSM_KEYATTR_RETURN_DEFAULT
;
879 OSStatus err
= noErr
;
881 const CSSM_KEY
* cssmKey
= NULL
;
882 err
= SecKeyGetCSSMKey(aKey
, &cssmKey
);
888 result
= cssmKey
->KeyHeader
.KeyAttr
;
892 CFTypeRef item
= NULL
;
893 CFIndex numItems
= CFArrayGetCount(usage
);
894 for (CFIndex iCnt
= 0L; iCnt
< numItems
; iCnt
++)
896 item
= (CFTypeRef
)CFArrayGetValueAtIndex(usage
, iCnt
);
897 if (CFEqual(item
, kSecAttrIsPermanent
))
899 result
|= CSSM_KEYATTR_PERMANENT
;
902 Currently the kSecAttrIsModifiable is private. Does this need to be
904 else if (CFEqual(item, kSecAttrIsModifiable))
906 result |= CSSM_KEYATTR_MODIFIABLE;
916 Boolean
ConvertSecKeyImportExportParametersToSecImportExportKeyParameters(SecKeyRef aKey
,
917 const SecItemImportExportKeyParameters
* newPtr
, SecKeyImportExportParameters
* oldPtr
)
919 Boolean result
= false;
921 if (NULL
!= oldPtr
&& NULL
!= newPtr
)
923 oldPtr
->version
= newPtr
->version
;
924 oldPtr
->flags
= newPtr
->flags
;
925 oldPtr
->passphrase
= newPtr
->passphrase
;
926 oldPtr
->alertTitle
= newPtr
->alertTitle
;
927 oldPtr
->alertPrompt
= newPtr
->alertPrompt
;
928 oldPtr
->accessRef
= newPtr
->accessRef
;
929 oldPtr
->keyUsage
= ConvertArrayToKeyUsage(newPtr
->keyUsage
);
930 oldPtr
->keyAttributes
= ConvertArrayToKeyAttributes(aKey
, newPtr
->keyAttributes
);