module PkernelJce::IdentityFactory

IdentityFactory

Public Instance Methods

build(key, cert = nil, chain = [], provider = nil)
build_from_components(key, cert = nil, chain = [], provider = nil) click to toggle source
# File lib/pkernel_jce/identity.rb, line 161
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
Also aliased as: build
dump(id, opts = {}, &block) click to toggle source

end build_from_components

# File lib/pkernel_jce/identity.rb, line 192
def dump(id, opts = {}, &block)
  
  if id.nil?
    raise PkernelJce::Error, "Identity object is nil in write to keystore"
  end

  result = { }

  format = opts[:format]
  case format
  when :pkcs8, :pk8, :p8

    res = dump_pk8(id, opts, &block)

    # private key
    file = opts[:file]
    if file.nil? or file.empty?
      result[:bin] = res[:bin]
    else
      ff = java.io.File.new(file)
      ff.parent_file.mkdirs if not ff.parent_file.exists?
      fos = java.io.FileOutputStream.new(ff)
      fos.write res[:bin].to_java.getBytes
      fos.flush
      fos.close

      result[:file] = file
    end

    # certificate
    cfile = opts[:cert_file]
    if not cfile.nil?
      ff = java.io.File.new(cfile)
      ff.parent_file.mkdirs if not ff.parent_file.exists?
      fos = java.io.FileOutputStream.new(ff)
      fos.write res[:cert_bin]
      fos.flush
      fos.close
      result[:cert_file] = cfile
    else
      result[:cert_bin] = res[:cert_bin]
    end
     
    # cert chain
    cafile = opts[:ca_file]
    if not cafile.nil?
      ff = java.io.File.new(cafile)
      ff.parent_file.mkdirs if not ff.parent_file.exists?
      fos = java.io.FileOutputStream.new(ff)
      res[:ca_bin].each do |ca|
        fos.write ca
      end
      fos.flush
      fos.close

      result[:ca_file] = cafile
    else
      result[:ca_bin] = res[:ca_bin]
    end

    result

  when :pem

    res = dump_pem(id, opts, &block)

    # private key
    file = opts[:file]
    if file.nil? or file.empty?
      result[:bin] = res[:bin]
    else
      ff = java.io.File.new(file)
      ff.parent_file.mkdirs if not ff.parent_file.exists?
      fos = java.io.FileOutputStream.new(ff)
      fos.write res[:bin]
      fos.flush
      fos.close

      result[:file] = file
    end

    # public key
    cfile = opts[:pubKey_file]
    if not cfile.nil?
      ff = java.io.File.new(cfile)
      ff.parent_file.mkdirs if not ff.parent_file.exists?
      fos = java.io.FileOutputStream.new(ff)
      fos.write res[:pubKey_bin]
      fos.flush
      fos.close
      result[:pubKey_file] = cfile
    else
      result[:pubKey_bin] = res[:pubKey_bin]
    end
     
    # certificate
    cfile = opts[:cert_file]
    if not cfile.nil?
      ff = java.io.File.new(cfile)
      ff.parent_file.mkdirs if not ff.parent_file.exists?
      fos = java.io.FileOutputStream.new(ff)
      fos.write res[:cert_bin]
      fos.flush
      fos.close
      result[:cert_file] = cfile
    else
      result[:cert_bin] = res[:cert_bin]
    end
     
    # cert chain
    cafile = opts[:ca_file]
    if not cafile.nil?
      ff = java.io.File.new(cafile)
      ff.parent_file.mkdirs if not ff.parent_file.exists?
      fos = java.io.FileOutputStream.new(ff)
      res[:ca_bin].each do |ca|
        fos.write ca
      end
      fos.flush
      fos.close

      result[:ca_file] = cafile
    else
      result[:ca_bin] = res[:ca_bin]
    end

    result


  else 
    # JCE/JCA keystore
    rres = dump_keystore(id, opts, &block)

    result.merge!(rres)

    file = opts[:file]
    if file.nil? or file.empty?
    else
      ff = java.io.File.new(file)
      ff.parent_file.mkdirs if not ff.parent_file.exists?
      fos = java.io.FileOutputStream.new(file)
      fos.write result[:bin]
      fos.flush
      fos.close

      result[:file] = file
    end

    result
  end

end
dump_to_file(id, file, opts = { }, &block) click to toggle source
# File lib/pkernel_jce/identity.rb, line 345
def dump_to_file(id, file, opts = { }, &block)  
  opts = { } if opts.nil?
  raise PkernelJce::Error, "Option for dump to file must be a hash" if not opts.is_a?(Hash)
  dump(id, opts.merge({ file: file }), &block)
