/*
 * SecCmsSignedDataEncodeBeforeStart - do all the necessary things to a SignedData
 *     before start of encoding.
 *
 * In detail:
 *  - find out about the right value to put into sigd->version
 *  - come up with a list of digestAlgorithms (which should be the union of the algorithms
 *         in the signerinfos).
 *         If we happen to have a pre-set list of algorithms (and digest values!), we
 *         check if we have all the signerinfos' algorithms. If not, this is an error.
 */
OSStatus
SecCmsSignedDataEncodeBeforeStart(SecCmsSignedDataRef sigd)
{
    SecCmsSignerInfoRef signerinfo;
    SECOidTag digestalgtag;
    CSSM_DATA_PTR dummy;
    int version;
    OSStatus rv;
    Boolean haveDigests = PR_FALSE;
    int n, i;
    PLArenaPool *poolp;

    poolp = sigd->cmsg->poolp;

    /* we assume that we have precomputed digests if there is a list of algorithms, and */
    /* a chunk of data for each of those algorithms */
    if (sigd->digestAlgorithms != NULL && sigd->digests != NULL) {
	for (i=0; sigd->digestAlgorithms[i] != NULL; i++) {
	    if (sigd->digests[i] == NULL)
		break;
	}
	if (sigd->digestAlgorithms[i] == NULL)	/* reached the end of the array? */
	    haveDigests = PR_TRUE;		/* yes: we must have all the digests */
    }
	    
    version = SEC_CMS_SIGNED_DATA_VERSION_BASIC;

    /* RFC2630 5.1 "version is the syntax version number..." */
    if (SecCmsContentInfoGetContentTypeTag(&(sigd->contentInfo)) != SEC_OID_PKCS7_DATA)
	version = SEC_CMS_SIGNED_DATA_VERSION_EXT;

    /* prepare all the SignerInfos (there may be none) */
    for (i=0; i < SecCmsSignedDataSignerInfoCount(sigd); i++) {
	signerinfo = SecCmsSignedDataGetSignerInfo(sigd, i);

	/* RFC2630 5.1 "version is the syntax version number..." */
	if (SecCmsSignerInfoGetVersion(signerinfo) != SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN)
	    version = SEC_CMS_SIGNED_DATA_VERSION_EXT;
	
	/* collect digestAlgorithms from SignerInfos */
	/* (we need to know which algorithms we have when the content comes in) */
	/* do not overwrite any existing digestAlgorithms (and digest) */
	digestalgtag = SecCmsSignerInfoGetDigestAlgTag(signerinfo);
        
	n = SecCmsAlgArrayGetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
	if (n < 0 && haveDigests) {
	    /* oops, there is a digestalg we do not have a digest for */
	    /* but we were supposed to have all the digests already... */
	    goto loser;
	} else if (n < 0) {
	    /* add the digestAlgorithm & a NULL digest */
	    rv = SecCmsSignedDataAddDigest((SecArenaPoolRef)poolp, sigd, digestalgtag, NULL);
	    if (rv != SECSuccess)
		goto loser;
	} else {
	    /* found it, nothing to do */
	}
    }

    dummy = SEC_ASN1EncodeInteger(poolp, &(sigd->version), (long)version);
    if (dummy == NULL)
	return SECFailure;

    /* this is a SET OF, so we need to sort them guys */
    rv = SecCmsArraySortByDER((void **)sigd->digestAlgorithms, 
                                SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
				(void **)sigd->digests);
    if (rv != SECSuccess)
	return SECFailure;
    
    return SECSuccess;

loser:
    return SECFailure;
}
NS_IMETHODIMP 
nsCRLManager::ImportCrl (uint8_t *aData, uint32_t aLength, nsIURI * aURI, uint32_t aType, bool doSilentDownload, const PRUnichar* crlKey)
{
  if (!NS_IsMainThread()) {
    NS_ERROR("nsCRLManager::ImportCrl called off the main thread");
    return NS_ERROR_NOT_SAME_THREAD;
  }
  
  nsNSSShutDownPreventionLock locker;
  nsresult rv;
  PRArenaPool *arena = NULL;
  CERTCertificate *caCert;
  SECItem derName = { siBuffer, NULL, 0 };
  SECItem derCrl;
  CERTSignedData sd;
  SECStatus sec_rv;
  CERTSignedCrl *crl;
  nsAutoCString url;
  nsCOMPtr<nsICRLInfo> crlData;
  bool importSuccessful;
  int32_t errorCode;
  nsString errorMessage;
  
  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  if (NS_FAILED(rv)) return rv;
	         
  aURI->GetSpec(url);
  arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  if (!arena) {
    goto loser;
  }
  memset(&sd, 0, sizeof(sd));

  derCrl.data = (unsigned char*)aData;
  derCrl.len = aLength;
  sec_rv = CERT_KeyFromDERCrl(arena, &derCrl, &derName);
  if (sec_rv != SECSuccess) {
    goto loser;
  }

  caCert = CERT_FindCertByName(CERT_GetDefaultCertDB(), &derName);
  if (!caCert) {
    if (aType == SEC_KRL_TYPE){
      goto loser;
    }
  } else {
    sec_rv = SEC_ASN1DecodeItem(arena,
                            &sd, SEC_ASN1_GET(CERT_SignedDataTemplate), 
                            &derCrl);
    if (sec_rv != SECSuccess) {
      goto loser;
    }
    sec_rv = CERT_VerifySignedData(&sd, caCert, PR_Now(),
                               nullptr);
    if (sec_rv != SECSuccess) {
      goto loser;
    }
  }
  
  crl = SEC_NewCrl(CERT_GetDefaultCertDB(), const_cast<char*>(url.get()), &derCrl,
                   aType);
  
  if (!crl) {
    goto loser;
  }

  crlData = new nsCRLInfo(crl);
  SSL_ClearSessionCache();
  SEC_DestroyCrl(crl);
  
  importSuccessful = true;
  goto done;

loser:
  importSuccessful = false;
  errorCode = PR_GetError();
  switch (errorCode) {
    case SEC_ERROR_CRL_EXPIRED:
      nssComponent->GetPIPNSSBundleString("CrlImportFailureExpired", errorMessage);
      break;

	case SEC_ERROR_CRL_BAD_SIGNATURE:
      nssComponent->GetPIPNSSBundleString("CrlImportFailureBadSignature", errorMessage);
      break;

	case SEC_ERROR_CRL_INVALID:
      nssComponent->GetPIPNSSBundleString("CrlImportFailureInvalid", errorMessage);
      break;

	case SEC_ERROR_OLD_CRL:
      nssComponent->GetPIPNSSBundleString("CrlImportFailureOld", errorMessage);
      break;

	case SEC_ERROR_CRL_NOT_YET_VALID:
      nssComponent->GetPIPNSSBundleString("CrlImportFailureNotYetValid", errorMessage);
      break;

    default:
      nssComponent->GetPIPNSSBundleString("CrlImportFailureReasonUnknown", errorMessage);
      errorMessage.AppendInt(errorCode,16);
      break;
  }

done:
          
  if(!doSilentDownload){
    if (!importSuccessful){
      nsString message;
      nsString temp;
      nssComponent->GetPIPNSSBundleString("CrlImportFailure1x", message);
      message.Append(NS_LITERAL_STRING("\n").get());
      message.Append(errorMessage);
      nssComponent->GetPIPNSSBundleString("CrlImportFailure2", temp);
      message.Append(NS_LITERAL_STRING("\n").get());
      message.Append(temp);

      nsNSSComponent::ShowAlertWithConstructedString(message);
    } else {
      nsCOMPtr<nsICertificateDialogs> certDialogs;
      // Not being able to display the success dialog should not
      // be a fatal error, so don't return a failure code.
      {
        nsPSMUITracker tracker;
        if (tracker.isUIForbidden()) {
          rv = NS_ERROR_NOT_AVAILABLE;
        }
        else {
          rv = ::getNSSDialogs(getter_AddRefs(certDialogs),
            NS_GET_IID(nsICertificateDialogs), NS_CERTIFICATEDIALOGS_CONTRACTID);
        }
      }
      if (NS_SUCCEEDED(rv)) {
        nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
        certDialogs->CrlImportStatusDialog(cxt, crlData);
      }
    }
  } else {
    if(crlKey == nullptr){
      return NS_ERROR_FAILURE;
    }
    nsCOMPtr<nsIPrefService> prefSvc = do_GetService(NS_PREFSERVICE_CONTRACTID,&rv);
    nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID,&rv);
    if (NS_FAILED(rv)){
      return rv;
    }
    
    nsAutoCString updateErrCntPrefStr(CRL_AUTOUPDATE_ERRCNT_PREF);
    LossyAppendUTF16toASCII(crlKey, updateErrCntPrefStr);
    if(importSuccessful){
      PRUnichar *updateTime;
      nsAutoCString updateTimeStr;
      nsCString updateURL;
      int32_t timingTypePref;
      double dayCnt;
      char *dayCntStr;
      nsAutoCString updateTypePrefStr(CRL_AUTOUPDATE_TIMIINGTYPE_PREF);
      nsAutoCString updateTimePrefStr(CRL_AUTOUPDATE_TIME_PREF);
      nsAutoCString updateUrlPrefStr(CRL_AUTOUPDATE_URL_PREF);
      nsAutoCString updateDayCntPrefStr(CRL_AUTOUPDATE_DAYCNT_PREF);
      nsAutoCString updateFreqCntPrefStr(CRL_AUTOUPDATE_FREQCNT_PREF);
      LossyAppendUTF16toASCII(crlKey, updateTypePrefStr);
      LossyAppendUTF16toASCII(crlKey, updateTimePrefStr);
      LossyAppendUTF16toASCII(crlKey, updateUrlPrefStr);
      LossyAppendUTF16toASCII(crlKey, updateDayCntPrefStr);
      LossyAppendUTF16toASCII(crlKey, updateFreqCntPrefStr);

      pref->GetIntPref(updateTypePrefStr.get(),&timingTypePref);
      
      //Compute and update the next download instant
      if(timingTypePref == TYPE_AUTOUPDATE_TIME_BASED){
        pref->GetCharPref(updateDayCntPrefStr.get(),&dayCntStr);
      }else{
        pref->GetCharPref(updateFreqCntPrefStr.get(),&dayCntStr);
      }
      dayCnt = atof(dayCntStr);
      nsMemory::Free(dayCntStr);

      bool toBeRescheduled = false;
      if(NS_SUCCEEDED(ComputeNextAutoUpdateTime(crlData, timingTypePref, dayCnt, &updateTime))){
        updateTimeStr.AssignWithConversion(updateTime);
        pref->SetCharPref(updateTimePrefStr.get(),updateTimeStr.get());
        //Now, check if this update time is already in the past. This would
        //imply we have downloaded the same crl, or there is something wrong
        //with the next update date. We will not reschedule this crl in this
        //session anymore - or else, we land into a loop. It would anyway be
        //imported once the browser is restarted.
        if(LL_CMP(updateTime, > , PR_Now())){
          toBeRescheduled = true;
        }
        nsMemory::Free(updateTime);
      }
      
      //Update the url to download from, next time
      crlData->GetLastFetchURL(updateURL);
      pref->SetCharPref(updateUrlPrefStr.get(),updateURL.get());
      
      pref->SetIntPref(updateErrCntPrefStr.get(),0);
      
      if (toBeRescheduled) {
        nsAutoString hashKey(crlKey);
        nssComponent->RemoveCrlFromList(hashKey);
        nssComponent->DefineNextTimer();
      }

    } else{
Beispiel #3
0
nsresult
CryptoKey::PublicKeyToSpki(SECKEYPublicKey* aPubKey,
                           CryptoBuffer& aRetVal,
                           const nsNSSShutDownPreventionLock& /*proofOfLock*/)
{
  ScopedCERTSubjectPublicKeyInfo spki;

  // NSS doesn't support exporting DH public keys.
  if (aPubKey->keyType == dhKey) {
    // Mimic the behavior of SECKEY_CreateSubjectPublicKeyInfo() and create
    // a new arena for the SPKI object.
    ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
    if (!arena) {
      return NS_ERROR_DOM_OPERATION_ERR;
    }

    spki = PORT_ArenaZNew(arena, CERTSubjectPublicKeyInfo);
    if (!spki) {
      return NS_ERROR_DOM_OPERATION_ERR;
    }

    // Assign |arena| to |spki| and null the variable afterwards so that the
    // arena created above that holds the SPKI object is free'd when |spki|
    // goes out of scope, not when |arena| does.
    spki->arena = arena.forget();

    nsresult rv = PublicDhKeyToSpki(aPubKey, spki);
    NS_ENSURE_SUCCESS(rv, rv);
  } else {
    spki = SECKEY_CreateSubjectPublicKeyInfo(aPubKey);
    if (!spki) {
      return NS_ERROR_DOM_OPERATION_ERR;
    }
  }

  // Per WebCrypto spec we must export ECDH SPKIs with the algorithm OID
  // id-ecDH (1.3.132.112) and DH SPKIs with OID dhKeyAgreement
  // (1.2.840.113549.1.3.1). NSS doesn't know about these OIDs and there is
  // no way to specify the algorithm to use when exporting a public key.
  if (aPubKey->keyType == ecKey || aPubKey->keyType == dhKey) {
    const SECItem* oidData = nullptr;
    if (aPubKey->keyType == ecKey) {
      oidData = &SEC_OID_DATA_EC_DH;
    } else if (aPubKey->keyType == dhKey) {
      oidData = &SEC_OID_DATA_DH_KEY_AGREEMENT;
    } else {
      MOZ_ASSERT(false);
    }

    SECStatus rv = SECITEM_CopyItem(spki->arena, &spki->algorithm.algorithm,
                                    oidData);
    if (rv != SECSuccess) {
      return NS_ERROR_DOM_OPERATION_ERR;
    }
  }

  const SEC_ASN1Template* tpl = SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate);
  ScopedSECItem spkiItem(SEC_ASN1EncodeItem(nullptr, nullptr, spki, tpl));

  if (!aRetVal.Assign(spkiItem.get())) {
    return NS_ERROR_DOM_OPERATION_ERR;
  }
  return NS_OK;
}
CRMFEncryptedValue *
crmf_create_encrypted_value_wrapped_privkey(SECKEYPrivateKey   *inPrivKey,
					    SECKEYPublicKey    *inCAKey,
					    CRMFEncryptedValue *destValue)
{
    SECItem                   wrappedPrivKey, wrappedSymKey;
    SECItem                   encodedParam, *dummy;
    SECStatus                 rv;
    CK_MECHANISM_TYPE         pubMechType, symKeyType;
    unsigned char            *wrappedSymKeyBits;
    unsigned char            *wrappedPrivKeyBits;
    SECItem                  *iv = NULL;
    SECOidTag                 tag;
    PK11SymKey               *symKey;
    PK11SlotInfo             *slot;
    SECAlgorithmID           *symmAlg;
    CRMFEncryptedValue       *myEncrValue = NULL;

    encodedParam.data = NULL;
    wrappedSymKeyBits  = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN);
    wrappedPrivKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN);
    if (wrappedSymKeyBits == NULL || wrappedPrivKeyBits == NULL) {
        goto loser;
    }
    if (destValue == NULL) {
        myEncrValue = destValue = PORT_ZNew(CRMFEncryptedValue);
	if (destValue == NULL) {
	    goto loser;
	}
    }

    pubMechType = crmf_get_mechanism_from_public_key(inCAKey);
    if (pubMechType == CKM_INVALID_MECHANISM) {
        /* XXX I should probably do something here for non-RSA 
	 *     keys that are in certs. (ie DSA)
	 * XXX or at least SET AN ERROR CODE.
	 */
        goto loser;
    }
    slot = inPrivKey->pkcs11Slot; 
    PORT_Assert(slot != NULL);
    symKeyType = crmf_get_best_privkey_wrap_mechanism(slot);
    symKey = PK11_KeyGen(slot, symKeyType, NULL, 0, NULL);
    if (symKey == NULL) {
        goto loser;
    }

    wrappedSymKey.data = wrappedSymKeyBits;
    wrappedSymKey.len  = MAX_WRAPPED_KEY_LEN;
    rv = PK11_PubWrapSymKey(pubMechType, inCAKey, symKey, &wrappedSymKey);
    if (rv != SECSuccess) {
        goto loser;
    }
    /* Make the length of the result a Bit String length. */
    wrappedSymKey.len <<= 3;

    wrappedPrivKey.data = wrappedPrivKeyBits;
    wrappedPrivKey.len  = MAX_WRAPPED_KEY_LEN;
    iv = crmf_get_iv(symKeyType);
    rv = PK11_WrapPrivKey(slot, symKey, inPrivKey, symKeyType, iv, 
			  &wrappedPrivKey, NULL);
    PK11_FreeSymKey(symKey);
    if (rv != SECSuccess) {
        goto loser;
    }
    /* Make the length of the result a Bit String length. */
    wrappedPrivKey.len <<= 3;
    rv = crmf_make_bitstring_copy(NULL, 
				  &destValue->encValue, 
				  &wrappedPrivKey);
    if (rv != SECSuccess) {
        goto loser;
    }

    rv = crmf_make_bitstring_copy(NULL,
				  &destValue->encSymmKey, 
				  &wrappedSymKey);
    if (rv != SECSuccess) {
        goto loser;
    }
    destValue->symmAlg = symmAlg = PORT_ZNew(SECAlgorithmID);
    if (symmAlg == NULL) {
        goto loser;
    }

    dummy = SEC_ASN1EncodeItem(NULL, &encodedParam, iv, 
                               SEC_ASN1_GET(SEC_OctetStringTemplate));
    if (dummy != &encodedParam) {
        SECITEM_FreeItem(dummy, PR_TRUE);
	goto loser;
    }

    symKeyType = crmf_get_non_pad_mechanism(symKeyType);
    tag = PK11_MechanismToAlgtag(symKeyType);
    rv = SECOID_SetAlgorithmID(NULL, symmAlg, tag, &encodedParam);
    if (rv != SECSuccess) {
        goto loser;
    }
    SECITEM_FreeItem(&encodedParam, PR_FALSE);
    PORT_Free(wrappedPrivKeyBits);
    PORT_Free(wrappedSymKeyBits);
    SECITEM_FreeItem(iv, PR_TRUE);
    return destValue;
 loser:
    if (iv != NULL) {
	SECITEM_FreeItem(iv, PR_TRUE);
    }
    if (myEncrValue != NULL) {
        crmf_destroy_encrypted_value(myEncrValue, PR_TRUE);
    }
    if (wrappedSymKeyBits != NULL) {
        PORT_Free(wrappedSymKeyBits);
    }
    if (wrappedPrivKeyBits != NULL) {
        PORT_Free(wrappedPrivKeyBits);
    }
    if (encodedParam.data != NULL) {
	SECITEM_FreeItem(&encodedParam, PR_FALSE);
    }
    return NULL;
}
Beispiel #5
0
RefPtr<DtlsIdentity> DtlsIdentity::Generate() {
    UniquePK11SlotInfo slot(PK11_GetInternalSlot());
    if (!slot) {
        return nullptr;
    }

    uint8_t random_name[16];

    SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), random_name,
                   sizeof(random_name));
    if (rv != SECSuccess)
        return nullptr;

    std::string name;
    char chunk[3];
    for (size_t i = 0; i < sizeof(random_name); ++i) {
        SprintfLiteral(chunk, "%.2x", random_name[i]);
        name += chunk;
    }

    std::string subject_name_string = "CN=" + name;
    UniqueCERTName subject_name(CERT_AsciiToName(subject_name_string.c_str()));
    if (!subject_name) {
        return nullptr;
    }

    unsigned char paramBuf[12]; // OIDs are small
    SECItem ecdsaParams = { siBuffer, paramBuf, sizeof(paramBuf) };
    SECOidData* oidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
    if (!oidData || (oidData->oid.len > (sizeof(paramBuf) - 2))) {
        return nullptr;
    }
    ecdsaParams.data[0] = SEC_ASN1_OBJECT_ID;
    ecdsaParams.data[1] = oidData->oid.len;
    memcpy(ecdsaParams.data + 2, oidData->oid.data, oidData->oid.len);
    ecdsaParams.len = oidData->oid.len + 2;

    SECKEYPublicKey *pubkey;
    UniqueSECKEYPrivateKey private_key(
        PK11_GenerateKeyPair(slot.get(),
                             CKM_EC_KEY_PAIR_GEN, &ecdsaParams, &pubkey,
                             PR_FALSE, PR_TRUE, nullptr));
    if (private_key == nullptr)
        return nullptr;
    UniqueSECKEYPublicKey public_key(pubkey);
    pubkey = nullptr;

    UniqueCERTSubjectPublicKeyInfo spki(
        SECKEY_CreateSubjectPublicKeyInfo(public_key.get()));
    if (!spki) {
        return nullptr;
    }

    UniqueCERTCertificateRequest certreq(
        CERT_CreateCertificateRequest(subject_name.get(), spki.get(), nullptr));
    if (!certreq) {
        return nullptr;
    }

    // From 1 day before todayto 30 days after.
    // This is a sort of arbitrary range designed to be valid
    // now with some slack in case the other side expects
    // some before expiry.
    //
    // Note: explicit casts necessary to avoid
    //       warning C4307: '*' : integral constant overflow
    static const PRTime oneDay = PRTime(PR_USEC_PER_SEC)
                                 * PRTime(60)  // sec
                                 * PRTime(60)  // min
                                 * PRTime(24); // hours
    PRTime now = PR_Now();
    PRTime notBefore = now - oneDay;
    PRTime notAfter = now + (PRTime(30) * oneDay);

    UniqueCERTValidity validity(CERT_CreateValidity(notBefore, notAfter));
    if (!validity) {
        return nullptr;
    }

    unsigned long serial;
    // Note: This serial in principle could collide, but it's unlikely
    rv = PK11_GenerateRandomOnSlot(slot.get(),
                                   reinterpret_cast<unsigned char *>(&serial),
                                   sizeof(serial));
    if (rv != SECSuccess) {
        return nullptr;
    }

    UniqueCERTCertificate certificate(
        CERT_CreateCertificate(serial, subject_name.get(), validity.get(),
                               certreq.get()));
    if (!certificate) {
        return nullptr;
    }

    PLArenaPool *arena = certificate->arena;

    rv = SECOID_SetAlgorithmID(arena, &certificate->signature,
                               SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, 0);
    if (rv != SECSuccess)
        return nullptr;

    // Set version to X509v3.
    *(certificate->version.data) = SEC_CERTIFICATE_VERSION_3;
    certificate->version.len = 1;

    SECItem innerDER;
    innerDER.len = 0;
    innerDER.data = nullptr;

    if (!SEC_ASN1EncodeItem(arena, &innerDER, certificate.get(),
                            SEC_ASN1_GET(CERT_CertificateTemplate))) {
        return nullptr;
    }

    SECItem *signedCert = PORT_ArenaZNew(arena, SECItem);
    if (!signedCert) {
        return nullptr;
    }

    rv = SEC_DerSignData(arena, signedCert, innerDER.data, innerDER.len,
                         private_key.get(),
                         SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE);
    if (rv != SECSuccess) {
        return nullptr;
    }
    certificate->derCert = *signedCert;

    RefPtr<DtlsIdentity> identity = new DtlsIdentity(Move(private_key),
            Move(certificate),
            ssl_kea_ecdh);
    return identity.forget();
}