nss_spi.c revision 2cbed7292737821015ab481353eb10e8346b2c05
/*
* 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
*/
/*
* NSS keystore wrapper
*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <errno.h>
#include <fcntl.h>
#include <synch.h>
#include <kmfapiP.h>
#include <ber_der.h>
/* NSS related headers */
#include <mps/cryptohi.h>
#include <mps/pk11func.h>
#define NSS_OK 0
static int nss_initialized = 0;
void
NSS_GetErrorString(KMF_HANDLE_T, char **);
static
{
1, /* Version */
NULL /* ListCRL */,
NULL, /* VerifyData */
NULL /* Finalize */
};
/* additions for importing and exporting PKCS 12 files */
typedef struct p12uContextStr {
char *filename; /* name of file */
int errorValue; /* which error occurred? */
} p12uContext;
{
return (&nss_plugin_table);
}
static char *
/*ARGSUSED*/
{
if (retry)
return (NULL);
else
return (NULL);
}
static KMF_RETURN
{
/* If a password was given, try to login to the slot */
return (KMF_ERR_BAD_PARAMETER);
}
return (KMF_OK);
}
if (nssrv != SECSuccess) {
return (KMF_ERR_AUTH_FAILED);
}
return (KMF_OK);
}
static SECStatus
Init_NSS_DBs(const char *configdir,
const char *certPrefix,
const char *keyPrefix,
const char *secmodName)
{
(void) mutex_lock(&init_lock);
/* If another thread already did it, return OK. */
if (nss_initialized) {
(void) mutex_unlock(&init_lock);
return (SECSuccess);
}
if (rv != SECSuccess) {
goto end;
}
end:
(void) mutex_unlock(&init_lock);
return (rv);
}
/*
* When it is called the first time, it will intialize NSS. Once the NSS
* is initialized, this function returns KMF_KEYSTORE_ALREADY_INITIALIZED
* if it is called again.
*/
{
char *configdir;
char *certPrefix;
char *keyPrefix;
char *secModName;
(void) mutex_lock(&init_lock);
if (nss_initialized == 0) {
(void) mutex_unlock(&init_lock);
if (err != SECSuccess) {
return (KMF_ERR_INTERNAL);
}
} else {
(void) mutex_unlock(&init_lock);
}
return (rv);
}
/*
* This function sets up the slot to be used for other operations.
* This function is basically called by every NSS SPI function.
* For those functions that can only be performed in the internal slot, the
* boolean "internal_slot_only" argument needs to be TRUE.
* A slot pointer will be returned when this function is executed successfully.
*/
{
if (!nss_initialized)
return (KMF_ERR_PLUGIN_INIT);
/*
* NSS Is already initialized, but we need to find
* the right slot.
*/
} else if (internal_slot_only == TRUE) {
goto end;
} else {
}
goto end;
}
/*
* If the token was not yet initialized, return an error.
*/
if (PK11_NeedUserInit(*nss_slot)) {
}
end:
return (rv);
}
static KMF_RETURN
{
NULL) {
return (KMF_ERR_MEMORY);
}
return (KMF_OK);
}
static KMF_RETURN
{
*num_certs = 0;
*num_certs = 0;
return (KMF_ERR_CERT_NOT_FOUND);
} else {
*num_certs = 1;
}
switch (find_criteria) {
case KMF_ALL_CERTS:
break;
case KMF_NONEXPIRED_CERTS:
PR_FALSE);
if (validity != secCertTimeValid) {
/* this is an invalid cert, reject it */
*num_certs = 0;
return (KMF_OK);
}
break;
case KMF_EXPIRED_CERTS:
PR_FALSE);
if (validity == secCertTimeValid) {
/* this is a valid cert, reject it in this case. */
*num_certs = 0;
return (KMF_OK);
}
break;
default:
return (KMF_ERR_BAD_PARAMETER);
}
/* We copied the data we need, so cleanup the internal record */
*num_certs = 0;
return (rv);
}
static KMF_RETURN
{
return (rv);
findIssuer = TRUE;
}
return (rv);
findSubject = TRUE;
}
findSerial = TRUE;
if (list) {
if (findIssuer) {
&cmpDN);
kmf_free_dn(&cmpDN);
if (!match)
goto delete_and_cont;
} else {
goto delete_and_cont;
}
}
if (findSubject) {
&cmpDN);
kmf_free_dn(&cmpDN);
if (!match)
goto delete_and_cont;
} else {
goto delete_and_cont;
}
}
if (findSerial) {
goto delete_and_cont;
goto delete_and_cont;
}
/* select the certs using find criteria */
switch (find_criteria) {
case KMF_ALL_CERTS:
break;
case KMF_NONEXPIRED_CERTS:
if (ret == SECFailure) {
/* this is an invalid cert */
goto skip;
}
break;
case KMF_EXPIRED_CERTS:
if (ret != SECFailure) {
/* this is a valid cert */
goto skip;
}
break;
}
skip:
continue;
}
}
} else {
}
return (rv);
}
static KMF_RETURN
convertCertList(void *kmfhandle,
{
if (maxcerts == 0)
maxcerts = 0xFFFFFFFF;
*numcerts = 0;
/*
* Don't copy more certs than the caller wanted.
*/
}
/*
* If we failed, delete any certs allocated so far.
*/
int i;
for (i = 0; i < *numcerts; i++)
*numcerts = 0;
}
return (rv);
}
{
return (KMF_ERR_BAD_PARAMETER);
}
return (rv);
return (KMF_ERR_BAD_PARAMETER);
if (maxcerts == 0)
maxcerts = 0xFFFFFFFF;
*num_certs = 0;
/* Get the optional returned certificate list */
/* Get optional search criteria attributes */
}
/* This will only find 1 certificate */
validity);
} else {
/*
* Build a list of matching certs.
*/
/*
* If the caller supplied a pointer to storage for
* a list of certs, convert up to 'maxcerts' of the
* matching certs.
*/
&maxcerts);
}
}
}
return (rv);
}
void
/*ARGSUSED*/
{
}
}
}
}
{
int nssrv;
return (KMF_ERR_BAD_PARAMETER);
}
return (rv);
/* Get the search criteria attributes. They are all optional. */
}
/* Start finding the matched certificates and delete them. */
return (KMF_ERR_CERT_NOT_FOUND);
}
switch (validity) {
case KMF_ALL_CERTS:
break;
case KMF_NONEXPIRED_CERTS:
if (nssrv == SECFailure) {
/* this is an invalid cert - skip it */
goto out;
}
break;
case KMF_EXPIRED_CERTS:
if (nssrv != SECFailure) {
/* this is a valid cert - skip it */
goto out;
}
break;
}
/* delete it from database */
if (nssrv) {
}
} else {
if (nssrv) {
}
}
}
}
out:
}
}
return (rv);
}
static void
InitRandom(char *filename)
{
char buf[2048];
int fd;
if (!fd)
return;
if (count > 0) {
}
}
{
void *nssparams;
return (KMF_ERR_BAD_PARAMETER);
}
return (rv);
}
return (rv);
return (rv);
}
/* "storekey" is optional. Default is TRUE */
/* keytype is optional. KMF_RSA is default */
&keylen, &keylen_size);
if (rv == KMF_ERR_ATTR_NOT_FOUND)
/* Default keylen = 1024 */
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
/* Now fill in the label value */
goto cleanup;
}
}
/* Get some random bits */
InitRandom("/dev/urandom");
/*
* NSS only allows for a 4 byte exponent.
* Ignore the exponent parameter if it is too big.
*/
}
}
int ks;
if (nssrv != SECSuccess) {
goto cleanup;
}
}
goto cleanup;
}
} else {
goto cleanup;
}
storekey, /* isPermanent */
PR_TRUE, /* isSensitive */
} else {
(void) PK11_SetPrivateKeyNickname(NSSprivkey,
keylabel);
}
/* Now, convert it to a KMF_KEY object for the framework */
}
if (NSSpubkey)
if (NSSprivkey)
}
if (keylabel)
return (rv);
}
{
signed_data.data = 0;
return (KMF_ERR_BAD_PARAMETER);
/* Map the OID to a NSS algorithm */
if (AlgId == KMF_ALGID_NONE)
return (KMF_ERR_BAD_PARAMETER);
if (AlgId == KMF_ALGID_MD5WithRSA)
else if (AlgId == KMF_ALGID_MD2WithRSA)
else if (AlgId == KMF_ALGID_SHA1WithRSA)
else if (AlgId == KMF_ALGID_SHA1WithDSA)
else
return (KMF_ERR_BAD_PARAMETER);
if (rv != 0) {
return (KMF_ERR_INTERNAL);
}
} else {
}
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
}
} else {
}
} else {
}
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
}
/*
* "delete_token" means to clear it from the token storage as well
* as from memory.
*/
return (KMF_ERR_BAD_PARAMETER);
(void *)&delete_token, NULL);
/* "delete_token" is optional. Default is TRUE */
if (delete_token) {
return (KMF_ERR_BAD_KEY_CLASS);
return (rv);
}
return (KMF_ERR_BAD_PARAMETER);
return (rv);
}
if (nssrv == SECSuccess)
}
if (nssrv != SECSuccess) {
}
} else {
} else {
return (KMF_ERR_BAD_KEY_CLASS);
}
}
return (rv);
}
{
char *str;
/* Get the error string in the default language */
} else {
}
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
}
return (rv);
/* Get the credential */
return (KMF_ERR_BAD_PARAMETER);
return (rv);
/* Get the key handle */
return (KMF_ERR_BAD_PARAMETER);
/* Get the cert data and decode it */
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_BAD_CERT_FORMAT);
}
return (KMF_ERR_KEY_NOT_FOUND);
}
return (KMF_OK);
}
{
unsigned int total_decrypted = 0, modulus_len = 0;
int i, blocks;
return (KMF_ERR_BAD_PARAMETER);
for (i = 0; i < blocks; i++) {
if (rv != 0) {
return (KMF_ERR_INTERNAL);
}
}
return (ret);
}
static KMF_KEY_ALG
{
switch (type) {
case CKK_RSA:
return (KMF_RSA);
case CKK_DSA:
return (KMF_RSA);
case CKK_AES:
return (KMF_AES);
case CKK_RC4:
return (KMF_RC4);
case CKK_DES:
return (KMF_DES);
case CKK_DES3:
return (KMF_DES3);
default:
/* not supported */
return (KMF_KEYALG_NONE);
}
}
{
int count;
char *findLabel;
char *nick;
int match = 0;
return (KMF_ERR_BAD_PARAMETER);
}
return (KMF_ERR_BAD_PARAMETER);
return (rv);
}
/* It is OK if this is NULL, we dont need a cred to find public keys */
return (rv);
}
}
if (maxkeys == 0)
maxkeys = 0xFFFFFFFF;
*numkeys = 0;
return (KMF_ERR_BAD_PARAMETER);
if (keyclass == KMF_ASYM_PUB) {
goto cleanup;
}
} else if (keyclass == KMF_ASYM_PRI) {
goto cleanup;
}
} else if (keyclass == KMF_SYMMETRIC) {
goto cleanup;
}
} else {
goto cleanup;
}
/* it is okay to have "keys" contains NULL */
if (keyclass == KMF_ASYM_PUB) {
match = 0;
/*
* Due to bug in NSS, we have to manually match
* the labels to be sure we have a match.
*/
if (findLabel) {
} else {
/* always match if findLabel is NULL */
match = 1;
}
}
if (match)
count++;
}
} else if (keyclass == KMF_ASYM_PRI) {
match = 0;
/*
* Due to bug in NSS, we have to manually match
* the labels to be sure we have a match.
*/
if (findLabel) {
} else {
/* always match if findLabel is NULL */
match = 1;
}
}
if (match)
count++;
}
} else if (keyclass == KMF_SYMMETRIC) {
count = 0;
match = 0;
/*
* If keytype is specified in the searching parameter,
* check the keytype and skip the key if its keytype
* doesn't match.
*/
/* free that key since we arent using it */
continue;
}
/*
* Due to bug in NSS, we have to manually match
* the labels to be sure we have a match.
*/
if (findLabel) {
} else {
/* always match if findLabel is NULL */
match = 1;
}
} else {
}
if (match)
count++;
}
/*
* Cleanup memory for unused keys.
*/
}
}
}
return (rv);
}
static SECStatus
{
unsigned int i;
unsigned char a;
return (SECFailure);
}
}
return (SECSuccess);
}
static PRBool
unsigned char *inBuf,
unsigned int inBufLen,
unsigned char *outBuf,
unsigned int maxOutBufLen,
unsigned int *outBufLen,
{
/*
* If converting Unicode to ASCII, swap bytes before conversion
* as neccessary.
*/
return (PR_FALSE);
}
}
/* Perform the conversion. */
if (dup)
return (ret);
}
static PRBool
{
return (PR_FALSE);
}
if (fileRead) {
} else {
}
return (PR_FALSE);
}
return (PR_TRUE);
}
static void
{
return;
}
}
if (removeFile) {
}
}
}
static p12uContext *
{
if (!p12ctx) {
return (NULL);
}
p12ctx->errorValue = 0;
return (NULL);
}
return (p12ctx);
}
static void
{
int writeLen;
return;
}
return;
}
}
}
#define HANDLE_NSS_ERROR(r) {\
rv = r; \
goto out; }
static KMF_RETURN
{
if (PK11_IsFIPS()) {
} else {
}
goto out;
}
!= SECSuccess) {
}
out:
return (rv);
}
{
return (KMF_ERR_BAD_PARAMETER);
}
return (rv);
return (KMF_ERR_BAD_PARAMETER);
return (rv);
return (KMF_ERR_BAD_PARAMETER);
numattr);
return (KMF_ERR_BAD_PARAMETER);
/* Get optional search criteria attributes */
/*
* Find the certificate(s) first.
*/
}
} else {
&certlist, 0);
return (KMF_ERR_CERT_NOT_FOUND);
}
return (rv);
}
/*
* The KMF_CREDENTIAL holds the password to use for
* encrypting the PKCS12 key information.
*/
if (!p12ctx) {
}
if (!p12ecx) {
}
!= SECSuccess) {
}
/*
* NSS actually supports storing a list of keys and certs
* in the PKCS#12 PDU. Nice feature.
*/
}
}
!= SECSuccess) {
}
out:
if (nsscert)
if (certlist)
if (p12ctx)
if (p12ecx)
return (rv);
}
{
int keySize;
return (KMF_ERR_BAD_PARAMETER);
}
return (KMF_ERR_BAD_PARAMETER);
NULL);
return (KMF_ERR_BAD_PARAMETER);
&keylen_size);
if (rv == KMF_ERR_ATTR_NOT_FOUND &&
/* keylength is not required for DES and 3DES */
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_BAD_PARAMETER);
switch (keytype) {
case KMF_AES:
return (KMF_ERR_BAD_KEY_SIZE);
break;
case KMF_RC4:
return (KMF_ERR_BAD_KEY_SIZE);
break;
case KMF_DES:
keySize = 0; /* required by PK11_TokenKeyGen() */
break;
case KMF_DES3:
keySize = 0; /* required by PK11_TokenKeyGen() */
break;
case KMF_GENERIC_SECRET:
return (KMF_ERR_BAD_KEY_SIZE);
break;
default:
goto out;
}
return (rv);
}
return (KMF_ERR_BAD_PARAMETER);
return (rv);
}
goto out;
}
if (nssrv != SECSuccess) {
goto out;
}
out:
}
return (rv);
}
{
return (KMF_ERR_UNINITIALIZED);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_BAD_KEY_CLASS);
return (KMF_ERR_BAD_KEYHANDLE);
return (KMF_ERR_MEMORY);
} else {
return (KMF_ERR_BAD_KEYHANDLE);
if (nss_rv != SECSuccess) {
goto out;
}
goto out;
}
goto out;
}
rv = KMF_ERR_MEMORY;
goto out;
}
}
out:
return (rv);
}
{
int rv;
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_BAD_PARAMETER);
/* If it was uninitialized, set it */
if (ret == KMF_ERR_UNINITIALIZED_TOKEN) {
if (rv != SECSuccess) {
} else {
}
return (ret);
}
if (rv != SECSuccess) {
}
}
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
}
return (rv);
}
return (KMF_ERR_BAD_PARAMETER);
return (rv);
}
/* look for private key */
numattr);
/* look for raw key */
}
/* If no keys were found, return error */
return (KMF_ERR_ATTR_NOT_FOUND);
}
return (rv);
/*
* Decode the cert into an NSS CERT object so we can access the
* SPKI and KeyUsage data later.
*/
goto cleanup;
}
goto cleanup;
goto cleanup;
}
}
if (pk == CK_INVALID_HANDLE) {
}
PR_TRUE);
if (pk == CK_INVALID_HANDLE) {
}
/* We stored it, but don't need the handle anymore */
}
return (rv);
}
/*
* This function is called by NSS_StoreCert() and NSS_ImportCert().
* The "label" and "trust_flag" arguments can be NULL.
*/
static KMF_RETURN
char *label, char *trust_flag)
{
return (KMF_ERR_BAD_PARAMETER);
goto out;
}
/* Store the cert into the NSS database */
label, 0);
if (nss_rv) {
goto out;
}
/* If trust_flag is NULL, then we are done */
if (trust_flag == NULL)
goto out;
goto out;
}
if (nss_rv) {
goto out;
}
if (nss_rv) {
}
out:
}
}
return (ret);
}
{
char *trust_flag = NULL;
return (KMF_ERR_BAD_PARAMETER);
}
return (ret);
/* Get the cert data */
return (KMF_ERR_BAD_PARAMETER);
/* The label attribute is optional */
/* The trustflag attriburte is optional */
out:
}
return (ret);
}
{
char *trust_flag = NULL;
return (KMF_ERR_BAD_PARAMETER);
}
return (ret);
/* Get the input cert filename attribute */
return (KMF_ERR_BAD_PARAMETER);
/* Check the cert file and auto-detect the file format of it. */
return (ret);
return (ret);
}
/*
* If the imported cert is in PEM format, convert it to
* DER format in order to store it in NSS token.
*/
if (format == KMF_FORMAT_PEM) {
int derlen;
goto cleanup;
}
} else {
}
if (format == KMF_FORMAT_PEM) {
}
return (ret);
}
{
int importOptions;
char *crlfilename;
return (KMF_ERR_BAD_PARAMETER);
}
return (ret);
}
numattr);
if (crlfilename == NULL)
return (KMF_ERR_BAD_CRLFILE);
/*
* Check if the input CRL file is a valid CRL file and auto-detect
* the encoded format of the file.
*/
return (ret);
/* set importOptions */
} else {
}
/* Read in the CRL file */
return (ret);
}
/* If the input CRL is in PEM format, convert it to DER first. */
if (format == KMF_FORMAT_PEM) {
int len;
goto out;
}
}
goto out;
}
out:
}
}
}
}
return (ret);
}
{
char *issuername, *subjectname;
/* check params */
return (KMF_ERR_BAD_PARAMETER);
}
return (rv);
}
numattr);
numattr);
/* Caller must specify issuer or subject but not both */
return (KMF_ERR_BAD_PARAMETER);
/* Find the CRL based on the deletion criteria. */
if (issuername != NULL) {
/*
* If the deletion is based on the issuer's certificate
* nickname, we will get the issuer's cert first, then
* get the CRL from the cert.
*/
if (!cert) {
goto out;
}
goto out;
}
} else {
/*
* If the deletion is based on the CRL's subject name, we will
* get all the CRLs from the internal database and search
* for the CRL with the same subject name.
*/
int nssrv;
if (nssrv) {
goto out;
}
goto out;
}
/* Allocate space for name */
rv = KMF_ERR_MEMORY;
goto out;
}
rv = KMF_ERR_MEMORY;
goto out;
}
if (!name) {
break;
}
break;
}
/* We found a cert but no CRL */
}
}
}
if (rv) {
goto out;
}
}
if (crl) {
(void) SEC_DeletePermCRL(crl);
}
out:
}
}
}
}
}
return (rv);
}
{
int crl_num;
int i, *CRLCount;
char **CRLNameList;
return (KMF_ERR_BAD_PARAMETER);
}
return (rv);
}
return (KMF_ERR_BAD_PARAMETER);
/* Look up Crls */
if (nssrv) {
goto out;
}
/* Allocate space for name first */
rv = KMF_ERR_MEMORY;
goto out;
}
rv = KMF_ERR_MEMORY;
goto out;
}
/*
* Loop thru the crlList and create a crl list with CRL's subject name.
*/
crl_num = 0;
while (crlNode) {
char *subj_name;
/* Get the CRL subject name */
if (!name) {
break;
}
if (CRLNameList != NULL) {
break;
}
rv = KMF_ERR_MEMORY;
break;
}
}
crl_num++;
}
/* success */
}
out:
}
}
}
/* If failed, free memory allocated for the returning rlist */
for (i = 0; i < crl_num; i++) {
free(CRLNameList[i]);
}
}
return (rv);
}
{
int i;
char *certlabel;
/* check params */
return (KMF_ERR_BAD_PARAMETER);
}
return (rv);
}
/* Find the certificate first */
} else {
return (KMF_ERR_BAD_PARAMETER);
}
goto out;
}
/* Find the CRL with the same issuer as the given certificate. */
/*
* Could not find the CRL issued by the same issuer. This
* usually means that the CRL is not installed in the DB.
*/
goto out;
}
/* Check if the certificate's serialNumber is revoked in the CRL */
i = 0;
break;
}
}
if (!match) {
}
out:
}
}
}
return (rv);
}