Пример #1
0
/* import PFX item 
 * der_pfx is the der encoded pfx structure
 * pbef and pbearg are the integrity/encryption password call back
 * ncCall is the nickname collision calllback
 * slot is the destination token
 * wincx window handler
 *
 * on error, error code set and SECFailure returned 
 */
SECStatus
SEC_PKCS12PutPFX(SECItem *der_pfx, SECItem *pwitem,
		 SEC_PKCS12NicknameCollisionCallback ncCall,
		 PK11SlotInfo *slot,
		 void *wincx)
{
    SEC_PKCS12PFXItem *pfx;
    SEC_PKCS12AuthenticatedSafe *asafe;
    SEC_PKCS12SafeContents *safe_contents = NULL;
    SECStatus rv;

    if(!der_pfx || !pwitem || !slot) {
	return SECFailure;
    }

    /* decode and validate each section */
    rv = SECFailure;

    pfx = sec_pkcs12_get_pfx(der_pfx, pwitem);
    if(pfx != NULL) {
	asafe = sec_pkcs12_get_auth_safe(pfx);
	if(asafe != NULL) {

	    /* decrypt safe -- only if not empty */
	    if(asafe->emptySafe != PR_TRUE) {
		rv = sec_pkcs12_decrypt_auth_safe(asafe, pwitem, wincx);
		if(rv == SECSuccess) {
		    safe_contents = sec_pkcs12_get_safe_contents(asafe);
		    if(safe_contents == NULL) {
			rv = SECFailure;
		    }
		}
	    } else {
		safe_contents = sec_pkcs12_create_safe_contents(asafe->poolp);
		if(safe_contents == NULL) {
		    rv = SECFailure;
		} else {
                    safe_contents->swapUnicode = pfx->swapUnicode;
		    rv = SECSuccess;
		}
	    }

	    /* get safe contents and begin import */
	    if(rv == SECSuccess) {
		SEC_PKCS12DecoderContext *p12dcx;

		p12dcx = sec_PKCS12ConvertOldSafeToNew(pfx->poolp, slot,
					pfx->swapUnicode,
					pwitem, wincx, safe_contents,
					&asafe->baggage);
		if(!p12dcx) {
		    rv = SECFailure;
		    goto loser;
		}

		if(SEC_PKCS12DecoderValidateBags(p12dcx, ncCall) 
				!= SECSuccess) {
		    rv = SECFailure;
		    goto loser;
		}

		rv = SEC_PKCS12DecoderImportBags(p12dcx);
	    }

	}
    }

loser:

    if(pfx) {
	SEC_PKCS12DestroyPFX(pfx);
    }

    return rv;
}
Пример #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;
}
Пример #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;
}
Пример #4
0
// 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;
}
Пример #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);
}