-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[PM-27279] Implement TDE Registration with V2 Keys #6671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: km/account-keys-command
Are you sure you want to change the base?
Conversation
|
New Issues (1)Checkmarx found the following issues in this Pull Request
|
|
Claude finished @quexten's task —— View job Code Review Complete ✅I've completed a thorough review of this PR implementing TDE registration with V2 keys. Here are my findings: Critical Issues Found1. 🚨 NULL REFERENCE BUG - Line 456 in AccountsController.csSeverity: CRITICAL - Runtime Exception Location: Issue: return new KeysResponseModel(model.AccountKeys.ToAccountKeysData(), user.Key);This line ALWAYS calls Evidence from test: Impact:
Recommended Fix: if (model.AccountKeys != null)
{
await _setAccountKeysForUserCommand.SetAccountKeysForUserAsync(user, model.AccountKeys);
return new KeysResponseModel(model.AccountKeys.ToAccountKeysData(), user.Key);
}
else
{
await _userService.SaveUserAsync(model.ToUser(user));
var accountKeys = await _userAccountKeysQuery.Run(user);
return new KeysResponseModel(accountKeys, user.Key);
}This mirrors the pattern used in the 2. 🔒 CSRF CONCERN - Line 431 (Checkmarx Finding)Severity: LOW (likely false positive) Location: Analysis:
Recommendation:
Security Concerns3.
|
| Severity | Count | Description |
|---|---|---|
| 🚨 CRITICAL | 1 | Null reference bug causing runtime failures |
| 2 | Input validation, Test coverage | |
| 📝 MEDIUM | 4 | Code quality, documentation, consistency |
| ℹ️ LOW | 1 | CSRF false positive |
Required Changes Before Merge:
- FIX CRITICAL BUG: Line 456 null reference - handle both code paths correctly
- ADD TESTS: Cover response construction for both v1 and v2 paths
- ADD VALIDATION: Ensure proper validation of input data
Recommended Changes:
- Refactor response construction into helper method
- Enable nullable reference types
- Add XML documentation explaining dual-path behavior
Verdict: ❌ CHANGES REQUESTED - Critical null reference bug must be fixed before merge. The security architecture is sound, but the implementation has a significant defect in the legacy compatibility path that will break v1 clients.
I've also added inline comments on the specific issues for easy navigation.
|
| await _userService.SaveUserAsync(model.ToUser(user)); | ||
| } | ||
|
|
||
| return new KeysResponseModel(model.AccountKeys.ToAccountKeysData(), user.Key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚨 CRITICAL BUG: This will throw a NullReferenceException when model.AccountKeys is null (the legacy v1 path).
The code at line 447-454 branches on model.AccountKeys != null, but the response construction at line 456 always calls model.AccountKeys.ToAccountKeysData().
Fix:
| return new KeysResponseModel(model.AccountKeys.ToAccountKeysData(), user.Key); | |
| if (model.AccountKeys != null) | |
| { | |
| await _setAccountKeysForUserCommand.SetAccountKeysForUserAsync(user, model.AccountKeys); | |
| return new KeysResponseModel(model.AccountKeys.ToAccountKeysData(), user.Key); | |
| } | |
| else | |
| { | |
| await _userService.SaveUserAsync(model.ToUser(user)); | |
| var accountKeys = await _userAccountKeysQuery.Run(user); | |
| return new KeysResponseModel(accountKeys, user.Key); | |
| } |
This mirrors the pattern used in GetKeys() at lines 468-469.
| model.EncryptedPrivateKey = "encrypted-private-key"; | ||
|
|
||
| _userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user); | ||
| _featureService.IsEnabled(Bit.Core.FeatureFlagKeys.ReturnErrorOnExistingKeypair).Returns(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📝 TEST COVERAGE GAP: This test doesn't validate the response construction, which would have caught the null reference bug at line 456 in the controller.
Recommendation: Add assertions to verify the response data:
// Assert
Assert.NotNull(result);
Assert.Equal("keys", result.Object);
Assert.Equal(user.Key, result.Key);
Assert.NotNull(result.AccountKeys);
// Verify response contains data from the saved user, not null model.AccountKeysYou'll also need to mock _userAccountKeysQuery.Run(user) to return the expected data.
| [Obsolete("Use AccountKeys.UserKeyEncryptedAccountPrivateKey instead")] | ||
| [Required] | ||
| public string EncryptedPrivateKey { get; set; } | ||
| public AccountKeysRequestModel AccountKeys { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AccountKeys property has no validation attributes, while the obsolete properties have [Required].
This creates an ambiguous state where neither old nor new properties might be provided. Consider adding validation:
public class KeysRequestModel : IValidatableObject
{
// ... existing properties ...
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (AccountKeys == null && (string.IsNullOrWhiteSpace(PublicKey) || string.IsNullOrWhiteSpace(EncryptedPrivateKey)))
{
yield return new ValidationResult(
"Either AccountKeys or both PublicKey and EncryptedPrivateKey must be provided.",
new[] { nameof(AccountKeys), nameof(PublicKey), nameof(EncryptedPrivateKey) });
}
}
}




🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-27279
📔 Objective
Adds registration with V2 keys for TDE flows. TDE flows use the postKeys method to set the keys. In this PR, this is extended to set the keys via a newly introduced command instead. The command supports both v1 and v2 under the hood.
📸 Screenshots
⏰ Reminders before review
🦮 Reviewer guidelines
:+1:) or similar for great changes:memo:) or ℹ️ (:information_source:) for notes or general info:question:) for questions:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion:art:) for suggestions / improvements:x:) or:warning:) for more significant problems or concerns needing attention:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt:pick:) for minor or nitpick changes