1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-20 02:48:03 -05:00
This commit is contained in:
Bernd Schoolmann 2025-06-09 10:15:39 +02:00
parent d860bdc401
commit 8be2868670
No known key found for this signature in database

View File

@ -61,21 +61,28 @@ public class RotateUserAccountKeysCommand(
user.RevisionDate = user.AccountRevisionDate = now;
user.LastKeyRotationDate = now;
user.SecurityStamp = Guid.NewGuid().ToString();
var currentSignatureKeyPair = await _userSignatureKeyPairRepository.GetByUserIdAsync(user.Id);
List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions = [];
if (!model.MasterPasswordUnlockData.ValidateForUser(user))
{
throw new InvalidOperationException("The provided master password unlock data is not valid for this user.");
}
if (model.AccountKeys.PublicKeyEncryptionKeyPairData.PublicKey != user.PublicKey)
{
throw new InvalidOperationException("The provided account public key does not match the user's current public key, and changing the account asymmetric keypair is currently not supported during key rotation.");
UpdateAccountKeys(model, user, saveEncryptedDataActions);
UpdateUnlockMethods(model, user, saveEncryptedDataActions);
UpdateUserData(model, user, saveEncryptedDataActions);
await _userRepository.UpdateUserKeyAndEncryptedDataV2Async(user, saveEncryptedDataActions);
await _pushService.PushLogOutAsync(user.Id);
return IdentityResult.Success;
}
if (currentSignatureKeyPair != null)
async Task<bool> IsUserV2UserAsync(User user)
{
// user is already v2 user
ArgumentNullException.ThrowIfNull(user);
var currentSignatureKeyPair = await _userSignatureKeyPairRepository.GetByUserIdAsync(user.Id);
return currentSignatureKeyPair != null;
}
async void ValidateRotationModelSignatureKeyPairForV2User(RotateUserAccountKeysData model, User user)
{
var currentSignatureKeyPair = await _userSignatureKeyPairRepository.GetByUserIdAsync(user.Id);
if (model.AccountKeys.SignatureKeyPairData == null)
{
throw new InvalidOperationException("The provided signing key data is null, but the user already has signing keys.");
@ -90,7 +97,8 @@ public class RotateUserAccountKeysCommand(
throw new InvalidOperationException("No signed public key provided, but the user already has a signature key pair.");
}
}
else
void ValidateRotationModelSignatureKeyPairForV1UserAndUpgradeToV2(RotateUserAccountKeysData model, User user, List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions)
{
if (model.AccountKeys.SignatureKeyPairData != null)
{
@ -109,11 +117,29 @@ public class RotateUserAccountKeysCommand(
}
}
user.Key = model.MasterPasswordUnlockData.MasterKeyEncryptedUserKey;
async void UpdateAccountKeys(RotateUserAccountKeysData model, User user, List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions)
{
// Changing the public key encryption key pair is not supported during key rotation for now; so this ensures it is not accidentally changed
if (model.AccountKeys.PublicKeyEncryptionKeyPairData.PublicKey != user.PublicKey)
{
throw new InvalidOperationException("The provided account public key does not match the user's current public key, and changing the account asymmetric keypair is currently not supported during key rotation.");
}
// Private key is re-wrapped with new user key by client
user.PrivateKey = model.UserKeyEncryptedAccountPrivateKey;
user.MasterPassword = _passwordHasher.HashPassword(user, model.MasterPasswordUnlockData.MasterKeyAuthenticationHash);
user.MasterPasswordHint = model.MasterPasswordUnlockData.MasterPasswordHint;
if (await IsUserV2UserAsync(user))
{
ValidateRotationModelSignatureKeyPairForV2User(model, user);
}
else
{
ValidateRotationModelSignatureKeyPairForV1UserAndUpgradeToV2(model, user, saveEncryptedDataActions);
}
}
void UpdateUserData(RotateUserAccountKeysData model, User user, List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions)
{
if (model.Ciphers.Any())
{
saveEncryptedDataActions.Add(_cipherRepository.UpdateForKeyRotation(user.Id, model.Ciphers));
@ -128,6 +154,18 @@ public class RotateUserAccountKeysCommand(
{
saveEncryptedDataActions.Add(_sendRepository.UpdateForKeyRotation(user.Id, model.Sends));
}
}
void UpdateUnlockMethods(RotateUserAccountKeysData model, User user, List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions)
{
if (!model.MasterPasswordUnlockData.ValidateForUser(user))
{
throw new InvalidOperationException("The provided master password unlock data is not valid for this user.");
}
// Update master password authentication & unlock
user.Key = model.MasterPasswordUnlockData.MasterKeyEncryptedUserKey;
user.MasterPassword = _passwordHasher.HashPassword(user, model.MasterPasswordUnlockData.MasterKeyAuthenticationHash);
user.MasterPasswordHint = model.MasterPasswordUnlockData.MasterPasswordHint;
if (model.EmergencyAccesses.Any())
{
@ -148,9 +186,5 @@ public class RotateUserAccountKeysCommand(
{
saveEncryptedDataActions.Add(_deviceRepository.UpdateKeysForRotationAsync(user.Id, model.DeviceKeys));
}
await _userRepository.UpdateUserKeyAndEncryptedDataV2Async(user, saveEncryptedDataActions);
await _pushService.PushLogOutAsync(user.Id);
return IdentityResult.Success;
}
}