pkcs11 0.2.4-x64-mingw32

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.
Files changed (55) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.autotest +23 -0
  3. data/.gemtest +0 -0
  4. data/.yardopts +1 -0
  5. data/History.txt +57 -0
  6. data/MIT-LICENSE +22 -0
  7. data/Manifest.txt +57 -0
  8. data/README.rdoc +205 -0
  9. data/Rakefile +111 -0
  10. data/ext/extconf.rb +7 -0
  11. data/ext/generate_constants.rb +57 -0
  12. data/ext/generate_structs.rb +206 -0
  13. data/ext/generate_thread_funcs.rb +72 -0
  14. data/ext/include/cryptoki.h +66 -0
  15. data/ext/include/ct-kip.h +50 -0
  16. data/ext/include/otp-pkcs11.h +125 -0
  17. data/ext/include/pkcs-11v2-20a3.h +124 -0
  18. data/ext/include/pkcs11.h +299 -0
  19. data/ext/include/pkcs11f.h +912 -0
  20. data/ext/include/pkcs11t.h +1885 -0
  21. data/ext/pk11.c +1675 -0
  22. data/ext/pk11.h +81 -0
  23. data/ext/pk11_const.c +205 -0
  24. data/ext/pk11_const_def.inc +452 -0
  25. data/ext/pk11_const_macros.h +38 -0
  26. data/ext/pk11_struct.doc +792 -0
  27. data/ext/pk11_struct_def.inc +302 -0
  28. data/ext/pk11_struct_impl.inc +302 -0
  29. data/ext/pk11_struct_macros.h +435 -0
  30. data/ext/pk11_thread_funcs.c +411 -0
  31. data/ext/pk11_thread_funcs.h +482 -0
  32. data/ext/pk11_version.h +6 -0
  33. data/lib/2.0/pkcs11_ext.so +0 -0
  34. data/lib/pkcs11.rb +9 -0
  35. data/lib/pkcs11/extensions.rb +68 -0
  36. data/lib/pkcs11/helper.rb +144 -0
  37. data/lib/pkcs11/library.rb +140 -0
  38. data/lib/pkcs11/object.rb +171 -0
  39. data/lib/pkcs11/session.rb +765 -0
  40. data/lib/pkcs11/slot.rb +102 -0
  41. data/pkcs11_protect_server/Manifest.txt +14 -0
  42. data/pkcs11_protect_server/README_PROTECT_SERVER.rdoc +89 -0
  43. data/test/fixtures/softokn/cert8.db +0 -0
  44. data/test/fixtures/softokn/key3.db +0 -0
  45. data/test/fixtures/softokn/secmod.db +0 -0
  46. data/test/helper.rb +58 -0
  47. data/test/test_pkcs11.rb +71 -0
  48. data/test/test_pkcs11_crypt.rb +220 -0
  49. data/test/test_pkcs11_object.rb +122 -0
  50. data/test/test_pkcs11_session.rb +123 -0
  51. data/test/test_pkcs11_slot.rb +78 -0
  52. data/test/test_pkcs11_structs.rb +166 -0
  53. data/test/test_pkcs11_thread.rb +44 -0
  54. metadata +213 -0
  55. metadata.gz.sig +0 -0
