All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.karasiq.tls.TLSKeyStore.scala Maven / Gradle / Ivy

The newest version!
package com.karasiq.tls

import java.io.{FileOutputStream, InputStream, OutputStream}
import java.security.KeyStore

import com.karasiq.tls.TLS.{Certificate, CertificateChain, CertificateKey, KeySet}
import com.karasiq.tls.TLSKeyStore.{CertificateEntry, KeyEntry}
import com.karasiq.tls.internal.BCConversions._
import com.karasiq.tls.internal.ObjectLoader
import com.typesafe.config.ConfigFactory
import org.apache.commons.io.IOUtils
import org.bouncycastle.crypto.params.{AsymmetricKeyParameter, DSAKeyParameters, ECKeyParameters, RSAKeyParameters}

import scala.collection.JavaConversions._
import scala.util.control.Exception

/**
 * Key store loader class
 * @param password Key store encryption password
 * @param keyStoreType Key store type
 */
class KeyStoreLoader(password: String = null, keyStoreType: String = KeyStore.getDefaultType) extends ObjectLoader[KeyStore] {
  override def fromInputStream(inputStream: InputStream): KeyStore = {
    val keyStore = KeyStore.getInstance(keyStoreType)
    keyStore.load(inputStream, Option(password).map(_.toCharArray).orNull)
    keyStore
  }
}

object TLSKeyStore {
  sealed trait Entry {
    def alias: String
  }

  sealed trait CertificateEntry extends Entry {
    def certificate: TLS.Certificate
    def chain: TLS.CertificateChain
  }

  sealed trait KeyEntry extends Entry with CertificateEntry {
    def keyPair(password: String = null): TLS.CertificateKeyPair
  }

  def emptyKeyStore(): KeyStore = new KeyStoreLoader().fromInputStream(null)

  def keyStore(inputStream: InputStream, password: String): KeyStore = {
    new KeyStoreLoader(password).fromInputStream(inputStream)
  }

  def keyStore(path: String, password: String): KeyStore = {
    new KeyStoreLoader(password).fromFile(path)
  }

  def defaultKeyStore(): KeyStore = {
    val config = ConfigFactory.load().getConfig("karasiq.tls")
    this.keyStore(config.getString("key-store"), this.defaultPassword())
  }

  def defaultPassword(): String = {
    val config = ConfigFactory.load().getConfig("karasiq.tls")
    config.getString("key-store-pass")
  }

  def open(path: String, password: String): TLSKeyStore = {
    new TLSKeyStore(keyStore(path, password), password)
  }

  def empty(): TLSKeyStore = new TLSKeyStore(emptyKeyStore(), defaultPassword())

  def apply(): TLSKeyStore = new TLSKeyStore(defaultKeyStore(), defaultPassword())
}

/**
 * JCA keystore wrapper
 * @param keyStore JCA keystore
 * @param password JCA keystore password
 */
class TLSKeyStore(val keyStore: KeyStore = TLSKeyStore.defaultKeyStore(), val password: String = TLSKeyStore.defaultPassword()) {
  def contains(alias: String): Boolean = {
    keyStore.containsAlias(alias)
  }

  def delete(alias: String): Unit = {
    if (keyStore.containsAlias(alias)) {
      keyStore.deleteEntry(alias)
    }
  }

  def deleteKeySet(alias: String): Unit = {
    Seq("rsa", "dsa", "ecdsa").foreach { postfix ⇒
      delete(s"$alias-$postfix")
    }
  }

  def putKey(alias: String, key: TLS.CertificateKey, password: String = password): Unit = {
    keyStore.setKeyEntry(alias, key.key.getPrivate.toPrivateKey, password.toCharArray, key.certificateChain.toJavaCertificateChain)
  }

  def putKeySet(alias: String, keySet: TLS.KeySet, password: String = password): Unit = {
    if (keyStore.isKeyEntry(alias)) delete(alias)
    keySet.rsa.foreach(key ⇒ putKey(s"$alias-rsa", key, password))
    keySet.dsa.foreach(key ⇒ putKey(s"$alias-dsa", key, password))
    keySet.ecdsa.foreach(key ⇒ putKey(s"$alias-ecdsa", key, password))
  }

  def putCertificate(alias: String, certificate: TLS.Certificate): Unit = {
    keyStore.setCertificateEntry(alias, certificate.toJavaCertificate)
  }

  def getKey(alias: String, password: String = password): TLS.CertificateKeyPair = {
    val key = keyStore.getKey(alias, password.toCharArray)
    key.toAsymmetricCipherKeyPair(getCertificate(alias).getSubjectPublicKeyInfo)
  }

  def getCertificate(alias: String): TLS.Certificate = {
    keyStore.getCertificate(alias).toTlsCertificate
  }

  def getKeySet(alias: String, password: String = password): TLS.KeySet = {
    def readKey[K <: AsymmetricKeyParameter](key: String)(implicit m: Manifest[K]): Option[CertificateKey] = {
      getEntry(key) match {
        case Some(e: TLSKeyStore.KeyEntry) ⇒
          val key = e.keyPair(password)
          if (m.runtimeClass.isAssignableFrom(key.getPrivate.getClass)) {
            Some(CertificateKey(e.chain, key))
          } else {
            None
          }

        case _ ⇒
          None
      }
    }

    def autoSearch[K <: AsymmetricKeyParameter](postfix: String)(implicit m: Manifest[K]) = {
      readKey[K](s"$alias-$postfix").orElse(readKey[K](alias))
    }

    KeySet(autoSearch[RSAKeyParameters]("rsa"), autoSearch[DSAKeyParameters]("dsa"), autoSearch[ECKeyParameters]("ecdsa"))
  }

  def getCertificateChain(alias: String): TLS.CertificateChain = {
    new CertificateChain(keyStore.getCertificateChain(alias).map(_.toTlsCertificate))
  }

  def getEntry(alias: String): Option[TLSKeyStore.Entry] = {
    val pf: PartialFunction[String, TLSKeyStore.Entry] = {
      case a if keyStore.isKeyEntry(a) ⇒
        new KeyEntry {
          override def chain: CertificateChain = getCertificateChain(a)

          override def certificate: Certificate = getCertificate(a)

          override def keyPair(password: String): TLS.CertificateKeyPair = {
            getKey(a, if (password == null) password else password)
          }

          override def alias: String = a
        }

      case a if keyStore.isCertificateEntry(a) ⇒
        new CertificateEntry {
          override def chain: CertificateChain = getCertificateChain(a)

          override def certificate: Certificate = getCertificate(a)

          override def alias: String = a
        }
    }
    pf.lift(alias)
  }

  def iterator(): Iterator[TLSKeyStore.Entry] = {
    keyStore.aliases().toIterator.flatMap(getEntry)
  }

  def save(outputStream: OutputStream, password: String = password): Unit = {
    keyStore.store(outputStream, password.toCharArray)
  }

  def saveAs(path: String, password: String = password): Unit = {
    val outputStream = new FileOutputStream(path)
    Exception.allCatch.andFinally(IOUtils.closeQuietly(outputStream)) {
      save(outputStream, password)
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy