mirror of
https://github.com/bitwarden/server
synced 2026-01-01 08:03:23 +00:00
[PM-21034] Feature Branch - "User Crypto V2" (#5982)
* [PM-21034] Database changes for signature keypairs (#5906) * Add signing key repositories, models, and sql migration scripts * Rename UserSigningKeys table to UserSigningKey * Rename signedpublickeyownershipclaim to signedpublickey * Move signedPublicKey to last parameter * Add newline at end of file * Rename to signature key pair * Further rename to signaturekeypair * Rename to UserSignatureKeyPairRepository * Add newline * Rename more instances to UserSignatureKeyPair * Update parameter order * Fix order * Add more renames * Cleanup * Fix sql * Add ef migrations * Fix difference in SQL SP compared to migration SP * Fix difference in SQL SP vs migration * Fix difference in SQL SP vs migration * Attempt to fix sql * Rename migration to start later * Address feedback * Move UserSignatureKeyPair to KM codeownership * Fix build * Fix build * Fix build * Move out entitytypeconfiguration * Use view for reading usersignaturekeypairs * Fix migration script * Fix migration script * Drop view if exists * Enable nullable * Replace with create or alter view * Switch go generatecomb * Switch to generatecomb * Move signature algorithm * Move useresignaturekeypairentitytypeconfiguration to km ownership * Move userSignatureKeyPair model * Unswap file names * Move sql files to km ownership * Add index on userid for signature keys * Fix wrong filename * Remove string length limit * Regenerate EF migrations * Undo changes to program.cs * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Rename dbset to plural * Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * [PM-21034] Implement api changes to retreive signing keys (#5932) * Add signing key repositories, models, and sql migration scripts * Rename UserSigningKeys table to UserSigningKey * Rename signedpublickeyownershipclaim to signedpublickey * Move signedPublicKey to last parameter * Add newline at end of file * Rename to signature key pair * Further rename to signaturekeypair * Rename to UserSignatureKeyPairRepository * Add newline * Rename more instances to UserSignatureKeyPair * Update parameter order * Fix order * Add more renames * Cleanup * Fix sql * Add ef migrations * Fix difference in SQL SP compared to migration SP * Fix difference in SQL SP vs migration * Fix difference in SQL SP vs migration * Attempt to fix sql * Rename migration to start later * Address feedback * Move UserSignatureKeyPair to KM codeownership * Fix build * Fix build * Fix build * Move out entitytypeconfiguration * Use view for reading usersignaturekeypairs * Fix migration script * Fix migration script * Add initial get keys endpoint * Add sync response * Cleanup * Add query and fix types * Add tests and cleanup * Fix test * Drop view if exists * Add km queries * Cleanup * Enable nullable * Cleanup * Cleanup * Enable nullable * Fix incorrect namespace * Remove unused using * Fix test build * Fix build error * Fix build * Attempt to fix tests * Attempt to fix tests * Replace with create or alter view * Attempt to fix tests * Attempt to fix build * Rename to include async suffix * Fix test * Rename repo * Attempt to fix tests * Cleanup * Test * Undo test * Fix tests * Fix test * Switch go generatecomb * Switch to generatecomb * Move signature algorithm * Move useresignaturekeypairentitytypeconfiguration to km ownership * Move userSignatureKeyPair model * Unswap file names * Move sql files to km ownership * Add index on userid for signature keys * Fix wrong filename * Fix build * Remove string length limit * Regenerate EF migrations * Undo changes to program.cs * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Rename dbset to plural * Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Controllers/UsersController.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Cleanup and move query to core * Fix test * Fix build * Fix tests * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Switch away from primary constructor * Use argumentNullException * Add test * Pass user account keys directly to profileresponsemodel * Move registration to core * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Remove empty line * Apply suggestions * Fix tests * Fix tests --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * [PM-22384] Implement key-rotation based enrollment to user-crypto v2 (#5934) * Add signing key repositories, models, and sql migration scripts * Rename UserSigningKeys table to UserSigningKey * Rename signedpublickeyownershipclaim to signedpublickey * Move signedPublicKey to last parameter * Add newline at end of file * Rename to signature key pair * Further rename to signaturekeypair * Rename to UserSignatureKeyPairRepository * Add newline * Rename more instances to UserSignatureKeyPair * Update parameter order * Fix order * Add more renames * Cleanup * Fix sql * Add ef migrations * Fix difference in SQL SP compared to migration SP * Fix difference in SQL SP vs migration * Fix difference in SQL SP vs migration * Attempt to fix sql * Rename migration to start later * Address feedback * Move UserSignatureKeyPair to KM codeownership * Fix build * Fix build * Fix build * Move out entitytypeconfiguration * Use view for reading usersignaturekeypairs * Fix migration script * Fix migration script * Add initial get keys endpoint * Add sync response * Cleanup * Add query and fix types * Add tests and cleanup * Fix test * Drop view if exists * Add km queries * Cleanup * Enable nullable * Cleanup * Cleanup * Enable nullable * Fix incorrect namespace * Remove unused using * Fix test build * Fix build error * Fix build * Attempt to fix tests * Attempt to fix tests * Replace with create or alter view * Attempt to fix tests * Attempt to fix build * Rename to include async suffix * Fix test * Rename repo * Attempt to fix tests * Cleanup * Test * Undo test * Fix tests * Fix test * Switch go generatecomb * Switch to generatecomb * Move signature algorithm * Move useresignaturekeypairentitytypeconfiguration to km ownership * Move userSignatureKeyPair model * Unswap file names * Move sql files to km ownership * Add index on userid for signature keys * Fix wrong filename * Fix build * Remove string length limit * Regenerate EF migrations * Undo changes to program.cs * Cleanup * Add migration to user encryption v2 * Fix build * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Rename dbset to plural * Cleanup * Cleanup * Fix build * Fix test * Add validation * Fix test * Apply fixes * Fix tests * Improve tests * Add tests * Add error message validation * Fix tests * Fix tests * Fix test * Add test * Fix tests and errors * Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Controllers/UsersController.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Cleanup and move query to core * Fix test * Fix build * Fix tests * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Switch away from primary constructor * Use argumentNullException * Add test * Pass user account keys directly to profileresponsemodel * Fix build * Fix namespace * Make signedpublickey optional * Remove unused file * Fix cases for request data conversion * Revert constructor change * Undo comments change * Apply fixes * Move registration to core * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Remove empty line * Apply suggestions * Fix tests * Fix tests * Fix build of integration tests * Attempt to fix tests * Add test * Move v2 encryption user async below public functions * Add todo * Rename to have async suffix * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Address feedback * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test coverage * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Split up validation from rotation * Fix tests * Increase test coverage * Rename tests * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test for no signature keypair data * Fix build * Enable nullable * Fix build * Clean up data model * Fix tests * Cleanup --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Fix build * [PM-22862] Account security version (#5995) * Add signing key repositories, models, and sql migration scripts * Rename UserSigningKeys table to UserSigningKey * Rename signedpublickeyownershipclaim to signedpublickey * Move signedPublicKey to last parameter * Add newline at end of file * Rename to signature key pair * Further rename to signaturekeypair * Rename to UserSignatureKeyPairRepository * Add newline * Rename more instances to UserSignatureKeyPair * Update parameter order * Fix order * Add more renames * Cleanup * Fix sql * Add ef migrations * Fix difference in SQL SP compared to migration SP * Fix difference in SQL SP vs migration * Fix difference in SQL SP vs migration * Attempt to fix sql * Rename migration to start later * Address feedback * Move UserSignatureKeyPair to KM codeownership * Fix build * Fix build * Fix build * Move out entitytypeconfiguration * Use view for reading usersignaturekeypairs * Fix migration script * Fix migration script * Add initial get keys endpoint * Add sync response * Cleanup * Add query and fix types * Add tests and cleanup * Fix test * Drop view if exists * Add km queries * Cleanup * Enable nullable * Cleanup * Cleanup * Enable nullable * Fix incorrect namespace * Remove unused using * Fix test build * Fix build error * Fix build * Attempt to fix tests * Attempt to fix tests * Replace with create or alter view * Attempt to fix tests * Attempt to fix build * Rename to include async suffix * Fix test * Rename repo * Attempt to fix tests * Cleanup * Test * Undo test * Fix tests * Fix test * Switch go generatecomb * Switch to generatecomb * Move signature algorithm * Move useresignaturekeypairentitytypeconfiguration to km ownership * Move userSignatureKeyPair model * Unswap file names * Move sql files to km ownership * Add index on userid for signature keys * Fix wrong filename * Fix build * Remove string length limit * Regenerate EF migrations * Undo changes to program.cs * Cleanup * Add migration to user encryption v2 * Fix build * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Rename dbset to plural * Cleanup * Cleanup * Fix build * Fix test * Add validation * Fix test * Apply fixes * Fix tests * Improve tests * Add tests * Add error message validation * Fix tests * Fix tests * Fix test * Add test * Fix tests and errors * Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Controllers/UsersController.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Cleanup and move query to core * Fix test * Fix build * Fix tests * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Switch away from primary constructor * Use argumentNullException * Add test * Pass user account keys directly to profileresponsemodel * Fix build * Fix namespace * Make signedpublickey optional * Remove unused file * Fix cases for request data conversion * Revert constructor change * Undo comments change * Apply fixes * Move registration to core * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Remove empty line * Apply suggestions * Fix tests * Fix tests * Fix build of integration tests * Attempt to fix tests * Add test * Move v2 encryption user async below public functions * Add todo * Rename to have async suffix * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Address feedback * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test coverage * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Split up validation from rotation * Fix tests * Increase test coverage * Rename tests * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test for no signature keypair data * Fix build * Enable nullable * Fix build * Clean up data model * Fix tests * Merge branch 'km/signing-upgrade-rotation' into km/account-security-version * Add security state to rotation * Update tests * Update tests and check for security state in v2 model * Cleanup * Add tests * Add security state data to integration test * Re-sort and remove limit * Update migrations * Fix sql * Fix sql * Fix sql * Fix fixture * Fix test * Fix test * Fix test --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * [PM-22853] Add feature flag (#6090) * Add signing key repositories, models, and sql migration scripts * Rename UserSigningKeys table to UserSigningKey * Rename signedpublickeyownershipclaim to signedpublickey * Move signedPublicKey to last parameter * Add newline at end of file * Rename to signature key pair * Further rename to signaturekeypair * Rename to UserSignatureKeyPairRepository * Add newline * Rename more instances to UserSignatureKeyPair * Update parameter order * Fix order * Add more renames * Cleanup * Fix sql * Add ef migrations * Fix difference in SQL SP compared to migration SP * Fix difference in SQL SP vs migration * Fix difference in SQL SP vs migration * Attempt to fix sql * Rename migration to start later * Address feedback * Move UserSignatureKeyPair to KM codeownership * Fix build * Fix build * Fix build * Move out entitytypeconfiguration * Use view for reading usersignaturekeypairs * Fix migration script * Fix migration script * Add initial get keys endpoint * Add sync response * Cleanup * Add query and fix types * Add tests and cleanup * Fix test * Drop view if exists * Add km queries * Cleanup * Enable nullable * Cleanup * Cleanup * Enable nullable * Fix incorrect namespace * Remove unused using * Fix test build * Fix build error * Fix build * Attempt to fix tests * Attempt to fix tests * Replace with create or alter view * Attempt to fix tests * Attempt to fix build * Rename to include async suffix * Fix test * Rename repo * Attempt to fix tests * Cleanup * Test * Undo test * Fix tests * Fix test * Switch go generatecomb * Switch to generatecomb * Move signature algorithm * Move useresignaturekeypairentitytypeconfiguration to km ownership * Move userSignatureKeyPair model * Unswap file names * Move sql files to km ownership * Add index on userid for signature keys * Fix wrong filename * Fix build * Remove string length limit * Regenerate EF migrations * Undo changes to program.cs * Cleanup * Add migration to user encryption v2 * Fix build * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Rename dbset to plural * Cleanup * Cleanup * Fix build * Fix test * Add validation * Fix test * Apply fixes * Fix tests * Improve tests * Add tests * Add error message validation * Fix tests * Fix tests * Fix test * Add test * Fix tests and errors * Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Controllers/UsersController.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Cleanup and move query to core * Fix test * Fix build * Fix tests * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Switch away from primary constructor * Use argumentNullException * Add test * Pass user account keys directly to profileresponsemodel * Fix build * Fix namespace * Make signedpublickey optional * Remove unused file * Fix cases for request data conversion * Revert constructor change * Undo comments change * Apply fixes * Move registration to core * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Remove empty line * Apply suggestions * Fix tests * Fix tests * Fix build of integration tests * Attempt to fix tests * Add test * Move v2 encryption user async below public functions * Add todo * Rename to have async suffix * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Address feedback * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test coverage * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Split up validation from rotation * Fix tests * Increase test coverage * Rename tests * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test for no signature keypair data * Fix build * Enable nullable * Fix build * Clean up data model * Fix tests * Merge branch 'km/signing-upgrade-rotation' into km/account-security-version * Add security state to rotation * Update tests * Add feature flag * Update tests and check for security state in v2 model * Cleanup * Add tests * Add security state data to integration test * Re-sort and remove limit * Update migrations * Fix sql * Fix sql * Fix sql * Fix fixture * Fix test * Fix test * Fix test --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * [PM-23222] Update revision date on key rotation (#6038) * Add signing key repositories, models, and sql migration scripts * Rename UserSigningKeys table to UserSigningKey * Rename signedpublickeyownershipclaim to signedpublickey * Move signedPublicKey to last parameter * Add newline at end of file * Rename to signature key pair * Further rename to signaturekeypair * Rename to UserSignatureKeyPairRepository * Add newline * Rename more instances to UserSignatureKeyPair * Update parameter order * Fix order * Add more renames * Cleanup * Fix sql * Add ef migrations * Fix difference in SQL SP compared to migration SP * Fix difference in SQL SP vs migration * Fix difference in SQL SP vs migration * Attempt to fix sql * Rename migration to start later * Address feedback * Move UserSignatureKeyPair to KM codeownership * Fix build * Fix build * Fix build * Move out entitytypeconfiguration * Use view for reading usersignaturekeypairs * Fix migration script * Fix migration script * Add initial get keys endpoint * Add sync response * Cleanup * Add query and fix types * Add tests and cleanup * Fix test * Drop view if exists * Add km queries * Cleanup * Enable nullable * Cleanup * Cleanup * Enable nullable * Fix incorrect namespace * Remove unused using * Fix test build * Fix build error * Fix build * Attempt to fix tests * Attempt to fix tests * Replace with create or alter view * Attempt to fix tests * Attempt to fix build * Rename to include async suffix * Fix test * Rename repo * Attempt to fix tests * Cleanup * Test * Undo test * Fix tests * Fix test * Switch go generatecomb * Switch to generatecomb * Move signature algorithm * Move useresignaturekeypairentitytypeconfiguration to km ownership * Move userSignatureKeyPair model * Unswap file names * Move sql files to km ownership * Add index on userid for signature keys * Fix wrong filename * Fix build * Remove string length limit * Regenerate EF migrations * Undo changes to program.cs * Cleanup * Add migration to user encryption v2 * Fix build * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update util/Migrator/DbScripts/2025-06-01_00_AddSignatureKeyPairTable.sql Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Rename dbset to plural * Cleanup * Cleanup * Fix build * Fix test * Add validation * Fix test * Apply fixes * Fix tests * Improve tests * Add tests * Add error message validation * Fix tests * Fix tests * Fix test * Add test * Fix tests and errors * Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Controllers/UsersController.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Cleanup and move query to core * Fix test * Fix build * Fix tests * Update src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Switch away from primary constructor * Use argumentNullException * Add test * Pass user account keys directly to profileresponsemodel * Fix build * Fix namespace * Make signedpublickey optional * Remove unused file * Fix cases for request data conversion * Revert constructor change * Undo comments change * Apply fixes * Move registration to core * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/Startup.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Remove empty line * Apply suggestions * Fix tests * Fix tests * Fix build of integration tests * Attempt to fix tests * Add test * Move v2 encryption user async below public functions * Add todo * Rename to have async suffix * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Address feedback * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test coverage * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Split up validation from rotation * Fix tests * Increase test coverage * Rename tests * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update src/Core/KeyManagement/UserKey/Implementations/RotateUserAccountkeysCommand.cs Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Add test for no signature keypair data * Fix build * Enable nullable * Fix build * Clean up data model * Fix tests * Merge branch 'km/signing-upgrade-rotation' into km/account-security-version * Add security state to rotation * Update tests * Update revision date on key rotation * Update tests and check for security state in v2 model * Cleanup * Add tests * Add security state data to integration test * Re-sort and remove limit * Update migrations * Fix sql * Fix sql * Fix sql * Fix fixture * Fix test * Fix test * Fix test * Add test for change date --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Fix signing keys * Update sql migrations * Fix tests * Add keys to identity token response * Fix tests * Fix tests * Fix formatting * Update src/Infrastructure.EntityFramework/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Infrastructure.Dapper/KeyManagement/Repositories/UserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Controllers/UsersController.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Requests/SignatureKeyPairRequestModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Api/KeyManagement/Models/Requests/PublicKeyEncryptionKeyPairRequestModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Entities/UserSignatureKeyPair.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Repositories/IUserSignatureKeyPairRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Queries/UserAccountKeysQuery.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Data/PublicKeyEncryptionKeyPairData.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Entities/UserSignatureKeyPair.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Data/RotateUserAccountKeysData.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Data/SignatureKeyPairData.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Data/SecurityStateData.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Data/UserAccountKeysData.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Request/SecurityStateModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Response/PrivateKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Response/PublicKeysResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Response/PublicKeyEncryptionKeyPairResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Queries/Interfaces/IUserAcountKeysQuery.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Update src/Core/KeyManagement/Models/Response/SignatureKeyPairResponseModel.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Remove unnecessary file * Add eof spacing * Move models * Fix build * Move models to API subdirectory * Rename model * Remove migrations * Add new ef migrations * Remove empty line * Only query account keys if the user has keys * Dotnet format * Fix test * Update test/Identity.Test/IdentityServer/BaseRequestValidatorTests.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Apply suggestion * Fix whitespace * Force camel case on response models * Address feedback for sql files * Fix build * Make index unique * Add contstraints * Fix sql * Fix order * Cleanup * Fix build * Update migrations * Update EF migrations * Change parameters to nvarchar * Update to Varchar * Apply feedback * Move refresh view * Attempt to fix build * Undo sql changes * Apply feedback about varchar * Apply feedback about refresh view * Apply feedback about new lines * Address SQL feedback * Re-sort columns * Fix build * Fix order * Fix build --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>
This commit is contained in:
30
src/Core/KeyManagement/Entities/UserSignatureKeyPair.cs
Normal file
30
src/Core/KeyManagement/Entities/UserSignatureKeyPair.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.KeyManagement.Enums;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
|
||||
namespace Bit.Core.KeyManagement.Entities;
|
||||
|
||||
public class UserSignatureKeyPair : ITableObject<Guid>, IRevisable
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
public SignatureAlgorithm SignatureAlgorithm { get; set; }
|
||||
|
||||
public required string VerifyingKey { get; set; }
|
||||
public required string SigningKey { get; set; }
|
||||
|
||||
public DateTime CreationDate { get; set; } = DateTime.UtcNow;
|
||||
public DateTime RevisionDate { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public void SetNewId()
|
||||
{
|
||||
Id = CoreHelpers.GenerateComb();
|
||||
}
|
||||
|
||||
public SignatureKeyPairData ToSignatureKeyPairData()
|
||||
{
|
||||
return new SignatureKeyPairData(SignatureAlgorithm, SigningKey, VerifyingKey);
|
||||
}
|
||||
}
|
||||
9
src/Core/KeyManagement/Enums/SignatureAlgorithm.cs
Normal file
9
src/Core/KeyManagement/Enums/SignatureAlgorithm.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Bit.Core.KeyManagement.Enums;
|
||||
|
||||
// <summary>
|
||||
// Represents the algorithm / digital signature scheme used for a signature key pair.
|
||||
// </summary>
|
||||
public enum SignatureAlgorithm : byte
|
||||
{
|
||||
Ed25519 = 0
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
using Bit.Core.KeyManagement.Commands.Interfaces;
|
||||
using Bit.Core.KeyManagement.Kdf;
|
||||
using Bit.Core.KeyManagement.Kdf.Implementations;
|
||||
using Bit.Core.KeyManagement.Queries;
|
||||
using Bit.Core.KeyManagement.Queries.Interfaces;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Bit.Core.KeyManagement;
|
||||
@@ -11,6 +13,7 @@ public static class KeyManagementServiceCollectionExtensions
|
||||
public static void AddKeyManagementServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddKeyManagementCommands();
|
||||
services.AddKeyManagementQueries();
|
||||
services.AddSendPasswordServices();
|
||||
}
|
||||
|
||||
@@ -19,4 +22,9 @@ public static class KeyManagementServiceCollectionExtensions
|
||||
services.AddScoped<IRegenerateUserAsymmetricKeysCommand, RegenerateUserAsymmetricKeysCommand>();
|
||||
services.AddScoped<IChangeKdfCommand, ChangeKdfCommand>();
|
||||
}
|
||||
|
||||
private static void AddKeyManagementQueries(this IServiceCollection services)
|
||||
{
|
||||
services.AddScoped<IUserAccountKeysQuery, UserAccountKeysQuery>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
|
||||
namespace Bit.Core.KeyManagement.Models.Api.Request;
|
||||
|
||||
public class SecurityStateModel
|
||||
{
|
||||
[StringLength(1000)]
|
||||
[JsonPropertyName("securityState")]
|
||||
public required string SecurityState { get; set; }
|
||||
[JsonPropertyName("securityVersion")]
|
||||
public required int SecurityVersion { get; set; }
|
||||
|
||||
public SecurityStateData ToSecurityState()
|
||||
{
|
||||
return new SecurityStateData
|
||||
{
|
||||
SecurityState = SecurityState,
|
||||
SecurityVersion = SecurityVersion
|
||||
};
|
||||
}
|
||||
|
||||
public static SecurityStateModel FromSecurityStateData(SecurityStateData data)
|
||||
{
|
||||
return new SecurityStateModel
|
||||
{
|
||||
SecurityState = data.SecurityState,
|
||||
SecurityVersion = data.SecurityVersion
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.KeyManagement.Models.Response;
|
||||
namespace Bit.Core.KeyManagement.Models.Api.Response;
|
||||
|
||||
public class MasterPasswordUnlockResponseModel
|
||||
{
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Bit.Core.KeyManagement.Models.Api.Request;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
using Bit.Core.Models.Api;
|
||||
|
||||
namespace Bit.Core.KeyManagement.Models.Api.Response;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This response model is used to return the asymmetric encryption keys,
|
||||
/// and signature keys of an entity. This includes the private keys of the key pairs,
|
||||
/// (private key, signing key), and the public keys of the key pairs (unsigned public key,
|
||||
/// signed public key, verification key).
|
||||
/// </summary>
|
||||
public class PrivateKeysResponseModel : ResponseModel
|
||||
{
|
||||
// Not all accounts have signature keys, but all accounts have public encryption keys.
|
||||
[JsonPropertyName("signatureKeyPair")]
|
||||
public SignatureKeyPairResponseModel? SignatureKeyPair { get; set; }
|
||||
|
||||
[JsonPropertyName("publicKeyEncryptionKeyPair")]
|
||||
public required PublicKeyEncryptionKeyPairResponseModel PublicKeyEncryptionKeyPair { get; set; }
|
||||
|
||||
[JsonPropertyName("securityState")]
|
||||
public SecurityStateModel? SecurityState { get; set; }
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute]
|
||||
public PrivateKeysResponseModel(UserAccountKeysData accountKeys) : base("privateKeys")
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(accountKeys);
|
||||
PublicKeyEncryptionKeyPair = new PublicKeyEncryptionKeyPairResponseModel(accountKeys.PublicKeyEncryptionKeyPairData);
|
||||
|
||||
if (accountKeys.SignatureKeyPairData != null && accountKeys.SecurityStateData != null)
|
||||
{
|
||||
SignatureKeyPair = new SignatureKeyPairResponseModel(accountKeys.SignatureKeyPairData);
|
||||
SecurityState = SecurityStateModel.FromSecurityStateData(accountKeys.SecurityStateData!);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
public PrivateKeysResponseModel(SignatureKeyPairResponseModel? signatureKeyPair, PublicKeyEncryptionKeyPairResponseModel publicKeyEncryptionKeyPair, SecurityStateModel? securityState)
|
||||
: base("privateKeys")
|
||||
{
|
||||
SignatureKeyPair = signatureKeyPair;
|
||||
PublicKeyEncryptionKeyPair = publicKeyEncryptionKeyPair ?? throw new ArgumentNullException(nameof(publicKeyEncryptionKeyPair));
|
||||
SecurityState = securityState;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
using Bit.Core.Models.Api;
|
||||
|
||||
namespace Bit.Core.KeyManagement.Models.Api.Response;
|
||||
|
||||
|
||||
public class PublicKeyEncryptionKeyPairResponseModel : ResponseModel
|
||||
{
|
||||
[JsonPropertyName("wrappedPrivateKey")]
|
||||
public required string WrappedPrivateKey { get; set; }
|
||||
[JsonPropertyName("publicKey")]
|
||||
public required string PublicKey { get; set; }
|
||||
[JsonPropertyName("signedPublicKey")]
|
||||
public string? SignedPublicKey { get; set; }
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute]
|
||||
public PublicKeyEncryptionKeyPairResponseModel(PublicKeyEncryptionKeyPairData keyPair)
|
||||
: base("publicKeyEncryptionKeyPair")
|
||||
{
|
||||
WrappedPrivateKey = keyPair.WrappedPrivateKey;
|
||||
PublicKey = keyPair.PublicKey;
|
||||
SignedPublicKey = keyPair.SignedPublicKey;
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
public PublicKeyEncryptionKeyPairResponseModel(string wrappedPrivateKey, string publicKey, string? signedPublicKey)
|
||||
: base("publicKeyEncryptionKeyPair")
|
||||
{
|
||||
WrappedPrivateKey = wrappedPrivateKey ?? throw new ArgumentNullException(nameof(wrappedPrivateKey));
|
||||
PublicKey = publicKey ?? throw new ArgumentNullException(nameof(publicKey));
|
||||
SignedPublicKey = signedPublicKey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
using Bit.Core.Models.Api;
|
||||
|
||||
namespace Bit.Core.KeyManagement.Models.Api.Response;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This response model is used to return the public keys of a user, to any other registered user or entity on the server.
|
||||
/// It can contain public keys (signature/encryption), and proofs between the two. It does not contain (encrypted) private keys.
|
||||
/// </summary>
|
||||
public class PublicKeysResponseModel : ResponseModel
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute]
|
||||
public PublicKeysResponseModel(UserAccountKeysData accountKeys)
|
||||
: base("publicKeys")
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(accountKeys);
|
||||
PublicKey = accountKeys.PublicKeyEncryptionKeyPairData.PublicKey;
|
||||
|
||||
if (accountKeys.SignatureKeyPairData != null)
|
||||
{
|
||||
SignedPublicKey = accountKeys.PublicKeyEncryptionKeyPairData.SignedPublicKey;
|
||||
VerifyingKey = accountKeys.SignatureKeyPairData.VerifyingKey;
|
||||
}
|
||||
}
|
||||
|
||||
public string? VerifyingKey { get; set; }
|
||||
public string? SignedPublicKey { get; set; }
|
||||
public required string PublicKey { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
using Bit.Core.Models.Api;
|
||||
|
||||
namespace Bit.Core.KeyManagement.Models.Api.Response;
|
||||
|
||||
|
||||
public class SignatureKeyPairResponseModel : ResponseModel
|
||||
{
|
||||
[JsonPropertyName("wrappedSigningKey")]
|
||||
public required string WrappedSigningKey { get; set; }
|
||||
[JsonPropertyName("verifyingKey")]
|
||||
public required string VerifyingKey { get; set; }
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute]
|
||||
public SignatureKeyPairResponseModel(SignatureKeyPairData signatureKeyPair)
|
||||
: base("signatureKeyPair")
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(signatureKeyPair);
|
||||
WrappedSigningKey = signatureKeyPair.WrappedSigningKey;
|
||||
VerifyingKey = signatureKeyPair.VerifyingKey;
|
||||
}
|
||||
|
||||
|
||||
[JsonConstructor]
|
||||
public SignatureKeyPairResponseModel(string wrappedSigningKey, string verifyingKey)
|
||||
: base("signatureKeyPair")
|
||||
{
|
||||
WrappedSigningKey = wrappedSigningKey ?? throw new ArgumentNullException(nameof(wrappedSigningKey));
|
||||
VerifyingKey = verifyingKey ?? throw new ArgumentNullException(nameof(verifyingKey));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Bit.Core.KeyManagement.Models.Response;
|
||||
namespace Bit.Core.KeyManagement.Models.Api.Response;
|
||||
|
||||
public class UserDecryptionResponseModel
|
||||
{
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Bit.Core.KeyManagement.Models.Data;
|
||||
|
||||
|
||||
public class PublicKeyEncryptionKeyPairData
|
||||
{
|
||||
public required string WrappedPrivateKey { get; set; }
|
||||
public string? SignedPublicKey { get; set; }
|
||||
public required string PublicKey { get; set; }
|
||||
|
||||
[JsonConstructor]
|
||||
[System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute]
|
||||
public PublicKeyEncryptionKeyPairData(string wrappedPrivateKey, string publicKey, string? signedPublicKey = null)
|
||||
{
|
||||
WrappedPrivateKey = wrappedPrivateKey ?? throw new ArgumentNullException(nameof(wrappedPrivateKey));
|
||||
PublicKey = publicKey ?? throw new ArgumentNullException(nameof(publicKey));
|
||||
SignedPublicKey = signedPublicKey;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
// FIXME: Update this file to be null safe and then delete the line below
|
||||
#nullable disable
|
||||
|
||||
|
||||
using Bit.Core.Auth.Entities;
|
||||
using Bit.Core.Auth.Models.Data;
|
||||
using Bit.Core.Entities;
|
||||
@@ -12,21 +10,19 @@ namespace Bit.Core.KeyManagement.Models.Data;
|
||||
public class RotateUserAccountKeysData
|
||||
{
|
||||
// Authentication for this requests
|
||||
public string OldMasterKeyAuthenticationHash { get; set; }
|
||||
public required string OldMasterKeyAuthenticationHash { get; set; }
|
||||
|
||||
// Other keys encrypted by the userkey
|
||||
public string UserKeyEncryptedAccountPrivateKey { get; set; }
|
||||
public string AccountPublicKey { get; set; }
|
||||
public required UserAccountKeysData AccountKeys { get; set; }
|
||||
|
||||
// All methods to get to the userkey
|
||||
public MasterPasswordUnlockAndAuthenticationData MasterPasswordUnlockData { get; set; }
|
||||
public IEnumerable<EmergencyAccess> EmergencyAccesses { get; set; }
|
||||
public IReadOnlyList<OrganizationUser> OrganizationUsers { get; set; }
|
||||
public IEnumerable<WebAuthnLoginRotateKeyData> WebAuthnKeys { get; set; }
|
||||
public IEnumerable<Device> DeviceKeys { get; set; }
|
||||
public required MasterPasswordUnlockAndAuthenticationData MasterPasswordUnlockData { get; set; }
|
||||
public required IEnumerable<EmergencyAccess> EmergencyAccesses { get; set; }
|
||||
public required IReadOnlyList<OrganizationUser> OrganizationUsers { get; set; }
|
||||
public required IEnumerable<WebAuthnLoginRotateKeyData> WebAuthnKeys { get; set; }
|
||||
public required IEnumerable<Device> DeviceKeys { get; set; }
|
||||
|
||||
// User vault data encrypted by the userkey
|
||||
public IEnumerable<Cipher> Ciphers { get; set; }
|
||||
public IEnumerable<Folder> Folders { get; set; }
|
||||
public IReadOnlyList<Send> Sends { get; set; }
|
||||
public required IEnumerable<Cipher> Ciphers { get; set; }
|
||||
public required IEnumerable<Folder> Folders { get; set; }
|
||||
public required IReadOnlyList<Send> Sends { get; set; }
|
||||
}
|
||||
|
||||
10
src/Core/KeyManagement/Models/Data/SecurityStateData.cs
Normal file
10
src/Core/KeyManagement/Models/Data/SecurityStateData.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
namespace Bit.Core.KeyManagement.Models.Data;
|
||||
|
||||
public class SecurityStateData
|
||||
{
|
||||
public required string SecurityState { get; set; }
|
||||
// The security version is included in the security state, but needs COSE parsing,
|
||||
// so this is a separate copy that can be used directly.
|
||||
public required int SecurityVersion { get; set; }
|
||||
}
|
||||
21
src/Core/KeyManagement/Models/Data/SignatureKeyPairData.cs
Normal file
21
src/Core/KeyManagement/Models/Data/SignatureKeyPairData.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using Bit.Core.KeyManagement.Enums;
|
||||
|
||||
namespace Bit.Core.KeyManagement.Models.Data;
|
||||
|
||||
public class SignatureKeyPairData
|
||||
{
|
||||
public required SignatureAlgorithm SignatureAlgorithm { get; set; }
|
||||
public required string WrappedSigningKey { get; set; }
|
||||
public required string VerifyingKey { get; set; }
|
||||
|
||||
[JsonConstructor]
|
||||
[System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute]
|
||||
public SignatureKeyPairData(SignatureAlgorithm signatureAlgorithm, string wrappedSigningKey, string verifyingKey)
|
||||
{
|
||||
SignatureAlgorithm = signatureAlgorithm;
|
||||
WrappedSigningKey = wrappedSigningKey ?? throw new ArgumentNullException(nameof(wrappedSigningKey));
|
||||
VerifyingKey = verifyingKey ?? throw new ArgumentNullException(nameof(verifyingKey));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Bit.Core.KeyManagement.Models.Data;
|
||||
|
||||
|
||||
public class UserAccountKeysData
|
||||
{
|
||||
public required PublicKeyEncryptionKeyPairData PublicKeyEncryptionKeyPairData { get; set; }
|
||||
public SignatureKeyPairData? SignatureKeyPairData { get; set; }
|
||||
public SecurityStateData? SecurityStateData { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
|
||||
namespace Bit.Core.KeyManagement.Queries.Interfaces;
|
||||
|
||||
public interface IUserAccountKeysQuery
|
||||
{
|
||||
Task<UserAccountKeysData> Run(User user);
|
||||
}
|
||||
35
src/Core/KeyManagement/Queries/UserAccountKeysQuery.cs
Normal file
35
src/Core/KeyManagement/Queries/UserAccountKeysQuery.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
using Bit.Core.KeyManagement.Queries.Interfaces;
|
||||
using Bit.Core.KeyManagement.Repositories;
|
||||
|
||||
namespace Bit.Core.KeyManagement.Queries;
|
||||
|
||||
|
||||
public class UserAccountKeysQuery(IUserSignatureKeyPairRepository signatureKeyPairRepository) : IUserAccountKeysQuery
|
||||
{
|
||||
public async Task<UserAccountKeysData> Run(User user)
|
||||
{
|
||||
if (user.GetSecurityVersion() < 2)
|
||||
{
|
||||
return new UserAccountKeysData
|
||||
{
|
||||
PublicKeyEncryptionKeyPairData = user.GetPublicKeyEncryptionKeyPair(),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return new UserAccountKeysData
|
||||
{
|
||||
PublicKeyEncryptionKeyPairData = user.GetPublicKeyEncryptionKeyPair(),
|
||||
SignatureKeyPairData = await signatureKeyPairRepository.GetByUserIdAsync(user.Id),
|
||||
SecurityStateData = new SecurityStateData
|
||||
{
|
||||
SecurityState = user.SecurityState!,
|
||||
SecurityVersion = user.GetSecurityVersion(),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
using Bit.Core.KeyManagement.Entities;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
using Bit.Core.KeyManagement.UserKey;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.KeyManagement.Repositories;
|
||||
|
||||
public interface IUserSignatureKeyPairRepository : IRepository<UserSignatureKeyPair, Guid>
|
||||
{
|
||||
public Task<SignatureKeyPairData?> GetByUserIdAsync(Guid userId);
|
||||
public UpdateEncryptedDataForKeyRotation UpdateForKeyRotation(Guid grantorId, SignatureKeyPairData signatureKeyPair);
|
||||
public UpdateEncryptedDataForKeyRotation SetUserSignatureKeyPair(Guid userId, SignatureKeyPairData signatureKeyPair);
|
||||
}
|
||||
@@ -1,6 +1,11 @@
|
||||
using Bit.Core.Auth.Repositories;
|
||||
// FIXME: Update this file to be null safe and then delete the line below
|
||||
#nullable disable
|
||||
|
||||
using Bit.Core.Auth.Repositories;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
using Bit.Core.KeyManagement.Repositories;
|
||||
using Bit.Core.Platform.Push;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
@@ -25,6 +30,8 @@ public class RotateUserAccountKeysCommand : IRotateUserAccountKeysCommand
|
||||
private readonly IdentityErrorDescriber _identityErrorDescriber;
|
||||
private readonly IWebAuthnCredentialRepository _credentialRepository;
|
||||
private readonly IPasswordHasher<User> _passwordHasher;
|
||||
private readonly IUserSignatureKeyPairRepository _userSignatureKeyPairRepository;
|
||||
private readonly IFeatureService _featureService;
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="RotateUserAccountKeysCommand"/>
|
||||
@@ -36,16 +43,19 @@ public class RotateUserAccountKeysCommand : IRotateUserAccountKeysCommand
|
||||
/// <param name="sendRepository">Provides a method to update re-encrypted send data</param>
|
||||
/// <param name="emergencyAccessRepository">Provides a method to update re-encrypted emergency access data</param>
|
||||
/// <param name="organizationUserRepository">Provides a method to update re-encrypted organization user data</param>
|
||||
/// <param name="deviceRepository">Provides a method to update re-encrypted device keys</param>
|
||||
/// <param name="passwordHasher">Hashes the new master password</param>
|
||||
/// <param name="pushService">Logs out user from other devices after successful rotation</param>
|
||||
/// <param name="errors">Provides a password mismatch error if master password hash validation fails</param>
|
||||
/// <param name="credentialRepository">Provides a method to update re-encrypted WebAuthn keys</param>
|
||||
/// <param name="userSignatureKeyPairRepository">Provides a method to update re-encrypted signature keys</param>
|
||||
public RotateUserAccountKeysCommand(IUserService userService, IUserRepository userRepository,
|
||||
ICipherRepository cipherRepository, IFolderRepository folderRepository, ISendRepository sendRepository,
|
||||
IEmergencyAccessRepository emergencyAccessRepository, IOrganizationUserRepository organizationUserRepository,
|
||||
IDeviceRepository deviceRepository,
|
||||
IPasswordHasher<User> passwordHasher,
|
||||
IPushNotificationService pushService, IdentityErrorDescriber errors, IWebAuthnCredentialRepository credentialRepository,
|
||||
IUserSignatureKeyPairRepository userSignatureKeyPairRepository,
|
||||
IFeatureService featureService)
|
||||
{
|
||||
_userService = userService;
|
||||
@@ -60,6 +70,8 @@ public class RotateUserAccountKeysCommand : IRotateUserAccountKeysCommand
|
||||
_identityErrorDescriber = errors;
|
||||
_credentialRepository = credentialRepository;
|
||||
_passwordHasher = passwordHasher;
|
||||
_userSignatureKeyPairRepository = userSignatureKeyPairRepository;
|
||||
_featureService = featureService;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -80,50 +92,106 @@ public class RotateUserAccountKeysCommand : IRotateUserAccountKeysCommand
|
||||
user.LastKeyRotationDate = now;
|
||||
user.SecurityStamp = Guid.NewGuid().ToString();
|
||||
|
||||
if (
|
||||
!model.MasterPasswordUnlockData.ValidateForUser(user)
|
||||
)
|
||||
List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions = [];
|
||||
|
||||
await UpdateAccountKeysAsync(model, user, saveEncryptedDataActions);
|
||||
UpdateUnlockMethods(model, user, saveEncryptedDataActions);
|
||||
UpdateUserData(model, user, saveEncryptedDataActions);
|
||||
|
||||
await _userRepository.UpdateUserKeyAndEncryptedDataV2Async(user, saveEncryptedDataActions);
|
||||
await _pushService.PushLogOutAsync(user.Id);
|
||||
return IdentityResult.Success;
|
||||
}
|
||||
|
||||
public async Task RotateV2AccountKeysAsync(RotateUserAccountKeysData model, User user, List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions)
|
||||
{
|
||||
ValidateV2Encryption(model);
|
||||
await ValidateVerifyingKeyUnchangedAsync(model, user);
|
||||
|
||||
saveEncryptedDataActions.Add(_userSignatureKeyPairRepository.UpdateForKeyRotation(user.Id, model.AccountKeys.SignatureKeyPairData));
|
||||
user.SignedPublicKey = model.AccountKeys.PublicKeyEncryptionKeyPairData.SignedPublicKey;
|
||||
user.SecurityState = model.AccountKeys.SecurityStateData!.SecurityState;
|
||||
user.SecurityVersion = model.AccountKeys.SecurityStateData.SecurityVersion;
|
||||
}
|
||||
|
||||
public void UpgradeV1ToV2Keys(RotateUserAccountKeysData model, User user, List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions)
|
||||
{
|
||||
ValidateV2Encryption(model);
|
||||
saveEncryptedDataActions.Add(_userSignatureKeyPairRepository.SetUserSignatureKeyPair(user.Id, model.AccountKeys.SignatureKeyPairData));
|
||||
user.SignedPublicKey = model.AccountKeys.PublicKeyEncryptionKeyPairData.SignedPublicKey;
|
||||
user.SecurityState = model.AccountKeys.SecurityStateData!.SecurityState;
|
||||
user.SecurityVersion = model.AccountKeys.SecurityStateData.SecurityVersion;
|
||||
}
|
||||
|
||||
public async Task UpdateAccountKeysAsync(RotateUserAccountKeysData model, User user, List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions)
|
||||
{
|
||||
ValidatePublicKeyEncryptionKeyPairUnchanged(model, user);
|
||||
|
||||
if (IsV2EncryptionUserAsync(user))
|
||||
{
|
||||
throw new InvalidOperationException("The provided master password unlock data is not valid for this user.");
|
||||
await RotateV2AccountKeysAsync(model, user, saveEncryptedDataActions);
|
||||
}
|
||||
if (
|
||||
model.AccountPublicKey != user.PublicKey
|
||||
)
|
||||
else if (model.AccountKeys.SignatureKeyPairData != null)
|
||||
{
|
||||
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.");
|
||||
UpgradeV1ToV2Keys(model, user, saveEncryptedDataActions);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetEncryptionType(model.AccountKeys.PublicKeyEncryptionKeyPairData.WrappedPrivateKey) != EncryptionType.AesCbc256_HmacSha256_B64)
|
||||
{
|
||||
throw new InvalidOperationException("The provided account private key was not wrapped with AES-256-CBC-HMAC");
|
||||
}
|
||||
// V1 user to V1 user rotation needs to further changes, the private key was re-encrypted.
|
||||
}
|
||||
|
||||
user.Key = model.MasterPasswordUnlockData.MasterKeyEncryptedUserKey;
|
||||
user.PrivateKey = model.UserKeyEncryptedAccountPrivateKey;
|
||||
user.MasterPassword = _passwordHasher.HashPassword(user, model.MasterPasswordUnlockData.MasterKeyAuthenticationHash);
|
||||
user.MasterPasswordHint = model.MasterPasswordUnlockData.MasterPasswordHint;
|
||||
// Private key is re-wrapped with new user key by client
|
||||
user.PrivateKey = model.AccountKeys.PublicKeyEncryptionKeyPairData.WrappedPrivateKey;
|
||||
}
|
||||
|
||||
public void UpdateUserData(RotateUserAccountKeysData model, User user, List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions)
|
||||
{
|
||||
// The revision date has to be updated so that de-synced clients don't accidentally post over the re-encrypted data
|
||||
// with an old-user key-encrypted copy
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions = new();
|
||||
if (model.Ciphers.Any())
|
||||
{
|
||||
saveEncryptedDataActions.Add(_cipherRepository.UpdateForKeyRotation(user.Id, model.Ciphers));
|
||||
var ciphersWithUpdatedDate = model.Ciphers.ToList().Select(c => { c.RevisionDate = now; return c; });
|
||||
saveEncryptedDataActions.Add(_cipherRepository.UpdateForKeyRotation(user.Id, ciphersWithUpdatedDate));
|
||||
}
|
||||
|
||||
if (model.Folders.Any())
|
||||
{
|
||||
saveEncryptedDataActions.Add(_folderRepository.UpdateForKeyRotation(user.Id, model.Folders));
|
||||
var foldersWithUpdatedDate = model.Folders.ToList().Select(f => { f.RevisionDate = now; return f; });
|
||||
saveEncryptedDataActions.Add(_folderRepository.UpdateForKeyRotation(user.Id, foldersWithUpdatedDate));
|
||||
}
|
||||
|
||||
if (model.Sends.Any())
|
||||
{
|
||||
saveEncryptedDataActions.Add(_sendRepository.UpdateForKeyRotation(user.Id, model.Sends));
|
||||
var sendsWithUpdatedDate = model.Sends.ToList().Select(s => { s.RevisionDate = now; return s; });
|
||||
saveEncryptedDataActions.Add(_sendRepository.UpdateForKeyRotation(user.Id, sendsWithUpdatedDate));
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
{
|
||||
saveEncryptedDataActions.Add(
|
||||
_emergencyAccessRepository.UpdateForKeyRotation(user.Id, model.EmergencyAccesses));
|
||||
saveEncryptedDataActions.Add(_emergencyAccessRepository.UpdateForKeyRotation(user.Id, model.EmergencyAccesses));
|
||||
}
|
||||
|
||||
if (model.OrganizationUsers.Any())
|
||||
{
|
||||
saveEncryptedDataActions.Add(
|
||||
_organizationUserRepository.UpdateForKeyRotation(user.Id, model.OrganizationUsers));
|
||||
saveEncryptedDataActions.Add(_organizationUserRepository.UpdateForKeyRotation(user.Id, model.OrganizationUsers));
|
||||
}
|
||||
|
||||
if (model.WebAuthnKeys.Any())
|
||||
@@ -135,9 +203,80 @@ public class RotateUserAccountKeysCommand : IRotateUserAccountKeysCommand
|
||||
{
|
||||
saveEncryptedDataActions.Add(_deviceRepository.UpdateKeysForRotationAsync(user.Id, model.DeviceKeys));
|
||||
}
|
||||
}
|
||||
|
||||
await _userRepository.UpdateUserKeyAndEncryptedDataV2Async(user, saveEncryptedDataActions);
|
||||
await _pushService.PushLogOutAsync(user.Id);
|
||||
return IdentityResult.Success;
|
||||
private bool IsV2EncryptionUserAsync(User user)
|
||||
{
|
||||
// Returns whether the user is a V2 user based on the private key's encryption type.
|
||||
ArgumentNullException.ThrowIfNull(user);
|
||||
var isPrivateKeyEncryptionV2 = GetEncryptionType(user.PrivateKey) == EncryptionType.XChaCha20Poly1305_B64;
|
||||
return isPrivateKeyEncryptionV2;
|
||||
}
|
||||
|
||||
private async Task ValidateVerifyingKeyUnchangedAsync(RotateUserAccountKeysData model, User user)
|
||||
{
|
||||
var currentSignatureKeyPair = await _userSignatureKeyPairRepository.GetByUserIdAsync(user.Id) ?? throw new InvalidOperationException("User does not have a signature key pair.");
|
||||
if (model.AccountKeys.SignatureKeyPairData.VerifyingKey != currentSignatureKeyPair!.VerifyingKey)
|
||||
{
|
||||
throw new InvalidOperationException("The provided verifying key does not match the user's current verifying key.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ValidatePublicKeyEncryptionKeyPairUnchanged(RotateUserAccountKeysData model, User user)
|
||||
{
|
||||
var publicKey = model.AccountKeys.PublicKeyEncryptionKeyPairData.PublicKey;
|
||||
if (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 key pair is currently not supported during key rotation.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ValidateV2Encryption(RotateUserAccountKeysData model)
|
||||
{
|
||||
if (model.AccountKeys.SignatureKeyPairData == null)
|
||||
{
|
||||
throw new InvalidOperationException("Signature key pair data is required for V2 encryption.");
|
||||
}
|
||||
if (GetEncryptionType(model.AccountKeys.SignatureKeyPairData.WrappedSigningKey) != EncryptionType.XChaCha20Poly1305_B64)
|
||||
{
|
||||
throw new InvalidOperationException("The provided signing key data is not wrapped with XChaCha20-Poly1305.");
|
||||
}
|
||||
if (string.IsNullOrEmpty(model.AccountKeys.SignatureKeyPairData.VerifyingKey))
|
||||
{
|
||||
throw new InvalidOperationException("The provided signature key pair data does not contain a valid verifying key.");
|
||||
}
|
||||
|
||||
if (GetEncryptionType(model.AccountKeys.PublicKeyEncryptionKeyPairData.WrappedPrivateKey) != EncryptionType.XChaCha20Poly1305_B64)
|
||||
{
|
||||
throw new InvalidOperationException("The provided private key encryption key is not wrapped with XChaCha20-Poly1305.");
|
||||
}
|
||||
if (string.IsNullOrEmpty(model.AccountKeys.PublicKeyEncryptionKeyPairData.SignedPublicKey))
|
||||
{
|
||||
throw new InvalidOperationException("No signed public key provided, but the user already has a signature key pair.");
|
||||
}
|
||||
if (model.AccountKeys.SecurityStateData == null || string.IsNullOrEmpty(model.AccountKeys.SecurityStateData.SecurityState))
|
||||
{
|
||||
throw new InvalidOperationException("No signed security state provider for V2 user");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to convert an encryption type string to an enum value.
|
||||
/// </summary>
|
||||
private static EncryptionType GetEncryptionType(string encString)
|
||||
{
|
||||
var parts = encString.Split('.');
|
||||
if (parts.Length == 1)
|
||||
{
|
||||
throw new ArgumentException("Invalid encryption type string.");
|
||||
}
|
||||
if (byte.TryParse(parts[0], out var encryptionTypeNumber))
|
||||
{
|
||||
if (Enum.IsDefined(typeof(EncryptionType), encryptionTypeNumber))
|
||||
{
|
||||
return (EncryptionType)encryptionTypeNumber;
|
||||
}
|
||||
}
|
||||
throw new ArgumentException("Invalid encryption type string.");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user