pkernel_jce 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.ruby-version +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +56 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/jars/bcmail-jdk15on-157.jar +0 -0
- data/jars/bcpg-jdk15on-157.jar +0 -0
- data/jars/bcpkix-jdk15on-157.jar +0 -0
- data/jars/bcprov-ext-jdk15on-157.jar +0 -0
- data/jars/bcprov-jdk15on-157.jar +0 -0
- data/lib/pkernel_jce/bc_helpers.rb +51 -0
- data/lib/pkernel_jce/certificate.rb +467 -0
- data/lib/pkernel_jce/certificate_owner.rb +90 -0
- data/lib/pkernel_jce/crl.rb +221 -0
- data/lib/pkernel_jce/csr.rb +126 -0
- data/lib/pkernel_jce/error.rb +7 -0
- data/lib/pkernel_jce/global.rb +17 -0
- data/lib/pkernel_jce/identity.rb +333 -0
- data/lib/pkernel_jce/io_utils.rb +45 -0
- data/lib/pkernel_jce/keypair.rb +359 -0
- data/lib/pkernel_jce/ocsp.rb +415 -0
- data/lib/pkernel_jce/provider.rb +40 -0
- data/lib/pkernel_jce/rfc3161.rb +389 -0
- data/lib/pkernel_jce/utils.rb +59 -0
- data/lib/pkernel_jce/version.rb +3 -0
- data/lib/pkernel_jce.rb +102 -0
- data/pkernel_jce.gemspec +45 -0
- metadata +146 -0
@@ -0,0 +1,467 @@
|
|
1
|
+
|
2
|
+
require 'pkernel'
|
3
|
+
require_relative 'provider'
|
4
|
+
require_relative 'utils'
|
5
|
+
require_relative 'global'
|
6
|
+
require_relative 'error'
|
7
|
+
require_relative 'certificate_owner'
|
8
|
+
|
9
|
+
require 'active_support/core_ext/time'
|
10
|
+
|
11
|
+
|
12
|
+
module PkernelJce
|
13
|
+
module Certificate
|
14
|
+
|
15
|
+
module KeyUsage
|
16
|
+
# bouncycastle v1.57
|
17
|
+
DIGITAL_SIGNATURE = Java::OrgBouncycastleAsn1X509::KeyUsage::digitalSignature
|
18
|
+
NON_REPUDIATION = Java::OrgBouncycastleAsn1X509::KeyUsage::nonRepudiation
|
19
|
+
KEY_ENCIPHERMENT = Java::OrgBouncycastleAsn1X509::KeyUsage::keyEncipherment
|
20
|
+
DATA_ENCIPHERMENT = Java::OrgBouncycastleAsn1X509::KeyUsage::dataEncipherment
|
21
|
+
KEY_AGREEMENT = Java::OrgBouncycastleAsn1X509::KeyUsage::keyAgreement
|
22
|
+
KEY_CERT_SIGN = Java::OrgBouncycastleAsn1X509::KeyUsage::keyCertSign
|
23
|
+
CRL_SIGN = Java::OrgBouncycastleAsn1X509::KeyUsage::cRLSign
|
24
|
+
# only meaningful of KEY_AGREEMENT is set
|
25
|
+
ENCIPHER_ONLY = Java::OrgBouncycastleAsn1X509::KeyUsage::encipherOnly
|
26
|
+
DECIPHER_ONLY = Java::OrgBouncycastleAsn1X509::KeyUsage::decipherOnly
|
27
|
+
|
28
|
+
DEF_USER_IDENTITY = DIGITAL_SIGNATURE | NON_REPUDIATION | KEY_ENCIPHERMENT | KEY_AGREEMENT
|
29
|
+
DEF_USER_DATA_SEC = DATA_ENCIPHERMENT | ENCIPHER_ONLY | DECIPHER_ONLY
|
30
|
+
DEF_ISSUER = DIGITAL_SIGNATURE | NON_REPUDIATION | KEY_ENCIPHERMENT | CRL_SIGN | KEY_CERT_SIGN
|
31
|
+
end
|
32
|
+
# end module CertKeyUsage
|
33
|
+
|
34
|
+
module ExtKeyUsage
|
35
|
+
ANY_EXT_KEY_USAGE = org.bouncycastle.asn1.x509.KeyPurposeId::anyExtendedKeyUsage
|
36
|
+
TLS_SERVER_AUTH = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_serverAuth
|
37
|
+
TLS_CLIENT_AUTH = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_clientAuth
|
38
|
+
CODE_SIGNING = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_codeSigning
|
39
|
+
EMAIL_PROTECTION = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_emailProtection
|
40
|
+
TIMESTAMPING = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_timeStamping
|
41
|
+
OCSP_SIGNING = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_OCSPSigning
|
42
|
+
DVCS = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_dvcs
|
43
|
+
SPGP_CERT_AA_SERVER_AUTH = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_sbgpCertAAServerAuth
|
44
|
+
end
|
45
|
+
# end CertExtKeyUsage
|
46
|
+
|
47
|
+
|
48
|
+
def generate(params = {}, &block)
|
49
|
+
|
50
|
+
raise PkernelJce::Error, "Block is required for certificate generation function" if block.nil?
|
51
|
+
|
52
|
+
PkernelJce::GConf.instance.glog.debug "Certificate generate parameters: #{params.inspect}"
|
53
|
+
owner = params[:owner]
|
54
|
+
pubKey = params[:pubKey]
|
55
|
+
serial = params[:serial]
|
56
|
+
kProv = params[:keypair_provider]
|
57
|
+
cProv = params[:cert_provider]
|
58
|
+
issuer = params[:issuer]
|
59
|
+
matchIssuerValidity = params[:match_issuer_validity] || true
|
60
|
+
|
61
|
+
issuer = false if issuer.nil?
|
62
|
+
|
63
|
+
pubKey = PkernelJce::KeyPair.public_key(pubKey)
|
64
|
+
|
65
|
+
if cProv.nil?
|
66
|
+
cProv = PkernelJce::Provider.add_provider(PkernelJce::Provider::DefProvider)
|
67
|
+
else
|
68
|
+
cProv = PkernelJce::Provider.add_provider(cProv)
|
69
|
+
end
|
70
|
+
|
71
|
+
if kProv.nil?
|
72
|
+
kProv = PkernelJce::Provider.add_provider(PkernelJce::Provider::DefProvider)
|
73
|
+
else
|
74
|
+
kProv = PkernelJce::Provider.add_provider(kProv)
|
75
|
+
end
|
76
|
+
|
77
|
+
extUtils = org.bouncycastle.cert.bc.BcX509ExtensionUtils.new
|
78
|
+
|
79
|
+
if serial.nil? or serial.empty?
|
80
|
+
serial = block.call(:serial)
|
81
|
+
end
|
82
|
+
|
83
|
+
if serial.is_a?(java.math.BigInteger)
|
84
|
+
else
|
85
|
+
serial = java.math.BigInteger.new(serial,16)
|
86
|
+
end
|
87
|
+
|
88
|
+
signHash = block.call(:signHash)
|
89
|
+
issuerKey = block.call(:issuerKey)
|
90
|
+
issuerCert = block.call(:issuerCert)
|
91
|
+
|
92
|
+
issuerKey = PkernelJce::KeyPair.private_key(issuerKey)
|
93
|
+
if issuerKey.nil?
|
94
|
+
raise PkernelJce::Error, "Issuer key cannot be nil"
|
95
|
+
end
|
96
|
+
|
97
|
+
signAlgo = PkernelJce::KeyPair.derive_signing_algo(issuerKey, signHash)
|
98
|
+
signer = org.bouncycastle.operator.jcajce.JcaContentSignerBuilder.new(signAlgo).setProvider(kProv).build(issuerKey)
|
99
|
+
x500Name = owner.to_x500_subject
|
100
|
+
|
101
|
+
if not issuerCert.nil?
|
102
|
+
|
103
|
+
issuerCert = issuerCert.to_java_cert if issuerCert.java_kind_of?(org.bouncycastle.cert.X509CertificateHolder)
|
104
|
+
|
105
|
+
validFrom, validTo = calculate_validity(params) do |from, to|
|
106
|
+
if matchIssuerValidity
|
107
|
+
|
108
|
+
PkernelJce::GConf.instance.glog.debug "Match issuer validity against issuer certificate is activated."
|
109
|
+
PkernelJce::GConf.instance.glog.debug "Issuer Cert : #{issuerCert.subject_dn.to_s} / #{issuerCert.not_before} / #{issuerCert.not_after}"
|
110
|
+
|
111
|
+
if from.to_java_date.before(issuerCert.not_before)
|
112
|
+
PkernelJce::GConf.instance.glog.warn "Certificate valid from has adjusted to match issuer valid from: #{from} [User requested] / #{issuerCert.not_before} [Adjusted to issuer]"
|
113
|
+
from = issuerCert.not_before
|
114
|
+
end
|
115
|
+
|
116
|
+
if to.to_java_date.after(issuerCert.not_after)
|
117
|
+
PkernelJce::GConf.instance.glog.warn "Certificate valid to has adjusted to match issuer valid to: #{to} [User requested] / #{issuerCert.not_after} [Adjusted to issuer]"
|
118
|
+
to = issuerCert.not_after
|
119
|
+
end
|
120
|
+
|
121
|
+
[from, to]
|
122
|
+
else
|
123
|
+
[from, to]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
certGen = org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder.new(issuerCert, serial, validFrom, validTo, x500Name, pubKey)
|
128
|
+
# generate authority key identifier
|
129
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getInstance(issuerCert.getPublicKey.getEncoded)))
|
130
|
+
else
|
131
|
+
|
132
|
+
validFrom, validTo = calculate_validity(params)
|
133
|
+
|
134
|
+
certGen = org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder.new(x500Name, serial, validFrom, validTo, x500Name, pubKey)
|
135
|
+
# generate authority key identifier
|
136
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getInstance(pubKey.getEncoded)))
|
137
|
+
end
|
138
|
+
|
139
|
+
keyUsage = block.call(:keyUsage)
|
140
|
+
if issuer
|
141
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::basicConstraints, true, org.bouncycastle.asn1.x509.BasicConstraints.new(true))
|
142
|
+
if not keyUsage.nil?
|
143
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::keyUsage, false, org.bouncycastle.asn1.x509.KeyUsage.new(keyUsage))
|
144
|
+
else
|
145
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::keyUsage, false, org.bouncycastle.asn1.x509.KeyUsage.new(KeyUsage::DEF_ISSUER))
|
146
|
+
end
|
147
|
+
else
|
148
|
+
if not keyUsage.nil?
|
149
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::keyUsage, false, org.bouncycastle.asn1.x509.KeyUsage.new(keyUsage))
|
150
|
+
else
|
151
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::keyUsage, false, org.bouncycastle.asn1.x509.KeyUsage.new(KeyUsage::DEF_USER_IDENTITY))
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
extKeyUsage = block.call(:extKeyUsage)
|
156
|
+
if not extKeyUsage.nil?
|
157
|
+
if extKeyUsage.is_a?(Hash)
|
158
|
+
# allow user to give eku -> true/false
|
159
|
+
# Since timestamping required this extension to be true, not sure others
|
160
|
+
extKeyUsage.each do |k,v|
|
161
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::extendedKeyUsage, v, org.bouncycastle.asn1.x509.ExtendedKeyUsage.new(k))
|
162
|
+
end
|
163
|
+
elsif extKeyUsage.is_a?(Array)
|
164
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::extendedKeyUsage, false, org.bouncycastle.asn1.x509.ExtendedKeyUsage.new(extKeyUsage.to_vector))
|
165
|
+
else
|
166
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::extendedKeyUsage, false, org.bouncycastle.asn1.x509.ExtendedKeyUsage.new([extKeyUsage].to_vector))
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
#
|
171
|
+
# handle alternative name
|
172
|
+
#
|
173
|
+
altName = []
|
174
|
+
if owner.emails.length > 0
|
175
|
+
owner.emails.each do |e|
|
176
|
+
altName << org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName::rfc822Name,e)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
owner.dns_names.each do |n|
|
181
|
+
altName << org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName::dNSName,n)
|
182
|
+
end
|
183
|
+
|
184
|
+
if altName.length > 0
|
185
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::subjectAlternativeName, false, org.bouncycastle.asn1.x509.GeneralNames.new(altName.to_java(org.bouncycastle.asn1.x509.GeneralName)) )
|
186
|
+
end
|
187
|
+
#
|
188
|
+
# Done alternative name
|
189
|
+
#
|
190
|
+
|
191
|
+
#
|
192
|
+
# handle CRL distribution point
|
193
|
+
#
|
194
|
+
crl = block.call(:crls)
|
195
|
+
if not crl.nil?
|
196
|
+
crls = []
|
197
|
+
if crl.is_a?(Array)
|
198
|
+
crl.each do |c|
|
199
|
+
crls << org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName::uniformResourceIdentifier, org.bouncycastle.asn1.DERIA5String.new(c));
|
200
|
+
end
|
201
|
+
gns = org.bouncycastle.asn1.x509.GeneralNames.new(crls.to_java(org.bouncycastle.asn1.x509.GeneralName));
|
202
|
+
else
|
203
|
+
gn = org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName::uniformResourceIdentifier, org.bouncycastle.asn1.DERIA5String.new(crl));
|
204
|
+
gns = org.bouncycastle.asn1.x509.GeneralNames.new(gn);
|
205
|
+
end
|
206
|
+
|
207
|
+
dpn = org.bouncycastle.asn1.x509.DistributionPointName.new(gns);
|
208
|
+
dp = org.bouncycastle.asn1.x509.DistributionPoint.new(dpn,nil,nil);
|
209
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.X509Extensions::CRLDistributionPoints,false,org.bouncycastle.asn1.DERSequence.new(dp));
|
210
|
+
end
|
211
|
+
# done adding CRL distribution point
|
212
|
+
|
213
|
+
|
214
|
+
#
|
215
|
+
# handle OCSP
|
216
|
+
#
|
217
|
+
ocsp = block.call(:ocsp)
|
218
|
+
if not ocsp.nil? and not ocsp.empty?
|
219
|
+
ocspName = org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName.uniformResourceIdentifier, ocsp);
|
220
|
+
authorityInformationAccess = org.bouncycastle.asn1.x509.AuthorityInformationAccess.new(org.bouncycastle.asn1.x509.X509ObjectIdentifiers.ocspAccessMethod, ocspName);
|
221
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.X509Extensions::AuthorityInfoAccess, false, authorityInformationAccess);
|
222
|
+
end
|
223
|
+
# done OCSP
|
224
|
+
|
225
|
+
# Let's generate subject key ID as default...
|
226
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getInstance(pubKey.getEncoded)))
|
227
|
+
|
228
|
+
cert = org.bouncycastle.cert.jcajce.JcaX509CertificateConverter.new().setProvider(cProv).getCertificate(certGen.build(signer))
|
229
|
+
cert
|
230
|
+
|
231
|
+
end
|
232
|
+
# end generate
|
233
|
+
|
234
|
+
def dump(cert, params = {})
|
235
|
+
if cert.nil?
|
236
|
+
raise PkernelJce::Error, "Certificate object to be written is nil"
|
237
|
+
end
|
238
|
+
|
239
|
+
file = params[:file]
|
240
|
+
baos = java.io.ByteArrayOutputStream.new
|
241
|
+
|
242
|
+
if not file.nil?
|
243
|
+
PkernelJce::GConf.instance.glog.debug "Dump certificate to file '#{file}'"
|
244
|
+
writer = org.bouncycastle.openssl.jcajce.JcaPEMWriter.new(java.io.OutputStreamWriter.new(java.io.FileOutputStream.new(file)))
|
245
|
+
else
|
246
|
+
PkernelJce::GConf.instance.glog.debug "Dump certificate to memory"
|
247
|
+
writer = org.bouncycastle.openssl.jcajce.JcaPEMWriter.new(java.io.OutputStreamWriter.new(baos))
|
248
|
+
end
|
249
|
+
|
250
|
+
begin
|
251
|
+
writer.writeObject(cert)
|
252
|
+
ensure
|
253
|
+
writer.flush
|
254
|
+
writer.close
|
255
|
+
end
|
256
|
+
|
257
|
+
if file.nil?
|
258
|
+
baos.toByteArray
|
259
|
+
end
|
260
|
+
|
261
|
+
end
|
262
|
+
# end write to
|
263
|
+
|
264
|
+
|
265
|
+
def load(options = {})
|
266
|
+
#is = options[:inputStream]
|
267
|
+
#if is.nil?
|
268
|
+
# raise PkernelJce::Error, "InputStream to load certificate is nil"
|
269
|
+
#end
|
270
|
+
|
271
|
+
file = options[:file]
|
272
|
+
bin = options[:bin]
|
273
|
+
baos = java.io.ByteArrayOutputStream.new
|
274
|
+
|
275
|
+
if not file.nil? and not file.empty?
|
276
|
+
PkernelJce::GConf.instance.glog.debug "Load certificate from #{file}"
|
277
|
+
f = java.io.File.new(file)
|
278
|
+
if f.exists?
|
279
|
+
b = Java::byte[f.length].new
|
280
|
+
dis = java.io.DataInputStream.new(java.io.FileInputStream.new(f))
|
281
|
+
dis.readFully(b)
|
282
|
+
dis.close
|
283
|
+
|
284
|
+
baos.write(b)
|
285
|
+
else
|
286
|
+
raise PkernelJce::Error, "File '#{f.absolute_path}' not found"
|
287
|
+
end
|
288
|
+
|
289
|
+
elsif not bin.nil?
|
290
|
+
PkernelJce::GConf.instance.glog.debug "Load certificate from memory"
|
291
|
+
baos.write(bin)
|
292
|
+
else
|
293
|
+
raise PkernelJce::Error, "No bin or file input is given to load"
|
294
|
+
end
|
295
|
+
|
296
|
+
reader = org.bouncycastle.openssl.PEMParser.new(java.io.InputStreamReader.new(java.io.ByteArrayInputStream.new(baos.toByteArray)))
|
297
|
+
obj = reader.readObject
|
298
|
+
# object here shall be org.bouncycastle.cert.X509CertificateHolder
|
299
|
+
# Hence other place using Java Certificate object shall call to_java_cert on this object
|
300
|
+
obj
|
301
|
+
#org.bouncycastle.cert.jcajce.JcaX509CertificateConverter.new.setProvider(PkernelJce::Provider::DefProvider).getCertificate(obj)
|
302
|
+
end
|
303
|
+
# end read_from
|
304
|
+
|
305
|
+
def Certificate.is_self_signed?(cert)
|
306
|
+
if cert.nil?
|
307
|
+
false
|
308
|
+
else
|
309
|
+
begin
|
310
|
+
cert.verify(cert.public_key)
|
311
|
+
true
|
312
|
+
rescue Exception
|
313
|
+
false
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def Certificate.is_issuer_cert?(cert)
|
319
|
+
if cert.nil?
|
320
|
+
false
|
321
|
+
else
|
322
|
+
cert = Certificate.ensure_java_cert(cert)
|
323
|
+
(cert.getKeyUsage[5] and cert.getBasicConstraints != -1)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
# end is_issuer_cert?
|
327
|
+
|
328
|
+
def Certificate.ensure_java_cert(cert)
|
329
|
+
if cert.nil?
|
330
|
+
raise PkernelJce::Error, "Certificate for conversion to java is nil"
|
331
|
+
else
|
332
|
+
case cert
|
333
|
+
when java.security.cert.Certificate
|
334
|
+
cert
|
335
|
+
when Java::OrgBouncycastleCert::X509CertificateHolder
|
336
|
+
cert.to_java_cert
|
337
|
+
else
|
338
|
+
raise PkernelJce::Error, "Unknown certificate type '#{cert.class}'"
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
Certificate.singleton_class.send(:alias_method, :to_java_cert, :ensure_java_cert)
|
343
|
+
# end ensure_java_cert
|
344
|
+
|
345
|
+
def Certificate.ensure_bc_cert(cert)
|
346
|
+
if cert.nil?
|
347
|
+
raise PkernelJce::Error, "Certificate for conversion to bc is nil"
|
348
|
+
else
|
349
|
+
if cert.is_a?(Array)
|
350
|
+
cert.map! do |c|
|
351
|
+
case c
|
352
|
+
when java.security.cert.Certificate
|
353
|
+
c.to_bc_cert_holder
|
354
|
+
when Java::OrgBouncycastleCert::X509CertificateHolder
|
355
|
+
c
|
356
|
+
else
|
357
|
+
raise PkernelJce::Error, "Unknown certificate type '#{c.class}'"
|
358
|
+
end
|
359
|
+
end
|
360
|
+
cert
|
361
|
+
else
|
362
|
+
case cert
|
363
|
+
when java.security.cert.Certificate
|
364
|
+
cert.to_bc_cert_holder
|
365
|
+
when Java::OrgBouncycastleCert::X509CertificateHolder
|
366
|
+
cert
|
367
|
+
else
|
368
|
+
raise PkernelJce::Error, "Unknown certificate type '#{cert.class}'"
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
Certificate.singleton_class.send(:alias_method, :to_bc_cert, :ensure_bc_cert)
|
374
|
+
# end ensure_bc_cert
|
375
|
+
#
|
376
|
+
|
377
|
+
def Certificate.public_key(cert)
|
378
|
+
if cert.nil?
|
379
|
+
raise PkernelJce::Error, "Object pass to public_key on certificate is nil"
|
380
|
+
end
|
381
|
+
|
382
|
+
case cert
|
383
|
+
when java.security.cert.Certificate
|
384
|
+
cert.public_key
|
385
|
+
when Java::OrgBouncycastleCert::X509CertificateHolder
|
386
|
+
PkernelJce::KeyPair.public_key(cert.subject_public_key_info)
|
387
|
+
else
|
388
|
+
raise PkernelJce::Error, "Unknown certificate type '#{cert.class}'"
|
389
|
+
end
|
390
|
+
|
391
|
+
end
|
392
|
+
|
393
|
+
def Certificate.is_cert_object?(obj)
|
394
|
+
if obj.nil?
|
395
|
+
false
|
396
|
+
else
|
397
|
+
case obj
|
398
|
+
when java.security.cert.Certificate, Java::OrgBouncycastleCert::X509CertificateHolder, Java::OrgBouncycastleJcajceProviderAsymmetricX509::X509CertificateObject
|
399
|
+
true
|
400
|
+
else
|
401
|
+
false
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
def Certificate.is_ext_key_usage_set?(cert, eku)
|
407
|
+
raise PkernelJce::Error, "Certificate not given to check eku." if cert.nil?
|
408
|
+
|
409
|
+
c = Certificate.to_bc_cert(cert)
|
410
|
+
ext = c.getExtension(org.bouncycastle.asn1.x509.Extension.extendedKeyUsage)
|
411
|
+
extKey = org.bouncycastle.asn1.x509.ExtendedKeyUsage.getInstance(ext.getParsedValue)
|
412
|
+
|
413
|
+
extKey.hasKeyPurposeId(eku)
|
414
|
+
end
|
415
|
+
|
416
|
+
private
|
417
|
+
#
|
418
|
+
# all date must be in Ruby datetime object?
|
419
|
+
#
|
420
|
+
def calculate_validity(params, &block)
|
421
|
+
validFrom = params[:validFrom]
|
422
|
+
validTo = params[:validTo]
|
423
|
+
validity = params[:validity] || 2
|
424
|
+
validityUnit = params[:validityUnit] || :years
|
425
|
+
|
426
|
+
validity = validity.to_i
|
427
|
+
|
428
|
+
if validFrom.nil?
|
429
|
+
raise PkernelJce::Error, "Valid from has to be given."
|
430
|
+
end
|
431
|
+
|
432
|
+
if validFrom.is_a?(Time) #or validFrom.is_a?(DateTime)
|
433
|
+
else
|
434
|
+
raise PkernelJce::Error, "Invalid valid from date object type : '#{validFrom.class}'"
|
435
|
+
end
|
436
|
+
|
437
|
+
if validTo.nil? or validTo.empty?
|
438
|
+
if (validity.nil?) and (validityUnit.nil?)
|
439
|
+
raise PkernelJce::Error, "Valid until and validity period both are not defined."
|
440
|
+
else
|
441
|
+
validTo = validFrom.advance( validityUnit => validity )
|
442
|
+
if block
|
443
|
+
# allow caller to check with issuer validity see if the valid to already surpass issuer's valid to
|
444
|
+
#validTo = block.call(validFrom, validTo)
|
445
|
+
validFrom, validTo = block.call(validFrom, validTo)
|
446
|
+
end
|
447
|
+
end
|
448
|
+
elsif validTo.is_a?(Time) or validTo.is_a?(DateTime)
|
449
|
+
else
|
450
|
+
raise PkernelJce::Error, "Invalid valid to date object type : '#{validTo.class}'"
|
451
|
+
end
|
452
|
+
|
453
|
+
[validFrom, validTo]
|
454
|
+
|
455
|
+
end
|
456
|
+
|
457
|
+
end
|
458
|
+
# end module certificate
|
459
|
+
|
460
|
+
|
461
|
+
class CertificateEngine
|
462
|
+
extend Certificate
|
463
|
+
end
|
464
|
+
|
465
|
+
|
466
|
+
end
|
467
|
+
|
@@ -0,0 +1,90 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
require 'pkernel'
|
6
|
+
require_relative 'csr'
|
7
|
+
require_relative 'global'
|
8
|
+
|
9
|
+
|
10
|
+
class Pkernel::Certificate::Owner
|
11
|
+
|
12
|
+
def to_x500_subject
|
13
|
+
|
14
|
+
PkernelJce::Provider.add_default
|
15
|
+
builder = Java::OrgBouncycastleAsn1X500::X500NameBuilder.new
|
16
|
+
builder.addRDN(Java::OrgBouncycastleAsn1X500Style::BCStyle::CN, @name)
|
17
|
+
|
18
|
+
builder.addRDN(Java::OrgBouncycastleAsn1X500Style::BCStyle::O, @org) if @org != nil and not @org.empty?
|
19
|
+
builder.addRDN(Java::OrgBouncycastleAsn1X500Style::BCStyle::OU, @orgUnit) if @orgUnit != nil and not @orgUnit.empty?
|
20
|
+
builder.addRDN(Java::OrgBouncycastleAsn1X500Style::BCStyle::SN, @serial) if @serial != nil and not @serial.empty?
|
21
|
+
|
22
|
+
# this should not be here...
|
23
|
+
if @emails.length > 0
|
24
|
+
builder.addRDN(Java::OrgBouncycastleAsn1X500Style::BCStyle::EmailAddress, @emails[0])
|
25
|
+
end
|
26
|
+
|
27
|
+
builder.build
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.parse_x500_subject(subject, &block)
|
32
|
+
if block
|
33
|
+
else
|
34
|
+
raise PkernelJce::Error, "Block required to parse x500 subject"
|
35
|
+
end
|
36
|
+
|
37
|
+
subject.getRDNs.each do |rd|
|
38
|
+
rd.getTypesAndValues.each do |tv|
|
39
|
+
case tv.type
|
40
|
+
when Java::OrgBouncycastleAsn1X500Style::BCStyle::CN
|
41
|
+
block.call(:cn, tv.value.string)
|
42
|
+
when Java::OrgBouncycastleAsn1X500Style::BCStyle::O
|
43
|
+
block.call(:o, tv.value.string)
|
44
|
+
when Java::OrgBouncycastleAsn1X500Style::BCStyle::OU
|
45
|
+
block.call(:ou, tv.value.string)
|
46
|
+
when Java::OrgBouncycastleAsn1X500Style::BCStyle::SN
|
47
|
+
block.call(:serial, tv.value.string)
|
48
|
+
when Java::OrgBouncycastleAsn1X500Style::BCStyle::EmailAddress
|
49
|
+
block.call(:email, tv.value.string)
|
50
|
+
else
|
51
|
+
PkernelJce::GConf.instance.glog.warn "Uncaught key-value in subject parsing '#{tv.type}-#{tv.value}'"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
# from_x500_subject
|
57
|
+
|
58
|
+
# assumption: CSR here already in object of PKCS10CertificationRequest
|
59
|
+
def self.from_p10(csr)
|
60
|
+
if csr.nil?
|
61
|
+
raise PkernelJce::Error, "Cannot load CSR from nil"
|
62
|
+
end
|
63
|
+
|
64
|
+
if PkernelJce::CSRProxy.is_signature_valid?(csr)
|
65
|
+
owner = Pkernel::Certificate::Owner.new
|
66
|
+
parse_x500_subject(csr.subject) do |k,v|
|
67
|
+
case k
|
68
|
+
when :cn
|
69
|
+
owner.name = v
|
70
|
+
when :o
|
71
|
+
owner.org = v
|
72
|
+
when :ou
|
73
|
+
owner.orgUnit = v
|
74
|
+
when :serial
|
75
|
+
owner.serial = v
|
76
|
+
when :email
|
77
|
+
owner.emails << v
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
owner
|
82
|
+
else
|
83
|
+
raise PkernelJce::Error, "Signature of CSR is not valid"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
# load_from_csr
|
87
|
+
|
88
|
+
end
|
89
|
+
# end class Owner
|
90
|
+
|