char *
crypto_encrypt (const char *cipher,
                const guint8 *data,
                gsize data_len,
                const char *iv,
                gsize iv_len,
                const char *key,
                gsize key_len,
                gsize *out_len,
                GError **error)
{
	SECStatus ret;
	CK_MECHANISM_TYPE cipher_mech = CKM_DES3_CBC_PAD;
	PK11SlotInfo *slot = NULL;
	SECItem key_item = { .data = (unsigned char *) key, .len = key_len };
	SECItem iv_item = { .data = (unsigned char *) iv, .len = iv_len };
	PK11SymKey *sym_key = NULL;
	SECItem *sec_param = NULL;
	PK11Context *ctx = NULL;
	unsigned char *output, *padded_buf;
	gsize output_len;
	int encrypted_len = 0, i;
	gboolean success = FALSE;
	gsize padded_buf_len, pad_len;

	if (!crypto_init (error))
		return NULL;

	if (!strcmp (cipher, CIPHER_DES_EDE3_CBC))
		cipher_mech = CKM_DES3_CBC_PAD;
	else if (!strcmp (cipher, CIPHER_AES_CBC))
		cipher_mech = CKM_AES_CBC_PAD;
	else {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERROR_UNKNOWN_CIPHER,
		             _("Private key cipher '%s' was unknown."),
		             cipher);
		return NULL;
	}

	/* If data->len % ivlen == 0, then we add another complete block
	 * onto the end so that the decrypter knows there's padding.
	 */
	pad_len = iv_len - (data_len % iv_len);
	output_len = padded_buf_len = data_len + pad_len;
	padded_buf = g_malloc0 (padded_buf_len);

	memcpy (padded_buf, data, data_len);
	for (i = 0; i < pad_len; i++)
		padded_buf[data_len + i] = (guint8) (pad_len & 0xFF);

	output = g_malloc0 (output_len);

	slot = PK11_GetBestSlot (cipher_mech, NULL);
	if (!slot) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERROR_FAILED,
		             _("Failed to initialize the encryption cipher slot."));
		goto out;
	}

	sym_key = PK11_ImportSymKey (slot, cipher_mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL);
	if (!sym_key) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
		             _("Failed to set symmetric key for encryption."));
		goto out;
	}

	sec_param = PK11_ParamFromIV (cipher_mech, &iv_item);
	if (!sec_param) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
		             _("Failed to set IV for encryption."));
		goto out;
	}

	ctx = PK11_CreateContextBySymKey (cipher_mech, CKA_ENCRYPT, sym_key, sec_param);
	if (!ctx) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
		             _("Failed to initialize the encryption context."));
		goto out;
	}

	ret = PK11_CipherOp (ctx, output, &encrypted_len, output_len, padded_buf, padded_buf_len);
	if (ret != SECSuccess) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
		             _("Failed to encrypt: %d."),
		             PORT_GetError ());
		goto out;
	}

	if (encrypted_len != output_len) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
		             _("Unexpected amount of data after encrypting."));
		goto out;
	}

	*out_len = encrypted_len;
	success = TRUE;

out:
	if (ctx)
		PK11_DestroyContext (ctx, PR_TRUE);
	if (sym_key)
		PK11_FreeSymKey (sym_key);
	if (sec_param)
		SECITEM_FreeItem (sec_param, PR_TRUE);
	if (slot)
		PK11_FreeSlot (slot);

	memset (padded_buf, 0, padded_buf_len);
	g_free (padded_buf);

	if (!success) {
		memset (output, 0, output_len);
		g_free (output);
		output = NULL;
	}
	return (char *) output;
}

NMCryptoFileFormat
crypto_verify_cert (const unsigned char *data,
                    gsize len,
                    GError **error)
{
	CERTCertificate *cert;

	if (!crypto_init (error))
		return NM_CRYPTO_FILE_FORMAT_UNKNOWN;

	/* Try DER/PEM first */
	cert = CERT_DecodeCertFromPackage ((char *) data, len);
	if (!cert) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERROR_INVALID_DATA,
		             _("Couldn't decode certificate: %d"),
		             PORT_GetError());
		return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
	}

	CERT_DestroyCertificate (cert);
	return NM_CRYPTO_FILE_FORMAT_X509;
}

