pkcs11 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,71 +1,90 @@
1
+ require 'pkcs11/helper'
2
+
1
3
  module PKCS11
2
4
  # Each slot corresponds to a physical reader or other device interface.
3
5
  # It may contain a token.
4
6
  class Slot
7
+ include Helper
8
+
9
+ # @private
5
10
  def initialize(pkcs11, slot) # :nodoc:
6
11
  @pk, @slot = pkcs11, slot
7
12
  end
8
13
 
9
14
  # The slot handle.
15
+ # @return [Integer]
10
16
  def to_int
11
17
  @slot
12
18
  end
13
19
  alias to_i to_int
14
20
 
21
+ # @private
15
22
  def inspect # :nodoc:
16
23
  "#<#{self.class} #{@slot.inspect}>"
17
24
  end
18
25
 
19
26
  # Obtains information about a particular slot in the system.
27
+ # @return [PKCS11::CK_SLOT_INFO]
20
28
  def C_GetSlotInfo
21
29
  @pk.C_GetSlotInfo(@slot)
22
30
  end
23
31
  alias info C_GetSlotInfo
24
32
 
25
33
  # Obtains information about a particular token in the system.
34
+ # @return [PKCS11::CK_TOKEN_INFO]
26
35
  def C_GetTokenInfo
27
36
  @pk.C_GetTokenInfo(@slot)
28
37
  end
29
38
  alias token_info C_GetTokenInfo
30
39
 
31
40
  # Waits for a slot event, such as token insertion or token removal, to
32
- # occur. flags determines whether or not the C_WaitForSlotEvent call blocks (i.e., waits
33
- # for a slot event to occur);
41
+ # occur.
42
+ # @param flags determines whether or not the C_WaitForSlotEvent call blocks (i.e., waits
43
+ # for a slot event to occur);
34
44
  def C_WaitForSlotEvent(flags)
35
45
  @pk.C_WaitForSlotEvent(@slot, flags)
36
46
  end
37
47
  alias wait_for_event C_WaitForSlotEvent
38
48
 
39
49
  # C_GetMechanismList is used to obtain a list of mechanism types supported by a token.
50
+ # @return [Array<PKCS11::CKM_*>]
40
51
  def C_GetMechanismList
41
- @pk.C_GetMechanismList(@slot).map{|mech|
42
- Mechanism.new MECHANISMS, mech
43
- }
52
+ @pk.C_GetMechanismList(@slot)
44
53
  end
45
54
  alias mechanisms C_GetMechanismList
46
55
 
47
56
  # Obtains information about a particular mechanism possibly
48
57
  # supported by a token.
58
+ #
59
+ # @param [Integer, Symbol] mechanism
60
+ # @return [CK_MECHANISM_INFO]
49
61
  def C_GetMechanismInfo(mechanism)
50
- @pk.C_GetMechanismInfo(@slot, Session.hash_to_mechanism(mechanism))
62
+ @pk.C_GetMechanismInfo(@slot, to_mechanism_int(mechanism))
51
63
  end
52
64
  alias mechanism_info C_GetMechanismInfo
53
65
 
54
- # Initializes a token. pin is the SO’s initial PIN; label is the label of the token (max 32-byte). This standard allows PIN
66
+ # Initializes a token.
67
+ # @param [String] pin is the SO's initial PIN
68
+ # @param [String] label is the label of the token (max 32-byte).
69
+ #
70
+ # The standard allows PIN
55
71
  # values to contain any valid UTF8 character, but the token may impose subset restrictions.
72
+ # @return [PKCS11::Slot]
56
73
  def C_InitToken(pin, label)
57
74
  @pk.C_InitToken(@slot, pin, label.ljust(32, " "))
75
+ self
58
76
  end
59
77
  alias init_token C_InitToken
60
78
 
61
79
  # Opens a Session between an application and a token in a particular slot.
62
80
  #
