ruby-keychain 0.3.1 → 0.3.2
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/access.rb +4 -2
- data/lib/keychain/certificate.rb +41 -39
- data/lib/keychain/error.rb +12 -10
- data/lib/keychain/identity.rb +34 -32
- data/lib/keychain/item.rb +147 -145
- data/lib/keychain/key.rb +45 -43
- data/lib/keychain/trusted_application.rb +4 -2
- data/lib/keychain/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c2ee5b2ee12fb40fcc21b22df81639cb35104bf
|
4
|
+
data.tar.gz: c0863f638b7b25276ea88dfabe29ed20be92b72f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2096c6908718c18c3cb741305e75141519a94f49c3439a98ceee5e780713fff9f684e8ee9962e670953eb848c8a28bfa5bcbe73ce7754d0dd679a96c91b3d6b7
|
7
|
+
data.tar.gz: 3b8f5d1789f5183ce0abac2cdad770b92f8b21ccf01998ce8dba185700e183e1f935053e11a4bae75a60e8541f5fec682f97bcfc8018f21a942bd51d74a30a90
|
data/lib/keychain/access.rb
CHANGED
data/lib/keychain/certificate.rb
CHANGED
@@ -15,43 +15,45 @@ module Sec
|
|
15
15
|
attach_variable 'kSecAttrPublicKeyHash', :pointer
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
18
|
+
module Keychain
|
19
|
+
class Certificate < Sec::Base
|
20
|
+
register_type 'SecCertificate'
|
21
|
+
|
22
|
+
ATTR_MAP = {CF::Base.typecast(Sec::kSecAttrAccessGroup) => :access_group,
|
23
|
+
CF::Base.typecast(Sec::kSecAttrCertificateType) => :certificate_type,
|
24
|
+
CF::Base.typecast(Sec::kSecAttrCertificateEncoding) => :certificate_encoding,
|
25
|
+
CF::Base.typecast(Sec::kSecAttrLabel) => :label,
|
26
|
+
CF::Base.typecast(Sec::kSecAttrSubject) => :subject,
|
27
|
+
CF::Base.typecast(Sec::kSecAttrIssuer) => :issuer,
|
28
|
+
CF::Base.typecast(Sec::kSecAttrSerialNumber) => :serial_number,
|
29
|
+
CF::Base.typecast(Sec::kSecAttrSubjectKeyID) => :subject_key_id,
|
30
|
+
CF::Base.typecast(Sec::kSecAttrPublicKeyHash) => :public_key_hash}
|
31
|
+
|
32
|
+
ATTR_MAP[CF::Base.typecast(Sec::kSecAttrAccessible)] = :accessible if defined?(Sec::kSecAttrAccessible)
|
33
|
+
ATTR_MAP[CF::Base.typecast(Sec::kSecAttrAccessControl)] = :access_control if defined?(Sec::kSecAttrAccessControl)
|
34
|
+
|
35
|
+
INVERSE_ATTR_MAP = ATTR_MAP.invert
|
36
|
+
define_attributes(ATTR_MAP)
|
37
|
+
|
38
|
+
def klass
|
39
|
+
Sec::Classes::CERTIFICATE.to_ruby
|
40
|
+
end
|
41
|
+
|
42
|
+
def public_key
|
43
|
+
key_ref = FFI::MemoryPointer.new(:pointer)
|
44
|
+
status = Sec.SecCertificateCopyPublicKey(self, key_ref)
|
45
|
+
Sec.check_osstatus(status)
|
46
|
+
|
47
|
+
Key.new(key_ref.read_pointer).release_on_gc
|
48
|
+
end
|
49
|
+
|
50
|
+
def x509
|
51
|
+
data_ptr = Sec.SecCertificateCopyData(self)
|
52
|
+
data = CF::Data.new(data_ptr)
|
53
|
+
|
54
|
+
result = OpenSSL::X509::Certificate.new(data.to_s)
|
55
|
+
data.release
|
56
|
+
result
|
57
|
+
end
|
39
58
|
end
|
40
|
-
|
41
|
-
def public_key
|
42
|
-
key_ref = FFI::MemoryPointer.new(:pointer)
|
43
|
-
status = Sec.SecCertificateCopyPublicKey(self, key_ref)
|
44
|
-
Sec.check_osstatus(status)
|
45
|
-
|
46
|
-
Keychain::Key.new(key_ref.read_pointer).release_on_gc
|
47
|
-
end
|
48
|
-
|
49
|
-
def x509
|
50
|
-
data_ptr = Sec.SecCertificateCopyData(self)
|
51
|
-
data = CF::Data.new(data_ptr)
|
52
|
-
|
53
|
-
result = OpenSSL::X509::Certificate.new(data.to_s)
|
54
|
-
data.release
|
55
|
-
result
|
56
|
-
end
|
57
|
-
end
|
59
|
+
end
|
data/lib/keychain/error.rb
CHANGED
@@ -6,16 +6,18 @@ end
|
|
6
6
|
# The base class of all keychain related errors
|
7
7
|
#
|
8
8
|
# The original error code is available as `code`
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
9
|
+
module Keychain
|
10
|
+
class Error < StandardError
|
11
|
+
attr_accessor :code
|
12
|
+
def initialize(code)
|
13
|
+
self.code = code
|
14
|
+
description = Sec.SecCopyErrorMessageString(code, nil)
|
15
|
+
if description.null?
|
16
|
+
super("Sec Error #{code}")
|
17
|
+
else
|
18
|
+
description = CF::Base.typecast(description)
|
19
|
+
super("#{description.to_s} (#{code})")
|
20
|
+
end
|
19
21
|
end
|
20
22
|
end
|
21
23
|
end
|
data/lib/keychain/identity.rb
CHANGED
@@ -8,46 +8,48 @@ module Sec
|
|
8
8
|
attach_variable 'kSecAttrLabel', :pointer
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
module Keychain
|
12
|
+
class Identity < Sec::Base
|
13
|
+
register_type 'SecIdentity'
|
13
14
|
|
14
|
-
|
15
|
+
ATTR_MAP = Certificate::ATTR_MAP.merge(Key::ATTR_MAP)
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
INVERSE_ATTR_MAP = ATTR_MAP.invert
|
18
|
+
define_attributes(ATTR_MAP)
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
def klass
|
21
|
+
Sec::Classes::IDENTITY.to_ruby
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
def certificate
|
25
|
+
certificate_ref = FFI::MemoryPointer.new(:pointer)
|
26
|
+
status = Sec.SecIdentityCopyCertificate(self, certificate_ref)
|
27
|
+
Sec.check_osstatus(status)
|
27
28
|
|
28
|
-
|
29
|
-
|
29
|
+
Certificate.new(certificate_ref.read_pointer).release_on_gc
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
def private_key
|
33
|
+
key_ref = FFI::MemoryPointer.new(:pointer)
|
34
|
+
status = Sec.SecIdentityCopyPrivateKey(self, key_ref)
|
35
|
+
Sec.check_osstatus(status)
|
35
36
|
|
36
|
-
|
37
|
-
|
37
|
+
Key.new(key_ref.read_pointer).release_on_gc
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
def pkcs12(passphrase='')
|
41
|
+
flags = Sec::SecItemImportExportKeyParameters.new
|
42
|
+
flags[:version] = Sec::SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION
|
43
|
+
flags[:passphrase] = CF::String.from_string(passphrase).to_ptr
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
45
|
+
data_ptr = FFI::MemoryPointer.new(:pointer)
|
46
|
+
status = Sec.SecItemExport(self, :kSecFormatPKCS12, 0, flags, data_ptr)
|
47
|
+
Sec.check_osstatus(status)
|
47
48
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
data = CF::Data.new(data_ptr.read_pointer)
|
50
|
+
result = OpenSSL::PKCS12.new(data.to_s)
|
51
|
+
data.release
|
52
|
+
result
|
53
|
+
end
|
52
54
|
end
|
53
|
-
end
|
55
|
+
end
|
data/lib/keychain/item.rb
CHANGED
@@ -9,166 +9,168 @@ end
|
|
9
9
|
# An individual item from the keychain. Individual accessors are generated for the items attributes
|
10
10
|
#
|
11
11
|
#
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
12
|
+
module Keychain
|
13
|
+
class Item < Sec::Base
|
14
|
+
register_type 'SecKeychainItem'
|
15
|
+
|
16
|
+
ATTR_MAP = {CF::Base.typecast(Sec::kSecAttrAccess) => :access,
|
17
|
+
CF::Base.typecast(Sec::kSecAttrAccount) => :account,
|
18
|
+
CF::Base.typecast(Sec::kSecAttrAuthenticationType) => :authentication_type,
|
19
|
+
CF::Base.typecast(Sec::kSecAttrComment) => :comment,
|
20
|
+
CF::Base.typecast(Sec::kSecAttrCreationDate) => :created_at,
|
21
|
+
CF::Base.typecast(Sec::kSecAttrCreator) => :creator,
|
22
|
+
CF::Base.typecast(Sec::kSecAttrDescription) => :description,
|
23
|
+
CF::Base.typecast(Sec::kSecAttrGeneric) => :generic,
|
24
|
+
CF::Base.typecast(Sec::kSecAttrIsInvisible) => :invisible,
|
25
|
+
CF::Base.typecast(Sec::kSecAttrIsNegative) => :negative,
|
26
|
+
CF::Base.typecast(Sec::kSecAttrLabel) => :label,
|
27
|
+
CF::Base.typecast(Sec::kSecAttrModificationDate) => :updated_at,
|
28
|
+
CF::Base.typecast(Sec::kSecAttrPath) => :path,
|
29
|
+
CF::Base.typecast(Sec::kSecAttrPort) => :port,
|
30
|
+
CF::Base.typecast(Sec::kSecAttrProtocol) => :protocol,
|
31
|
+
CF::Base.typecast(Sec::kSecAttrSecurityDomain) => :security_domain,
|
32
|
+
CF::Base.typecast(Sec::kSecAttrServer) => :server,
|
33
|
+
CF::Base.typecast(Sec::kSecAttrService) => :service,
|
34
|
+
CF::Base.typecast(Sec::kSecAttrType) => :type,
|
35
|
+
CF::Base.typecast(Sec::kSecClass) => :klass}
|
36
|
+
|
37
|
+
INVERSE_ATTR_MAP = ATTR_MAP.invert
|
38
|
+
define_attributes(ATTR_MAP)
|
39
|
+
|
40
|
+
# returns a programmer friendly description of the item
|
41
|
+
# @return [String]
|
42
|
+
def inspect
|
43
|
+
"<SecKeychainItem 0x#{@ptr.address.to_s(16)} #{service ? "service: #{service}" : "server: #{server}"} account: #{account}>"
|
44
|
+
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
46
|
+
# Creates a new keychain item either from an FFI::Pointer or a hash of attributes
|
47
|
+
#
|
48
|
+
# @param [FFI::Pointer, Hash] attrs_or_pointer Either an FFI::Pointer to an existing
|
49
|
+
# SecKeychainItemRef to wrap or hash of attributes to create a new, unsaved Keychain::Item from
|
50
|
+
# see {Keychain::Scope#create}
|
51
|
+
#
|
52
|
+
def self.new(attrs_or_pointer)
|
53
|
+
if attrs_or_pointer.is_a? Hash
|
54
|
+
super(0).tap do |result|
|
55
|
+
attrs_or_pointer.each {|k,v| result.send("#{k}=", v)}
|
56
|
+
end
|
57
|
+
else
|
58
|
+
super
|
55
59
|
end
|
56
|
-
else
|
57
|
-
super
|
58
60
|
end
|
59
|
-
end
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
62
|
+
# Removes the item from the associated keychain
|
63
|
+
#
|
64
|
+
def delete
|
65
|
+
status = Sec.SecKeychainItemDelete(self)
|
66
|
+
Sec.check_osstatus(status)
|
67
|
+
self
|
68
|
+
end
|
68
69
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
70
|
+
# Set a new password for the item
|
71
|
+
# @note The new password is not saved into the keychain until you call {Keychain::Item#save!}
|
72
|
+
# @param [String] value The new value for the password
|
73
|
+
# @return [String] The set value
|
74
|
+
def password=(value)
|
75
|
+
@unsaved_password = value
|
76
|
+
end
|
76
77
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
78
|
+
# Fetches the password data associated with the item. This may cause the user to be asked for access
|
79
|
+
# @return [String] The password data, an ASCII_8BIT encoded string
|
80
|
+
def password
|
81
|
+
return @unsaved_password if @unsaved_password
|
82
|
+
out_buffer = FFI::MemoryPointer.new(:pointer)
|
83
|
+
status = Sec.SecItemCopyMatching({Sec::Query::ITEM_LIST => CF::Array.immutable([self]),
|
84
|
+
Sec::Query::SEARCH_LIST => [self.keychain],
|
85
|
+
Sec::Query::CLASS => self.klass,
|
86
|
+
Sec::Query::RETURN_DATA => true}.to_cf, out_buffer)
|
87
|
+
Sec.check_osstatus(status)
|
88
|
+
CF::Base.typecast(out_buffer.read_pointer).release_on_gc.to_s
|
89
|
+
end
|
89
90
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
91
|
+
# Attempts to update the keychain with any changes made to the item
|
92
|
+
# or saves a previously unpersisted item
|
93
|
+
# @param [optional, Hash] options extra options when saving the item
|
94
|
+
# @option options [Keychain::Keychain] :keychain when saving an unsaved item, they keychain to save it in
|
95
|
+
# @return [Keychain::Item] returns the item
|
96
|
+
def save!(options={})
|
97
|
+
if persisted?
|
98
|
+
cf_dict = update
|
99
|
+
else
|
100
|
+
cf_dict = create(options)
|
101
|
+
self.ptr = cf_dict[Sec::Value::REF].to_ptr
|
102
|
+
self.retain.release_on_gc
|
103
|
+
end
|
104
|
+
@unsaved_password = nil
|
105
|
+
update_self_from_dictionary(cf_dict)
|
106
|
+
cf_dict.release
|
107
|
+
self
|
102
108
|
end
|
103
|
-
@unsaved_password = nil
|
104
|
-
update_self_from_dictionary(cf_dict)
|
105
|
-
cf_dict.release
|
106
|
-
self
|
107
|
-
end
|
108
109
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
110
|
+
# @private
|
111
|
+
def self.from_dictionary_of_attributes(cf_dict)
|
112
|
+
new(0).tap {|item| item.send :update_self_from_dictionary, cf_dict}
|
113
|
+
end
|
113
114
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
115
|
+
# Whether the item has been persisted to the keychain
|
116
|
+
# @return [Boolean]
|
117
|
+
def persisted?
|
118
|
+
!@ptr.null?
|
119
|
+
end
|
119
120
|
|
120
|
-
|
121
|
+
private
|
121
122
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
123
|
+
def create(options)
|
124
|
+
result = FFI::MemoryPointer.new :pointer
|
125
|
+
query = build_create_query(options)
|
126
|
+
query.merge!(build_new_attributes)
|
127
|
+
status = Sec.SecItemAdd(query, result);
|
128
|
+
Sec.check_osstatus(status)
|
129
|
+
cf_dict = CF::Base.typecast(result.read_pointer)
|
130
|
+
end
|
130
131
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
132
|
+
def update
|
133
|
+
status = Sec.SecItemUpdate({Sec::Query::SEARCH_LIST => [self.keychain],
|
134
|
+
Sec::Query::ITEM_LIST => [self],
|
135
|
+
Sec::Query::CLASS => klass}.to_cf, build_new_attributes);
|
136
|
+
Sec.check_osstatus(status)
|
137
|
+
|
138
|
+
result = FFI::MemoryPointer.new :pointer
|
139
|
+
query = build_refresh_query
|
140
|
+
status = Sec.SecItemCopyMatching(query, result);
|
141
|
+
Sec.check_osstatus(status)
|
142
|
+
cf_dict = CF::Base.typecast(result.read_pointer)
|
143
|
+
end
|
144
|
+
|
145
|
+
def build_create_query options
|
146
|
+
query = CF::Dictionary.mutable
|
147
|
+
query[Sec::Value::DATA] = CF::Data.from_string(@unsaved_password) if @unsaved_password
|
148
|
+
query[Sec::Query::KEYCHAIN] = options[:keychain] if options[:keychain]
|
149
|
+
query[Sec::Query::RETURN_ATTRIBUTES] = CF::Boolean::TRUE
|
150
|
+
query[Sec::Query::RETURN_REF] = CF::Boolean::TRUE
|
151
|
+
query
|
152
|
+
end
|
152
153
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
154
|
+
def build_refresh_query
|
155
|
+
query = CF::Dictionary.mutable
|
156
|
+
query[Sec::Query::SEARCH_LIST] = CF::Array.immutable([self.keychain])
|
157
|
+
query[Sec::Query::ITEM_LIST] = CF::Array.immutable([self])
|
158
|
+
query[Sec::Query::RETURN_ATTRIBUTES] = CF::Boolean::TRUE
|
159
|
+
query[Sec::Query::RETURN_REF] = CF::Boolean::TRUE
|
160
|
+
query[Sec::Query::CLASS] = klass.to_cf
|
161
|
+
query
|
162
|
+
end
|
162
163
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
164
|
+
def build_new_attributes
|
165
|
+
new_attributes = CF::Dictionary.mutable
|
166
|
+
@attributes.each do |k,v|
|
167
|
+
next if k == :created_at || k == :updated_at
|
168
|
+
next if k == :klass && persisted?
|
169
|
+
k = self.class::INVERSE_ATTR_MAP[k]
|
170
|
+
new_attributes[k] = v.to_cf
|
171
|
+
end
|
172
|
+
new_attributes[Sec::Value::DATA] = CF::Data.from_string(@unsaved_password) if @unsaved_password
|
173
|
+
new_attributes
|
170
174
|
end
|
171
|
-
new_attributes[Sec::Value::DATA] = CF::Data.from_string(@unsaved_password) if @unsaved_password
|
172
|
-
new_attributes
|
173
175
|
end
|
174
176
|
end
|
data/lib/keychain/key.rb
CHANGED
@@ -67,48 +67,50 @@ module Sec
|
|
67
67
|
|
68
68
|
end
|
69
69
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
70
|
+
module Keychain
|
71
|
+
class Key < Sec::Base
|
72
|
+
register_type 'SecKey'
|
73
|
+
|
74
|
+
ATTR_MAP = {CF::Base.typecast(Sec::kSecAttrAccessGroup) => :access_group,
|
75
|
+
CF::Base.typecast(Sec::kSecAttrKeyClass) => :key_class,
|
76
|
+
CF::Base.typecast(Sec::kSecAttrLabel) => :label,
|
77
|
+
CF::Base.typecast(Sec::kSecAttrApplicationLabel) => :application_label,
|
78
|
+
CF::Base.typecast(Sec::kSecAttrIsPermanent) => :is_permanent,
|
79
|
+
CF::Base.typecast(Sec::kSecAttrApplicationTag) => :application_tag,
|
80
|
+
CF::Base.typecast(Sec::kSecAttrKeyType) => :key_type,
|
81
|
+
CF::Base.typecast(Sec::kSecAttrKeySizeInBits) => :size_in_bites,
|
82
|
+
CF::Base.typecast(Sec::kSecAttrEffectiveKeySize) => :effective_key_size,
|
83
|
+
CF::Base.typecast(Sec::kSecAttrCanEncrypt) => :can_encrypt,
|
84
|
+
CF::Base.typecast(Sec::kSecAttrCanDecrypt) => :can_decrypt,
|
85
|
+
CF::Base.typecast(Sec::kSecAttrCanDerive) => :can_derive,
|
86
|
+
CF::Base.typecast(Sec::kSecAttrCanSign) => :can_sign,
|
87
|
+
CF::Base.typecast(Sec::kSecAttrCanVerify) => :can_verify,
|
88
|
+
CF::Base.typecast(Sec::kSecAttrCanWrap) => :can_wrap,
|
89
|
+
CF::Base.typecast(Sec::kSecAttrCanUnwrap) => :can_unwrap}
|
90
|
+
|
91
|
+
ATTR_MAP[CF::Base.typecast(Sec::kSecAttrAccessible)] = :accessible if defined?(Sec::kSecAttrAccessible)
|
92
|
+
ATTR_MAP[CF::Base.typecast(Sec::kSecAttrAccessControl)] = :access_control if defined?(Sec::kSecAttrAccessControl)
|
93
|
+
|
94
|
+
INVERSE_ATTR_MAP = ATTR_MAP.invert
|
95
|
+
define_attributes(ATTR_MAP)
|
96
|
+
|
97
|
+
def klass
|
98
|
+
Sec::Classes::KEY.to_ruby
|
99
|
+
end
|
100
|
+
|
101
|
+
def export(passphrase = nil, format = :kSecFormatUnknown)
|
102
|
+
flags = Sec::SecItemImportExportKeyParameters.new
|
103
|
+
flags[:version] = Sec::SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION
|
104
|
+
flags[:passphrase] = CF::String.from_string(passphrase).to_ptr if passphrase
|
105
|
+
|
106
|
+
data_ptr = FFI::MemoryPointer.new(:pointer)
|
107
|
+
status = Sec.SecItemExport(self, format, :kSecItemPemArmour, flags, data_ptr)
|
108
|
+
Sec.check_osstatus(status)
|
109
|
+
|
110
|
+
data = CF::Data.new(data_ptr.read_pointer)
|
111
|
+
result = data.to_s
|
112
|
+
data.release
|
113
|
+
result
|
114
|
+
end
|
113
115
|
end
|
114
116
|
end
|
data/lib/keychain/version.rb
CHANGED