require_relative 'provider' require_relative 'csr' module PkernelJce # # Identity # Identity is abstraction consist of keypair + certificate, stored separately # #class Identity # attr_reader :priv_key, :cert, :keystore, :chain # def initialize(opts = {}) # @priv_key = opts[:priv_key] # @cert = opts[:cert] # @keystore = opts[:keystore] # @chain = opts[:chain] # end #end # end Identity # class Pkernel::Identity def key=(val) @key = val if not @key.nil? @privKey = PkernelJce::KeyPair.private_key(@key) @pubKey = PkernelJce::KeyPair.public_key(@key) end end def key if @key.nil? if not @privKey.nil? if not @pubKey.nil? @key = java.security.KeyPair.new(@pubKey,@privKey) elsif not @certificate.nil? @key = java.security.KeyPair.new(@certificate.public_key,@privKey) else # no possible to generate without public key end else # not possible to generate without private key end else # key is not nil... end @key end def privKey if @privKey.nil? and not @key.nil? @privKey = PkernelJce::KeyPair.private_key(@key) end @privKey end def pubKey if @pubKey.nil? if not @key.nil? @pubKey = PkernelJce::KeyPair.public_key(@key) elsif not @certificate.nil? @pubKey = PkernelJce::KeyPair.public_key(@certificate) end end @pubKey end def certificate if not @certificate.nil? and @certificate.java_kind_of?(Java::OrgBouncycastleCert::X509CertificateHolder) @certificate = @certificate.to_java_cert end @certificate end # In java world, JCE/JCA provides switchable engine to call if it is software/hardware # This provider is tightly related to private key. # Since private key is encapsulated in this object, might as well keep the pointer here. # Whoever want to use the private key, also should check the provider to load correct # signing engine def provider=(val) if not val.nil? if val.is_a?(String) and not val.empty? @provider = PkernelJce::Provider.add_provider(val) else @provider = PkernelJce::Provider.add_provider(val) end end end def provider if @provider.nil? PkernelJce::GConf.instance.glog.debug "Provider is nil in Identity object. Setting it to default provider '#{PkernelJce::Provider::DefProvider.name}'" @provider = PkernelJce::Provider.add_default end @provider end end # # IdentityFactory # module IdentityFactory def build_from_components(key, cert = nil, chain = [], provider = nil) if key.nil? raise PkernelJce::Error, "Key cannot be nil to build identity" end id = Pkernel::Identity.new( { key: key, certificate: cert, chain: chain } ) if cert.nil? class_eval do include PkernelJce::IdentityManagement end else c = PkernelJce::Certificate.ensure_java_cert(cert) if PkernelJce::Certificate.is_issuer_cert?(c) class_eval do include PkernelJce::IdentityIssuer include PkernelJce::IdentityManagement end else class_eval do include PkernelJce::IdentityManagement end end end id.provider = provider id end alias_method :build, :build_from_components # end build_from_components def dump(id, opts = {}) if id.nil? raise PkernelJce::Error, "Identity object is nil in write to keystore" end prov = opts[:provider] if prov.nil? prov = PkernelJce::Provider.add_default else prov = PkernelJce::Provider.add_provider(prov) end format = opts[:format] format = :p12 if format.nil? sFormat = format case format when :p12, :pkcs12 PkernelJce::GConf.instance.glog.debug "Loading PKCS12 keystore" ks = java.security.KeyStore.getInstance("PKCS12",prov) sFormat = :p12 when :jks PkernelJce::GConf.instance.glog.debug "Loading JKS keystore" ks = java.security.KeyStore.getInstance("JKS") sFormat = :jks else PkernelJce::GConf.instance.glog.debug "Loading '#{format}' keystore" if prov.nil? ks = java.security.KeyStore.getInstance(format) else ks = java.security.KeyStore.getInstance(format, prov) end sFormat = format end result = { } pass = opts[:password] if pass.nil? or pass.empty? PkernelJce::GConf.instance.glog.warn "Password is not given to dump identity. Random password shall be generated." pass = SecureRandom.hex(8) result[:password] = pass #raise PkernelJce::Error, "Password should not be empty for identity storage" end chain = id.chain.map do |c| if c.java_kind_of?(org.bouncycastle.cert.X509CertificateHolder) c.to_java_cert else c end end name = opts[:key_name] || "Pkernel JCE" ks.load(nil,nil) ks.setKeyEntry(name, id.privKey, pass.to_java.toCharArray, chain.to_java(java.security.cert.Certificate)) baos = java.io.ByteArrayOutputStream.new file = opts[:file] if file.nil? or file.empty? ks.store(baos, pass.to_java.toCharArray) baos.toByteArray else fos = java.io.FileOutputStream.new(file) ks.store(fos, pass.to_java.toCharArray) fos.flush fos.close end result end def load(opts = {}) prov = opts[:provider] if prov.nil? prov = PkernelJce::Provider.add_default else prov = PkernelJce::Provider.add_provider(prov) end format = opts[:format] format = :p12 if format.nil? sFormat = format case format when :p12, :pkcs12 PkernelJce::GConf.instance.glog.debug "Loading PKCS12 keystore" ks = java.security.KeyStore.getInstance("PKCS12",prov) sFormat = :p12 when :jks PkernelJce::GConf.instance.glog.debug "Loading JKS keystore" ks = java.security.KeyStore.getInstance("JKS") sFormat = :jks else PkernelJce::GConf.instance.glog.debug "Loading '#{format}' keystore" if prov.nil? ks = java.security.KeyStore.getInstance(format.to_s) else ks = java.security.KeyStore.getInstance(format.to_s, prov) end end pass = opts[:password] || '' file = opts[:file] bin = opts[:bin] baos = java.io.ByteArrayOutputStream.new if not file.nil? or not file.empty? fis = java.io.FileInputStream.new(file) ks.load(fis,pass.to_java.toCharArray) fis.close elsif bin.nil? ks.load(java.io.ByteArrayInputStream.new(bin),pass.to_java.toCharArray) else raise PkernelJce::Error, "No file or bin is given to load identity" end name = opts[:key_name] || ks.aliases.to_a[0] key = ks.getKey(name,pass.to_java.toCharArray) cert = ks.getCertificate(name) chain = ks.getCertificateChain(name) id = Pkernel::Identity.new( { privKey: key, certificate: cert, chain: chain } ) id end end # end IdentityFactory module IdentityIssuer #def issue_cert(identity, opts = {}) # src = opts[:source] # if src.nil? or src.empty? # raise PkernelJce::Error, "Issue cert requires source key indicating either from CSR or Owner structure" # end # conf = opts[:config] # if conf.nil? or conf.empty? # raise PkernelJce::Error, "Config for certificate generation is not given!" # end # if src[:csr_file].nil? # csrBin = PkernelJce::CSRCore.load({ file: src[:csr_file] }) # elsif src[:csr].nil? # owner = Pkernel::Certificate::Owner.load_from_csr(src[:csr]) # elsif src[:owner].nil? # # else # raise PkernelJce::Error, "No CSR or Owner is given to issue certificate" # end # issuerKey = PkernelJce::KeyPair.private_key(identity.privKey) # conf[:owner] = owner # cert = @cdriver.generate(conf) do |v| # case v # when :signAlgo # PkernelJce::KeyPair.derive_signing_algo(issuerKey, "SHA256") # when :issuerKey # issuerKey # when :issuerCert # when :keyUsage # when :extKeyUsage # end # end #end end # end IdentityIssuer module IdentityManagement def destroy PkernelJce::GConf.instance.glog.warn "Destroy not implemented for JCE context" end end class IdentityEngine extend IdentityFactory end end