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,102 @@
1
+ require 'pkcs11/helper'
2
+
3
+ module PKCS11
4
+ # Each slot corresponds to a physical reader or other device interface.
5
+ # It may contain a token.
6
+ class Slot
7
+ include Helper
8
+
9
+ # @private
10
+ def initialize(pkcs11, slot) # :nodoc:
11
+ @pk, @slot = pkcs11, slot
12
+ end
13
+
14
+ # The slot handle.
15
+ # @return [Integer]
16
+ def to_int
17
+ @slot
18
+ end
19
+ alias to_i to_int
20
+
21
+ # @private
22
+ def inspect # :nodoc:
23
+ "#<#{self.class} #{@slot.inspect}>"
24
+ end
25
+
26
+ # Obtains information about a particular slot in the system.
27
+ # @return [PKCS11::CK_SLOT_INFO]
28
+ def C_GetSlotInfo
29
+ @pk.C_GetSlotInfo(@slot)
30
+ end
31
+ alias info C_GetSlotInfo
32
+
33
+ # Obtains information about a particular token in the system.
34
+ # @return [PKCS11::CK_TOKEN_INFO]
35
+ def C_GetTokenInfo
36
+ @pk.C_GetTokenInfo(@slot)
37
+ end
38
+ alias token_info C_GetTokenInfo
39
+
40
+ # C_GetMechanismList is used to obtain a list of mechanism types supported by a token.
41
+ # @return [Array<PKCS11::CKM_*>]
42
+ def C_GetMechanismList
43
+ @pk.C_GetMechanismList(@slot)
44
+ end
45
+ alias mechanisms C_GetMechanismList
46
+
47
+ # Obtains information about a particular mechanism possibly
48
+ # supported by a token.
49
+ #
50
+ # @param [Integer, Symbol] mechanism
51
+ # @return [CK_MECHANISM_INFO]
52
+ def C_GetMechanismInfo(mechanism)
53
+ @pk.C_GetMechanismInfo(@slot, string_to_handle('CKM_', mechanism))
54
+ end
55
+ alias mechanism_info C_GetMechanismInfo
56
+
57
+ # Initializes a token.
58
+ # @param [String] pin is the SO's initial PIN
59
+ # @param [String] label is the label of the token (max 32-byte).
60
+ #
61
+ # The standard allows PIN
62
+ # values to contain any valid UTF8 character, but the token may impose subset restrictions.
63
+ # @return [PKCS11::Slot]
64
+ def C_InitToken(pin, label)
65
+ @pk.C_InitToken(@slot, pin, label.ljust(32, " "))
66
+ self
67
+ end
68
+ alias init_token C_InitToken
69
+
70
+ # Opens a Session between an application and a token in a particular slot.
71
+ #
72
+ # @param [Integer] flags indicates the type of session. Default is read-only,
73
+ # use <tt>CKF_SERIAL_SESSION | CKF_RW_SESSION</tt> for read-write session.
74
+ #
75
+ # * If called with block, yields the block with the session and closes the session
76
+ # when the is finished.
77
+ # * If called without block, returns the session object.
78
+ # @return [PKCS11::Session]
79
+ def C_OpenSession(flags=CKF_SERIAL_SESSION)
80
+ nr = @pk.C_OpenSession(@slot, flags)
81
+ sess = Session.new @pk, nr
82
+ if block_given?
83
+ begin
84
+ yield sess
85
+ ensure
86
+ sess.close
87
+ end
88
+ else
89
+ sess
90
+ end
91
+ end
92
+ alias open C_OpenSession
93
+
94
+ # Closes all sessions an application has with a token.
95
+ # @return [PKCS11::Slot]
96
+ def C_CloseAllSessions
97
+ @pk.C_CloseAllSessions(@slot)
98
+ self
99
+ end
100
+ alias close_all_sessions C_CloseAllSessions
101
+ end
102
+ end
@@ -0,0 +1,14 @@
1
+ .gemtest
2
+ .yardopts
3
+ Manifest.txt
4
+ README_PROTECT_SERVER.rdoc
5
+ Rakefile
6
+ ext/extconf.rb
7
+ ext/generate_constants.rb
8
+ ext/generate_structs.rb
9
+ ext/pk11s.c
10
+ lib/pkcs11_protect_server.rb
11
+ lib/pkcs11_protect_server/extensions.rb
12
+ test/helper.rb
13
+ test/test_pkcs11_protect_server.rb
14
+ test/test_pkcs11_protect_server_crypt.rb
@@ -0,0 +1,89 @@
1
+ = PKCS #11/Ruby Interface for Safenet Protect Server HSM
2
+
3
+ * Homepage: http://github.com/larskanis/pkcs11
4
+ * API documentation: http://pkcs11.rubyforge.org/pkcs11/
5
+ * Safenet[http://www.safenet-inc.com] - Protect Server HSM
6
+
7
+ This ruby gem is an add-on to ruby-pkcs11[http://github.com/larskanis/pkcs11] .
8
+ It allowes to use Protect Server specific extensions, which are beyond the PKCS#11 standard.
9
+ That means CKA_EXPORT, CKM_DES3_DERIVE_CBC, structs like CK_DES3_CBC_PARAMS, special functions and so on.
10
+ The module works on the Unix like operating systems and win32.
11
+
12
+ == Requirements
13
+
14
+ * ProtectServer PTKC-SDK to compile the module
15
+ * pkcs11 gem installed (use: <tt>gem install pkcs11</tt> )
16
+
17
+ == Installation
18
+
19
+ gem install pkcs11_protect_server -- --with-protect-server-sdk-dir=/path/to/ETcpsdk
20
+
21
+ This installs the ProtectServer-PKCS#11 extension along with pkcs11-gem either by compiling (Unix)
22
+ or by using the precompiled gem for Win32.
23
+
24
+ git clone git://github.com/larskanis/pkcs11.git
25
+ cd pkcs11_protect_server
26
+ rake gem PROTECT_SERVER_SDK_DIR=/path/to/ETcpsdk
27
+ gem install -l pkg/pkcs11_protect_server -- --with-protect-server-sdk-dir=/path/to/ETcpsdk
28
+
29
+ Downloads and installs the gem from git source.
30
+
31
+ == Usage
32
+
33
+ Open the software emulation library and login to a session:
34
+
35
+ require "rubygems"
36
+ require "pkcs11_protect_server"
37
+
38
+ pkcs11 = PKCS11::ProtectServer::Library.new(:sw)
39
+ p pkcs11.info
40
+ session = pkcs11.active_slots.last.open
41
+ session.login(:USER, "1234")
42
+ # ... crypto operations
43
+ session.logout
44
+ session.close
45
+
46
+ {PKCS11::ProtectServer::Library#initialize} tries to find the library file in
47
+ the standard installation directory on Windows or Linux.
48
+
49
+ == Cross compiling for mswin32
50
+
51
+ Using rake-compiler a cross compiled pkcs11_protect_server.gem can be build on a linux host for
52
+ the win32 platform. There are no runtime dependencies to any but the standard Windows DLLs.
53
+
54
+ Install mingw32. On a debian based system this should work:
55
+
56
+ apt-get install mingw32
57
+
58
+ On MacOS X, if you have MacPorts installed:
59
+
60
+ port install i386-mingw32-gcc
61
+
62
+ Install the rake-compiler:
63
+
64
+ gem install rake-compiler
65
+
66
+ Download and cross compile ruby for win32:
67
+
68
+ rake-compiler cross-ruby VERSION=1.8.7-p352
69
+ rake-compiler cross-ruby VERSION=1.9.2-p290
70
+
71
+ Download and cross compile pkcs11_protect_server for win32:
72
+
73
+ rake cross native gem PROTECT_SERVER_SDK_DIR=/path/to/ETcpsdk
74
+
75
+ If everything works, there should be pkcs11_protect_server-VERSION-x86-mswin32.gem in the pkg
76
+ directory.
77
+
78
+
79
+ == ToDo
80
+
81
+ * implement ProtectServer specific function calls
82
+ * implement possibility to use callbacks
83
+ * add all structs and constants
84
+
85
+ == Authors
86
+ * Lars Kanis <kanis@comcard.de>
87
+
88
+ == Copying
89
+ See MIT-LICENSE included in the package.
@@ -0,0 +1,58 @@
1
+ require "pkcs11"
2
+
3
+ def find_softokn
4
+ if RUBY_PLATFORM =~ /mswin|mingw/
5
+ lLIBSOFTOKEN3_SO = "softokn3.dll"
6
+
7
+ # Try to find the firefox path.
8
+ unless so_path = ENV['SOFTOKN_PATH']
9
+ require 'win32/registry'
10
+ begin
11
+ firefox_path = Win32::Registry::HKEY_LOCAL_MACHINE.open('SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\firefox.exe'){|reg|
12
+ reg.read('Path')[1]
13
+ }
14
+ rescue Win32::Registry::Error
15
+ end
16
+ if firefox_path
17
+ ENV['Path'] = ENV['Path'] + ";" + firefox_path
18
+ so_path = File.join(firefox_path, lLIBSOFTOKEN3_SO)
19
+ end
20
+ end
21
+ else
22
+ lLIBSOFTOKEN3_SO = "libsoftokn3.so"
23
+ lLIBNSS_PATHS = %w(
24
+ /usr/lib64
25
+ /usr/lib
26
+ /usr/lib64/nss
27
+ /usr/lib/nss
28
+ /usr/lib/i386-linux-gnu/nss
29
+ /usr/lib/x86_64-linux-gnu/nss
30
+ )
31
+ unless so_path = ENV['SOFTOKN_PATH']
32
+ paths = lLIBNSS_PATHS.collect{|path| File.join(path, lLIBSOFTOKEN3_SO) }
33
+ so_path = paths.find do |path|
34
+ File.exist?(path) && open_softokn(path).close rescue false
35
+ end
36
+ end
37
+ end
38
+
39
+ raise "#{lLIBSOFTOKEN3_SO} not found - please install firefox or libnss3 or set ENV['SOFTOKN_PATH']" unless so_path
40
+ so_path
41
+ end
42
+
43
+ def softokn_params
44
+ dir = File.join(File.dirname(__FILE__), 'fixtures/softokn')
45
+ [
46
+ "configDir='#{dir}'",
47
+ "secmod='secmod.db'",
48
+ "flags='readWrite'",
49
+ ]
50
+ end
51
+
52
+ def softokn_params_string
53
+ softokn_params.join(" ")
54
+ end
55
+
56
+ def open_softokn(so_path=nil)
57
+ PKCS11.open(so_path || find_softokn, :flags=>0, :pReserved=>softokn_params_string)
58
+ end
@@ -0,0 +1,71 @@
1
+ require "test/unit"
2
+ require "pkcs11"
3
+ require "test/helper"
4
+
5
+ class TestPkcs11 < Test::Unit::TestCase
6
+ attr_reader :pk
7
+
8
+ def open
9
+ @pk = open_softokn
10
+ end
11
+
12
+ def close
13
+ @pk.close
14
+ @pk = nil
15
+ GC.start
16
+ end
17
+
18
+ def test_info
19
+ open
20
+ info = pk.info
21
+ assert info.inspect =~ /cryptokiVersion=/, 'There should be a version in the library info'
22
+ close
23
+ end
24
+
25
+ def test_slots
26
+ open
27
+ slots = pk.active_slots
28
+ assert slots.length>=1, 'Hope there is at least one active slot'
29
+ close
30
+ end
31
+
32
+ def test_close
33
+ open
34
+ pk.close
35
+ pk.unload_library
36
+ assert_raise(PKCS11::Error){ pk.info }
37
+
38
+ @pk = PKCS11.open
39
+ pk.load_library(find_softokn)
40
+
41
+ pk.C_GetFunctionList
42
+
43
+ pargs = PKCS11::CK_C_INITIALIZE_ARGS.new
44
+ pargs.flags = 0
45
+ pargs.pReserved = softokn_params.join(" ")
46
+ pk.C_Initialize(pargs)
47
+
48
+ pk.info
49
+ close
50
+ end
51
+
52
+ def test_C_Initialize_with_Hash
53
+ pk = PKCS11.open
54
+ pk.load_library(find_softokn)
55
+ pk.C_GetFunctionList
56
+ pk.C_Initialize(:flags=>0, :pReserved=>softokn_params_string)
57
+ pk.info
58
+ pk.close
59
+ end
60
+
61
+ def test_wait_for_slot_event
62
+ open
63
+ # Softokn's C_WaitForSlotEvent() currently raises PKCS11::CKR_FUNCTION_NOT_SUPPORTED.
64
+ # So just check, that the call goes to softokn at all.
65
+ begin
66
+ pk.wait_for_slot_event
67
+ rescue PKCS11::Error
68
+ end
69
+ close
70
+ end
71
+ end
@@ -0,0 +1,220 @@
1
+ require "test/unit"
2
+ require "pkcs11"
3
+ require "test/helper"
4
+ require "openssl"
5
+
6
+ class TestPkcs11Crypt < Test::Unit::TestCase
7
+ include PKCS11
8
+
9
+ attr_reader :slots
10
+ attr_reader :slot
11
+ attr_reader :session
12
+ attr_reader :rsa_priv_key
13
+ attr_reader :rsa_pub_key
14
+ attr_reader :secret_key
15
+
16
+ def setup
17
+ $pkcs11 ||= open_softokn
18
+ @slots = pk.active_slots
19
+ @slot = slots.last
20
+ @session = slot.open
21
+ # session.login(:USER, "")
22
+
23
+ @rsa_pub_key = session.find_objects(:CLASS => CKO_PUBLIC_KEY,
24
+ :KEY_TYPE => CKK_RSA).first
25
+ @rsa_priv_key = session.find_objects(:CLASS => CKO_PRIVATE_KEY,
26
+ :KEY_TYPE => CKK_RSA).first
27
+ @secret_key = session.create_object(
28
+ :CLASS=>CKO_SECRET_KEY,
29
+ :KEY_TYPE=>CKK_DES2,
30
+ :ENCRYPT=>true, :WRAP=>true, :DECRYPT=>true, :UNWRAP=>true, :TOKEN=>false,
31
+ :VALUE=>'0123456789abcdef',
32
+ :LABEL=>'test_secret_key')
33
+ end
34
+
35
+ def teardown
36
+ @secret_key.destroy
37
+ # @session.logout
38
+ @session.close
39
+ end
40
+
41
+ def pk
42
+ $pkcs11
43
+ end
44
+
45
+ def test_endecrypt_rsa
46
+ plaintext1 = "secret text"
47
+ cryptogram = session.encrypt( :RSA_PKCS, rsa_pub_key, plaintext1)
48
+ assert cryptogram.length>10, 'The cryptogram should contain some data'
49
+ assert_not_equal cryptogram, plaintext1, 'The cryptogram should be different to plaintext'
50
+
51
+ plaintext2 = session.decrypt( :RSA_PKCS, rsa_priv_key, cryptogram)
52
+ assert_equal plaintext1, plaintext2, 'Decrypted plaintext should be the same'
53
+ end
54
+
55
+ def test_endecrypt_des
56
+ plaintext1 = "secret message "
57
+ cryptogram = session.encrypt( {:DES3_CBC_PAD=>"\0"*8}, secret_key, plaintext1)
58
+ assert_equal 16, cryptogram.length, 'The cryptogram should contain some data'
59
+ assert_not_equal cryptogram, plaintext1, 'The cryptogram should be different to plaintext'
60
+
61
+ cryptogram2 = ''
62
+ cryptogram2 << session.encrypt( {:DES3_CBC_PAD=>"\0"*8}, secret_key ) do |cipher|
63
+ cryptogram2 << cipher.update(plaintext1[0, 8])
64
+ cryptogram2 << cipher.update(plaintext1[8..-1])
65
+ end
66
+ assert_equal cryptogram, cryptogram2, "Encrypt with and w/o block should be lead to the same result"
67
+
68
+ plaintext2 = session.decrypt( {:DES3_CBC_PAD=>"\0"*8}, secret_key, cryptogram)
69
+ assert_equal plaintext1, plaintext2, 'Decrypted plaintext should be the same'
70
+ end
71
+
72
+ def test_sign_verify
73
+ plaintext = "important text"
74
+ signature = session.sign( :SHA1_RSA_PKCS, rsa_priv_key, plaintext)
75
+ assert signature.length>10, 'The signature should contain some data'
76
+
77
+ signature2 = session.sign( :SHA1_RSA_PKCS, rsa_priv_key){|c|
78
+ c.update(plaintext[0..3])
79
+ c.update(plaintext[4..-1])
80
+ }
81
+ assert_equal signature, signature2, 'results of one-step and two-step signatures should be equal'
82
+
83
+ valid = session.verify( :SHA1_RSA_PKCS, rsa_pub_key, signature, plaintext)
84
+ assert valid, 'The signature should be correct'
85
+
86
+ assert_raise(CKR_SIGNATURE_INVALID, 'The signature should be invalid on different text') do
87
+ session.verify( :SHA1_RSA_PKCS, rsa_pub_key, signature, "modified text")
88
+ end
89
+ end
90
+
91
+ def create_openssl_cipher(pk11_key)
92
+ rsa = OpenSSL::PKey::RSA.new
93
+ rsa.n = OpenSSL::BN.new pk11_key[:MODULUS], 2
94
+ rsa.e = OpenSSL::BN.new pk11_key[:PUBLIC_EXPONENT], 2
95
+ rsa
96
+ end
97
+
98
+ def test_compare_sign_with_openssl
99
+ signature = session.sign( :SHA1_RSA_PKCS, rsa_priv_key, "important text")
100
+
101
+ osslc = create_openssl_cipher rsa_pub_key
102
+ valid = osslc.verify(OpenSSL::Digest::SHA1.new, signature, "important text")
103
+ assert valid, 'The signature should be correct'
104
+ end
105
+
106
+ def test_compare_endecrypt_with_openssl
107
+ plaintext1 = "secret text"
108
+ osslc = create_openssl_cipher rsa_pub_key
109
+ cryptogram = osslc.public_encrypt(plaintext1)
110
+
111
+ plaintext2 = session.decrypt( :RSA_PKCS, rsa_priv_key, cryptogram)
112
+ assert_equal plaintext1, plaintext2, 'Decrypted plaintext should be the same'
113
+ end
114
+
115
+ def test_digest
116
+ plaintext = "secret text"
117
+ digest1 = session.digest( :SHA_1, plaintext)
118
+ digest2 = OpenSSL::Digest::SHA1.new(plaintext).digest
119
+ assert_equal digest1, digest2, 'Digests should be equal'
120
+ digest3 = session.digest(:SHA_1){|c|
121
+ c.update(plaintext[0..3])
122
+ c.update(plaintext[4..-1])
123
+ }
124
+ assert_equal digest1, digest3, 'Digests should be equal'
125
+
126
+ digest3 = session.digest(:SHA256){|c|
127
+ c.update(plaintext)
128
+ c.digest_key(secret_key)
129
+ }
130
+ end
131
+
132
+ def test_wrap_key
133
+ wrapped_key_value = session.wrap_key(:DES3_ECB, secret_key, secret_key)
134
+ assert_equal 16, wrapped_key_value.length, '112 bit 3DES key should have same size wrapped'
135
+
136
+ unwrapped_key = session.unwrap_key(:DES3_ECB, secret_key, wrapped_key_value, :CLASS=>CKO_SECRET_KEY, :KEY_TYPE=>CKK_DES2, :ENCRYPT=>true, :DECRYPT=>true)
137
+
138
+ secret_key_kcv = session.encrypt( :DES3_ECB, secret_key, "\0"*8)
139
+ unwrapped_key_kcv = session.encrypt( :DES3_ECB, unwrapped_key, "\0"*8)
140
+ assert_equal secret_key_kcv, unwrapped_key_kcv, 'Key check values of original and wrapped/unwrapped key should be equal'
141
+ end
142
+
143
+ def test_wrap_private_key
144
+ wrapped_key_value = session.wrap_key({:DES3_CBC_PAD=>"\0"*8}, secret_key, rsa_priv_key)
145
+ assert wrapped_key_value.length>100, 'RSA private key should have bigger size wrapped'
146
+ end
147
+
148
+ def test_generate_secret_key
149
+ key = session.generate_key(:DES2_KEY_GEN,
150
+ {:ENCRYPT=>true, :WRAP=>true, :DECRYPT=>true, :UNWRAP=>true, :TOKEN=>false, :LOCAL=>true})
151
+ assert_equal true, key[:LOCAL], 'Keys created on the token should be marked as local'
152
+ assert_equal CKK_DES2, key[:KEY_TYPE], 'Should be a 2 key 3des key'
153
+
154
+ # other ways to use mechanisms
155
+ key = session.generate_key(CKM_DES2_KEY_GEN,
156
+ {:ENCRYPT=>true, :WRAP=>true, :DECRYPT=>true, :UNWRAP=>true, :TOKEN=>false, :LOCAL=>true})
157
+ assert_equal CKK_DES2, key[:KEY_TYPE], 'Should be a 2 key 3des key'
158
+ key = session.generate_key(CK_MECHANISM.new(CKM_DES2_KEY_GEN, nil),
159
+ {:ENCRYPT=>true, :WRAP=>true, :DECRYPT=>true, :UNWRAP=>true, :TOKEN=>false, :LOCAL=>true})
160
+ assert_equal CKK_DES2, key[:KEY_TYPE], 'Should be a 2 key 3des key'
161
+ end
162
+
163
+ def test_generate_key_pair
164
+ pub_key, priv_key = session.generate_key_pair(:RSA_PKCS_KEY_PAIR_GEN,
165
+ {:ENCRYPT=>true, :VERIFY=>true, :WRAP=>true, :MODULUS_BITS=>768, :PUBLIC_EXPONENT=>[3].pack("N"), :TOKEN=>false},
166
+ {:PRIVATE=>true, :SUBJECT=>'test', :ID=>[123].pack("n"),
167
+ :SENSITIVE=>true, :DECRYPT=>true, :SIGN=>true, :UNWRAP=>true, :TOKEN=>false, :LOCAL=>true})
168
+
169
+ assert_equal true, priv_key[:LOCAL], 'Private keys created on the token should be marked as local'
170
+ assert_equal priv_key[:CLASS], CKO_PRIVATE_KEY
171
+ assert_equal pub_key[:CLASS], CKO_PUBLIC_KEY
172
+ assert_equal true, priv_key[:SENSITIVE], 'Private key should be sensitive'
173
+ end
174
+
175
+ def test_derive_key
176
+ # Generate DH key for side 1
177
+ key1 = OpenSSL::PKey::DH.new(512)
178
+
179
+ # Generate key side 2 with same prime and base as side 1
180
+ pub_key2, priv_key2 = session.generate_key_pair(:DH_PKCS_KEY_PAIR_GEN,
181
+ {:PRIME=>key1.p.to_s(2), :BASE=>key1.g.to_s(2), :TOKEN=>false},
182
+ {:VALUE_BITS=>512, :DERIVE=>true, :TOKEN=>false})
183
+
184
+ # Derive secret DES key for side 1 with OpenSSL
185
+ new_key1 = key1.compute_key(OpenSSL::BN.new pub_key2[:VALUE], 2)
186
+
187
+ # Derive secret DES key for side 2 with softokn3
188
+ new_key2 = session.derive_key( {:DH_PKCS_DERIVE=>key1.pub_key.to_s(2)}, priv_key2,
189
+ :CLASS=>CKO_SECRET_KEY, :KEY_TYPE=>CKK_AES, :VALUE_LEN=>16, :ENCRYPT=>true, :DECRYPT=>true, :SENSITIVE=>false )
190
+
191
+ # Some versions of softokn3 use left- and some use rightmost bits of exchanged key
192
+ assert_operator [new_key1[0,16], new_key1[-16..-1]], :include?, new_key2[:VALUE], 'Exchanged session key should be equal'
193
+ end
194
+
195
+ def test_derive_key2
196
+ deriv_data = "\0"*16
197
+ new_key1 = session.derive_key( {CKM_XOR_BASE_AND_DATA => {:pData => deriv_data}}, secret_key,
198
+ :CLASS=>CKO_SECRET_KEY, :KEY_TYPE=>CKK_AES, :VALUE_LEN=>16, :ENCRYPT=>true, :DECRYPT=>true, :SENSITIVE=>false )
199
+
200
+ assert_equal secret_key[:VALUE], new_key1[:VALUE], 'Derived key should have equal key value'
201
+ end
202
+
203
+ def test_ssl3
204
+ pm_key = session.generate_key({:SSL3_PRE_MASTER_KEY_GEN => {:major=>3, :minor=>0}},
205
+ {:TOKEN=>false})
206
+ assert_equal 48, pm_key[:VALUE_LEN], "SSL3 pre master key should be 48 bytes long"
207
+
208
+ dp = CK_SSL3_MASTER_KEY_DERIVE_PARAMS.new
209
+ dp.RandomInfo.pServerRandom = 'srandom ' * 4
210
+ dp.RandomInfo.pClientRandom = 'crandom ' * 4
211
+ dp.pVersion = CK_VERSION.new
212
+ dp.pVersion.major = 3
213
+ dp.pVersion.minor = 1
214
+ ms_key = session.derive_key( {CKM_SSL3_MASTER_KEY_DERIVE => dp}, pm_key )
215
+
216
+ assert_equal 48, ms_key[:VALUE_LEN], "SSL3 master secret key should be 48 bytes long"
217
+ assert_equal 0, dp.pVersion.minor, 'SSL3 version number should have changed'
218
+ end
219
+
220
+ end