gboolean
crypto_verify_pkcs12 (const guint8 *data,
                      gsize data_len,
                      const char *password,
                      GError **error)
{
	SEC_PKCS12DecoderContext *p12ctx = NULL;
	SECItem pw = { 0 };
	PK11SlotInfo *slot = NULL;
	SECStatus s;
	gunichar2 *ucs2_password;
	glong ucs2_chars = 0;
#ifndef WORDS_BIGENDIAN
	guint16 *p;
#endif /* WORDS_BIGENDIAN */

	if (error)
		g_return_val_if_fail (*error == NULL, FALSE);

	if (!crypto_init (error))
		return FALSE;

	/* PKCS#12 passwords are apparently UCS2 BIG ENDIAN, and NSS doesn't do
	 * any conversions for us.
	 */
	if (password && *password) {
		if (!g_utf8_validate (password, -1, NULL)) {
			g_set_error (error, NM_CRYPTO_ERROR,
			             NM_CRYPTO_ERROR_INVALID_PASSWORD,
			             _("Password must be UTF-8"));
			return FALSE;
		}
		ucs2_password = g_utf8_to_utf16 (password, strlen (password), NULL, &ucs2_chars, NULL);
		/* Can't fail if g_utf8_validate() succeeded */
		g_return_val_if_fail (ucs2_password != NULL && ucs2_chars != 0, FALSE);

		ucs2_chars *= 2;  /* convert # UCS2 characters -> bytes */
		pw.data = PORT_ZAlloc(ucs2_chars + 2);
		memcpy (pw.data, ucs2_password, ucs2_chars);
		pw.len = ucs2_chars + 2;  /* include terminating NULL */

		memset (ucs2_password, 0, ucs2_chars);
		g_free (ucs2_password);

#ifndef WORDS_BIGENDIAN
		for (p = (guint16 *) pw.data; p < (guint16 *) (pw.data + pw.len); p++)
			*p = GUINT16_SWAP_LE_BE (*p);
#endif /* WORDS_BIGENDIAN */
	} else {
		/* NULL password */
		pw.data = NULL;
		pw.len = 0;
	}

	slot = PK11_GetInternalKeySlot();
	p12ctx = SEC_PKCS12DecoderStart (&pw, slot, NULL, NULL, NULL, NULL, NULL, NULL);
	if (!p12ctx) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERROR_FAILED,
		             _("Couldn't initialize PKCS#12 decoder: %d"),
		             PORT_GetError());
		goto error;
	}

	s = SEC_PKCS12DecoderUpdate (p12ctx, (guint8 *)data, data_len);
	if (s != SECSuccess) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERROR_INVALID_DATA,
		             _("Couldn't decode PKCS#12 file: %d"),
		             PORT_GetError());
		goto error;
	}

	s = SEC_PKCS12DecoderVerify (p12ctx);
	if (s != SECSuccess) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERROR_DECRYPTION_FAILED,
		             _("Couldn't verify PKCS#12 file: %d"),
		             PORT_GetError());
		goto error;
	}

	SEC_PKCS12DecoderFinish (p12ctx);
	SECITEM_ZfreeItem (&pw, PR_FALSE);
	return TRUE;

