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"
28 #include "readline_cssm.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>
44 #include <utilities/SecCFRelease.h>
46 #include "srCdsaUtils.h"
48 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
50 const char * const _masterKeychainName
= "FileVaultMaster.keychain";
51 const char * const _masterKeychainPath
= "./FileVaultMaster";
54 * Parameters used to create key pairs and certificates in
55 * SR_CertificateAndKeyCreate().
57 #define SR_KEY_ALGORITHM CSSM_ALGID_RSA
58 #define SR_KEY_SIZE_IN_BITS 1024
60 #define SR2_KEY_SIZE_IN_BITS 2048 // Recommended size for FileVault2 (FDE)
63 * The CSSM_ALGORITHMS and OID values defining the signature
64 * algorithm in the generated certificate.
66 #define SR_CERT_SIGNATURE_ALGORITHM CSSM_ALGID_SHA256WithRSA
67 #define SR_CERT_SIGNATURE_ALG_OID CSSMOID_SHA256WithRSA
69 OSStatus
makeMasterPassword(const char *fvmkcName
, const char *masterPasswordPassword
, uint32 keySizeInBits
, SecKeychainRef
*keychainRef
);
71 OSStatus
createPair(CFStringRef hostName
,CFStringRef userName
,SecKeychainRef keychainRef
, uint32 keySizeInBits
, CFDataRef
*cert
);
72 OSStatus
generateKeyPair(CSSM_CSP_HANDLE cspHand
, CSSM_DL_DB_HANDLE dlDbHand
, CSSM_ALGORITHMS keyAlg
,
73 uint32 keySizeInBits
, const char *keyLabel
, CSSM_KEY_PTR
*pubKeyPtr
, CSSM_KEY_PTR
*privKeyPtr
);
74 OSStatus
createRootCert(CSSM_TP_HANDLE tpHand
, CSSM_CL_HANDLE clHand
, CSSM_CSP_HANDLE cspHand
,
75 CSSM_KEY_PTR subjPubKey
, CSSM_KEY_PTR signerPrivKey
, const char *hostName
, const char *userName
,
76 CSSM_ALGORITHMS sigAlg
, const CSSM_OID
*sigOid
, CSSM_DATA_PTR certData
);
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
);
106 } else if (status
!= errSecSuccess
) {
107 sec_error("Could not create keychain file %s: %s", fvmkcName
, sec_errstr(status
));
112 // Create the key pair
114 int rx
= gethostname(host
, sizeof(host
));
116 strcpy(host
, "localhost");
118 CFStringRef hostName
= CFSTR("FileVault Recovery Key"); // This is what shows up in Keychain Access display
119 CFStringRef userName
= CFStringCreateWithCString(kCFAllocatorDefault
, host
, kCFStringEncodingUTF8
);
120 CFDataRef certData
= NULL
;
121 printf("Generating a %d bit key pair; this may take several minutes\n", keySizeInBits
);
122 status
= createPair(hostName
,userName
,*keychainRef
,keySizeInBits
, &certData
);
123 CFReleaseNull(userName
);
125 sec_error("Error in createPair: %s", sec_errstr(status
));
132 OSStatus
createPair(CFStringRef hostName
,CFStringRef userName
,SecKeychainRef keychainRef
, uint32 keySizeInBits
, CFDataRef
*cert
)
134 SecCertificateRef certRef
= NULL
;
135 CSSM_DL_DB_HANDLE dlDbHand
= {0, 0};
136 CSSM_CSP_HANDLE cspHand
= 0;
137 CSSM_TP_HANDLE tpHand
= 0;
138 CSSM_CL_HANDLE clHand
= 0;
139 CSSM_KEY_PTR pubKey
= NULL
;
140 CSSM_KEY_PTR privKey
= NULL
;
141 CSSM_DATA certData
= {0, NULL
};
142 char *hostStr
= NULL
;
143 char *userStr
= NULL
;
145 CSSM_OID algOid
= SR_CERT_SIGNATURE_ALG_OID
;
147 hostStr
= secCopyCString(hostName
);
148 userStr
= secCopyCString(userName
);
149 if (!hostStr
|| !userStr
) // could not convert to UTF-8
155 // open keychain, connect to all the CDSA modules we'll need
157 ortn
= SecKeychainGetCSPHandle(keychainRef
, &cspHand
);
161 ortn
= SecKeychainGetDLDBHandle(keychainRef
, &dlDbHand
);
165 tpHand
= srTpStartup();
172 clHand
= srClStartup();
179 // generate key pair, private key stored in keychain
180 ortn
= generateKeyPair(cspHand
, dlDbHand
, SR_KEY_ALGORITHM
, keySizeInBits
,
181 "FileVault Master Password Key", &pubKey
, &privKey
);
186 ortn
= createRootCert(tpHand
,clHand
,cspHand
,pubKey
,privKey
,hostStr
,userStr
,
187 SR_CERT_SIGNATURE_ALGORITHM
,&algOid
,&certData
);
191 // store the cert in the same DL/DB as the key pair [see SecCertificateCreateFromData]
192 ortn
= SecCertificateCreateFromData(&certData
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, &certRef
);
196 ortn
= SecCertificateAddToKeychain(certRef
, keychainRef
);
200 // return the cert to caller
201 *cert
= CFDataCreate(NULL
, certData
.Data
, certData
.Length
);
218 CSSM_ModuleDetach(tpHand
);
221 CSSM_ModuleDetach(clHand
);
225 CSSM_FreeKey(cspHand
,
228 CSSM_FALSE
); // delete
233 CSSM_FreeKey(cspHand
,
236 CSSM_FALSE
); // delete
244 * Given a CFStringRef, this function allocates and returns a pointer
245 * to a null-terminated 'C' string copy. If conversion of the string
246 * to UTF8 fails for some reason, the function will return NULL.
248 * The caller must free this pointer
251 char *secCopyCString(CFStringRef theString
)
253 CFIndex maxLength
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(theString
), kCFStringEncodingUTF8
) + 1;
254 char* buffer
= (char*) malloc(maxLength
);
255 Boolean converted
= CFStringGetCString(theString
, buffer
, maxLength
, kCFStringEncodingUTF8
);
264 #pragma mark -------------------- SecFileVaultCert private implementation --------------------
266 OSStatus
createRootCert(
267 CSSM_TP_HANDLE tpHand
,
268 CSSM_CL_HANDLE clHand
,
269 CSSM_CSP_HANDLE cspHand
,
270 CSSM_KEY_PTR subjPubKey
,
271 CSSM_KEY_PTR signerPrivKey
,
272 const char *hostName
, // CSSMOID_CommonName
273 const char *userName
, // CSSMOID_Description
274 CSSM_ALGORITHMS sigAlg
,
275 const CSSM_OID
*sigOid
,
276 CSSM_DATA_PTR certData
) // mallocd and RETURNED
278 CE_DataAndType exts
[2];
279 CE_DataAndType
*extp
= exts
;
281 CSSM_DATA refId
; // mallocd by
282 // CSSM_TP_SubmitCredRequest
283 CSSM_APPLE_TP_CERT_REQUEST certReq
;
284 CSSM_TP_REQUEST_SET reqSet
;
286 CSSM_BOOL confirmRequired
;
287 CSSM_TP_RESULT_SET_PTR resultSet
=NULL
;
288 CSSM_ENCODED_CERT
*encCert
=NULL
;
289 CSSM_APPLE_TP_NAME_OID subjectNames
[2];
290 CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext
;
295 certReq
.challengeString
= NULL
;
297 /* KeyUsage extension */
298 extp
->type
= DT_KeyUsage
;
299 extp
->critical
= CSSM_FALSE
;
300 extp
->extension
.keyUsage
= CE_KU_DigitalSignature
|
302 CE_KU_KeyEncipherment
|
303 CE_KU_DataEncipherment
;
307 /* BasicConstraints */
308 extp
->type
= DT_BasicConstraints
;
309 extp
->critical
= CSSM_TRUE
;
310 extp
->extension
.basicConstraints
.cA
= CSSM_FALSE
;
311 extp
->extension
.basicConstraints
.pathLenConstraintPresent
= CSSM_FALSE
;
316 subjectNames
[0].string
= hostName
;
317 subjectNames
[0].oid
= &CSSMOID_CommonName
;
318 subjectNames
[1].string
= userName
;
319 subjectNames
[1].oid
= &CSSMOID_Description
;
322 certReq
.cspHand
= cspHand
;
323 certReq
.clHand
= clHand
;
324 certReq
.serialNumber
= arc4random();
325 certReq
.numSubjectNames
= 2;
326 certReq
.subjectNames
= subjectNames
;
328 certReq
.numIssuerNames
= 0; // root for now
329 certReq
.issuerNames
= NULL
;
330 certReq
.issuerNameX509
= NULL
;
331 certReq
.certPublicKey
= subjPubKey
;
332 certReq
.issuerPrivateKey
= signerPrivKey
;
333 certReq
.signatureAlg
= sigAlg
;
334 certReq
.signatureOid
= *sigOid
;
335 certReq
.notBefore
= 0;
336 certReq
.notAfter
= 60 * 60 * 24 * 365; // seconds from now, one year
337 certReq
.numExtensions
= numExts
;
338 certReq
.extensions
= exts
;
340 reqSet
.NumberOfRequests
= 1;
341 reqSet
.Requests
= &certReq
;
343 /* a CSSM_TP_CALLERAUTH_CONTEXT to specify an OID */
344 memset(&CallerAuthContext
, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT
));
345 memset(&policyId
, 0, sizeof(CSSM_FIELD
));
346 policyId
.FieldOid
= CSSMOID_APPLE_TP_LOCAL_CERT_GEN
;
348 CallerAuthContext
.Policy
.NumberOfPolicyIds
= 1;
349 CallerAuthContext
.Policy
.PolicyIds
= &policyId
;
351 CSSM_RETURN crtn
= CSSM_TP_SubmitCredRequest(tpHand
,
352 NULL
, // PreferredAuthority
353 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE
,
360 sec_error("CSSM_TP_SubmitCredRequest: %s", sec_errstr(crtn
));
363 crtn
= CSSM_TP_RetrieveCredResult(tpHand
,
365 NULL
, // CallerAuthCredentials
370 sec_error("CSSM_TP_RetrieveCredResult: %s", sec_errstr(crtn
));
373 if(resultSet
== NULL
) {
374 sec_error("CSSM_TP_RetrieveCredResult: returned NULL result set");
378 encCert
= (CSSM_ENCODED_CERT
*)resultSet
->Results
;
379 certData
->Length
= encCert
->CertBlob
.Length
;
380 certData
->Data
= malloc(encCert
->CertBlob
.Length
);
382 memcpy(certData
->Data
, encCert
->CertBlob
.Data
, encCert
->CertBlob
.Length
);
386 /* free resources allocated by TP */
387 APP_FREE(refId
.Data
);
390 if (encCert
->CertBlob
.Data
)
392 APP_FREE(encCert
->CertBlob
.Data
);
400 /* Convert a reference key to a raw key. */
401 static CSSM_RETURN
refKeyToRaw(
402 CSSM_CSP_HANDLE cspHand
,
403 const CSSM_KEY
*refKey
,
404 CSSM_KEY_PTR rawKey
) // RETURNED
406 CSSM_CC_HANDLE ccHand
;
408 CSSM_ACCESS_CREDENTIALS creds
;
410 memset(rawKey
, 0, sizeof(CSSM_KEY
));
411 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
412 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
415 &creds
, // passPhrase
416 NULL
, // wrapping key
418 CSSM_PADDING_NONE
, // Padding
422 sec_error("CSSM_CSP_CreateSymmetricContext: refKeyToRaw context err: %s", sec_errstr(crtn
));
426 crtn
= CSSM_WrapKey(ccHand
,
429 NULL
, // DescriptiveData
431 if(crtn
!= CSSM_OK
) {
432 sec_error("CSSM_WrapKey: refKeyToRaw wrap err: %s", sec_errstr(crtn
));
435 CSSM_DeleteContext(ccHand
);
440 * Find private key by label, modify its Label attr to be the
441 * hash of the associated public key.
443 static CSSM_RETURN
setPubKeyHash(
444 CSSM_CSP_HANDLE cspHand
,
445 CSSM_DL_DB_HANDLE dlDbHand
,
446 const CSSM_KEY
*pubOrPrivKey
, // to get hash; raw or ref/CSPDL
447 const char *keyLabel
) // look up by this
450 CSSM_SELECTION_PREDICATE predicate
;
451 CSSM_DB_UNIQUE_RECORD_PTR record
= NULL
;
454 CSSM_HANDLE resultHand
;
456 labelData
.Data
= (uint8
*)keyLabel
;
457 labelData
.Length
= strlen(keyLabel
) + 1; // incl. NULL
458 query
.RecordType
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
459 query
.Conjunctive
= CSSM_DB_NONE
;
460 query
.NumSelectionPredicates
= 1;
461 predicate
.DbOperator
= CSSM_DB_EQUAL
;
463 predicate
.Attribute
.Info
.AttributeNameFormat
=
464 CSSM_DB_ATTRIBUTE_NAME_AS_STRING
;
465 predicate
.Attribute
.Info
.Label
.AttributeName
= "Label";
466 predicate
.Attribute
.Info
.AttributeFormat
=
467 CSSM_DB_ATTRIBUTE_FORMAT_BLOB
;
468 predicate
.Attribute
.Value
= &labelData
;
469 query
.SelectionPredicate
= &predicate
;
471 query
.QueryLimits
.TimeLimit
= 0;
472 query
.QueryLimits
.SizeLimit
= 1;
473 query
.QueryFlags
= 0;
475 /* build Record attribute with one attr */
476 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs
;
477 CSSM_DB_ATTRIBUTE_DATA attr
;
478 attr
.Info
.AttributeNameFormat
= CSSM_DB_ATTRIBUTE_NAME_AS_STRING
;
479 attr
.Info
.Label
.AttributeName
= "Label";
480 attr
.Info
.AttributeFormat
= CSSM_DB_ATTRIBUTE_FORMAT_BLOB
;
482 recordAttrs
.DataRecordType
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
483 recordAttrs
.NumberOfAttributes
= 1;
484 recordAttrs
.AttributeData
= &attr
;
486 crtn
= CSSM_DL_DataGetFirst(dlDbHand
,
490 NULL
, // hopefully optional ...theData,
492 /* abort only on success */
493 if(crtn
!= CSSM_OK
) {
494 sec_error("CSSM_DL_DataGetFirst: setPubKeyHash: can't find private key: %s", sec_errstr(crtn
));
499 * If specified key is a ref key, do NULL unwrap for use with raw CSP.
500 * If the CSPDL and SecurityServer support the key digest passthrough
501 * this is unnecessary.
503 CSSM_KEY rawKeyToDigest
;
504 if(pubOrPrivKey
->KeyHeader
.BlobType
== CSSM_KEYBLOB_REFERENCE
) {
505 crtn
= refKeyToRaw(cspHand
, pubOrPrivKey
, &rawKeyToDigest
);
507 sec_error("setPubKeyHash: Error converting public key to raw format: %s", sec_errstr(crtn
));
513 rawKeyToDigest
= *pubOrPrivKey
;
516 /* connect to raw CSP */
517 CSSM_CSP_HANDLE rawCspHand
= srCspStartup(CSSM_TRUE
);
518 if(rawCspHand
== 0) {
519 printf("***Error connecting to raw CSP; aborting.\n");
523 /* calculate hash of pub key from private or public part */
524 CSSM_DATA_PTR keyDigest
= NULL
;
525 CSSM_CC_HANDLE ccHand
;
526 crtn
= CSSM_CSP_CreatePassThroughContext(rawCspHand
,
530 sec_error("CSSM_CSP_CreatePassThroughContext: Error calculating public key hash. Aborting: %s", sec_errstr(crtn
));
533 crtn
= CSSM_CSP_PassThrough(ccHand
,
534 CSSM_APPLECSP_KEYDIGEST
,
536 (void **)&keyDigest
);
538 sec_error("CSSM_CSP_PassThrough(PUBKEYHASH): Error calculating public key hash. Aborting: %s", sec_errstr(crtn
));
541 if(pubOrPrivKey
->KeyHeader
.BlobType
== CSSM_KEYBLOB_REFERENCE
) {
542 /* created in refKeyToRaw().... */
543 CSSM_FreeKey(cspHand
, NULL
, &rawKeyToDigest
, CSSM_FALSE
);
545 CSSM_DeleteContext(ccHand
);
546 CSSM_ModuleDetach(rawCspHand
);
549 * Replace Label attr data with hash.
550 * NOTE: the module which allocated this attribute data - a DL -
551 * was loaded and attached by the Sec layer, not by us. Thus
552 * we can't use the memory allocator functions *we* used when
553 * attaching to the CSPDL - we have to use the ones
554 * which the Sec layer registered with the DL.
556 CSSM_API_MEMORY_FUNCS memFuncs
;
557 crtn
= CSSM_GetAPIMemoryFunctions(dlDbHand
.DLHandle
, &memFuncs
);
559 sec_error("CSSM_GetAPIMemoryFunctions(DLHandle): Error: %s", sec_errstr(crtn
));
560 /* oh well, leak and continue */
563 memFuncs
.free_func(attr
.Value
->Data
, memFuncs
.AllocRef
);
564 memFuncs
.free_func(attr
.Value
, memFuncs
.AllocRef
);
566 attr
.Value
= keyDigest
;
568 /* modify key attributes */
569 crtn
= CSSM_DL_DataModify(dlDbHand
,
570 CSSM_DL_DB_RECORD_PRIVATE_KEY
,
573 NULL
, // DataToBeModified
574 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
576 sec_error("CSSM_DL_DataModify(PUBKEYHASH): Error setting public key hash. Aborting: %s", sec_errstr(crtn
));
579 crtn
= CSSM_DL_DataAbortQuery(dlDbHand
, resultHand
);
581 sec_error("CSSM_DL_DataAbortQuery: Error while stopping query: %s", sec_errstr(crtn
));
582 /* let's keep going in this case */
584 crtn
= CSSM_DL_FreeUniqueRecord(dlDbHand
, record
);
586 sec_error("CSSM_DL_FreeUniqueRecord: Error while freeing record: %s", sec_errstr(crtn
));
587 /* let's keep going in this case */
594 srAppFree(keyDigest
->Data
, NULL
);
595 srAppFree(keyDigest
, NULL
);
601 * Generate a key pair using the CSPDL.
603 OSStatus
generateKeyPair(
604 CSSM_CSP_HANDLE cspHand
,
605 CSSM_DL_DB_HANDLE dlDbHand
,
606 CSSM_ALGORITHMS keyAlg
, // e.g., CSSM_ALGID_RSA
607 uint32 keySizeInBits
,
608 const char *keyLabel
, // C string
609 CSSM_KEY_PTR
*pubKeyPtr
, // mallocd, created, RETURNED
610 CSSM_KEY_PTR
*privKeyPtr
) // mallocd, created, RETURNED
612 CSSM_KEY_PTR pubKey
= (CSSM_KEY_PTR
)(APP_MALLOC(sizeof(CSSM_KEY
)));
613 CSSM_KEY_PTR privKey
= (CSSM_KEY_PTR
)(APP_MALLOC(sizeof(CSSM_KEY
)));
614 if((pubKey
== NULL
) || (privKey
== NULL
)) {
619 CSSM_KEYUSE pubKeyUse
;
620 CSSM_KEYUSE privKeyUse
;
622 pubKeyUse
= CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_ENCRYPT
|
624 privKeyUse
= CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_DECRYPT
|
627 crtn
= srCspGenKeyPair(cspHand
,
631 (int) strlen(keyLabel
) + 1,
635 CSSM_KEYATTR_EXTRACTABLE
| CSSM_KEYATTR_RETURN_REF
,
638 CSSM_KEYATTR_SENSITIVE
| CSSM_KEYATTR_RETURN_REF
|
639 CSSM_KEYATTR_PERMANENT
| CSSM_KEYATTR_EXTRACTABLE
);
647 /* bind private key to cert by public key hash */
648 crtn
= setPubKeyHash(cspHand
,
653 sec_error("setPubKeyHash: Error setting public key hash. Continuing at peril: %s", sec_errstr(crtn
));
657 *privKeyPtr
= privKey
;
661 //==========================================================================
664 keychain_createMFV(int argc
, char * const *argv
)
666 int zero_password
= 0;
667 char *password
= NULL
;
668 const char *keychainName
= NULL
;
669 int result
= 0, ch
= 0;
670 Boolean do_prompt
= FALSE
;
671 SecKeychainRef keychainRef
= NULL
;
672 uint32 keySizeInBits
= SR2_KEY_SIZE_IN_BITS
; // default
674 /* AG: getopts optstring name [args]
675 AG: while loop calling getopt is used to extract password from cl from user
676 password is the only option to keychain_create
677 optstring is a string containing the legitimate option
678 characters. If such a character is followed by a colon,
679 the option requires an argument, so getopt places a
680 pointer to the following text in the same argv-element, or
681 the text of the following argv-element, in optarg.
683 while ((ch
= getopt(argc
, argv
, "hp:s:P")) != -1)
694 // Specify the keysize in bits (default 1024)
695 keySizeInBits
= atoi(optarg
);
696 if (!(keySizeInBits
== SR_KEY_SIZE_IN_BITS
|| keySizeInBits
== SR2_KEY_SIZE_IN_BITS
|| keySizeInBits
== 4096))
697 return SHOW_USAGE_MESSAGE
;
701 return SHOW_USAGE_MESSAGE
;
705 AG: The external variable optind is the index of the next
706 array element of argv[] to be processed; it communicates
707 from one call of getopt() to the next which element to
709 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.
716 return SHOW_USAGE_MESSAGE
;
718 keychainName
= (argc
== 1)?*argv
:_masterKeychainName
;
719 if (!keychainName
|| *keychainName
== '\0') {
723 if (!password
&& !do_prompt
)
728 for (tries
= 3; tries
-- > 0;)
732 password
= getpass("password for new keychain: ");
739 firstpass
= malloc(strlen(password
) + 1);
740 strcpy(firstpass
, password
);
741 password
= getpass("retype password for new keychain: ");
742 compare
= password
? strcmp(password
, firstpass
) : 1;
743 memset(firstpass
, 0, strlen(firstpass
));
753 fprintf(stderr
, "passwords don't match\n");
754 memset(password
, 0, strlen(password
));
772 // result = do_create(keychain, password, do_prompt);
773 result
= makeMasterPassword(keychainName
, password
, keySizeInBits
, &keychainRef
);
775 CFRelease(keychainRef
);
777 memset(password
, 0, strlen(password
));
783 keychainName
= *argv
;