/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MLSTransactionParent.h" #include "MLSTransactionMessage.h" #include "mozilla/dom/quota/QuotaManager.h" #include "mozilla/security/mls/mls_gk_ffi_generated.h" #include "MLSLogging.h" #include "mozilla/Base64.h" #include "nsIFile.h" #include "nsIPrincipal.h" #include "nsString.h" #include "nsCOMPtr.h" using mozilla::dom::quota::QuotaManager; namespace mozilla::dom { /* static */ nsresult MLSTransactionParent::CreateDirectoryIfNotExists( nsIFile* aDir) { nsresult rv = aDir->Create(nsIFile::DIRECTORY_TYPE, 0755); if (rv == NS_ERROR_FILE_ALREADY_EXISTS) { // Evaluate if the file is a directory bool isDirectory = false; rv = aDir->IsDirectory(&isDirectory); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // Check if the file is actually a directory if (!isDirectory) { return NS_ERROR_FILE_NOT_DIRECTORY; } return NS_OK; } return rv; } /* static */ nsresult MLSTransactionParent::ConstructDatabasePrefixPath( nsCOMPtr& aFile) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::ConstructDatabasePath()")); // Get the base path from the quota manager QuotaManager* quotaManager = QuotaManager::Get(); if (NS_WARN_IF(!quotaManager)) { return NS_ERROR_FAILURE; } // Create an nsIFile object from the path nsresult rv = NS_NewLocalFile(quotaManager->GetBasePath(), getter_AddRefs(aFile)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // Append the hardcoded "mls" directory name to the path rv = aFile->AppendNative("mls"_ns); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } return NS_OK; } /* static */ nsresult MLSTransactionParent::ConstructDatabaseFullPath( nsCOMPtr& aFile, nsIPrincipal* aPrincipal, nsCString& aDatabasePath) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::ConstructDatabaseFullPath()")); // Get StorageOriginKey nsAutoCString originKey; nsresult rv = aPrincipal->GetStorageOriginKey(originKey); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // Get OriginSuffix nsAutoCString originAttrSuffix; rv = aPrincipal->GetOriginSuffix(originAttrSuffix); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // Set the base path and origin nsAutoCString origin = originKey + originAttrSuffix; // Encode the origin with its suffix nsAutoCString encodedOrigin; rv = mozilla::Base64Encode(origin, encodedOrigin); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::ConstructDatabasePath() - origin: %s", origin.get())); MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::ConstructDatabasePath() - encodedOrigin: " "%s", encodedOrigin.get())); // Append the origin to the path rv = aFile->AppendNative(encodedOrigin); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // Get the updated path back into the nsCString nsAutoString databasePathUTF16; rv = aFile->GetPath(databasePathUTF16); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } aDatabasePath = NS_ConvertUTF16toUTF8(databasePathUTF16); MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::ConstructDatabasePath() - databasePath: %s", aDatabasePath.get())); return NS_OK; } void MLSTransactionParent::ActorDestroy(ActorDestroyReason) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::ActorDestroy()")); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestStateDelete( RequestStateDeleteResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestStateDelete()")); // Call to the MLS rust code nsresult rv = security::mls::mls_state_delete(&mDatabasePath); aResolver(NS_SUCCEEDED(rv)); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupStateDelete( const nsTArray& aGroupIdentifier, const nsTArray& aIdentifier, RequestGroupStateDeleteResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestGroupStateDelete()")); // Call to the MLS rust code security::mls::GkGroupIdEpoch groupIdEpoch; nsresult rv = security::mls::mls_state_delete_group( &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(), aIdentifier.Elements(), aIdentifier.Length(), &groupIdEpoch); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(std::move(groupIdEpoch))); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGenerateIdentityKeypair( RequestGenerateIdentityKeypairResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestGenerateIdentityKeypair()")); // Call to the MLS rust code nsTArray identity; nsresult rv = security::mls::mls_generate_identity(&mDatabasePath, &identity); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(RawBytes{std::move(identity)})); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGenerateCredentialBasic( const nsTArray& aCredContent, RequestGenerateCredentialBasicResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestGenerateCredentialBasic()")); // Call to the MLS rust code nsTArray credential; nsresult rv = security::mls::mls_generate_credential_basic( aCredContent.Elements(), aCredContent.Length(), &credential); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(RawBytes{std::move(credential)})); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGenerateKeyPackage( const nsTArray& aIdentifier, const nsTArray& aCredential, RequestGenerateKeyPackageResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestGenerateKeyPackage()")); // Call to the MLS rust code nsTArray keyPackage; nsresult rv = security::mls::mls_generate_keypackage( &mDatabasePath, aIdentifier.Elements(), aIdentifier.Length(), aCredential.Elements(), aCredential.Length(), &keyPackage); // Return Nothing if failed if (NS_FAILED(rv)) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(RawBytes{std::move(keyPackage)})); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupCreate( const nsTArray& aIdentifier, const nsTArray& aCredential, const nsTArray& aInOptGroupIdentifier, RequestGroupCreateResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestGroupCreate()")); // Call to the MLS rust code security::mls::GkGroupIdEpoch groupIdEpoch; nsresult rv = security::mls::mls_group_create( &mDatabasePath, aIdentifier.Elements(), aIdentifier.Length(), aCredential.Elements(), aCredential.Length(), aInOptGroupIdentifier.Elements(), aInOptGroupIdentifier.Length(), &groupIdEpoch); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(std::move(groupIdEpoch))); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupJoin( const nsTArray& aIdentifier, const nsTArray& aWelcome, RequestGroupJoinResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestGroupJoin()")); // Call to the MLS rust code security::mls::GkGroupIdEpoch groupIdEpoch; nsresult rv = security::mls::mls_group_join( &mDatabasePath, aIdentifier.Elements(), aIdentifier.Length(), aWelcome.Elements(), aWelcome.Length(), &groupIdEpoch); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(std::move(groupIdEpoch))); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupAdd( const nsTArray& aGroupIdentifier, const nsTArray& aIdentifier, const nsTArray& aKeyPackage, RequestGroupAddResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestGroupAdd()")); // Call to the MLS rust code security::mls::GkMlsCommitOutput commitOutput; nsresult rv = security::mls::mls_group_add( &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(), aIdentifier.Elements(), aIdentifier.Length(), aKeyPackage.Elements(), aKeyPackage.Length(), &commitOutput); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(std::move(commitOutput))); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupProposeAdd( const nsTArray& aGroupIdentifier, const nsTArray& aIdentifier, const nsTArray& aKeyPackage, RequestGroupProposeAddResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestGroupProposeAdd()")); // Call to the MLS rust code nsTArray proposal; nsresult rv = security::mls::mls_group_propose_add( &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(), aIdentifier.Elements(), aIdentifier.Length(), aKeyPackage.Elements(), aKeyPackage.Length(), &proposal); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(RawBytes{std::move(proposal)})); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupRemove( const nsTArray& aGroupIdentifier, const nsTArray& aIdentifier, const nsTArray& aRemIdentifier, RequestGroupRemoveResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestGroupRemove()")); // Call to the MLS rust code security::mls::GkMlsCommitOutput commitOutput; nsresult rv = security::mls::mls_group_remove( &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(), aIdentifier.Elements(), aIdentifier.Length(), aRemIdentifier.Elements(), aRemIdentifier.Length(), &commitOutput); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(std::move(commitOutput))); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupProposeRemove( const nsTArray& aGroupIdentifier, const nsTArray& aIdentifier, const nsTArray& aRemIdentifier, RequestGroupProposeRemoveResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestGroupProposeRemove()")); nsTArray proposal; nsresult rv = security::mls::mls_group_propose_remove( &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(), aIdentifier.Elements(), aIdentifier.Length(), aRemIdentifier.Elements(), aRemIdentifier.Length(), &proposal); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(RawBytes{std::move(proposal)})); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupClose( const nsTArray& aGroupIdentifier, const nsTArray& aIdentifier, RequestGroupCloseResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestGroupClose()")); // Call to the MLS rust code security::mls::GkMlsCommitOutput commitOutput; nsresult rv = security::mls::mls_group_close( &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(), aIdentifier.Elements(), aIdentifier.Length(), &commitOutput); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(std::move(commitOutput))); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupDetails( const nsTArray& aGroupIdentifier, const nsTArray& aIdentifier, RequestGroupDetailsResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestGroupDetails()")); // Call to the MLS rust code security::mls::GkGroupDetails details; nsresult rv = security::mls::mls_group_details( &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(), aIdentifier.Elements(), aIdentifier.Length(), &details); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(std::move(details))); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestSend( const nsTArray& aGroupIdentifier, const nsTArray& aIdentifier, const nsTArray& aMessage, RequestSendResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestSend()")); // Call to the MLS rust code nsTArray outputMessage; nsresult rv = security::mls::mls_send( &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(), aIdentifier.Elements(), aIdentifier.Length(), aMessage.Elements(), aMessage.Length(), &outputMessage); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(RawBytes{std::move(outputMessage)})); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestReceive( const nsTArray& aClientIdentifier, const nsTArray& aMessage, RequestReceiveResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestReceive()")); // Call to the MLS rust code GkReceived received; nsTArray group_id_bytes; nsresult rv = security::mls::mls_receive( &mDatabasePath, aClientIdentifier.Elements(), aClientIdentifier.Length(), aMessage.Elements(), aMessage.Length(), &group_id_bytes, &received); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(GkReceived()); return IPC_OK(); } // Return the result if success aResolver(received); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestHasPendingProposals( const nsTArray& aGroupIdentifier, const nsTArray& aClientIdentifier, RequestHasPendingProposalsResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestHasPendingProposals()")); // Call to the MLS rust code bool received = true; nsresult rv = security::mls::mls_has_pending_proposals( &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(), aClientIdentifier.Elements(), aClientIdentifier.Length(), &received); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(received); return IPC_OK(); } // Return the result if success aResolver(received); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestClearPendingProposals( const nsTArray& aGroupIdentifier, const nsTArray& aClientIdentifier, RequestClearPendingProposalsResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestCleanPendingProposals()")); // Call to the MLS rust code bool received = true; nsresult rv = security::mls::mls_clear_pending_proposals( &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(), aClientIdentifier.Elements(), aClientIdentifier.Length(), &received); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(received); return IPC_OK(); } // Return the result if success aResolver(received); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestHasPendingCommit( const nsTArray& aGroupIdentifier, const nsTArray& aClientIdentifier, RequestHasPendingCommitResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestHasPendingCommit()")); // Call to the MLS rust code bool received = true; nsresult rv = security::mls::mls_has_pending_commit( &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(), aClientIdentifier.Elements(), aClientIdentifier.Length(), &received); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(received); return IPC_OK(); } // Return the result if success aResolver(received); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestClearPendingCommit( const nsTArray& aGroupIdentifier, const nsTArray& aClientIdentifier, RequestClearPendingCommitResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestCleanPendingCommit()")); // Call to the MLS rust code bool received = true; nsresult rv = security::mls::mls_clear_pending_commit( &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(), aClientIdentifier.Elements(), aClientIdentifier.Length(), &received); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(received); return IPC_OK(); } // Return the result if success aResolver(received); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestApplyPendingCommit( const nsTArray& aGroupIdentifier, const nsTArray& aClientIdentifier, RequestApplyPendingCommitResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestApplyPendingCommit()")); // Call to the MLS rust code GkReceived received; nsresult rv = security::mls::mls_apply_pending_commit( &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(), aClientIdentifier.Elements(), aClientIdentifier.Length(), &received); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(GkReceived()); return IPC_OK(); } // Return the result if success aResolver(received); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestExportSecret( const nsTArray& aGroupIdentifier, const nsTArray& aIdentifier, const nsTArray& aLabel, const nsTArray& aContext, uint64_t aLen, RequestExportSecretResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestExportSecret()")); // Call to the MLS rust code security::mls::GkExporterOutput exporterOutput; nsresult rv = security::mls::mls_derive_exporter( &mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(), aIdentifier.Elements(), aIdentifier.Length(), aLabel.Elements(), aLabel.Length(), aContext.Elements(), aContext.Length(), aLen, &exporterOutput); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(std::move(exporterOutput))); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGetGroupIdentifier( const nsTArray& aMessage, RequestGetGroupIdentifierResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestGetGroupIdentifier()")); nsTArray groupId; nsresult rv = security::mls::mls_get_group_id(aMessage.Elements(), aMessage.Length(), &groupId); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(RawBytes{std::move(groupId)})); return IPC_OK(); } mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGetGroupEpoch( const nsTArray& aMessage, RequestGetGroupIdentifierResolver&& aResolver) { MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug, ("MLSTransactionParent::RecvRequestGetGroupEpoch()")); nsTArray groupEpoch; nsresult rv = security::mls::mls_get_group_epoch( aMessage.Elements(), aMessage.Length(), &groupEpoch); // Return Nothing if failed if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(Nothing()); return IPC_OK(); } // Return the result if success aResolver(Some(RawBytes{std::move(groupEpoch)})); return IPC_OK(); } } // namespace mozilla::dom