error:
	if (p12ctx)
		SEC_PKCS12DecoderFinish (p12ctx);

	if (slot)
		PK11_FreeSlot(slot);

	SECITEM_ZfreeItem (&pw, PR_FALSE);
	return FALSE;
}
Exemple #2
0
nsresult
nsPKCS12Blob::ImportFromFileHelper(nsILocalFile *file, 
                                   nsPKCS12Blob::ImportMode aImportMode,
                                   nsPKCS12Blob::RetryReason &aWantRetry)
{
  nsNSSShutDownPreventionLock locker;
  nsresult rv;
  SECStatus srv = SECSuccess;
  SEC_PKCS12DecoderContext *dcx = NULL;
  SECItem unicodePw;

  PK11SlotInfo *slot=nsnull;
  nsXPIDLString tokenName;
  unicodePw.data = NULL;
  
  aWantRetry = rr_do_not_retry;

  if (aImportMode == im_try_zero_length_secitem)
  {
    unicodePw.len = 0;
  }
  else
  {
    // get file password (unicode)
    rv = getPKCS12FilePassword(&unicodePw);
    if (NS_FAILED(rv)) goto finish;
    if (unicodePw.data == NULL) {
      handleError(PIP_PKCS12_USER_CANCELED);
      return NS_OK;
    }
  }
  
  mToken->GetTokenName(getter_Copies(tokenName));
  {
    NS_ConvertUTF16toUTF8 tokenNameCString(tokenName);
    slot = PK11_FindSlotByName(tokenNameCString.get());
  }
  if (!slot) {
    srv = SECFailure;
    goto finish;
  }

  // initialize the decoder
  dcx = SEC_PKCS12DecoderStart(&unicodePw, slot, NULL,
                               digest_open, digest_close,
                               digest_read, digest_write,
                               this);
  if (!dcx) {
    srv = SECFailure;
    goto finish;
  }
  // read input file and feed it to the decoder
  rv = inputToDecoder(dcx, file);
  if (NS_FAILED(rv)) {
    if (NS_ERROR_ABORT == rv) {
      // inputToDecoder indicated a NSS error
      srv = SECFailure;
    }
    goto finish;
  }
  // verify the blob
  srv = SEC_PKCS12DecoderVerify(dcx);
  if (srv) goto finish;
  // validate bags
  srv = SEC_PKCS12DecoderValidateBags(dcx, nickname_collision);
  if (srv) goto finish;
  // import cert and key
  srv = SEC_PKCS12DecoderImportBags(dcx);
  if (srv) goto finish;
  // Later - check to see if this should become default email cert
  handleError(PIP_PKCS12_RESTORE_OK);
finish:
  // If srv != SECSuccess, NSS probably set a specific error code.
  // We should use that error code instead of inventing a new one
  // for every error possible.
  if (srv != SECSuccess) {
    if (SEC_ERROR_BAD_PASSWORD == PORT_GetError()) {
      if (unicodePw.len == sizeof(PRUnichar))
      {
        // no password chars available, 
        // unicodeToItem allocated space for the trailing zero character only.
        aWantRetry = rr_auto_retry_empty_password_flavors;
      }
      else
      {
        aWantRetry = rr_bad_password;
        handleError(PIP_PKCS12_NSS_ERROR);
      }
    }
    else
    {
      handleError(PIP_PKCS12_NSS_ERROR);
    }
  } else if (NS_FAILED(rv)) { 
    handleError(PIP_PKCS12_RESTORE_FAILED);
  }
  if (slot)
    PK11_FreeSlot(slot);
  // finish the decoder
  if (dcx)
    SEC_PKCS12DecoderFinish(dcx);
  SECITEM_ZfreeItem(&unicodePw, false);
  return NS_OK;
}
Exemple #3
0
static gboolean
import_from_file_helper (EPKCS12 *pkcs12,
                         PK11SlotInfo *slot,
                         const gchar *path,
                         gboolean *aWantRetry,
                         GError **error)
{
	/*nsNSSShutDownPreventionLock locker; */
	gboolean rv;
	SECStatus srv = SECSuccess;
	SEC_PKCS12DecoderContext *dcx = NULL;
	SECItem passwd;
	GError *err = NULL;

	*aWantRetry = FALSE;

	passwd.data = NULL;
	rv = prompt_for_password (
		_("PKCS12 File Password"),
		_("Enter password for PKCS12 file:"), &passwd);
	if (!rv) goto finish;
	if (passwd.data == NULL) {
		handle_error (PKCS12_USER_CANCELED);
		return TRUE;
	}

	/* initialize the decoder */
	dcx = SEC_PKCS12DecoderStart (
		&passwd,
		slot,
		/* we specify NULL for all the
		 * funcs + data so it'll use the
		 * default pk11wrap functions */
		NULL, NULL, NULL,
		NULL, NULL, NULL);
	if (!dcx) {
		srv = SECFailure;
		goto finish;
	}
	/* read input file and feed it to the decoder */
	rv = input_to_decoder (dcx, path, &err);
	if (!rv) {
#ifdef notyet
		/* XXX we need this to check the gerror */
		if (NS_ERROR_ABORT == rv) {
			/* inputToDecoder indicated a NSS error */
			srv = SECFailure;
		}
#else
		srv = SECFailure;
#endif
		goto finish;
	}

	/* verify the blob */
	srv = SEC_PKCS12DecoderVerify (dcx);
	if (srv) goto finish;
	/* validate bags */
	srv = SEC_PKCS12DecoderValidateBags (dcx, nickname_collision);
	if (srv) goto finish;
	/* import cert and key */
	srv = SEC_PKCS12DecoderImportBags (dcx);
	if (srv) goto finish;
	/* Later - check to see if this should become default email cert */
	handle_error (PKCS12_RESTORE_OK);
 finish:
	/* If srv != SECSuccess, NSS probably set a specific error code.
	 * We should use that error code instead of inventing a new one
	 * for every error possible. */
	if (srv != SECSuccess) {
		if (SEC_ERROR_BAD_PASSWORD == PORT_GetError ()) {
			*aWantRetry = TRUE;
		}
		handle_error (PKCS12_NSS_ERROR);
	} else if (!rv) {
		handle_error (PKCS12_RESTORE_FAILED);
	}
	/* finish the decoder */
	if (dcx)
		SEC_PKCS12DecoderFinish (dcx);
	return TRUE;
}
// Based on nsPKCS12Blob::ImportFromFileHelper.
int
nsPKCS12Blob_ImportHelper(const char* pkcs12_data,
                          size_t pkcs12_len,
                          const base::string16& password,
                          bool is_extractable,
                          bool try_zero_length_secitem,
                          PK11SlotInfo *slot,
                          net::CertificateList* imported_certs)
{
    DCHECK(pkcs12_data);
    DCHECK(slot);
    int import_result = net::ERR_PKCS12_IMPORT_FAILED;
    SECStatus srv = SECSuccess;
    SEC_PKCS12DecoderContext *dcx = NULL;
    SECItem unicodePw;
    SECItem attribute_value;
    CK_BBOOL attribute_data = CK_FALSE;
    const SEC_PKCS12DecoderItem* decoder_item = NULL;

    unicodePw.type = siBuffer;
    unicodePw.len = 0;
    unicodePw.data = NULL;
    if (!try_zero_length_secitem) {
        unicodeToItem(password.c_str(), &unicodePw);
    }

    // Initialize the decoder
    dcx = SEC_PKCS12DecoderStart(&unicodePw, slot,
                                 // wincx
                                 NULL,
                                 // dOpen, dClose, dRead, dWrite, dArg: NULL
                                 // specifies default impl using memory buffer.
                                 NULL, NULL, NULL, NULL, NULL);
    if (!dcx) {
        srv = SECFailure;
        goto finish;
    }
    // feed input to the decoder
    srv = SEC_PKCS12DecoderUpdate(dcx,
                                  (unsigned char*)pkcs12_data,
                                  pkcs12_len);
    if (srv) goto finish;
    // verify the blob
    srv = SEC_PKCS12DecoderVerify(dcx);
    if (srv) goto finish;
    // validate bags
    srv = SEC_PKCS12DecoderValidateBags(dcx, nickname_collision);
    if (srv) goto finish;
    // import certificate and key
    srv = SEC_PKCS12DecoderImportBags(dcx);
    if (srv) goto finish;

    attribute_value.data = &attribute_data;
    attribute_value.len = sizeof(attribute_data);

    srv = SEC_PKCS12DecoderIterateInit(dcx);
    if (srv) goto finish;

    if (imported_certs)
        imported_certs->clear();

    // Collect the list of decoded certificates, and mark private keys
    // non-extractable if needed.
    while (SEC_PKCS12DecoderIterateNext(dcx, &decoder_item) == SECSuccess) {
        if (decoder_item->type != SEC_OID_PKCS12_V1_CERT_BAG_ID)
            continue;

        CERTCertificate* cert = PK11_FindCertFromDERCertItem(
                                    slot, decoder_item->der,
                                    NULL);  // wincx
        if (!cert) {
            LOG(ERROR) << "Could not grab a handle to the certificate in the slot "
                       << "from the corresponding PKCS#12 DER certificate.";
            continue;
        }

        // Add the cert to the list
        if (imported_certs) {
            // Empty list of intermediates.
            net::X509Certificate::OSCertHandles intermediates;
            imported_certs->push_back(
                net::X509Certificate::CreateFromHandle(cert, intermediates));
        }

        // Once we have determined that the imported certificate has an
        // associated private key too, only then can we mark the key as
        // non-extractable.
        if (!decoder_item->hasKey) {
            CERT_DestroyCertificate(cert);
            continue;
        }

        // Iterate through all the imported PKCS12 items and mark any accompanying
        // private keys as non-extractable.
        if (!is_extractable) {
            SECKEYPrivateKey* privKey = PK11_FindPrivateKeyFromCert(slot, cert,
                                        NULL);  // wincx
            if (privKey) {
                // Mark the private key as non-extractable.
                srv = PK11_WriteRawAttribute(PK11_TypePrivKey, privKey, CKA_EXTRACTABLE,
                                             &attribute_value);
                SECKEY_DestroyPrivateKey(privKey);
                if (srv) {
                    LOG(ERROR) << "Could not set CKA_EXTRACTABLE attribute on private "
                               << "key.";
                    CERT_DestroyCertificate(cert);
                    break;
                }
            }
        }
        CERT_DestroyCertificate(cert);
        if (srv) goto finish;
    }
    import_result = net::OK;
finish:
    // If srv != SECSuccess, NSS probably set a specific error code.
    // We should use that error code instead of inventing a new one
    // for every error possible.
    if (srv != SECSuccess) {
        int error = PORT_GetError();
        LOG(ERROR) << "PKCS#12 import failed with error " << error;
        switch (error) {
        case SEC_ERROR_BAD_PASSWORD:
        case SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT:
            import_result = net::ERR_PKCS12_IMPORT_BAD_PASSWORD;
            break;
        case SEC_ERROR_PKCS12_INVALID_MAC:
            import_result = net::ERR_PKCS12_IMPORT_INVALID_MAC;
            break;
        case SEC_ERROR_BAD_DER:
        case SEC_ERROR_PKCS12_DECODING_PFX:
        case SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE:
            import_result = net::ERR_PKCS12_IMPORT_INVALID_FILE;
            break;
        case SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM:
        case SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE:
        case SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM:
        case SEC_ERROR_PKCS12_UNSUPPORTED_VERSION:
            import_result = net::ERR_PKCS12_IMPORT_UNSUPPORTED;
            break;
        default:
            import_result = net::ERR_PKCS12_IMPORT_FAILED;
            break;
        }
    }
    // Finish the decoder
    if (dcx)
        SEC_PKCS12DecoderFinish(dcx);
    SECITEM_ZfreeItem(&unicodePw, PR_FALSE);
    return import_result;
}
Exemple #5
0
UtlBoolean SmimeBody::nssSmimeDecrypt(const char* derPkcs12,
                               int derPkcs12Length,
                               const char* pkcs12Password,
                               UtlBoolean dataIsInBase64Format,
                               const char* dataToDecrypt,
                               int dataToDecryptLength,
                               UtlString& decryptedData)
{
    UtlBoolean decryptSucceeded = FALSE;
    decryptedData.remove(0);

#ifdef ENABLE_NSS_SMIME
    Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SmimeBody::nssSmimeDecrypt not implemented");

    ////// BEGIN WARNING: THIS CODE HAS NOT BEEN TESTED AT ALL ///////

    // allocate a temporaty slot in the database
    PK11SlotInfo *slot = PK11_GetInternalKeySlot();
    PRBool swapUnicode = PR_FALSE;
    SEC_PKCS12DecoderContext *p12Decoder = NULL;

    // Need to put the pkcs12 password into a SECItem
    SECItem passwordItem;
    passwordItem.data = (unsigned char*) pkcs12Password;
    passwordItem.len = strlen(pkcs12Password);
    SECItem uniPasswordItem;
    uniPasswordItem.data = NULL;
    uniPasswordItem.len = 0;

#ifdef IS_LITTLE_ENDIAN
    swapUnicode = PR_TRUE;
#endif

    // Allocate a temporary internal slot
    slot = PK11_GetInternalSlot();
    if(slot == NULL)
    {
        Os::Logger::instance().log(FAC_SIP, PRI_ERR, "unable to use slot in NSS dataqbase for S/MIME decryption");
    }
    else
    {
        // Do UNICODE conversion of password based upon the platform
        // (not sure this is even neccessary in our application).  I do not
        // know how we would get unicode passwords
        if(0) //P12U_UnicodeConversion(NULL, &uniPasswordItem, passwordItem, PR_TRUE,
			  //    swapUnicode) != SECSuccess)
        {
            Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                "NSS Unicode conversion failed for PKCS12 object for S/MIME decryption");
        }
        else
        {
            // Initialze the decoder for the PKCS12 container for the private key
            p12Decoder = SEC_PKCS12DecoderStart(&passwordItem, slot, NULL,
				    NULL, NULL, NULL, NULL, NULL);
            if(!p12Decoder)
            {
                Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                    "failed to initialize PKCS12 decoder to extract private key for S/MIME decryption");
            }
            else
            {
                // Add the PKCS12 data to the decoder
                if(SEC_PKCS12DecoderUpdate(p12Decoder,
                                           (unsigned char *) derPkcs12,
                                           derPkcs12Length) != SECSuccess ||
                   // Validate the decoded PKCS12
                   SEC_PKCS12DecoderVerify(p12Decoder) != SECSuccess)

                {
                    Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                        "unable to decrypt PKCS12 for S/MIME decryption. Perhaps invalid PKCS12 or PKCS12 password");
                }
                else
                {
                    // Import the private key and certificate from the
                    // decoded PKCS12 into the database
                    if(SEC_PKCS12DecoderImportBags(p12Decoder) != SECSuccess)
                    {
                        Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                            "failed to import private key and certificate into NSS database");
                    }
                    else
                    {
                        // Put the S/MIME data in a SECItem
                        SECItem dataToDecodeItem;
                        dataToDecodeItem.data = (unsigned char *) dataToDecrypt;
                        dataToDecodeItem.len = dataToDecryptLength;

                        if(dataIsInBase64Format)
                        {
                            // TODO:
                            // Use some NSS util. to convert base64 to binary
                            Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                                "NSS decrypt of base64 S/MIME message not implemented");
                        }
                        else
                        {
                            // Decode the S/MIME blob
                            NSSCMSMessage *cmsMessage =
                                NSS_CMSMessage_CreateFromDER(&dataToDecodeItem,
                                                             nssOutToUtlString,
                                                             &decryptedData,
                                                             NULL, NULL,
                                                             NULL, NULL);


                            if(cmsMessage &&
                               decryptedData.length() > 0)
                            {
                                decryptSucceeded = TRUE;
                            }

                            // TODO:
                            // Remove the temporary private key from the
                            // database using the slot handle
                        }
                    }

                }
            }
        }
    }

    // Clean up
    if(p12Decoder)
    {
	    SEC_PKCS12DecoderFinish(p12Decoder);
    }
    if(uniPasswordItem.data)
    {
	    SECITEM_ZfreeItem(&uniPasswordItem, PR_FALSE);
    }

    ////// END WARNING   /////
#else
    Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SmimeBody::nssSmimeDecrypt invoked with ENABLE_NSS_SMIME not defined");
#endif

    return(decryptSucceeded);
}