metasploit-credential 6.0.13 → 6.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d84ee592f81cc2fc01fdf4baffd55d57a97ee9ee9c35571ad053f40d34771971
4
- data.tar.gz: 234e4b50c39153c7eab48cc1b47d2b0cecc06528f1db6aed34a70a0aa63564ce
3
+ metadata.gz: 6b08c247237833c0a93eee32f6d14a678a2f320d46827eec1553d999e2601447
4
+ data.tar.gz: 8c446fa6be10d1040cb8bbcdee59fc6be9cc167bcc569d4e608ac80aafbc4b01
5
5
  SHA512:
6
- metadata.gz: 5954cc20987a1807378274482f583edf446d08dda3bfaeff2f2f0d35126b5c15b101bdb160266659324a96d9566c6e252ab55976e4be60fe41091698348edb78
7
- data.tar.gz: 7da6a368c8813fd66d9bc77a3a556a4a71d1801238b81efe0bf1a591b46826fb31adff407312dde1f5316760c868666350159986d1b4e88924b262e5379b7ba0
6
+ metadata.gz: 5922d220d8a3614d21b3a6a4639527b0d0486dac4edf6d7832f9e0354274b5b3903d6ab6049722ff3ec66f5ec7bd2aedb09155980f49582307c54f08f9efe5d0
7
+ data.tar.gz: 40dbe1b8f9ebf70be13840c791ffc05149759e44347a08946291b4c0e76b3450a4fc718910b20d7585509731d8d4432a52dbaa5067726fefd68cd475dc118bcf
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Metasploit::Credential [![Build Status](https://github.com/rapid7/metasploit-credential/actions/workflows/verify.yml/badge.svg)](https://github.com/rapid7/metasploit-credential/actions/workflows/verify.yml)[![Code Climate](https://codeclimate.com/github/rapid7/metasploit-credential.png)](https://codeclimate.com/github/rapid7/metasploit-credential)[![Dependency Status](https://gemnasium.com/rapid7/metasploit-credential.svg)](https://gemnasium.com/rapid7/metasploit-credential)[![Gem Version](https://badge.fury.io/rb/metasploit-credential.svg)](http://badge.fury.io/rb/metasploit-credential)[![Inline docs](http://inch-ci.org/github/rapid7/metasploit-credential.svg)](http://inch-ci.org/github/rapid7/metasploit-credential)[![PullReview stats](https://www.pullreview.com/github/rapid7/metasploit-credential/badges/master.svg)](https://www.pullreview.com/github/rapid7/metasploit-credential/reviews/master)
1
+ # Metasploit::Credential [![Build Status](https://github.com/rapid7/metasploit-credential/actions/workflows/verify.yml/badge.svg)](https://github.com/rapid7/metasploit-credential/actions/workflows/verify.yml)[![Dependency Status](https://gemnasium.com/rapid7/metasploit-credential.svg)](https://gemnasium.com/rapid7/metasploit-credential)[![Gem Version](https://badge.fury.io/rb/metasploit-credential.svg)](http://badge.fury.io/rb/metasploit-credential)[![Inline docs](http://inch-ci.org/github/rapid7/metasploit-credential.svg)](http://inch-ci.org/github/rapid7/metasploit-credential)
2
2
 
3
3
  ## Versioning
4
4
 
@@ -3,6 +3,7 @@ require 'base64'
3
3
 
4
4
  # A private Pkcs12 file.
5
5
  class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
6
+
6
7
  #
7
8
  # Attributes
8
9
  #
@@ -12,6 +13,14 @@ class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
12
13
  #
13
14
  # @return [String]
14
15
 
16
+ # @!attribute metadata
17
+ # Metadata for this Pkcs12:
18
+ # adcs_ca: The Certificate Authority that issued the certificate
19
+ # adcs_template: The certificate template used to issue the certificate
20
+ # pkcs12_password: The password to decrypt the Pkcs12
21
+ #
22
+ # @return [JSONB]
23
+
15
24
  #
16
25
  #
17
26
  # Validations
@@ -24,15 +33,49 @@ class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
24
33
 
25
34
  validates :data,
26
35
  presence: true
36
+
27
37
  #
28
38
  # Method Validations
29
39
  #
30
40
 
31
41
  validate :readable
32
42
 
43
+ #
44
+ # Class methods
45
+ #
46
+
33
47
  #
34
48
  # Instance Methods
35
49
  #
50
+ #
51
+
52
+ # The CA that issued the certificate
53
+ #
54
+ # @return [String]
55
+ def adcs_ca
56
+ metadata['adcs_ca']
57
+ end
58
+
59
+ # The certificate template used to issue the certificate
60
+ #
61
+ # @return [String]
62
+ def adcs_template
63
+ metadata['adcs_template']
64
+ end
65
+
66
+ # The password to decrypt the Pkcs12
67
+ #
68
+ # @return [String]
69
+ def pkcs12_password
70
+ metadata['pkcs12_password']
71
+ end
72
+
73
+ # The status if the certificate (active or inactive)
74
+ #
75
+ # @return [String]
76
+ def status
77
+ metadata['status']
78
+ end
36
79
 
37
80
  # Converts the private pkcs12 data in {#data} to an `OpenSSL::PKCS12` instance.
38
81
  #
@@ -41,7 +84,7 @@ class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
41
84
  def openssl_pkcs12
42
85
  if data
43
86
  begin
44
- password = ''
87
+ password = metadata.fetch('pkcs12_password', '')
45
88
  OpenSSL::PKCS12.new(Base64.strict_decode64(data), password)
46
89
  rescue OpenSSL::PKCS12::PKCS12Error => error
47
90
  raise ArgumentError.new(error)
@@ -50,7 +93,7 @@ class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
50
93
  end
51
94
 
52
95
  # The {#data key data}'s fingerprint, suitable for displaying to the
53
- # user.
96
+ # user. The Pkcs12 password is voluntarily not included.
54
97
  #
55
98
  # @return [String]
56
99
  def to_s
@@ -60,9 +103,12 @@ class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
60
103
  result = []
61
104
  result << "subject:#{cert.subject.to_s}"
62
105
  result << "issuer:#{cert.issuer.to_s}"
106
+ result << "ADCS CA:#{metadata['adcs_ca']}" if metadata['adcs_ca']
107
+ result << "ADCS template:#{metadata['adcs_template']}" if metadata['adcs_template']
63
108
  result.join(',')
64
109
  end
65
110
 
111
+
66
112
  private
67
113
 
68
114
  #
@@ -80,5 +126,8 @@ class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
80
126
  end
81
127
  end
82
128
 
129
+
130
+ public
131
+
83
132
  Metasploit::Concern.run(self)
84
133
  end
@@ -50,6 +50,11 @@ class Metasploit::Credential::Private < ApplicationRecord
50
50
  #
51
51
  # @return [DateTime]
52
52
 
53
+ # @!attribute metadata
54
+ # Metadata related to the private data. The data contained in this JSONB structure varies based on the subclass.
55
+ #
56
+ # @return [JSONB]
57
+
53
58
  #
54
59
  #
55
60
  # Search
@@ -63,6 +68,9 @@ class Metasploit::Credential::Private < ApplicationRecord
63
68
  search_attribute :data,
64
69
  type: :string
65
70
 
71
+ search_attribute :metadata,
72
+ type: :jsonb
73
+
66
74
  #
67
75
  # Search Withs
68
76
  #
@@ -87,7 +87,7 @@ en:
87
87
  metasploit/credential/pkcs12:
88
88
  attributes:
89
89
  data:
90
- format: "is not a Base64 encoded pkcs12 file without a password"
90
+ format: "is not a serialized data containing Base64 encoded pkcs12 file without a password and metadata"
91
91
  metasploit/credential/ssh_key:
92
92
  attributes:
93
93
  data:
@@ -0,0 +1,5 @@
1
+ class AddMetadataToMetasploitCredentialPrivates < ActiveRecord::Migration[7.0]
2
+ def change
3
+ add_column :metasploit_credential_privates, :metadata, :jsonb, null: false, default: {}
4
+ end
5
+ end
@@ -480,7 +480,7 @@ module Metasploit::Credential::Creation
480
480
  when :ssh_key
481
481
  private_object = Metasploit::Credential::SSHKey.where(data: private_data).first_or_create
482
482
  when :pkcs12
483
- private_object = Metasploit::Credential::Pkcs12.where(data: private_data).first_or_create
483
+ private_object = Metasploit::Credential::Pkcs12.where(data: private_data, metadata: opts.fetch(:private_metadata, {})).first_or_create
484
484
  when :krb_enc_key
485
485
  private_object = Metasploit::Credential::KrbEncKey.where(data: private_data).first_or_create
486
486
  when :ntlm_hash
@@ -3,7 +3,7 @@
3
3
  module Metasploit
4
4
  module Credential
5
5
  # VERSION is managed by GemRelease
6
- VERSION = '6.0.13'
6
+ VERSION = '6.0.14'
7
7
 
8
8
  # @return [String]
9
9
  #
@@ -1,6 +1,7 @@
1
1
  SET statement_timeout = 0;
2
2
  SET lock_timeout = 0;
3
3
  SET idle_in_transaction_session_timeout = 0;
4
+ SET transaction_timeout = 0;
4
5
  SET client_encoding = 'UTF8';
5
6
  SET standard_conforming_strings = on;
6
7
  SELECT pg_catalog.set_config('search_path', '', false);
@@ -929,7 +930,8 @@ CREATE TABLE public.metasploit_credential_privates (
929
930
  data text NOT NULL,
930
931
  created_at timestamp without time zone NOT NULL,
931
932
  updated_at timestamp without time zone NOT NULL,
932
- jtr_format character varying
933
+ jtr_format character varying,
934
+ metadata jsonb DEFAULT '{}'::jsonb NOT NULL
933
935
  );
934
936
 
935
937
 
@@ -4147,6 +4149,7 @@ INSERT INTO "schema_migrations" (version) VALUES
4147
4149
  ('20190308134512'),
4148
4150
  ('20190507120211'),
4149
4151
  ('20221209005658'),
4152
+ ('20250204172657'),
4150
4153
  ('21'),
4151
4154
  ('22'),
4152
4155
  ('23'),
@@ -10,10 +10,15 @@ FactoryBot.define do
10
10
  subject { '/C=BE/O=Test/OU=Test/CN=Test' }
11
11
  # the cert issuer
12
12
  issuer { '/C=BE/O=Test/OU=Test/CN=Test' }
13
+ # the pkcs12 password
14
+ pkcs12_password { '' }
15
+ # the cert not_before date
16
+ not_before { Time.now }
17
+ # the cert not_after date
18
+ not_after { Time.now + 365 * 24 * 60 * 60 }
13
19
  end
14
20
 
15
21
  data {
16
- password = ''
17
22
  pkcs12_name = ''
18
23
 
19
24
  private_key = OpenSSL::PKey::RSA.new(key_size)
@@ -22,16 +27,71 @@ FactoryBot.define do
22
27
  cert = OpenSSL::X509::Certificate.new
23
28
  cert.subject = OpenSSL::X509::Name.parse(subject)
24
29
  cert.issuer = OpenSSL::X509::Name.parse(issuer)
25
- cert.not_before = Time.now
26
- cert.not_after = Time.now + 365 * 24 * 60 * 60
30
+ cert.not_before = not_before
31
+ cert.not_after = not_after
27
32
  cert.public_key = public_key
28
33
  cert.serial = 0x0
29
34
  cert.version = 2
30
35
  cert.sign(private_key, OpenSSL::Digest.new(signing_algorithm))
31
36
 
32
- pkcs12 = OpenSSL::PKCS12.create(password, pkcs12_name, private_key, cert)
33
- pkcs12_base64 = Base64.strict_encode64(pkcs12.to_der)
34
- pkcs12_base64
37
+ pkcs12 = OpenSSL::PKCS12.create(pkcs12_password, pkcs12_name, private_key, cert)
38
+ Base64.strict_encode64(pkcs12.to_der)
35
39
  }
36
40
  end
41
+
42
+ factory :metasploit_credential_pkcs12_with_ca, parent: :metasploit_credential_pkcs12 do
43
+ transient do
44
+ # The CA that issued the certificate
45
+ adcs_ca { 'test-ca' }
46
+ end
47
+
48
+ metadata { { adcs_ca: adcs_ca } }
49
+ end
50
+
51
+ factory :metasploit_credential_pkcs12_with_adcs_template, parent: :metasploit_credential_pkcs12 do
52
+ transient do
53
+ # The certificate template used to issue the certificate
54
+ adcs_template { 'User' }
55
+ end
56
+
57
+ metadata { { adcs_template: adcs_template} }
58
+ end
59
+
60
+ factory :metasploit_credential_pkcs12_with_pkcs12_password, parent: :metasploit_credential_pkcs12 do
61
+ transient do
62
+ # The password to decrypt the pkcs12
63
+ pkcs12_password { 'Password!' }
64
+ end
65
+
66
+ metadata { { pkcs12_password: pkcs12_password } }
67
+ end
68
+
69
+ factory :metasploit_credential_pkcs12_with_status, parent: :metasploit_credential_pkcs12 do
70
+ transient do
71
+ # The CA that issued the certificate
72
+ status { 'active' }
73
+ end
74
+
75
+ metadata { { status: status } }
76
+ end
77
+
78
+ factory :metasploit_credential_pkcs12_with_ca_and_adcs_template, parent: :metasploit_credential_pkcs12 do
79
+ transient do
80
+ adcs_ca { 'test-ca' }
81
+ adcs_template { 'User' }
82
+ end
83
+
84
+ metadata { { adcs_ca: adcs_ca, adcs_template: adcs_template } }
85
+ end
86
+
87
+ factory :metasploit_credential_pkcs12_with_ca_and_adcs_template_and_pkcs12_password, parent: :metasploit_credential_pkcs12 do
88
+ transient do
89
+ adcs_ca { 'test-ca' }
90
+ adcs_template { 'User' }
91
+ pkcs12_password { 'Password!' }
92
+ end
93
+
94
+ metadata { { adcs_ca: adcs_ca, adcs_template: adcs_template, pkcs12_password: pkcs12_password } }
95
+ end
96
+
37
97
  end
@@ -864,13 +864,36 @@ RSpec.describe Metasploit::Credential::Creation do
864
864
  end
865
865
 
866
866
  context 'when :private_type is pkcs12' do
867
- it 'creates a Metasploit::Credential::Pkcs12' do
868
- opts = {
867
+ let(:opts) {
868
+ {
869
869
  private_data: FactoryBot.build(:metasploit_credential_pkcs12).data,
870
870
  private_type: :pkcs12
871
871
  }
872
+ }
873
+ it 'creates a Metasploit::Credential::Pkcs12' do
872
874
  expect{ test_object.create_credential_private(opts) }.to change{ Metasploit::Credential::Pkcs12.count }.by(1)
873
875
  end
876
+
877
+ context 'with metadata' do
878
+ it 'creates a Metasploit::Credential::Pkcs12 with the expected metadata' do
879
+ adcs_ca = 'test_ca'
880
+ adcs_template = 'test_template'
881
+ opts[:private_metadata] = { adcs_ca: adcs_ca, adcs_template: adcs_template }
882
+ pkcs12 = test_object.create_credential_private(opts)
883
+ expect(pkcs12.adcs_ca).to eq(adcs_ca)
884
+ expect(pkcs12.adcs_template).to eq(adcs_template)
885
+ end
886
+ end
887
+
888
+ context 'and the Pkcs12 has a password' do
889
+ it 'creates a valid Metasploit::Credential::Pkcs12' do
890
+ pkcs12_password = 'test_password'
891
+ opts[:private_data] = FactoryBot.build(:metasploit_credential_pkcs12, pkcs12_password: pkcs12_password ).data
892
+ opts[:private_metadata] = { pkcs12_password: pkcs12_password }
893
+ pkcs12 = test_object.create_credential_private(opts)
894
+ expect(pkcs12).to be_valid
895
+ end
896
+ end
874
897
  end
875
898
  end
876
899
 
@@ -1,6 +1,8 @@
1
1
  RSpec.describe Metasploit::Credential::Pkcs12, type: :model do
2
2
  it_should_behave_like 'Metasploit::Concern.run'
3
3
 
4
+ it { is_expected.to be_a Metasploit::Credential::Private }
5
+
4
6
  context 'factories' do
5
7
  context 'metasploit_credential_pkcs12' do
6
8
  subject(:metasploit_credential_pkcs12) do
@@ -9,6 +11,54 @@ RSpec.describe Metasploit::Credential::Pkcs12, type: :model do
9
11
 
10
12
  it { is_expected.to be_valid }
11
13
  end
14
+
15
+ context 'metasploit_credential_pkcs12_with_ca' do
16
+ subject(:metasploit_credential_pkcs12_with_ca) do
17
+ FactoryBot.build(:metasploit_credential_pkcs12_with_ca)
18
+ end
19
+
20
+ it { is_expected.to be_valid }
21
+ end
22
+
23
+ context 'metasploit_credential_pkcs12_with_adcs_template' do
24
+ subject(:metasploit_credential_pkcs12_with_adcs_template) do
25
+ FactoryBot.build(:metasploit_credential_pkcs12_with_adcs_template)
26
+ end
27
+
28
+ it { is_expected.to be_valid }
29
+ end
30
+
31
+ context 'metasploit_credential_pkcs12_with_pkcs12_password' do
32
+ subject(:metasploit_credential_pkcs12_with_pkcs12_password) do
33
+ FactoryBot.build(:metasploit_credential_pkcs12_with_pkcs12_password)
34
+ end
35
+
36
+ it { is_expected.to be_valid }
37
+ end
38
+
39
+ context 'metasploit_credential_pkcs12_with_status' do
40
+ subject(:metasploit_credential_pkcs12_with_status) do
41
+ FactoryBot.build(:metasploit_credential_pkcs12_with_status)
42
+ end
43
+
44
+ it { is_expected.to be_valid }
45
+ end
46
+
47
+ context 'metasploit_credential_pkcs12_with_ca_and_adcs_template' do
48
+ subject(:metasploit_credential_pkcs12_with_ca_and_adcs_template) do
49
+ FactoryBot.build(:metasploit_credential_pkcs12_with_ca_and_adcs_template)
50
+ end
51
+
52
+ it { is_expected.to be_valid }
53
+ end
54
+
55
+ context 'metasploit_credential_pkcs12_with_ca_and_adcs_template_and_pkcs12_password' do
56
+ subject(:metasploit_credential_pkcs12_with_ca_and_adcs_template_and_pkcs12_password) do
57
+ FactoryBot.build(:metasploit_credential_pkcs12_with_ca_and_adcs_template_and_pkcs12_password)
58
+ end
59
+
60
+ it { is_expected.to be_valid }
61
+ end
12
62
  end
13
63
 
14
64
  context 'validations' do
@@ -105,6 +155,194 @@ RSpec.describe Metasploit::Credential::Pkcs12, type: :model do
105
155
  it { is_expected.to include(error) }
106
156
  end
107
157
  end
158
+
159
+ end
160
+ end
161
+
162
+ context '#data' do
163
+ it 'returns the base64 encoded pkcs12' do
164
+ cert = 'mycert'
165
+ data = Base64.strict_encode64(cert)
166
+ pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data)
167
+ expect(pkcs12.data).to eq(data)
168
+ end
169
+ end
170
+
171
+ context '#metadata' do
172
+ let(:cert) { 'mycert' }
173
+ let(:data) { Base64.strict_encode64(cert) }
174
+
175
+ context 'with the CA' do
176
+ it 'returns the CA in the metadata' do
177
+ adcs_ca = 'myca'
178
+ pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data, metadata: { adcs_ca: adcs_ca })
179
+ expect(pkcs12.metadata).to eq( { 'adcs_ca' => adcs_ca } )
180
+ end
181
+ end
182
+
183
+ context 'with the Certififate Template' do
184
+ it 'returns the certificate template in the metadata' do
185
+ adcs_template = 'mytemplate'
186
+ pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data, metadata: { adcs_template: adcs_template })
187
+ expect(pkcs12.metadata).to eq( { 'adcs_template' => adcs_template } )
188
+ end
189
+ end
190
+
191
+ context 'with both the CA and the Certififate Template' do
192
+ it 'returns the CA and the certificate template in the metadata' do
193
+ adcs_ca = 'myca'
194
+ adcs_template = 'mytemplate'
195
+ pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data, metadata: { adcs_ca: adcs_ca, adcs_template: adcs_template })
196
+ expect(pkcs12.metadata).to eq( { 'adcs_ca' => adcs_ca, 'adcs_template' => adcs_template } )
197
+ end
198
+ end
199
+
200
+ context 'with both the CA, the Certififate Template and the cert password' do
201
+ it 'returns the CA and the certificate template in the metadata' do
202
+ adcs_ca = 'myca'
203
+ adcs_template = 'mytemplate'
204
+ pkcs12_password = 'mypassword'
205
+ pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data, metadata: { adcs_ca: adcs_ca, adcs_template: adcs_template, pkcs12_password: pkcs12_password })
206
+ expect(pkcs12.metadata).to eq( { 'adcs_ca' => adcs_ca, 'adcs_template' => adcs_template, 'pkcs12_password' => pkcs12_password } )
207
+ end
208
+ end
209
+ end
210
+
211
+ context '#adcs_ca' do
212
+ it 'returns the CA' do
213
+ cert = 'mycert'
214
+ data = Base64.strict_encode64(cert)
215
+ adcs_ca = 'myca'
216
+ pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data, metadata: { adcs_ca: adcs_ca })
217
+ expect(pkcs12.adcs_ca).to eq(adcs_ca)
218
+ end
219
+ end
220
+
221
+ context '#adcs_template' do
222
+ it 'returns the certificate template' do
223
+ cert = 'mycert'
224
+ data = Base64.strict_encode64(cert)
225
+ adcs_template = 'mytemplate'
226
+ pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data, metadata: { adcs_template: adcs_template })
227
+ expect(pkcs12.adcs_template).to eq(adcs_template)
228
+ end
229
+ end
230
+
231
+ context '#pkcs12_password' do
232
+ it 'returns the Pkcs12 password' do
233
+ cert = 'mycert'
234
+ data = Base64.strict_encode64(cert)
235
+ pkcs12_password = 'mypassword'
236
+ pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data, metadata: { pkcs12_password: pkcs12_password })
237
+ expect(pkcs12.pkcs12_password).to eq(pkcs12_password)
238
+ end
239
+ end
240
+
241
+ context '#openssl_pkcs12' do
242
+ subject { FactoryBot.build(:metasploit_credential_pkcs12).openssl_pkcs12 }
243
+
244
+ it { is_expected.to be_a OpenSSL::PKCS12 }
245
+
246
+ it 'raises an exception if data is not a base64-encoded certificate' do
247
+ expect {
248
+ FactoryBot.build(:metasploit_credential_pkcs12, data: 'wrong_cert').openssl_pkcs12
249
+ }.to raise_error(ArgumentError)
250
+ end
251
+
252
+ it 'returns the expected OpenSSL::PKCS12' do
253
+ subject = '/C=FR/O=Yeah/OU=Yeah/CN=Yeah'
254
+ issuer = '/C=FR/O=Issuer1/OU=Issuer1/CN=Issuer1'
255
+ pkcs12 = FactoryBot.build(
256
+ :metasploit_credential_pkcs12,
257
+ signing_algorithm: 'SHA512',
258
+ subject: subject,
259
+ issuer: issuer
260
+ )
261
+ openssl_pkcs12 = pkcs12.openssl_pkcs12
262
+ expect(openssl_pkcs12.certificate.signature_algorithm).to eq("sha512WithRSAEncryption")
263
+ expect(openssl_pkcs12.certificate.subject.to_s).to eq(subject)
264
+ expect(openssl_pkcs12.certificate.issuer.to_s).to eq(issuer)
265
+ end
266
+ end
267
+
268
+ context '#to_s' do
269
+ let(:subject) { '/C=FR/O=Yeah/OU=Yeah/CN=Yeah' }
270
+ let(:issuer) { '/C=FR/O=Issuer1/OU=Issuer1/CN=Issuer1' }
271
+ let(:adcs_ca) { 'myca' }
272
+ let(:adcs_template) { 'mytemplate' }
273
+ let(:pkcs12_password) { 'mypassword' }
274
+
275
+ context 'with the pkcs21 only' do
276
+ it 'returns the expected string' do
277
+ pkcs12 = FactoryBot.build(
278
+ :metasploit_credential_pkcs12,
279
+ subject: subject,
280
+ issuer: issuer
281
+ )
282
+ expect(pkcs12.to_s).to eq("subject:#{subject},issuer:#{issuer}")
283
+ end
284
+ end
285
+
286
+ context 'with the pkcs21 and the CA' do
287
+ it 'returns the expected string' do
288
+ pkcs12 = FactoryBot.build(
289
+ :metasploit_credential_pkcs12_with_ca,
290
+ subject: subject,
291
+ issuer: issuer,
292
+ metadata: { adcs_ca: adcs_ca }
293
+ )
294
+ expect(pkcs12.to_s).to eq("subject:#{subject},issuer:#{issuer},ADCS CA:#{adcs_ca}")
295
+ end
296
+ end
297
+
298
+ context 'with the pkcs21 and the ADCS template' do
299
+ it 'returns the expected string' do
300
+ pkcs12 = FactoryBot.build(
301
+ :metasploit_credential_pkcs12_with_adcs_template,
302
+ subject: subject,
303
+ issuer: issuer,
304
+ metadata: { adcs_template: adcs_template }
305
+ )
306
+ expect(pkcs12.to_s).to eq("subject:#{subject},issuer:#{issuer},ADCS template:#{adcs_template}")
307
+ end
308
+ end
309
+
310
+ context 'with the pkcs21, the CA and the ADCS template' do
311
+ it 'returns the expected string' do
312
+ subject = '/C=FR/O=Yeah/OU=Yeah/CN=Yeah'
313
+ issuer = '/C=FR/O=Issuer1/OU=Issuer1/CN=Issuer1'
314
+ pkcs12 = FactoryBot.build(
315
+ :metasploit_credential_pkcs12_with_ca_and_adcs_template,
316
+ subject: subject,
317
+ issuer: issuer,
318
+ metadata: { adcs_ca: adcs_ca, adcs_template: adcs_template }
319
+ )
320
+ expect(pkcs12.to_s).to eq("subject:#{subject},issuer:#{issuer},ADCS CA:#{adcs_ca},ADCS template:#{adcs_template}")
321
+ end
322
+ end
323
+
324
+ context 'with the pkcs21, the CA, the ADCS template and the pkcs12 password' do
325
+ it 'returns the expected string' do
326
+ subject = '/C=FR/O=Yeah/OU=Yeah/CN=Yeah'
327
+ issuer = '/C=FR/O=Issuer1/OU=Issuer1/CN=Issuer1'
328
+ pkcs12_password = 'mypassword'
329
+ pkcs12 = FactoryBot.build(
330
+ :metasploit_credential_pkcs12_with_ca_and_adcs_template_and_pkcs12_password,
331
+ subject: subject,
332
+ issuer: issuer,
333
+ pkcs12_password: pkcs12_password,
334
+ metadata: { adcs_ca: adcs_ca, adcs_template: adcs_template, pkcs12_password: pkcs12_password }
335
+ )
336
+ # The Pkcs12 password is voluntarily not included
337
+ expect(pkcs12.to_s).to eq("subject:#{subject},issuer:#{issuer},ADCS CA:#{adcs_ca},ADCS template:#{adcs_template}")
338
+ end
339
+ end
340
+
341
+ context 'with no data' do
342
+ it 'returns an empty string' do
343
+ pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: nil)
344
+ expect(pkcs12.to_s).to eq('')
345
+ end
108
346
  end
