Class: Ccrypto::Java::Keystore::JCEKeystore

Inherits:
Object
  • Object
show all
Includes:
DataConversion, TR::CondUtils
Defined in:
lib/ccrypto/java/keystore/jce_keystore.rb

Defined Under Namespace

Classes: KeystoreException

Class Method Summary collapse

Methods included from DataConversion

#from_b64, #from_b64_mime, #from_hex, included, #logger, #to_b64, #to_b64_mime, #to_bin, #to_hex, #to_java_bytes, #to_str

Class Method Details

.from_keystore(bin, storeType, &block) ⇒ Object

Raises:



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/ccrypto/java/keystore/jce_keystore.rb', line 14

def self.from_keystore(bin, storeType, &block)

  raise KeystoreException, "block is required" if not block

  logger = block.call(:logger) || TeLogger::TLogger.new(STDOUT)

  prov = block.call(:jce_provider)

  if not_empty?(prov)
    logger.debug "Keystore type '#{storeType}' with provider #{prov}"
    ks = java.security.KeyStore.getInstance(storeType, prov)
  else
    logger.debug "Keystore type '#{storeType}' with nil provider"
    ks = java.security.KeyStore.getInstance(storeType)
  end

  pass = block.call(:store_pass)
  name = block.call(:key_name)

  inForm = block.call(:in_format)
  case inForm
  when :b64
    inp = from_b64(bin)
  when :hex
    inp = from_hex(bin)
  else
    inp = bin
  end

  bbin = to_java_bytes(inp)

  ks.load(java.io.ByteArrayInputStream.new(bbin),pass.to_java.toCharArray)


  logger.debug "Aliases found from keystore : #{ks.aliases.to_a.join(", ")}"
  logger.debug "Given key name : #{name}"

  # on situation there are multiple aliases, which is an error condition
  # all subsequent chain and userCert shall be nil
  name = ks.aliases.to_a.first if is_empty?(name)

  logger.debug "Alias used to select cert and key : #{name}"

  userCert = Ccrypto::X509Cert.new(ks.getCertificate(name))
  raise KeystoreException, "User certificate is nil. Alias used to retrieve user certificate is '#{name}'. Aliases detected from the keystore are: #{ks.aliases.to_a.join(", ")}" if userCert.nil?
  chain = ks.get_certificate_chain(name)
  if not chain.nil?
    chain = chain.collect { |c| Ccrypto::X509Cert.new(c) }
  else
    chain = []
  end

  key = ks.getKey(name, pass.to_java.toCharArray)
  raise KeystoreException, "Private key is nil. Alias used to retrieve private key is '#{name}'. Aliases detected from the keystore are: #{ks.aliases.to_a.join(", ")}" if key.nil?
  kp = java.security.KeyPair.new(userCert.getPublicKey, key)
  case key
  when java.security.interfaces.ECPrivateKey
    param = java.security.AlgorithmParameters.getInstance("EC")
    param.init(key.params)
    oid = param.getParameterSpec(java.security.spec.ECGenParameterSpec.java_class).name
    curve = org.bouncycastle.asn1.x9.ECNamedCurveTable.getName(org.bouncycastle.asn1.ASN1ObjectIdentifier.new(oid)) 
    logger.debug "Recover curve info : #{curve}"
    conf = Ccrypto::Java::ECCEngine.find_curve(curve) 
    logger.debug "Found config : #{conf}"
    [Ccrypto::Java::ECCKeyBundle.new(kp, conf), userCert, chain]

  when org.bouncycastle.jcajce.provider.asymmetric.ec::BCECPrivateKey
    curve = key.params.name
    logger.debug "Recover curve info : #{curve}"
    conf = Ccrypto::Java::ECCEngine.find_curve(curve) 
    logger.debug "Found config : #{conf}"
    [Ccrypto::Java::ECCKeyBundle.new(kp, conf), userCert, chain]
  when java.security.interfaces.RSAPrivateKey
    [Ccrypto::Java::RSAKeyBundle.new(kp), userCert, chain]
  else
    raise KeystoreException, "Unknown key type #{key}"
  end
  
