/* * * Panbox - encryption for cloud storage * Copyright (C) 2014-2015 by Fraunhofer SIT and Sirrix AG * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Additonally, third party code may be provided with notices and open source * licenses from communities and third parties that govern the use of those * portions, and any licenses granted hereunder do not alter any rights and * obligations you may have under such open source licenses, however, the * disclaimer of warranty and limitation of liability provisions of the GPLv3 * will apply to all the product. * */ package org.panbox.core.identitymgmt; import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.util.Collection; import java.util.Date; import java.util.Enumeration; import java.util.LinkedList; import org.apache.log4j.Logger; import org.panbox.core.crypto.CryptCore; import org.panbox.core.crypto.KeyConstants; public class Identity extends AbstractIdentity { // KeyStore holds all Keypairs and is only protected by // CryptCore.DEFAULT_PASSWORD. Private Owner keys must be protected by // dedicated password /** * Local KeyStore holding owner and device keys */ private static final Logger logger = Logger.getLogger("org.panbox.core"); protected KeyStore keyStore; public static final String OWNER_KEY_SIGN_PRIV = "ownerKeySignPriv"; public static final String OWNER_KEY_ENC_PRIV = "ownerKeyEncPriv"; public static final String OWNER_CERT_ENC = "ownerCertEnc"; public static final String OWNER_CERT_SIGN = "ownerCertSign"; public Identity(IAddressbook addressbook, String email, String firstName, String name) { super(email, firstName, name, addressbook); initKeystore(); } public Identity(IAddressbook addressbook) { super(addressbook); initKeystore(); } /** * Creates an empty Keystore, protected by the Cryptcore.DEFAULT_PASSWORD */ private void initKeystore() { this.keyStore = CryptCore.createUnprotectedKeyStore(); } /** * Stores the owner key for signing in the keystore of this identity and * protects it by the given password * * @param ownerKeySign * - Keypair representing the owner key for signing * @param password * - to protect the private key */ @Override public void setOwnerKeySign(KeyPair ownerKeySign, char[] password) { try { // set key for existing signature cert if it already has been set, // otherwise create completely new one X509Certificate certChain = getCertSign(); if (certChain == null) { certChain = CryptCore.createSelfSignedX509Certificate( ownerKeySign.getPrivate(), ownerKeySign.getPublic(), this); } this.keyStore.setKeyEntry(OWNER_KEY_SIGN_PRIV, ownerKeySign.getPrivate(), password, new java.security.cert.Certificate[] { certChain }); // store as certificate as well this.keyStore.setCertificateEntry(OWNER_CERT_SIGN, certChain); } catch (KeyStoreException e) { logger.error("Could not add " + OWNER_KEY_SIGN_PRIV + " to identity's keystore", e); } } /** * Stores the owner key for encryption in the keystore of this identity and * protects it by the given password * * @param ownerKeyEnc * - Keypair representing the owner key for encryption * @param password * - to protect the private key */ @Override public void setOwnerKeyEnc(KeyPair ownerKeyEnc, char[] password) { try { // set key for existing signature cert if it already has been set, // otherwise create completely new one X509Certificate certChain = getCertEnc(); if (certChain == null) { certChain = CryptCore .createSelfSignedX509Certificate( ownerKeyEnc.getPrivate(), ownerKeyEnc.getPublic(), this); } this.keyStore.setKeyEntry(OWNER_KEY_ENC_PRIV, ownerKeyEnc.getPrivate(), password, new java.security.cert.Certificate[] { certChain }); // store as certificate as well this.keyStore.setCertificateEntry(OWNER_CERT_ENC, certChain); } catch (KeyStoreException e) { logger.error("Could not add " + OWNER_KEY_ENC_PRIV + " to identity's keystore", e); } } /** * Retrieve the public key for encryption as a certificate (i.e. with expiry * dates) * * @return null if an error occurred */ @Override public X509Certificate getCertEnc() { try { return (X509Certificate) this.keyStore .getCertificate(OWNER_CERT_ENC); } catch (KeyStoreException e) { logger.error("Could not fetch " + OWNER_CERT_ENC + " from identity's keystore", e); } return null; } /** * Retrieve the public key for signatures as a certificate (i.e. with expiry * dates) * * @return null if an error occurred */ @Override public X509Certificate getCertSign() { try { return (X509Certificate) this.keyStore .getCertificate(OWNER_CERT_SIGN); } catch (KeyStoreException e) { logger.error("Could not fetch " + OWNER_CERT_ENC + " from identity's keystore", e); } return null; } /** * Stores a given device key in the keystore of this identity. * The given device key will be protected with the well known * secret. * * @param ownerKeySign * - Keypair representing the device key * @param deviceName * - name of the device where the key will be used */ @Override public void addDeviceKey(KeyPair deviceKey, String deviceName) { try { X509Certificate certChain = CryptCore .createSelfSignedX509Certificate(deviceKey.getPrivate(), deviceKey.getPublic(), this); this.keyStore.setKeyEntry(deviceName, deviceKey.getPrivate(), KeyConstants.OPEN_KEYSTORE_PASSWORD, new java.security.cert.Certificate[] { certChain }); } catch (KeyStoreException e) { logger.error("Could not add device key for device " + deviceName + " to identity's keystore", e); } } /** * Stores a given device key in the keystore of this identity. * The given device key will be protected with the provided * password. * * @param ownerKeySign * - Keypair representing the device key * @param deviceName * - name of the device where the key will be used */ @Override public void addDeviceKey(KeyPair deviceKey, String deviceName, char[] password) { try { X509Certificate certChain = CryptCore .createSelfSignedX509Certificate(deviceKey.getPrivate(), deviceKey.getPublic(), this); this.keyStore.setKeyEntry(deviceName, deviceKey.getPrivate(), password, new java.security.cert.Certificate[] { certChain }); } catch (KeyStoreException e) { logger.error("Could not add device key for device " + deviceName + " to identity's keystore", e); } } /** * Stores a given device key and its certificate in the keystore of this * identity * * @param deviceKey * - Keypair representing the device key * @param deviceCert * - X509 certificate for the device * @param deviceName * - name of the device where the key will be used */ @Override public void addDeviceKey(KeyPair deviceKey, Certificate deviceCert, String deviceName) { try { this.keyStore.setKeyEntry(deviceName, deviceKey.getPrivate(), KeyConstants.OPEN_KEYSTORE_PASSWORD, new java.security.cert.Certificate[] { deviceCert }); } catch (KeyStoreException e) { logger.error("Could not add device key for device " + deviceName + " to identity's keystore", e); } } /** * Stores a certificate from a second device in our keystore (i.e. we are * running on a laptop and get the certificate from our mobile) * * @param cert * - Certificate of the other device * @param deviceName * - Name of the other device */ @Override public void addDeviceCert(Certificate cert, String deviceName) { try { this.keyStore.setCertificateEntry(deviceName, cert); } catch (KeyStoreException e) { logger.error("Could not add device certificate for device " + deviceName + " to identity's keystore", e); } } @Override public Certificate getDeviceCert(String deviceName) { try { return this.keyStore.getCertificate(deviceName); } catch (KeyStoreException e) { logger.error("Could not get device certificate for device " + deviceName + " from identity's keystore", e); } return null; } public KeyStore getKeyStore() { return keyStore; } /** * If an existing keystore is loaded from a file, set it with this method * * @param keyStore */ public void setKeyStore(KeyStore keyStore) { this.keyStore = keyStore; } /** * Retrieve the private owner key for signing out of the keystore * * @param password * - Password to unlock the private key * @return - Private Key for signing */ @Override public PrivateKey getPrivateKeySign(char[] password) throws UnrecoverableKeyException { PrivateKey key = null; try { key = (PrivateKey) this.keyStore.getKey(OWNER_KEY_SIGN_PRIV, password); } catch (KeyStoreException | NoSuchAlgorithmException e) { logger.error("Could not fetch " + OWNER_KEY_SIGN_PRIV + " from identity's keystore", e); throw new UnrecoverableKeyException("Could not fetch " + OWNER_KEY_SIGN_PRIV + " from identity's keystore"); } return key; } /** * Retrieve the private owner key for encryption out of the keystore * * @param password * - Password to unlock the private key * @return - Private key for encryption, or null if an error occurred * @throws UnrecoverableKeyException */ @Override public PrivateKey getPrivateKeyEnc(char[] password) throws UnrecoverableKeyException { PrivateKey key = null; try { key = (PrivateKey) this.keyStore.getKey(OWNER_KEY_ENC_PRIV, password); } catch (KeyStoreException | NoSuchAlgorithmException e) { throw new UnrecoverableKeyException("Could not fetch private key " + OWNER_KEY_ENC_PRIV + " from identity's keystore"); } return key; } /** * Retrieve the public owner key for encryption * * @return - public owner key for encryption, or null if an error occurred */ @Override public PublicKey getPublicKeyEnc() { PublicKey key = null; try { //OWNER_CERT_ENC // key = (PublicKey) this.keyStore.getCertificate(OWNER_KEY_ENC_PRIV) // .getPublicKey(); key = (PublicKey) this.keyStore.getCertificate(OWNER_CERT_ENC) .getPublicKey(); } catch (KeyStoreException e) { logger.error("Could not fetch public key " + OWNER_CERT_ENC + " from identity's keystore", e); } return key; } /** * Retrieve the public owner key for signing * * @return - public owner key for signing, or null if an error occurred */ @Override public PublicKey getPublicKeySign() { PublicKey key = null; try { //OWNER_CERT_SIGN // key = (PublicKey) this.keyStore.getCertificate(OWNER_KEY_SIGN_PRIV) // .getPublicKey(); key = (PublicKey) this.keyStore.getCertificate(OWNER_CERT_SIGN) .getPublicKey(); } catch (KeyStoreException e) { logger.error("Could not fetch certificate " + OWNER_CERT_SIGN + " from identity's keystore", e); } return key; } /** * Retrieve the private key of a device with name deviceName * * @param password * - password to unlock the key * @param deviceName * - name of the device to retrieve the private key for * @return - private key for deviceName or null if we run on a different * device * @throws GeneralSecurityException */ @Override public PrivateKey getPrivateKeyForDevice(char[] password, String deviceName) throws UnrecoverableKeyException { PrivateKey key = null; try { key = (PrivateKey) this.keyStore.getKey(deviceName, password); } catch (KeyStoreException | NoSuchAlgorithmException e) { logger.error("Could not fetch private key for device " + deviceName + " from identity's keystore", e); } return key; } /** * Retrieve the public key of a device with name deviceName * * @param deviceName * - name of the device to retrieve the public key for * @return - public key of device deviceName, or null if an error occurred * @throws UnrecoverableKeyException */ @Override public PublicKey getPublicKeyForDevice(String deviceName) throws UnrecoverableKeyException { PublicKey key = null; try { Certificate certificate = this.keyStore.getCertificate(deviceName); if (certificate == null) { throw new UnrecoverableKeyException( "Could not find Certificate for device " + deviceName); } key = (PublicKey) certificate.getPublicKey(); } catch (KeyStoreException e) { logger.error("Could not fetch public key for device " + deviceName + " from identity's keystore", e); } return key; } @Override /** * Obtain a list of all device names the identity has keys for * * @return - List of devices as strings */ public Collection<String> getDeviceList() { LinkedList<String> myDevices = new LinkedList<String>(); String alias = null; try { Enumeration<String> aliases = this.keyStore.aliases(); while (aliases.hasMoreElements()) { alias = aliases.nextElement(); if (!OWNER_CERT_ENC.equalsIgnoreCase(alias) && !OWNER_CERT_SIGN.equalsIgnoreCase(alias) && !OWNER_KEY_ENC_PRIV.equalsIgnoreCase(alias) && !OWNER_KEY_SIGN_PRIV.equalsIgnoreCase(alias)) { myDevices.add(alias); } } } catch (KeyStoreException e) { logger.error( "Could not fetch key aliases from identity's keystore", e); } return myDevices; } @Override public void setOwnerKeySign(Certificate cert) { try { this.keyStore.setCertificateEntry(OWNER_CERT_SIGN, cert); } catch (KeyStoreException e) { logger.error( "Could not store certificate for signing in identity's keystore", e); } } @Override public void setOwnerKeyEnc(Certificate cert) { try { this.keyStore.setCertificateEntry(OWNER_CERT_ENC, cert); } catch (KeyStoreException e) { logger.error( "Could not store certificate for encryption in identity's keystore", e); } } @Override public boolean checkCertificateValidity() { X509Certificate sigCert = getCertSign(); X509Certificate encCert = getCertEnc(); if (null == sigCert || null == encCert) { logger.error("Cannot obtain Certificates for validation"); // treat as invalid return false; } Date now = new Date(); try { sigCert.checkValidity(now); encCert.checkValidity(now); } catch (CertificateExpiredException | CertificateNotYetValidException e) { // certificate not (yet) valid return false; } return true; } }