109
347
  end
110
348
 
@@ -126,6 +126,15 @@ RSpec.describe Metasploit::Credential::Private, type: :model do
126
126
  :type,
127
127
  type: :string
128
128
 
129
+ it_should_behave_like 'search_attribute',
130
+ :data,
131
+ type: :string
132
+
133
+ it_should_behave_like 'search_attribute',
134
+ :metadata,
135
+ type: :jsonb
136
+
137
+
129
138
  it_should_behave_like 'search_with',
130
139
  Metasploit::Credential::Search::Operator::Type,
131
140
  name: :type,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metasploit-credential
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.13
4
+ version: 6.0.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Metasploit Hackers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-01 00:00:00.000000000 Z
11
+ date: 2025-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: metasploit-concern
@@ -205,6 +205,7 @@ files:
205
205
  - db/migrate/20161107153145_recreate_index_on_private_data_and_type.rb
206
206
  - db/migrate/20161107203710_create_index_on_private_data_and_type_for_ssh_key.rb
207
207
  - db/migrate/20221209005658_create_index_on_private_data_and_type_for_pkcs12.rb
208
+ - db/migrate/20250204172657_add_metadata_to_metasploit_credential_privates.rb
208
209
  - lib/metasploit/credential.rb
209
210
  - lib/metasploit/credential/case_insensitive_serializer.rb
210
211
  - lib/metasploit/credential/core_validations.rb