ruby-keychain 0.2.1 → 0.3.0
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 +4 -4
- data/lib/keychain/certificate.rb +3 -3
- data/lib/keychain/identity.rb +2 -2
- data/lib/keychain/item.rb +1 -1
- data/lib/keychain/key.rb +12 -3
- data/lib/keychain/keychain.rb +63 -1
- data/lib/keychain/sec.rb +1 -1
- data/lib/keychain/version.rb +1 -1
- data/spec/keychain_spec.rb +22 -0
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f322cf88ad0e198a1c6a869188ae692bae81af38
|
4
|
+
data.tar.gz: c26a017ef9ed99821844d0943b697367b10caff6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c3375d692838ca66ed6b89cccae65e93ee738ead6371bac4b32e9facd7407f157189f3288d75f19c91719dc5f62a44eba5f3e4d5da223e605b775591fe89ae5
|
7
|
+
data.tar.gz: f309869ceeeb3b9f9a3294089ba1f40c3c80fda4c41a6ffaab997f5274391a383f02325992107b65af2ffe0f8467b4ccdde40eab81f10651a1b8407ca7dcd018
|
data/lib/keychain/certificate.rb
CHANGED
@@ -18,8 +18,7 @@ end
|
|
18
18
|
class Keychain::Certificate < Sec::Base
|
19
19
|
register_type 'SecCertificate'
|
20
20
|
|
21
|
-
ATTR_MAP = {CF::Base.typecast(Sec::
|
22
|
-
CF::Base.typecast(Sec::kSecAttrAccessGroup) => :access_group,
|
21
|
+
ATTR_MAP = {CF::Base.typecast(Sec::kSecAttrAccessGroup) => :access_group,
|
23
22
|
CF::Base.typecast(Sec::kSecAttrCertificateType) => :certificate_type,
|
24
23
|
CF::Base.typecast(Sec::kSecAttrCertificateEncoding) => :certificate_encoding,
|
25
24
|
CF::Base.typecast(Sec::kSecAttrLabel) => :label,
|
@@ -29,6 +28,7 @@ class Keychain::Certificate < Sec::Base
|
|
29
28
|
CF::Base.typecast(Sec::kSecAttrSubjectKeyID) => :subject_key_id,
|
30
29
|
CF::Base.typecast(Sec::kSecAttrPublicKeyHash) => :public_key_hash}
|
31
30
|
|
31
|
+
ATTR_MAP[CF::Base.typecast(Sec::kSecAttrAccessible)] = :accessible if defined?(Sec::kSecAttrAccessible)
|
32
32
|
ATTR_MAP[CF::Base.typecast(Sec::kSecAttrAccessControl)] = :access_control if defined?(Sec::kSecAttrAccessControl)
|
33
33
|
|
34
34
|
INVERSE_ATTR_MAP = ATTR_MAP.invert
|
@@ -43,7 +43,7 @@ class Keychain::Certificate < Sec::Base
|
|
43
43
|
status = Sec.SecCertificateCopyPublicKey(self, key_ref)
|
44
44
|
Sec.check_osstatus(status)
|
45
45
|
|
46
|
-
Keychain::Key.new(key_ref.read_pointer)
|
46
|
+
Keychain::Key.new(key_ref.read_pointer).release_on_gc
|
47
47
|
end
|
48
48
|
|
49
49
|
def x509
|
data/lib/keychain/identity.rb
CHANGED
@@ -25,7 +25,7 @@ class Keychain::Identity < Sec::Base
|
|
25
25
|
status = Sec.SecIdentityCopyCertificate(self, certificate_ref)
|
26
26
|
Sec.check_osstatus(status)
|
27
27
|
|
28
|
-
Keychain::Certificate.new(certificate_ref.read_pointer)
|
28
|
+
Keychain::Certificate.new(certificate_ref.read_pointer).release_on_gc
|
29
29
|
end
|
30
30
|
|
31
31
|
def private_key
|
@@ -33,7 +33,7 @@ class Keychain::Identity < Sec::Base
|
|
33
33
|
status = Sec.SecIdentityCopyPrivateKey(self, key_ref)
|
34
34
|
Sec.check_osstatus(status)
|
35
35
|
|
36
|
-
Keychain::Key.new(key_ref.read_pointer)
|
36
|
+
Keychain::Key.new(key_ref.read_pointer).release_on_gc
|
37
37
|
end
|
38
38
|
|
39
39
|
def pkcs12(passphrase='')
|
data/lib/keychain/item.rb
CHANGED
@@ -84,7 +84,7 @@ class Keychain::Item < Sec::Base
|
|
84
84
|
Sec::Query::CLASS => self.klass,
|
85
85
|
Sec::Query::RETURN_DATA => true}.to_cf, out_buffer)
|
86
86
|
Sec.check_osstatus(status)
|
87
|
-
CF::Base.typecast(out_buffer.read_pointer).to_s
|
87
|
+
CF::Base.typecast(out_buffer.read_pointer).release_on_gc.to_s
|
88
88
|
end
|
89
89
|
|
90
90
|
# Attempts to update the keychain with any changes made to the item
|
data/lib/keychain/key.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Sec
|
2
|
-
|
2
|
+
begin
|
3
|
+
attach_variable 'kSecAttrAccessible', :pointer
|
4
|
+
rescue FFI::NotFoundError #Only available in 10.9
|
5
|
+
end
|
3
6
|
|
4
7
|
begin
|
5
8
|
attach_variable 'kSecAttrAccessControl', :pointer
|
@@ -56,13 +59,18 @@ module Sec
|
|
56
59
|
end
|
57
60
|
|
58
61
|
attach_function 'SecItemExport', [:pointer, :SecExternalFormat, :SecItemImportExportFlags, :pointer, :pointer], :osstatus
|
62
|
+
attach_function 'SecItemImport', [:pointer, :pointer,
|
63
|
+
:SecExternalFormat,
|
64
|
+
:SecExternalItemType,
|
65
|
+
:SecItemImportExportFlags,
|
66
|
+
:pointer, :pointer, :pointer], :osstatus
|
67
|
+
|
59
68
|
end
|
60
69
|
|
61
70
|
class Keychain::Key < Sec::Base
|
62
71
|
register_type 'SecKey'
|
63
72
|
|
64
|
-
ATTR_MAP = {CF::Base.typecast(Sec::
|
65
|
-
CF::Base.typecast(Sec::kSecAttrAccessGroup) => :access_group,
|
73
|
+
ATTR_MAP = {CF::Base.typecast(Sec::kSecAttrAccessGroup) => :access_group,
|
66
74
|
CF::Base.typecast(Sec::kSecAttrKeyClass) => :key_class,
|
67
75
|
CF::Base.typecast(Sec::kSecAttrLabel) => :label,
|
68
76
|
CF::Base.typecast(Sec::kSecAttrApplicationLabel) => :application_label,
|
@@ -79,6 +87,7 @@ class Keychain::Key < Sec::Base
|
|
79
87
|
CF::Base.typecast(Sec::kSecAttrCanWrap) => :can_wrap,
|
80
88
|
CF::Base.typecast(Sec::kSecAttrCanUnwrap) => :can_unwrap}
|
81
89
|
|
90
|
+
ATTR_MAP[CF::Base.typecast(Sec::kSecAttrAccessible)] = :accessible if defined?(Sec::kSecAttrAccessible)
|
82
91
|
ATTR_MAP[CF::Base.typecast(Sec::kSecAttrAccessControl)] = :access_control if defined?(Sec::kSecAttrAccessControl)
|
83
92
|
|
84
93
|
INVERSE_ATTR_MAP = ATTR_MAP.invert
|
data/lib/keychain/keychain.rb
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
|
2
2
|
module Sec
|
3
|
+
enum :SecExternalItemType, [:kSecItemTypeUnknown ,
|
4
|
+
:kSecItemTypePrivateKey,
|
5
|
+
:kSecItemTypePublicKey,
|
6
|
+
:kSecItemTypeSessionKey,
|
7
|
+
:kSecItemTypeCertificate,
|
8
|
+
:kSecItemTypeAggregate]
|
9
|
+
|
10
|
+
attach_function 'SecAccessCreate', [:pointer, :pointer, :pointer], :osstatus
|
11
|
+
attach_function 'SecTrustedApplicationCreateFromPath', [:string, :pointer], :osstatus
|
12
|
+
|
3
13
|
attach_function 'SecKeychainCopyDefault', [:pointer], :osstatus
|
4
14
|
attach_function 'SecKeychainDelete', [:keychainref], :osstatus
|
5
15
|
attach_function 'SecKeychainOpen', [:string, :pointer], :osstatus
|
@@ -19,6 +29,14 @@ module Sec
|
|
19
29
|
:lock_interval, :uint32
|
20
30
|
end
|
21
31
|
|
32
|
+
class Keychain::TrustedApplication < Sec::Base
|
33
|
+
register_type 'SecTrustedApplication'
|
34
|
+
end
|
35
|
+
|
36
|
+
class Keychain::Access < Sec::Base
|
37
|
+
register_type 'SecAccess'
|
38
|
+
end
|
39
|
+
|
22
40
|
attach_function 'SecKeychainSetSettings', [:keychainref, KeychainSettings], :osstatus
|
23
41
|
attach_function 'SecKeychainCopySettings', [:keychainref, KeychainSettings], :osstatus
|
24
42
|
|
@@ -50,7 +68,7 @@ module Keychain
|
|
50
68
|
list = FFI::MemoryPointer.new(:pointer)
|
51
69
|
status = Sec.SecKeychainCopySearchList(list)
|
52
70
|
Sec.check_osstatus(status)
|
53
|
-
ruby_list = CF::Base.typecast(list.read_pointer).to_ruby
|
71
|
+
ruby_list = CF::Base.typecast(list.read_pointer).release_on_gc.to_ruby
|
54
72
|
ruby_list << self unless ruby_list.include?(self)
|
55
73
|
status = Sec.SecKeychainSetSearchList(CF::Array.immutable(ruby_list))
|
56
74
|
Sec.check_osstatus(status)
|
@@ -102,6 +120,39 @@ module Keychain
|
|
102
120
|
Scope.new(Sec::Classes::GENERIC, self)
|
103
121
|
end
|
104
122
|
|
123
|
+
# Imports item from string or file to this keychain
|
124
|
+
#
|
125
|
+
# @param [IO, String] input IO object or String with raw data to import
|
126
|
+
# @param [Array <String>] app_list List of applications which will be
|
127
|
+
# permitted to access imported items
|
128
|
+
# @return [Array <SecKeychainItem>] List of imported keychain objects,
|
129
|
+
# each of which may be a SecCertificate, SecKey, or SecIdentity instance
|
130
|
+
def import(input, app_list=[])
|
131
|
+
input = input.read if input.is_a? IO
|
132
|
+
|
133
|
+
# Create array of TrustedApplication objects
|
134
|
+
trusted_apps = get_trusted_apps(app_list)
|
135
|
+
|
136
|
+
# Create an Access object
|
137
|
+
access_buffer = FFI::MemoryPointer.new(:pointer)
|
138
|
+
status = Sec.SecAccessCreate(path.to_cf, trusted_apps, access_buffer)
|
139
|
+
Sec.check_osstatus status
|
140
|
+
access = CF::Base.typecast(access_buffer.read_pointer)
|
141
|
+
|
142
|
+
key_params = Sec::SecItemImportExportKeyParameters.new
|
143
|
+
key_params[:accessRef] = access
|
144
|
+
|
145
|
+
# Import item to the keychain
|
146
|
+
cf_data = CF::Data.from_string(input).release_on_gc
|
147
|
+
cf_array = FFI::MemoryPointer.new(:pointer)
|
148
|
+
status = Sec.SecItemImport(cf_data, nil, :kSecFormatUnknown, :kSecItemTypeUnknown, :kSecItemPemArmour, key_params, self, cf_array)
|
149
|
+
access.release
|
150
|
+
Sec.check_osstatus status
|
151
|
+
item_array = CF::Base.typecast(cf_array.read_pointer).release_on_gc
|
152
|
+
|
153
|
+
item_array.to_ruby
|
154
|
+
end
|
155
|
+
|
105
156
|
# returns a description of the keychain
|
106
157
|
# @return [String]
|
107
158
|
def inspect
|
@@ -198,6 +249,17 @@ module Keychain
|
|
198
249
|
settings
|
199
250
|
end
|
200
251
|
|
252
|
+
def get_trusted_apps apps
|
253
|
+
trusted_app_array = apps.map do |path|
|
254
|
+
trusted_app_buffer = FFI::MemoryPointer.new(:pointer)
|
255
|
+
status = Sec.SecTrustedApplicationCreateFromPath(
|
256
|
+
path.encode(Encoding::UTF_8), trusted_app_buffer)
|
257
|
+
Sec.check_osstatus(status)
|
258
|
+
CF::Base.typecast(trusted_app_buffer.read_pointer).release_on_gc
|
259
|
+
end
|
260
|
+
trusted_app_array.to_cf
|
261
|
+
end
|
262
|
+
|
201
263
|
def put_settings settings
|
202
264
|
status = Sec.SecKeychainSetSettings(self, settings)
|
203
265
|
Sec.check_osstatus status
|
data/lib/keychain/sec.rb
CHANGED
@@ -163,7 +163,7 @@ module Sec
|
|
163
163
|
Sec::Query::RETURN_REF => false}.to_cf, result)
|
164
164
|
Sec.check_osstatus(status)
|
165
165
|
|
166
|
-
cf_dict = CF::Base.typecast(result.read_pointer)
|
166
|
+
cf_dict = CF::Base.typecast(result.read_pointer).release_on_gc
|
167
167
|
update_self_from_dictionary(cf_dict)
|
168
168
|
end
|
169
169
|
end
|
data/lib/keychain/version.rb
CHANGED
data/spec/keychain_spec.rb
CHANGED
@@ -57,6 +57,28 @@ describe Keychain do
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
+
describe 'import' do
|
61
|
+
before(:all) do
|
62
|
+
@keychain = Keychain.create(File.join(Dir.tmpdir, "keychain_spec_#{Time.now.to_i}_#{Time.now.usec}_#{rand(1000)}.keychain"), 'pass')
|
63
|
+
@rsa_key = OpenSSL::PKey::RSA.new(2048).to_s
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should import item to the keychain' do
|
67
|
+
imported_key = @keychain.import(@rsa_key, ['/usr/bin/codesign']).first
|
68
|
+
imported_key.load_attributes
|
69
|
+
found_key = Keychain::Scope.new(Sec::Classes::KEY, @keychain).all.first
|
70
|
+
expect(imported_key.attributes).to eq(found_key.attributes)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should raise an exception for duplicated item' do
|
74
|
+
expect { @keychain.import(@rsa_key) }.to raise_error(Keychain::DuplicateItemError)
|
75
|
+
end
|
76
|
+
|
77
|
+
after(:all) do
|
78
|
+
@keychain.delete
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
60
82
|
describe 'exists?' do
|
61
83
|
context 'the keychain exists' do
|
62
84
|
it 'should return true' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-keychain
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Frederick Cheung
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -44,20 +44,20 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '3.
|
47
|
+
version: '3.3'
|
48
48
|
- - ">="
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version: 3.
|
50
|
+
version: 3.3.0
|
51
51
|
type: :development
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
55
|
- - "~>"
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version: '3.
|
57
|
+
version: '3.3'
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: 3.
|
60
|
+
version: 3.3.0
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: rake
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|