end
dump_to_file_p8(id, idFile, certFile, caFile, password, opts = { }, &block) click to toggle source
# File lib/pkernel_jce/identity.rb, line 351
def dump_to_file_p8(id, idFile, certFile, caFile, password, opts = { }, &block)
  opts = { } if opts.nil?
  raise PkernelJce::Error, "Option for dump to file in pkcs8 format must be a hash" if not opts.is_a?(Hash)
  
  raise PkernelJce::Error, "Identity file path cannot be empty" if empty?(idFile) 
  raise PkernelJce::Error, "Certificate file path cannot be empty" if empty?(certFile) 
  raise PkernelJce::Error, "CA chain file path cannot be empty" if empty?(caFile) 

  dump(id, opts.merge({ file: idFile, cert_file: certFile, ca_file: caFile, format: :pkcs8 }),&block)
end
load(opts = {}, &block) click to toggle source
# File lib/pkernel_jce/identity.rb, line 362
def load(opts = {}, &block)

  format = opts[:format]
  case format
  when :pk8, :p8, :pkcs8
    res = load_pk8(opts, &block)
  when :pem
    res = load_pem(opts, &block)
  else
    res = load_keystore(opts, &block)
  end

  if res[:key].nil?
    raise Pkernel::Error, "Failed to load key from the store."
  end

  Pkernel::Identity.new( { privKey: res[:key], certificate: res[:cert], chain: res[:chain] } )
end

Private Instance Methods

dump_keystore(id, opts = { }, &block) click to toggle source

end load()

# File lib/pkernel_jce/identity.rb, line 383
def dump_keystore(id, opts = { }, &block)  
  
  result = { }
  prov = opts[:provider] 
  if prov.nil?
    prov = PkernelJce::Provider.add_default
  else
    prov = PkernelJce::Provider.add_provider(prov)
  end

  case opts[:format]
  when :p12, :pkcs12
    stype = "PKCS12"
  when :jks, :java
    stype = "jks"
  when :bks
    stype = "bks"
  else
    PkernelJce::GConf.instance.glog.debug "No keystore type given. Default to pkcs12 keystore"
    stype = "PKCS12"
  end

  if prov.nil? or stype == "jks"
    PkernelJce::GConf.instance.glog.debug "Loading #{stype} keystore with null provider"
    ks = java.security.KeyStore.getInstance(stype)
  else
    PkernelJce::GConf.instance.glog.debug "Loading #{stype} keystore with provider #{prov.name}"
    ks = java.security.KeyStore.getInstance(stype,prov)
  end
 
  pass = opts[:password]
  if pass.nil? or pass.empty?
    if block
      pass = block.call(:prompt_pass)
    end
  end

  passLen = opts[:password_length] || 8
  # cannot be too small...
  if (passLen/2) < 8
    passLen = 8
  else
    passLen = passLen/2
  end

  if pass.nil? or pass.empty?
    PkernelJce::GConf.instance.glog.warn "Password is not given to dump identity. Random password of #{passLen*2} characters shall be generated."
    pass = SecureRandom.hex(passLen)
    result[:password] = pass
  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] || opts[:keyName] || opts[:keyname] || Certificate.get_subject_fields(id.certificate,[:cn])[:cn][0]
  
  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
  ks.store(baos, pass.to_java.toCharArray)
  result[:bin] = baos.toByteArray 

  result
  
end
dump_pem(id,opts,&block) click to toggle source

load_keystore

# File lib/pkernel_jce/identity.rb, line 543
def dump_pem(id,opts,&block)

  result = { }
  baos = java.io.ByteArrayOutputStream.new

  pass = opts[:password]
  if (pass.nil? or pass.empty?) and block
    pass = block.call(:prompt_pass)
  end

  PkernelJce::Provider.add_default

  writer = org.bouncycastle.openssl.PEMWriter.new(java.io.OutputStreamWriter.new(baos))
  if pass.nil? or pass.empty?
    PkernelJce::GConf.instance.glog.debug "Constructing plain PEM..."
    writer.writeObject(id.privKey)
  else
    PkernelJce::GConf.instance.glog.debug "Constructing encrypted PEM..."
    encryptor = org.bouncycastle.openssl.jcajce.JcePEMEncryptorBuilder.new("AES-256-GCM").build(pass.to_java.toCharArray)
    writer.writeObject(id.privKey,encryptor)
  end
  writer.flush
  writer.close
  result[:bin] = baos.toByteArray

  baos.reset
  writer = org.bouncycastle.openssl.PEMWriter.new(java.io.OutputStreamWriter.new(baos))
  writer.writeObject(id.certificate)
  writer.flush
  writer.close
  result[:cert_bin] = baos.toByteArray

  baos.reset
  writer = org.bouncycastle.openssl.PEMWriter.new(java.io.OutputStreamWriter.new(baos))
  writer.writeObject(id.pubKey)
  writer.flush
  writer.close
  result[:pubKey_bin] = baos.toByteArray

  cc = []
  id.chain.each do |c|
    baos.reset
    writer = org.bouncycastle.openssl.PEMWriter.new(java.io.OutputStreamWriter.new(baos))
    writer.writeObject(c)
    writer.flush
    writer.close
    cc << baos.toByteArray
  end
  result[:ca_bin] = cc

  result

