Beispiel #1
0
bool ReadAndEncodeAttribute(SECKEYPrivateKey* aKey,
                            CK_ATTRIBUTE_TYPE aAttribute,
                            Optional<nsString>& aDst)
{
  ScopedSECItem item(::SECITEM_AllocItem(nullptr, nullptr, 0));
  if (!item) {
    return false;
  }

  if (PK11_ReadRawAttribute(PK11_TypePrivKey, aKey, aAttribute, item)
        != SECSuccess) {
    return false;
  }

  CryptoBuffer buffer;
  if (!buffer.Assign(item)) {
    return false;
  }

  if (NS_FAILED(buffer.ToJwkBase64(aDst.Value()))) {
    return false;
  }

  return true;
}
Beispiel #2
0
static nsresult
AssembleClientData(const nsAString& aOrigin, const CryptoBuffer& aChallenge,
                   /* out */ nsACString& aJsonOut)
{
  MOZ_ASSERT(NS_IsMainThread());

  nsString challengeBase64;
  nsresult rv = aChallenge.ToJwkBase64(challengeBase64);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return NS_ERROR_FAILURE;
  }

  WebAuthnClientData clientDataObject;
  clientDataObject.mOrigin.Assign(aOrigin);
  clientDataObject.mHashAlg.SetAsString().Assign(NS_LITERAL_STRING("S256"));
  clientDataObject.mChallenge.Assign(challengeBase64);

  nsAutoString temp;
  if (NS_WARN_IF(!clientDataObject.ToJSON(temp))) {
    return NS_ERROR_FAILURE;
  }

  aJsonOut.Assign(NS_ConvertUTF16toUTF8(temp));
  return NS_OK;
}
Beispiel #3
0
NS_IMETHODIMP
U2FSignTask::Run()
{
  nsNSSShutDownPreventionLock locker;
  if (isAlreadyShutDown()) {
    ReturnError(ErrorCode::OTHER_ERROR);
    return NS_ERROR_FAILURE;
  }

  // Search the requests for one a token can fulfill
  for (size_t i = 0; i < mRegisteredKeys.Length(); i += 1) {
    RegisteredKey request(mRegisteredKeys[i]);

    // Check for required attributes
    if (!(request.mVersion.WasPassed() &&
          request.mKeyHandle.WasPassed())) {
      continue;
    }

    // Do not permit an individual RegisteredKey to assert a different AppID
    if (request.mAppId.WasPassed() && mAppId != request.mAppId.Value()) {
      continue;
    }

    // Assemble a clientData object
    CryptoBuffer clientData;
    nsresult rv = AssembleClientData(mOrigin, kGetAssertion, mChallenge,
                                     clientData);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      ReturnError(ErrorCode::OTHER_ERROR);
      return NS_ERROR_FAILURE;
    }

    // Hash the AppID and the ClientData into the AppParam and ChallengeParam
    SECStatus srv;
    nsCString cAppId = NS_ConvertUTF16toUTF8(mAppId);
    CryptoBuffer appParam;
    CryptoBuffer challengeParam;
    if (!appParam.SetLength(SHA256_LENGTH, fallible) ||
        !challengeParam.SetLength(SHA256_LENGTH, fallible)) {
      ReturnError(ErrorCode::OTHER_ERROR);
      return NS_ERROR_FAILURE;
    }

    srv = PK11_HashBuf(SEC_OID_SHA256, appParam.Elements(),
                       reinterpret_cast<const uint8_t*>(cAppId.BeginReading()),
                       cAppId.Length());
    if (srv != SECSuccess) {
      ReturnError(ErrorCode::OTHER_ERROR);
      return NS_ERROR_FAILURE;
    }

    srv = PK11_HashBuf(SEC_OID_SHA256, challengeParam.Elements(),
                       clientData.Elements(), clientData.Length());
    if (srv != SECSuccess) {
      ReturnError(ErrorCode::OTHER_ERROR);
      return NS_ERROR_FAILURE;
    }

    // Decode the key handle
    CryptoBuffer keyHandle;
    rv = keyHandle.FromJwkBase64(request.mKeyHandle.Value());
    if (NS_WARN_IF(NS_FAILED(rv))) {
      ReturnError(ErrorCode::OTHER_ERROR);
      return NS_ERROR_FAILURE;
    }

    // Get the signature from the token
    CryptoBuffer signatureData;
    bool signSuccess = false;

    // We ignore mTransports, as it is intended to be used for sorting the
    // available devices by preference, but is not an exclusion factor.

    for (size_t a = 0; a < mAuthenticators.Length() && !signSuccess; ++a) {
      Authenticator token(mAuthenticators[a]);
      bool isCompatible = false;
      bool isRegistered = false;

      rv = token->IsCompatibleVersion(request.mVersion.Value(), &isCompatible);
      if (NS_FAILED(rv)) {
        ReturnError(ErrorCode::OTHER_ERROR);
        return NS_ERROR_FAILURE;
      }
      if (!isCompatible) {
        continue;
      }

      rv = token->IsRegistered(keyHandle.Elements(), keyHandle.Length(),
                               &isRegistered);
      if (NS_FAILED(rv)) {
        ReturnError(ErrorCode::OTHER_ERROR);
        return NS_ERROR_FAILURE;
      }

      if (isCompatible && isRegistered) {
        uint8_t* buffer;
        uint32_t bufferlen;
        nsresult rv = token->Sign(appParam.Elements(), appParam.Length(),
                                  challengeParam.Elements(), challengeParam.Length(),
                                  keyHandle.Elements(), keyHandle.Length(),
                                  &buffer, &bufferlen);
        if (NS_FAILED(rv)) {
          ReturnError(ErrorCode::OTHER_ERROR);
          return NS_ERROR_FAILURE;
        }

        MOZ_ASSERT(buffer);
        signatureData.Assign(buffer, bufferlen);
        free(buffer);
        signSuccess = true;
      }
    }

    if (!signSuccess) {
      // Try another request
      continue;
    }

    // Assemble a response object to return
    nsString clientDataBase64, signatureDataBase64;
    nsresult rvClientData =
      clientData.ToJwkBase64(clientDataBase64);
    nsresult rvSignatureData =
      signatureData.ToJwkBase64(signatureDataBase64);
    if (NS_WARN_IF(NS_FAILED(rvClientData)) ||
        NS_WARN_IF(NS_FAILED(rvSignatureData))) {
      ReturnError(ErrorCode::OTHER_ERROR);
      return NS_ERROR_FAILURE;
    }
    SignResponse response;
    response.mKeyHandle.Construct(request.mKeyHandle.Value());
    response.mClientData.Construct(clientDataBase64);
    response.mSignatureData.Construct(signatureDataBase64);
    response.mErrorCode.Construct(static_cast<uint32_t>(ErrorCode::OK));

    ErrorResult result;
    mCallback->Call(response, result);
    NS_WARN_IF(result.Failed());
    // Useful exceptions already got reported.
    result.SuppressException();
    return NS_OK;
  }

  // Nothing could satisfy
  ReturnError(ErrorCode::DEVICE_INELIGIBLE);
  return NS_ERROR_FAILURE;
}