@@ -0,0 +1,6 @@
1
+ #ifndef RUBY_PK11_VERSION_H
2
+ #define RUBY_PK11_VERSION_H
3
+
4
+ static const char *VERSION = "0.2.4";
5
+
6
+ #endif
Binary file
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Extend the search path for Windows binary gem, depending of the current ruby version
4
+ major_minor = RUBY_VERSION[ /^(\d+\.\d+)/ ] or
5
+ raise "Oops, can't extract the major/minor version from #{RUBY_VERSION.dump}"
6
+ $: << File.join(File.dirname(__FILE__), major_minor)
7
+
8
+ require 'pkcs11_ext'
9
+ require 'pkcs11/extensions'
@@ -0,0 +1,68 @@
1
+ require 'pkcs11/library'
2
+ require 'pkcs11/slot'
3
+ require 'pkcs11/session'
4
+ require 'pkcs11/object'
5
+
6
+ # Ruby connector to PKCS#11 libraries.
7
+ #
8
+ # This library allowes to use PKCS#11 librarys in Ruby MRI.
9
+ #
10
+ # @example
11
+ # pkcs11 = PKCS11.open("/path/to/pkcs11.so")
12
+ # slot = pkcs11.active_slots.first
13
+ # p slot.info
14
+ # session = slot.open(PKCS11::CKF_SERIAL_SESSION|PKCS11::CKF_RW_SESSION)
15
+ # session.login(:USER, "1234")
16
+ # # ... crypto operations
17
+ # session.logout
18
+ # session.close
19
+ #
20
+ # See unit tests in the <tt>test</tt> directory for further examples of the usage.
21
+ module PKCS11
22
+
23
+ class << self
24
+ # Open a PKCS#11 library file.
25
+ alias new open
26
+ end
27
+
28
+ # Base class of all PKCS#11 structs.
29
+ class CStruct
30
+ # @return [Array<String>] attribute names
31
+ def values
32
+ members.inject([]){|a,v| a << send(v) }
33
+ end
34
+ # @return [Hash] with attribute names and current values
35
+ def to_hash
36
+ members.inject({}){|h,v| h[v.intern] = send(v); h }
37
+ end
38
+ def inspect
39
+ "#<#{self.class} #{to_hash.map{|k,v| "#{k}=#{v.inspect}"}.join(", ") }>"
40
+ end
41
+ end
42
+
43
+ # Struct to hold an attribute type and it's value.
44
+ #
45
+ # @see PKCS11::Object
46
+ class CK_ATTRIBUTE
47
+ # @return [Array<String>] attribute names
48
+ def members
49
+ ['type', 'value']
50
+ end
51
+ # @return [Array<String, Boolean, Integer>] attribute values
52
+ def values
53
+ members.inject([]){|a,v| a << send(v) }
54
+ end
55
+ # @return [Hash] with attribute names and current values
56
+ def to_hash
57
+ members.inject({}){|h,v| h[v.intern] = send(v); h }
58
+ end
59
+ # Get the constant name as String of the given value.
60
+ # @return [String, nil] Returns <tt>nil</tt> if value is unknown
61
+ def to_s
62
+ ATTRIBUTES[type]
63
+ end
64
+ def inspect
65
+ "#<#{self.class} #{ to_s ? "#{to_s} (#{type})" : type} value=#{value.inspect}>"
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,144 @@
1
+ module PKCS11
2
+ # Some functions internaly used to make the API more convenient.
3
+ # @private
4
+ module Helper # :nodoc:
5
+ private
6
+
7
+ MechanismParameters = {
8
+ CKM_RSA_PKCS_OAEP => CK_RSA_PKCS_OAEP_PARAMS,
9
+ CKM_RSA_PKCS_PSS => CK_RSA_PKCS_PSS_PARAMS,
10
+ CKM_SHA1_RSA_PKCS_PSS => CK_RSA_PKCS_PSS_PARAMS,
11
+ CKM_SHA256_RSA_PKCS_PSS => CK_RSA_PKCS_PSS_PARAMS,
12
+ CKM_SHA384_RSA_PKCS_PSS => CK_RSA_PKCS_PSS_PARAMS,
13
+ CKM_SHA512_RSA_PKCS_PSS => CK_RSA_PKCS_PSS_PARAMS,
14
+ CKM_ECDH1_DERIVE => CK_ECDH1_DERIVE_PARAMS,
15
+ CKM_ECDH1_COFACTOR_DERIVE => CK_ECDH1_DERIVE_PARAMS,
16
+ CKM_ECMQV_DERIVE => CK_ECMQV_DERIVE_PARAMS,
17
+ CKM_X9_42_DH_DERIVE => CK_X9_42_DH1_DERIVE_PARAMS,
18
+ # CKM_X9_42_MQV_DERIVE => CK_X9_42_DH2_DERIVE_PARAMS,
19
+ CKM_X9_42_DH_HYBRID_DERIVE => CK_X9_42_DH2_DERIVE_PARAMS,
20
+ CKM_X9_42_MQV_DERIVE => CK_X9_42_MQV_DERIVE_PARAMS,
21
+ CKM_KEA_KEY_DERIVE => CK_KEA_DERIVE_PARAMS,
22
+ CKM_RC2_CBC => CK_RC2_CBC_PARAMS,
23
+ CKM_RC2_CBC_PAD => CK_RC2_CBC_PARAMS,
24
+ CKM_RC2_MAC_GENERAL => CK_RC2_MAC_GENERAL_PARAMS,
25
+ CKM_RC5_MAC => CK_RC5_PARAMS,
26
+ CKM_RC5_ECB => CK_RC5_PARAMS,
27
+ CKM_RC5_CBC => CK_RC5_CBC_PARAMS,
28
+ CKM_RC5_CBC_PAD => CK_RC5_CBC_PARAMS,
29
+ CKM_RC5_MAC_GENERAL => CK_RC5_MAC_GENERAL_PARAMS,
30
+
31
+ CKM_SKIPJACK_PRIVATE_WRAP => CK_SKIPJACK_PRIVATE_WRAP_PARAMS,
32
+ CKM_SKIPJACK_RELAYX => CK_SKIPJACK_RELAYX_PARAMS,
33
+ CKM_PBE_MD2_DES_CBC => CK_PBE_PARAMS,
34
+ CKM_PBE_MD5_DES_CBC => CK_PBE_PARAMS,
35
+ CKM_PBE_MD5_CAST_CBC => CK_PBE_PARAMS,
36
+ CKM_PBE_MD5_CAST3_CBC => CK_PBE_PARAMS,
37
+ CKM_PBE_MD5_CAST5_CBC => CK_PBE_PARAMS,
38
+ CKM_PBE_MD5_CAST128_CBC => CK_PBE_PARAMS,
39
+ CKM_PBE_SHA1_CAST5_CBC => CK_PBE_PARAMS,
40
+ CKM_PBE_SHA1_CAST128_CBC => CK_PBE_PARAMS,
41
+ CKM_PBE_SHA1_RC4_128 => CK_PBE_PARAMS,
42
+ CKM_PBE_SHA1_RC4_40 => CK_PBE_PARAMS,
43
+ CKM_PBE_SHA1_DES3_EDE_CBC => CK_PBE_PARAMS,
44
+ CKM_PBE_SHA1_DES2_EDE_CBC => CK_PBE_PARAMS,
45
+ CKM_PBE_SHA1_RC2_128_CBC => CK_PBE_PARAMS,
46
+ CKM_PBE_SHA1_RC2_40_CBC => CK_PBE_PARAMS,
47
+ CKM_PBA_SHA1_WITH_SHA1_HMAC => CK_PBE_PARAMS,
48
+ CKM_PKCS5_PBKD2 => CK_PKCS5_PBKD2_PARAMS,
49
+ CKM_KEY_WRAP_SET_OAEP => CK_KEY_WRAP_SET_OAEP_PARAMS,
50
+ CKM_SSL3_MASTER_KEY_DERIVE => CK_SSL3_RANDOM_DATA,
51
+ CKM_SSL3_KEY_AND_MAC_DERIVE => CK_SSL3_RANDOM_DATA,
52
+ CKM_SSL3_MASTER_KEY_DERIVE => CK_SSL3_MASTER_KEY_DERIVE_PARAMS,
53
+ CKM_SSL3_KEY_AND_MAC_DERIVE => CK_SSL3_KEY_MAT_OUT,
54
+ CKM_SSL3_KEY_AND_MAC_DERIVE => CK_SSL3_KEY_MAT_PARAMS,
55
+ CKM_TLS_MASTER_KEY_DERIVE => CK_SSL3_MASTER_KEY_DERIVE_PARAMS,
56
+ CKM_TLS_PRF => CK_TLS_PRF_PARAMS,
57
+ CKM_WTLS_MASTER_KEY_DERIVE => CK_WTLS_RANDOM_DATA,
58
+ CKM_WTLS_MASTER_KEY_DERIVE => CK_WTLS_MASTER_KEY_DERIVE_PARAMS,
59
+ CKM_WTLS_PRF => CK_WTLS_PRF_PARAMS,
60
+ CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE => CK_WTLS_KEY_MAT_PARAMS,
61
+ CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE => CK_WTLS_KEY_MAT_PARAMS,
62
+ CKM_CMS_SIG => CK_CMS_SIG_PARAMS,
63
+
64
+ CKM_DES_ECB_ENCRYPT_DATA => CK_KEY_DERIVATION_STRING_DATA,
65
+ CKM_DES_CBC_ENCRYPT_DATA => CK_DES_CBC_ENCRYPT_DATA_PARAMS,
66
+ CKM_DES3_ECB_ENCRYPT_DATA => CK_KEY_DERIVATION_STRING_DATA,
67
+ CKM_DES3_CBC_ENCRYPT_DATA => CK_DES_CBC_ENCRYPT_DATA_PARAMS,
68
+ CKM_AES_ECB_ENCRYPT_DATA => CK_KEY_DERIVATION_STRING_DATA,
69
+ CKM_AES_CBC_ENCRYPT_DATA => CK_AES_CBC_ENCRYPT_DATA_PARAMS,
70
+ CKM_CONCATENATE_BASE_AND_DATA => CK_KEY_DERIVATION_STRING_DATA,
71
+ CKM_CONCATENATE_DATA_AND_BASE => CK_KEY_DERIVATION_STRING_DATA,
72
+ CKM_XOR_BASE_AND_DATA => CK_KEY_DERIVATION_STRING_DATA,
73
+
74
+ CKM_ARIA_ECB_ENCRYPT_DATA => CK_KEY_DERIVATION_STRING_DATA,
75
+ CKM_ARIA_CBC_ENCRYPT_DATA => CK_ARIA_CBC_ENCRYPT_DATA_PARAMS,
76
+
77
+ CKM_SSL3_PRE_MASTER_KEY_GEN => CK_VERSION,
78
+ CKM_TLS_PRE_MASTER_KEY_GEN => CK_VERSION,
79
+ =begin
80
+ # for PKCS#11 v2.30
81
+ CKM_SEED_ECB_ENCRYPT_DATA => CK_KEY_DERIVATION_STRING_DATA,
82
+ CKM_SEED_CBC_ENCRYPT_DATA => CK_CBC_ENCRYPT_DATA_PARAMS,
83
+ CKM_GOSTR3410_KEY_WRAP => CK_GOSTR3410_KEY_WRAP_PARAMS,
84
+ CKM_GOSTR3410_DERIVE => CK_GOSTR3410_DERIVE_PARAMS,
85
+ CKM_GOSTR3410_KEY_WRAP => CK_GOSTR3410_KEY_WRAP_PARAMS,
86
+ =end
87
+ }
88
+
89
+ def to_attributes(template)
90
+ case template
91
+ when Array
92
+ template.map{|v| @pk.vendor_class_CK_ATTRIBUTE.new(string_to_handle('CKA_', v), nil) }
93
+ when Hash
94
+ template.map{|k,v| @pk.vendor_class_CK_ATTRIBUTE.new(string_to_handle('CKA_', k), v) }
95
+ when String, Symbol
96
+ [@pk.vendor_class_CK_ATTRIBUTE.new(string_to_handle('CKA_', template), nil)]
97
+ when Integer
98
+ [@pk.vendor_class_CK_ATTRIBUTE.new(template, nil)]
99
+ else
100
+ template
101
+ end
102
+ end
103
+
104
+ def string_to_handle(prefix, attribute) # :nodoc:
105
+ case attribute
106
+ when String, Symbol
107
+ @pk.vendor_const_get("#{prefix}#{attribute}")
108
+ else
109
+ attribute
110
+ end
111
+ end
112
+
113
+ def to_mechanism(mechanism) # :nodoc:
114
+ case mechanism
115
+ when String, Symbol
116
+ PKCS11::CK_MECHANISM.new(string_to_handle('CKM_', mechanism))
117
+ when Hash
118
+ raise "only one mechanism allowed" unless mechanism.length==1
119
+
120
+ mech = string_to_handle('CKM_', mechanism.keys.first)
121
+ param = mechanism.values.first
122
+ case param
123
+ when Hash
124
+ param_class = @pk.vendor_mechanism_parameter_struct(mech)
125
+ raise ArgumentError, "unknown mechanism - please use String/Int/Struct as mechanism parameter" unless param_class
126
+
127
+ pa = param_class.new
128
+ param.each do |k, v|
129
+ pa.send "#{k}=", v
130
+ end
131
+ param = pa
132
+ end
133
+
134
+ PKCS11::CK_MECHANISM.new(mech, param)
135
+ when Fixnum
136
+ PKCS11::CK_MECHANISM.new(mechanism)
137
+ when Bignum
138
+ PKCS11::CK_MECHANISM.new(mechanism)
139
+ else
140
+ mechanism
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,140 @@
1
+ module PKCS11
2
+ # A Library instance holds a handle to the opened PKCS#11 - dll or so file.
3
+ #
4
+ # == Low layer API
5
+ # The API of the binding consists of a lower layer, which
6
+ # is near to the PKCS#11 C interface, and a higher layer, which
7
+ # is more Ruby like and more comfortable. The low layer is currently
8
+ # not explicitly documented and is not recommented to use.
9
+ #
10
+ # All low layer PKCS#11 functions can be called on the {PKCS11::Library} object.
11
+ # Example for starting a session:
12
+ # pkcs11 = PKCS11.open("/path/to/pkcs11.so")
13
+ # slot = pkcs11.C_GetSlotList(true).first
14
+ # session = pkcs11.C_OpenSession(slot, PKCS11::CKF_SERIAL_SESSION | PKCS11::CKF_RW_SESSION)
15
+ # pkcs11.C_Login(session, PKCS11::CKU_USER, "password")
16
+ #
17
+ # The same on the high layer:
18
+ # pkcs11 = PKCS11.open("/path/to/pkcs11.so")
19
+ # session = pkcs11.active_slots.first.open
20
+ # session.login(:USER, "password")
21
+ class Library
22
+ # @private
23
+ alias unwrapped_initialize initialize # :nodoc:
24
+
25
+ # Load and initialize a pkcs11 dynamic library.
26
+ #
27
+ # @param [String, nil] so_path Path to the *.so or *.dll file to load.
28
+ # @param [Hash, CK_C_INITIALIZE_ARGS] args A Hash or CK_C_INITIALIZE_ARGS instance with load params.
29
+ #
30
+ # If so_path is +nil+ no library is loaded or initialized.
31
+ # In this case the calls to {#load_library}, {#C_GetFunctionList} and
32
+ # {#C_Initialize} have to be done manually, before using other methods:
33
+ # pkcs11 = PKCS11::Library.new
34
+ # pkcs11.load_library(so_path)
35
+ # pkcs11.C_GetFunctionList
36
+ # pkcs11.C_Initialize(args)
37
+ def initialize(so_path=nil, args={})
38
+ unwrapped_initialize(so_path, args)
39
+ end
40
+
41
+ alias unwrapped_C_Initialize C_Initialize
42
+ # Initialize a pkcs11 dynamic library.
43
+ #
44
+ # @param [Hash, CK_C_INITIALIZE_ARGS] args A Hash or CK_C_INITIALIZE_ARGS instance with load params.
45
+ def C_Initialize(args=nil)
46
+ case args
47
+ when Hash
48
+ pargs = CK_C_INITIALIZE_ARGS.new
49
+ args.each{|k,v| pargs.send("#{k}=", v) }
50
+ else
51
+ pargs = args
52
+ end
53
+ unwrapped_C_Initialize(pargs)
54
+ end
55
+
56
+ alias unwrapped_C_GetInfo C_GetInfo
57
+ # Returns general information about Cryptoki.
58
+ # @return [CK_INFO]
59
+ def C_GetInfo
60
+ unwrapped_C_GetInfo
61
+ end
62
+ alias info C_GetInfo
63
+
64
+ alias unwrapped_C_GetSlotList C_GetSlotList
65
+
66
+ # Obtain an array of Slot objects in the system.
67
+ #
68
+ # @param [true, false] tokenPresent indicates whether the list
69
+ # obtained includes only those slots with a token present (true), or
70
+ # all slots (false);
71
+ # @return [Array<Slot>]
72
+ def C_GetSlotList(tokenPresent=false)
73
+ slots = unwrapped_C_GetSlotList(tokenPresent)
74
+ slots.map{|slot|
75
+ Slot.new self, slot
76
+ }
77
+ end
78
+ alias slots C_GetSlotList
79
+
80
+ # Obtain an array of Slot objects in the system with a token present.
81
+ # @return [Array<Slot>]
82
+ def active_slots
83
+ slots(true)
84
+ end
85
+
86
+ # Obtain an array of Slot objects in the system regardless if a token is present.
87
+ # @return [Array<Slot>]
88
+ def all_slots
89
+ slots(false)
90
+ end
91
+
92
+ alias unwrapped_C_WaitForSlotEvent C_WaitForSlotEvent
93
+
94
+ # Waits for a slot event, such as token insertion or token removal, to occur.
95
+ #
96
+ # @param [Integer] flags determines whether or not the C_WaitForSlotEvent call blocks (i.e., waits
97
+ # for a slot event to occur);
98
+ # At present, the only flag defined for use in the flags argument is PKCS11::CKF_DONT_BLOCK
99
+ # @return [Slot, nil] the slot that the event occurred in; nil if no event occured (CKR_NO_EVENT)
100
+ def C_WaitForSlotEvent(flags=0)
101
+ slot = unwrapped_C_WaitForSlotEvent(flags)
102
+ slot ? Slot.new(self, slot) : nil
103
+ end
104
+ alias wait_for_slot_event C_WaitForSlotEvent
105
+
106
+ # Finalize and unload the library. If not called explicit, the library is freed by the GC.
107
+ def close
108
+ self.C_Finalize
109
+ self.unload_library
110
+ end
111
+
112
+ # Return the value of a named constant. Used for CKA_* and CKM_* .
113
+ # This method could be overloaded for vendor specific extensions.
114
+ #
115
+ # @param [String] name Name of the constant
116
+ # @return [Integer] Value of the constant
117
+ def vendor_const_get(name)
118
+ PKCS11.const_get(name)
119
+ end
120
+
121
+ # Return an array of all known CKA_* attributes as String.
122
+ # This method could be overloaded for vendor specific extensions.
123
+ def vendor_all_attribute_names
124
+ return ATTRIBUTES.values
125
+ end
126
+
127
+ # Return the parameter struct of a given mechanism.
128
+ # This method could be overloaded for vendor specific extensions.
129
+ #
130
+ # @param [Integer] mech Mechanism
131
+ # @return [PKCS11::CStruct] appropriate class as parameter for the mechanism
132
+ def vendor_mechanism_parameter_struct(mech)
133
+ Helper::MechanismParameters[mech]
134
+ end
135
+
136
+ private :unwrapped_initialize
137
+ private :unwrapped_C_GetSlotList
138
+ private :unwrapped_C_GetInfo
139
+ end
140
+ end
@@ -0,0 +1,171 @@
1
+ require 'pkcs11/helper'
2
+
3
+ module PKCS11
4
+ # Cryptoki's logical view of a token is a device that stores objects and can perform
5
+ # cryptographic functions. Cryptoki defines three classes of object: data, certificates, and
6
+ # keys.
7
+ #
8
+ # Attributes are characteristics that distinguish an instance of an object.
9
+ class Object
10
+ include Helper
11
+
12
+ # @private
13
+ def initialize(pkcs11, session, object) # :nodoc:
14
+ @pk, @sess, @obj = pkcs11, session, object
15
+ end
16
+
17
+ # The object handle.
18
+ # @return [Integer]
19
+ def to_int
20
+ @obj
21
+ end
22
+ alias to_i to_int
23
+
24
+ # @private
25
+ def inspect # :nodoc:
26
+ "#<#{self.class} #{@obj.inspect}>"
27
+ end
28
+
29
+ # Get the value of one or several attributes of the object.
30
+ #
31
+ # @param [String, Symbol, Integer, Array] attribute can be String or Symbol
32
+ # of the attribute(s) constant or the attribute(s) number as Integer.
33
+ #
34
+ # @return [String, Integer, Boolean, Array, nil] the attribute value as String,
35
+ # Integer or true/false depending on the attribute type.
36
+ # If called with more than one parameter or with an Array, a Array
37
+ # of attribute values is returned.
38
+ # Unknown attributes (out of PKCS#11 v2.2) are not converted to adequate
39
+ # ruby objects but returned as String.
40
+ # That is true/false will be returned as "\\001" respectively "\\000".
41
+ #
42
+ # @example
43
+ # object[:VALUE] # => "\000\000\000\000\000\000\000\000"
44
+ # object[:MODULUS_BITS] # => 768
45
+ # object[:MODULUS_BITS, :LABEL] # => [1024, "MyKey"]
46
+ #
47
+ # See PKCS#11 for attribute definitions.
48
+ def [](*attributes)
49
+ attrs = C_GetAttributeValue( attributes.flatten )
50
+ if attrs.length>1 || attributes.first.kind_of?(Array)
51
+ attrs.map(&:value)
52
+ else
53
+ attrs.first.value unless attrs.empty?
54
+ end
55
+ end
56
+
57
+ # Modifies the value of one or several attributes of the object.
58
+ #
59
+ # @param [String, Symbol, Integer] attribute can be String or Symbol of the attribute constant
60
+ # or the attribute value as Integer.
61
+ # @param [String, Integer, Boolean, Array, nil] value value(s) the attribute(s) will be set to.
62
+ #
63
+ # Following value conversations are done from Ruby to C:
64
+ # true -> 0x01
65
+ # false -> 0x00
66
+ # nil -> NULL pointer
67
+ # Fixnum -> binary encoded unsigned long
68
+ #
69
+ # @example
70
+ # object[:VALUE] = "\000\000\000\000\000\000\000\000"
71
+ # object[:MODULUS_BITS] = 768
72
+ # object[:MODULUS_BITS, :LABEL] = 1024, 'MyKey'
73
+ #
74
+ # See PKCS#11 for attribute definitions.
75
+ # @return value
76
+ def []=(*attributes)
77
+ values = attributes.pop
78
+ values = [values] unless values.kind_of?(Array)
79
+ raise ArgumentError, "different number of attributes to set (#{attributes.length}) and given values (#{values.length})" unless attributes.length == values.length
80
+ map = values.each.with_index.inject({}){|s, v| s[attributes[v[1]]] = v[0]; s }
81
+ C_SetAttributeValue( map )
82
+ end
83
+
84
+ # Modifies the value of one or more attributes of the object in a single call.
85
+ #
86
+ # @example
87
+ # object.attributes = {:SUBJECT => cert_subject, PKCS11::CKA_VALUE => cert_data}
88
+ # @return template
89
+ def C_SetAttributeValue(template={})
90
+ @pk.C_SetAttributeValue(@sess, @obj, to_attributes(template))
91
+ template
92
+ end
93
+ alias attributes= C_SetAttributeValue
94
+
95
+ # Obtains the value of one or more attributes of the object in a single call.
96
+ #
97
+ # @param [Array<String, Symbol, Integer>, Hash, String, Integer] attribute attribute names
98
+ # whose values should be returned
99
+ #
100
+ # Without params all known attributes are tried to read from the Object.
101
+ # This is significant slower then naming the needed attributes and should
102
+ # be used for debug purposes only.
103
+ #
104
+ # @return [Array<PKCS11::CK_ATTRIBUTE>] Requested attributes with values.
105
+ #
106
+ # @example
107
+ # certificate.attributes :VALUE, :CLASS
108
+ # => [#<PKCS11::CK_ATTRIBUTE CKA_VALUE (17) value="0\x82...">, #<PKCS11::CK_ATTRIBUTE CKA_CLASS (0) value=1>]
109
+ def C_GetAttributeValue(*template)
110
+ case template.length
111
+ when 0
112
+ return @pk.vendor_all_attribute_names.map{|attr|
113
+ begin
114
+ attributes(@pk.vendor_const_get(attr))
115
+ rescue PKCS11::Error
116
+ end
117
+ }.flatten.compact
118
+ when 1
119
+ template = template[0]
120
+ end
121
+ template = to_attributes template
122
+ @pk.C_GetAttributeValue(@sess, @obj, template)
123
+ end
124
+ alias attributes C_GetAttributeValue
125
+
126
+ # Copies an object, creating a new object for the copy.
127
+ #
128
+ # @param [Hash] template
129
+ #
130
+ # The template may specify new values for any attributes of the object that can ordinarily
131
+ # be modified (e.g., in the course of copying a secret key, a key's CKA_EXTRACTABLE
132
+ # attribute may be changed from true to false, but not the other way around.
133
+ # If this change is made, the new key's CKA_NEVER_EXTRACTABLE attribute will
134
+ # have the value false. Similarly, the template may specify that the new key's
135
+ # CKA_SENSITIVE attribute be true; the new key will have the same value for its
136
+ # CKA_ALWAYS_SENSITIVE attribute as the original key). It may also specify new
137
+ # values of the CKA_TOKEN and CKA_PRIVATE attributes (e.g., to copy a session
138
+ # object to a token object). If the template specifies a value of an attribute which is
139
+ # incompatible with other existing attributes of the object, the call fails with exception
140
+ # CKR_TEMPLATE_INCONSISTENT.
141
+ #
142
+ # Only session objects can be created during a read-only session. Only public objects can
143
+ # be created unless the normal user is logged in.
144
+ #
145
+ # @return [PKCS11::Object] the newly created object
146
+ def C_CopyObject(template={})
147
+ handle = @pk.C_CopyObject(@sess, @obj, to_attributes(template))
148
+ Object.new @pk, @sess, handle
149
+ end
150
+ alias copy C_CopyObject
151
+
152
+ # Destroys the object.
153
+ #
154
+ # Only session objects can be destroyed during a read-only session. Only public objects
155
+ # can be destroyed unless the normal user is logged in.
156
+ # @return [PKCS11::Object]
157
+ def C_DestroyObject()
158
+ @pk.C_DestroyObject(@sess, @obj)
159
+ self
160
+ end
161
+ alias destroy C_DestroyObject
162
+
163
+ # Gets the size of an object in bytes.
164
+ # @return [Integer]
165
+ def C_GetObjectSize()
166
+ @pk.C_GetObjectSize(@sess, @obj)
167
+ end
168
+ alias size C_GetObjectSize
169
+
170
+ end
171
+ end