/* * 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 * or http://www.opensolaris.org/os/licensing. * 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 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include /* NSS related headers */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define NSS_OK 0 mutex_t init_lock = DEFAULTMUTEX; static int nss_initialized = 0; KMF_RETURN NSS_ConfigureKeystore(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_FindCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); void NSS_FreeKMFCert(KMF_HANDLE_T, KMF_X509_DER_CERT *); KMF_RETURN NSS_StoreCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_ImportCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_DeleteCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_CreateKeypair(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_StoreKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *); KMF_RETURN NSS_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *, KMF_DATA *, KMF_DATA *); KMF_RETURN NSS_ImportCRL(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_DeleteCRL(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_FindCRL(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_FindKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_FindCertInCRL(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_GetErrorString(KMF_HANDLE_T, char **); KMF_RETURN NSS_DeleteKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_FindPrikeyByCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *, KMF_DATA *, KMF_DATA *); KMF_RETURN NSS_ExportPK12(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_CreateSymKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); KMF_RETURN NSS_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *); KMF_RETURN NSS_SetTokenPin(KMF_HANDLE_T, int, KMF_ATTRIBUTE *); static KMF_PLUGIN_FUNCLIST nss_plugin_table = { 1, /* Version */ NSS_ConfigureKeystore, NSS_FindCert, NSS_FreeKMFCert, NSS_StoreCert, NSS_ImportCert, NSS_ImportCRL, NSS_DeleteCert, NSS_DeleteCRL, NSS_CreateKeypair, NSS_FindKey, NSS_EncodePubKeyData, NSS_SignData, NSS_DeleteKey, NULL /* ListCRL */, NSS_FindCRL, NSS_FindCertInCRL, NSS_GetErrorString, NSS_FindPrikeyByCert, NSS_DecryptData, NSS_ExportPK12, NSS_CreateSymKey, NSS_GetSymKeyValue, NSS_SetTokenPin, NSS_StoreKey, NULL /* Finalize */ }; /* additions for importing and exporting PKCS 12 files */ typedef struct p12uContextStr { char *filename; /* name of file */ PRFileDesc *file; /* pointer to file */ PRBool error; /* error occurred? */ int errorValue; /* which error occurred? */ } p12uContext; #define SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_NSS; \ h->lasterr.errcode = c; KMF_PLUGIN_FUNCLIST * KMF_Plugin_Initialize() { (void) SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1); (void) SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1); (void) SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1); (void) SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1); (void) SEC_PKCS12EnableCipher(PKCS12_DES_56, 1); (void) SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1); (void) SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1); return (&nss_plugin_table); } static char * /*ARGSUSED*/ nss_getpassword(PK11SlotInfo *slot, PRBool retry, void *arg) { if (retry) return (NULL); if (arg != NULL) return ((char *)strdup(arg)); else return (NULL); } static KMF_RETURN nss_authenticate(KMF_HANDLE_T handle, PK11SlotInfo *nss_slot, KMF_CREDENTIAL *cred) { SECStatus nssrv = SECSuccess; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; /* If a password was given, try to login to the slot */ if (cred == NULL || cred->cred == NULL || cred->credlen == 0 || nss_slot == NULL) { return (KMF_ERR_BAD_PARAMETER); } if (PK11_IsLoggedIn(nss_slot, NULL)) { return (KMF_OK); } PK11_SetPasswordFunc(nss_getpassword); nssrv = PK11_Authenticate(nss_slot, PR_TRUE, (void *)cred->cred); if (nssrv != SECSuccess) { SET_ERROR(kmfh, nssrv); PK11_FreeSlot(nss_slot); 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) { SECStatus rv = NSS_OK; (void) mutex_lock(&init_lock); /* If another thread already did it, return OK. */ if (nss_initialized) { (void) mutex_unlock(&init_lock); return (SECSuccess); } rv = NSS_Initialize((configdir && strlen(configdir)) ? configdir : "./", certPrefix, keyPrefix, secmodName ? secmodName : "secmod.db", NSS_INIT_COOPERATE); if (rv != SECSuccess) { goto end; } nss_initialized++; 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. */ KMF_RETURN NSS_ConfigureKeystore(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN rv = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; char *configdir; char *certPrefix; char *keyPrefix; char *secModName; configdir = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr); certPrefix = kmf_get_attr_ptr(KMF_CERTPREFIX_ATTR, attrlist, numattr); keyPrefix = kmf_get_attr_ptr(KMF_KEYPREFIX_ATTR, attrlist, numattr); secModName = kmf_get_attr_ptr(KMF_SECMODNAME_ATTR, attrlist, numattr); (void) mutex_lock(&init_lock); if (nss_initialized == 0) { SECStatus err; (void) mutex_unlock(&init_lock); err = Init_NSS_DBs(configdir, certPrefix, keyPrefix, secModName); if (err != SECSuccess) { SET_ERROR(kmfh, err); return (KMF_ERR_INTERNAL); } } else { rv = KMF_KEYSTORE_ALREADY_INITIALIZED; (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. */ KMF_RETURN do_nss_init(void *handle, int numattr, KMF_ATTRIBUTE *attrlist, boolean_t internal_slot_only, PK11SlotInfo **nss_slot) { KMF_RETURN rv = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; char *slotlabel = NULL; if (!nss_initialized) return (KMF_ERR_PLUGIN_INIT); slotlabel = kmf_get_attr_ptr(KMF_TOKEN_LABEL_ATTR, attrlist, numattr); /* * NSS Is already initialized, but we need to find * the right slot. */ if (slotlabel == NULL || strcmp(slotlabel, "internal") == 0) { *nss_slot = PK11_GetInternalKeySlot(); } else if (internal_slot_only == TRUE) { rv = KMF_ERR_SLOTNAME; goto end; } else { *nss_slot = PK11_FindSlotByName(slotlabel); } if (*nss_slot == NULL) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_SLOTNAME; goto end; } /* * If the token was not yet initialized, return an error. */ if (PK11_NeedUserInit(*nss_slot)) { rv = KMF_ERR_UNINITIALIZED_TOKEN; } end: return (rv); } static KMF_RETURN nss2kmf_cert(CERTCertificate *nss_cert, KMF_X509_DER_CERT *kmf_cert) { kmf_cert->kmf_private.keystore_type = KMF_KEYSTORE_NSS; kmf_cert->kmf_private.flags = KMF_FLAG_CERT_VALID; kmf_cert->certificate.Length = nss_cert->derCert.len; if ((kmf_cert->certificate.Data = malloc(nss_cert->derCert.len)) == NULL) { kmf_cert->certificate.Length = 0; return (KMF_ERR_MEMORY); } (void) memcpy(kmf_cert->certificate.Data, nss_cert->derCert.data, nss_cert->derCert.len); if (nss_cert->nickname != NULL) kmf_cert->kmf_private.label = (char *)strdup(nss_cert->nickname); return (KMF_OK); } static KMF_RETURN nss_getcert_by_label(KMF_HANDLE *kmfh, char *name, KMF_X509_DER_CERT *kmf_cert, uint32_t *num_certs, KMF_CERT_VALIDITY find_criteria) { KMF_RETURN rv = KMF_OK; CERTCertificate *nss_cert; SECCertTimeValidity validity; nss_cert = PK11_FindCertFromNickname(name, NULL); if (nss_cert == NULL) { *num_certs = 0; SET_ERROR(kmfh, PORT_GetError()); *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: validity = CERT_CheckCertValidTimes(nss_cert, PR_Now(), PR_FALSE); if (validity != secCertTimeValid) { /* this is an invalid cert, reject it */ *num_certs = 0; CERT_DestroyCertificate(nss_cert); return (KMF_OK); } break; case KMF_EXPIRED_CERTS: validity = CERT_CheckCertValidTimes(nss_cert, PR_Now(), PR_FALSE); if (validity == secCertTimeValid) { /* this is a valid cert, reject it in this case. */ *num_certs = 0; CERT_DestroyCertificate(nss_cert); return (KMF_OK); } break; default: return (KMF_ERR_BAD_PARAMETER); } if (kmf_cert != NULL) rv = nss2kmf_cert(nss_cert, kmf_cert); /* We copied the data we need, so cleanup the internal record */ CERT_DestroyCertificate(nss_cert); if (rv != KMF_OK) *num_certs = 0; return (rv); } static KMF_RETURN nss_find_matching_certs(PK11SlotInfo *slot, char *issuer, char *subject, KMF_BIGINT *serial, CERTCertList **certlist, KMF_CERT_VALIDITY find_criteria) { KMF_RETURN rv = KMF_OK; SECStatus ret; CERTCertList *list; CERTCertListNode *node; KMF_X509_NAME issuerDN, subjectDN; boolean_t findIssuer = FALSE; boolean_t findSubject = FALSE; boolean_t findSerial = FALSE; if (issuer != NULL && strlen(issuer)) { rv = kmf_dn_parser(issuer, &issuerDN); if (rv != KMF_OK) return (rv); findIssuer = TRUE; } if (subject != NULL && strlen(subject)) { rv = kmf_dn_parser(subject, &subjectDN); if (rv != KMF_OK) return (rv); findSubject = TRUE; } if (serial != 0 && serial->val != NULL && serial->len > 0) findSerial = TRUE; list = PK11_ListCertsInSlot(slot); if (list) { node = CERT_LIST_HEAD(list); while (!CERT_LIST_END(node, list)) { KMF_X509_NAME cmpDN; KMF_DATA der; boolean_t match; CERTCertListNode *freenode; if (findIssuer) { der.Data = node->cert->derIssuer.data; der.Length = node->cert->derIssuer.len; rv = DerDecodeName(&der, &cmpDN); if (rv == KMF_OK) { match = !KMF_CompareRDNs(&issuerDN, &cmpDN); kmf_free_dn(&cmpDN); if (!match) goto delete_and_cont; } else { goto delete_and_cont; } } if (findSubject) { der.Data = node->cert->derSubject.data; der.Length = node->cert->derSubject.len; rv = DerDecodeName(&der, &cmpDN); if (rv == KMF_OK) { match = !KMF_CompareRDNs(&subjectDN, &cmpDN); kmf_free_dn(&cmpDN); if (!match) goto delete_and_cont; } else { goto delete_and_cont; } } if (findSerial) { SECItem *sernum; sernum = &node->cert->serialNumber; if (serial->len != sernum->len) goto delete_and_cont; if (memcmp(sernum->data, serial->val, serial->len)) goto delete_and_cont; } /* select the certs using find criteria */ switch (find_criteria) { case KMF_ALL_CERTS: break; case KMF_NONEXPIRED_CERTS: ret = CERT_CertTimesValid(node->cert); if (ret == SECFailure) { /* this is an invalid cert */ goto skip; } break; case KMF_EXPIRED_CERTS: ret = CERT_CertTimesValid(node->cert); if (ret != SECFailure) { /* this is a valid cert */ goto skip; } break; } skip: node = CERT_LIST_NEXT(node); continue; delete_and_cont: freenode = node; node = CERT_LIST_NEXT(node); CERT_RemoveCertListNode(freenode); } } if (rv == KMF_OK && certlist != NULL) { *certlist = list; } else { CERT_DestroyCertList(list); } return (rv); } static KMF_RETURN convertCertList(void *kmfhandle, CERTCertList *nsscerts, KMF_X509_DER_CERT *kmfcerts, uint32_t *numcerts) { KMF_RETURN rv = KMF_OK; CERTCertListNode *node; uint32_t maxcerts = *numcerts; maxcerts = *numcerts; if (maxcerts == 0) maxcerts = 0xFFFFFFFF; *numcerts = 0; /* * Don't copy more certs than the caller wanted. */ for (node = CERT_LIST_HEAD(nsscerts); !CERT_LIST_END(node, nsscerts) && rv == KMF_OK && (*numcerts) < maxcerts; node = CERT_LIST_NEXT(node), (*numcerts)++) { if (kmfcerts != NULL) rv = nss2kmf_cert(node->cert, &kmfcerts[*numcerts]); } /* * If we failed, delete any certs allocated so far. */ if (rv != KMF_OK) { int i; for (i = 0; i < *numcerts; i++) kmf_free_kmf_cert(kmfhandle, &kmfcerts[i]); *numcerts = 0; } return (rv); } KMF_RETURN NSS_FindCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN rv = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; PK11SlotInfo *nss_slot = NULL; CERTCertList *certlist = NULL; uint32_t maxcerts; uint32_t *num_certs; KMF_X509_DER_CERT *kmfcerts = NULL; char *certlabel = NULL; char *issuer = NULL; char *subject = NULL; KMF_BIGINT *serial = NULL; KMF_CERT_VALIDITY validity; if (handle == NULL || attrlist == NULL || numattr == 0) { return (KMF_ERR_BAD_PARAMETER); } rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); if (rv != KMF_OK) return (rv); num_certs = kmf_get_attr_ptr(KMF_COUNT_ATTR, attrlist, numattr); if (num_certs == NULL) return (KMF_ERR_BAD_PARAMETER); maxcerts = *num_certs; if (maxcerts == 0) maxcerts = 0xFFFFFFFF; *num_certs = 0; /* Get the optional returned certificate list */ kmfcerts = kmf_get_attr_ptr(KMF_X509_DER_CERT_ATTR, attrlist, numattr); /* Get optional search criteria attributes */ certlabel = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr); issuer = kmf_get_attr_ptr(KMF_ISSUER_NAME_ATTR, attrlist, numattr); subject = kmf_get_attr_ptr(KMF_SUBJECT_NAME_ATTR, attrlist, numattr); serial = kmf_get_attr_ptr(KMF_BIGINT_ATTR, attrlist, numattr); rv = kmf_get_attr(KMF_CERT_VALIDITY_ATTR, attrlist, numattr, &validity, NULL); if (rv != KMF_OK) { validity = KMF_ALL_CERTS; rv = KMF_OK; } if (certlabel != NULL) { /* This will only find 1 certificate */ rv = nss_getcert_by_label(kmfh, certlabel, kmfcerts, num_certs, validity); } else { /* * Build a list of matching certs. */ rv = nss_find_matching_certs(nss_slot, issuer, subject, serial, &certlist, validity); /* * If the caller supplied a pointer to storage for * a list of certs, convert up to 'maxcerts' of the * matching certs. */ if (rv == KMF_OK && certlist != NULL) { rv = convertCertList(handle, certlist, kmfcerts, &maxcerts); CERT_DestroyCertList(certlist); if (rv == KMF_OK) *num_certs = maxcerts; } } if (nss_slot != NULL) { PK11_FreeSlot(nss_slot); } if (rv == KMF_OK && *num_certs == 0) rv = KMF_ERR_CERT_NOT_FOUND; return (rv); } void /*ARGSUSED*/ NSS_FreeKMFCert(KMF_HANDLE_T handle, KMF_X509_DER_CERT *kmf_cert) { if (kmf_cert != NULL) { if (kmf_cert->certificate.Data != NULL) { free(kmf_cert->certificate.Data); kmf_cert->certificate.Data = NULL; kmf_cert->certificate.Length = 0; } if (kmf_cert->kmf_private.label != NULL) { free(kmf_cert->kmf_private.label); kmf_cert->kmf_private.label = NULL; } } } KMF_RETURN NSS_DeleteCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN rv = KMF_OK; int nssrv; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; CERTCertificate *cert = NULL; PK11SlotInfo *nss_slot = NULL; char *certlabel = NULL; char *issuer = NULL; char *subject = NULL; KMF_BIGINT *serial = NULL; KMF_CERT_VALIDITY validity; if (handle == NULL || attrlist == NULL || numattr == 0) { return (KMF_ERR_BAD_PARAMETER); } rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); if (rv != KMF_OK) return (rv); /* Get the search criteria attributes. They are all optional. */ certlabel = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr); issuer = kmf_get_attr_ptr(KMF_ISSUER_NAME_ATTR, attrlist, numattr); subject = kmf_get_attr_ptr(KMF_SUBJECT_NAME_ATTR, attrlist, numattr); serial = kmf_get_attr_ptr(KMF_BIGINT_ATTR, attrlist, numattr); rv = kmf_get_attr(KMF_CERT_VALIDITY_ATTR, attrlist, numattr, &validity, NULL); if (rv != KMF_OK) { validity = KMF_ALL_CERTS; rv = KMF_OK; } /* Start finding the matched certificates and delete them. */ if (certlabel != NULL) { cert = PK11_FindCertFromNickname(certlabel, NULL); if (cert == NULL) { return (KMF_ERR_CERT_NOT_FOUND); } switch (validity) { case KMF_ALL_CERTS: break; case KMF_NONEXPIRED_CERTS: nssrv = CERT_CertTimesValid(cert); if (nssrv == SECFailure) { /* this is an invalid cert - skip it */ goto out; } break; case KMF_EXPIRED_CERTS: nssrv = CERT_CertTimesValid(cert); if (nssrv != SECFailure) { /* this is a valid cert - skip it */ goto out; } break; } /* delete it from database */ nssrv = SEC_DeletePermCertificate(cert); if (nssrv) { SET_ERROR(kmfh, nssrv); rv = KMF_ERR_INTERNAL; } } else { CERTCertListNode *node; CERTCertList *certlist = NULL; rv = nss_find_matching_certs(nss_slot, issuer, subject, serial, &certlist, validity); for (node = CERT_LIST_HEAD(certlist); !CERT_LIST_END(node, certlist) && rv == KMF_OK; node = CERT_LIST_NEXT(node)) { nssrv = SEC_DeletePermCertificate(node->cert); if (nssrv) { SET_ERROR(kmfh, nssrv); rv = KMF_ERR_INTERNAL; } } if (rv == KMF_OK && certlist != NULL) { CERT_DestroyCertList(certlist); } else if (rv == KMF_OK && certlist == NULL) { rv = KMF_ERR_CERT_NOT_FOUND; } } out: if (nss_slot != NULL) { PK11_FreeSlot(nss_slot); } if (cert != NULL) { CERT_DestroyCertificate(cert); } return (rv); } static void InitRandom(char *filename) { char buf[2048]; int fd; PRInt32 count; fd = open(filename, O_RDONLY); if (!fd) return; count = read(fd, buf, sizeof (buf)); if (count > 0) { (void) PK11_RandomUpdate(buf, count); } (void) close(fd); } KMF_RETURN NSS_CreateKeypair(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN rv = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; PK11RSAGenParams rsaparams; void *nssparams; CK_MECHANISM_TYPE mechanism; ulong_t publicExponent = 0x010001; PK11SlotInfo *nss_slot = NULL; SECKEYPrivateKey *NSSprivkey = NULL; SECKEYPublicKey *NSSpubkey = NULL; SECKEYECParams *ecparams = NULL; PQGParams *pqgParams = NULL; KMF_CREDENTIAL cred; boolean_t storekey = TRUE; uint32_t keylen = 1024, len; uint32_t keylen_size = sizeof (uint32_t); KMF_KEY_ALG keytype = KMF_RSA; KMF_KEY_HANDLE *pubkey = NULL; KMF_KEY_HANDLE *privkey = NULL; char *keylabel = NULL; if (handle == NULL || attrlist == NULL || numattr == 0) { return (KMF_ERR_BAD_PARAMETER); } rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); if (rv != KMF_OK) { return (rv); } rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr, (void *)&cred, NULL); if (rv != KMF_OK) return (rv); rv = nss_authenticate(handle, nss_slot, &cred); if (rv != KMF_OK) { return (rv); } /* "storekey" is optional. Default is TRUE */ (void) kmf_get_attr(KMF_STOREKEY_BOOL_ATTR, attrlist, numattr, &storekey, NULL); /* keytype is optional. KMF_RSA is default */ (void) kmf_get_attr(KMF_KEYALG_ATTR, attrlist, numattr, (void *)&keytype, NULL); rv = kmf_get_attr(KMF_KEYLENGTH_ATTR, attrlist, numattr, &keylen, &keylen_size); if (rv == KMF_ERR_ATTR_NOT_FOUND) /* Default keylen = 1024 */ rv = KMF_OK; else if (rv != KMF_OK) return (KMF_ERR_BAD_PARAMETER); pubkey = kmf_get_attr_ptr(KMF_PUBKEY_HANDLE_ATTR, attrlist, numattr); privkey = kmf_get_attr_ptr(KMF_PRIVKEY_HANDLE_ATTR, attrlist, numattr); if (pubkey == NULL || privkey == NULL) return (KMF_ERR_BAD_PARAMETER); (void) memset(pubkey, 0, sizeof (KMF_KEY_HANDLE)); (void) memset(privkey, 0, sizeof (KMF_KEY_HANDLE)); rv = kmf_get_attr(KMF_KEYLABEL_ATTR, attrlist, numattr, NULL, &len); if (rv == KMF_OK && len > 0) { keylabel = malloc(len + 1); if (keylabel == NULL) return (KMF_ERR_MEMORY); /* Now fill in the label value */ (void) memset(keylabel, 0, len + 1); rv = kmf_get_attr(KMF_KEYLABEL_ATTR, attrlist, numattr, keylabel, NULL); if (rv != KMF_OK) { free(keylabel); goto cleanup; } } /* Get some random bits */ InitRandom("/dev/urandom"); if (keytype == KMF_RSA) { KMF_BIGINT rsaexp; rsaparams.keySizeInBits = keylen; /* * NSS only allows for a 4 byte exponent. * Ignore the exponent parameter if it is too big. */ if ((rv = kmf_get_attr(KMF_RSAEXP_ATTR, attrlist, numattr, &rsaexp, NULL)) == KMF_OK) { if (rsaexp.len > 0 && rsaexp.len <= sizeof (publicExponent) && rsaexp.val != NULL) { (void) memcpy(&publicExponent, rsaexp.val, rsaexp.len); } } rsaparams.pe = publicExponent; mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; nssparams = &rsaparams; } else if (keytype == KMF_DSA) { PQGVerify *pqgVerify = NULL; int ks; SECStatus nssrv, passed; mechanism = CKM_DSA_KEY_PAIR_GEN; ks = PQG_PBITS_TO_INDEX(keylen); nssrv = PK11_PQG_ParamGen(ks, &pqgParams, &pqgVerify); if (nssrv != SECSuccess) { SET_ERROR(kmfh, rv); PK11_PQG_DestroyVerify(pqgVerify); rv = KMF_ERR_KEYGEN_FAILED; goto cleanup; } nssrv = PK11_PQG_VerifyParams(pqgParams, pqgVerify, &passed); if (nssrv != SECSuccess || passed != SECSuccess) { SET_ERROR(kmfh, rv); rv = KMF_ERR_KEYGEN_FAILED; } PK11_PQG_DestroyVerify(pqgVerify); if (rv != KMF_OK) { SET_ERROR(kmfh, PORT_GetError()); goto cleanup; } nssparams = pqgParams; } else if (keytype == KMF_ECDSA) { KMF_OID *eccoid = kmf_get_attr_ptr(KMF_ECC_CURVE_OID_ATTR, attrlist, numattr); if (eccoid == NULL) return (KMF_ERR_BAD_PARAMETER); ecparams = SECITEM_AllocItem(NULL, NULL, (eccoid->Length)); if (!ecparams) return (KMF_ERR_MEMORY); (void) memcpy(ecparams->data, eccoid->Data, eccoid->Length); mechanism = CKM_EC_KEY_PAIR_GEN; nssparams = ecparams; } else { rv = KMF_ERR_BAD_PARAMETER; goto cleanup; } NSSprivkey = PK11_GenerateKeyPair(nss_slot, mechanism, nssparams, &NSSpubkey, storekey, /* isPermanent */ PR_TRUE, /* isSensitive */ (void *)cred.cred); if (NSSprivkey == NULL || NSSpubkey == NULL) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_KEYGEN_FAILED; } else { if (keylabel != NULL && strlen(keylabel)) { (void) PK11_SetPrivateKeyNickname(NSSprivkey, keylabel); (void) PK11_SetPublicKeyNickname(NSSpubkey, keylabel); } /* Now, convert it to a KMF_KEY object for the framework */ privkey->kstype = KMF_KEYSTORE_NSS; privkey->keyalg = keytype; privkey->keyclass = KMF_ASYM_PRI; privkey->keylabel = PK11_GetPrivateKeyNickname(NSSprivkey); privkey->keyp = (void *)NSSprivkey; pubkey->kstype = KMF_KEYSTORE_NSS; pubkey->keyalg = keytype; pubkey->keyp = (void *)NSSpubkey; pubkey->keyclass = KMF_ASYM_PUB; pubkey->keylabel = PK11_GetPublicKeyNickname(NSSpubkey); rv = KMF_OK; } cleanup: if (rv != KMF_OK) { if (NSSpubkey) (void) PK11_DeleteTokenPublicKey(NSSpubkey); if (NSSprivkey) (void) PK11_DeleteTokenPrivateKey(NSSprivkey, PR_TRUE); privkey->keyp = NULL; pubkey->keyp = NULL; } if (keylabel) free(keylabel); if (pqgParams != NULL) PK11_PQG_DestroyParams(pqgParams); if (ecparams != NULL) SECITEM_FreeItem(ecparams, PR_TRUE); if (nss_slot != NULL) PK11_FreeSlot(nss_slot); return (rv); } KMF_RETURN NSS_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, KMF_OID *AlgOID, KMF_DATA *tobesigned, KMF_DATA *output) { KMF_RETURN ret = KMF_OK; KMF_ALGORITHM_INDEX AlgId; SECOidTag signAlgTag; SECKEYPrivateKey *NSSprivkey = NULL; SECStatus rv; SECItem signed_data; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; signed_data.data = 0; if (key == NULL || AlgOID == NULL || tobesigned == NULL || output == NULL || tobesigned->Data == NULL || output->Data == NULL) return (KMF_ERR_BAD_PARAMETER); /* Map the OID to a NSS algorithm */ AlgId = x509_algoid_to_algid(AlgOID); if (AlgId == KMF_ALGID_NONE) return (KMF_ERR_BAD_PARAMETER); NSSprivkey = (SECKEYPrivateKey *)key->keyp; if (AlgId == KMF_ALGID_MD5WithRSA) signAlgTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; else if (AlgId == KMF_ALGID_MD2WithRSA) signAlgTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; else if (AlgId == KMF_ALGID_SHA1WithRSA) signAlgTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; else if (AlgId == KMF_ALGID_SHA256WithRSA) signAlgTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; else if (AlgId == KMF_ALGID_SHA384WithRSA) signAlgTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; else if (AlgId == KMF_ALGID_SHA512WithRSA) signAlgTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; else if (AlgId == KMF_ALGID_SHA1WithDSA) signAlgTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; else if (AlgId == KMF_ALGID_SHA1WithECDSA || AlgId == KMF_ALGID_ECDSA) signAlgTag = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST; else if (AlgId == KMF_ALGID_SHA256WithECDSA) signAlgTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; else if (AlgId == KMF_ALGID_SHA384WithECDSA) signAlgTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; else if (AlgId == KMF_ALGID_SHA512WithECDSA) signAlgTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; else /* NSS does not support DSA with SHA2 hashes (FIPS 186-3) */ return (KMF_ERR_BAD_PARAMETER); rv = SEC_SignData(&signed_data, tobesigned->Data, tobesigned->Length, NSSprivkey, signAlgTag); if (rv != 0) { SET_ERROR(kmfh, rv); return (KMF_ERR_INTERNAL); } if (signed_data.len <= output->Length) { (void) memcpy(output->Data, signed_data.data, signed_data.len); output->Length = signed_data.len; } else { output->Length = 0; ret = KMF_ERR_BAD_PARAMETER; } free(signed_data.data); return (ret); } KMF_RETURN NSS_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *keyp, KMF_DATA *encoded) { KMF_RETURN ret = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; SECItem *rvitem; CERTSubjectPublicKeyInfo *spki = NULL; if (keyp == NULL || encoded == NULL || keyp->keyp == NULL) return (KMF_ERR_BAD_PARAMETER); spki = SECKEY_CreateSubjectPublicKeyInfo(keyp->keyp); if (spki == NULL) { SET_ERROR(kmfh, PORT_GetError()); return (KMF_ERR_MEMORY); } rvitem = SEC_ASN1EncodeItem(NULL, NULL, spki, CERT_SubjectPublicKeyInfoTemplate); if (rvitem != NULL) { encoded->Data = malloc(rvitem->len); if (encoded->Data == NULL) { ret = KMF_ERR_MEMORY; } else { (void) memcpy(encoded->Data, rvitem->data, rvitem->len); encoded->Length = rvitem->len; } SECITEM_FreeItem(rvitem, TRUE); } else { SET_ERROR(kmfh, PORT_GetError()); encoded->Data = NULL; encoded->Length = 0; ret = KMF_ERR_ENCODING; } SECKEY_DestroySubjectPublicKeyInfo(spki); return (ret); } KMF_RETURN NSS_DeleteKey(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN rv = KMF_OK; PK11SlotInfo *nss_slot = NULL; KMF_KEY_HANDLE *key; KMF_CREDENTIAL cred; boolean_t delete_token = B_TRUE; if (handle == NULL || attrlist == NULL || numattr == 0) { return (KMF_ERR_BAD_PARAMETER); } /* * "delete_token" means to clear it from the token storage as well * as from memory. */ key = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr); if (key == NULL || key->keyp == NULL) return (KMF_ERR_BAD_PARAMETER); rv = kmf_get_attr(KMF_DESTROY_BOOL_ATTR, attrlist, numattr, (void *)&delete_token, NULL); if (rv != KMF_OK) /* "delete_token" is optional. Default is TRUE */ rv = KMF_OK; if (delete_token) { SECStatus nssrv = SECSuccess; if (key->keyclass != KMF_ASYM_PUB && key->keyclass != KMF_ASYM_PRI && key->keyclass != KMF_SYMMETRIC) return (KMF_ERR_BAD_KEY_CLASS); rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); if (rv != KMF_OK) { return (rv); } rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr, (void *)&cred, NULL); if (rv != KMF_OK) return (KMF_ERR_BAD_PARAMETER); rv = nss_authenticate(handle, nss_slot, &cred); if (rv != KMF_OK) { return (rv); } if (key->keyclass == KMF_ASYM_PUB) { nssrv = PK11_DeleteTokenPublicKey( (SECKEYPublicKey *)key->keyp); } else if (key->keyclass == KMF_ASYM_PRI) { nssrv = PK11_DeleteTokenPrivateKey( (SECKEYPrivateKey *)key->keyp, PR_TRUE); } else if (key->keyclass == KMF_SYMMETRIC) { nssrv = PK11_DeleteTokenSymKey( (PK11SymKey *) key->keyp); if (nssrv == SECSuccess) PK11_FreeSymKey((PK11SymKey *) key->keyp); } if (nssrv != SECSuccess) { SET_ERROR(handle, PORT_GetError()); rv = KMF_ERR_INTERNAL; } } else { if (key->keyclass == KMF_ASYM_PUB) { SECKEY_DestroyPublicKey((SECKEYPublicKey *)key->keyp); } else if (key->keyclass == KMF_ASYM_PRI) { SECKEY_DestroyPrivateKey((SECKEYPrivateKey *)key->keyp); } else if (key->keyclass == KMF_SYMMETRIC) { PK11_FreeSymKey((PK11SymKey *) key->keyp); } else { return (KMF_ERR_BAD_KEY_CLASS); } } key->keyp = NULL; return (rv); } KMF_RETURN NSS_GetErrorString(KMF_HANDLE_T handle, char **msgstr) { KMF_RETURN ret = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; char *str; /* Get the error string in the default language */ str = (char *)PR_ErrorToName((PRErrorCode)kmfh->lasterr.errcode); if (str != NULL) { *msgstr = (char *)strdup(str); if ((*msgstr) == NULL) ret = KMF_ERR_MEMORY; } else { *msgstr = NULL; } return (ret); } KMF_RETURN NSS_FindPrikeyByCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN rv = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; PK11SlotInfo *nss_slot = NULL; KMF_CREDENTIAL cred; KMF_KEY_HANDLE *key = NULL; KMF_DATA *cert = NULL; CERTCertificate *nss_cert = NULL; SECKEYPrivateKey* privkey = NULL; if (handle == NULL || attrlist == NULL || numattr == 0) { return (KMF_ERR_BAD_PARAMETER); } rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); if (rv != KMF_OK) return (rv); /* Get the credential */ rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr, (void *)&cred, NULL); if (rv != KMF_OK) return (KMF_ERR_BAD_PARAMETER); rv = nss_authenticate(handle, nss_slot, &cred); if (rv != KMF_OK) return (rv); /* Get the key handle */ key = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr); if (key == NULL) return (KMF_ERR_BAD_PARAMETER); /* Get the cert data and decode it */ cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist, numattr); if (cert == NULL || cert->Data == NULL) return (KMF_ERR_BAD_PARAMETER); nss_cert = CERT_DecodeCertFromPackage((char *)cert->Data, cert->Length); if (nss_cert == NULL) { SET_ERROR(kmfh, PORT_GetError()); return (KMF_ERR_BAD_CERT_FORMAT); } privkey = PK11_FindPrivateKeyFromCert(nss_slot, nss_cert, NULL); if (privkey == NULL) { SET_ERROR(kmfh, PORT_GetError()); return (KMF_ERR_KEY_NOT_FOUND); } key->kstype = KMF_KEYSTORE_NSS; key->keyclass = KMF_ASYM_PRI; key->keyp = (void *)privkey; key->keylabel = PK11_GetPrivateKeyNickname(privkey); CERT_DestroyCertificate(nss_cert); return (KMF_OK); } KMF_RETURN NSS_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, KMF_OID *AlgOID, KMF_DATA *ciphertext, KMF_DATA *output) { KMF_RETURN ret = KMF_OK; SECKEYPrivateKey *NSSprivkey = NULL; SECStatus rv; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; unsigned int in_len = 0, out_len = 0; unsigned int total_decrypted = 0, modulus_len = 0; uint8_t *in_data, *out_data; int i, blocks; if (key == NULL || AlgOID == NULL || ciphertext == NULL || output == NULL || ciphertext->Data == NULL || output->Data == NULL) return (KMF_ERR_BAD_PARAMETER); NSSprivkey = (SECKEYPrivateKey *)key->keyp; modulus_len = PK11_GetPrivateModulusLen(NSSprivkey); blocks = ciphertext->Length/modulus_len; out_data = output->Data; in_data = ciphertext->Data; out_len = modulus_len - 11; in_len = modulus_len; for (i = 0; i < blocks; i++) { rv = PK11_PrivDecryptPKCS1(NSSprivkey, out_data, &out_len, ciphertext->Length, in_data, in_len); if (rv != 0) { SET_ERROR(kmfh, rv); return (KMF_ERR_INTERNAL); } out_data += out_len; total_decrypted += out_len; in_data += in_len; } output->Length = total_decrypted; return (ret); } static KMF_KEY_ALG pk11keytype2kmf(CK_KEY_TYPE type) { 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); case CKK_EC: return (KMF_ECDSA); default: /* not supported */ return (KMF_KEYALG_NONE); } } KMF_RETURN NSS_FindKey(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN rv; SECKEYPrivateKeyList *prilist; SECKEYPrivateKeyListNode *prinode; SECKEYPublicKeyList *publist; SECKEYPublicKeyListNode *pubnode; PK11SlotInfo *nss_slot = NULL; PK11SymKey *symlist = NULL; int count; uint32_t maxkeys; KMF_KEY_HANDLE *keys; uint32_t *numkeys; KMF_CREDENTIAL *cred = NULL; KMF_KEY_CLASS keyclass; char *findLabel; char *nick; int match = 0; KMF_KEY_ALG keytype = KMF_KEYALG_NONE; if (handle == NULL || attrlist == NULL || numattr == 0) { return (KMF_ERR_BAD_PARAMETER); } numkeys = kmf_get_attr_ptr(KMF_COUNT_ATTR, attrlist, numattr); if (numkeys == NULL) return (KMF_ERR_BAD_PARAMETER); rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); if (rv != KMF_OK) { return (rv); } /* It is OK if this is NULL, we dont need a cred to find public keys */ cred = kmf_get_attr_ptr(KMF_CREDENTIAL_ATTR, attrlist, numattr); if (cred != NULL) { rv = nss_authenticate(handle, nss_slot, cred); if (rv != KMF_OK) { return (rv); } } maxkeys = *numkeys; if (maxkeys == 0) maxkeys = 0xFFFFFFFF; *numkeys = 0; rv = kmf_get_attr(KMF_KEYCLASS_ATTR, attrlist, numattr, (void *)&keyclass, NULL); if (rv != KMF_OK) return (KMF_ERR_BAD_PARAMETER); findLabel = kmf_get_attr_ptr(KMF_KEYLABEL_ATTR, attrlist, numattr); if (keyclass == KMF_ASYM_PUB) { publist = PK11_ListPublicKeysInSlot(nss_slot, findLabel); if (publist == NULL) { rv = KMF_ERR_KEY_NOT_FOUND; goto cleanup; } } else if (keyclass == KMF_ASYM_PRI) { prilist = PK11_ListPrivKeysInSlot(nss_slot, findLabel, NULL); if (prilist == NULL) { rv = KMF_ERR_KEY_NOT_FOUND; goto cleanup; } } else if (keyclass == KMF_SYMMETRIC) { symlist = PK11_ListFixedKeysInSlot(nss_slot, findLabel, NULL); if (symlist == NULL) { rv = KMF_ERR_KEY_NOT_FOUND; goto cleanup; } } else { rv = KMF_ERR_BAD_KEY_CLASS; goto cleanup; } keys = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr); /* it is okay to have "keys" contains NULL */ if (keyclass == KMF_ASYM_PUB) { for (count = 0, pubnode = PUBKEY_LIST_HEAD(publist); !PUBKEY_LIST_END(pubnode, publist) && count < maxkeys; pubnode = PUBKEY_LIST_NEXT(pubnode)) { match = 0; /* * Due to bug in NSS, we have to manually match * the labels to be sure we have a match. */ nick = PK11_GetPublicKeyNickname(pubnode->key); if (findLabel) { match = (nick && (strcmp(nick, findLabel) == 0)); } else { /* always match if findLabel is NULL */ match = 1; } if (keys != NULL && match) { keys[count].kstype = KMF_KEYSTORE_NSS; keys[count].keyclass = KMF_ASYM_PUB; keys[count].keyp = (void *)pubnode->key; keys[count].keylabel = nick; if (pubnode->key->keyType == rsaKey) keys[count].keyalg = KMF_RSA; else if (pubnode->key->keyType == dsaKey) keys[count].keyalg = KMF_DSA; else if (pubnode->key->keyType == ecKey) keys[count].keyalg = KMF_ECDSA; } if (match) count++; } *numkeys = count; } else if (keyclass == KMF_ASYM_PRI) { for (count = 0, prinode = PRIVKEY_LIST_HEAD(prilist); !PRIVKEY_LIST_END(prinode, prilist) && count < maxkeys; prinode = PRIVKEY_LIST_NEXT(prinode)) { match = 0; /* * Due to bug in NSS, we have to manually match * the labels to be sure we have a match. */ nick = PK11_GetPrivateKeyNickname(prinode->key); if (findLabel) { match = (nick && (strcmp(nick, findLabel) == 0)); } else { /* always match if findLabel is NULL */ match = 1; } if (keys != NULL && match) { keys[count].kstype = KMF_KEYSTORE_NSS; keys[count].keyclass = KMF_ASYM_PRI; keys[count].keyp = (void *)prinode->key; keys[count].keylabel = nick; if (prinode->key->keyType == rsaKey) keys[count].keyalg = KMF_RSA; else if (prinode->key->keyType == dsaKey) keys[count].keyalg = KMF_DSA; else if (prinode->key->keyType == ecKey) keys[count].keyalg = KMF_ECDSA; } if (match) count++; } *numkeys = count; } else if (keyclass == KMF_SYMMETRIC) { count = 0; rv = kmf_get_attr(KMF_KEYALG_ATTR, attrlist, numattr, (void *)&keytype, NULL); if (rv != KMF_OK) rv = KMF_OK; while (symlist && count < maxkeys) { PK11SymKey *symkey = symlist; CK_KEY_TYPE type; KMF_KEY_ALG keyalg; match = 0; type = PK11_GetSymKeyType(symkey); keyalg = pk11keytype2kmf(type); symlist = PK11_GetNextSymKey(symkey); /* * If keytype is specified in the searching parameter, * check the keytype and skip the key if its keytype * doesn't match. */ if (keytype != KMF_KEYALG_NONE && keytype != keyalg) { /* free that key since we arent using it */ PK11_FreeSymKey(symkey); continue; } /* * Due to bug in NSS, we have to manually match * the labels to be sure we have a match. */ nick = PK11_GetSymKeyNickname(symkey); if (findLabel) { match = (nick && (strcmp(nick, findLabel) == 0)); } else { /* always match if findLabel is NULL */ match = 1; } if (keys != NULL && match) { keys[count].kstype = KMF_KEYSTORE_NSS; keys[count].keyclass = KMF_SYMMETRIC; keys[count].keyp = (void *) symkey; keys[count].keylabel = nick; keys[count].keyalg = keyalg; } else { PK11_FreeSymKey(symkey); } if (match) count++; } /* * Cleanup memory for unused keys. */ while (symlist != NULL) { PK11SymKey *symkey = symlist; PK11_FreeSymKey(symkey); symlist = PK11_GetNextSymKey(symkey); } *numkeys = count; } cleanup: if (nss_slot != NULL) { PK11_FreeSlot(nss_slot); } return (rv); } static SECStatus p12u_SwapUnicodeBytes(SECItem *uniItem) { unsigned int i; unsigned char a; if ((uniItem == NULL) || (uniItem->len % 2)) { return (SECFailure); } for (i = 0; i < uniItem->len; i += 2) { a = uniItem->data[i]; uniItem->data[i] = uniItem->data[i+1]; uniItem->data[i+1] = a; } return (SECSuccess); } static PRBool p12u_ucs2_ascii_conversion_function( PRBool toUnicode, unsigned char *inBuf, unsigned int inBufLen, unsigned char *outBuf, unsigned int maxOutBufLen, unsigned int *outBufLen, PRBool swapBytes) { SECItem it = { 0 }; SECItem *dup = NULL; PRBool ret; it.data = inBuf; it.len = inBufLen; dup = SECITEM_DupItem(&it); /* * If converting Unicode to ASCII, swap bytes before conversion * as neccessary. */ if (!toUnicode && swapBytes) { if (p12u_SwapUnicodeBytes(dup) != SECSuccess) { SECITEM_ZfreeItem(dup, PR_TRUE); return (PR_FALSE); } } /* Perform the conversion. */ ret = PORT_UCS2_UTF8Conversion(toUnicode, dup->data, dup->len, outBuf, maxOutBufLen, outBufLen); if (dup) SECITEM_ZfreeItem(dup, PR_TRUE); return (ret); } static PRBool p12u_OpenFile(p12uContext *p12ctx, PRBool fileRead) { if (!p12ctx || !p12ctx->filename) { return (PR_FALSE); } if (fileRead) { p12ctx->file = PR_Open(p12ctx->filename, PR_RDONLY, 0400); } else { p12ctx->file = PR_Open(p12ctx->filename, PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 0600); } if (!p12ctx->file) { p12ctx->error = PR_TRUE; return (PR_FALSE); } return (PR_TRUE); } static void p12u_DestroyContext(p12uContext **ppCtx, PRBool removeFile) { if (!ppCtx || !(*ppCtx)) { return; } if ((*ppCtx)->file != NULL) { (void) PR_Close((*ppCtx)->file); } if ((*ppCtx)->filename != NULL) { if (removeFile) { (void) PR_Delete((*ppCtx)->filename); } free((*ppCtx)->filename); } free(*ppCtx); *ppCtx = NULL; } static p12uContext * p12u_InitContext(PRBool fileImport, char *filename) { p12uContext *p12ctx; p12ctx = PORT_ZNew(p12uContext); if (!p12ctx) { return (NULL); } p12ctx->error = PR_FALSE; p12ctx->errorValue = 0; p12ctx->filename = strdup(filename); if (!p12u_OpenFile(p12ctx, fileImport)) { p12u_DestroyContext(&p12ctx, PR_FALSE); return (NULL); } return (p12ctx); } static void p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len) { p12uContext *p12cxt = arg; int writeLen; if (!p12cxt || (p12cxt->error == PR_TRUE)) { return; } if (p12cxt->file == NULL) { p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE; p12cxt->error = PR_TRUE; return; } writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (int32)len); if (writeLen != (int)len) { (void) PR_Close(p12cxt->file); free(p12cxt->filename); p12cxt->filename = NULL; p12cxt->file = NULL; p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE; p12cxt->error = PR_TRUE; } } #define HANDLE_NSS_ERROR(r) {\ SET_ERROR(kmfh, PORT_GetError()); \ rv = r; \ goto out; } static KMF_RETURN add_cert_to_bag(SEC_PKCS12ExportContext *p12ecx, CERTCertificate *cert, SECItem *pwitem) { KMF_RETURN rv = KMF_OK; SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL; keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx); if (PK11_IsFIPS()) { certSafe = keySafe; } else { certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem, SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC); } if (!certSafe || !keySafe) { rv = KMF_ERR_INTERNAL; goto out; } if (SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert, CERT_GetDefaultCertDB(), keySafe, NULL, PR_TRUE, pwitem, SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC) != SECSuccess) { rv = KMF_ERR_INTERNAL; } out: return (rv); } KMF_RETURN NSS_ExportPK12(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN rv; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; SEC_PKCS12ExportContext *p12ecx = NULL; p12uContext *p12ctx = NULL; CERTCertList *certlist = NULL; CERTCertificate *nsscert = NULL; CERTCertListNode* node = NULL; PK11SlotInfo *slot = NULL; SECItem pwitem = {NULL, 0}; KMF_CREDENTIAL *cred = NULL; KMF_CREDENTIAL *p12cred = NULL; char *certlabel = NULL; char *issuer = NULL; char *subject = NULL; KMF_BIGINT *serial = NULL; char *filename = NULL; if (kmfh == NULL || attrlist == NULL || numattr == 0) { return (KMF_ERR_BAD_PARAMETER); } rv = do_nss_init(handle, numattr, attrlist, FALSE, &slot); if (rv != KMF_OK) return (rv); cred = kmf_get_attr_ptr(KMF_CREDENTIAL_ATTR, attrlist, numattr); if (cred == NULL) return (KMF_ERR_BAD_PARAMETER); rv = nss_authenticate(handle, slot, cred); if (rv != KMF_OK) return (rv); p12cred = kmf_get_attr_ptr(KMF_PK12CRED_ATTR, attrlist, numattr); if (p12cred == NULL) return (KMF_ERR_BAD_PARAMETER); filename = kmf_get_attr_ptr(KMF_OUTPUT_FILENAME_ATTR, attrlist, numattr); if (filename == NULL) return (KMF_ERR_BAD_PARAMETER); /* Get optional search criteria attributes */ certlabel = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr); issuer = kmf_get_attr_ptr(KMF_ISSUER_NAME_ATTR, attrlist, numattr); subject = kmf_get_attr_ptr(KMF_SUBJECT_NAME_ATTR, attrlist, numattr); serial = kmf_get_attr_ptr(KMF_BIGINT_ATTR, attrlist, numattr); /* * Find the certificate(s) first. */ if (certlabel != NULL) { nsscert = PK11_FindCertFromNickname(certlabel, NULL); if (nsscert == NULL) { HANDLE_NSS_ERROR(KMF_ERR_CERT_NOT_FOUND) } } else { rv = nss_find_matching_certs(slot, issuer, subject, serial, &certlist, 0); if (rv == KMF_OK && certlist == NULL) { return (KMF_ERR_CERT_NOT_FOUND); } if (rv != KMF_OK) return (rv); } /* * The KMF_CREDENTIAL holds the password to use for * encrypting the PKCS12 key information. */ pwitem.data = (uchar_t *)p12cred->cred; pwitem.len = p12cred->credlen; p12ctx = p12u_InitContext(PR_FALSE, filename); if (!p12ctx) { HANDLE_NSS_ERROR(KMF_ERR_OPEN_FILE) } PORT_SetUCS2_ASCIIConversionFunction( p12u_ucs2_ascii_conversion_function); p12ecx = SEC_PKCS12CreateExportContext(NULL, NULL, slot, NULL); if (!p12ecx) { HANDLE_NSS_ERROR(KMF_ERR_OPEN_FILE) } if (SEC_PKCS12AddPasswordIntegrity(p12ecx, &pwitem, SEC_OID_SHA1) != SECSuccess) { HANDLE_NSS_ERROR(KMF_ERR_INTERNAL) } /* * NSS actually supports storing a list of keys and certs * in the PKCS#12 PDU. Nice feature. */ if (certlist != NULL) { for (node = CERT_LIST_HEAD(certlist); !CERT_LIST_END(node, certlist) && rv == KMF_OK; node = CERT_LIST_NEXT(node)) { rv = add_cert_to_bag(p12ecx, node->cert, &pwitem); } } else if (nsscert != NULL) { rv = add_cert_to_bag(p12ecx, nsscert, &pwitem); } if (SEC_PKCS12Encode(p12ecx, p12u_WriteToExportFile, p12ctx) != SECSuccess) { HANDLE_NSS_ERROR(KMF_ERR_ENCODING) } out: if (nsscert) CERT_DestroyCertificate(nsscert); if (certlist) CERT_DestroyCertList(certlist); if (p12ctx) p12u_DestroyContext(&p12ctx, PR_FALSE); if (p12ecx) SEC_PKCS12DestroyExportContext(p12ecx); return (rv); } #define SETATTR(t, n, atype, value, size) \ t[n].type = atype; \ t[n].pValue = (CK_BYTE *)value; \ t[n].ulValueLen = (CK_ULONG)size; KMF_RETURN NSS_CreateSymKey(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN rv = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; PK11SlotInfo *nss_slot = NULL; PK11SymKey *nsskey = NULL; CK_MECHANISM_TYPE keyType; SECStatus nssrv; int keySize; KMF_KEY_HANDLE *symkey; KMF_CREDENTIAL cred; uint32_t keylen; uint32_t keylen_size = sizeof (uint32_t); KMF_KEY_ALG keytype; char *keylabel = NULL; if (kmfh == NULL || attrlist == NULL || numattr == 0) { return (KMF_ERR_BAD_PARAMETER); } symkey = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr); if (symkey == NULL) return (KMF_ERR_BAD_PARAMETER); rv = kmf_get_attr(KMF_KEYALG_ATTR, attrlist, numattr, (void *)&keytype, NULL); if (rv != KMF_OK) return (KMF_ERR_BAD_PARAMETER); rv = kmf_get_attr(KMF_KEYLENGTH_ATTR, attrlist, numattr, &keylen, &keylen_size); if (rv == KMF_ERR_ATTR_NOT_FOUND && (keytype == KMF_DES || keytype == KMF_DES3)) /* keylength is not required for DES and 3DES */ rv = KMF_OK; if (rv != KMF_OK) return (KMF_ERR_BAD_PARAMETER); keylabel = kmf_get_attr_ptr(KMF_KEYLABEL_ATTR, attrlist, numattr); if (keylabel == NULL) return (KMF_ERR_BAD_PARAMETER); switch (keytype) { case KMF_AES: keyType = CKM_AES_KEY_GEN; keySize = keylen; if (keySize == 0 || (keySize % 8) != 0) return (KMF_ERR_BAD_KEY_SIZE); break; case KMF_RC4: keyType = CKM_RC4_KEY_GEN; keySize = keylen; if (keySize == 0 || (keySize % 8) != 0) return (KMF_ERR_BAD_KEY_SIZE); break; case KMF_DES: keyType = CKM_DES_KEY_GEN; keySize = 0; /* required by PK11_TokenKeyGen() */ break; case KMF_DES3: keyType = CKM_DES3_KEY_GEN; keySize = 0; /* required by PK11_TokenKeyGen() */ break; case KMF_GENERIC_SECRET: keyType = CKM_GENERIC_SECRET_KEY_GEN; keySize = keylen; if (keySize == 0 || (keySize % 8) != 0) return (KMF_ERR_BAD_KEY_SIZE); break; default: rv = KMF_ERR_BAD_KEY_TYPE; goto out; } rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); if (rv != KMF_OK) { return (rv); } rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr, (void *)&cred, NULL); if (rv != KMF_OK) return (KMF_ERR_BAD_PARAMETER); rv = nss_authenticate(handle, nss_slot, &cred); if (rv != KMF_OK) { return (rv); } /* convert key length to bytes */ nsskey = PK11_TokenKeyGen(nss_slot, keyType, NULL, keySize / 8, NULL, PR_TRUE, (void *)cred.cred); if (nsskey == NULL) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_KEYGEN_FAILED; goto out; } nssrv = PK11_SetSymKeyNickname(nsskey, keylabel); if (nssrv != SECSuccess) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_KEYGEN_FAILED; goto out; } symkey->kstype = KMF_KEYSTORE_NSS; symkey->keyalg = keytype; symkey->keyclass = KMF_SYMMETRIC; symkey->israw = FALSE; symkey->keyp = (void *)nsskey; out: if (nss_slot != NULL) PK11_FreeSlot(nss_slot); if (rv != KMF_OK && nsskey != NULL) { (void) PK11_DeleteTokenSymKey(nsskey); PK11_FreeSymKey(nsskey); } return (rv); } KMF_RETURN NSS_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey, KMF_RAW_SYM_KEY *rkey) { KMF_RETURN rv = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; SECItem *value = NULL; PK11SymKey *nsskey; SECStatus nss_rv; if (kmfh == NULL) return (KMF_ERR_UNINITIALIZED); if (symkey == NULL || rkey == NULL) return (KMF_ERR_BAD_PARAMETER); else if (symkey->keyclass != KMF_SYMMETRIC) return (KMF_ERR_BAD_KEY_CLASS); if (symkey->israw) { KMF_RAW_KEY_DATA *rawkey = (KMF_RAW_KEY_DATA *)symkey->keyp; if (rawkey == NULL || rawkey->rawdata.sym.keydata.val == NULL || rawkey->rawdata.sym.keydata.len == 0) return (KMF_ERR_BAD_KEYHANDLE); rkey->keydata.len = rawkey->rawdata.sym.keydata.len; if ((rkey->keydata.val = malloc(rkey->keydata.len)) == NULL) return (KMF_ERR_MEMORY); (void) memcpy(rkey->keydata.val, rawkey->rawdata.sym.keydata.val, rkey->keydata.len); } else { nsskey = (PK11SymKey *)(symkey->keyp); if (nsskey == NULL) return (KMF_ERR_BAD_KEYHANDLE); nss_rv = PK11_ExtractKeyValue(nsskey); if (nss_rv != SECSuccess) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_GETKEYVALUE_FAILED; goto out; } value = PK11_GetKeyData(nsskey); if (value == NULL) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_GETKEYVALUE_FAILED; goto out; } if (value->len == 0 || value->data == NULL) { rv = KMF_ERR_GETKEYVALUE_FAILED; goto out; } rkey->keydata.val = malloc(value->len); if (rkey->keydata.val == NULL) { rv = KMF_ERR_MEMORY; goto out; } (void) memcpy(rkey->keydata.val, value->data, value->len); rkey->keydata.len = value->len; (void) memset(value->data, 0, value->len); } out: if (value != NULL) SECITEM_FreeItem(value, PR_TRUE); return (rv); } KMF_RETURN NSS_SetTokenPin(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN ret = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; int rv; PK11SlotInfo *nss_slot = NULL; KMF_CREDENTIAL oldcred, newcred; if (handle == NULL || attrlist == NULL || numattr == 0) return (KMF_ERR_BAD_PARAMETER); ret = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr, (void *)&oldcred, NULL); if (ret != KMF_OK) return (KMF_ERR_BAD_PARAMETER); ret = kmf_get_attr(KMF_NEWPIN_ATTR, attrlist, numattr, (void *)&newcred, NULL); if (ret != KMF_OK) return (KMF_ERR_BAD_PARAMETER); ret = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); /* If it was uninitialized, set it */ if (ret == KMF_ERR_UNINITIALIZED_TOKEN) { rv = PK11_InitPin(nss_slot, NULL, newcred.cred); if (rv != SECSuccess) { SET_ERROR(kmfh, PORT_GetError()); ret = KMF_ERR_AUTH_FAILED; } else { ret = KMF_OK; } } else if (ret == KMF_OK) { ret = nss_authenticate(handle, nss_slot, &oldcred); if (ret != KMF_OK) { return (ret); } rv = PK11_ChangePW(nss_slot, oldcred.cred, newcred.cred); if (rv != SECSuccess) { SET_ERROR(kmfh, PORT_GetError()); ret = KMF_ERR_AUTH_FAILED; } } return (ret); } KMF_RETURN NSS_StoreKey(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN rv = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; PK11SlotInfo *nss_slot = NULL; KMF_CREDENTIAL cred = {NULL, 0}; KMF_KEY_HANDLE *pubkey = NULL, *prikey = NULL; KMF_RAW_KEY_DATA *rawkey = NULL; char *keylabel = NULL; SECStatus ckrv = SECSuccess; SECItem nickname = {NULL, 0}; CERTCertificate *nss_cert = NULL; if (kmfh == NULL || attrlist == NULL || numattr == 0) { return (KMF_ERR_BAD_PARAMETER); } rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); if (rv != KMF_OK) { return (rv); } rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr, (void *)&cred, NULL); if (rv != KMF_OK) return (KMF_ERR_BAD_PARAMETER); rv = nss_authenticate(handle, nss_slot, &cred); if (rv != KMF_OK) { return (rv); } pubkey = kmf_get_attr_ptr(KMF_PUBKEY_HANDLE_ATTR, attrlist, numattr); if (pubkey == NULL) { /* look for private key */ prikey = kmf_get_attr_ptr(KMF_PRIVKEY_HANDLE_ATTR, attrlist, numattr); if (prikey == NULL) /* look for raw key */ rawkey = kmf_get_attr_ptr(KMF_RAW_KEY_ATTR, attrlist, numattr); } /* If no keys were found, return error */ if (pubkey == NULL && prikey == NULL && rawkey == NULL) return (KMF_ERR_ATTR_NOT_FOUND); keylabel = kmf_get_attr_ptr(KMF_KEYLABEL_ATTR, attrlist, numattr); if (keylabel != NULL) { nickname.data = (uchar_t *)keylabel; nickname.len = strlen(keylabel); } if (rawkey != NULL) { uchar_t ver = 0; SECKEYPrivateKeyInfo rpk; KMF_DATA derkey = {NULL, 0}; KMF_DATA *cert; cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist, numattr); if (cert == NULL) return (rv); /* * Decode the cert into an NSS CERT object so we can access the * SPKI and KeyUsage data later. */ nss_cert = CERT_DecodeCertFromPackage((char *)cert->Data, cert->Length); if (nss_cert == NULL) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_BAD_CERT_FORMAT; goto cleanup; } (void) memset(&rpk, 0, sizeof (rpk)); rpk.arena = NULL; rpk.version.type = siUnsignedInteger; rpk.version.data = &ver; rpk.version.len = 1; if (rawkey->keytype == KMF_RSA) { rv = DerEncodeRSAPrivateKey(&derkey, &rawkey->rawdata.rsa); if (rv != KMF_OK) goto cleanup; } else if (rawkey->keytype == KMF_DSA) { rv = DerEncodeDSAPrivateKey(&derkey, &rawkey->rawdata.dsa); if (rv != KMF_OK) goto cleanup; } else if (rawkey->keytype == KMF_ECDSA) { rv = DerEncodeECPrivateKey(&derkey, &rawkey->rawdata.ec); if (rv != KMF_OK) goto cleanup; } rpk.algorithm = nss_cert->subjectPublicKeyInfo.algorithm; rpk.privateKey.data = derkey.Data; rpk.privateKey.len = derkey.Length; rpk.attributes = NULL; ckrv = PK11_ImportPrivateKeyInfo(nss_slot, &rpk, &nickname, &nss_cert->subjectPublicKeyInfo.subjectPublicKey, TRUE, TRUE, nss_cert->keyUsage, NULL); if (ckrv != CKR_OK) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_INTERNAL; } kmf_free_data(&derkey); } else if (pubkey != NULL && pubkey->kstype == KMF_KEYSTORE_NSS) { CK_OBJECT_HANDLE pk; SECKEYPublicKey *publicKey = (SECKEYPublicKey *) pubkey->keyp; pk = PK11_ImportPublicKey(nss_slot, publicKey, PR_TRUE); if (pk == CK_INVALID_HANDLE) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_INTERNAL; } } else if (prikey != NULL && prikey->kstype == KMF_KEYSTORE_NSS) { SECKEYPrivateKey *pk; SECKEYPrivateKey *privKey = (SECKEYPrivateKey *) prikey->keyp; pk = PK11_LoadPrivKey(nss_slot, privKey, NULL, PR_TRUE, PR_TRUE); if (pk == CK_INVALID_HANDLE) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_INTERNAL; } /* We stored it, but don't need the handle anymore */ SECKEY_DestroyPrivateKey(pk); } cleanup: if (nss_cert != NULL) CERT_DestroyCertificate(nss_cert); PK11_FreeSlot(nss_slot); return (rv); } /* * This function is called by NSS_StoreCert() and NSS_ImportCert(). * The "label" and "trust_flag" arguments can be NULL. */ static KMF_RETURN store_cert(KMF_HANDLE_T handle, PK11SlotInfo *nss_slot, KMF_DATA *cert, char *label, char *trust_flag) { KMF_RETURN ret = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; SECStatus nss_rv; CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB(); CERTCertificate *nss_cert = NULL; CERTCertTrust *nss_trust = NULL; if (nss_slot == NULL || cert == NULL) return (KMF_ERR_BAD_PARAMETER); nss_cert = CERT_DecodeCertFromPackage((char *)cert->Data, cert->Length); if (nss_cert == NULL) { SET_ERROR(kmfh, PORT_GetError()); ret = KMF_ERR_BAD_CERT_FORMAT; goto out; } /* Store the cert into the NSS database */ nss_rv = PK11_ImportCert(nss_slot, nss_cert, CK_INVALID_HANDLE, label, 0); if (nss_rv) { SET_ERROR(kmfh, nss_rv); ret = KMF_ERR_BAD_CERT_FORMAT; goto out; } /* If trust_flag is NULL, then we are done */ if (trust_flag == NULL) goto out; nss_trust = (CERTCertTrust *) malloc(sizeof (CERTCertTrust)); if (nss_trust == NULL) { ret = KMF_ERR_MEMORY; goto out; } nss_rv = CERT_DecodeTrustString(nss_trust, trust_flag); if (nss_rv) { SET_ERROR(kmfh, nss_rv); ret = KMF_ERR_BAD_PARAMETER; goto out; } nss_rv = CERT_ChangeCertTrust(certHandle, nss_cert, nss_trust); if (nss_rv) { SET_ERROR(kmfh, nss_rv); ret = KMF_ERR_BAD_PARAMETER; } out: if (nss_cert != NULL) { CERT_DestroyCertificate(nss_cert); } if (nss_trust != NULL) { free(nss_trust); } return (ret); } KMF_RETURN NSS_StoreCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN ret = KMF_OK; PK11SlotInfo *nss_slot = NULL; KMF_DATA *cert = NULL; char *label = NULL; char *trust_flag = NULL; if (handle == NULL || attrlist == NULL || numattr == 0) { return (KMF_ERR_BAD_PARAMETER); } ret = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); if (ret != KMF_OK) return (ret); /* Get the cert data */ cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist, numattr); if (cert == NULL || cert->Data == NULL) return (KMF_ERR_BAD_PARAMETER); /* The label attribute is optional */ label = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr); /* The trustflag attriburte is optional */ trust_flag = kmf_get_attr_ptr(KMF_TRUSTFLAG_ATTR, attrlist, numattr); ret = store_cert(handle, nss_slot, cert, label, trust_flag); out: if (nss_slot != NULL) { PK11_FreeSlot(nss_slot); } return (ret); } KMF_RETURN NSS_ImportCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN ret = KMF_OK; PK11SlotInfo *nss_slot = NULL; KMF_DATA cert = {NULL, 0}; KMF_DATA cert_der = {NULL, 0}; KMF_DATA *cptr = NULL; KMF_ENCODE_FORMAT format; char *label = NULL; char *trust_flag = NULL; char *certfile = NULL; if (handle == NULL || attrlist == NULL || numattr == 0) { return (KMF_ERR_BAD_PARAMETER); } ret = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); if (ret != KMF_OK) return (ret); /* Get the input cert filename attribute */ certfile = kmf_get_attr_ptr(KMF_CERT_FILENAME_ATTR, attrlist, numattr); if (certfile == NULL) return (KMF_ERR_BAD_PARAMETER); /* Check the cert file and auto-detect the file format of it. */ ret = kmf_is_cert_file(handle, certfile, &format); if (ret != KMF_OK) return (ret); ret = kmf_read_input_file(handle, certfile, &cert); if (ret != KMF_OK) { 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; ret = kmf_pem_to_der(cert.Data, cert.Length, &cert_der.Data, &derlen); if (ret != KMF_OK) { goto cleanup; } cert_der.Length = (size_t)derlen; cptr = &cert_der; } else { cptr = &cert; } label = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr); trust_flag = kmf_get_attr_ptr(KMF_TRUSTFLAG_ATTR, attrlist, numattr); ret = store_cert(handle, nss_slot, cptr, label, trust_flag); cleanup: if (format == KMF_FORMAT_PEM) { kmf_free_data(&cert_der); } kmf_free_data(&cert); return (ret); } KMF_RETURN NSS_ImportCRL(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN ret = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; PK11SlotInfo *nss_slot = NULL; CERTSignedCrl *nss_crl = NULL; KMF_ENCODE_FORMAT format; int importOptions; SECItem crlDER; KMF_DATA crl1; KMF_DATA crl2; char *crlfilename; boolean_t crlcheck = FALSE; if (attrlist == NULL || numattr == 0) { return (KMF_ERR_BAD_PARAMETER); } ret = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); if (ret != KMF_OK) { return (ret); } crlfilename = kmf_get_attr_ptr(KMF_CRL_FILENAME_ATTR, attrlist, 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. */ ret = kmf_is_crl_file(handle, crlfilename, &format); if (ret != KMF_OK) return (ret); ret = kmf_get_attr(KMF_CRL_CHECK_ATTR, attrlist, numattr, &crlcheck, NULL); if (ret != KMF_OK) ret = KMF_OK; /* CRL_CHECK is optional */ /* set importOptions */ if (crlcheck == B_FALSE) { importOptions = CRL_IMPORT_DEFAULT_OPTIONS | CRL_IMPORT_BYPASS_CHECKS; } else { importOptions = CRL_IMPORT_DEFAULT_OPTIONS; } /* Read in the CRL file */ crl1.Data = NULL; crl2.Data = NULL; ret = kmf_read_input_file(handle, crlfilename, &crl1); if (ret != KMF_OK) { return (ret); } /* If the input CRL is in PEM format, convert it to DER first. */ if (format == KMF_FORMAT_PEM) { int len; ret = kmf_pem_to_der(crl1.Data, crl1.Length, &crl2.Data, &len); if (ret != KMF_OK) { goto out; } crl2.Length = (size_t)len; } crlDER.data = format == KMF_FORMAT_ASN1 ? crl1.Data : crl2.Data; crlDER.len = format == KMF_FORMAT_ASN1 ? crl1.Length : crl2.Length; nss_crl = PK11_ImportCRL(nss_slot, &crlDER, NULL, SEC_CRL_TYPE, NULL, importOptions, NULL, CRL_DECODE_DEFAULT_OPTIONS); if (nss_crl == NULL) { SET_ERROR(kmfh, PORT_GetError()); ret = KMF_ERR_BAD_CRLFILE; goto out; } out: if (nss_slot != NULL) { PK11_FreeSlot(nss_slot); } if (crl1.Data != NULL) { free(crl1.Data); } if (crl2.Data != NULL) { free(crl2.Data); } if (nss_crl != NULL) { (void) SEC_DestroyCrl(nss_crl); } return (ret); } KMF_RETURN NSS_DeleteCRL(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN rv = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; CERTSignedCrl *crl = NULL; CERTCertificate *cert = NULL; PK11SlotInfo *nss_slot = NULL; CERTCrlHeadNode *crlList = NULL; CERTCrlNode *crlNode = NULL; PRArenaPool *arena = NULL; CERTName *name = NULL; CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB(); char *issuername, *subjectname; /* check params */ if (numattr == 0 || attrlist == NULL) { return (KMF_ERR_BAD_PARAMETER); } rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); if (rv != KMF_OK) { return (rv); } issuername = kmf_get_attr_ptr(KMF_ISSUER_NAME_ATTR, attrlist, numattr); subjectname = kmf_get_attr_ptr(KMF_SUBJECT_NAME_ATTR, attrlist, numattr); /* Caller must specify issuer or subject but not both */ if ((issuername == NULL && subjectname == NULL) || (issuername != NULL && subjectname != NULL)) 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. */ cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, issuername); if (!cert) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_CERT_NOT_FOUND; goto out; } crl = SEC_FindCrlByName(certHandle, &cert->derSubject, SEC_CRL_TYPE); if (crl == NULL) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_CRL_NOT_FOUND; 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. */ boolean_t found = B_FALSE; int nssrv; nssrv = SEC_LookupCrls(certHandle, &crlList, SEC_CRL_TYPE); if (nssrv) { SET_ERROR(kmfh, nssrv); rv = KMF_ERR_CRL_NOT_FOUND; goto out; } if (crlList == NULL) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_CRL_NOT_FOUND; goto out; } /* Allocate space for name */ arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); if (arena == NULL) { rv = KMF_ERR_MEMORY; goto out; } name = PORT_ArenaZAlloc(arena, sizeof (*name)); if (name == NULL) { rv = KMF_ERR_MEMORY; goto out; } name->arena = arena; crlNode = crlList->first; while (crlNode && !found) { char *asciiname = NULL; SECItem* issuer; name = &crlNode->crl->crl.name; if (!name) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_CRL_NOT_FOUND; break; } asciiname = CERT_NameToAscii(name); if (asciiname == NULL) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_CRL_NOT_FOUND; break; } if (strcmp(subjectname, asciiname) == 0) { found = B_TRUE; issuer = &crlNode->crl->crl.derName; crl = SEC_FindCrlByName(certHandle, issuer, SEC_CRL_TYPE); if (crl == NULL) { /* We found a cert but no CRL */ SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_CRL_NOT_FOUND; } } PORT_Free(asciiname); crlNode = crlNode->next; } if (rv) { goto out; } } if (crl) { (void) SEC_DeletePermCRL(crl); } out: if (nss_slot != NULL) { PK11_FreeSlot(nss_slot); } if (crlList != NULL) { PORT_FreeArena(crlList->arena, PR_FALSE); } if (arena != NULL) { PORT_FreeArena(arena, PR_FALSE); } if (cert != NULL) { CERT_DestroyCertificate(cert); } if (crl != NULL) { (void) SEC_DestroyCrl(crl); } return (rv); } KMF_RETURN NSS_FindCRL(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN rv = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; PK11SlotInfo *nss_slot = NULL; CERTCrlHeadNode *crlList = NULL; CERTCrlNode *crlNode = NULL; PRArenaPool *arena = NULL; CERTName *name = NULL; SECStatus nssrv; char *asciiname = NULL; int crl_num; int i, *CRLCount; CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB(); char **CRLNameList; if (numattr == 0 || attrlist == NULL) { return (KMF_ERR_BAD_PARAMETER); } rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); if (rv != KMF_OK) { return (rv); } CRLCount = kmf_get_attr_ptr(KMF_CRL_COUNT_ATTR, attrlist, numattr); if (CRLCount == NULL) return (KMF_ERR_BAD_PARAMETER); CRLNameList = (char **)kmf_get_attr_ptr(KMF_CRL_NAMELIST_ATTR, attrlist, numattr); /* Look up Crls */ nssrv = SEC_LookupCrls(certHandle, &crlList, SEC_CRL_TYPE); if (nssrv) { SET_ERROR(kmfh, rv); rv = KMF_ERR_CRL_NOT_FOUND; goto out; } /* Allocate space for name first */ arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); if (arena == NULL) { rv = KMF_ERR_MEMORY; goto out; } name = PORT_ArenaZAlloc(arena, sizeof (*name)); if (name == NULL) { rv = KMF_ERR_MEMORY; goto out; } name->arena = arena; /* * Loop thru the crlList and create a crl list with CRL's subject name. */ crlNode = crlList->first; crl_num = 0; while (crlNode) { char *subj_name; /* Get the CRL subject name */ name = &crlNode->crl->crl.name; if (!name) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_CRL_NOT_FOUND; break; } if (CRLNameList != NULL) { asciiname = CERT_NameToAscii(name); if (asciiname == NULL) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_CRL_NOT_FOUND; break; } subj_name = strdup(asciiname); PORT_Free(asciiname); if (subj_name == NULL) { rv = KMF_ERR_MEMORY; break; } CRLNameList[crl_num] = subj_name; } crl_num++; crlNode = crlNode->next; } if (rv == KMF_OK) { /* success */ *CRLCount = crl_num; } out: if (nss_slot != NULL) { PK11_FreeSlot(nss_slot); } if (crlList != NULL) { PORT_FreeArena(crlList->arena, PR_FALSE); } if (arena != NULL) { PORT_FreeArena(arena, PR_FALSE); } /* If failed, free memory allocated for the returning rlist */ if (rv && (CRLNameList != NULL)) { for (i = 0; i < crl_num; i++) { free(CRLNameList[i]); } } return (rv); } KMF_RETURN NSS_FindCertInCRL(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist) { KMF_RETURN rv = KMF_OK; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; PK11SlotInfo *nss_slot = NULL; CERTCertificate *cert = NULL; CERTSignedCrl *crl = NULL; CERTCrlEntry *entry; boolean_t match = B_FALSE; int i; CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB(); char *certlabel; KMF_DATA *certdata; /* check params */ if (numattr == 0 || attrlist == NULL) { return (KMF_ERR_BAD_PARAMETER); } rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot); if (rv != KMF_OK) { return (rv); } certlabel = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr); /* Find the certificate first */ if (certlabel != NULL) { cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, certlabel); } else { SECItem derCert = { NULL, 0}; certdata = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist, numattr); if (certdata == NULL) return (KMF_ERR_BAD_PARAMETER); derCert.data = certdata->Data; derCert.len = certdata->Length; cert = CERT_FindCertByDERCert(certHandle, &derCert); } if (cert == NULL) { SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_CERT_NOT_FOUND; goto out; } /* Find the CRL with the same issuer as the given certificate. */ crl = SEC_FindCrlByName(certHandle, &cert->derIssuer, SEC_CRL_TYPE); if (crl == NULL) { /* * Could not find the CRL issued by the same issuer. This * usually means that the CRL is not installed in the DB. */ SET_ERROR(kmfh, PORT_GetError()); rv = KMF_ERR_CRL_NOT_FOUND; goto out; } /* Check if the certificate's serialNumber is revoked in the CRL */ i = 0; while ((entry = (crl->crl).entries[i++]) != NULL) { if (SECITEM_CompareItem(&(cert->serialNumber), &(entry->serialNumber)) == SECEqual) { match = B_TRUE; break; } } if (!match) { rv = KMF_ERR_NOT_REVOKED; } out: if (nss_slot != NULL) { PK11_FreeSlot(nss_slot); } if (cert != NULL) { CERT_DestroyCertificate(cert); } if (crl != NULL) { (void) SEC_DestroyCrl(crl); } return (rv); }