From 00937252b04d386e786d2e7fcdaf91b62886ed9f Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Thu, 1 Aug 2024 17:32:59 +0200 Subject: [PATCH 1/6] Add ssh key item type --- src/Api/Vault/Models/CipherSSHKeyModel.cs | 26 +++++++++++++++++++ .../Models/Request/CipherRequestModel.cs | 19 ++++++++++++++ .../Models/Response/CipherResponseModel.cs | 7 +++++ src/Core/Vault/Enums/CipherType.cs | 1 + .../Vault/Models/Data/CipherSSHKeyData.cs | 10 +++++++ 5 files changed, 63 insertions(+) create mode 100644 src/Api/Vault/Models/CipherSSHKeyModel.cs create mode 100644 src/Core/Vault/Models/Data/CipherSSHKeyData.cs diff --git a/src/Api/Vault/Models/CipherSSHKeyModel.cs b/src/Api/Vault/Models/CipherSSHKeyModel.cs new file mode 100644 index 000000000000..262539b931c8 --- /dev/null +++ b/src/Api/Vault/Models/CipherSSHKeyModel.cs @@ -0,0 +1,26 @@ +using Bit.Core.Utilities; +using Bit.Core.Vault.Models.Data; + +namespace Bit.Api.Vault.Models; + +public class CipherSSHKeyModel +{ + public CipherSSHKeyModel() { } + + public CipherSSHKeyModel(CipherSSHKeyData data) + { + PrivateKey = data.PrivateKey; + PublicKey = data.PublicKey; + KeyAlgorithm = data.KeyAlgorithm; + } + + [EncryptedString] + [EncryptedStringLength(5000)] + public string PrivateKey { get; set; } + [EncryptedString] + [EncryptedStringLength(1000)] + public string PublicKey { get; set; } + [EncryptedString] + [EncryptedStringLength(1000)] + public string KeyAlgorithm { get; set; } +} diff --git a/src/Api/Vault/Models/Request/CipherRequestModel.cs b/src/Api/Vault/Models/Request/CipherRequestModel.cs index b62f2ff96e35..304749a9511a 100644 --- a/src/Api/Vault/Models/Request/CipherRequestModel.cs +++ b/src/Api/Vault/Models/Request/CipherRequestModel.cs @@ -37,6 +37,7 @@ public class CipherRequestModel public CipherCardModel Card { get; set; } public CipherIdentityModel Identity { get; set; } public CipherSecureNoteModel SecureNote { get; set; } + public CipherSSHKeyModel SSHKey { get; set; } public DateTime? LastKnownRevisionDate { get; set; } = null; public CipherDetails ToCipherDetails(Guid userId, bool allowOrgIdSet = true) @@ -82,6 +83,9 @@ public Cipher ToCipher(Cipher existingCipher) case CipherType.SecureNote: existingCipher.Data = JsonSerializer.Serialize(ToCipherSecureNoteData(), JsonHelpers.IgnoreWritingNull); break; + case CipherType.SSHKey: + existingCipher.Data = JsonSerializer.Serialize(ToCipherSSHKeyData(), JsonHelpers.IgnoreWritingNull); + break; default: throw new ArgumentException("Unsupported type: " + nameof(Type) + "."); } @@ -230,6 +234,21 @@ private CipherSecureNoteData ToCipherSecureNoteData() Type = SecureNote.Type, }; } + + private CipherSSHKeyData ToCipherSSHKeyData() + { + return new CipherSSHKeyData + { + Name = Name, + Notes = Notes, + Fields = Fields?.Select(f => f.ToCipherFieldData()), + PasswordHistory = PasswordHistory?.Select(ph => ph.ToCipherPasswordHistoryData()), + + PrivateKey = SSHKey.PrivateKey, + PublicKey = SSHKey.PublicKey, + KeyAlgorithm = SSHKey.KeyAlgorithm, + }; + } } public class CipherWithIdRequestModel : CipherRequestModel diff --git a/src/Api/Vault/Models/Response/CipherResponseModel.cs b/src/Api/Vault/Models/Response/CipherResponseModel.cs index aa86b17f5258..10b77274b50a 100644 --- a/src/Api/Vault/Models/Response/CipherResponseModel.cs +++ b/src/Api/Vault/Models/Response/CipherResponseModel.cs @@ -48,6 +48,12 @@ public CipherMiniResponseModel(Cipher cipher, IGlobalSettings globalSettings, bo cipherData = identityData; Identity = new CipherIdentityModel(identityData); break; + case CipherType.SSHKey: + var sshKeyData = JsonSerializer.Deserialize(cipher.Data); + Data = sshKeyData; + cipherData = sshKeyData; + SSHKey = new CipherSSHKeyModel(sshKeyData); + break; default: throw new ArgumentException("Unsupported " + nameof(Type) + "."); } @@ -76,6 +82,7 @@ public CipherMiniResponseModel(Cipher cipher, IGlobalSettings globalSettings, bo public CipherCardModel Card { get; set; } public CipherIdentityModel Identity { get; set; } public CipherSecureNoteModel SecureNote { get; set; } + public CipherSSHKeyModel SSHKey { get; set; } public IEnumerable Fields { get; set; } public IEnumerable PasswordHistory { get; set; } public IEnumerable Attachments { get; set; } diff --git a/src/Core/Vault/Enums/CipherType.cs b/src/Core/Vault/Enums/CipherType.cs index f3c7a90f454e..a0a49ce990f9 100644 --- a/src/Core/Vault/Enums/CipherType.cs +++ b/src/Core/Vault/Enums/CipherType.cs @@ -8,4 +8,5 @@ public enum CipherType : byte SecureNote = 2, Card = 3, Identity = 4, + SSHKey = 5, } diff --git a/src/Core/Vault/Models/Data/CipherSSHKeyData.cs b/src/Core/Vault/Models/Data/CipherSSHKeyData.cs new file mode 100644 index 000000000000..33ec5bcaa40a --- /dev/null +++ b/src/Core/Vault/Models/Data/CipherSSHKeyData.cs @@ -0,0 +1,10 @@ +namespace Bit.Core.Vault.Models.Data; + +public class CipherSSHKeyData : CipherData +{ + public CipherSSHKeyData() { } + + public string PrivateKey { get; set; } + public string PublicKey { get; set; } + public string KeyAlgorithm { get; set; } +} From cd5baf4e8c5824c798930b077abbc775b41749db Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Fri, 2 Aug 2024 18:40:53 +0200 Subject: [PATCH 2/6] Add fingerprint --- src/Api/Vault/Models/CipherSSHKeyModel.cs | 4 ++++ src/Api/Vault/Models/Request/CipherRequestModel.cs | 1 + src/Core/Vault/Models/Data/CipherSSHKeyData.cs | 1 + 3 files changed, 6 insertions(+) diff --git a/src/Api/Vault/Models/CipherSSHKeyModel.cs b/src/Api/Vault/Models/CipherSSHKeyModel.cs index 262539b931c8..0b01a48e1f95 100644 --- a/src/Api/Vault/Models/CipherSSHKeyModel.cs +++ b/src/Api/Vault/Models/CipherSSHKeyModel.cs @@ -12,6 +12,7 @@ public CipherSSHKeyModel(CipherSSHKeyData data) PrivateKey = data.PrivateKey; PublicKey = data.PublicKey; KeyAlgorithm = data.KeyAlgorithm; + KeyFingerprint = data.KeyFingerprint; } [EncryptedString] @@ -23,4 +24,7 @@ public CipherSSHKeyModel(CipherSSHKeyData data) [EncryptedString] [EncryptedStringLength(1000)] public string KeyAlgorithm { get; set; } + [EncryptedString] + [EncryptedStringLength(1000)] + public string KeyFingerprint { get; set; } } diff --git a/src/Api/Vault/Models/Request/CipherRequestModel.cs b/src/Api/Vault/Models/Request/CipherRequestModel.cs index 304749a9511a..cc5eddc5817f 100644 --- a/src/Api/Vault/Models/Request/CipherRequestModel.cs +++ b/src/Api/Vault/Models/Request/CipherRequestModel.cs @@ -247,6 +247,7 @@ private CipherSSHKeyData ToCipherSSHKeyData() PrivateKey = SSHKey.PrivateKey, PublicKey = SSHKey.PublicKey, KeyAlgorithm = SSHKey.KeyAlgorithm, + KeyFingerprint = SSHKey.KeyFingerprint, }; } } diff --git a/src/Core/Vault/Models/Data/CipherSSHKeyData.cs b/src/Core/Vault/Models/Data/CipherSSHKeyData.cs index 33ec5bcaa40a..eb0b7353651c 100644 --- a/src/Core/Vault/Models/Data/CipherSSHKeyData.cs +++ b/src/Core/Vault/Models/Data/CipherSSHKeyData.cs @@ -7,4 +7,5 @@ public CipherSSHKeyData() { } public string PrivateKey { get; set; } public string PublicKey { get; set; } public string KeyAlgorithm { get; set; } + public string KeyFingerprint { get; set; } } From ddec883cd02d7354495c5de2806e31c6ab41f1a7 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Thu, 8 Aug 2024 15:14:19 +0200 Subject: [PATCH 3/6] Limit ssh key ciphers to new clients --- src/Api/Vault/Controllers/SyncController.cs | 24 +++++++++++++++++++-- src/Core/Constants.cs | 1 + 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Api/Vault/Controllers/SyncController.cs b/src/Api/Vault/Controllers/SyncController.cs index 0381bdca6c48..e32983e92f09 100644 --- a/src/Api/Vault/Controllers/SyncController.cs +++ b/src/Api/Vault/Controllers/SyncController.cs @@ -1,7 +1,9 @@ using Bit.Api.Vault.Models.Response; +using Bit.Core; using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Enums.Provider; using Bit.Core.AdminConsole.Repositories; +using Bit.Core.Context; using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Exceptions; @@ -10,6 +12,7 @@ using Bit.Core.Services; using Bit.Core.Settings; using Bit.Core.Tools.Repositories; +using Bit.Core.Vault.Models.Data; using Bit.Core.Vault.Repositories; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -30,6 +33,8 @@ public class SyncController : Controller private readonly IPolicyRepository _policyRepository; private readonly ISendRepository _sendRepository; private readonly GlobalSettings _globalSettings; + private readonly ICurrentContext _currentContext; + private readonly Version _sshKeyCipherMinimumVersion = new(Constants.SSHKeyCipherMinimumVersion); public SyncController( IUserService userService, @@ -41,7 +46,8 @@ public SyncController( IProviderUserRepository providerUserRepository, IPolicyRepository policyRepository, ISendRepository sendRepository, - GlobalSettings globalSettings) + GlobalSettings globalSettings, + ICurrentContext currentContext) { _userService = userService; _folderRepository = folderRepository; @@ -53,6 +59,7 @@ public SyncController( _policyRepository = policyRepository; _sendRepository = sendRepository; _globalSettings = globalSettings; + _currentContext = currentContext; } [HttpGet("")] @@ -74,7 +81,8 @@ await _providerUserRepository.GetManyOrganizationDetailsByUserAsync(user.Id, var hasEnabledOrgs = organizationUserDetails.Any(o => o.Enabled); var folders = await _folderRepository.GetManyByUserIdAsync(user.Id); - var ciphers = await _cipherRepository.GetManyByUserIdAsync(user.Id, withOrganizations: hasEnabledOrgs); + var allCiphers = await _cipherRepository.GetManyByUserIdAsync(user.Id, withOrganizations: hasEnabledOrgs); + var ciphers = FilterSSHKeys(allCiphers); var sends = await _sendRepository.GetManyByUserIdAsync(user.Id); IEnumerable collections = null; @@ -95,4 +103,16 @@ await _providerUserRepository.GetManyOrganizationDetailsByUserAsync(user.Id, collectionCiphersGroupDict, excludeDomains, policies, sends); return response; } + + private ICollection FilterSSHKeys(ICollection ciphers) + { + if (_currentContext.ClientVersion >= _sshKeyCipherMinimumVersion) + { + return ciphers; + } + else + { + return ciphers.Where(c => c.Type != Core.Vault.Enums.CipherType.SSHKey).ToList(); + } + } } diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs index 34f499c96ee6..e55aa5a0a13e 100644 --- a/src/Core/Constants.cs +++ b/src/Core/Constants.cs @@ -22,6 +22,7 @@ public static class Constants public const int OrganizationSelfHostSubscriptionGracePeriodDays = 60; public const string Fido2KeyCipherMinimumVersion = "2023.10.0"; + public const string SSHKeyCipherMinimumVersion = "2024.7.0"; /// /// Used by IdentityServer to identify our own provider. From c755ec37d5ca91c8406278c18a66fd0a0b185f2a Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Thu, 8 Aug 2024 18:29:37 +0200 Subject: [PATCH 4/6] Fix enc string length for 4096 bit rsa keys --- src/Api/Vault/Models/CipherSSHKeyModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Api/Vault/Models/CipherSSHKeyModel.cs b/src/Api/Vault/Models/CipherSSHKeyModel.cs index 0b01a48e1f95..b8087050b899 100644 --- a/src/Api/Vault/Models/CipherSSHKeyModel.cs +++ b/src/Api/Vault/Models/CipherSSHKeyModel.cs @@ -19,7 +19,7 @@ public CipherSSHKeyModel(CipherSSHKeyData data) [EncryptedStringLength(5000)] public string PrivateKey { get; set; } [EncryptedString] - [EncryptedStringLength(1000)] + [EncryptedStringLength(5000)] public string PublicKey { get; set; } [EncryptedString] [EncryptedStringLength(1000)] From 39ab9a7756ebd52137ecc5e359202a2e4d64f481 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Thu, 15 Aug 2024 22:52:11 +0200 Subject: [PATCH 5/6] Remove keyAlgorithm from ssh cipher --- src/Api/Vault/Models/CipherSSHKeyModel.cs | 4 ---- src/Api/Vault/Models/Request/CipherRequestModel.cs | 1 - src/Core/Vault/Models/Data/CipherSSHKeyData.cs | 1 - 3 files changed, 6 deletions(-) diff --git a/src/Api/Vault/Models/CipherSSHKeyModel.cs b/src/Api/Vault/Models/CipherSSHKeyModel.cs index b8087050b899..47853aa36e0f 100644 --- a/src/Api/Vault/Models/CipherSSHKeyModel.cs +++ b/src/Api/Vault/Models/CipherSSHKeyModel.cs @@ -11,7 +11,6 @@ public CipherSSHKeyModel(CipherSSHKeyData data) { PrivateKey = data.PrivateKey; PublicKey = data.PublicKey; - KeyAlgorithm = data.KeyAlgorithm; KeyFingerprint = data.KeyFingerprint; } @@ -23,8 +22,5 @@ public CipherSSHKeyModel(CipherSSHKeyData data) public string PublicKey { get; set; } [EncryptedString] [EncryptedStringLength(1000)] - public string KeyAlgorithm { get; set; } - [EncryptedString] - [EncryptedStringLength(1000)] public string KeyFingerprint { get; set; } } diff --git a/src/Api/Vault/Models/Request/CipherRequestModel.cs b/src/Api/Vault/Models/Request/CipherRequestModel.cs index cc5eddc5817f..89eda415b1af 100644 --- a/src/Api/Vault/Models/Request/CipherRequestModel.cs +++ b/src/Api/Vault/Models/Request/CipherRequestModel.cs @@ -246,7 +246,6 @@ private CipherSSHKeyData ToCipherSSHKeyData() PrivateKey = SSHKey.PrivateKey, PublicKey = SSHKey.PublicKey, - KeyAlgorithm = SSHKey.KeyAlgorithm, KeyFingerprint = SSHKey.KeyFingerprint, }; } diff --git a/src/Core/Vault/Models/Data/CipherSSHKeyData.cs b/src/Core/Vault/Models/Data/CipherSSHKeyData.cs index eb0b7353651c..45c2cf607498 100644 --- a/src/Core/Vault/Models/Data/CipherSSHKeyData.cs +++ b/src/Core/Vault/Models/Data/CipherSSHKeyData.cs @@ -6,6 +6,5 @@ public CipherSSHKeyData() { } public string PrivateKey { get; set; } public string PublicKey { get; set; } - public string KeyAlgorithm { get; set; } public string KeyFingerprint { get; set; } } From f582cf5c75a71334b99785913e65750e2332b3fb Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Thu, 29 Aug 2024 12:42:04 +0200 Subject: [PATCH 6/6] Add featureflag and exclude mobile from sync --- src/Api/Vault/Controllers/SyncController.cs | 2 +- src/Core/Constants.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Api/Vault/Controllers/SyncController.cs b/src/Api/Vault/Controllers/SyncController.cs index e32983e92f09..f73f5c5c135b 100644 --- a/src/Api/Vault/Controllers/SyncController.cs +++ b/src/Api/Vault/Controllers/SyncController.cs @@ -106,7 +106,7 @@ await _providerUserRepository.GetManyOrganizationDetailsByUserAsync(user.Id, private ICollection FilterSSHKeys(ICollection ciphers) { - if (_currentContext.ClientVersion >= _sshKeyCipherMinimumVersion) + if (_currentContext.ClientVersion >= _sshKeyCipherMinimumVersion && _currentContext.DeviceType != DeviceType.Android && _currentContext.DeviceType != DeviceType.iOS && _currentContext.DeviceType != DeviceType.AndroidAmazon) { return ciphers; } diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs index e55aa5a0a13e..ba543bd79b00 100644 --- a/src/Core/Constants.cs +++ b/src/Core/Constants.cs @@ -132,6 +132,7 @@ public static class FeatureFlagKeys public const string AC2828_ProviderPortalMembersPage = "AC-2828_provider-portal-members-page"; public const string ProviderClientVaultPrivacyBanner = "ac-2833-provider-client-vault-privacy-banner"; public const string DeviceTrustLogging = "pm-8285-device-trust-logging"; + public const string SSHKeyItemVaultItem = "ssh-key-vault-item"; public static List GetAllKeys() {