kmsKeystoreUtil.c revision 4f14b0f29aa144cc03efdde5508ae126ae197acf
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*/
#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <strings.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <cryptoutil.h>
#include <unistd.h>
#include <utmpx.h>
#include <pthread.h>
#include <pwd.h>
#include <sha2.h>
#include <security/cryptoki.h>
#include <aes_impl.h>
#include "kmsSession.h"
#include "kmsGlobal.h"
#include "kmsObject.h"
static CK_RV
static char keystore_path[BUFSIZ];
static time_t last_objlist_mtime = 0;
0,
0,
0,
0,
0,
0,
{0, 0, 0, 0}
};
#define KEYSTORE_PATH "/var/kms"
#define ALTERNATE_KEYSTORE_PATH "KMSTOKEN_DIR"
#define KMS_PROFILE_FILENAME "profile.cfg"
#define KMS_DATAUNIT_DESCRIPTION "Oracle PKCS11/KMS"
#define KMS_ATTR_DESC_PFX "PKCS#11v2.20: "
#define KMSTOKEN_CONFIG_FILENAME "kmstoken.cfg"
#define KMSTOKEN_LABELLIST_FILENAME "objlabels.lst"
static void
{
}
static char *
{
long buflen;
if (buflen == -1)
return (username); /* should not happen */
return (username); /* zero-ed earlier */
return (username);
}
static char *
{
char *env_val;
if (!keystore_path_initialized) {
/*
* If it isn't set or is set to the empty string use the
* default location. We need to check for the empty string
* because some users "unset" environment variables by giving
* them no value, this isn't the same thing as removing it
* from the environment.
*/
(void) snprintf(keystore_path,
sizeof (keystore_path), "%s/%s",
} else {
sizeof (keystore_path));
}
}
return (keystore_path);
}
static char *
{
char *s = cfgbuf;
char *f;
/* check for comment sign */
if (*s == '#') {
/* skip the rest of the line */
s++;
}
s++;
}
if (s < end) {
char save, *e;
f = s; /* mark the beginning. */
/* Find the end of the line and null terminate it. */
save = *s;
*s = 0x00;
*s = save;
/* Strip trailing whitespace */
f = buf;
while (e >= f && isspace(*e)) {
*e = 0x00;
e--;
}
} else {
/* If we reached the end, return NULL */
s = NULL;
}
done:
return (s);
}
static int
{
int ret = 0;
(void) pthread_mutex_lock(mutex);
break;
}
(void) pthread_mutex_unlock(mutex);
return (ret);
}
/*
* Open the keystore description file in the specified mode.
* If the keystore doesn't exist, the "do_create_keystore"
* argument determines if the keystore should be created
*/
static int
{
int fd;
if (fd < 0)
return (fd);
if (fd > 0)
return (-1);
}
return (fd);
}
static int
{
if (fd == -1)
return (-1);
do {
break;
else
total += n;
total = -1;
return (total);
}
/*
* The KMS token is considered "initialized" if the file with the token
* configuration information is present.
*/
{
char *ksdir;
char cfgfile_path[BUFSIZ];
return (CKR_FUNCTION_FAILED);
else
return (rv);
}
static CK_RV
{
char *ptr;
return (CKR_ARGUMENTS_BAD);
return (CKR_FUNCTION_FAILED);
}
return (CKR_HOST_MEMORY);
return (CKR_FUNCTION_FAILED);
}
goto done;
}
if (ptr == 0) {
goto done;
}
if (ptr == 0) {
goto done;
}
if (ptr == 0) {
goto done;
}
if (ptr == 0) {
goto done;
}
if (ptr == 0) {
goto done;
}
if (ptr == 0) {
goto done;
}
done:
return (rv);
}
{
char *ksdir;
return (FALSE);
return (FALSE);
/*
* The PK12 file is only established once the user has enrolled
* and is thus considered having a PIN set.
*/
else
return (rv);
}
void
{
}
}
static void
{
int i;
return;
/* Remove trailing CR */
while (i > 0 && label[i] == '\n')
label[i--] = 0x00;
return;
}
/* see if this entry already exists */
} else {
/* It's a dup, don't add it */
}
}
{
char *ksdir;
return (CKR_GENERAL_ERROR);
/* Create it */
return (CKR_GENERAL_ERROR);
}
}
return (CKR_OK);
}
return (CKR_HOST_MEMORY);
return (CKR_FUNCTION_FAILED);
}
/* No change */
goto end;
}
/* If we got here, we need to refresh the entire list */
/*
* Read each line and add it as a label node.
*/
while (remain > 0) {
goto end;
}
}
end:
if (cfgbuf)
return (rv);
}
static CK_RV
{
/*
* The caller MUST provide a CKA_LABEL when deleting.
*/
return (rv);
}
/*
* Retrieve a data unit associated with the label.
*/
static CK_RV
{
/* Find the data unit that holds the key */
(const unsigned char *)externalUniqueId,
sizeof (externalUniqueId),
if (status != KMS_AGENT_STATUS_OK) {
return (GetPKCS11StatusFromAgentStatus(status));
}
return (CKR_OK);
}
static CK_RV
{
char *ptr;
/* If it doesn't start with the expected prefix, return */
return (rv);
/*
* Decode as follows:
* CK_OBJECT_CLASS (2 bytes)
* CK_KEY_TYPE (2 bytes)
* CKA_VALUE_LEN (4 bytes)
* CK_CERTIFICATE_TYPE (2 bytes - not used)
* CK_MECHANISM_TYPE (4 bytes)
* boolean attributes (3 bytes)
* extra attributes (1 byte)
* non-boolean attributes
*/
"%02lx%02lx%02x00%04lx%06llx00",
&keylen,
&boolattrs) != 5)
/* We didn't get the full set of attributes */
return (rv);
}
/*
* Create a new PKCS#11 object record for the KMSAgent_Key.
*/
static CK_RV
char *label,
kms_object_t **pObj)
{
CK_ATTRIBUTE template[] = {
};
newObj = kms_new_object();
return (CKR_HOST_MEMORY);
/*
* Decode the DataUnit description field to find various
* object attributes.
*/
if (rv) {
return (rv);
}
/*
* Set the template keytype and class according to the
* data parsed from the description.
*/
if (rv) {
return (rv);
}
return (rv);
}
static CK_RV
{
int keysLeft = 0;
(int * const)&keysLeft,
NULL, /* KeyID */
&kmskeys);
if (status != KMS_AGENT_STATUS_OK) {
return (GetPKCS11StatusFromAgentStatus(status));
}
return (rv);
}
/*
* Retrieve a key from KMS. We can't use "RetrieveKey" because
* we don't know the key id. Instead get all keys associated
* with our data unit (there should be only 1.
*/
{
return (rv);
return (CKR_GENERAL_ERROR);
return (rv);
}
{
return (rv);
/*
* If an object is not in the list, reload it from KMS.
*/
/* Search object list for matching object */
(void) pthread_mutex_unlock(
&pObj->object_mutex);
return (rv);
}
}
if (!found) {
/*
* Fetch KMS key and prepend it to the
* token object list for the slot.
*/
} else {
}
}
}
}
return (rv);
}
KMS_Initialize(void)
{
char *ksdir;
return (CKR_GENERAL_ERROR);
/*
* If the keystore directory doesn't exist, create it.
*/
return (CKR_GENERAL_ERROR);
}
}
return (GetPKCS11StatusFromAgentStatus(kmsrv));
}
return (CKR_OK);
}
{
last_objlist_mtime = 0;
return (KMSAgent_FinalizeLibrary() == KMS_AGENT_STATUS_OK) ?
}
const char *pOldPassword,
const char *pNewPassword)
{
(char * const)pOldPassword,
(char * const)pNewPassword);
return (GetPKCS11StatusFromAgentStatus(status));
}
{
char cfgfile_path[BUFSIZ];
char *ksdir = kms_get_keystore_path();
return (CKR_GENERAL_ERROR);
return (rv);
}
const char *pPassword,
{
char *sPassword;
char cfgfile_path[BUFSIZ];
char *ksdir;
return (CKR_FUNCTION_FAILED);
return (CKR_GENERAL_ERROR);
return (rv);
}
/* First, try to load existing profile */
return (GetPKCS11StatusFromAgentStatus(status));
}
static CK_RV
{
switch (status) {
case KMS_AGENT_STATUS_OK:
return (CKR_OK);
return (CKR_GENERAL_ERROR);
return (CKR_HOST_MEMORY);
return (CKR_ARGUMENTS_BAD);
return (CKR_CRYPTOKI_NOT_INITIALIZED);
return (CKR_DEVICE_MEMORY);
return (CKR_GENERAL_ERROR);
return (CKR_USER_ANOTHER_ALREADY_LOGGED_IN);
return (CKR_DEVICE_ERROR);
return (CKR_PIN_INCORRECT);
default:
return (CKR_GENERAL_ERROR);
}
}
void
{
(void) KMSAgent_UnloadProfile(kmsProfile);
}
/*
* kms_update_label_file
*
* KMS doesn't provide an API to allow one to query for available
* data units (which map 1-1 to keys). To allow for PKCS11 to
* query for a list of available objects, we keep a local list
* and update it when an object is added or deleted.
*/
static CK_RV
{
int fd;
return (CKR_GENERAL_ERROR);
return (CKR_HOST_MEMORY);
return (CKR_GENERAL_ERROR);
}
/* Lock it even though its a temporary file */
return (rv);
}
}
/* Update the last mtime */
}
return (rv);
}
/*
* Destroy a key in the KMS by disassociating an entire data unit.
* The KMSAgent API does not have an interface for destroying an
* individual key.
*/
{
avl_index_t where = 0;
/*
* The caller MUST provide a CKA_LABEL when deleting.
*/
return (rv);
}
return (rv);
/*
* Remove the label from the label list and update
* the file that tracks active keys.
*/
/* rewrite the list of labels to disk */
if (rv)
/* Ignore error here */
return (GetPKCS11StatusFromAgentStatus(status));
}
void
{
char *ptr;
/*
* Encode as follows:
* CK_OBJECT_CLASS (2 bytes)
* CK_KEY_TYPE (2 bytes)
* CKA_VALUE_LEN (4 bytes)
* CK_CERTIFICATE_TYPE (2 bytes - not used)
* CK_MECHANISM_TYPE (4 bytes)
* boolean attributes (3 bytes)
* extra attributes (1 byte)
* non-boolean attributes
*/
"%02x%02x%02x00%04x%06x00",
32,
}
{
char label[128];
/*
* The caller MUST provide a CKA_LABEL for storing in the KMS.
*/
return (rv);
}
/* Encode attributes in Description */
sizeof (pDescription));
(const unsigned char *)externalUniqueId,
sizeof (externalUniqueId),
label, /* externalTag */
&oDataUnit);
/*
* If the DataUnit exists, check to see if it has any keys.
* If it has no keys, then it is OK to continue.
*/
int numkeys = 0;
return (rv);
/*
* This would be better if there were PKCS#11
* error codes for duplicate objects or
* something like that.
*/
return (CKR_ARGUMENTS_BAD);
/* If no keys associated with data unit, continue */
}
if (status != KMS_AGENT_STATUS_OK) {
return (GetPKCS11StatusFromAgentStatus(status));
}
if (status != KMS_AGENT_STATUS_OK) {
/*
* Clean up the old data unit.
*/
return (GetPKCS11StatusFromAgentStatus(status));
}
/*
* KMS Agent only creates AES-256 keys, so ignore what the user
* requested at this point.
*/
return (CKR_HOST_MEMORY);
}
/*
* Add the label to the local list of available objects
*/
return (GetPKCS11StatusFromAgentStatus(status));
}