ccrypto-java 0.1.0 → 0.2.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 +4 -4
- data/.java-version +1 -1
- data/.release_history.yml +4 -0
- data/.ruby-version +1 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +68 -53
- data/Rakefile +2 -1
- data/bin/console +14 -0
- data/jars/bcjmail-jdk18on-172.jar +0 -0
- data/jars/bcmail-jdk18on-172.jar +0 -0
- data/jars/bcpg-jdk18on-172.1.jar +0 -0
- data/jars/bcpkix-jdk18on-172.jar +0 -0
- data/jars/bcprov-ext-jdk18on-172.jar +0 -0
- data/jars/bcprov-jdk18on-172.jar +0 -0
- data/jars/bctls-jdk18on-172.jar +0 -0
- data/jars/bcutil-jdk18on-172.jar +0 -0
- data/lib/ccrypto/java/bc_const_mapping.rb +42 -0
- data/lib/ccrypto/java/data_conversion.rb +23 -2
- data/lib/ccrypto/java/engines/argon2_engine.rb +95 -0
- data/lib/ccrypto/java/engines/asn1_engine.rb +2 -1
- data/lib/ccrypto/java/engines/bcrypt_engine.rb +56 -0
- data/lib/ccrypto/java/engines/cipher_engine.rb +462 -130
- data/lib/ccrypto/java/engines/compression_engine.rb +7 -28
- data/lib/ccrypto/java/engines/crystal_dilithium_engine.rb +226 -0
- data/lib/ccrypto/java/engines/crystal_kyber_engine.rb +260 -0
- data/lib/ccrypto/java/engines/decompression_engine.rb +5 -4
- data/lib/ccrypto/java/engines/digest_engine.rb +221 -139
- data/lib/ccrypto/java/engines/ecc_engine.rb +249 -96
- data/lib/ccrypto/java/engines/ed25519_engine.rb +211 -0
- data/lib/ccrypto/java/engines/hkdf_engine.rb +82 -23
- data/lib/ccrypto/java/engines/hmac_engine.rb +98 -23
- data/lib/ccrypto/java/engines/pbkdf2_engine.rb +82 -33
- data/lib/ccrypto/java/engines/pkcs7_engine.rb +44 -33
- data/lib/ccrypto/java/engines/rsa_engine.rb +85 -31
- data/lib/ccrypto/java/engines/scrypt_engine.rb +12 -3
- data/lib/ccrypto/java/engines/secret_key_engine.rb +77 -12
- data/lib/ccrypto/java/engines/secret_sharing_engine.rb +17 -2
- data/lib/ccrypto/java/engines/x25519_engine.rb +249 -0
- data/lib/ccrypto/java/engines/x509_csr_engine.rb +141 -0
- data/lib/ccrypto/java/engines/x509_engine.rb +365 -71
- data/lib/ccrypto/java/ext/secret_key.rb +37 -25
- data/lib/ccrypto/java/ext/x509_cert.rb +429 -5
- data/lib/ccrypto/java/ext/x509_csr.rb +151 -0
- data/lib/ccrypto/java/jce_provider.rb +0 -11
- data/lib/ccrypto/java/keystore/jce_keystore.rb +205 -0
- data/lib/ccrypto/java/keystore/jks_keystore.rb +52 -0
- data/lib/ccrypto/java/keystore/keystore.rb +97 -0
- data/lib/ccrypto/java/keystore/pem_keystore.rb +147 -0
- data/lib/ccrypto/java/keystore/pkcs12_keystore.rb +56 -0
- data/lib/ccrypto/java/utils/comparator.rb +25 -2
- data/lib/ccrypto/java/version.rb +1 -1
- data/lib/ccrypto/java.rb +46 -0
- data/lib/ccrypto/provider.rb +139 -3
- metadata +40 -24
- data/ccrypto-java.gemspec +0 -44
- data/jars/bcmail-jdk15on-165.jar +0 -0
- data/jars/bcpg-jdk15on-165.jar +0 -0
- data/jars/bcpkix-jdk15on-165.jar +0 -0
- data/jars/bcprov-ext-jdk15on-165.jar +0 -0
- data/jars/bcprov-jdk15on-165.jar +0 -0
- data/jars/bctls-jdk15on-165.jar +0 -0
- data/lib/ccrypto/java/keybundle_store/pkcs12.rb +0 -125
@@ -0,0 +1,141 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Ccrypto
|
4
|
+
module Java
|
5
|
+
|
6
|
+
class X509CSREngine
|
7
|
+
include TR::CondUtils
|
8
|
+
include TeLogger::TeLogHelper
|
9
|
+
teLogger_tag :j_csr
|
10
|
+
|
11
|
+
def initialize(csrProf)
|
12
|
+
@csrProfile = csrProf
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate(privKey, &block)
|
16
|
+
|
17
|
+
cp = @csrProfile
|
18
|
+
|
19
|
+
subject = to_cert_subject(cp)
|
20
|
+
|
21
|
+
signHash = cp.hashAlgo
|
22
|
+
raise X509CSREngineException, "Certificate hash algorithm '#{signHash}' is not supported" if not DigestEngine.is_digest_supported?(signHash)
|
23
|
+
|
24
|
+
provider = block.call(:jce_provider) if block
|
25
|
+
|
26
|
+
if provider.nil?
|
27
|
+
teLogger.debug "Adding default provider"
|
28
|
+
prov = Ccrypto::Java::JCEProvider::DEFProv
|
29
|
+
else
|
30
|
+
teLogger.debug "Adding provider #{provider.name}"
|
31
|
+
prov = Ccrypto::Java::JCEProvider.add_provider(provider)
|
32
|
+
end
|
33
|
+
|
34
|
+
foundDigest = DigestEngine.find_digest_config(signHash)
|
35
|
+
if foundDigest.length == 1
|
36
|
+
selDigest = foundDigest.first
|
37
|
+
else
|
38
|
+
## prompt user for digest
|
39
|
+
if block
|
40
|
+
selDigest = block.call(:multiple_digest_algo_found, foundDigest)
|
41
|
+
else
|
42
|
+
raise X509EngineException, "Multiple digest algo found but not given a block. Not able to proceed."
|
43
|
+
end
|
44
|
+
end
|
45
|
+
signHashVal = selDigest.provider_config[:algo_name].gsub("-","")
|
46
|
+
|
47
|
+
|
48
|
+
#signHashVal = DigestEngine.find_digest_config(signHash).provider_config[:algo_name]
|
49
|
+
#signHashVal.gsub!("-","")
|
50
|
+
|
51
|
+
signAlgo = nil
|
52
|
+
gKey = privKey
|
53
|
+
loop do
|
54
|
+
case gKey
|
55
|
+
when org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey
|
56
|
+
signAlgo = "#{signHashVal}WithECDSA"
|
57
|
+
break
|
58
|
+
when java.security.interfaces.RSAPrivateKey , org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey
|
59
|
+
signAlgo = "#{signHashVal}WithRSA"
|
60
|
+
break
|
61
|
+
when Ccrypto::PrivateKey
|
62
|
+
teLogger.debug "Found Ccrypto::Private key #{gKey}."
|
63
|
+
gKey = gKey.native_privKey
|
64
|
+
else
|
65
|
+
raise X509CSREngineException, "Unsupported signing key type '#{gKey}'"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
p10Builder = org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder.new(subject, cp.public_key)
|
70
|
+
|
71
|
+
ext = []
|
72
|
+
cp.email.each do |e|
|
73
|
+
ext << org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName.rfc822Name,e)
|
74
|
+
end
|
75
|
+
|
76
|
+
cp.dns_name.each do |dn|
|
77
|
+
ext << org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName.dNSName,dn)
|
78
|
+
end
|
79
|
+
|
80
|
+
cp.ip_addr.each do |ip|
|
81
|
+
ext << org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName.iPAddress,ip)
|
82
|
+
end
|
83
|
+
|
84
|
+
cp.uri.each do |u|
|
85
|
+
ext << org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName.uniformResourceIdentifier,u)
|
86
|
+
end
|
87
|
+
|
88
|
+
#cp.custom_extension.each do |k,v|
|
89
|
+
# val = v[:value]
|
90
|
+
# val = "" if is_empty?(val)
|
91
|
+
# ev = org.bouncycastle.asn1.x509.Extension.new(org.bouncycastle.asn1.DERObjectIdentifier.new(k), v[:critical], org.bouncycastle.asn1.DEROctetString.new(val.to_java.getBytes))
|
92
|
+
# ext << org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName.otherName,ev)
|
93
|
+
#end
|
94
|
+
|
95
|
+
gn = org.bouncycastle.asn1.x509.GeneralNames.new(ext.to_java(org.bouncycastle.asn1.x509.GeneralName))
|
96
|
+
eg = org.bouncycastle.asn1.x509.ExtensionsGenerator.new
|
97
|
+
eg.addExtension(org.bouncycastle.asn1.x509.Extension.subjectAlternativeName, false, gn)
|
98
|
+
|
99
|
+
cp.custom_extension.each do |k,v|
|
100
|
+
val = v[:value]
|
101
|
+
val = "" if is_empty?(val)
|
102
|
+
ev = org.bouncycastle.asn1.x509.Extension.new(org.bouncycastle.asn1.ASN1ObjectIdentifier.new(k), v[:critical], org.bouncycastle.asn1.DEROctetString.new(val.to_java.getBytes))
|
103
|
+
eg.addExtension(ev)
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
p10Builder.addAttribute(org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, eg.generate)
|
108
|
+
|
109
|
+
sign = org.bouncycastle.operator.jcajce.JcaContentSignerBuilder.new(signAlgo).setProvider(prov).build(gKey)
|
110
|
+
csr = p10Builder.build(sign)
|
111
|
+
|
112
|
+
Ccrypto::X509CSR.new(csr)
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
private
|
118
|
+
def to_cert_subject(cp)
|
119
|
+
|
120
|
+
builder = org.bouncycastle.asn1.x500.X500NameBuilder.new
|
121
|
+
builder.addRDN(org.bouncycastle.asn1.x500.style::BCStyle::CN, cp.owner_name)
|
122
|
+
|
123
|
+
builder.addRDN(org.bouncycastle.asn1.x500.style::BCStyle::O, cp.org) if not_empty?(cp.org)
|
124
|
+
|
125
|
+
cp.org_unit.each do |ou|
|
126
|
+
builder.addRDN(org.bouncycastle.asn1.x500.style::BCStyle::OU, ou)
|
127
|
+
end
|
128
|
+
|
129
|
+
e = cp.email.first
|
130
|
+
if not_empty?(e)
|
131
|
+
builder.addRDN(org.bouncycastle.asn1.x500.style::BCStyle::EmailAddress, e)
|
132
|
+
end
|
133
|
+
|
134
|
+
builder.build
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
@@ -1,35 +1,54 @@
|
|
1
1
|
|
2
|
+
require_relative '../bc_const_mapping'
|
3
|
+
|
2
4
|
module Ccrypto
|
3
5
|
module Java
|
4
6
|
|
5
7
|
class X509Engine
|
6
8
|
include TR::CondUtils
|
7
9
|
|
8
|
-
|
10
|
+
def self.cert_to_bin(cert)
|
11
|
+
cert.encoded
|
12
|
+
end
|
9
13
|
|
10
|
-
|
14
|
+
def self.bin_to_cert(bin)
|
15
|
+
cf = java.security.cert.CertificateFactory.getInstance("X509",JCEProvider::DEFProv)
|
16
|
+
cf.generateCertificate(bin)
|
17
|
+
end
|
11
18
|
|
12
19
|
def initialize(certProf)
|
13
20
|
@certProfile = certProf
|
14
21
|
end
|
15
22
|
|
16
23
|
def generate(issuerKey, &block)
|
24
|
+
if @certProfile.csr.nil?
|
25
|
+
generate_from_cert_profile(@certProfile, issuerKey, &block)
|
26
|
+
else
|
27
|
+
generate_from_csr(@certProfile, issuerKey, &block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def generate_from_csr(cp, issuerKey, &block)
|
32
|
+
|
33
|
+
csrObj = Ccrypto::X509CSR.new(cp.csr)
|
34
|
+
csrCp = csrObj.csr_info
|
17
35
|
|
18
|
-
cp = @certProfile
|
19
36
|
|
20
37
|
raise X509EngineException, "Issuer key must be given" if issuerKey.nil?
|
21
38
|
raise X509EngineException, "Issuer key must be a private key. Given #{issuerKey}" if not issuerKey.is_a?(Ccrypto::PrivateKey)
|
22
39
|
|
23
40
|
prov = Ccrypto::Java::JCEProvider::DEFProv
|
41
|
+
signHash = cp.hashAlgo
|
24
42
|
signSpec = nil
|
25
43
|
if block
|
26
44
|
uprov = block.call(:jce_provider_name)
|
27
45
|
prov if not_empty?(uprov)
|
28
46
|
signSpec = block.call(:sign_spec)
|
29
|
-
signHash = block.call(:sign_hash)
|
47
|
+
signHash = block.call(:sign_hash) if is_empty?(signHash)
|
30
48
|
end
|
31
49
|
|
32
50
|
signHash = :sha256 if is_empty?(signHash)
|
51
|
+
raise X509EngineException, "Given digest algo '#{signHash}' is not suported" if not DigestEngine.is_digest_supported?(signHash)
|
33
52
|
|
34
53
|
validFrom = cp.not_before
|
35
54
|
validTo = cp.not_after
|
@@ -42,16 +61,260 @@ module Ccrypto
|
|
42
61
|
serial = java.math.BigInteger.new(cp.serial, 16)
|
43
62
|
end
|
44
63
|
|
64
|
+
iss = cp.issuer_cert
|
65
|
+
if not_empty?(iss)
|
66
|
+
raise X509EngineException, "Issuer certificate must be Ccrypto::X509Cert object (#{iss.class})" if not iss.is_a?(Ccrypto::X509Cert)
|
67
|
+
|
68
|
+
certGen = org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder.new(Ccrypto::X509Cert.to_java_cert(iss), serial, validFrom, validTo, to_cert_subject(csrCp), csrCp.public_key)
|
69
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getInstance(iss.getPublicKey.encoded)))
|
70
|
+
|
71
|
+
else
|
72
|
+
|
73
|
+
name = to_cert_subject(csrCp)
|
74
|
+
certGen = org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder.new(name, serial, validFrom, validTo, name, csrCp.public_key.native_pubKey)
|
75
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getInstance(csrCp.public_key.to_bin)))
|
76
|
+
end
|
77
|
+
|
78
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::basicConstraints, true, org.bouncycastle.asn1.x509.BasicConstraints.new(true)) if cp.gen_issuer_cert?
|
79
|
+
|
80
|
+
#certGen.addExtension(org.bouncycastle.asn1.x509.Extension::keyUsage, false, org.bouncycastle.asn1.x509.KeyUsage.new(to_keyusage))
|
81
|
+
#criticalKu = 0
|
82
|
+
#nonCriticalKu = 0
|
83
|
+
kuv = 0
|
84
|
+
criticalKu = false
|
85
|
+
cp.key_usage.selected.each do |ku, critical|
|
86
|
+
kur = BCConstMapping::KeyUsageMapping[ku]
|
87
|
+
#case ku
|
88
|
+
#when :digitalSignature
|
89
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::digitalSignature
|
90
|
+
#when :nonRepudiation
|
91
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::nonRepudiation
|
92
|
+
#when :keyEncipherment
|
93
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::keyEncipherment
|
94
|
+
#when :dataEncipherment
|
95
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::dataEncipherment
|
96
|
+
#when :keyAgreement
|
97
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::keyAgreement
|
98
|
+
#when :keyCertSign
|
99
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::keyCertSign
|
100
|
+
#when :crlSign
|
101
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::cRLSign
|
102
|
+
#when :encipherOnly
|
103
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::encipherOnly
|
104
|
+
#when :decipherOnly
|
105
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::decipherOnly
|
106
|
+
#end
|
107
|
+
|
108
|
+
criticalKu = critical if critical
|
109
|
+
|
110
|
+
kuv |= kur
|
111
|
+
|
112
|
+
#if critical
|
113
|
+
# criticalKu |= kur
|
114
|
+
#else
|
115
|
+
# nonCriticalKu |= kur
|
116
|
+
#end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::keyUsage, criticalKu, org.bouncycastle.asn1.x509.KeyUsage.new(kuv))
|
121
|
+
#certGen.addExtension(org.bouncycastle.asn1.x509.Extension::keyUsage, true, org.bouncycastle.asn1.x509.KeyUsage.new(criticalKu)) if criticalKu != 0
|
122
|
+
#certGen.addExtension(org.bouncycastle.asn1.x509.Extension::keyUsage, false, org.bouncycastle.asn1.x509.KeyUsage.new(nonCriticalKu)) if nonCriticalKu != 0
|
123
|
+
|
124
|
+
ekuCritical = false
|
125
|
+
eku = java.util.Vector.new
|
126
|
+
#ekuCritical = java.util.Vector.new
|
127
|
+
#ekuNonCritical = java.util.Vector.new
|
128
|
+
cp.ext_key_usage.selected.each do |ku,critical|
|
129
|
+
kur = BCConstMapping::ExtKeyUsageMapping[ku]
|
130
|
+
#case ku
|
131
|
+
#when :allPurpose
|
132
|
+
# kur = org.bouncycastle.asn1.x509.KeyPurposeId::anyExtendedKeyUsage
|
133
|
+
#when :serverAuth
|
134
|
+
# kur = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_serverAuth
|
135
|
+
#when :clientAuth
|
136
|
+
# kur = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_clientAuth
|
137
|
+
#when :codeSigning
|
138
|
+
# kur = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_codeSigning
|
139
|
+
#when :emailProtection
|
140
|
+
# kur = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_emailProtection
|
141
|
+
#when :timeStamping
|
142
|
+
# kur = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_timeStamping
|
143
|
+
#when :ocspSigning
|
144
|
+
# kur = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_OCSPSigning
|
145
|
+
#end
|
146
|
+
|
147
|
+
ekuCritical = critical if critical
|
148
|
+
eku.add_element(kur)
|
149
|
+
#if critical
|
150
|
+
# ekuCritical.add_element(kur)
|
151
|
+
#else
|
152
|
+
# ekuNonCritical.add_element(kur)
|
153
|
+
#end
|
154
|
+
end
|
155
|
+
|
156
|
+
#extKeyUsage = java.util.Vector.new
|
157
|
+
cp.domain_key_usage.each do |dku, critical|
|
158
|
+
#kur = org.bouncycastle.asn1.DERObjectIdentifier.new(dku)
|
159
|
+
kur = org.bouncycastle.asn1.ASN1ObjectIdentifier.new(dku)
|
160
|
+
|
161
|
+
ekuCritical = critical if critical
|
162
|
+
eku.add_element(kur)
|
163
|
+
#if critical
|
164
|
+
# ekuCritical.add_element(kur)
|
165
|
+
#else
|
166
|
+
# ekuNonCritical.add_element(kur)
|
167
|
+
#end
|
168
|
+
end
|
169
|
+
|
170
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::extendedKeyUsage, ekuCritical, org.bouncycastle.asn1.x509.ExtendedKeyUsage.new(eku)) if not_empty?(eku)
|
171
|
+
#certGen.addExtension(org.bouncycastle.asn1.x509.Extension::extendedKeyUsage, true, org.bouncycastle.asn1.x509.ExtendedKeyUsage.new(ekuCritical)) if not_empty?(ekuCritical)
|
172
|
+
#certGen.addExtension(org.bouncycastle.asn1.x509.Extension::extendedKeyUsage, false, org.bouncycastle.asn1.x509.ExtendedKeyUsage.new(ekuNonCritical)) if not_empty?(ekuNonCritical)
|
173
|
+
#certGen.addExtension(org.bouncycastle.asn1.x509.Extension::extendedKeyUsage, false, org.bouncycastle.asn1.x509.ExtendedKeyUsage.new(extKeyUsage)) if not extKeyUsage.is_empty?
|
174
|
+
|
175
|
+
altName = []
|
176
|
+
csrCp.email.uniq.each do |e|
|
177
|
+
altName << org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName::rfc822Name,e)
|
178
|
+
end
|
179
|
+
|
180
|
+
csrCp.dns_name.uniq.each do |d|
|
181
|
+
altName << org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName::dNSName,d)
|
182
|
+
end
|
183
|
+
|
184
|
+
csrCp.ip_addr.uniq.each do |d|
|
185
|
+
altName << org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName::iPAddress,d)
|
186
|
+
end
|
187
|
+
|
188
|
+
csrCp.uri.uniq.each do |u|
|
189
|
+
altName << org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName::uniformResourceIdentifier,u)
|
190
|
+
end
|
191
|
+
|
192
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::subjectAlternativeName, false, org.bouncycastle.asn1.x509.GeneralNames.new(altName.to_java(org.bouncycastle.asn1.x509.GeneralName)) )
|
193
|
+
|
194
|
+
csrCp.custom_extension.each do |k, v|
|
195
|
+
val = v[:value]
|
196
|
+
val = "" if is_empty?(val)
|
197
|
+
#ev = org.bouncycastle.asn1.x509.Extension.new(org.bouncycastle.asn1.DERObjectIdentifier.new(k), v[:critical], org.bouncycastle.asn1.DEROctetString.new(val.to_java.getBytes))
|
198
|
+
ev = org.bouncycastle.asn1.x509.Extension.new(org.bouncycastle.asn1.ASN1ObjectIdentifier.new(k), v[:critical], org.bouncycastle.asn1.DEROctetString.new(val.to_java.getBytes))
|
199
|
+
certGen.addExtension(ev)
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
if not_empty?(cp.crl_dist_point)
|
204
|
+
crls = []
|
205
|
+
cp.crl_dist_point.each do |c|
|
206
|
+
crls << org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName::uniformResourceIdentifier, org.bouncycastle.asn1.DERIA5String.new(c))
|
207
|
+
end
|
208
|
+
gns = org.bouncycastle.asn1.x509.GeneralNames.new(crls.to_java(org.bouncycastle.asn1.x509.GeneralName))
|
209
|
+
dpn = org.bouncycastle.asn1.x509.DistributionPointName.new(gns)
|
210
|
+
dp = org.bouncycastle.asn1.x509.DistributionPoint.new(dpn,nil,nil)
|
211
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.X509Extensions::CRLDistributionPoints,false,org.bouncycastle.asn1.DERSequence.new(dp))
|
212
|
+
end
|
213
|
+
|
214
|
+
aia = []
|
215
|
+
cp.ocsp_url.each do |o|
|
216
|
+
ov = org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName::uniformResourceIdentifier, org.bouncycastle.asn1.DERIA5String.new(o))
|
217
|
+
aia << org.bouncycastle.asn1.x509.AccessDescription.new(org.bouncycastle.asn1.x509.AccessDescription.id_ad_ocsp, ov)
|
218
|
+
end
|
219
|
+
|
220
|
+
cp.issuer_url.each do |i|
|
221
|
+
iv = org.bouncycastle.asn1.x509.GeneralName.new(org.bouncycastle.asn1.x509.GeneralName::uniformResourceIdentifier, org.bouncycastle.asn1.DERIA5String.new(i))
|
222
|
+
aia << org.bouncycastle.asn1.x509.AccessDescription.new(org.bouncycastle.asn1.x509.AccessDescription.id_ad_caIssuers, iv)
|
223
|
+
end
|
224
|
+
|
225
|
+
if not_empty?(aia)
|
226
|
+
authorityInformationAccess = org.bouncycastle.asn1.x509.AuthorityInformationAccess.new(aia.to_java(org.bouncycastle.asn1.x509.AccessDescription))
|
227
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.X509Extensions::AuthorityInfoAccess, false, authorityInformationAccess)
|
228
|
+
end
|
229
|
+
|
230
|
+
|
231
|
+
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getInstance(csrCp.public_key.to_bin)))
|
232
|
+
|
233
|
+
signAlgo = nil
|
234
|
+
# alreacy check if digest algo exist or not at the entry of the method
|
235
|
+
foundDigest = DigestEngine.find_digest_config(signHash)
|
236
|
+
if foundDigest.length == 1
|
237
|
+
selDigest = foundDigest.first
|
238
|
+
else
|
239
|
+
## prompt user for digest
|
240
|
+
if block
|
241
|
+
selDigest = block.call(:multiple_digest_algo_found, foundDigest)
|
242
|
+
else
|
243
|
+
raise X509EngineException, "Multiple digest algo configuration found based on given value '#{signHash}' but not given a block. Not able to proceed."
|
244
|
+
end
|
245
|
+
end
|
246
|
+
signHashVal = selDigest.provider_config[:algo_name].gsub("-","")
|
247
|
+
|
248
|
+
gKey = issuerKey
|
249
|
+
loop do
|
250
|
+
case gKey
|
251
|
+
when org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey
|
252
|
+
signAlgo = "#{signHashVal}WithECDSA"
|
253
|
+
break
|
254
|
+
when java.security.interfaces.RSAPrivateKey , org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey
|
255
|
+
signAlgo = "#{signHashVal}WithRSA"
|
256
|
+
break
|
257
|
+
when Ccrypto::PrivateKey
|
258
|
+
logger.debug "Found Ccrypto::Private key #{gKey}."
|
259
|
+
gKey = gKey.native_privKey
|
260
|
+
else
|
261
|
+
raise X509EngineException, "Unsupported issuer key type '#{gKey}'"
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
#signAlgo = "SHA256WithECDSA"
|
266
|
+
#signer = org.bouncycastle.operator.jcajce.JcaContentSignerBuilder.new(signAlgo).setProvider(prov).build(issuerKey.private_key)
|
267
|
+
signer = org.bouncycastle.operator.jcajce.JcaContentSignerBuilder.new(signAlgo).setProvider(prov).build(gKey)
|
268
|
+
|
269
|
+
cert = org.bouncycastle.cert.jcajce.JcaX509CertificateConverter.new().setProvider(prov).getCertificate(certGen.build(signer))
|
270
|
+
cert
|
271
|
+
|
272
|
+
Ccrypto::X509Cert.new(cert)
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
def generate_from_cert_profile(cp, issuerKey, &block)
|
278
|
+
|
279
|
+
raise X509EngineException, "Issuer key must be given" if issuerKey.nil?
|
280
|
+
raise X509EngineException, "Issuer key must be a private key. Given #{issuerKey}" if not issuerKey.is_a?(Ccrypto::PrivateKey)
|
281
|
+
|
282
|
+
prov = Ccrypto::Java::JCEProvider::DEFProv
|
283
|
+
signHash = cp.hashAlgo
|
284
|
+
signSpec = nil
|
285
|
+
if block
|
286
|
+
uprov = block.call(:jce_provider_name)
|
287
|
+
prov if not_empty?(uprov)
|
288
|
+
signSpec = block.call(:sign_spec)
|
289
|
+
signHash = block.call(:sign_hash) if is_empty?(signHash)
|
290
|
+
end
|
291
|
+
|
292
|
+
signHash = :sha256 if is_empty?(signHash)
|
293
|
+
raise X509EngineException, "Given digest algo '#{signHash}' is not suported" if not DigestEngine.is_digest_supported?(signHash)
|
294
|
+
|
295
|
+
validFrom = cp.not_before
|
296
|
+
validTo = cp.not_after
|
297
|
+
|
298
|
+
extUtils = org.bouncycastle.cert.bc.BcX509ExtensionUtils.new
|
299
|
+
|
300
|
+
if is_empty?(cp.serial)
|
301
|
+
serial = SecureRandom.hex(16)
|
302
|
+
elsif cp.serial.is_a?(java.math.BigInteger)
|
303
|
+
serial = cp.serial
|
304
|
+
else
|
305
|
+
serial = java.math.BigInteger.new(cp.serial, 16)
|
306
|
+
end
|
307
|
+
|
45
308
|
iss = cp.issuer_cert
|
46
309
|
if not_empty?(iss)
|
47
310
|
raise X509EngineException, "Issuer certificate must be Ccrypto::X509Cert object (#{iss.class})" if not iss.is_a?(Ccrypto::X509Cert) #iss.is_a?(java.security.cert.Certificate)
|
48
311
|
|
49
|
-
certGen = org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder.new(Ccrypto::X509Cert.to_java_cert(iss), serial, validFrom, validTo, to_cert_subject, cp.public_key)
|
312
|
+
certGen = org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder.new(Ccrypto::X509Cert.to_java_cert(iss), serial, validFrom, validTo, to_cert_subject(cp), cp.public_key)
|
50
313
|
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getInstance(iss.getPublicKey.encoded)))
|
51
314
|
|
52
315
|
else
|
53
316
|
|
54
|
-
name = to_cert_subject
|
317
|
+
name = to_cert_subject(cp)
|
55
318
|
certGen = org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder.new(name, serial, validFrom, validTo, name, cp.public_key.native_pubKey)
|
56
319
|
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getInstance(cp.public_key.to_bin)))
|
57
320
|
end
|
@@ -64,26 +327,27 @@ module Ccrypto
|
|
64
327
|
kuv = 0
|
65
328
|
criticalKu = false
|
66
329
|
cp.key_usage.selected.each do |ku, critical|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
330
|
+
kur = BCConstMapping::KeyUsageMapping[ku]
|
331
|
+
#case ku
|
332
|
+
#when :digitalSignature
|
333
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::digitalSignature
|
334
|
+
#when :nonRepudiation
|
335
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::nonRepudiation
|
336
|
+
#when :keyEncipherment
|
337
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::keyEncipherment
|
338
|
+
#when :dataEncipherment
|
339
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::dataEncipherment
|
340
|
+
#when :keyAgreement
|
341
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::keyAgreement
|
342
|
+
#when :keyCertSign
|
343
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::keyCertSign
|
344
|
+
#when :crlSign
|
345
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::cRLSign
|
346
|
+
#when :encipherOnly
|
347
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::encipherOnly
|
348
|
+
#when :decipherOnly
|
349
|
+
# kur = org.bouncycastle.asn1.x509::KeyUsage::decipherOnly
|
350
|
+
#end
|
87
351
|
|
88
352
|
criticalKu = critical if critical
|
89
353
|
|
@@ -106,22 +370,23 @@ module Ccrypto
|
|
106
370
|
#ekuCritical = java.util.Vector.new
|
107
371
|
#ekuNonCritical = java.util.Vector.new
|
108
372
|
cp.ext_key_usage.selected.each do |ku,critical|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
373
|
+
kur = BCConstMapping::ExtKeyUsageMapping[ku]
|
374
|
+
#case ku
|
375
|
+
#when :allPurpose
|
376
|
+
# kur = org.bouncycastle.asn1.x509.KeyPurposeId::anyExtendedKeyUsage
|
377
|
+
#when :serverAuth
|
378
|
+
# kur = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_serverAuth
|
379
|
+
#when :clientAuth
|
380
|
+
# kur = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_clientAuth
|
381
|
+
#when :codeSigning
|
382
|
+
# kur = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_codeSigning
|
383
|
+
#when :emailProtection
|
384
|
+
# kur = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_emailProtection
|
385
|
+
#when :timeStamping
|
386
|
+
# kur = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_timeStamping
|
387
|
+
#when :ocspSigning
|
388
|
+
# kur = org.bouncycastle.asn1.x509.KeyPurposeId::id_kp_OCSPSigning
|
389
|
+
#end
|
125
390
|
|
126
391
|
ekuCritical = critical if critical
|
127
392
|
eku.add_element(kur)
|
@@ -134,7 +399,8 @@ module Ccrypto
|
|
134
399
|
|
135
400
|
#extKeyUsage = java.util.Vector.new
|
136
401
|
cp.domain_key_usage.each do |dku, critical|
|
137
|
-
kur = org.bouncycastle.asn1.DERObjectIdentifier.new(dku)
|
402
|
+
#kur = org.bouncycastle.asn1.DERObjectIdentifier.new(dku)
|
403
|
+
kur = org.bouncycastle.asn1.ASN1ObjectIdentifier.new(dku)
|
138
404
|
|
139
405
|
ekuCritical = critical if critical
|
140
406
|
eku.add_element(kur)
|
@@ -169,6 +435,14 @@ module Ccrypto
|
|
169
435
|
|
170
436
|
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::subjectAlternativeName, false, org.bouncycastle.asn1.x509.GeneralNames.new(altName.to_java(org.bouncycastle.asn1.x509.GeneralName)) )
|
171
437
|
|
438
|
+
cp.custom_extension.each do |k, v|
|
439
|
+
val = v[:value]
|
440
|
+
val = "" if is_empty?(val)
|
441
|
+
#ev = org.bouncycastle.asn1.x509.Extension.new(org.bouncycastle.asn1.DERObjectIdentifier.new(k), v[:critical], org.bouncycastle.asn1.DEROctetString.new(val.to_java.getBytes))
|
442
|
+
ev = org.bouncycastle.asn1.x509.Extension.new(org.bouncycastle.asn1.ASN1ObjectIdentifier.new(k), v[:critical], org.bouncycastle.asn1.DEROctetString.new(val.to_java.getBytes))
|
443
|
+
certGen.addExtension(ev)
|
444
|
+
end
|
445
|
+
|
172
446
|
if not_empty?(cp.crl_dist_point)
|
173
447
|
crls = []
|
174
448
|
cp.crl_dist_point.each do |c|
|
@@ -200,24 +474,39 @@ module Ccrypto
|
|
200
474
|
certGen.addExtension(org.bouncycastle.asn1.x509.Extension::subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getInstance(cp.public_key.to_bin)))
|
201
475
|
|
202
476
|
signAlgo = nil
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
signAlgo = "#{signHash.to_s.upcase}WithECDSA"
|
209
|
-
break
|
210
|
-
when java.security.interfaces.RSAPrivateKey , org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey
|
211
|
-
signAlgo = "#{signHash.to_s.upcase}WithRSA"
|
212
|
-
break
|
213
|
-
when Ccrypto::PrivateKey
|
214
|
-
teLogger.debug "Found Ccrypto::Private key #{gKey}."
|
215
|
-
gKey = gKey.native_privKey
|
216
|
-
else
|
217
|
-
raise X509EngineException, "Unsupported issuer key type '#{gKey}'"
|
218
|
-
end
|
219
|
-
end
|
477
|
+
|
478
|
+
# alreacy check if digest algo exist or not at the entry of the method
|
479
|
+
foundDigest = DigestEngine.find_digest_config(signHash)
|
480
|
+
if foundDigest.length == 1
|
481
|
+
selDigest = foundDigest.first
|
220
482
|
else
|
483
|
+
p foundDigest
|
484
|
+
## prompt user for digest
|
485
|
+
if block
|
486
|
+
selDigest = block.call(:multiple_digest_algo_found, foundDigest)
|
487
|
+
else
|
488
|
+
raise X509EngineException, "Multiple digest algo found but not given a block. Not able to proceed."
|
489
|
+
end
|
490
|
+
end
|
491
|
+
signHashVal = selDigest.provider_config[:algo_name].gsub("-","")
|
492
|
+
|
493
|
+
#signHashVal = DigestEngine.find_digest_config(signHash).provider_config[:algo_name].gsub("-","")
|
494
|
+
|
495
|
+
gKey = issuerKey
|
496
|
+
loop do
|
497
|
+
case gKey
|
498
|
+
when org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey
|
499
|
+
signAlgo = "#{signHashVal}WithECDSA"
|
500
|
+
break
|
501
|
+
when java.security.interfaces.RSAPrivateKey , org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey
|
502
|
+
signAlgo = "#{signHashVal}WithRSA"
|
503
|
+
break
|
504
|
+
when Ccrypto::PrivateKey
|
505
|
+
logger.debug "Found Ccrypto::Private key #{gKey}."
|
506
|
+
gKey = gKey.native_privKey
|
507
|
+
else
|
508
|
+
raise X509EngineException, "Unsupported issuer key type '#{gKey}'"
|
509
|
+
end
|
221
510
|
end
|
222
511
|
|
223
512
|
#signAlgo = "SHA256WithECDSA"
|
@@ -231,23 +520,21 @@ module Ccrypto
|
|
231
520
|
|
232
521
|
end
|
233
522
|
|
234
|
-
def to_cert_subject
|
523
|
+
def to_cert_subject(cp)
|
235
524
|
|
236
525
|
builder = org.bouncycastle.asn1.x500.X500NameBuilder.new
|
237
|
-
builder.addRDN(org.bouncycastle.asn1.x500.style::BCStyle::CN,
|
526
|
+
builder.addRDN(org.bouncycastle.asn1.x500.style::BCStyle::CN, cp.owner_name)
|
238
527
|
|
239
|
-
builder.addRDN(org.bouncycastle.asn1.x500.style::BCStyle::O,
|
528
|
+
builder.addRDN(org.bouncycastle.asn1.x500.style::BCStyle::O, cp.org) if not_empty?(cp.org)
|
240
529
|
|
241
|
-
|
242
|
-
builder.addRDN(org.bouncycastle.asn1.x500.style::BCStyle::OU, ou)
|
530
|
+
cp.org_unit.each do |ou|
|
531
|
+
builder.addRDN(org.bouncycastle.asn1.x500.style::BCStyle::OU, ou) if not_empty?(ou)
|
243
532
|
end
|
244
533
|
|
245
|
-
#
|
246
|
-
|
247
|
-
e
|
248
|
-
|
249
|
-
builder.addRDN(org.bouncycastle.asn1.x500.style::BCStyle::EmailAddress, e)
|
250
|
-
end
|
534
|
+
#e = cp.email.first
|
535
|
+
#if not_empty?(e)
|
536
|
+
# builder.addRDN(org.bouncycastle.asn1.x500.style::BCStyle::EmailAddress, e)
|
537
|
+
#end
|
251
538
|
|
252
539
|
builder.build
|
253
540
|
|
@@ -305,6 +592,13 @@ module Ccrypto
|
|
305
592
|
kur
|
306
593
|
end
|
307
594
|
|
595
|
+
def self.logger(&block)
|
596
|
+
Ccrypto::Java.logger(:x509_eng, &block)
|
597
|
+
end
|
598
|
+
def logger(&block)
|
599
|
+
self.class.logger(&block)
|
600
|
+
end
|
601
|
+
|
308
602
|
end
|
309
603
|
|
310
604
|
end
|