ccrypto-ruby 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +64 -0
- data/README.md +149 -0
- data/Rakefile +10 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/ccrypto-ruby.gemspec +45 -0
- data/lib/ccrypto/provider.rb +175 -0
- data/lib/ccrypto/ruby/data_conversion.rb +68 -0
- data/lib/ccrypto/ruby/engines/asn1_engine.rb +110 -0
- data/lib/ccrypto/ruby/engines/asn1_object.rb +19 -0
- data/lib/ccrypto/ruby/engines/cipher_engine.rb +170 -0
- data/lib/ccrypto/ruby/engines/compression_engine.rb +61 -0
- data/lib/ccrypto/ruby/engines/data_conversion_engine.rb +9 -0
- data/lib/ccrypto/ruby/engines/decompression_engine.rb +70 -0
- data/lib/ccrypto/ruby/engines/digest_engine.rb +127 -0
- data/lib/ccrypto/ruby/engines/ecc_engine.rb +218 -0
- data/lib/ccrypto/ruby/engines/hkdf_engine.rb +54 -0
- data/lib/ccrypto/ruby/engines/hmac_engine.rb +53 -0
- data/lib/ccrypto/ruby/engines/pbkdf2_engine.rb +69 -0
- data/lib/ccrypto/ruby/engines/pkcs7_engine.rb +179 -0
- data/lib/ccrypto/ruby/engines/rsa_engine.rb +300 -0
- data/lib/ccrypto/ruby/engines/scrypt_engine.rb +34 -0
- data/lib/ccrypto/ruby/engines/secret_key_engine.rb +18 -0
- data/lib/ccrypto/ruby/engines/secret_sharing_engine.rb +331 -0
- data/lib/ccrypto/ruby/engines/secure_random_engine.rb +34 -0
- data/lib/ccrypto/ruby/engines/x509_engine.rb +213 -0
- data/lib/ccrypto/ruby/ext/secret_key.rb +24 -0
- data/lib/ccrypto/ruby/ext/x509_cert.rb +24 -0
- data/lib/ccrypto/ruby/keybundle_store/pem_store.rb +73 -0
- data/lib/ccrypto/ruby/keybundle_store/pkcs12.rb +111 -0
- data/lib/ccrypto/ruby/utils/comparator.rb +15 -0
- data/lib/ccrypto/ruby/utils/memory_buffer.rb +63 -0
- data/lib/ccrypto/ruby/utils/native_helper.rb +17 -0
- data/lib/ccrypto/ruby/version.rb +7 -0
- data/lib/ccrypto/ruby.rb +25 -0
- metadata +136 -0
@@ -0,0 +1,331 @@
|
|
1
|
+
|
2
|
+
require 'openssl'
|
3
|
+
|
4
|
+
module Ccrypto
|
5
|
+
module Ruby
|
6
|
+
|
7
|
+
class SecretSharingEngine
|
8
|
+
def initialize(*args, &block)
|
9
|
+
@config = args.first
|
10
|
+
raise SecretSharingException, "SecretSharingConfig is required" if not @config.is_a?(Ccrypto::SecretSharingConfig)
|
11
|
+
raise SecretSharingException, "split_into value must be more than 1" if not @config.split_into.to_i > 1
|
12
|
+
raise SecretSharingException, "required_parts value (#{@config.required_parts}) must be less than or equal split_into value (#{@config.split_into})." if not @config.required_parts.to_i < @config.split_into.to_i
|
13
|
+
end
|
14
|
+
|
15
|
+
def split(secVal)
|
16
|
+
|
17
|
+
case secVal
|
18
|
+
when MemoryBuffer
|
19
|
+
data = secVal.bytes
|
20
|
+
when String
|
21
|
+
data = secVal
|
22
|
+
when Ccrypto::SecretKey
|
23
|
+
data = secVal.to_bin
|
24
|
+
else
|
25
|
+
raise SecretSharingException, "Unknown how to process split for #{secVal.class}"
|
26
|
+
end
|
27
|
+
|
28
|
+
eng = ShamirSharing.new(@config.required_parts.to_i, data)
|
29
|
+
shares = []
|
30
|
+
(1..@config.split_into.to_i).each do |i|
|
31
|
+
res = eng.compute_share(i)
|
32
|
+
res[1] = res[1].map { |v| v.chr }.join
|
33
|
+
shares << res
|
34
|
+
end
|
35
|
+
shares
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.combine(req, parts)
|
39
|
+
|
40
|
+
parts.each do |k,v|
|
41
|
+
parts[k] = v.chars.map(&:ord)
|
42
|
+
end
|
43
|
+
|
44
|
+
ss = ShamirSharing.new(req)
|
45
|
+
ss.recover_secretdata(parts.to_a)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
#
|
51
|
+
# This code is borrowed from PolyPasswordHasher-Ruby project at https://github.com/PolyPasswordHasher/PolyPasswordHasher-Ruby
|
52
|
+
#
|
53
|
+
class ShamirSharing
|
54
|
+
attr_reader :_coefficients
|
55
|
+
attr_reader :secretdata
|
56
|
+
|
57
|
+
def initialize(threshold, secretdata=nil)
|
58
|
+
@threshold = threshold
|
59
|
+
@secretdata = secretdata
|
60
|
+
@_coefficients = []
|
61
|
+
|
62
|
+
if secretdata
|
63
|
+
secretdata.each_char do |secretbyte|
|
64
|
+
thesecoefficients = secretbyte+OpenSSL::Random.random_bytes(@threshold-1)
|
65
|
+
@_coefficients << thesecoefficients
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def is_valid_share?(share)
|
71
|
+
raise "Share is of incorrect length: #{share.size}" if share.size !=2
|
72
|
+
raise "Must initialize coefficient before checking is_valid_share?" unless @_coefficients
|
73
|
+
raise "Must initialize coefficient before checking is_valid_share?" if @_coefficients.size != share[1].size
|
74
|
+
|
75
|
+
x = share[0]
|
76
|
+
fx = share[1]
|
77
|
+
|
78
|
+
correctshare = compute_share(x)
|
79
|
+
|
80
|
+
correctshare == share
|
81
|
+
end
|
82
|
+
|
83
|
+
def compute_share(x)
|
84
|
+
raise "x should be integer" unless x.class == Fixnum
|
85
|
+
raise "x must be between 1 and 255" if x <= 0 || x >256
|
86
|
+
raise "@_coefficient must be initialized" if @_coefficients.empty?
|
87
|
+
|
88
|
+
sharebytes = []
|
89
|
+
|
90
|
+
@_coefficients.each do |thiscoefficient|
|
91
|
+
thisshare = _f(x,thiscoefficient)
|
92
|
+
sharebytes << thisshare
|
93
|
+
end
|
94
|
+
|
95
|
+
return x, sharebytes
|
96
|
+
end
|
97
|
+
|
98
|
+
def recover_secretdata(shares)
|
99
|
+
newshares = []
|
100
|
+
|
101
|
+
shares.each do |share|
|
102
|
+
newshares << share unless newshares.include?(share)
|
103
|
+
end
|
104
|
+
|
105
|
+
shares = newshares
|
106
|
+
|
107
|
+
if @threshold > shares.size
|
108
|
+
raise "Threshold: #{@threshold} is smaller than the number of uniquie shares: #{shares.size}"
|
109
|
+
end
|
110
|
+
|
111
|
+
if @secretdata
|
112
|
+
raise "Recovoring secretdata when some is stored. Use check_share instead"
|
113
|
+
end
|
114
|
+
|
115
|
+
xs = []
|
116
|
+
|
117
|
+
shares.each do |share|
|
118
|
+
if xs.include?(share[0])
|
119
|
+
raise "Different shares with the same first byte: #{share[0]}"
|
120
|
+
end
|
121
|
+
|
122
|
+
if share[1].size != shares[0][1].size
|
123
|
+
raise "Shares have different lengths!"
|
124
|
+
end
|
125
|
+
|
126
|
+
xs << share[0]
|
127
|
+
end
|
128
|
+
|
129
|
+
mycoefficients = []
|
130
|
+
mysecretdata = ''
|
131
|
+
|
132
|
+
shares[0][1].size.times.each do |byte_to_use|
|
133
|
+
fxs = []
|
134
|
+
shares.each do |share|
|
135
|
+
fxs << share[1][byte_to_use]
|
136
|
+
end
|
137
|
+
|
138
|
+
resulting_poly = _full_lagrange(xs,fxs)
|
139
|
+
|
140
|
+
if resulting_poly[0..@threshold-1] + [0]*(shares.size - @threshold) != resulting_poly
|
141
|
+
raise "Share do not match. Cannot decode"
|
142
|
+
end
|
143
|
+
|
144
|
+
mycoefficients << resulting_poly.map{|p| p.chr}.join
|
145
|
+
|
146
|
+
mysecretdata += resulting_poly[0].chr
|
147
|
+
end
|
148
|
+
|
149
|
+
@_coefficients = mycoefficients
|
150
|
+
@secretdata = mysecretdata
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
def _f(x, coefs_bytes)
|
155
|
+
raise "invalid share index value. cannot be 0" if x == 0
|
156
|
+
|
157
|
+
accumulator = 0
|
158
|
+
|
159
|
+
x_i = 1
|
160
|
+
|
161
|
+
coefs_bytes.each_byte do |c|
|
162
|
+
accumulator = _gf256_add(accumulator, _gf256_mul(c, x_i))
|
163
|
+
x_i = _gf256_mul(x_i, x)
|
164
|
+
end
|
165
|
+
|
166
|
+
return accumulator
|
167
|
+
end
|
168
|
+
|
169
|
+
def _multiply_polynomials(a,b)
|
170
|
+
resultterms = []
|
171
|
+
|
172
|
+
termpadding = []
|
173
|
+
|
174
|
+
b.each do |bterm|
|
175
|
+
thisvalue = termpadding.clone
|
176
|
+
|
177
|
+
a.each do |aterm|
|
178
|
+
val = _gf256_mul(aterm, bterm)
|
179
|
+
thisvalue << _gf256_mul(aterm, bterm)
|
180
|
+
end
|
181
|
+
|
182
|
+
resultterms = _add_polynomials(resultterms, thisvalue)
|
183
|
+
|
184
|
+
termpadding << 0
|
185
|
+
end
|
186
|
+
|
187
|
+
return resultterms
|
188
|
+
end
|
189
|
+
|
190
|
+
def _add_polynomials(a,b)
|
191
|
+
if a.size < b.size
|
192
|
+
a = a + [0]*(b.size - a.size)
|
193
|
+
elsif a.size > b.size
|
194
|
+
b = b + [0]*(a.size - b.size)
|
195
|
+
end
|
196
|
+
|
197
|
+
result = []
|
198
|
+
|
199
|
+
a.size.times do |pos|
|
200
|
+
result << _gf256_add(a[pos], b[pos])
|
201
|
+
end
|
202
|
+
|
203
|
+
return result
|
204
|
+
end
|
205
|
+
|
206
|
+
def _full_lagrange(xs, fxs)
|
207
|
+
returnedcoefficients = []
|
208
|
+
|
209
|
+
fxs.size.times do |i|
|
210
|
+
this_polynomial = [1]
|
211
|
+
|
212
|
+
fxs.size.times do |j|
|
213
|
+
next if i == j
|
214
|
+
|
215
|
+
denominator = _gf256_sub(xs[i], xs[j])
|
216
|
+
|
217
|
+
this_term = [_gf256_div(xs[j], denominator), _gf256_div(1, denominator)]
|
218
|
+
|
219
|
+
this_polynomial = _multiply_polynomials(this_polynomial, this_term)
|
220
|
+
end
|
221
|
+
|
222
|
+
this_polynomial = _multiply_polynomials(this_polynomial, [fxs[i]]) if fxs[i]
|
223
|
+
|
224
|
+
returnedcoefficients = _add_polynomials(returnedcoefficients, this_polynomial)
|
225
|
+
end
|
226
|
+
|
227
|
+
return returnedcoefficients
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
GF256_EXP = [
|
232
|
+
0x01, 0x03, 0x05, 0x0f, 0x11, 0x33, 0x55, 0xff,
|
233
|
+
0x1a, 0x2e, 0x72, 0x96, 0xa1, 0xf8, 0x13, 0x35,
|
234
|
+
0x5f, 0xe1, 0x38, 0x48, 0xd8, 0x73, 0x95, 0xa4,
|
235
|
+
0xf7, 0x02, 0x06, 0x0a, 0x1e, 0x22, 0x66, 0xaa,
|
236
|
+
0xe5, 0x34, 0x5c, 0xe4, 0x37, 0x59, 0xeb, 0x26,
|
237
|
+
0x6a, 0xbe, 0xd9, 0x70, 0x90, 0xab, 0xe6, 0x31,
|
238
|
+
0x53, 0xf5, 0x04, 0x0c, 0x14, 0x3c, 0x44, 0xcc,
|
239
|
+
0x4f, 0xd1, 0x68, 0xb8, 0xd3, 0x6e, 0xb2, 0xcd,
|
240
|
+
0x4c, 0xd4, 0x67, 0xa9, 0xe0, 0x3b, 0x4d, 0xd7,
|
241
|
+
0x62, 0xa6, 0xf1, 0x08, 0x18, 0x28, 0x78, 0x88,
|
242
|
+
0x83, 0x9e, 0xb9, 0xd0, 0x6b, 0xbd, 0xdc, 0x7f,
|
243
|
+
0x81, 0x98, 0xb3, 0xce, 0x49, 0xdb, 0x76, 0x9a,
|
244
|
+
0xb5, 0xc4, 0x57, 0xf9, 0x10, 0x30, 0x50, 0xf0,
|
245
|
+
0x0b, 0x1d, 0x27, 0x69, 0xbb, 0xd6, 0x61, 0xa3,
|
246
|
+
0xfe, 0x19, 0x2b, 0x7d, 0x87, 0x92, 0xad, 0xec,
|
247
|
+
0x2f, 0x71, 0x93, 0xae, 0xe9, 0x20, 0x60, 0xa0,
|
248
|
+
0xfb, 0x16, 0x3a, 0x4e, 0xd2, 0x6d, 0xb7, 0xc2,
|
249
|
+
0x5d, 0xe7, 0x32, 0x56, 0xfa, 0x15, 0x3f, 0x41,
|
250
|
+
0xc3, 0x5e, 0xe2, 0x3d, 0x47, 0xc9, 0x40, 0xc0,
|
251
|
+
0x5b, 0xed, 0x2c, 0x74, 0x9c, 0xbf, 0xda, 0x75,
|
252
|
+
0x9f, 0xba, 0xd5, 0x64, 0xac, 0xef, 0x2a, 0x7e,
|
253
|
+
0x82, 0x9d, 0xbc, 0xdf, 0x7a, 0x8e, 0x89, 0x80,
|
254
|
+
0x9b, 0xb6, 0xc1, 0x58, 0xe8, 0x23, 0x65, 0xaf,
|
255
|
+
0xea, 0x25, 0x6f, 0xb1, 0xc8, 0x43, 0xc5, 0x54,
|
256
|
+
0xfc, 0x1f, 0x21, 0x63, 0xa5, 0xf4, 0x07, 0x09,
|
257
|
+
0x1b, 0x2d, 0x77, 0x99, 0xb0, 0xcb, 0x46, 0xca,
|
258
|
+
0x45, 0xcf, 0x4a, 0xde, 0x79, 0x8b, 0x86, 0x91,
|
259
|
+
0xa8, 0xe3, 0x3e, 0x42, 0xc6, 0x51, 0xf3, 0x0e,
|
260
|
+
0x12, 0x36, 0x5a, 0xee, 0x29, 0x7b, 0x8d, 0x8c,
|
261
|
+
0x8f, 0x8a, 0x85, 0x94, 0xa7, 0xf2, 0x0d, 0x17,
|
262
|
+
0x39, 0x4b, 0xdd, 0x7c, 0x84, 0x97, 0xa2, 0xfd,
|
263
|
+
0x1c, 0x24, 0x6c, 0xb4, 0xc7, 0x52, 0xf6, 0x01]
|
264
|
+
|
265
|
+
GF256_LOG = [
|
266
|
+
0x00, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1a, 0xc6,
|
267
|
+
0x4b, 0xc7, 0x1b, 0x68, 0x33, 0xee, 0xdf, 0x03,
|
268
|
+
0x64, 0x04, 0xe0, 0x0e, 0x34, 0x8d, 0x81, 0xef,
|
269
|
+
0x4c, 0x71, 0x08, 0xc8, 0xf8, 0x69, 0x1c, 0xc1,
|
270
|
+
0x7d, 0xc2, 0x1d, 0xb5, 0xf9, 0xb9, 0x27, 0x6a,
|
271
|
+
0x4d, 0xe4, 0xa6, 0x72, 0x9a, 0xc9, 0x09, 0x78,
|
272
|
+
0x65, 0x2f, 0x8a, 0x05, 0x21, 0x0f, 0xe1, 0x24,
|
273
|
+
0x12, 0xf0, 0x82, 0x45, 0x35, 0x93, 0xda, 0x8e,
|
274
|
+
0x96, 0x8f, 0xdb, 0xbd, 0x36, 0xd0, 0xce, 0x94,
|
275
|
+
0x13, 0x5c, 0xd2, 0xf1, 0x40, 0x46, 0x83, 0x38,
|
276
|
+
0x66, 0xdd, 0xfd, 0x30, 0xbf, 0x06, 0x8b, 0x62,
|
277
|
+
0xb3, 0x25, 0xe2, 0x98, 0x22, 0x88, 0x91, 0x10,
|
278
|
+
0x7e, 0x6e, 0x48, 0xc3, 0xa3, 0xb6, 0x1e, 0x42,
|
279
|
+
0x3a, 0x6b, 0x28, 0x54, 0xfa, 0x85, 0x3d, 0xba,
|
280
|
+
0x2b, 0x79, 0x0a, 0x15, 0x9b, 0x9f, 0x5e, 0xca,
|
281
|
+
0x4e, 0xd4, 0xac, 0xe5, 0xf3, 0x73, 0xa7, 0x57,
|
282
|
+
0xaf, 0x58, 0xa8, 0x50, 0xf4, 0xea, 0xd6, 0x74,
|
283
|
+
0x4f, 0xae, 0xe9, 0xd5, 0xe7, 0xe6, 0xad, 0xe8,
|
284
|
+
0x2c, 0xd7, 0x75, 0x7a, 0xeb, 0x16, 0x0b, 0xf5,
|
285
|
+
0x59, 0xcb, 0x5f, 0xb0, 0x9c, 0xa9, 0x51, 0xa0,
|
286
|
+
0x7f, 0x0c, 0xf6, 0x6f, 0x17, 0xc4, 0x49, 0xec,
|
287
|
+
0xd8, 0x43, 0x1f, 0x2d, 0xa4, 0x76, 0x7b, 0xb7,
|
288
|
+
0xcc, 0xbb, 0x3e, 0x5a, 0xfb, 0x60, 0xb1, 0x86,
|
289
|
+
0x3b, 0x52, 0xa1, 0x6c, 0xaa, 0x55, 0x29, 0x9d,
|
290
|
+
0x97, 0xb2, 0x87, 0x90, 0x61, 0xbe, 0xdc, 0xfc,
|
291
|
+
0xbc, 0x95, 0xcf, 0xcd, 0x37, 0x3f, 0x5b, 0xd1,
|
292
|
+
0x53, 0x39, 0x84, 0x3c, 0x41, 0xa2, 0x6d, 0x47,
|
293
|
+
0x14, 0x2a, 0x9e, 0x5d, 0x56, 0xf2, 0xd3, 0xab,
|
294
|
+
0x44, 0x11, 0x92, 0xd9, 0x23, 0x20, 0x2e, 0x89,
|
295
|
+
0xb4, 0x7c, 0xb8, 0x26, 0x77, 0x99, 0xe3, 0xa5,
|
296
|
+
0x67, 0x4a, 0xed, 0xde, 0xc5, 0x31, 0xfe, 0x18,
|
297
|
+
0x0d, 0x63, 0x8c, 0x80, 0xc0, 0xf7, 0x70, 0x07]
|
298
|
+
|
299
|
+
|
300
|
+
def _gf256_add(a, b)
|
301
|
+
val = a ^ b
|
302
|
+
val
|
303
|
+
end
|
304
|
+
|
305
|
+
def _gf256_sub(a,b)
|
306
|
+
_gf256_add(a,b)
|
307
|
+
end
|
308
|
+
|
309
|
+
def _gf256_mul(a,b)
|
310
|
+
a = a.to_i
|
311
|
+
b = b.to_i
|
312
|
+
if a == 0 || b == 0
|
313
|
+
return 0
|
314
|
+
else
|
315
|
+
GF256_EXP[(GF256_LOG[a] + GF256_LOG[b]) % 255]
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
def _gf256_div(a,b)
|
320
|
+
if a == 0
|
321
|
+
return 0
|
322
|
+
elsif b == 0
|
323
|
+
raise ZeroDivisionError
|
324
|
+
else
|
325
|
+
GF256_EXP[(GF256_LOG[a] - GF256_LOG[b]) % 255]
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end # class ShamirSharing
|
329
|
+
|
330
|
+
end
|
331
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Ccrypto
|
4
|
+
module Ruby
|
5
|
+
class SecureRandomEngine
|
6
|
+
|
7
|
+
def self.random_bytes(size)
|
8
|
+
SecureRandom.random_bytes(size)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.random_hex(size)
|
12
|
+
SecureRandom.hex(size)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.random_b64(size)
|
16
|
+
SecureRandom.base64(size)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.random_uuid
|
20
|
+
SecureRandom.uuid
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.random_alphanum(size)
|
24
|
+
SecureRandom.alphanumeric(size)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.random_number(val = nil)
|
28
|
+
SecureRandom.rand(val)
|
29
|
+
end
|
30
|
+
self.singleton_class.alias_method :rand, :random_number
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Ccrypto
|
4
|
+
module Ruby
|
5
|
+
class X509Engine
|
6
|
+
include TR::CondUtils
|
7
|
+
|
8
|
+
include TeLogger::TeLogHelper
|
9
|
+
teLogger_tag :x509Eng
|
10
|
+
|
11
|
+
def initialize(cert_profile)
|
12
|
+
@certProfile = cert_profile
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate(issuerKey, &block)
|
16
|
+
|
17
|
+
cp = @certProfile
|
18
|
+
cert = OpenSSL::X509::Certificate.new
|
19
|
+
cert.version = 2
|
20
|
+
cert.serial = OpenSSL::BN.new(cp.serial, 16)
|
21
|
+
cert.subject = to_cert_subject
|
22
|
+
|
23
|
+
ext = OpenSSL::X509::ExtensionFactory.new
|
24
|
+
ext.subject_certificate = cert
|
25
|
+
|
26
|
+
iss = cp.issuer_cert
|
27
|
+
|
28
|
+
iss = iss.nativeX509 if iss.is_a?(Ccrypto::X509Cert)
|
29
|
+
|
30
|
+
if not_empty?(iss)
|
31
|
+
raise X509EngineException, "Issuer certificate must be X509 Certificate object" if not iss.is_a?(OpenSSL::X509::Certificate)
|
32
|
+
cert.issuer = iss.subject
|
33
|
+
ext.issuer_certificate = iss
|
34
|
+
|
35
|
+
cp.match_issuer_not_before(iss.not_before)
|
36
|
+
cp.match_issuer_not_after(iss.not_after)
|
37
|
+
|
38
|
+
else
|
39
|
+
cert.issuer = cert.subject
|
40
|
+
ext.issuer_certificate = cert
|
41
|
+
end
|
42
|
+
|
43
|
+
cert.not_before = cp.not_before
|
44
|
+
cert.not_after = cp.not_after
|
45
|
+
|
46
|
+
case cp.public_key
|
47
|
+
when Ccrypto::PublicKey
|
48
|
+
pubKey = cp.public_key.native_pubKey
|
49
|
+
else
|
50
|
+
raise X509EngineException, "Public key type '#{cp.public_key.class}' is not supported"
|
51
|
+
end
|
52
|
+
|
53
|
+
if pubKey.is_a?(OpenSSL::PKey::EC::Point)
|
54
|
+
# ECC patch
|
55
|
+
pub = OpenSSL::PKey::EC.new(pubKey.group)
|
56
|
+
pub.public_key = pubKey
|
57
|
+
cert.public_key = pub
|
58
|
+
else
|
59
|
+
cert.public_key = pubKey
|
60
|
+
end
|
61
|
+
|
62
|
+
cert.add_extension(ext.create_extension("basicConstraints","CA:TRUE",true)) if cp.gen_issuer_cert?
|
63
|
+
cert.add_extension(ext.create_extension("subjectKeyIdentifier","hash")) if cp.gen_subj_key_id?
|
64
|
+
cert.add_extension(ext.create_extension("authorityKeyIdentifier","keyid:always,issuer:always")) if cp.gen_auth_key_id?
|
65
|
+
|
66
|
+
#cert.add_extension(ext.create_extension("keyUsage",to_keyusage,true))
|
67
|
+
cp.key_usage.selected.each do |ku,critical|
|
68
|
+
teLogger.debug "Setting KeyUsage : #{ku} (#{critical})"
|
69
|
+
case ku
|
70
|
+
when :crlSign
|
71
|
+
cert.add_extension(ext.create_extension("keyUsage","cRLSign",critical))
|
72
|
+
else
|
73
|
+
cert.add_extension(ext.create_extension("keyUsage",ku.to_s,critical))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
#extKeyUsage = to_extkeyusage
|
79
|
+
extKeyUsage = []
|
80
|
+
cp.ext_key_usage.selected.each do |ku,critical|
|
81
|
+
case ku
|
82
|
+
when :allPurpose
|
83
|
+
#kur << :anyExtendedKeyUsage
|
84
|
+
cert.add_extension(ext.create_extension("extendedKeyUsage","anyExtendedKeyUsage",critical))
|
85
|
+
when :timestamping
|
86
|
+
#kur << :timeStamping
|
87
|
+
cert.add_extension(ext.create_extension("extendedKeyUsage","timeStamping",critical))
|
88
|
+
when :ocspSigning
|
89
|
+
#kur << :oCSPSigning
|
90
|
+
cert.add_extension(ext.create_extension("extendedKeyUsage","oCSPSigning",critical))
|
91
|
+
when :ipSecIKE
|
92
|
+
#kur << :ipsecIKE
|
93
|
+
cert.add_extension(ext.create_extension("extendedKeyUsage","ipsecIKE",critical))
|
94
|
+
when :msCtlsign
|
95
|
+
#kur << :msCTLSign
|
96
|
+
cert.add_extension(ext.create_extension("extendedKeyUsage","msCTLSign",critical))
|
97
|
+
when :msEFS
|
98
|
+
#kur << :msEfs
|
99
|
+
cert.add_extension(ext.create_extension("extendedKeyUsage","msEfs",critical))
|
100
|
+
else
|
101
|
+
#kur << ku
|
102
|
+
cert.add_extension(ext.create_extension("extendedKeyUsage",ku.to_s,critical))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
cp.domain_key_usage.each do |dku, critical|
|
107
|
+
cert.add_extension(ext.create_extension("extendedKeyUsage",dku.to_s,critical))
|
108
|
+
end
|
109
|
+
|
110
|
+
cert.add_extension(ext.create_extension("subjectAltName","email:#{cp.email.join(",email:")}",false)) if not_empty?(cp.email)
|
111
|
+
cert.add_extension(ext.create_extension("subjectAltName","DNS:#{cp.dns_name.join(",DNS:")}",false)) if not_empty?(cp.dns_name)
|
112
|
+
cert.add_extension(ext.create_extension("subjectAltName","IP:#{cp.ip_addr.join(",IP:")}",false)) if not_empty?(cp.ip_addr)
|
113
|
+
cert.add_extension(ext.create_extension("subjectAltName","URI:#{cp.uri.join(",URI:")}",false)) if not_empty?(cp.uri)
|
114
|
+
|
115
|
+
# try to sync the structure with Java BC output
|
116
|
+
# whereby single name = multiple URI however failed
|
117
|
+
# If single format is required need more R&D
|
118
|
+
#
|
119
|
+
#crlDistPoint = []
|
120
|
+
#if not_empty?(cp.crl_dist_point)
|
121
|
+
# cnt = 1
|
122
|
+
# cp.crl_dist_point.each do |cdp|
|
123
|
+
# crlDistPoint << "URI.#{cnt}:#{cdp}"
|
124
|
+
# cnt += 1
|
125
|
+
# end
|
126
|
+
#end
|
127
|
+
#p crlDistPoint.join(",")
|
128
|
+
#cert.add_extension(ext.create_extension("crlDistributionPoints","URI:#{crlDistPoint.join(",")}",false)) if not_empty?(crlDistPoint)
|
129
|
+
#
|
130
|
+
cert.add_extension(ext.create_extension("crlDistributionPoints","URI:#{cp.crl_dist_point.join(",URI:")}",false)) if not_empty?(cp.crl_dist_point)
|
131
|
+
|
132
|
+
aia = []
|
133
|
+
aia << "OCSP;URI:#{cp.ocsp_url.join(",OCSP;URI:")}" if not_empty?(cp.ocsp_url)
|
134
|
+
aia << "caIssuers;URI:#{cp.issuer_url.join(",caIssuers;URI:")}" if not_empty?(cp.issuer_url)
|
135
|
+
cert.add_extension(ext.create_extension("authorityInfoAccess",aia.join(","),false)) if not_empty?(aia)
|
136
|
+
|
137
|
+
|
138
|
+
case issuerKey
|
139
|
+
when Ccrypto::KeyBundle
|
140
|
+
privKey = issuerKey.private_key.native_privKey
|
141
|
+
when Ccrypto::PrivateKey
|
142
|
+
privKey = issuerKey.native_privKey
|
143
|
+
else
|
144
|
+
raise X509EngineException, "Unsupported issuer key #{issuerKey}"
|
145
|
+
end
|
146
|
+
|
147
|
+
res = cert.sign(privKey, DigestEngine.instance(cp.hashAlgo).native_instance)
|
148
|
+
|
149
|
+
Ccrypto::X509Cert.new(res)
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
def to_cert_subject
|
155
|
+
res = []
|
156
|
+
res << ["CN", @certProfile.owner_name]
|
157
|
+
res << ["O", @certProfile.org] if not_empty?(@certProfile.org)
|
158
|
+
@certProfile.org_unit.each do |ou|
|
159
|
+
res << ["OU", ou]
|
160
|
+
end
|
161
|
+
|
162
|
+
e = @certProfile.email.first
|
163
|
+
if not_empty?(e)
|
164
|
+
res << ["emailAddress", e]
|
165
|
+
end
|
166
|
+
|
167
|
+
OpenSSL::X509::Name.new(res)
|
168
|
+
end
|
169
|
+
|
170
|
+
#def to_keyusage
|
171
|
+
# kur = []
|
172
|
+
# @certProfile.key_usage.selected.each do |ku,critical|
|
173
|
+
# case ku
|
174
|
+
# when :crlSign
|
175
|
+
# cert.add_extension(ext.create_extension("keyUsage",:cRLSign,critical))
|
176
|
+
# #kur << :cRLSign
|
177
|
+
# else
|
178
|
+
# #kur << ku
|
179
|
+
# cert.add_extension(ext.create_extension("keyUsage",ku,critical))
|
180
|
+
# end
|
181
|
+
# end
|
182
|
+
|
183
|
+
# #kur.join(",")
|
184
|
+
#end
|
185
|
+
|
186
|
+
#def to_extkeyusage
|
187
|
+
# kur = []
|
188
|
+
# @certProfile.ext_key_usage.selected.keys.each do |ku|
|
189
|
+
# case ku
|
190
|
+
# when :allPurpose
|
191
|
+
# kur << :anyExtendedKeyUsage
|
192
|
+
# when :timestamping
|
193
|
+
# kur << :timeStamping
|
194
|
+
# when :ocspSigning
|
195
|
+
# kur << :oCSPSigning
|
196
|
+
# when :ipSecIKE
|
197
|
+
# kur << :ipsecIKE
|
198
|
+
# when :msCtlsign
|
199
|
+
# kur << :msCTLSign
|
200
|
+
# when :msEFS
|
201
|
+
# kur << :msEfs
|
202
|
+
# else
|
203
|
+
# kur << ku
|
204
|
+
# end
|
205
|
+
# end
|
206
|
+
|
207
|
+
# #kur.join(",")
|
208
|
+
# kur
|
209
|
+
#end
|
210
|
+
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Ccrypto
|
4
|
+
class X509Cert
|
5
|
+
include TR::CondUtils
|
6
|
+
|
7
|
+
def equal?(cert)
|
8
|
+
if is_empty?(cert)
|
9
|
+
if is_empty?(@nativeX509)
|
10
|
+
true
|
11
|
+
else
|
12
|
+
false
|
13
|
+
end
|
14
|
+
else
|
15
|
+
@nativeX509.to_der == cert.to_der
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(mtd, *args, &block)
|
20
|
+
@nativeX509.send(mtd, *args, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Ccrypto
|
4
|
+
module Ruby
|
5
|
+
module PEMStore
|
6
|
+
include TR::CondUtils
|
7
|
+
include DataConversion
|
8
|
+
|
9
|
+
class PEMStoreException < KeyBundleStorageException; end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def is_pem?(input)
|
13
|
+
if is_empty?(input)
|
14
|
+
false
|
15
|
+
else
|
16
|
+
begin
|
17
|
+
(input =~ /BEGIN/) != nil
|
18
|
+
rescue ArgumentError => ex
|
19
|
+
if ex.message =~ /invalid byte sequence/
|
20
|
+
false
|
21
|
+
else
|
22
|
+
raise KeypairEngineException, ex
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def from_pem(input, &block)
|
29
|
+
|
30
|
+
begin
|
31
|
+
# try with no password first to check if the keystore is really encrypted
|
32
|
+
# If not the library will prompt at command prompt which might halt the flow of program
|
33
|
+
pKey = OpenSSL::PKey.read(input,"")
|
34
|
+
ECCKeyBundle.new(pKey)
|
35
|
+
rescue OpenSSL::PKey::PKeyError => ex
|
36
|
+
raise PEMStoreException, "block is required" if not block
|
37
|
+
pass = block.call(:pem_pass)
|
38
|
+
begin
|
39
|
+
pKey = OpenSSL::PKey.read(input, pass)
|
40
|
+
ECCKeyBundle.new(pKey)
|
41
|
+
rescue OpenSSL::PKey::PKeyError => exx
|
42
|
+
raise PEMStoreException, exx
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
def self.included(klass)
|
49
|
+
klass.extend(ClassMethods)
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_pem(&block)
|
53
|
+
raise PEMStoreException, "Block is required" if not block
|
54
|
+
kcipher = block.call(:pem_cipher)
|
55
|
+
kpass = block.call(:pem_pass)
|
56
|
+
|
57
|
+
kcipher = "AES-256-GCM" if is_empty?(kcipher)
|
58
|
+
|
59
|
+
keypair = block.call(:keypair)
|
60
|
+
raise PEMStoreException, "Keypair is required" if is_empty?(keypair)
|
61
|
+
|
62
|
+
if not_empty?(kpass)
|
63
|
+
kCipher = OpenSSL::Cipher.new(kcipher)
|
64
|
+
keypair.export(kCipher, kpass)
|
65
|
+
else
|
66
|
+
keypair.export
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|