end
dump_pk8(id, opts, &block) click to toggle source

dump_pk8()

# File lib/pkernel_jce/identity.rb, line 674
def dump_pk8(id, opts, &block)

  PkernelJce::GConf.instance.glog.debug "Dump to PKCS8 format..."

  result = { }

  pass = opts[:password]
  if (pass.nil? or pass.empty?) and block
    pass = block.call(:prompt_pass)
  end

  prov = opts[:provider]
  if not prov.nil?
    prov = PkernelJce::Provider.add_provider(prov)
  end

  # private key only
  # remove file parameter if given
  # because we want the dump to be available here
  keyDumpPara = opts.clone
  keyDumpPara.delete(:file)
  # KeyPair already using the PKCS8 format for output... might as well just reuse...
  rres = PkernelJce::KeyPairEngine.dump(id.keypair, keyDumpPara, &block)

  result[:bin] = rres

  result[:cert_bin] = PkernelJce::CertificateEngine.dump(id.certificate, { outForm: :pem })

  cc = []
  id.chain.each do |c|
    cc << PkernelJce::CertificateEngine.dump(c, { outForm: :pem })
  end

  result[:ca_bin] = cc

  result

end
load_keystore(opts = { }, &block) click to toggle source

dump_keystore

# File lib/pkernel_jce/identity.rb, line 456
def load_keystore(opts = { }, &block)

  result = { }

  prov = opts[:provider] 
  if not prov.nil?
    prov = PkernelJce::Provider.add_provider(prov)
  end

  format = opts[:format]
  format = :p12 if format.nil?
  sFormat = format
  case format.to_sym
  when :p12, :pkcs12
    PkernelJce::GConf.instance.glog.debug "Loading PKCS12 keystore"
    pprov = PkernelJce::Provider.add_default
    ks = java.security.KeyStore.getInstance("PKCS12",pprov)
    result[:ks_format] = :p12
  when :jks        
    PkernelJce::GConf.instance.glog.debug "Loading JKS keystore"
    ks = java.security.KeyStore.getInstance("JKS")
    result[:ks_format] = :jks

  when :pk8, :pkcs8, :p8

  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

    result[:ks_format] = format
  end   
  
  pass = opts[:password] 

  if (pass.nil? or pass.empty?) and block
    pass = block.call(:prompt_pass)
  end
  
  file = opts[:file]
  bin = opts[:bin]
  baos = java.io.ByteArrayOutputStream.new

  if not (file.nil? or file.empty?)
    fis = java.io.FileInputStream.new(file)
    ks.load(fis,pass.to_java.toCharArray)
    fis.close
  elsif not bin.nil?
    ks.load(java.io.ByteArrayInputStream.new(bin),pass.to_java.toCharArray)
  else
    raise PkernelJce::Error, "No file or bin in keystore format is given to load identity"
  end

  keyname = opts[:keyname] || opts[:keyName] || opts[:key_name]

  if not (keyname.empty? or keyname.nil?)
    result[:ks_alias] = keyname
  else
    aliases = ks.aliases.to_a
    if aliases.length == 0
      raise PkernelJce::Error, "No alias available from the keystore"
    end

    if aliases.length > 1 
      # more the 1 aliases
      # to ensure the loading is correct, call block or error
      if block
        result[:ks_alias] = block.call(:multiple_aliases, aliases)
      else
        raise PkernelJce::Error, "Multiple aliases exist in the keystores. Please provide keyname to pick one or provide a block for processing"
      end
    else
      result[:ks_alias] = aliases.first
    end
  end

  result[:key] = ks.getKey(result[:ks_alias],pass.to_java.toCharArray)
  result[:cert] = ks.getCertificate(result[:ks_alias])
  result[:chain] = ks.getCertificateChain(result[:ks_alias])

  result
end
load_pem(opts, &block) click to toggle source

dump_pem

