keystore.c revision 2
2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 2N/A * Use is subject to license terms. 2N/A * Description: This module contains the structure definitions for processing 2N/A * package keystore files. 2N/A /* truststore handles */ 2N/A /* user certificate handles */ 2N/A /* private key handles */ 2N/A/* locking routines */ 2N/A/* wait on other keystore access for 1 minute before giving up */ 2N/A * print_certs - prints certificates out of a keystore, to a file. 2N/A * err - Error object to append errors to 2N/A * keystore - Keystore on which to operate 2N/A * alias - Name of certificate to print, NULL means print all 2N/A * format - Format in which to print certificates 2N/A * outfile - Where to print certificates 2N/A * non-zero - Failure, errors added to err 2N/A /* print out each client cert */ 2N/A /* no name recorded, keystore is corrupt */ 2N/A /* name does not match, skip it */ 2N/A /* print out each trusted cert */ 2N/A /* no name recorded, keystore is corrupt */ 2N/A /* name does not match, skip it */ 2N/A /* no certs printed */ 2N/A * print_cert - prints a single certificate, to a file 2N/A * err - Error object to append errors to 2N/A * x - The certificate to print 2N/A * alias - Name of certificate to print 2N/A * format - Format in which to print certificate 2N/A * outfile - Where to print certificate 2N/A * non-zero - Failure, errors added to err 2N/A /* need to localize the word "Fingerprint", hence these pointers */ 2N/A * make a copy, otherwise the next call to get_fingerprint 2N/A * will overwrite this one 2N/A /* i18n: 14 characters max */ 2N/A /* i18n: 14 characters max */ 2N/A /* i18n: 18 characters max */ 2N/A /* i18n: 18 characters max */ 2N/A /* i18n: 18 characters max */ 2N/A /* i18n: 18 characters max */ 2N/A /* i18n: 18 characters max */ 2N/A * open_keystore - Initialize new keystore object for 2N/A * err - Error object to append errors to 2N/A * keystore_file - Base filename or directory of keystore 2N/A * app - Application making request 2N/A * passwd - Password used to decrypt keystore 2N/A * flags - Control flags used to control access mode and behavior 2N/A * result - Resulting keystore object stored here on success 2N/A * 0 - Success - result contains a pointer to the opened keystore 2N/A * non-zero - Failure, errors added to err 2N/A /* unable to determine keystore paths */ 2N/A /* unable to repair keystore */ 2N/A /* now that we have locked the keystore, go ahead and read it */ 2N/A * new_keystore - Allocates and initializes a Keystore object 2N/A * NULL - out of memory 2N/A * otherwise, returns a pointer to the newly allocated object, 2N/A * which should be freed with free_keystore() when no longer 2N/A * free_keystore - Deallocates a Keystore object 2N/A * keystore - The keystore to deallocate 2N/A * close_keystore - Writes keystore to disk if needed, then 2N/A * unlocks and closes keystore. 2N/A * err - Error object to append errors to 2N/A * keystore - Keystore which should be closed 2N/A * passwd - Password used to encrypt keystore 2N/A * 0 - Success - keystore is committed to disk, and unlocked 2N/A * non-zero - Failure, errors added to err 2N/A /* write out the keystore first */ 2N/A * merge_ca_cert - Adds a trusted certificate (trust anchor) to a keystore. 2N/A * certificate checked for validity dates and non-duplicity. 2N/A * err - Error object to add errors to 2N/A * cacert - Certificate which to merge into keystore 2N/A * keystore - The keystore into which the certificate is merged 2N/A * 0 - Success - Certificate passes validity, and 2N/A * is merged into keystore 2N/A * non-zero - Failure, errors recorded in err 2N/A /* check validity dates */ 2N/A /* create the certificate's friendlyName */ 2N/A /* merge certificate into the keystore */ 2N/A /* no existing truststore, so make a new one */ 2N/A /* existing truststore, make sure there's no duplicate */ 2N/A /* could not search properly! */ 2N/A /* whoops, found one already */ 2N/A * find_key_cert_pair - Searches a keystore for a matching 2N/A * public key certificate and private key, given an alias. 2N/A * err - Error object to add errors to 2N/A * ks - Keystore to search 2N/A * alias - Name to used to match certificate's alias 2N/A * key - Resulting key is placed here 2N/A * cert - Resulting cert is placed here 2N/A * 0 - Success - Matching cert/key pair placed in key and cert. 2N/A * non-zero - Failure, errors recorded in err 2N/A /* no public certs */ 2N/A /* no private keys */ 2N/A /* try the easy case first */ 2N/A * only one private key and public key cert, and they 2N/A * match, so use them 2N/A /* Attempt to find the right pair given the alias */ 2N/A * find_ca_certs - Searches a keystore for trusted certificates 2N/A * err - Error object to add errors to 2N/A * ks - Keystore to search 2N/A * cacerts - resulting set of trusted certs are placed here 2N/A * 0 - Success - trusted cert list returned in cacerts 2N/A * non-zero - Failure, errors recorded in err 2N/A * find_cl_certs - Searches a keystore for user certificates 2N/A * err - Error object to add errors to 2N/A * ks - Keystore to search 2N/A * cacerts - resulting set of user certs are placed here 2N/A * No matching of any kind is performed. 2N/A * 0 - Success - trusted cert list returned in cacerts 2N/A * non-zero - Failure, errors recorded in err 2N/A * merge_cert_and_key - Adds a user certificate and matching 2N/A * private key to a keystore. 2N/A * certificate checked for validity dates and non-duplicity. 2N/A * err - Error object to add errors to 2N/A * cert - Certificate which to merge into keystore 2N/A * key - matching private key to 'cert' 2N/A * alias - Name which to store the cert and key under 2N/A * keystore - The keystore into which the certificate is merged 2N/A * 0 - Success - Certificate passes validity, and 2N/A * is merged into keystore, along with key 2N/A * non-zero - Failure, errors recorded in err 2N/A /* check validity dates */ 2N/A /* set the friendlyName of the key and cert to the supplied alias */ 2N/A /* merge certificate and key into the keystore */ 2N/A /* no existing truststore, so make a new one */ 2N/A /* existing certstore, make sure there's no duplicate */ 2N/A /* could not search properly! */ 2N/A /* whoops, found one already */ 2N/A /* no existing keystore, so make a new one */ 2N/A /* existing keystore, so make sure there's no duplicate entry */ 2N/A /* could not search properly! */ 2N/A /* whoops, found one already */ 2N/A * delete_cert_and_keys - Deletes one or more certificates 2N/A * and matching private keys from a keystore. 2N/A * err - Error object to add errors to 2N/A * ks - The keystore from which certs and keys are deleted 2N/A * alias - Name which to search for certificates and keys 2N/A * 0 - Success - All trusted certs which match 'alias' 2N/A * are deleted. All user certificates 2N/A * which match 'alias' are deleted, along 2N/A * with the matching private key. 2N/A * non-zero - Failure, errors recorded in err 2N/A /* delete any and all client certs with the supplied name */ 2N/A /* match, so nuke it */ 2N/A /* we deleted all the client certs */ 2N/A /* and now the private keys */ 2N/A /* match, so nuke it */ 2N/A /* we deleted all the private keys */ 2N/A /* finally, remove any trust anchors that match */ 2N/A /* match, so nuke it */ 2N/A /* we deleted all the CA certs */ 2N/A /* no certs or keys deleted */ 2N/A * check_cert - Checks certificate validity. This routine 2N/A * checks that the current time falls within the period 2N/A * of validity for the cert. 2N/A * err - Error object to add errors to 2N/A * cert - The certificate to check 2N/A * 0 - Success - Certificate checks out 2N/A * non-zero - Failure, errors and reasons recorded in err 2N/A /* get current time */ 2N/A /* trim whitespace from end of time string */ 2N/A /* check validity of cert */ 2N/A /* Current time meets requested checks */ 2N/A /* 'not before' field is invalid */ 2N/A /* 'not after' field is invalid */ 2N/A /* Current time is before 'not before' */ 2N/A * Ignore expiration time since the trust cert used to 2N/A * verify the certs used to sign Sun patches is already 2N/A * expired. Once the patches get resigned with the new 2N/A * cert we will check expiration against the time the 2N/A * patch was signed and not the time it is installed. 2N/A * check_cert - Checks certificate validity. This routine 2N/A * checks everything that check_cert checks, and additionally 2N/A * verifies that the private key and corresponding public 2N/A * key are indeed a pair. 2N/A * err - Error object to add errors to 2N/A * cert - The certificate to check 2N/A * key - the key to check 2N/A * 0 - Success - Certificate checks out 2N/A * non-zero - Failure, errors and reasons recorded in err 2N/A /* check validity dates */ 2N/A /* check key pair match */ 2N/A/* ------------------ private functions ---------------------- */ 2N/A * verify_keystore_integrity - Searches for the remnants 2N/A * of a failed or aborted keystore modification, and 2N/A * cleans up the files, retstores the keystore to a known 2N/A * err - Error object to add errors to 2N/A * keystore_file - Base directory or filename of keystore 2N/A * app - Application making request 2N/A * 0 - Success - Keystore is restored, or untouched in the 2N/A * case that cleanup was unnecessary 2N/A * non-zero - Failure, errors and reasons recorded in err 2N/A * restore_keystore_file - restores a keystore file to 2N/A * Keystore files can possibly be corrupted by a variety 2N/A * routine, along with write_keystore_file, tries to 2N/A * maintain keystore integrity by writing the files 2N/A * out in a particular order, minimizing the time period 2N/A * that the keystore is in an indeterminate state. 2N/A * With the current implementation, there are some failures 2N/A * that are wholly unrecoverable, such as disk corruption. 2N/A * These routines attempt to minimize the risk, but not 2N/A * eliminate it. When better, atomic operations are available 2N/A * (such as a trued atabase with commit, rollback, and 2N/A * guaranteed atomicity), this implementation should use that. 2N/A * err - Error object to add errors to 2N/A * keystore_file - keystore file path to restore. 2N/A * 0 - Success - Keystore file is restored, or untouched in the 2N/A * case that cleanup was unnecessary 2N/A * non-zero - Failure, errors and reasons recorded in err 2N/A * restore the file, waiting on it 2N/A * to be free for locking, or for 2N/A /* "new" file is not a regular file */ 2N/A /* couldn't stat "new" file */ 2N/A /* "new" file doesn't exist */ 2N/A /* could not lock file */ 2N/A * The new file still 2N/A /* The file is not complete. Remove it */ 2N/A /* remove backup file */ 2N/A * new file exists, but is not a 2N/A * could not stat file. Unless 2N/A * the reason was that the file 2N/A * is now gone, this is an error 2N/A * otherwise, file is gone. The process 2N/A * that held the lock must have 2N/A * successfully cleaned up and 2N/A * exited with a valid keystore 2N/A * resolve_paths - figure out if we are dealing with a single-file 2N/A * or multi-file keystore 2N/A * The flags tell resolve_paths how to behave: 2N/A * KEYSTORE_PATH_SOFT 2N/A * If the keystore file does not exist at <base>/<app> then 2N/A * use <base> as the path to the keystore. This can be used, 2N/A * for example, to access an app-specific keystore iff it 2N/A * exists, otherwise revert back to an app-generic keystore. 2N/A * KEYSTORE_PATH_HARD 2N/A * Always use the keystore located at <keystore_path>/<app>. 2N/A * they will be created. This is used to avoid falling 2N/A * back to an app-generic keystore path when the app-specific 2N/A * one does not exist. 2N/A * err - Error object to add errors to 2N/A * keystore_file - base keystore file path to lock 2N/A * app - Application making requests 2N/A * flags - Control flags (see above description) 2N/A * keystore - object which is being locked 2N/A * B_TRUE - Success - Keystore file is locked, paths to 2N/A * appropriate files placed in keystore. 2N/A * B_FALSE - Failure, errors and reasons recorded in err 2N/A * figure out whether we are dealing with a single-file keystore 2N/A * or a multi-file keystore 2N/A * app-specific does not exist 2N/A * fallback to app-generic, if flags say we can 2N/A * app-generic file exists, so 2N/A * use it as a single file ks 2N/A * app-generic dir exists, so use 2N/A * it as a multi-file keystore 2N/A /* app-specific keystore */ 2N/A /* app-generic keystore */ 2N/A /* single-file app-generic keystore */ 2N/A /* multi-file app-generic keystore */ 2N/A * lock_keystore - Locks a keystore for shared (read-only) 2N/A * or exclusive (read-write) access. 2N/A * The flags tell lock_keystore how to behave: 2N/A * KEYSTORE_ACCESS_READONLY 2N/A * opens keystore read-only. Attempts to modify results in an error 2N/A * KEYSTORE_ACCESS_READWRITE 2N/A * opens keystore read-write 2N/A * KEYSTORE_PATH_SOFT 2N/A * If the keystore file does not exist at <base>/<app> then 2N/A * use <base> as the path to the keystore. This can be used, 2N/A * for example, to access an app-specific keystore iff it 2N/A * exists, otherwise revert back to an app-generic keystore. 2N/A * KEYSTORE_PATH_HARD 2N/A * Always use the keystore located at <keystore_path>/<app>. 2N/A * they will be created. This is used to avoid falling 2N/A * back to an app-generic keystore path when the app-specific 2N/A * one does not exist. 2N/A * err - Error object to add errors to 2N/A * flags - Control flags (see above description) 2N/A * keystore - object which is being locked 2N/A * 0 - Success - Keystore file is locked, paths to 2N/A * appropriate files placed in keystore. 2N/A * non-zero - Failure, errors and reasons recorded in err 2N/A * no keystore. try to create an 2N/A * empty one so we can lock on it and 2N/A * prevent others from gaining 2N/A * exclusive access. It will be 2N/A * deleted when the keystore is closed. 2N/A /* ca file not a regular file! */ 2N/A /* does not exist. try to create an empty one */ 2N/A /* ca file not a regular file! */ 2N/A * unlock_keystore - Unocks a keystore 2N/A * err - Error object to add errors to 2N/A * keystore - keystore object to unlock 2N/A * 0 - Success - Keystore files are unlocked, files are closed, 2N/A * non-zero - Failure, errors and reasons recorded in err 2N/A * Release lock on the CA file. 2N/A * Delete file if it is empty 2N/A * read_keystore - Reads keystore files of disk, parses 2N/A * into internal structures. 2N/A * err - Error object to add errors to 2N/A * keystore - keystore object to read into 2N/A * cb - callback to get password, if required 2N/A * 0 - Success - Keystore files are read, and placed 2N/A * into keystore structure. 2N/A * non-zero - Failure, errors and reasons recorded in err 2N/A /* first read the ca file */ 2N/A /* Get password, using callback if necessary */ 2N/A /* decrypt and parse keystore file */ 2N/A /* could not parse the contents */ 2N/A * truststore is empty, so we don't have any trusted 2N/A * if there is no cl file or key file, use the cl's and key's found 2N/A * files are in separate files. read keys out of the keystore 2N/A * certs out of the certstore, if they are not empty 2N/A /* Get password, using callback if necessary */ 2N/A * password in client cert file 2N/A * the one in the other files! 2N/A /* could not parse the contents */ 2N/A /* Get password, using callback if necessary */ 2N/A /* could not parse the contents */ 2N/A * get_keystore_password - retrieves pasword used to 2N/A * decrypt PKCS12 structure. 2N/A * err - Error object to add errors to 2N/A * p12 - PKCS12 structure which returned password should 2N/A * cb - callback to collect password. 2N/A * keystore - The keystore in which the PKCS12 structure 2N/A * will eventually populate. 2N/A * keystore password is set in keystore->passphrase. 2N/A * B_FALSE - failure, errors logged 2N/A /* see if no password is the right password */ 2N/A /* oops, it's encrypted. get password */ 2N/A /* could not get password */ 2N/A /* wrong password */ 2N/A * make copy of password buffer, since it 2N/A * goes away upon return 2N/A * write_keystore - Writes keystore files to disk 2N/A * err - Error object to add errors to 2N/A * keystore - keystore object to write from 2N/A * passwd - password used to encrypt keystore 2N/A * 0 - Success - Keystore contents are written out to 2N/A * the same locations as read from 2N/A * non-zero - Failure, errors and reasons recorded in err 2N/A * keystore is a file. 2N/A * just write out a single file 2N/A * no keys or certs to write out, so 2N/A * blank the ca file. we do not 2N/A * delete it since it is used as a 2N/A * lock by lock_keystore() in 2N/A * subsequent invocations 2N/A * if the keystore is being created for the first time, 2N/A * prompt for a passphrase for encryption 2N/A * use the one used when the keystore 2N/A /* files are seprate. Do one at a time */ 2N/A * if the keystore is being created for the first time, 2N/A * prompt for a passphrase for encryption 2N/A /* use the one used when the keystore was read */ 2N/A /* do private keys first */ 2N/A /* do user certs next */ 2N/A /* finally do CA cert file */ 2N/A * nothing to write out, so truncate the file 2N/A * (it will be deleted during close_keystore) 2N/A * clear_keystore_file - Clears (zeros out) a keystore file. 2N/A * err - Error object to add errors to 2N/A * dest - Path of keystore file to zero out. 2N/A * 0 - Success - Keystore file is truncated to zero length 2N/A * non-zero - Failure, errors and reasons recorded in err 2N/A /* can't open for writing */ 2N/A /* not a regular file */ 2N/A * write_keystore_file - Writes keystore file to disk. 2N/A * Keystore files can possibly be corrupted by a variety 2N/A * routine, along with restore_keystore_file, tries to 2N/A * maintain keystore integity by writing the files 2N/A * out in a particular order, minimizing the time period 2N/A * that the keystore is in an indeterminate state. 2N/A * With the current implementation, there are some failures 2N/A * that are wholly unrecoverable, such as disk corruption. 2N/A * These routines attempt to minimize the risk, but not 2N/A * eliminate it. When better, atomic operations are available 2N/A * (such as a true database with commit, rollback, and 2N/A * guaranteed atomicity), this implementation should use that. 2N/A * err - Error object to add errors to 2N/A * dest - Destination filename 2N/A * contents - Contents to write to the file 2N/A * 0 - Success - Keystore contents are written out to 2N/A * non-zero - Failure, errors and reasons recorded in err 2N/A /* flush, then close */ 2N/A /* now back up the original file */ 2N/A /* put new one in its place */ 2N/A * read_keystore_file - Reads single keystore file 2N/A * off disk in PKCS12 format. 2N/A * err - Error object to add errors to 2N/A * file - File path to read 2N/A * PKCS12 contents of file, or NULL if an error occurred. 2N/A * errors recorded in 'err'. 2N/A * Locks the specified file. 2N/A * The caller would have to wait to get the 2N/A * lock on this file. 2N/A * Returns FALSE if the file is not locked; TRUE 2N/A * The caller would have to wait to get the 2N/A * lock on this file. 2N/A * The file is not locked. 2N/A * Unlocks the specified file. 2N/A * Determines if file has a length of 0 or not 2N/A /* file is empty if size = 0 or it doesn't exist */ 2N/A * Name: get_time_string 2N/A * Description: Generates a human-readable string from an ASN1_TIME 2N/A * Arguments: intime - The time to convert 2N/A * Returns : A pointer to a static string representing the passed-in time. 2N/A /* trim the end of the string */ 2N/A * check_password - do various password checks to see if the current password 2N/A * will work or we need to prompt for a new one. 2N/A * pass - password to check 2N/A * B_TRUE - Password is OK. 2N/A * B_FALSE - Password not valid. 2N/A * If password is zero length or NULL then try verifying both cases 2N/A * to determine which password is correct. The reason for this is that 2N/A * under PKCS#12 password based encryption no password and a zero 2N/A * length password are two different things...