end

.to_keystore(storeType, &block) ⇒ Object

from_keystore

Raises:



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/ccrypto/java/keystore/jce_keystore.rb', line 94

def self.to_keystore(storeType, &block)
  raise KeystoreException, "Block is required" if not block

  logger = block.call(:logger) || TeLogger::TLogger.new(STDOUT)

  logger.debug "storetype #{storeType}"

  prov = block.call(:jce_provider)

  pkcs12NewCipher = false
  if storeType == "PKCS12"
    pkcs12NewCipher = block.call(:pkcs12_new_cipher?)
    if pkcs12NewCipher == true
      storeType = "JKS"
      prov = nil
      logger.debug "PKCS12 new cipher is on. Write to JKS first."
    end
  end

  if not_empty?(prov)
    logger.debug "Generating keystore of #{storeType} from provider #{prov}"
    ks = java.security.KeyStore.getInstance(storeType, prov)
  else
    logger.debug "Generating keystore of #{storeType} using SUN provider"
    ks = java.security.KeyStore.getInstance(storeType)
  end

  ks.load(nil,nil)

  gcert = block.call(:cert)
  raise KeystoreException, "#{storeType.upcase} requires the owner's X.509 certificate" if is_empty?(gcert)

  ca = block.call(:cert_chain) || block.call(:certchain) || [gcert]
  ca = [gcert] if ca.nil?
  ca = ca.unshift(gcert) if not ca.first.equal?(gcert)
  ca = ca.collect { |c|
    Ccrypto::X509Cert.to_java_cert(c) 
  }

  logger.debug "Cert Chain : #{ca.inspect}"

  pass = block.call(:store_pass)
  raise KeystoreException, "Password is required" if is_empty?(pass)

  name = block.call(:key_name)
  name = "Keystore for #{gcert.owner.name}" if is_empty?(name)

  keypair = block.call(:keypair)
  raise KeystoreException, "Keypair is required" if is_empty?(keypair)

  logger.debug "Setting key entry with name : #{name}"
  ks.setKeyEntry(name, keypair.private, pass.to_java.toCharArray, ca.to_java(java.security.cert.Certificate))

  baos = java.io.ByteArrayOutputStream.new
  ks.store(baos, pass.to_java.toCharArray)
  res = baos.toByteArray

  output = block.call(:output)
  if not_empty?(output)
    if pkcs12NewCipher
      randName = SecureRandom.uuid
      File.open(randName,"wb") do |f|
        f.write res
      end

      # temporary until BC or JCE has way to completely support this to be able to load from OpenSSL
      `keytool -importkeystore -alias "#{name}" -destalias "#{name}" -srckeystore #{randName} -destkeystore "#{output}" -srcstoretype JKS -deststoretype PKCS12 -srcstorepass "#{pass}" -deststorepass "#{pass}" -noprompt`

      FileUtils.rm(randName)
    else
      File.open(output,"wb") do |f|
        f.write res
      end
    end
  else
    outForm = block.call(:out_format)
    case outForm
    when :b64
      bres = to_b64(res)
    when :hex
      bres = to_hex(res)
    else
      bres = res
    end

    if pkcs12NewCipher
      randName = SecureRandom.uuid
      File.open(randName,"wb") do |f|
        f.write bres
      end

      # temporary until BC or JCE has way to completely support this to be able to load from OpenSSL
      `keytool -importkeystore -alias "#{name}" -destalias "#{name}" -srckeystore #{randName} -destkeystore "#{output}" -srcstoretype JKS -deststoretype PKCS12 -srcstorepass "#{pass}" -deststorepass "#{pass}" -noprompt`

      bcres = File.read(randName)
      FileUtils.rm(randName)

      bcres
    else
      bres
    end

  end

end