63
- # flags:: indicates the type of session. Default is read-only,
81
+ # @param [Integer] flags indicates the type of session. Default is read-only,
64
82
  # use <tt>CKF_SERIAL_SESSION | CKF_RW_SESSION</tt> for read-write session.
65
83
  #
66
84
  # * If called with block, yields the block with the session and closes the session
67
- # when the is finished.
85
+ # when the is finished.
68
86
  # * If called without block, returns the session object.
87
+ # @return [PKCS11::Session]
69
88
  def C_OpenSession(flags=CKF_SERIAL_SESSION)
70
89
  nr = @pk.C_OpenSession(@slot, flags)
71
90
  sess = Session.new @pk, nr
@@ -82,8 +101,10 @@ module PKCS11
82
101
  alias open C_OpenSession
83
102
 
84
103
  # Closes all sessions an application has with a token.
104
+ # @return [PKCS11::Slot]
85
105
  def C_CloseAllSessions
86
106
  @pk.C_CloseAllSessions(@slot)
107
+ self
87
108
  end
88
109
  alias close_all_sessions C_CloseAllSessions
89
110
  end
@@ -1,10 +1,9 @@
1
1
  require "openssl"
2
2
 
3
- def open_softokn
4
-
5
- if RUBY_PLATFORM =~ /win32/
3
+ def find_softokn
4
+ if RUBY_PLATFORM =~ /mswin|mingw/
6
5
  lLIBSOFTOKEN3_SO = "softokn3.dll"
7
-
6
+
8
7
  # Try to find the firefox path.
9
8
  unless ENV['SOFTOKN_PATH']
10
9
  require 'win32/registry'
@@ -31,13 +30,21 @@ def open_softokn
31
30
  end
32
31
 
33
32
  raise "#{lLIBSOFTOKEN3_SO} not found - please install firefox or set ENV['SOFTOKN_PATH']" unless so_path
33
+ so_path
34
+ end
34
35
 
36
+ def softokn_params
35
37
  dir = File.join(File.dirname(__FILE__), 'fixtures/softokn')
