pkcs11 0.1.0-x86-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +23 -0
- data/History.txt +3 -0
- data/MIT-LICENSE +22 -0
- data/Manifest.txt +34 -0
- data/README.rdoc +156 -0
- data/Rakefile +36 -0
- data/ext/extconf.rb +6 -0
- data/ext/include/cryptoki.h +66 -0
- data/ext/include/ct-kip.h +50 -0
- data/ext/include/otp-pkcs11.h +125 -0
- data/ext/include/pkcs-11v2-20a3.h +124 -0
- data/ext/include/pkcs11.h +299 -0
- data/ext/include/pkcs11f.h +912 -0
- data/ext/include/pkcs11t.h +1885 -0
- data/ext/pk11.c +1737 -0
- data/ext/pk11.h +78 -0
- data/ext/pk11_const.c +680 -0
- data/lib/1.8/pkcs11_ext.so +0 -0
- data/lib/1.9/pkcs11_ext.so +0 -0
- data/lib/pkcs11.rb +12 -0
- data/lib/pkcs11/extensions.rb +160 -0
- data/lib/pkcs11/library.rb +63 -0
- data/lib/pkcs11/object.rb +104 -0
- data/lib/pkcs11/session.rb +568 -0
- data/lib/pkcs11/slot.rb +90 -0
- data/sample/firefox_certs.rb +90 -0
- data/sample/nssckbi.rb +51 -0
- data/test/fixtures/softokn/cert8.db +0 -0
- data/test/fixtures/softokn/key3.db +0 -0
- data/test/fixtures/softokn/secmod.db +0 -0
- data/test/helper.rb +43 -0
- data/test/test_pkcs11.rb +36 -0
- data/test/test_pkcs11_crypt.rb +167 -0
- data/test/test_pkcs11_object.rb +94 -0
- data/test/test_pkcs11_session.rb +97 -0
- data/test/test_pkcs11_slot.rb +66 -0
- metadata +122 -0
Binary file
|
Binary file
|
data/lib/pkcs11.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Load the correct version if it's a Windows binary gem
|
4
|
+
if RUBY_PLATFORM =~/(mswin|mingw)/i
|
5
|
+
major_minor = RUBY_VERSION[ /^(\d+\.\d+)/ ] or
|
6
|
+
raise "Oops, can't extract the major/minor version from #{RUBY_VERSION.dump}"
|
7
|
+
require "#{major_minor}/pkcs11_ext"
|
8
|
+
else
|
9
|
+
require 'pkcs11_ext'
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'pkcs11/extensions'
|
@@ -0,0 +1,160 @@
|
|
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 usage:
|
11
|
+
#
|
12
|
+
# pkcs11 = PKCS11.open("/path/to/pkcs11.so")
|
13
|
+
# slot = pkcs11.active_slots.first
|
14
|
+
# p slot.info
|
15
|
+
# session = slot.open(PKCS11::CKF_SERIAL_SESSION|PKCS11::CKF_RW_SESSION)
|
16
|
+
# session.login(:USER, "1234")
|
17
|
+
# ...
|
18
|
+
# session.logout
|
19
|
+
# session.close
|
20
|
+
#
|
21
|
+
# See unit tests in the <tt>test</tt> directory for further examples of the usage.
|
22
|
+
module PKCS11
|
23
|
+
|
24
|
+
class << self
|
25
|
+
# Open a PKCS#11 library file.
|
26
|
+
alias new open
|
27
|
+
end
|
28
|
+
|
29
|
+
module InspectableStruct
|
30
|
+
# Array of the InspectableStruct's attribute names.
|
31
|
+
def members
|
32
|
+
(self.methods - ::Object.new.methods - InspectableStruct.instance_methods).grep(/[^=]$/).sort
|
33
|
+
end
|
34
|
+
# Array of the InspectableStruct's attribute values.
|
35
|
+
def values
|
36
|
+
members.inject([]){|a,v| a << send(v) }
|
37
|
+
end
|
38
|
+
# Hash with the InspectableStruct's attribute names and values.
|
39
|
+
def to_hash
|
40
|
+
members.inject({}){|h,v| h[v.intern] = send(v); h }
|
41
|
+
end
|
42
|
+
def inspect # :nodoc:
|
43
|
+
"#<#{self.class} #{to_hash.map{|k,v| "#{k}=#{v.inspect}"}.join(", ") }>"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module InspectableAttribute
|
48
|
+
# Array of the InspectableStruct's attribute names.
|
49
|
+
def members
|
50
|
+
['type', 'value']
|
51
|
+
end
|
52
|
+
# Array of the InspectableStruct's attribute values.
|
53
|
+
def values
|
54
|
+
members.inject([]){|a,v| a << send(v) }
|
55
|
+
end
|
56
|
+
# Hash with the InspectableStruct's attribute names and values.
|
57
|
+
def to_hash
|
58
|
+
members.inject({}){|h,v| h[v.intern] = send(v); h }
|
59
|
+
end
|
60
|
+
# Get the constant name as String of the given value.
|
61
|
+
# Returns <tt>nil</tt> if value is unknown.
|
62
|
+
def to_s
|
63
|
+
ATTRIBUTES[type]
|
64
|
+
end
|
65
|
+
def inspect # :nodoc:
|
66
|
+
"#<#{self.class} #{ to_s ? "#{to_s} (#{type})" : type} value=#{value.inspect}>"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# See InspectableStruct.
|
71
|
+
class CK_INFO
|
72
|
+
include InspectableStruct
|
73
|
+
end
|
74
|
+
# See InspectableStruct.
|
75
|
+
class CK_C_INITIALIZE_ARGS
|
76
|
+
include InspectableStruct
|
77
|
+
end
|
78
|
+
# See InspectableStruct.
|
79
|
+
class CK_ATTRIBUTE
|
80
|
+
include InspectableAttribute
|
81
|
+
end
|
82
|
+
# See InspectableStruct.
|
83
|
+
class CK_TOKEN_INFO
|
84
|
+
include InspectableStruct
|
85
|
+
end
|
86
|
+
# See InspectableStruct.
|
87
|
+
class CK_SLOT_INFO
|
88
|
+
include InspectableStruct
|
89
|
+
end
|
90
|
+
# See InspectableStruct.
|
91
|
+
class CK_MECHANISM_INFO
|
92
|
+
include InspectableStruct
|
93
|
+
end
|
94
|
+
# See InspectableStruct.
|
95
|
+
class CK_SESSION_INFO
|
96
|
+
include InspectableStruct
|
97
|
+
end
|
98
|
+
# See InspectableStruct.
|
99
|
+
class CK_MECHANISM
|
100
|
+
include InspectableStruct
|
101
|
+
end
|
102
|
+
|
103
|
+
class ConstValue
|
104
|
+
def initialize(enum_hash, value) # :nodoc:
|
105
|
+
@enum_hash, @value = enum_hash, value
|
106
|
+
end
|
107
|
+
|
108
|
+
# Get the constant name as String of the given value.
|
109
|
+
# Returns <tt>nil</tt> if value is unknown.
|
110
|
+
def to_s
|
111
|
+
@enum_hash[@value]
|
112
|
+
end
|
113
|
+
def inspect
|
114
|
+
# "#<#{self.class} #{ to_s ? "#{to_s} (#{@value})" : @value}>"
|
115
|
+
@value.inspect
|
116
|
+
end
|
117
|
+
|
118
|
+
# The value of the constant.
|
119
|
+
def to_int
|
120
|
+
@value
|
121
|
+
end
|
122
|
+
alias to_i to_int
|
123
|
+
end
|
124
|
+
|
125
|
+
module ConstValueHash # :nodoc:
|
126
|
+
def [](value)
|
127
|
+
super(value.to_int)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class << self
|
132
|
+
def extend_ConstValueHash(hash_symb) # :nodoc:
|
133
|
+
# The MECHANISMS, ATTRIBUTES, etc. Hashs are freezed.
|
134
|
+
# So, we have make a copy, to extend the class.
|
135
|
+
my_HASH = const_get(hash_symb).dup
|
136
|
+
my_HASH.extend ConstValueHash
|
137
|
+
my_HASH.freeze
|
138
|
+
const_set("UNWRAPPED_#{hash_symb}", hash_symb)
|
139
|
+
remove_const(hash_symb)
|
140
|
+
const_set(hash_symb, my_HASH)
|
141
|
+
end
|
142
|
+
private :extend_ConstValueHash
|
143
|
+
end
|
144
|
+
|
145
|
+
extend_ConstValueHash(:OBJECT_CLASSES)
|
146
|
+
class ObjectClass < ConstValue
|
147
|
+
end
|
148
|
+
|
149
|
+
extend_ConstValueHash(:ATTRIBUTES)
|
150
|
+
class Attribute < ConstValue
|
151
|
+
end
|
152
|
+
|
153
|
+
extend_ConstValueHash(:MECHANISMS)
|
154
|
+
class Mechanism < ConstValue
|
155
|
+
end
|
156
|
+
|
157
|
+
# extend_ConstValueHash(:RETURN_VALUES)
|
158
|
+
# class ReturnValue < ConstValue
|
159
|
+
# end
|
160
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module PKCS11
|
2
|
+
# A Library instance holds a handle to the opened PKCS#11 - dll or so file.
|
3
|
+
class Library
|
4
|
+
alias unwrapped_initialize initialize # :nodoc:
|
5
|
+
|
6
|
+
# Load and initialize a pkcs11 dynamic library.
|
7
|
+
#
|
8
|
+
# so_path:: Path to the *.so or *.dll file to load.
|
9
|
+
# args:: A Hash or CK_C_INITIALIZE_ARGS instance with load params.
|
10
|
+
def initialize(so_path, args={})
|
11
|
+
case args
|
12
|
+
when Hash
|
13
|
+
pargs = CK_C_INITIALIZE_ARGS.new
|
14
|
+
args.each{|k,v| pargs.send("#{k}=", v) }
|
15
|
+
else
|
16
|
+
pargs = args
|
17
|
+
end
|
18
|
+
unwrapped_initialize(so_path, pargs)
|
19
|
+
end
|
20
|
+
|
21
|
+
alias unwrapped_C_GetInfo C_GetInfo
|
22
|
+
# Returns general information about Cryptoki.
|
23
|
+
def C_GetInfo
|
24
|
+
unwrapped_C_GetInfo
|
25
|
+
end
|
26
|
+
alias info C_GetInfo
|
27
|
+
|
28
|
+
alias unwrapped_C_GetSlotList C_GetSlotList
|
29
|
+
|
30
|
+
# Obtain an array of Slot objects in the system. tokenPresent indicates
|
31
|
+
# whether the list obtained includes only those slots with a token present (true), or
|
32
|
+
# all slots (false);
|
33
|
+
def C_GetSlotList(tokenPresent=true)
|
34
|
+
slots = unwrapped_C_GetSlotList(tokenPresent)
|
35
|
+
slots.map{|slot|
|
36
|
+
Slot.new self, slot
|
37
|
+
}
|
38
|
+
end
|
39
|
+
alias slots C_GetSlotList
|
40
|
+
|
41
|
+
# Obtain an array of Slot objects in the system with a token present.
|
42
|
+
def active_slots
|
43
|
+
slots(true)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Obtain an array of Slot objects in the system regardless if a token is present.
|
47
|
+
def all_slots
|
48
|
+
slots(false)
|
49
|
+
end
|
50
|
+
|
51
|
+
alias unwrapped_C_Finalize C_Finalize
|
52
|
+
# Close and unload library. If not called, the library is freed by the GC.
|
53
|
+
def C_Finalize
|
54
|
+
unwrapped_C_Finalize
|
55
|
+
end
|
56
|
+
alias close C_Finalize
|
57
|
+
|
58
|
+
private :unwrapped_initialize
|
59
|
+
private :unwrapped_C_GetSlotList
|
60
|
+
private :unwrapped_C_Finalize
|
61
|
+
private :unwrapped_C_GetInfo
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module PKCS11
|
2
|
+
# Cryptoki’s logical view of a token is a device that stores objects and can perform
|
3
|
+
# cryptographic functions. Cryptoki defines three classes of object: data, certificates, and
|
4
|
+
# keys.
|
5
|
+
#
|
6
|
+
# Attributes are characteristics that distinguish an instance of an object.
|
7
|
+
class Object
|
8
|
+
def initialize(pkcs11, session, object) # :nodoc:
|
9
|
+
@pk, @sess, @obj = pkcs11, session, object
|
10
|
+
end
|
11
|
+
|
12
|
+
# The object handle.
|
13
|
+
def to_int
|
14
|
+
@obj
|
15
|
+
end
|
16
|
+
alias to_i to_int
|
17
|
+
|
18
|
+
def inspect # :nodoc:
|
19
|
+
"#<#{self.class} #{@obj.inspect}>"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the value of one attribute of the object.
|
23
|
+
#
|
24
|
+
# attribute:: can be String or Symbol of the attribute constant
|
25
|
+
# or the attribute number as Integer.
|
26
|
+
#
|
27
|
+
# Returns the attribute value as String, Integer or true/false
|
28
|
+
# depending on the attribute type.
|
29
|
+
# Unknown attributes (out of PKCS#11 v2.2) are not converted but returned as String.
|
30
|
+
# That is true/false will be returned as "\\001" respectively "\\000".
|
31
|
+
def [](attribute)
|
32
|
+
attrs = C_GetAttributeValue( [attribute] )
|
33
|
+
attrs.first.value unless attrs.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
# Modifies the value of one attribute the object.
|
37
|
+
#
|
38
|
+
# attribute:: can be String or Symbol of the attribute constant
|
39
|
+
# or the attribute value as Integer.
|
40
|
+
# value:: String value the attribute will be set to.
|
41
|
+
#
|
42
|
+
# Following value conversations are done:
|
43
|
+
# true -> 0x01
|
44
|
+
# false -> 0x00
|
45
|
+
# nil -> NULL pointer
|
46
|
+
# Fixnum -> binary encoded unsigned long
|
47
|
+
def []=(attribute, value)
|
48
|
+
C_SetAttributeValue( attribute => value )
|
49
|
+
end
|
50
|
+
|
51
|
+
# Modifies the value of one or more attributes of the object in a single call.
|
52
|
+
#
|
53
|
+
# Examples:
|
54
|
+
# object.attributes = {:SUBJECT => cert_subject, PKCS11::CKA_VALUE => cert_data}
|
55
|
+
def C_SetAttributeValue(template={})
|
56
|
+
template = Session.hash_to_attributes template
|
57
|
+
@pk.C_SetAttributeValue(@sess, @obj, template)
|
58
|
+
end
|
59
|
+
alias attributes= C_SetAttributeValue
|
60
|
+
|
61
|
+
# Obtains the value of one or more attributes of the object in a single call.
|
62
|
+
#
|
63
|
+
# Without params all known attributes are tried to read from the Object.
|
64
|
+
# This is significant slower then naming the needed attributes and should
|
65
|
+
# be used for debug purposes only.
|
66
|
+
#
|
67
|
+
# Returns an Array of PKCS11::CK_ATTRIBUTE's.
|
68
|
+
#
|
69
|
+
# Example:
|
70
|
+
# certificate.attributes :ID, :VALUE
|
71
|
+
def C_GetAttributeValue(*template)
|
72
|
+
case template.length
|
73
|
+
when 0
|
74
|
+
return PKCS11::ATTRIBUTES.values.map{|attr|
|
75
|
+
begin
|
76
|
+
attributes(PKCS11.const_get(attr))
|
77
|
+
rescue PKCS11::Error
|
78
|
+
end
|
79
|
+
}.flatten.compact
|
80
|
+
when 1
|
81
|
+
template = template[0]
|
82
|
+
end
|
83
|
+
template = Session.hash_to_attributes template
|
84
|
+
@pk.C_GetAttributeValue(@sess, @obj, template)
|
85
|
+
end
|
86
|
+
alias attributes C_GetAttributeValue
|
87
|
+
|
88
|
+
# Destroys the object.
|
89
|
+
#
|
90
|
+
# Only session objects can be destroyed during a read-only session. Only public objects
|
91
|
+
# can be destroyed unless the normal user is logged in.
|
92
|
+
def C_DestroyObject()
|
93
|
+
@pk.C_DestroyObject(@sess, @obj)
|
94
|
+
end
|
95
|
+
alias destroy C_DestroyObject
|
96
|
+
|
97
|
+
# Gets the size of an object in bytes.
|
98
|
+
def C_GetObjectSize()
|
99
|
+
@pk.C_GetObjectSize(@sess, @obj)
|
100
|
+
end
|
101
|
+
alias size C_GetObjectSize
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,568 @@
|
|
1
|
+
module PKCS11
|
2
|
+
# Cryptoki requires that an application open one or more sessions with a token to gain
|
3
|
+
# access to the token’s objects and functions. A session provides a logical connection
|
4
|
+
# between the application and the token. A session can be a read/write (R/W) session or a
|
5
|
+
# read-only (R/O) session (default).
|
6
|
+
class Session
|
7
|
+
class << self
|
8
|
+
def hash_to_attributes(template) # :nodoc:
|
9
|
+
case template
|
10
|
+
when Array
|
11
|
+
template.map{|v| PKCS11::CK_ATTRIBUTE.new(string_to_handle('CKA_', v), nil) }
|
12
|
+
when Hash
|
13
|
+
template.map{|k,v| PKCS11::CK_ATTRIBUTE.new(string_to_handle('CKA_', k), v) }
|
14
|
+
when String, Symbol
|
15
|
+
[PKCS11::CK_ATTRIBUTE.new(string_to_handle('CKA_', template), nil)]
|
16
|
+
when Integer
|
17
|
+
[PKCS11::CK_ATTRIBUTE.new(template, nil)]
|
18
|
+
else
|
19
|
+
template
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def string_to_handle(prefix, attribute) # :nodoc:
|
24
|
+
case attribute
|
25
|
+
when String, Symbol
|
26
|
+
PKCS11.const_get("#{prefix}#{attribute}")
|
27
|
+
else
|
28
|
+
attribute
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def hash_to_mechanism(hash) # :nodoc:
|
33
|
+
case hash
|
34
|
+
when String, Symbol
|
35
|
+
PKCS11::CK_MECHANISM.new(string_to_handle('CKM_', hash))
|
36
|
+
when Hash
|
37
|
+
raise "only one mechanism allowed" unless hash.length==1
|
38
|
+
PKCS11::CK_MECHANISM.new(string_to_handle('CKM_', hash.keys.first), hash.values.first)
|
39
|
+
else
|
40
|
+
hash.to_int
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize(pkcs11, session) # :nodoc:
|
46
|
+
@pk, @sess = pkcs11, session
|
47
|
+
end
|
48
|
+
|
49
|
+
# The session handle.
|
50
|
+
def to_int
|
51
|
+
@sess
|
52
|
+
end
|
53
|
+
alias to_i to_int
|
54
|
+
|
55
|
+
def inspect # :nodoc:
|
56
|
+
"#<#{self.class} #{@sess.inspect}>"
|
57
|
+
end
|
58
|
+
|
59
|
+
# Logs a user into a token.
|
60
|
+
# user_type:: is the user type CKU_*;
|
61
|
+
# pin:: is the user’s PIN.
|
62
|
+
#
|
63
|
+
# When the user type is either CKU_SO or CKU_USER, if the call succeeds, each of the
|
64
|
+
# application's sessions will enter either the "R/W SO Functions" state, the "R/W User
|
65
|
+
# Functions" state, or the "R/O User Functions" state. If the user type is
|
66
|
+
# CKU_CONTEXT_SPECIFIC , the behavior of C_Login depends on the context in which
|
67
|
+
# it is called. Improper use of this user type will result in a return value
|
68
|
+
# CKR_OPERATION_NOT_INITIALIZED.
|
69
|
+
def C_Login(user_type, pin)
|
70
|
+
@pk.C_Login(@sess, Session::string_to_handle('CKU_', user_type), pin)
|
71
|
+
end
|
72
|
+
alias login C_Login
|
73
|
+
|
74
|
+
# Logs a user out from a token.
|
75
|
+
#
|
76
|
+
# Depending on the current user type, if the call succeeds, each of the application’s
|
77
|
+
# sessions will enter either the “R/W Public Session” state or the “R/O Public Session”
|
78
|
+
# state.
|
79
|
+
def C_Logout()
|
80
|
+
@pk.C_Logout(@sess)
|
81
|
+
end
|
82
|
+
alias logout C_Logout
|
83
|
+
|
84
|
+
# Closes the session between an application and a token.
|
85
|
+
def C_CloseSession()
|
86
|
+
@pk.C_CloseSession(@sess)
|
87
|
+
end
|
88
|
+
alias close C_CloseSession
|
89
|
+
|
90
|
+
# Obtains information about a session. Returns a CK_SESSION_INFO.
|
91
|
+
def C_GetSessionInfo()
|
92
|
+
@pk.C_GetSessionInfo(@sess)
|
93
|
+
end
|
94
|
+
alias info C_GetSessionInfo
|
95
|
+
|
96
|
+
# Initializes a search for token and session objects that match a
|
97
|
+
# template.
|
98
|
+
#
|
99
|
+
# find_template:: points to a search template that
|
100
|
+
# specifies the attribute values to match
|
101
|
+
# The matching criterion is an exact byte-for-byte match with all attributes in the
|
102
|
+
# template. Use empty Hash to find all objects.
|
103
|
+
|
104
|
+
def C_FindObjectsInit(find_template={})
|
105
|
+
@pk.C_FindObjectsInit(@sess, Session.hash_to_attributes(find_template))
|
106
|
+
end
|
107
|
+
|
108
|
+
# Continues a search for token and session objects that match a template,
|
109
|
+
# obtaining additional object handles.
|
110
|
+
#
|
111
|
+
# Returns an array of Object instances.
|
112
|
+
def C_FindObjects(max_count)
|
113
|
+
objs = @pk.C_FindObjects(@sess, max_count)
|
114
|
+
objs.map{|obj| Object.new @pk, @sess, obj }
|
115
|
+
end
|
116
|
+
|
117
|
+
# Terminates a search for token and session objects.
|
118
|
+
def C_FindObjectsFinal
|
119
|
+
@pk.C_FindObjectsFinal(@sess)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Convenience method for the C_FindObjectsInit, C_FindObjects, C_FindObjectsFinal cycle.
|
123
|
+
#
|
124
|
+
# * If called with block, it iterates over all found objects.
|
125
|
+
# * If called without block, it returns with an array of all found Object instances.
|
126
|
+
#
|
127
|
+
# Example (prints subject of all certificates stored in the token):
|
128
|
+
# session.find_objects(:CLASS => PKCS11::CKO_CERTIFICATE) do |obj|
|
129
|
+
# p OpenSSL::X509::Name.new(obj[:SUBJECT])
|
130
|
+
# end
|
131
|
+
def find_objects(template={})
|
132
|
+
all_objs = [] unless block_given?
|
133
|
+
C_FindObjectsInit(template)
|
134
|
+
begin
|
135
|
+
loop do
|
136
|
+
objs = C_FindObjects(20)
|
137
|
+
break if objs.empty?
|
138
|
+
if block_given?
|
139
|
+
objs.each{|obj| yield obj }
|
140
|
+
else
|
141
|
+
all_objs += objs
|
142
|
+
end
|
143
|
+
end
|
144
|
+
ensure
|
145
|
+
C_FindObjectsFinal()
|
146
|
+
end
|
147
|
+
return all_objs
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
# Creates a new Object based on given template. Returns a new object’s handle.
|
152
|
+
# If C_CreateObject is used to create a key object, the key object will have its
|
153
|
+
# CKA_LOCAL attribute set to false. If that key object is a secret or private key
|
154
|
+
# then the new key will have the CKA_ALWAYS_SENSITIVE attribute set to
|
155
|
+
# false, and the CKA_NEVER_EXTRACTABLE attribute set to false.
|
156
|
+
#
|
157
|
+
# Only session objects can be created during a read-only session. Only public objects can
|
158
|
+
# be created unless the normal user is logged in.
|
159
|
+
def C_CreateObject(template={})
|
160
|
+
handle = @pk.C_CreateObject(@sess, Session.hash_to_attributes(template))
|
161
|
+
Object.new @pk, @sess, handle
|
162
|
+
end
|
163
|
+
alias create_object C_CreateObject
|
164
|
+
|
165
|
+
# Initializes the normal user’s PIN. This standard
|
166
|
+
# allows PIN values to contain any valid UTF8 character, but the token may impose subset
|
167
|
+
# restrictions.
|
168
|
+
def C_InitPIN(pin)
|
169
|
+
@pk.C_InitPIN(@sess, pin)
|
170
|
+
end
|
171
|
+
alias init_pin C_InitPIN
|
172
|
+
|
173
|
+
# Modifies the PIN of the user that is currently logged in, or the CKU_USER
|
174
|
+
# PIN if the session is not logged in.
|
175
|
+
def C_SetPIN(old_pin, new_pin)
|
176
|
+
@pk.C_SetPIN(@sess, old_pin, new_pin)
|
177
|
+
end
|
178
|
+
alias set_pin C_SetPIN
|
179
|
+
|
180
|
+
class Cipher
|
181
|
+
def initialize(update_block) # :nodoc:
|
182
|
+
@update_block = update_block
|
183
|
+
end
|
184
|
+
def update(data)
|
185
|
+
@update_block.call(data)
|
186
|
+
end
|
187
|
+
alias << update
|
188
|
+
end
|
189
|
+
|
190
|
+
class DigestCipher < Cipher
|
191
|
+
def initialize(update_block, digest_key_block) # :nodoc:
|
192
|
+
super(update_block)
|
193
|
+
@digest_key_block = digest_key_block
|
194
|
+
end
|
195
|
+
alias digest_update update
|
196
|
+
def digest_key(key)
|
197
|
+
@digest_key_block.call(key)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def common_crypt( init, update, final, single, mechanism, key, data=nil) # :nodoc:
|
202
|
+
send(init, mechanism, key)
|
203
|
+
if block_given?
|
204
|
+
raise "data not nil, but block given" if data
|
205
|
+
yield Cipher.new(proc{|data_|
|
206
|
+
send(update, data_)
|
207
|
+
})
|
208
|
+
send(final)
|
209
|
+
else
|
210
|
+
send(single, data)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
private :common_crypt
|
214
|
+
|
215
|
+
def common_verify( init, update, final, single, mechanism, key, signature, data=nil ) # :nodoc:
|
216
|
+
send(init, mechanism, key)
|
217
|
+
if block_given?
|
218
|
+
raise "data not nil, but block given" if data
|
219
|
+
yield Cipher.new(proc{|data_|
|
220
|
+
send(update, data_)
|
221
|
+
})
|
222
|
+
send(final, signature)
|
223
|
+
else
|
224
|
+
send(single, data, signature)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
private :common_verify
|
228
|
+
|
229
|
+
# Initializes an encryption operation.
|
230
|
+
#
|
231
|
+
# mechanism:: the encryption mechanism, Hash, String or Integer
|
232
|
+
# key:: the object handle of the encryption key.
|
233
|
+
#
|
234
|
+
# See Session#encrypt for convenience.
|
235
|
+
#
|
236
|
+
# The CKA_ENCRYPT attribute of the encryption key, which indicates whether the key
|
237
|
+
# supports encryption, must be true.
|
238
|
+
#
|
239
|
+
# After calling C_EncryptInit, the application can either call C_Encrypt to encrypt data
|
240
|
+
# in a single part; or call C_EncryptUpdate zero or more times, followed by
|
241
|
+
# C_EncryptFinal, to encrypt data in multiple parts. The encryption operation is active
|
242
|
+
# until the application uses a call to C_Encrypt or C_EncryptFinal to actually obtain the
|
243
|
+
# final piece of ciphertext. To process additional data (in single or multiple parts), the
|
244
|
+
# application must call C_EncryptInit again.
|
245
|
+
def C_EncryptInit(mechanism, key)
|
246
|
+
@pk.C_EncryptInit(@sess, Session.hash_to_mechanism(mechanism), key)
|
247
|
+
end
|
248
|
+
# Encrypts single-part data.
|
249
|
+
def C_Encrypt(data, out_size=nil)
|
250
|
+
@pk.C_Encrypt(@sess, data, out_size)
|
251
|
+
end
|
252
|
+
# Continues a multiple-part encryption operation, processing another
|
253
|
+
# data part.
|
254
|
+
def C_EncryptUpdate(data, out_size=nil)
|
255
|
+
@pk.C_EncryptUpdate(@sess, data, out_size)
|
256
|
+
end
|
257
|
+
# Finishes a multiple-part encryption operation.
|
258
|
+
def C_EncryptFinal(out_size=nil)
|
259
|
+
@pk.C_EncryptFinal(@sess, out_size)
|
260
|
+
end
|
261
|
+
|
262
|
+
# Convenience method for the C_EncryptInit, C_EncryptUpdate, C_EncryptFinal call flow.
|
263
|
+
#
|
264
|
+
# If no block is given, the single part operation C_EncryptInit, C_Encrypt is called.
|
265
|
+
# If a block is given, the multi part operation (C_EncryptInit, C_EncryptUpdate, C_EncryptFinal)
|
266
|
+
# is used. The given block is called once with a cipher object. There can be any number of
|
267
|
+
# Cipher#update calls within the block, each giving the encryption result of this part as String.
|
268
|
+
#
|
269
|
+
# Returns the final part of the encryption operation.
|
270
|
+
#
|
271
|
+
# Example:
|
272
|
+
# iv = "12345678"
|
273
|
+
# cryptogram = ''
|
274
|
+
# cryptogram << session.encrypt( {:DES_CBC_PAD=>iv}, key ) do |cipher|
|
275
|
+
# cryptogram << cipher.update("block 1")
|
276
|
+
# cryptogram << cipher.update("block 2")
|
277
|
+
# end
|
278
|
+
def encrypt(mechanism, key, data=nil, &block)
|
279
|
+
common_crypt(:C_EncryptInit, :C_EncryptUpdate, :C_EncryptFinal, :C_Encrypt,
|
280
|
+
mechanism, key, data, &block)
|
281
|
+
end
|
282
|
+
|
283
|
+
# Initializes a decryption operation.
|
284
|
+
#
|
285
|
+
# See Session#decrypt for convenience.
|
286
|
+
def C_DecryptInit(mechanism, key)
|
287
|
+
@pk.C_DecryptInit(@sess, Session.hash_to_mechanism(mechanism), key)
|
288
|
+
end
|
289
|
+
# Decrypts encrypted data in a single part.
|
290
|
+
def C_Decrypt(data, out_size=nil)
|
291
|
+
@pk.C_Decrypt(@sess, data, out_size)
|
292
|
+
end
|
293
|
+
# Continues a multiple-part decryption operation, processing another
|
294
|
+
# encrypted data part.
|
295
|
+
def C_DecryptUpdate(data, out_size=nil)
|
296
|
+
@pk.C_DecryptUpdate(@sess, data, out_size)
|
297
|
+
end
|
298
|
+
# Finishes a multiple-part decryption operation.
|
299
|
+
def C_DecryptFinal(out_size=nil)
|
300
|
+
@pk.C_DecryptFinal(@sess, out_size)
|
301
|
+
end
|
302
|
+
|
303
|
+
# Convenience method for the C_DecryptInit, C_DecryptUpdate, C_DecryptFinal call flow.
|
304
|
+
#
|
305
|
+
# See Session#encrypt
|
306
|
+
def decrypt(mechanism, key, data=nil, &block)
|
307
|
+
common_crypt(:C_DecryptInit, :C_DecryptUpdate, :C_DecryptFinal, :C_Decrypt,
|
308
|
+
mechanism, key, data, &block)
|
309
|
+
end
|
310
|
+
|
311
|
+
# Initializes a message-digesting operation.
|
312
|
+
#
|
313
|
+
# See Session#digest for convenience.
|
314
|
+
def C_DigestInit(mechanism)
|
315
|
+
@pk.C_DigestInit(@sess, Session.hash_to_mechanism(mechanism))
|
316
|
+
end
|
317
|
+
# Digests data in a single part.
|
318
|
+
def C_Digest(data, out_size=nil)
|
319
|
+
@pk.C_Digest(@sess, data, out_size)
|
320
|
+
end
|
321
|
+
# Continues a multiple-part message-digesting operation, processing
|
322
|
+
# another data part.
|
323
|
+
def C_DigestUpdate(data)
|
324
|
+
@pk.C_DigestUpdate(@sess, data)
|
325
|
+
end
|
326
|
+
# Continues a multiple-part message-digesting operation by digesting the
|
327
|
+
# value of a secret key.
|
328
|
+
#
|
329
|
+
# The message-digesting operation must have been initialized with C_DigestInit. Calls to
|
330
|
+
# this function and C_DigestUpdate may be interspersed any number of times in any
|
331
|
+
# order.
|
332
|
+
def C_DigestKey(key)
|
333
|
+
@pk.C_DigestKey(@sess, key)
|
334
|
+
end
|
335
|
+
# Finishes a multiple-part message-digesting operation, returning the
|
336
|
+
# message digest as String.
|
337
|
+
def C_DigestFinal(out_size=nil)
|
338
|
+
@pk.C_DigestFinal(@sess, out_size)
|
339
|
+
end
|
340
|
+
|
341
|
+
# Convenience method for the C_DigestInit, C_DigestUpdate, C_DigestKey,
|
342
|
+
# C_DigestFinal call flow.
|
343
|
+
#
|
344
|
+
# Example:
|
345
|
+
# digest_string = session.digest( :SHA_1 ) do |cipher|
|
346
|
+
# cipher.update("key prefix")
|
347
|
+
# cipher.digest_key(some_key)
|
348
|
+
# end
|
349
|
+
def digest(mechanism, data=nil, &block)
|
350
|
+
C_DigestInit(mechanism)
|
351
|
+
if block_given?
|
352
|
+
raise "data not nil, but block given" if data
|
353
|
+
yield DigestCipher.new(proc{|data_|
|
354
|
+
C_DigestUpdate(data_)
|
355
|
+
}, proc{|key_|
|
356
|
+
C_DigestKey(key_)
|
357
|
+
})
|
358
|
+
C_DigestFinal()
|
359
|
+
else
|
360
|
+
C_Digest(data)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
# Initializes a signature operation, where the signature is an appendix to the
|
365
|
+
# data.
|
366
|
+
#
|
367
|
+
# See Session#sign for convenience.
|
368
|
+
def C_SignInit(mechanism, key)
|
369
|
+
@pk.C_SignInit(@sess, Session.hash_to_mechanism(mechanism), key)
|
370
|
+
end
|
371
|
+
# Signs data in a single part, where the signature is an appendix to the data.
|
372
|
+
def C_Sign(data, out_size=nil)
|
373
|
+
@pk.C_Sign(@sess, data, out_size)
|
374
|
+
end
|
375
|
+
# Continues a multiple-part signature operation, processing another data
|
376
|
+
# part.
|
377
|
+
def C_SignUpdate(data)
|
378
|
+
@pk.C_SignUpdate(@sess, data)
|
379
|
+
end
|
380
|
+
# Finishes a multiple-part signature operation, returning the signature.
|
381
|
+
def C_SignFinal(out_size=nil)
|
382
|
+
@pk.C_SignFinal(@sess, out_size)
|
383
|
+
end
|
384
|
+
|
385
|
+
# Convenience method for the C_SignInit, C_SignUpdate, C_SignFinal call flow.
|
386
|
+
#
|
387
|
+
# See Session#encrypt
|
388
|
+
def sign(mechanism, key, data=nil, &block)
|
389
|
+
common_crypt(:C_SignInit, :C_SignUpdate, :C_SignFinal, :C_Sign,
|
390
|
+
mechanism, key, data, &block)
|
391
|
+
end
|
392
|
+
|
393
|
+
|
394
|
+
# Initializes a verification operation, where the signature is an appendix to
|
395
|
+
# the data.
|
396
|
+
#
|
397
|
+
# See ession#verify for convenience.
|
398
|
+
def C_VerifyInit(mechanism, key)
|
399
|
+
@pk.C_VerifyInit(@sess, Session.hash_to_mechanism(mechanism), key)
|
400
|
+
end
|
401
|
+
# Verifies a signature in a single-part operation, where the signature is an
|
402
|
+
# appendix to the data.
|
403
|
+
def C_Verify(data, out_size=nil)
|
404
|
+
@pk.C_Verify(@sess, data, out_size)
|
405
|
+
end
|
406
|
+
# Continues a multiple-part verification operation, processing another
|
407
|
+
# data part.
|
408
|
+
def C_VerifyUpdate(data)
|
409
|
+
@pk.C_VerifyUpdate(@sess, data)
|
410
|
+
end
|
411
|
+
# Finishes a multiple-part verification operation, checking the signature.
|
412
|
+
#
|
413
|
+
# Returns <tt>true</tt> for valid signature.
|
414
|
+
def C_VerifyFinal(out_size=nil)
|
415
|
+
@pk.C_VerifyFinal(@sess, out_size)
|
416
|
+
end
|
417
|
+
|
418
|
+
# Convenience method for the C_VerifyInit, C_VerifyUpdate, C_VerifyFinal call flow.
|
419
|
+
#
|
420
|
+
# See Session#encrypt
|
421
|
+
def verify(mechanism, key, signature, data=nil, &block)
|
422
|
+
common_verify(:C_VerifyInit, :C_VerifyUpdate, :C_VerifyFinal, :C_Verify,
|
423
|
+
mechanism, key, signature, data, &block)
|
424
|
+
end
|
425
|
+
|
426
|
+
# Initializes a signature operation, where the data can be recovered
|
427
|
+
# from the signature
|
428
|
+
def C_SignRecoverInit(mechanism, key)
|
429
|
+
@pk.C_SignRecoverInit(@sess, Session.hash_to_mechanism(mechanism), key)
|
430
|
+
end
|
431
|
+
# Signs data in a single operation, where the data can be recovered from
|
432
|
+
# the signature.
|
433
|
+
def C_SignRecover(data, out_size=nil)
|
434
|
+
@pk.C_SignRecover(@sess, data, out_size)
|
435
|
+
end
|
436
|
+
|
437
|
+
# Convenience method for the C_SignRecoverInit, C_SignRecover call flow.
|
438
|
+
def sign_recover(mechanism, key, data)
|
439
|
+
C_SignRecoverInit(mechanism, key)
|
440
|
+
C_SignRecover(data)
|
441
|
+
end
|
442
|
+
|
443
|
+
|
444
|
+
# Initializes a signature verification operation, where the data can be recovered
|
445
|
+
# from the signature
|
446
|
+
#
|
447
|
+
# See Session#verify_recover for convenience.
|
448
|
+
def C_VerifyRecoverInit(mechanism, key)
|
449
|
+
@pk.C_VerifyRecoverInit(@sess, Session.hash_to_mechanism(mechanism), key)
|
450
|
+
end
|
451
|
+
# Verifies a signature in a single-part operation, where the data is
|
452
|
+
# recovered from the signature.
|
453
|
+
def C_VerifyRecover(signature, out_size=nil)
|
454
|
+
@pk.C_VerifyRecover(@sess, signature, out_size=nil)
|
455
|
+
end
|
456
|
+
|
457
|
+
# Convenience method for the C_VerifyRecoverInit, C_VerifyRecover call flow.
|
458
|
+
def verify_recover(mechanism, key, signature)
|
459
|
+
C_VerifyRecoverInit(mechanism, key)
|
460
|
+
C_VerifyRecover(signature)
|
461
|
+
end
|
462
|
+
|
463
|
+
# Continues multiple-part digest and encryption operations,
|
464
|
+
# processing another data part.
|
465
|
+
#
|
466
|
+
# Digest and encryption operations must both be active (they must have been initialized
|
467
|
+
# with C_DigestInit and C_EncryptInit, respectively). This function may be called any
|
468
|
+
# number of times in succession, and may be interspersed with C_DigestUpdate,
|
469
|
+
# C_DigestKey, and C_EncryptUpdate calls.
|
470
|
+
def C_DigestEncryptUpdate(data, out_size=nil)
|
471
|
+
@pk.C_DigestEncryptUpdate(@sess, data, out_size)
|
472
|
+
end
|
473
|
+
|
474
|
+
# Continues a multiple-part combined decryption and digest
|
475
|
+
# operation, processing another data part.
|
476
|
+
#
|
477
|
+
# Decryption and digesting operations must both be active (they must have been initialized
|
478
|
+
# with C_DecryptInit and C_DigestInit, respectively). This function may be called any
|
479
|
+
# number of times in succession, and may be interspersed with C_DecryptUpdate,
|
480
|
+
# C_DigestUpdate, and C_DigestKey calls.
|
481
|
+
def C_DecryptDigestUpdate(data, out_size=nil)
|
482
|
+
@pk.C_DecryptDigestUpdate(@sess, data, out_size)
|
483
|
+
end
|
484
|
+
|
485
|
+
# Continues a multiple-part combined signature and encryption
|
486
|
+
# operation, processing another data part.
|
487
|
+
#
|
488
|
+
# Signature and encryption operations must both be active (they must have been initialized
|
489
|
+
# with C_SignInit and C_EncryptInit, respectively). This function may be called any
|
490
|
+
# number of times in succession, and may be interspersed with C_SignUpdate and
|
491
|
+
# C_EncryptUpdate calls.
|
492
|
+
def C_SignEncryptUpdate(data, out_size=nil)
|
493
|
+
@pk.C_SignEncryptUpdate(@sess, data, out_size)
|
494
|
+
end
|
495
|
+
|
496
|
+
# Continues a multiple-part combined decryption and
|
497
|
+
# verification operation, processing another data part.
|
498
|
+
#
|
499
|
+
# Decryption and signature operations must both be active (they must have been initialized
|
500
|
+
# with C_DecryptInit and C_VerifyInit, respectively). This function may be called any
|
501
|
+
# number of times in succession, and may be interspersed with C_DecryptUpdate and
|
502
|
+
# C_VerifyUpdate calls.
|
503
|
+
def C_DecryptVerifyUpdate(data, out_size=nil)
|
504
|
+
@pk.C_DecryptVerifyUpdate(@sess, data, out_size)
|
505
|
+
end
|
506
|
+
|
507
|
+
# Generates a secret key Object or set of domain parameters, creating a new
|
508
|
+
# Object.
|
509
|
+
#
|
510
|
+
# Returns key Object of the new created key.
|
511
|
+
def C_GenerateKey(mechanism, template={})
|
512
|
+
obj = @pk.C_GenerateKey(@sess, Session.hash_to_mechanism(mechanism), Session.hash_to_attributes(template))
|
513
|
+
Object.new @pk, @sess, obj
|
514
|
+
end
|
515
|
+
alias generate_key C_GenerateKey
|
516
|
+
|
517
|
+
# Generates a public/private key pair, creating new key Object instances.
|
518
|
+
#
|
519
|
+
# Returns an two-items array of new created public and private key Object.
|
520
|
+
def C_GenerateKeyPair(mechanism, pubkey_template={}, privkey_template={})
|
521
|
+
objs = @pk.C_GenerateKeyPair(@sess, Session.hash_to_mechanism(mechanism), Session.hash_to_attributes(pubkey_template), Session.hash_to_attributes(privkey_template))
|
522
|
+
objs.map{|obj| Object.new @pk, @sess, obj }
|
523
|
+
end
|
524
|
+
alias generate_key_pair C_GenerateKeyPair
|
525
|
+
|
526
|
+
# Wraps (i.e., encrypts) a private or secret key.
|
527
|
+
#
|
528
|
+
# Returns the encrypted binary data.
|
529
|
+
def C_WrapKey(mechanism, wrapping_key, wrapped_key, out_size=nil)
|
530
|
+
@pk.C_WrapKey(@sess, Session.hash_to_mechanism(mechanism), wrapping_key, wrapped_key, out_size)
|
531
|
+
end
|
532
|
+
alias wrap_key C_WrapKey
|
533
|
+
|
534
|
+
# Unwraps (i.e. decrypts) a wrapped key, creating a new private key or
|
535
|
+
# secret key object.
|
536
|
+
#
|
537
|
+
# Returns key Object of the new created key.
|
538
|
+
def C_UnwrapKey(mechanism, wrapping_key, wrapped_key, template={})
|
539
|
+
obj = @pk.C_UnwrapKey(@sess, Session.hash_to_mechanism(mechanism), wrapping_key, wrapped_key, Session.hash_to_attributes(template))
|
540
|
+
Object.new @pk, @sess, obj
|
541
|
+
end
|
542
|
+
alias unwrap_key C_UnwrapKey
|
543
|
+
|
544
|
+
# Derives a key from a base key, creating a new key object.
|
545
|
+
#
|
546
|
+
# Returns key Object of the new created key.
|
547
|
+
def C_DeriveKey(mechanism, base_key, template={})
|
548
|
+
obj = @pk.C_DeriveKey(@sess, Session.hash_to_mechanism(mechanism), base_key, Session.hash_to_attributes(template))
|
549
|
+
Object.new @pk, @sess, obj
|
550
|
+
end
|
551
|
+
alias derive_key C_DeriveKey
|
552
|
+
|
553
|
+
# Mixes additional seed material into the token’s random number
|
554
|
+
# generator.
|
555
|
+
def C_SeedRandom(data)
|
556
|
+
@pk.C_SeedRandom(@sess, data)
|
557
|
+
end
|
558
|
+
alias seed_random C_SeedRandom
|
559
|
+
|
560
|
+
# Generates random or pseudo-random data.
|
561
|
+
#
|
562
|
+
# Returns random or pseudo-random binary data of <tt>out_size</tt> bytes.
|
563
|
+
def C_GenerateRandom(out_size)
|
564
|
+
@pk.C_GenerateRandom(@sess, out_size)
|
565
|
+
end
|
566
|
+
alias generate_random C_GenerateRandom
|
567
|
+
end
|
568
|
+
end
|