Beispiel #1
0
// getPKCS12FilePassword
//
// Launch a dialog requesting the user for the password to a PKCS#12 file.
// Handle user canceled by returning null password (caller must catch).
nsresult
nsPKCS12Blob::getPKCS12FilePassword(SECItem *unicodePw)
{
  nsresult rv = NS_OK;
  nsAutoString password;
  nsCOMPtr<nsICertificateDialogs> certDialogs;
  rv = ::getNSSDialogs(getter_AddRefs(certDialogs), 
                       NS_GET_IID(nsICertificateDialogs),
                       NS_CERTIFICATEDIALOGS_CONTRACTID);
  if (NS_FAILED(rv)) return rv;
  bool pressedOK;
  {
    nsPSMUITracker tracker;
    if (tracker.isUIForbidden()) {
      rv = NS_ERROR_NOT_AVAILABLE;
    }
    else {
      rv = certDialogs->GetPKCS12FilePassword(mUIContext, password, &pressedOK);
    }
  }
  if (NS_FAILED(rv) || !pressedOK) return rv;
  unicodeToItem(password.get(), unicodePw);
  return NS_OK;
}
// 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;
}