4 Description: certificate manipulation tool
8 Copyright: © Copyright 2002 Apple Computer, Inc. All rights reserved.
10 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
11 Computer, Inc. ("Apple") in consideration of your agreement to
12 the following terms, and your use, installation, modification
13 or redistribution of this Apple software constitutes acceptance
14 of these terms. If you do not agree with these terms, please
15 do not use, install, modify or redistribute this Apple software.
17 In consideration of your agreement to abide by the following
18 terms, and subject to these terms, Apple grants you a personal,
19 non-exclusive license, under Apple's copyrights in this
20 original Apple software (the "Apple Software"), to use,
21 reproduce, modify and redistribute the Apple Software, with
22 or without modifications, in source and/or binary forms;
23 provided that if you redistribute the Apple Software in
24 its entirety and without modifications, you must retain
25 this notice and the following text and disclaimers in all
26 such redistributions of the Apple Software. Neither the
27 name, trademarks, service marks or logos of Apple Computer,
28 Inc. may be used to endorse or promote products derived from the
29 Apple Software without specific prior written permission from
30 Apple. Except as expressly stated in this notice, no other
31 rights or licenses, express or implied, are granted by Apple
32 herein, including but not limited to any patent rights that
33 may be infringed by your derivative works or by other works
34 in which the Apple Software may be incorporated.
36 The Apple Software is provided by Apple on an "AS IS" basis.
37 APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
38 WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
39 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
40 REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE
41 OR IN COMBINATION WITH YOUR PRODUCTS.
43 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT,
44 INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
45 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
48 AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
49 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING
50 NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE
51 HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 #include <Security/SecKeychainItem.h>
55 #include <Security/SecKeychain.h>
56 #include <Security/SecKey.h>
57 #include <Security/SecAccess.h>
58 #include <Security/SecACL.h>
59 #include <Security/certextensions.h>
60 #include <Security/cssmapple.h>
61 #include <Security/oidsattr.h>
62 #include <Security/oidscert.h>
63 #include <Security/oidsalg.h>
68 #include <sys/param.h>
69 #include <cdsaUtils/cdsaUtils.h>
70 #include <cdsaUtils/printCert.h>
71 #include <cdsaUtils/fileIo.h>
72 #include <cdsaUtils/pem.h>
73 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
75 #include <CoreFoundation/CoreFoundation.h>
76 #include <Security/utilities.h>
77 #include <Security/aclclient.h>
79 /* will change soon */
80 #include <Security/SecCertificate.h>
86 /* SecKeychainGetCSPHandle implemented? */
87 #define SEC_KEYCHAIN_GET_CSP 0
89 /* SecCertificateAddToKeychain fully functional? */
90 #define SEC_CERT_ADD_TO_KC 1
92 /* SecKeyCreatePair() implemented */
93 #define SEC_KEY_CREATE_PAIR 0
95 #if !SEC_KEY_CREATE_PAIR
96 /* munge Label attr if manually generating keys */
97 #define MUNGE_LABEL_ATTR 1
100 #define KC_DB_PATH "Library/Keychains" /* relative to home */
103 * defaults for undocumented 'Z' option
105 #define ZDEF_KEY_LABEL "testCert"
106 #define ZDEF_KEY_ALG CSSM_ALGID_RSA
107 #define ZDEF_KEY_SIZE 512
108 #define ZDEF_KEY_USAGE (kKeyUseSigning | kKeyUseEncrypting)
109 #define ZDEF_SIG_ALG CSSM_ALGID_SHA1WithRSA
110 #define ZDEF_SIG_OID CSSMOID_SHA1WithRSA
111 #define ZDEF_COMMON_NAME "10.0.61.5"
112 #define ZDEF_ORG_NAME "Apple Computer - DEBUG ONLY"
113 #define ZDEF_COUNTRY "US"
114 #define ZDEF_STATE "Washington"
115 #define ZDEF_CHALLENGE "someChallenge"
117 static void usage(char **argv
)
120 printf(" Create a keypair and cert: %s c [options]\n", argv
[0]);
121 printf(" Create a CSR: %s r outFileName [options]\n",
123 printf(" Verify a CSR: %s v infileName [options]\n", argv
[0]);
124 #if SEC_CERT_ADD_TO_KC
125 printf(" Import a certificate: %s i inFileName [options]\n", argv
[0]);
127 /* this one needs the printName */
128 printf(" Import a certificate: %s i inFileName printName [options]\n",
131 printf(" Display a certificate: %s d inFileName [options]\n", argv
[0]);
132 printf("Options:\n");
133 printf(" k=keychainName\n");
134 printf(" c(reate the keychain)\n");
135 printf(" v(erbose)\n");
136 printf(" d (CSR in DER format; default is PEM)\n");
141 #if SEC_KEY_CREATE_PAIR
142 /* #error Work needed to generate key pair using Keychain. */
146 * Workaround to manually generate a key pair and munge its DB attributes
147 * to include the hash of the public key in the private key's Label attr.
151 /* Convert a reference key to a raw key. */
152 static CSSM_RETURN
refKeyToRaw(
153 CSSM_CSP_HANDLE cspHand
,
154 const CSSM_KEY
*refKey
,
155 CSSM_KEY_PTR rawKey
) // RETURNED
157 CSSM_CC_HANDLE ccHand
;
159 CSSM_ACCESS_CREDENTIALS creds
;
161 memset(rawKey
, 0, sizeof(CSSM_KEY
));
162 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
163 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
166 &creds
, // passPhrase
167 NULL
, // wrapping key
169 CSSM_PADDING_NONE
, // Padding
173 showError(crtn
, "refKeyToRaw: context err");
176 crtn
= CSSM_WrapKey(ccHand
,
179 NULL
, // DescriptiveData
181 if(crtn
!= CSSM_OK
) {
182 showError(crtn
, "refKeyToRaw: CSSM_WrapKey");
185 CSSM_DeleteContext(ccHand
);
190 * Find private key by label, modify its Label attr to be the
191 * hash of the associated public key.
193 static CSSM_RETURN
setPubKeyHash(
194 CSSM_CSP_HANDLE cspHand
,
195 CSSM_DL_DB_HANDLE dlDbHand
,
196 const CSSM_KEY
*pubKey
, // to get hash
197 CSSM_KEY_PTR privKey
, // its record gets updated
198 const char *keyLabel
) // look up by this
201 CSSM_SELECTION_PREDICATE predicate
;
202 CSSM_DB_UNIQUE_RECORD_PTR record
= NULL
;
205 CSSM_HANDLE resultHand
;
207 labelData
.Data
= (uint8
*)keyLabel
;
208 labelData
.Length
= strlen(keyLabel
) + 1; // incl. NULL
209 query
.RecordType
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
210 query
.Conjunctive
= CSSM_DB_NONE
;
211 query
.NumSelectionPredicates
= 1;
212 predicate
.DbOperator
= CSSM_DB_EQUAL
;
214 predicate
.Attribute
.Info
.AttributeNameFormat
=
215 CSSM_DB_ATTRIBUTE_NAME_AS_STRING
;
216 predicate
.Attribute
.Info
.Label
.AttributeName
= "Label";
217 predicate
.Attribute
.Info
.AttributeFormat
= CSSM_DB_ATTRIBUTE_FORMAT_BLOB
;
218 /* hope this cast is OK */
219 predicate
.Attribute
.Value
= &labelData
;
220 query
.SelectionPredicate
= &predicate
;
222 query
.QueryLimits
.TimeLimit
= 0; // FIXME - meaningful?
223 query
.QueryLimits
.SizeLimit
= 1; // FIXME - meaningful?
224 query
.QueryFlags
= 0; // CSSM_QUERY_RETURN_DATA; // FIXME - used?
226 /* build Record attribute with one attr */
227 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs
;
228 CSSM_DB_ATTRIBUTE_DATA attr
;
229 attr
.Info
.AttributeNameFormat
= CSSM_DB_ATTRIBUTE_NAME_AS_STRING
;
230 attr
.Info
.Label
.AttributeName
= "Label";
231 attr
.Info
.AttributeFormat
= CSSM_DB_ATTRIBUTE_FORMAT_BLOB
;
233 recordAttrs
.DataRecordType
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
234 recordAttrs
.NumberOfAttributes
= 1;
235 recordAttrs
.AttributeData
= &attr
;
237 crtn
= CSSM_DL_DataGetFirst(dlDbHand
,
241 NULL
, // hopefully optional ...theData,
243 /* abort only on success */
244 if(crtn
!= CSSM_OK
) {
245 showError(crtn
, "CSSM_DL_DataGetFirst");
246 printf("***setPubKeyHash: can't find private key\n");
250 /* do NULL unwrap of public key for use with raw CSP */
252 crtn
= refKeyToRaw(cspHand
, pubKey
, &rawPubKey
);
254 printf("***Error converting public key to raw format\n");
258 /* connect to raw CSP */
259 CSSM_CSP_HANDLE rawCspHand
= cuCspStartup(CSSM_TRUE
);
260 if(rawCspHand
== 0) {
261 printf("***Error connecting to raw CSP; aborting.\n");
265 /* calculate hash of pub key */
266 CSSM_DATA_PTR keyDigest
= NULL
;
267 CSSM_CC_HANDLE ccHand
;
268 crtn
= CSSM_CSP_CreatePassThroughContext(rawCspHand
,
272 showError(crtn
, "CSSM_CSP_CreatePassThroughContext");
273 printf("***Error calculating public key hash. Aborting.\n");
276 crtn
= CSSM_CSP_PassThrough(ccHand
,
277 CSSM_APPLECSP_KEYDIGEST
,
279 (void **)&keyDigest
);
281 showError(crtn
, "CSSM_CSP_PassThrough(PUBKEYHASH)");
282 printf("***Error calculating public key hash. Aborting.\n");
285 CSSM_FreeKey(cspHand
, NULL
, &rawPubKey
, CSSM_FALSE
);
286 CSSM_DeleteContext(ccHand
);
287 CSSM_ModuleDetach(rawCspHand
);
290 * Replace Label attr data with hash.
291 * NOTE: the module which allocated this attribute data - a DL -
292 * was loaded and attached by the Sec layer, not by us. Thus
293 * we can't use the memory allocator functions *we* used when
294 * attaching to the CSPDL - we have to use the ones
295 * which the Sec layer registered with the DL.
297 CSSM_API_MEMORY_FUNCS memFuncs
;
298 crtn
= CSSM_GetAPIMemoryFunctions(dlDbHand
.DLHandle
, &memFuncs
);
300 showError(crtn
, "CSSM_GetAPIMemoryFunctions(DLHandle)");
301 /* oh well, leak and continue */
304 memFuncs
.free_func(attr
.Value
->Data
, memFuncs
.AllocRef
);
305 memFuncs
.free_func(attr
.Value
, memFuncs
.AllocRef
);
307 attr
.Value
= keyDigest
;
309 /* modify key attributes */
310 crtn
= CSSM_DL_DataModify(dlDbHand
,
311 CSSM_DL_DB_RECORD_PRIVATE_KEY
,
314 NULL
, // DataToBeModified
315 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
317 showError(crtn
, "CSSM_DL_DataModify(PUBKEYHASH)");
318 printf("***Error setting public key hash. Aborting.\n");
321 crtn
= CSSM_DL_DataAbortQuery(dlDbHand
, resultHand
);
323 showError(crtn
, "CSSM_DL_DataAbortQuery");
324 /* let's keep going in this case */
326 crtn
= CSSM_DL_FreeUniqueRecord(dlDbHand
, record
);
328 showError(crtn
, "CSSM_DL_FreeUniqueRecord");
329 /* let's keep going in this case */
334 cuAppFree(keyDigest
->Data
, NULL
);
337 #endif /* MUNGE_LABEL_ATTR */
339 /* Still on the !SEC_KEY_CREATE_PAIR workaround */
342 * Generate a key pair using the CSPDL.
344 static OSStatus
generateKeyPair(
345 CSSM_CSP_HANDLE cspHand
,
346 CSSM_DL_DB_HANDLE dlDbHand
,
347 CSSM_ALGORITHMS keyAlg
, // e.g., CSSM_ALGID_RSA
348 uint32 keySizeInBits
,
349 const char *keyLabel
, // C string
350 CU_KeyUsage keyUsage
, // CUK_Signing, etc.
352 const CSSM_KEY
**pubKeyPtr
, // mallocd, created, RETURNED
353 const CSSM_KEY
**privKeyPtr
) // mallocd, created, RETURNED
355 CSSM_KEY_PTR pubKey
= reinterpret_cast<CSSM_KEY_PTR
>(
356 APP_MALLOC(sizeof(CSSM_KEY
)));
357 CSSM_KEY_PTR privKey
= reinterpret_cast<CSSM_KEY_PTR
>(
358 APP_MALLOC(sizeof(CSSM_KEY
)));
359 if((pubKey
== NULL
) || (privKey
== NULL
)) {
364 CSSM_KEYUSE pubKeyUse
= 0;
365 CSSM_KEYUSE privKeyUse
= 0;
367 if(keyUsage
& kKeyUseSigning
) {
368 pubKeyUse
|= CSSM_KEYUSE_VERIFY
;
369 privKeyUse
|= CSSM_KEYUSE_SIGN
;
371 if(keyUsage
& kKeyUseEncrypting
) {
372 pubKeyUse
|= (CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_WRAP
);
373 privKeyUse
|= (CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_UNWRAP
);
376 crtn
= cuCspGenKeyPair(cspHand
,
380 strlen(keyLabel
) + 1,
384 CSSM_KEYATTR_EXTRACTABLE
| CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_PERMANENT
,
387 CSSM_KEYATTR_SENSITIVE
| CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_PERMANENT
);
394 printf("...%u bit key pair generated.\n",
395 (unsigned)keySizeInBits
);
399 /* bind private key to cert by public key hash */
400 crtn
= setPubKeyHash(cspHand
,
406 printf("***Error setting public key hash. Continuing at peril.\n");
408 #endif /* MUNGE_LABEL_ATTR */
411 *privKeyPtr
= privKey
;
414 #endif /* SEC_KEY_CREATE_PAIR */
416 static void verifyCsr(
417 CSSM_CL_HANDLE clHand
,
418 const char *fileName
,
421 unsigned char *csr
= NULL
;
424 unsigned char *der
= NULL
;
427 if(readFile(fileName
, &csr
, &csrLen
)) {
428 printf("***Error reading CSR from file %s. Aborting.\n",
433 int rtn
= pemDecode(csr
, csrLen
, &der
, &derLen
);
435 printf("***%s: Bad PEM formatting. Aborting.\n", fileName
);
439 csrData
.Length
= derLen
;
443 csrData
.Length
= csrLen
;
446 CSSM_RETURN crtn
= CSSM_CL_PassThrough(clHand
,
448 CSSM_APPLEX509CL_VERIFY_CSR
,
452 cuPrintError("Verify CSR", crtn
);
455 printf("...CSR verified successfully.\n");
465 static void displayCert(
466 const char *fileName
,
469 unsigned char *rawCert
= NULL
;
470 unsigned rawCertSize
;
471 unsigned char *derCert
= NULL
;
472 unsigned derCertSize
;
475 rtn
= readFile(fileName
, &rawCert
, &rawCertSize
);
477 printf("Error reading %s; aborting.\n", fileName
);
481 rtn
= pemDecode(rawCert
, rawCertSize
, &derCert
, &derCertSize
);
483 printf("***%s: Bad PEM formatting. Aborting.\n", fileName
);
486 printCert(derCert
, derCertSize
, CSSM_TRUE
);
490 printCert(rawCert
, rawCertSize
, CSSM_TRUE
);
494 static void importCert(
495 SecKeychainRef kcRef
, // if SEC_CERT_ADD_TO_KC
496 CSSM_DL_DB_HANDLE dlDbHand
, // otherwise
497 const char *fileName
,
499 /* cruft needed by cuAddCertToDb */
500 const char *printName
) // C string
502 unsigned char *cert
= NULL
;
505 unsigned char *der
= NULL
;
507 #if !SEC_CERT_ADD_TO_KC
508 CSSM_DATA pubKeyHash
= {3, (uint8
*)"foo"};
511 if(readFile(fileName
, &cert
, &certLen
)) {
512 printf("***Error reading certificate from file %s. Aborting.\n",
517 int rtn
= pemDecode(cert
, certLen
, &der
, &derLen
);
519 printf("***%s: Bad PEM formatting. Aborting.\n", fileName
);
523 certData
.Length
= derLen
;
526 certData
.Data
= cert
;
527 certData
.Length
= certLen
;
530 #if SEC_CERT_ADD_TO_KC
531 SecCertificateRef certRef
;
532 OSStatus ortn
= SecCertificateCreateFromData(
535 CSSM_CERT_ENCODING_DER
,
538 printf("***SecCertificateCreateFromData returned %d; aborting.\n",
542 ortn
= SecCertificateAddToKeychain(certRef
, kcRef
);
544 printf("***SecCertificateAddToKeychain returned %d; aborting.\n",
549 CSSM_RETURN crtn
= cuAddCertToDb(dlDbHand
,
552 CSSM_CERT_ENCODING_DER
,
553 printName
, // printName
556 printf("***Error adding cert to keychain. Aborting.\n");
559 #endif /* SEC_CERT_ADD_TO_KC */
561 printf("...certificate successfully imported.\n");
571 static OSStatus
createCertCsr(
572 CSSM_BOOL createCsr
, // true: CSR, false: Cert
573 CSSM_TP_HANDLE tpHand
, // eventually, a SecKeychainRef
574 CSSM_CL_HANDLE clHand
,
575 CSSM_CSP_HANDLE cspHand
,
576 const CSSM_KEY
*subjPubKey
,
577 const CSSM_KEY
*signerPrivKey
,
578 CSSM_ALGORITHMS sigAlg
,
579 const CSSM_OID
*sigOid
,
580 CU_KeyUsage keyUsage
, // kKeyUseSigning, etc.
582 * Issuer's RDN is obtained from the issuer cert, if present, or is
583 * assumed to be the same as the subject name (i.e., we're creating
584 * a self-signed root cert).
586 const CSSM_DATA
*issuerCert
,
587 CSSM_BOOL useAllDefaults
,
588 CSSM_DATA_PTR certData
) // mallocd and RETURNED
590 CE_DataAndType exts
[2];
591 CE_DataAndType
*extp
= exts
;
594 CSSM_DATA refId
; // mallocd by CSSM_TP_SubmitCredRequest
595 CSSM_APPLE_TP_CERT_REQUEST certReq
;
596 CSSM_TP_REQUEST_SET reqSet
;
598 CSSM_BOOL confirmRequired
;
599 CSSM_TP_RESULT_SET_PTR resultSet
;
600 CSSM_ENCODED_CERT
*encCert
;
601 CSSM_APPLE_TP_NAME_OID subjectNames
[MAX_NAMES
];
603 CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext
;
606 /* Note a lot of the CSSM_APPLE_TP_CERT_REQUEST fields are not
607 * used for the createCsr option, but we'll fill in as much as is practical
610 if(issuerCert
!= NULL
) {
611 printf("createCertCsr: issuerCert not implemented\n");
617 char challengeBuf
[400];
620 strcpy(challengeBuf
, ZDEF_CHALLENGE
);
624 getStringWithPrompt("Enter challenge string: ",
625 challengeBuf
, sizeof(challengeBuf
));
626 if(challengeBuf
[0] != '\0') {
631 certReq
.challengeString
= challengeBuf
;
635 certReq
.challengeString
= NULL
;
637 /* KeyUsage extension */
638 extp
->type
= DT_KeyUsage
;
639 extp
->critical
= CSSM_FALSE
;
640 extp
->extension
.keyUsage
= 0;
641 if(keyUsage
& kKeyUseSigning
) {
642 extp
->extension
.keyUsage
|=
643 (CE_KU_DigitalSignature
| CE_KU_KeyCertSign
);
645 if(keyUsage
& kKeyUseEncrypting
) {
646 extp
->extension
.keyUsage
|=
647 (CE_KU_KeyEncipherment
| CE_KU_DataEncipherment
);
652 /* BasicConstraints */
653 extp
->type
= DT_BasicConstraints
;
654 extp
->critical
= CSSM_TRUE
;
655 extp
->extension
.basicConstraints
.cA
= CSSM_TRUE
;
656 extp
->extension
.basicConstraints
.pathLenConstraintPresent
= CSSM_FALSE
;
661 /* name array, get from user. */
663 subjectNames
[0].string
= ZDEF_COMMON_NAME
;
664 subjectNames
[0].oid
= &CSSMOID_CommonName
;
665 subjectNames
[1].string
= ZDEF_ORG_NAME
;
666 subjectNames
[1].oid
= &CSSMOID_OrganizationName
;
667 subjectNames
[2].string
= ZDEF_COUNTRY
;
668 subjectNames
[2].oid
= &CSSMOID_CountryName
;
669 subjectNames
[3].string
= ZDEF_STATE
;
670 subjectNames
[3].oid
= &CSSMOID_StateProvinceName
;
674 getNameOids(subjectNames
, &numNames
);
678 certReq
.cspHand
= cspHand
;
679 certReq
.clHand
= clHand
;
680 certReq
.serialNumber
= 0x12345678; // TBD - random? From user?
681 certReq
.numSubjectNames
= numNames
;
682 certReq
.subjectNames
= subjectNames
;
684 /* TBD - if we're passed in a signing cert, certReq.issuerNameX509 will
685 * be obtained from that cert. For now we specify "self-signed" cert
686 * by not providing an issuer name at all. */
687 certReq
.numIssuerNames
= 0; // root for now
688 certReq
.issuerNames
= NULL
;
689 certReq
.issuerNameX509
= NULL
;
690 certReq
.certPublicKey
= subjPubKey
;
691 certReq
.issuerPrivateKey
= signerPrivKey
;
692 certReq
.signatureAlg
= sigAlg
;
693 certReq
.signatureOid
= *sigOid
;
694 certReq
.notBefore
= 0; // TBD - from user
695 certReq
.notAfter
= 60 * 60 * 24 * 30; // seconds from now
696 certReq
.numExtensions
= numExts
;
697 certReq
.extensions
= exts
;
699 reqSet
.NumberOfRequests
= 1;
700 reqSet
.Requests
= &certReq
;
702 /* a CSSM_TP_CALLERAUTH_CONTEXT to specify an OID */
703 memset(&CallerAuthContext
, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT
));
704 memset(&policyId
, 0, sizeof(CSSM_FIELD
));
706 policyId
.FieldOid
= CSSMOID_APPLE_TP_CSR_GEN
;
709 policyId
.FieldOid
= CSSMOID_APPLE_TP_LOCAL_CERT_GEN
;
711 CallerAuthContext
.Policy
.NumberOfPolicyIds
= 1;
712 CallerAuthContext
.Policy
.PolicyIds
= &policyId
;
713 CssmClient::AclFactory factory
;
714 CallerAuthContext
.CallerCredentials
= const_cast<Security::AccessCredentials
*>(factory
.promptCred());
716 CSSM_RETURN crtn
= CSSM_TP_SubmitCredRequest(tpHand
,
717 NULL
, // PreferredAuthority
718 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE
,
724 /* before proceeding, free resources allocated thus far */
725 if(!useAllDefaults
) {
726 freeNameOids(subjectNames
, numNames
);
730 cuPrintError("CSSM_TP_SubmitCredRequest", crtn
);
733 crtn
= CSSM_TP_RetrieveCredResult(tpHand
,
735 NULL
, // CallerAuthCredentials
740 cuPrintError("CSSM_TP_RetrieveCredResult", crtn
);
743 if(resultSet
== NULL
) {
744 printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n");
747 encCert
= (CSSM_ENCODED_CERT
*)resultSet
->Results
;
748 *certData
= encCert
->CertBlob
;
750 /* free resources allocated by TP */
751 APP_FREE(refId
.Data
);
766 int main(int argc
, char **argv
)
768 SecKeychainRef kcRef
= nil
;
769 char kcPath
[MAXPATHLEN
+ 1];
770 UInt32 kcPathLen
= MAXPATHLEN
+ 1;
771 CSSM_BOOL createKc
= CSSM_FALSE
;
773 CSSM_DL_DB_HANDLE dlDbHand
= {0, 0};
774 CSSM_CSP_HANDLE cspHand
= 0;
775 CSSM_TP_HANDLE tpHand
= 0;
776 CSSM_CL_HANDLE clHand
= 0;
777 const CSSM_KEY
*pubKey
;
778 const CSSM_KEY
*privKey
;
781 CSSM_BOOL verbose
= CSSM_FALSE
;
782 CSSM_ALGORITHMS keyAlg
;
783 CSSM_ALGORITHMS sigAlg
;
784 const CSSM_OID
*sigOid
;
785 CSSM_DATA certData
= {0, NULL
};
787 CU_KeyUsage keyUsage
= 0;
790 #if SEC_KEY_CREATE_PAIR
791 CSSM_KEYUSE pubKeyUse
= 0;
792 CSSM_KEYUSE privKeyUse
= 0;
793 CSSM_KEYATTR_FLAGS pubKeyAttrs
;
794 CSSM_KEYATTR_FLAGS privKeyAttrs
;
795 CFStringRef description
= NULL
;
796 SecAccessRef access
= NULL
;
797 CFArrayRef acls
= NULL
;
798 SecACLRef acl
= NULL
;
799 bool aclFound
= false;
800 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
=
802 CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION
, 0
804 SecKeyRef pubKeyRef
= 0, privKeyRef
= 0;
805 #elif !MUNGE_LABEL_ATTR
806 CSSM_DATA pubKeyHash
= {3, (uint8
*)"foo"};
808 CSSM_BOOL createCsr
= CSSM_FALSE
; // else create cert
811 /* command line arguments */
812 char *fileName
= NULL
;
813 CSSM_BOOL pemFormat
= CSSM_TRUE
;
814 char *certPrintName
= NULL
;
816 uint32 keySizeInBits
;
818 CSSM_BOOL useAllDefaults
= CSSM_FALSE
; // undoc'd cmd option
833 createCsr
= CSSM_TRUE
;
846 #if SEC_CERT_ADD_TO_KC
855 certPrintName
= argv
[3];
857 #endif /* SEC_CERT_ADD_TO_KC */
872 for(arg
=optArgs
; arg
<argc
; arg
++) {
882 pemFormat
= CSSM_FALSE
;
885 createKc
= CSSM_TRUE
;
888 /* undocumented "use all defaults quickly" option */
889 useAllDefaults
= CSSM_TRUE
;
895 if(op
== CO_DisplayCert
) {
897 displayCert(fileName
, pemFormat
);
901 clHand
= cuClStartup();
903 printf("Error connecting to CL. Aborting.\n");
907 /* that's all we need for verifying a CSR */
908 if(op
== CO_VerifyCSR
) {
909 verifyCsr(clHand
, fileName
, pemFormat
);
913 /* remaining ops need TP and CSP as well */
914 #if !SEC_KEYCHAIN_GET_CSP
915 /* get it from keychain */
916 cspHand
= cuCspStartup(CSSM_FALSE
);
918 printf("Error connecting to CSP/DL. Aborting.\n");
922 tpHand
= cuTpStartup();
924 printf("Error connecting to TP. Aborting.\n");
929 char *userHome
= getenv("HOME");
931 if(userHome
== NULL
) {
932 /* well, this is probably not going to work */
935 sprintf(kcPath
, "%s/%s/%s", userHome
, KC_DB_PATH
, kcName
);
939 /* use default keychain */
940 ortn
= SecKeychainCopyDefault(&kcRef
);
942 showError(ortn
, "SecKeychainCopyDefault");
945 ortn
= SecKeychainGetPath(kcRef
, &kcPathLen
, kcPath
);
947 showError(ortn
, "SecKeychainGetPath");
952 * OK, we have a path, we have to release the first KC ref,
953 * then get another one by opening it
958 ortn
= SecKeychainCreate(kcPath
,
962 nil
, // initialAccess
964 /* fixme - do we have to open it? */
966 showError(ortn
, "SecKeychainCreateNew");
967 printf("***Error creating keychain at %s; aborting.\n", kcPath
);
972 ortn
= SecKeychainOpen(kcPath
, &kcRef
);
974 showError(ortn
, "SecKeychainOpen");
975 printf("Cannot open keychain at %s. Aborting.\n", kcPath
);
980 /* get associated DL/DB handle */
981 ortn
= SecKeychainGetDLDBHandle(kcRef
, &dlDbHand
);
983 showError(ortn
, "SecKeychainGetDLDBHandle");
987 if(op
== CO_ImportCert
) {
988 importCert(kcRef
, dlDbHand
, fileName
, pemFormat
, certPrintName
);
992 #if SEC_KEYCHAIN_GET_CSP
993 /* create cert, CSR need CSP handle */
994 ortn
= SecKeychainGetCSPHandle(kcRef
, &cspHand
);
996 showError(ortn
, "SecKeychainGetCSPHandle");
1002 * TBD: eventually we want to present the option of using an existing
1003 * SecIdentityRef from the keychain as the signing cert/key. If none
1004 * found or the user says they want a root, we generate the signing key
1005 * pair as follows....
1010 * Generate a key pair. For now we do this via CDSA.
1013 if(useAllDefaults
) {
1014 strcpy(labelBuf
, ZDEF_KEY_LABEL
);
1018 getStringWithPrompt("Enter key and certificate label: ", labelBuf
,
1020 if(labelBuf
[0] != '\0') {
1025 keyLabel
.Data
= (uint8
*)labelBuf
;
1026 keyLabel
.Length
= strlen(labelBuf
);
1028 /* get key algorithm and size */
1029 if(useAllDefaults
) {
1030 keyAlg
= ZDEF_KEY_ALG
;
1031 keySizeInBits
= ZDEF_KEY_SIZE
;
1034 getKeyParams(keyAlg
, keySizeInBits
);
1037 /* get usage for keys and certs */
1038 if(useAllDefaults
) {
1039 keyUsage
= ZDEF_KEY_USAGE
;
1042 keyUsage
= getKeyUsage(isRoot
);
1045 printf("...Generating key pair...\n");
1046 #if SEC_KEY_CREATE_PAIR
1048 description
= CFStringCreateWithCString(NULL
, labelBuf
, kCFStringEncodingMacRoman
);
1049 ortn
= SecAccessCreate(description
, NULL
, &access
);
1051 printf("Error creating SecAccessRef; aborting.\n");
1054 ortn
= SecAccessCopyACLList(access
, &acls
);
1056 printf("Error calling SecAccessCopyACLList; aborting.\n");
1059 for (CFIndex ix
= 0; ix
< CFArrayGetCount(acls
); ++ix
)
1061 CSSM_ACL_AUTHORIZATION_TAG tags
[20];
1062 uint32 tagCount
= 20;
1064 acl
= (SecACLRef
)CFArrayGetValueAtIndex(acls
, ix
);
1065 ortn
= SecACLGetAuthorizations(acl
, tags
, &tagCount
);
1067 printf("Error calling SecACLGetAuthorizations; aborting.\n");
1071 for (uint32 tix
= 0; tix
< tagCount
; ++tix
)
1073 if (tags
[tix
] == CSSM_ACL_AUTHORIZATION_DECRYPT
1074 || tags
[tix
] == CSSM_ACL_AUTHORIZATION_ANY
)
1086 printf("Could not find ACL for decrypt right; aborting.\n");
1090 // Make the ACL an any allowed acl by setting the trusted application list to NULL
1091 ortn
= SecACLSetSimpleContents(acl
, NULL
, description
, &promptSelector
);
1093 printf("Error calling SecACLSetSimpleContents; aborting.\n");
1097 pubKeyAttrs
= CSSM_KEYATTR_EXTRACTABLE
| CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_PERMANENT
;
1098 privKeyAttrs
= CSSM_KEYATTR_SENSITIVE
| CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_PERMANENT
;
1100 if(keyUsage
& kKeyUseSigning
) {
1101 pubKeyUse
|= CSSM_KEYUSE_VERIFY
;
1102 privKeyUse
|= CSSM_KEYUSE_SIGN
;
1104 if(keyUsage
& kKeyUseEncrypting
) {
1105 pubKeyUse
|= (CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_WRAP
);
1106 privKeyUse
|= (CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_UNWRAP
);
1109 ortn
= SecKeyCreatePair(kcRef
, keyAlg
, keySizeInBits
, 0, pubKeyUse
, pubKeyAttrs
, privKeyUse
, privKeyAttrs
, access
, &pubKeyRef
, &privKeyRef
);
1112 ortn
= SecKeyGetCSSMKey(pubKeyRef
, &pubKey
);
1114 ortn
= SecKeyGetCSSMKey(privKeyRef
, &privKey
);
1116 ortn
= generateKeyPair(cspHand
,
1125 #endif /* SEC_KEY_CREATE_PAIR */
1127 printf("Error generating keys; aborting.\n");
1131 /* get signing algorithm per the signing key */
1132 if(useAllDefaults
) {
1133 sigAlg
= ZDEF_SIG_ALG
;
1134 sigOid
= &ZDEF_SIG_OID
;
1137 ortn
= getSigAlg(privKey
, sigAlg
, sigOid
);
1139 printf("Can not sign with this private key. Aborting.\n");
1145 printf("...creating CSR...\n");
1148 printf("...creating certificate...\n");
1150 /* generate the cert */
1151 ortn
= createCertCsr(createCsr
,
1160 NULL
, // issuer cert
1167 printCert(certData
.Data
, certData
.Length
, CSSM_FALSE
);
1168 printCertShutdown();
1172 /* just write this to a file */
1173 unsigned char *pem
= NULL
;
1178 rtn
= pemEncode(certData
.Data
, certData
.Length
, &pem
, &pemLen
,
1179 "CERTIFICATE REQUEST");
1181 /* very unlikely, I think malloc is the only failure */
1182 printf("***Error PEM-encoding CSR. Aborting.\n");
1185 rtn
= writeFile(fileName
, pem
, pemLen
);
1188 rtn
= writeFile(fileName
, certData
.Data
, certData
.Length
);
1191 printf("***Error writing CSR to %s\n", fileName
);
1194 printf("Wrote %u bytes of CSR to %s\n", (unsigned)certData
.Length
,
1202 /* store the cert in the same DL/DB as the key pair */
1203 #if SEC_CERT_ADD_TO_KC
1204 crtn
= cuAddCertToKC(kcRef
,
1207 CSSM_CERT_ENCODING_DER
,
1208 labelBuf
, // printName
1211 crtn
= cuAddCertToDb(dlDbHand
,
1214 CSSM_CERT_ENCODING_DER
,
1215 labelBuf
, // printName
1217 #endif /* SEC_CERT_ADD_TO_KC */
1218 if(crtn
== CSSM_OK
) {
1219 printf("..cert stored in Keychain.\n");
1224 #if SEC_KEY_CREATE_PAIR
1225 if (description
) CFRelease(description
);
1226 if (access
) CFRelease(access
);
1227 if (acls
) CFRelease(acls
);
1228 if (pubKeyRef
) CFRelease(pubKeyRef
);
1229 if (privKeyRef
) CFRelease(privKeyRef
);
1230 #endif /* SEC_KEY_CREATE_PAIR */