2 * Copyright (c) 2011-2012,2014 Apple 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@
26 #include "createFVMaster.h"
29 #include "security_tool.h"
38 #include <Security/SecKeychain.h>
39 #include <Security/SecCertificate.h>
40 #include <Security/SecKeychain.h>
41 #include <Security/oidsalg.h>
42 #include <Security/oidsattr.h>
45 #include "srCdsaUtils.h"
47 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
49 const char * const _masterKeychainName
= "FileVaultMaster.keychain";
50 const char * const _masterKeychainPath
= "./FileVaultMaster";
53 * Parameters used to create key pairs and certificates in
54 * SR_CertificateAndKeyCreate().
56 #define SR_KEY_ALGORITHM CSSM_ALGID_RSA
57 #define SR_KEY_SIZE_IN_BITS 1024
59 #define SR2_KEY_SIZE_IN_BITS 2048 // Recommended size for FileVault2 (FDE)
62 * The CSSM_ALGORITHMS and OID values defining the signature
63 * algorithm in the generated certificate.
65 #define SR_CERT_SIGNATURE_ALGORITHM CSSM_ALGID_SHA256WithRSA
66 #define SR_CERT_SIGNATURE_ALG_OID CSSMOID_SHA256WithRSA
68 OSStatus
makeMasterPassword(const char *fvmkcName
, const char *masterPasswordPassword
, uint32 keySizeInBits
, SecKeychainRef
*keychainRef
);
70 OSStatus
createPair(CFStringRef hostName
,CFStringRef userName
,SecKeychainRef keychainRef
, uint32 keySizeInBits
, CFDataRef
*cert
);
71 OSStatus
generateKeyPair(CSSM_CSP_HANDLE cspHand
, CSSM_DL_DB_HANDLE dlDbHand
, CSSM_ALGORITHMS keyAlg
,
72 uint32 keySizeInBits
, const char *keyLabel
, CSSM_KEY_PTR
*pubKeyPtr
, CSSM_KEY_PTR
*privKeyPtr
);
73 OSStatus
createRootCert(CSSM_TP_HANDLE tpHand
, CSSM_CL_HANDLE clHand
, CSSM_CSP_HANDLE cspHand
,
74 CSSM_KEY_PTR subjPubKey
, CSSM_KEY_PTR signerPrivKey
, const char *hostName
, const char *userName
,
75 CSSM_ALGORITHMS sigAlg
, const CSSM_OID
*sigOid
, CSSM_DATA_PTR certData
);
76 void randUint32(uint32
*u
);
78 static char *secCopyCString(CFStringRef theString
);
80 OSStatus
makeMasterPassword(const char *fvmkcName
, const char *masterPasswordPassword
, uint32 keySizeInBits
, SecKeychainRef
*keychainRef
)
83 OSStatus SecFileVaultMakeMasterPassword(CFStringRef masterPasswordPassword);
85 *** In the real code, this will be done directly rather than exec'ing a tool, since there are too many parameters to specify
86 *** this needs to be done as root, since the keychain will be a system keychain
87 /usr/bin/certtool y c k=/Library/Keychains/FileVaultMaster.keychain p=<masterPasswordPassword>
88 /usr/bin/certtool c k=/Library/Keychains/FileVaultMaster.keychain o=/Library/Keychains/FileVaultMaster.cer
89 Two steps: create the keychain, then create the keypair
92 SecAccessRef initialAccess
= NULL
;
94 if (!masterPasswordPassword
)
96 sec_error("You must supply a non-empty password");
100 // We return an error if the keychain already exists
101 OSStatus status
= SecKeychainCreate(fvmkcName
, (UInt32
) strlen(masterPasswordPassword
), masterPasswordPassword
, false, initialAccess
, keychainRef
);
104 if (status
==errSecDuplicateKeychain
|| status
==CSSMERR_DL_DATASTORE_ALREADY_EXISTS
)
105 sec_error("The keychain file %s already exists", fvmkcName
);
109 // Create the key pair
111 int rx
= gethostname(host
, sizeof(host
));
113 strcpy(host
, "localhost");
115 CFStringRef hostName
= CFSTR("FileVault Recovery Key"); // This is what shows up in Keychain Access display
116 CFStringRef userName
= CFStringCreateWithCString(kCFAllocatorDefault
, host
, kCFStringEncodingUTF8
);
117 CFDataRef certData
= NULL
;
118 printf("Generating a %d bit key pair; this may take several minutes\n", keySizeInBits
);
119 status
= createPair(hostName
,userName
,*keychainRef
,keySizeInBits
, &certData
);
121 sec_error("Error in createPair: %s", sec_errstr(status
));
128 OSStatus
createPair(CFStringRef hostName
,CFStringRef userName
,SecKeychainRef keychainRef
, uint32 keySizeInBits
, CFDataRef
*cert
)
130 SecCertificateRef certRef
= NULL
;
131 CSSM_DL_DB_HANDLE dlDbHand
= {0, 0};
132 CSSM_CSP_HANDLE cspHand
= 0;
133 CSSM_TP_HANDLE tpHand
= 0;
134 CSSM_CL_HANDLE clHand
= 0;
135 CSSM_KEY_PTR pubKey
= NULL
;
136 CSSM_KEY_PTR privKey
= NULL
;
137 CSSM_DATA certData
= {0, NULL
};
138 char *hostStr
= NULL
;
139 char *userStr
= NULL
;
141 CSSM_OID algOid
= SR_CERT_SIGNATURE_ALG_OID
;
143 hostStr
= secCopyCString(hostName
);
144 userStr
= secCopyCString(userName
);
145 if (!hostStr
|| !userStr
) // could not convert to UTF-8
151 // open keychain, connect to all the CDSA modules we'll need
153 ortn
= SecKeychainGetCSPHandle(keychainRef
, &cspHand
);
157 ortn
= SecKeychainGetDLDBHandle(keychainRef
, &dlDbHand
);
161 tpHand
= srTpStartup();
168 clHand
= srClStartup();
175 // generate key pair, private key stored in keychain
176 ortn
= generateKeyPair(cspHand
, dlDbHand
, SR_KEY_ALGORITHM
, keySizeInBits
,
177 "FileVault Master Password Key", &pubKey
, &privKey
);
182 ortn
= createRootCert(tpHand
,clHand
,cspHand
,pubKey
,privKey
,hostStr
,userStr
,
183 SR_CERT_SIGNATURE_ALGORITHM
,&algOid
,&certData
);
187 // store the cert in the same DL/DB as the key pair [see SecCertificateCreateFromData]
188 ortn
= SecCertificateCreateFromData(&certData
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, &certRef
);
192 ortn
= SecCertificateAddToKeychain(certRef
, keychainRef
);
196 // return the cert to caller
197 *cert
= CFDataCreate(NULL
, certData
.Data
, certData
.Length
);
210 CSSM_ModuleDetach(tpHand
);
212 CSSM_ModuleDetach(clHand
);
215 CSSM_FreeKey(cspHand
,
218 CSSM_FALSE
); // delete
223 CSSM_FreeKey(cspHand
,
226 CSSM_FALSE
); // delete
234 * Given a CFStringRef, this function allocates and returns a pointer
235 * to a null-terminated 'C' string copy. If conversion of the string
236 * to UTF8 fails for some reason, the function will return NULL.
238 * The caller must free this pointer
241 char *secCopyCString(CFStringRef theString
)
243 CFIndex maxLength
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(theString
), kCFStringEncodingUTF8
) + 1;
244 char* buffer
= (char*) malloc(maxLength
);
245 Boolean converted
= CFStringGetCString(theString
, buffer
, maxLength
, kCFStringEncodingUTF8
);
254 #pragma mark -------------------- SecFileVaultCert private implementation --------------------
256 OSStatus
createRootCert(
257 CSSM_TP_HANDLE tpHand
,
258 CSSM_CL_HANDLE clHand
,
259 CSSM_CSP_HANDLE cspHand
,
260 CSSM_KEY_PTR subjPubKey
,
261 CSSM_KEY_PTR signerPrivKey
,
262 const char *hostName
, // CSSMOID_CommonName
263 const char *userName
, // CSSMOID_Description
264 CSSM_ALGORITHMS sigAlg
,
265 const CSSM_OID
*sigOid
,
266 CSSM_DATA_PTR certData
) // mallocd and RETURNED
268 CE_DataAndType exts
[2];
269 CE_DataAndType
*extp
= exts
;
271 CSSM_DATA refId
; // mallocd by
272 // CSSM_TP_SubmitCredRequest
273 CSSM_APPLE_TP_CERT_REQUEST certReq
;
274 CSSM_TP_REQUEST_SET reqSet
;
276 CSSM_BOOL confirmRequired
;
277 CSSM_TP_RESULT_SET_PTR resultSet
=NULL
;
278 CSSM_ENCODED_CERT
*encCert
=NULL
;
279 CSSM_APPLE_TP_NAME_OID subjectNames
[2];
280 CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext
;
285 certReq
.challengeString
= NULL
;
287 /* KeyUsage extension */
288 extp
->type
= DT_KeyUsage
;
289 extp
->critical
= CSSM_FALSE
;
290 extp
->extension
.keyUsage
= CE_KU_DigitalSignature
|
292 CE_KU_KeyEncipherment
|
293 CE_KU_DataEncipherment
;
297 /* BasicConstraints */
298 extp
->type
= DT_BasicConstraints
;
299 extp
->critical
= CSSM_TRUE
;
300 extp
->extension
.basicConstraints
.cA
= CSSM_FALSE
;
301 extp
->extension
.basicConstraints
.pathLenConstraintPresent
= CSSM_FALSE
;
306 subjectNames
[0].string
= hostName
;
307 subjectNames
[0].oid
= &CSSMOID_CommonName
;
308 subjectNames
[1].string
= userName
;
309 subjectNames
[1].oid
= &CSSMOID_Description
;
312 certReq
.cspHand
= cspHand
;
313 certReq
.clHand
= clHand
;
314 randUint32(&certReq
.serialNumber
); // random serial number
315 certReq
.numSubjectNames
= 2;
316 certReq
.subjectNames
= subjectNames
;
318 certReq
.numIssuerNames
= 0; // root for now
319 certReq
.issuerNames
= NULL
;
320 certReq
.issuerNameX509
= NULL
;
321 certReq
.certPublicKey
= subjPubKey
;
322 certReq
.issuerPrivateKey
= signerPrivKey
;
323 certReq
.signatureAlg
= sigAlg
;
324 certReq
.signatureOid
= *sigOid
;
325 certReq
.notBefore
= 0;
326 certReq
.notAfter
= 60 * 60 * 24 * 365; // seconds from now, one year
327 certReq
.numExtensions
= numExts
;
328 certReq
.extensions
= exts
;
330 reqSet
.NumberOfRequests
= 1;
331 reqSet
.Requests
= &certReq
;
333 /* a CSSM_TP_CALLERAUTH_CONTEXT to specify an OID */
334 memset(&CallerAuthContext
, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT
));
335 memset(&policyId
, 0, sizeof(CSSM_FIELD
));
336 policyId
.FieldOid
= CSSMOID_APPLE_TP_LOCAL_CERT_GEN
;
338 CallerAuthContext
.Policy
.NumberOfPolicyIds
= 1;
339 CallerAuthContext
.Policy
.PolicyIds
= &policyId
;
341 CSSM_RETURN crtn
= CSSM_TP_SubmitCredRequest(tpHand
,
342 NULL
, // PreferredAuthority
343 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE
,
350 sec_error("CSSM_TP_SubmitCredRequest: %s", sec_errstr(crtn
));
353 crtn
= CSSM_TP_RetrieveCredResult(tpHand
,
355 NULL
, // CallerAuthCredentials
360 sec_error("CSSM_TP_RetrieveCredResult: %s", sec_errstr(crtn
));
363 if(resultSet
== NULL
) {
364 sec_error("CSSM_TP_RetrieveCredResult: returned NULL result set");
368 encCert
= (CSSM_ENCODED_CERT
*)resultSet
->Results
;
369 certData
->Length
= encCert
->CertBlob
.Length
;
370 certData
->Data
= malloc(encCert
->CertBlob
.Length
);
372 memcpy(certData
->Data
, encCert
->CertBlob
.Data
, encCert
->CertBlob
.Length
);
376 /* free resources allocated by TP */
377 APP_FREE(refId
.Data
);
380 if (encCert
->CertBlob
.Data
)
382 APP_FREE(encCert
->CertBlob
.Data
);
390 /* Convert a reference key to a raw key. */
391 static CSSM_RETURN
refKeyToRaw(
392 CSSM_CSP_HANDLE cspHand
,
393 const CSSM_KEY
*refKey
,
394 CSSM_KEY_PTR rawKey
) // RETURNED
396 CSSM_CC_HANDLE ccHand
;
398 CSSM_ACCESS_CREDENTIALS creds
;
400 memset(rawKey
, 0, sizeof(CSSM_KEY
));
401 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
402 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
405 &creds
, // passPhrase
406 NULL
, // wrapping key
408 CSSM_PADDING_NONE
, // Padding
412 sec_error("CSSM_CSP_CreateSymmetricContext: refKeyToRaw context err: %s", sec_errstr(crtn
));
416 crtn
= CSSM_WrapKey(ccHand
,
419 NULL
, // DescriptiveData
421 if(crtn
!= CSSM_OK
) {
422 sec_error("CSSM_WrapKey: refKeyToRaw wrap err: %s", sec_errstr(crtn
));
425 CSSM_DeleteContext(ccHand
);
430 * Find private key by label, modify its Label attr to be the
431 * hash of the associated public key.
433 static CSSM_RETURN
setPubKeyHash(
434 CSSM_CSP_HANDLE cspHand
,
435 CSSM_DL_DB_HANDLE dlDbHand
,
436 const CSSM_KEY
*pubOrPrivKey
, // to get hash; raw or ref/CSPDL
437 const char *keyLabel
) // look up by this
440 CSSM_SELECTION_PREDICATE predicate
;
441 CSSM_DB_UNIQUE_RECORD_PTR record
= NULL
;
444 CSSM_HANDLE resultHand
;
446 labelData
.Data
= (uint8
*)keyLabel
;
447 labelData
.Length
= strlen(keyLabel
) + 1; // incl. NULL
448 query
.RecordType
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
449 query
.Conjunctive
= CSSM_DB_NONE
;
450 query
.NumSelectionPredicates
= 1;
451 predicate
.DbOperator
= CSSM_DB_EQUAL
;
453 predicate
.Attribute
.Info
.AttributeNameFormat
=
454 CSSM_DB_ATTRIBUTE_NAME_AS_STRING
;
455 predicate
.Attribute
.Info
.Label
.AttributeName
= "Label";
456 predicate
.Attribute
.Info
.AttributeFormat
=
457 CSSM_DB_ATTRIBUTE_FORMAT_BLOB
;
458 predicate
.Attribute
.Value
= &labelData
;
459 query
.SelectionPredicate
= &predicate
;
461 query
.QueryLimits
.TimeLimit
= 0;
462 query
.QueryLimits
.SizeLimit
= 1;
463 query
.QueryFlags
= 0;
465 /* build Record attribute with one attr */
466 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs
;
467 CSSM_DB_ATTRIBUTE_DATA attr
;
468 attr
.Info
.AttributeNameFormat
= CSSM_DB_ATTRIBUTE_NAME_AS_STRING
;
469 attr
.Info
.Label
.AttributeName
= "Label";
470 attr
.Info
.AttributeFormat
= CSSM_DB_ATTRIBUTE_FORMAT_BLOB
;
472 recordAttrs
.DataRecordType
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
473 recordAttrs
.NumberOfAttributes
= 1;
474 recordAttrs
.AttributeData
= &attr
;
476 crtn
= CSSM_DL_DataGetFirst(dlDbHand
,
480 NULL
, // hopefully optional ...theData,
482 /* abort only on success */
483 if(crtn
!= CSSM_OK
) {
484 sec_error("CSSM_DL_DataGetFirst: setPubKeyHash: can't find private key: %s", sec_errstr(crtn
));
489 * If specified key is a ref key, do NULL unwrap for use with raw CSP.
490 * If the CSPDL and SecurityServer support the key digest passthrough
491 * this is unnecessary.
493 CSSM_KEY rawKeyToDigest
;
494 if(pubOrPrivKey
->KeyHeader
.BlobType
== CSSM_KEYBLOB_REFERENCE
) {
495 crtn
= refKeyToRaw(cspHand
, pubOrPrivKey
, &rawKeyToDigest
);
497 sec_error("setPubKeyHash: Error converting public key to raw format: %s", sec_errstr(crtn
));
503 rawKeyToDigest
= *pubOrPrivKey
;
506 /* connect to raw CSP */
507 CSSM_CSP_HANDLE rawCspHand
= srCspStartup(CSSM_TRUE
);
508 if(rawCspHand
== 0) {
509 printf("***Error connecting to raw CSP; aborting.\n");
513 /* calculate hash of pub key from private or public part */
514 CSSM_DATA_PTR keyDigest
= NULL
;
515 CSSM_CC_HANDLE ccHand
;
516 crtn
= CSSM_CSP_CreatePassThroughContext(rawCspHand
,
520 sec_error("CSSM_CSP_CreatePassThroughContext: Error calculating public key hash. Aborting: %s", sec_errstr(crtn
));
523 crtn
= CSSM_CSP_PassThrough(ccHand
,
524 CSSM_APPLECSP_KEYDIGEST
,
526 (void **)&keyDigest
);
528 sec_error("CSSM_CSP_PassThrough(PUBKEYHASH): Error calculating public key hash. Aborting: %s", sec_errstr(crtn
));
531 if(pubOrPrivKey
->KeyHeader
.BlobType
== CSSM_KEYBLOB_REFERENCE
) {
532 /* created in refKeyToRaw().... */
533 CSSM_FreeKey(cspHand
, NULL
, &rawKeyToDigest
, CSSM_FALSE
);
535 CSSM_DeleteContext(ccHand
);
536 CSSM_ModuleDetach(rawCspHand
);
539 * Replace Label attr data with hash.
540 * NOTE: the module which allocated this attribute data - a DL -
541 * was loaded and attached by the Sec layer, not by us. Thus
542 * we can't use the memory allocator functions *we* used when
543 * attaching to the CSPDL - we have to use the ones
544 * which the Sec layer registered with the DL.
546 CSSM_API_MEMORY_FUNCS memFuncs
;
547 crtn
= CSSM_GetAPIMemoryFunctions(dlDbHand
.DLHandle
, &memFuncs
);
549 sec_error("CSSM_GetAPIMemoryFunctions(DLHandle): Error: %s", sec_errstr(crtn
));
550 /* oh well, leak and continue */
553 memFuncs
.free_func(attr
.Value
->Data
, memFuncs
.AllocRef
);
554 memFuncs
.free_func(attr
.Value
, memFuncs
.AllocRef
);
556 attr
.Value
= keyDigest
;
558 /* modify key attributes */
559 crtn
= CSSM_DL_DataModify(dlDbHand
,
560 CSSM_DL_DB_RECORD_PRIVATE_KEY
,
563 NULL
, // DataToBeModified
564 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
566 sec_error("CSSM_DL_DataModify(PUBKEYHASH): Error setting public key hash. Aborting: %s", sec_errstr(crtn
));
569 crtn
= CSSM_DL_DataAbortQuery(dlDbHand
, resultHand
);
571 sec_error("CSSM_DL_DataAbortQuery: Error while stopping query: %s", sec_errstr(crtn
));
572 /* let's keep going in this case */
574 crtn
= CSSM_DL_FreeUniqueRecord(dlDbHand
, record
);
576 sec_error("CSSM_DL_FreeUniqueRecord: Error while freeing record: %s", sec_errstr(crtn
));
577 /* let's keep going in this case */
584 srAppFree(keyDigest
->Data
, NULL
);
585 srAppFree(keyDigest
, NULL
);
591 * Generate a key pair using the CSPDL.
593 OSStatus
generateKeyPair(
594 CSSM_CSP_HANDLE cspHand
,
595 CSSM_DL_DB_HANDLE dlDbHand
,
596 CSSM_ALGORITHMS keyAlg
, // e.g., CSSM_ALGID_RSA
597 uint32 keySizeInBits
,
598 const char *keyLabel
, // C string
599 CSSM_KEY_PTR
*pubKeyPtr
, // mallocd, created, RETURNED
600 CSSM_KEY_PTR
*privKeyPtr
) // mallocd, created, RETURNED
602 CSSM_KEY_PTR pubKey
= (CSSM_KEY_PTR
)(APP_MALLOC(sizeof(CSSM_KEY
)));
603 CSSM_KEY_PTR privKey
= (CSSM_KEY_PTR
)(APP_MALLOC(sizeof(CSSM_KEY
)));
604 if((pubKey
== NULL
) || (privKey
== NULL
)) {
609 CSSM_KEYUSE pubKeyUse
;
610 CSSM_KEYUSE privKeyUse
;
612 pubKeyUse
= CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_ENCRYPT
|
614 privKeyUse
= CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_DECRYPT
|
617 crtn
= srCspGenKeyPair(cspHand
,
621 (int) strlen(keyLabel
) + 1,
625 CSSM_KEYATTR_EXTRACTABLE
| CSSM_KEYATTR_RETURN_REF
,
628 CSSM_KEYATTR_SENSITIVE
| CSSM_KEYATTR_RETURN_REF
|
629 CSSM_KEYATTR_PERMANENT
| CSSM_KEYATTR_EXTRACTABLE
);
637 /* bind private key to cert by public key hash */
638 crtn
= setPubKeyHash(cspHand
,
643 sec_error("setPubKeyHash: Error setting public key hash. Continuing at peril: %s", sec_errstr(crtn
));
647 *privKeyPtr
= privKey
;
651 // Fill a uint32 with random data
652 void randUint32(uint32
*u
)
654 int dev
= open("/dev/random", O_RDONLY
);
658 read(dev
, u
, sizeof(*u
));
663 //==========================================================================
666 keychain_createMFV(int argc
, char * const *argv
)
668 int zero_password
= 0;
669 char *password
= NULL
;
670 const char *keychainName
= NULL
;
671 int result
= 0, ch
= 0;
672 Boolean do_prompt
= FALSE
;
673 SecKeychainRef keychainRef
= NULL
;
674 uint32 keySizeInBits
= SR2_KEY_SIZE_IN_BITS
; // default
676 /* AG: getopts optstring name [args]
677 AG: while loop calling getopt is used to extract password from cl from user
678 password is the only option to keychain_create
679 optstring is a string containing the legitimate option
680 characters. If such a character is followed by a colon,
681 the option requires an argument, so getopt places a
682 pointer to the following text in the same argv-element, or
683 the text of the following argv-element, in optarg.
685 while ((ch
= getopt(argc
, argv
, "hp:s:P")) != -1)
696 // Specify the keysize in bits (default 1024)
697 keySizeInBits
= atoi(optarg
);
698 if (!(keySizeInBits
== SR_KEY_SIZE_IN_BITS
|| keySizeInBits
== SR2_KEY_SIZE_IN_BITS
|| keySizeInBits
== 4096))
703 return 2; /* @@@ Return 2 triggers usage message. */
707 AG: The external variable optind is the index of the next
708 array element of argv[] to be processed; it communicates
709 from one call of getopt() to the next which element to
711 The variable optind is the index of the next element of the argv[] vector to be processed. It shall be initialized to 1 by the system, and getopt() shall update it when it finishes with each element of argv[]. When an element of argv[] contains multiple option characters, it is unspecified how getopt() determines which options have already been processed.
718 return 2; /* @@@ Return 2 triggers usage message. */
720 keychainName
= (argc
== 1)?*argv
:_masterKeychainName
;
721 if (!keychainName
|| *keychainName
== '\0')
724 if (!password
&& !do_prompt
)
729 for (tries
= 3; tries
-- > 0;)
733 password
= getpass("password for new keychain: ");
740 firstpass
= malloc(strlen(password
) + 1);
741 strcpy(firstpass
, password
);
742 password
= getpass("retype password for new keychain: ");
743 compare
= password
? strcmp(password
, firstpass
) : 1;
744 memset(firstpass
, 0, strlen(firstpass
));
754 fprintf(stderr
, "passwords don't match\n");
755 memset(password
, 0, strlen(password
));
773 // result = do_create(keychain, password, do_prompt);
774 result
= makeMasterPassword(keychainName
, password
, keySizeInBits
, &keychainRef
);
776 CFRelease(keychainRef
);
778 memset(password
, 0, strlen(password
));
784 keychainName
= *argv
;