# File lib/pkernel_jce/identity.rb, line 598
def load_pem(opts, &block)
  res = { }
  file = opts[:file]
  bin = opts[:bin]

  prov = PkernelJce::Provider.add_default

                    converter = org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter.new.setProvider prov

  if not (file.nil? or file.empty?)
    reader = org.bouncycastle.openssl.PEMParser.new(java.io.InputStreamReader.new(java.io.FileInputStream.new(file)))
  elsif not (bin.nil? or bin.empty?)
    reader = org.bouncycastle.openssl.PEMParser.new(java.io.InputStreamReader.new(java.io.ByteArrayInputStream.new(IoUtils.ensure_java_bytes(bin))))
  else
    raise PkernelJce::Error, "No file or bin in PEM format is given to load identity"
  end   

  obj = reader.readObject
                    if obj.java_kind_of? org.bouncycastle.openssl.PEMKeyPair
    res[:keypair] = converter.getKeyPair(obj)
    res[:key] = PkernelJce::KeyPair.private_key(res[:keypair])

                    elsif obj.java_kind_of? org.bouncycastle.openssl.PEMEncryptedKeyPair

    PkernelJce::GConf.instance.glog.debug "Loading encrypted PEM..."
    pass = opts[:password]
    if (pass.nil? or pass.empty?) and block
      pass = block.call(:prompt_pass)
    end

    if pass.nil? or pass.empty?
      raise PkernelJce::Error, "The given key file to load is password protected but password is not given. Process shall abort."
    end

                            decryptor = org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder.new.setProvider(prov).build(pass.to_java.toCharArray)
    res[:keypair] = converter.getKeyPair(obj.decryptKeyPair(decryptor))
    res[:key] = PkernelJce::KeyPair.private_key(res[:keypair])

                    elsif obj.java_kind_of? org.bouncycastle.asn1.pkcs.PrivateKeyInfo
                            res[:key] = converter.getPrivateKey obj
  else
    raise PkernelJce::Error, "Unknown object for further processing #{obj.class}"
                    end

  if not (opts[:cert_file].nil? or opts[:cert_file].empty?)
    reader = org.bouncycastle.openssl.PEMParser.new(java.io.InputStreamReader.new(java.io.FileInputStream.new(opts[:cert_file])))
    res[:cert] = reader.readObject
  elsif not (opts[:cert_bin].nil? or opts[:cert_bin].empty?)
    reader = org.bouncycastle.openssl.PEMParser.new(java.io.InputStreamReader.new(java.io.ByteArrayInputStream.new(IoUtils.ensure_java_bytes(opts[:cert_bin]))))
    res[:cert] = reader.readObject
  end

  if not (opts[:ca_file].nil? or opts[:ca_file].empty?)
    reader = org.bouncycastle.openssl.PEMParser.new(java.io.InputStreamReader.new(java.io.FileInputStream.new(opts[:ca_file])))
    res[:chain] = []
    o = reader.readObject
    while(o != nil)
      res[:chain] << o
      o = reader.readObject
    end
  elsif not (opts[:ca_bin].nil? or opts[:ca_bin].empty?)
    reader = org.bouncycastle.openssl.PEMParser.new(java.io.InputStreamReader.new(java.io.ByteArrayInputStream.new(IoUtils.ensure_java_bytes(opts[:ca_bin]))))
    res[:chain] = []
    o = reader.readObject
    while(o != nil)
      res[:chain] << o
      o = reader.readObject
    end
  end

  res

end
load_pk8(opts, &block) click to toggle source

dump_pk8

# File lib/pkernel_jce/identity.rb, line 714
def load_pk8(opts, &block)

  res = { }
  pass = opts[:password]
  if (pass.nil? or pass.empty?) and block
    pass = block.call(:prompt_pass)
  end

  prov = opts[:provider]
  if not prov.nil?
    prov = PkernelJce::Provider.add_provider(prov)
  end

  key = PkernelJce::KeyPairEngine.load(opts)

  res[:key] = key

  certPara = { }
  certPara[:file] = opts[:cert_file] if not (opts[:cert_file].nil? or opts[:cert_file].empty?)
  certPara[:bin] = opts[:cert_bin] if not (opts[:cert_bin].nil? or opts[:cert_file].empty?)
  res[:cert] = PkernelJce::CertificateEngine.load(certPara)

  chainPara = { multiple: true }
  chainPara[:file] = opts[:ca_file] if not (opts[:ca_file].nil? or opts[:ca_file].empty?)
  chainPara[:bin] = opts[:ca_bin] if not (opts[:ca_bin].nil? or opts[:ca_bin].empty?)
  res[:chain] = PkernelJce::CertificateEngine.load(chainPara)

  res

end