36
- nNSS_INIT_ARGS = [
38
+ [
37
39
  "configDir='#{dir}'",
38
40
  "secmod='secmod.db'",
39
41
  "flags='readWrite'",
40
42
  ]
43
+ end
44
+
45
+ def open_softokn
46
+ so_path = find_softokn
47
+ nNSS_INIT_ARGS = softokn_params
41
48
 
42
- pk11 = PKCS11.open(so_path, :flags=>0, :pReserved=>nNSS_INIT_ARGS.join(" "))
49
+ PKCS11.open(so_path, :flags=>0, :pReserved=>nNSS_INIT_ARGS.join(" "))
43
50
  end
@@ -29,8 +29,19 @@ class TestPkcs11 < Test::Unit::TestCase
29
29
 
30
30
  def test_close
31
31
  pk.close
32
+ pk.unload_library
32
33
  assert_raise(PKCS11::Error){ pk.info }
33
- pk.close
34
- assert_raise(PKCS11::Error){ pk.active_slots }
34
+
35
+ @pk = PKCS11.open
36
+ pk.load_library(find_softokn)
37
+
38
+ pk.C_GetFunctionList
39
+
40
+ pargs = PKCS11::CK_C_INITIALIZE_ARGS.new
41
+ pargs.flags = 0
42
+ pargs.pReserved = softokn_params.join(" ")
43
+ pk.C_Initialize(pargs)
44
+
45
+ pk.info
35
46
  end
36
47
  end
@@ -18,7 +18,7 @@ class TestPkcs11Crypt < Test::Unit::TestCase
18
18
  @slots = pk.active_slots
19
19
  @slot = slots.last
20
20
  @session = slot.open
21
- session.login(:USER, "")
21
+ # session.login(:USER, "")
22
22
 
23
23
  @rsa_pub_key = session.find_objects(:CLASS => CKO_PUBLIC_KEY,
24
24
  :KEY_TYPE => CKK_RSA).first
@@ -34,7 +34,7 @@ class TestPkcs11Crypt < Test::Unit::TestCase
34
34
 
35
35
  def teardown
36
36
  @secret_key.destroy
37
- @session.logout
37
+ # @session.logout
38
38
  @session.close
39
39
  end
40
40
 
@@ -66,7 +66,7 @@ class TestPkcs11Crypt < Test::Unit::TestCase
66
66
  valid = session.verify( :SHA1_RSA_PKCS, rsa_pub_key, signature, plaintext)
67
67
  assert valid, 'The signature should be correct'
68
68
 
69
- assert_raise(PKCS11::Error, 'The signature should be invalid on different text') do
69
+ assert_raise(CKR_SIGNATURE_INVALID, 'The signature should be invalid on different text') do
70
70
  session.verify( :SHA1_RSA_PKCS, rsa_pub_key, signature, "modified text")
71
71
  end
72
72
  end
@@ -132,6 +132,15 @@ class TestPkcs11Crypt < Test::Unit::TestCase
132
132
  key = session.generate_key(:DES2_KEY_GEN,
133
133
  {:ENCRYPT=>true, :WRAP=>true, :DECRYPT=>true, :UNWRAP=>true, :TOKEN=>false, :LOCAL=>true})
134
134
  assert_equal true, key[:LOCAL], 'Keys created on the token should be marked as local'
135
+ assert_equal CKK_DES2, key[:KEY_TYPE], 'Should be a 2 key 3des key'
136
+
137
+ # other ways to use mechanisms
138
+ key = session.generate_key(CKM_DES2_KEY_GEN,
139
+ {:ENCRYPT=>true, :WRAP=>true, :DECRYPT=>true, :UNWRAP=>true, :TOKEN=>false, :LOCAL=>true})
140
+ assert_equal CKK_DES2, key[:KEY_TYPE], 'Should be a 2 key 3des key'
141
+ key = session.generate_key(CK_MECHANISM.new(CKM_DES2_KEY_GEN, nil),
142
+ {:ENCRYPT=>true, :WRAP=>true, :DECRYPT=>true, :UNWRAP=>true, :TOKEN=>false, :LOCAL=>true})
143
+ assert_equal CKK_DES2, key[:KEY_TYPE], 'Should be a 2 key 3des key'
135
144
  end
136
145
 
137
146
  def test_generate_key_pair
@@ -164,4 +173,30 @@ class TestPkcs11Crypt < Test::Unit::TestCase
164
173
 
165
174
  assert_equal new_key1[0,16], new_key2[:VALUE], 'Exchanged session key should be equal'
166
175
  end
176
+
177
+ def test_derive_key2
178
+ deriv_data = "\0"*16
179
+ new_key1 = session.derive_key( {CKM_XOR_BASE_AND_DATA => {:pData => deriv_data}}, secret_key,
180
+ :CLASS=>CKO_SECRET_KEY, :KEY_TYPE=>CKK_AES, :VALUE_LEN=>16, :ENCRYPT=>true, :DECRYPT=>true, :SENSITIVE=>false )
181
+
182
+ assert_equal secret_key[:VALUE], new_key1[:VALUE], 'Derived key should have equal key value'
183
+ end
184
+
185
+ def test_ssl3
186
+ pm_key = session.generate_key({:SSL3_PRE_MASTER_KEY_GEN => {:major=>3, :minor=>0}},
187
+ {:TOKEN=>false})
188
+ assert_equal 48, pm_key[:VALUE_LEN], "SSL3 pre master key should be 48 bytes long"
189
+
190
+ dp = CK_SSL3_MASTER_KEY_DERIVE_PARAMS.new
191
+ dp.RandomInfo.pServerRandom = 'srandom ' * 4
192
+ dp.RandomInfo.pClientRandom = 'crandom ' * 4
193
+ dp.pVersion = CK_VERSION.new
194
+ dp.pVersion.major = 3
195
+ dp.pVersion.minor = 1
196
+ ms_key = session.derive_key( {CKM_SSL3_MASTER_KEY_DERIVE => dp}, pm_key )
197
+
198
+ assert_equal 48, ms_key[:VALUE_LEN], "SSL3 master secret key should be 48 bytes long"
199
+ assert_equal 0, dp.pVersion.minor, 'SSL3 version number should have changed'
200
+ end
201
+
167
202
  end
@@ -18,7 +18,7 @@ class TestPkcs11Object < Test::Unit::TestCase
18
18
 
19
19
  flags = CKF_SERIAL_SESSION #| CKF_RW_SESSION
20
20
  @session = slot.C_OpenSession(flags)
21
- @session.login(:USER, "")
21
+ # @session.login(:USER, "")
22
22
 
23
23
  # Create session object for tests.
24
24
  @object = session.create_object(
@@ -29,7 +29,7 @@ class TestPkcs11Object < Test::Unit::TestCase
29
29
  end
30
30
 
31
31
  def teardown
32
- @session.logout
32
+ # @session.logout
33
33
  @session.close
34
34
  end
35
35
 
@@ -84,10 +84,24 @@ class TestPkcs11Object < Test::Unit::TestCase
84
84
  assert object.size, 'There should be an object size'
85
85
  end
86
86
 
87
+ def test_copy_without_params
88
+ new_obj = object.copy
89
+ new_obj[:APPLICATION] = 'Copied object'
90
+ assert_equal 'Copied object', new_obj[:APPLICATION], "Application should be changed"
91
+ assert_equal 'My Application', object[:APPLICATION], "Original object should be unchanged"
92
+ end
93
+
94
+ def test_copy_with_params
95
+ new_obj = object.copy :APPLICATION=>'Copied object'
96
+ assert_equal 'value', new_obj[:VALUE], "Value should be copied"
97
+ assert_equal 'Copied object', new_obj[:APPLICATION], "Application should be changed"
98
+ assert_equal 'My Application', object[:APPLICATION], "Original object should be unchanged"
99
+ end
100
+
87
101
  def test_destroy
88
102
  object.destroy
89
-
90
- assert_raise(PKCS11::Error, 'destroyed object shouldn\'t have any attributes') do
103
+
104
+ assert_raise(CKR_OBJECT_HANDLE_INVALID, 'destroyed object shouldn\'t have any attributes') do
91
105
  object[:VALUE]
92
106
  end
93
107
  end
@@ -19,11 +19,11 @@ class TestPkcs11Session < Test::Unit::TestCase
19
19
 
20
20
  flags = CKF_SERIAL_SESSION #| CKF_RW_SESSION
21
21
  @session = slot.C_OpenSession(flags)
22
- @session.login(:USER, "")
22
+ # @session.login(:USER, "")
23
23
  end
24
24
 
25
25
  def teardown
26
- @session.logout
26
+ # @session.logout
27
27
  @session.close
28
28
  end
29
29
 
@@ -94,4 +94,30 @@ class TestPkcs11Session < Test::Unit::TestCase
94
94
 
95
95
  assert_equal 'test_create_public_key_object', obj[:LABEL], 'Value as created'
96
96
  end
97
+
98
+ def test_get_set_operation_state
99
+ plaintext = "secret text"
100
+
101
+ # Start a digest operation
102
+ session.C_DigestInit(:SHA_1)
103
+ session.C_DigestUpdate(plaintext[0..3])
104
+
105
+ # Save the current state and close the session
106
+ state = session.get_operation_state
107
+ @session.close
108
+
109
+ assert state.length >= 4, 'There should be at least some bytes for the first part of plaintext in the state'
110
+
111
+ # Open a new session and restore the previous state
112
+ @session = @slot.open
113
+ session.login(:USER, "")
114
+ session.set_operation_state(state)
115
+
116
+ # Finish the digest
117
+ session.C_DigestUpdate(plaintext[4..-1])
118
+ digest1 = session.C_DigestFinal
119
+ digest2 = OpenSSL::Digest::SHA1.new(plaintext).digest
120
+
121
+ assert_equal digest2, digest1, 'Digests should be equal'
122
+ end
97
123
  end
@@ -23,13 +23,16 @@ class TestPkcs11Slot < Test::Unit::TestCase
23
23
 
24
24
  def test_info
25
25
  sinfo = slot.info
26
-
26
+
27
27
  assert sinfo.inspect =~ /manufacturerID=/, 'Slot info should tell about manufacturerID'
28
-
29
- [
30
- sinfo.slotDescription, sinfo.manufacturerID, sinfo.flags,
31
- sinfo.hardwareVersion, sinfo.firmwareVersion
32
- ]
28
+
29
+ assert_equal Fixnum, sinfo.flags.class
30
+ assert sinfo.manufacturerID =~ /Mozilla/i, "It's the mozilla libaray we test against"
31
+ assert sinfo.slotDescription =~ /Private Key/i, "It's the slot with users private keys"
32
+ assert_equal Fixnum, sinfo.hardwareVersion.major.class, "Version should be a number"
33
+ assert_equal Fixnum, sinfo.hardwareVersion.minor.class, "Version should be a number"
34
+ assert_equal Fixnum, sinfo.firmwareVersion.major.class, "Version should be a number"
35
+ assert_equal Fixnum, sinfo.firmwareVersion.minor.class, "Version should be a number"
33
36
  end
34
37
 
35
38
  def test_token_info
@@ -0,0 +1,134 @@
1
+ require "test/unit"
2
+ require "pkcs11"
3
+ require "test/helper"
4
+
5
+ class TestPkcs11Structs < Test::Unit::TestCase
6
+ include PKCS11
7
+
8
+ def setup
9
+ end
10
+
11
+ def teardown
12
+ end
13
+
14
+ def test_STRING_ACCESSOR
15
+ s = CK_DATE.new
16
+ assert_equal "\0\0", s.day
17
+ assert_equal "\0\0\0\0", s.year
18
+ s.day = "12345"
19
+ assert_equal "12", s.day
20
+ s.day = "9"
21
+ assert_equal "9\0", s.day
22
+ assert_raise(TypeError){ s.day = nil }
23
+ end
24
+
25
+ def test_ULONG_ACCESSOR
26
+ s = CK_SSL3_KEY_MAT_PARAMS.new
27
+ assert_equal 0, s.ulIVSizeInBits
28
+ s.ulIVSizeInBits = 1234567890
29
+ assert_equal 1234567890, s.ulIVSizeInBits
30
+ s.ulIVSizeInBits = 2345678901
31
+ assert_equal 2345678901, s.ulIVSizeInBits
32
+ assert_raise(TypeError){ s.ulIVSizeInBits = nil }
33
+ end
34
+
35
+ def test_BOOL_ACCESSOR
36
+ s = CK_SSL3_KEY_MAT_PARAMS.new
37
+ assert_equal false, s.bIsExport
38
+ s.bIsExport = true
39
+ assert_equal true, s.bIsExport
40
+ s.bIsExport = false
41
+ assert_equal false, s.bIsExport
42
+ assert_raise(ArgumentError){ s.bIsExport = nil }
43
+ end
44
+
45
+ def test_STRING_PTR_ACCESSOR
46
+ s = CK_WTLS_MASTER_KEY_DERIVE_PARAMS.new
47
+ assert_nil s.pVersion
48
+ s.pVersion = "1.2.3"
49
+ assert_equal "1.2.3", s.pVersion
50
+ s.pVersion = nil
51
+ assert_nil s.pVersion
52
+ end
53
+
54
+ def test_STRUCT_ACCESSOR
55
+ s = CK_SSL3_KEY_MAT_PARAMS.new
56
+ ri = s.RandomInfo
57
+ ro = s.RandomInfo
58
+ assert_nil ri.pClientRandom
59
+ assert_nil ro.pServerRandom
60
+ GC.start
61
+ ri.pServerRandom = 'serv'
62
+ ro.pClientRandom = 'client'
63
+ GC.start
64
+ assert_equal 'client', ri.pClientRandom
65
+ assert_equal 'serv', ro.pServerRandom
66
+
67
+ ro = CK_SSL3_RANDOM_DATA.new
68
+ ro.pClientRandom = 'clrnd'
69
+ s.RandomInfo = ro
70
+ assert_equal 'clrnd', ri.pClientRandom
71
+ assert_nil ri.pServerRandom
72
+
73
+ assert_raise(ArgumentError){ s.RandomInfo = nil }
74
+ end
75
+
76
+ def test_gc_STRUCT_ACCESSOR
77
+ ri = CK_SSL3_KEY_MAT_PARAMS.new.RandomInfo
78
+ ro = CK_SSL3_KEY_MAT_PARAMS.new.RandomInfo
79
+ ri.pServerRandom = 'serv'
80
+ ro.pServerRandom = '_serv'
81
+ GC.start
82
+ assert_equal '_serv', ro.pServerRandom
83
+ assert_equal 'serv', ri.pServerRandom
84
+ assert_nil ro.pClientRandom
85
+ assert_nil ri.pClientRandom
86
+ end
87
+
88
+ def test_STRING_PTR_LEN_ACCESSOR
89
+ s = CK_SSL3_RANDOM_DATA.new
90
+ assert_nil s.pServerRandom
91
+ GC.start
92
+ s.pServerRandom = 'serv'
93
+ s.pClientRandom = 'client'
94
+ GC.start
95
+ assert_equal 'client', s.pClientRandom
96
+ assert_equal 'serv', s.pServerRandom
97
+ GC.start
98
+ s.pServerRandom = nil
99
+ assert_nil s.pServerRandom
100
+ end
101
+
102
+ def test_STRUCT_PTR_ACCESSOR
103
+ s = CK_SSL3_KEY_MAT_PARAMS.new
104
+ assert_nil s.pReturnedKeyMaterial
105
+ ri = s.pReturnedKeyMaterial = CK_SSL3_KEY_MAT_OUT.new
106
+ assert_nil ri.pIVClient
107
+ ri.pIVClient = 'cli'
108
+ GC.start
109
+ assert_equal 'cli', ri.pIVClient
110
+ assert_equal 'cli', s.pReturnedKeyMaterial.pIVClient
111
+ s.pReturnedKeyMaterial = nil
112
+ assert_nil s.pReturnedKeyMaterial
113
+ end
114
+
115
+ def test_ULONG_PTR_ACCESSOR
116
+ s = CK_WTLS_PRF_PARAMS.new
117
+ assert_nil s.pulOutputLen
118
+ s.pulOutputLen = 123
119
+ GC.start
120
+ assert_equal 123, s.pulOutputLen
121
+ s.pulOutputLen = nil
122
+ assert_nil s.pulOutputLen
123
+ end
124
+
125
+ def test_CStruct
126
+ s = CK_DATE.new
127
+ s.day, s.month, s.year = "31", "12", "2010"
128
+
129
+ assert s.inspect =~ /year="2010"/, 'There should be a year in CK_DATE'
130
+ assert_equal ["day", "month", "year"], s.members, 'CK_DATE should contain some attributes'
131
+ assert_equal ["31", "12", "2010"], s.values, 'values of CK_DATE'
132
+ assert_equal( {:day=>"31", :month=>"12", :year=>"2010"}, s.to_hash, 'CK_DATE as hash' )
133
+ end
134
+ end