void PushSubscription::ToJSON(PushSubscriptionJSON& aJSON) { aJSON.mEndpoint.Construct(); aJSON.mEndpoint.Value() = mEndpoint; aJSON.mKeys.mP256dh.Construct(); nsresult rv = Base64URLEncode(mRawP256dhKey.Length(), mRawP256dhKey.Elements(), aJSON.mKeys.mP256dh.Value()); Unused << NS_WARN_IF(NS_FAILED(rv)); aJSON.mKeys.mAuth.Construct(); rv = Base64URLEncode(mAuthSecret.Length(), mAuthSecret.Elements(), aJSON.mKeys.mAuth.Value()); Unused << NS_WARN_IF(NS_FAILED(rv)); }
nsresult CryptoBuffer::ToJwkBase64(nsString& aBase64) const { // Shortcut for the empty octet string if (Length() == 0) { aBase64.Truncate(); return NS_OK; } nsAutoCString base64; nsresult rv = Base64URLEncode(Length(), Elements(), Base64URLEncodePaddingPolicy::Omit, base64); NS_ENSURE_SUCCESS(rv, rv); CopyASCIItoUTF16(base64, aBase64); return NS_OK; }
// A U2F Sign operation creates a signature over the "param" arguments (plus // some other stuff) using the private key indicated in the key handle argument. // // The format of the signed data is as follows: // // 32 Application parameter // 1 User presence (0x01) // 4 Counter // 32 Challenge parameter // // The format of the signature data is as follows: // // 1 User presence // 4 Counter // * Signature // nsresult U2FSoftTokenManager::Sign(nsTArray<uint8_t>& aApplication, nsTArray<uint8_t>& aChallenge, nsTArray<uint8_t>& aKeyHandle, nsTArray<uint8_t>& aSignature) { nsNSSShutDownPreventionLock locker; if (NS_WARN_IF(isAlreadyShutDown())) { return NS_ERROR_NOT_AVAILABLE; } MOZ_ASSERT(mInitialized); if (NS_WARN_IF(!mInitialized)) { nsresult rv = Init(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } MOZ_ASSERT(mWrappingKey); UniquePK11SlotInfo slot(PK11_GetInternalSlot()); MOZ_ASSERT(slot.get()); if (NS_WARN_IF((aChallenge.Length() != kParamLen) || (aApplication.Length() != kParamLen))) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Parameter lengths are wrong! challenge=%d app=%d expected=%d", (uint32_t)aChallenge.Length(), (uint32_t)aApplication.Length(), kParamLen)); return NS_ERROR_ILLEGAL_VALUE; } // Decode the key handle UniqueSECKEYPrivateKey privKey = PrivateKeyFromKeyHandle(slot, mWrappingKey, aKeyHandle.Elements(), aKeyHandle.Length(), aApplication.Elements(), aApplication.Length(), locker); if (NS_WARN_IF(!privKey.get())) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Couldn't get the priv key!")); return NS_ERROR_FAILURE; } // Increment the counter and turn it into a SECItem mCounter += 1; ScopedAutoSECItem counterItem(4); counterItem.data[0] = (mCounter >> 24) & 0xFF; counterItem.data[1] = (mCounter >> 16) & 0xFF; counterItem.data[2] = (mCounter >> 8) & 0xFF; counterItem.data[3] = (mCounter >> 0) & 0xFF; uint32_t counter = mCounter; AbstractThread::MainThread()->Dispatch(NS_NewRunnableFunction( [counter] () { MOZ_ASSERT(NS_IsMainThread()); Preferences::SetUint(PREF_U2F_NSSTOKEN_COUNTER, counter); })); // Compute the signature mozilla::dom::CryptoBuffer signedDataBuf; if (NS_WARN_IF(!signedDataBuf.SetCapacity(1 + 4 + (2 * kParamLen), mozilla::fallible))) { return NS_ERROR_OUT_OF_MEMORY; } // It's OK to ignore the return values here because we're writing into // pre-allocated space signedDataBuf.AppendElements(aApplication.Elements(), aApplication.Length(), mozilla::fallible); signedDataBuf.AppendElement(0x01, mozilla::fallible); signedDataBuf.AppendSECItem(counterItem); signedDataBuf.AppendElements(aChallenge.Elements(), aChallenge.Length(), mozilla::fallible); if (MOZ_LOG_TEST(gNSSTokenLog, LogLevel::Debug)) { nsAutoCString base64; nsresult rv = Base64URLEncode(signedDataBuf.Length(), signedDataBuf.Elements(), Base64URLEncodePaddingPolicy::Omit, base64); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; } MOZ_LOG(gNSSTokenLog, LogLevel::Debug, ("U2F Token signing bytes (base64): %s", base64.get())); } ScopedAutoSECItem signatureItem; SECStatus srv = SEC_SignData(&signatureItem, signedDataBuf.Elements(), signedDataBuf.Length(), privKey.get(), SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE); if (NS_WARN_IF(srv != SECSuccess)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Signature failure: %d", PORT_GetError())); return NS_ERROR_FAILURE; } // Assemble the signature data into a buffer for return mozilla::dom::CryptoBuffer signatureBuf; if (NS_WARN_IF(!signatureBuf.SetCapacity(1 + counterItem.len + signatureItem.len, mozilla::fallible))) { return NS_ERROR_OUT_OF_MEMORY; } // It's OK to ignore the return values here because we're writing into // pre-allocated space signatureBuf.AppendElement(0x01, mozilla::fallible); signatureBuf.AppendSECItem(counterItem); signatureBuf.AppendSECItem(signatureItem); aSignature = signatureBuf; return NS_OK; }