예제 #1
0
void
U2FTokenManager::Sign(PWebAuthnTransactionParent* aTransactionParent,
                      const uint64_t& aTransactionId,
                      const WebAuthnGetAssertionInfo& aTransactionInfo)
{
  MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthSign"));

  ClearTransaction();
  mTransactionParent = aTransactionParent;
  mTokenManagerImpl = GetTokenManagerImpl();

  if (!mTokenManagerImpl) {
    AbortTransaction(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR);
    return;
  }

  if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) ||
      (aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) {
    AbortTransaction(aTransactionId, NS_ERROR_DOM_UNKNOWN_ERR);
    return;
  }

  // Show a prompt that lets the user cancel the ongoing transaction.
  NS_ConvertUTF16toUTF8 origin(aTransactionInfo.Origin());
  SendPromptNotification(kSignPromptNotifcation,
                         aTransactionId,
                         origin.get());

  uint64_t tid = mLastTransactionId = aTransactionId;
  mozilla::TimeStamp startTime = mozilla::TimeStamp::Now();

  mTokenManagerImpl
    ->Sign(aTransactionInfo)
    ->Then(GetCurrentThreadSerialEventTarget(), __func__,
      [tid, startTime](WebAuthnGetAssertionResult&& aResult) {
        U2FTokenManager* mgr = U2FTokenManager::Get();
        mgr->MaybeConfirmSign(tid, aResult);
        Telemetry::ScalarAdd(
          Telemetry::ScalarID::SECURITY_WEBAUTHN_USED,
          NS_LITERAL_STRING("U2FSignFinish"), 1);
        Telemetry::AccumulateTimeDelta(
          Telemetry::WEBAUTHN_GET_ASSERTION_MS,
          startTime);
      },
      [tid](nsresult rv) {
        MOZ_ASSERT(NS_FAILED(rv));
        U2FTokenManager* mgr = U2FTokenManager::Get();
        mgr->MaybeAbortSign(tid, rv);
        Telemetry::ScalarAdd(
          Telemetry::ScalarID::SECURITY_WEBAUTHN_USED,
          NS_LITERAL_STRING("U2FSignAbort"), 1);
      })
    ->Track(mSignPromise);
}
예제 #2
0
void WinWebAuthnManager::Sign(PWebAuthnTransactionParent* aTransactionParent,
                              const uint64_t& aTransactionId,
                              const WebAuthnGetAssertionInfo& aInfo) {
  MOZ_LOG(gWinWebAuthnManagerLog, LogLevel::Debug, ("WinWebAuthNSign"));

  ClearTransaction();
  mTransactionParent = aTransactionParent;

  // User Verification Requirement
  DWORD winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;

  // RPID
  PCWSTR rpID = nullptr;

  // Attachment
  DWORD winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY;

  // AppId
  BOOL bU2fAppIdUsed = FALSE;
  BOOL* pbU2fAppIdUsed = nullptr;
  PCWSTR winAppIdentifier = nullptr;

  // Client Data
  WEBAUTHN_CLIENT_DATA WebAuthNClientData = {
      WEBAUTHN_CLIENT_DATA_CURRENT_VERSION, aInfo.ClientDataJSON().Length(),
      (BYTE*)(aInfo.ClientDataJSON().get()), WEBAUTHN_HASH_ALGORITHM_SHA_256};

  if (aInfo.Extra().type() ==
      WebAuthnMaybeGetAssertionExtraInfo::TWebAuthnGetAssertionExtraInfo) {
    const auto& extra = aInfo.Extra().get_WebAuthnGetAssertionExtraInfo();

    for (const WebAuthnExtension& ext : extra.Extensions()) {
      if (ext.type() == WebAuthnExtension::TWebAuthnExtensionAppId) {
        winAppIdentifier =
            ext.get_WebAuthnExtensionAppId().appIdentifier().get();
        pbU2fAppIdUsed = &bU2fAppIdUsed;
        break;
      }
    }

    // RPID
    rpID = aInfo.RpId().get();

    // User Verification Requirement
    UserVerificationRequirement userVerificationReq =
        static_cast<UserVerificationRequirement>(
            extra.userVerificationRequirement());

    switch (userVerificationReq) {
      case UserVerificationRequirement::Required:
        winUserVerificationReq =
            WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
        break;
      case UserVerificationRequirement::Preferred:
        winUserVerificationReq =
            WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED;
        break;
      case UserVerificationRequirement::Discouraged:
        winUserVerificationReq =
            WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
        break;
      default:
        winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
        break;
    }
  } else {
    rpID = aInfo.Origin().get();
    winAppIdentifier = aInfo.RpId().get();
    pbU2fAppIdUsed = &bU2fAppIdUsed;
    winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM_U2F_V2;
    winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
  }

  // allow Credentials
  nsTArray<WEBAUTHN_CREDENTIAL_EX> allowCredentials;
  WEBAUTHN_CREDENTIAL_EX* pAllowCredentials = nullptr;
  nsTArray<WEBAUTHN_CREDENTIAL_EX*> allowCredentialsPtrs;
  WEBAUTHN_CREDENTIAL_LIST allowCredentialList = {0};
  WEBAUTHN_CREDENTIAL_LIST* pAllowCredentialList = nullptr;

  for (auto& cred : aInfo.AllowList()) {
    uint8_t transports = cred.transports();
    DWORD winTransports = 0;
    if (transports & U2F_AUTHENTICATOR_TRANSPORT_USB) {
      winTransports |= WEBAUTHN_CTAP_TRANSPORT_USB;
    }
    if (transports & U2F_AUTHENTICATOR_TRANSPORT_NFC) {
      winTransports |= WEBAUTHN_CTAP_TRANSPORT_NFC;
    }
    if (transports & U2F_AUTHENTICATOR_TRANSPORT_BLE) {
      winTransports |= WEBAUTHN_CTAP_TRANSPORT_BLE;
    }
    if (transports & CTAP_AUTHENTICATOR_TRANSPORT_INTERNAL) {
      winTransports |= WEBAUTHN_CTAP_TRANSPORT_INTERNAL;
    }

    WEBAUTHN_CREDENTIAL_EX credential = {
        WEBAUTHN_CREDENTIAL_EX_CURRENT_VERSION,
        static_cast<DWORD>(cred.id().Length()), (PBYTE)(cred.id().Elements()),
        WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY, winTransports};
    allowCredentials.AppendElement(credential);
  }

  if (allowCredentials.Length()) {
    pAllowCredentials = allowCredentials.Elements();
    for (DWORD i = 0; i < allowCredentials.Length(); i++) {
      allowCredentialsPtrs.AppendElement(&pAllowCredentials[i]);
    }
    allowCredentialList.cCredentials = allowCredentials.Length();
    allowCredentialList.ppCredentials = allowCredentialsPtrs.Elements();
    pAllowCredentialList = &allowCredentialList;
  }

  WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS WebAuthNAssertionOptions = {
      WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_CURRENT_VERSION,
      aInfo.TimeoutMS(),
      {0, NULL},
      {0, NULL},
      WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY,
      winUserVerificationReq,
      0,  // dwFlags
      winAppIdentifier,
      pbU2fAppIdUsed,
      nullptr,  // pCancellationId
      pAllowCredentialList,
  };

  GUID cancellationId = {0};
  if (gWinWebauthnGetCancellationId(&cancellationId) == S_OK) {
    WebAuthNAssertionOptions.pCancellationId = &cancellationId;
    mCancellationIds.emplace(aTransactionId, &cancellationId);
  }

  PWEBAUTHN_ASSERTION pWebAuthNAssertion = nullptr;

  // Bug 1518876: Get Window Handle from Content process for Windows WebAuthN
  // APIs
  HWND hWnd = GetForegroundWindow();

  HRESULT hr =
      gWinWebauthnGetAssertion(hWnd, rpID, &WebAuthNClientData,
                               &WebAuthNAssertionOptions, &pWebAuthNAssertion);

  mCancellationIds.erase(aTransactionId);

  if (hr == S_OK) {
    nsTArray<uint8_t> signature;
    if (aInfo.Extra().type() ==
        WebAuthnMaybeGetAssertionExtraInfo::TWebAuthnGetAssertionExtraInfo) {
      signature.AppendElements(pWebAuthNAssertion->pbSignature,
                               pWebAuthNAssertion->cbSignature);
    } else {
      // AuthenticatorData Length check.
      // First 32 bytes: RPID Hash
      // Next 1 byte: Flags
      // Next 4 bytes: Counter
      if (pWebAuthNAssertion->cbAuthenticatorData < 32 + 1 + 4) {
        MaybeAbortRegister(aTransactionId, NS_ERROR_DOM_INVALID_STATE_ERR);
      }

      signature.AppendElement(0x01);  // User Presence bit
      signature.AppendElements(pWebAuthNAssertion->pbAuthenticatorData +
                                   32 +  // RPID Hash length
                                   1,    // Flags
                               4);       // Counter length
      signature.AppendElements(pWebAuthNAssertion->pbSignature,
                               pWebAuthNAssertion->cbSignature);
    }

    nsTArray<uint8_t> keyHandle;
    keyHandle.AppendElements(pWebAuthNAssertion->Credential.pbId,
                             pWebAuthNAssertion->Credential.cbId);

    nsTArray<uint8_t> authenticatorData;
    authenticatorData.AppendElements(pWebAuthNAssertion->pbAuthenticatorData,
                                     pWebAuthNAssertion->cbAuthenticatorData);

    nsTArray<WebAuthnExtensionResult> extensions;

    if (pbU2fAppIdUsed && *pbU2fAppIdUsed) {
      extensions.AppendElement(WebAuthnExtensionResultAppId(true));
    }

    WebAuthnGetAssertionResult result(aInfo.ClientDataJSON(), keyHandle,
                                      signature, authenticatorData, extensions,
                                      signature);

    Unused << mTransactionParent->SendConfirmSign(aTransactionId, result);
    ClearTransaction();

    gWinWebauthnFreeAssertion(pWebAuthNAssertion);

  } else {
    PCWSTR errorName = gWinWebauthnGetErrorName(hr);
    nsresult aError = NS_ERROR_DOM_ABORT_ERR;

    if (_wcsicmp(errorName, L"InvalidStateError") == 0) {
      aError = NS_ERROR_DOM_INVALID_STATE_ERR;
    } else if (_wcsicmp(errorName, L"ConstraintError") == 0 ||
               _wcsicmp(errorName, L"UnknownError") == 0) {
      aError = NS_ERROR_DOM_UNKNOWN_ERR;
    } else if (_wcsicmp(errorName, L"NotSupportedError") == 0) {
      aError = NS_ERROR_DOM_INVALID_STATE_ERR;
    } else if (_wcsicmp(errorName, L"NotAllowedError") == 0) {
      aError = NS_ERROR_DOM_NOT_ALLOWED_ERR;
    }

    MaybeAbortSign(aTransactionId, aError);
  }
}