GordianKeyStoreElement.java
/*
* GordianKnot: Security Suite
* Copyright 2012-2026. Tony Washer
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.github.tonywasher.joceanus.gordianknot.impl.core.keystore;
import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
import io.github.tonywasher.joceanus.gordianknot.api.base.GordianKeySpec;
import io.github.tonywasher.joceanus.gordianknot.api.cert.GordianCertificate;
import io.github.tonywasher.joceanus.gordianknot.api.factory.GordianFactory;
import io.github.tonywasher.joceanus.gordianknot.api.key.GordianKey;
import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPair;
import io.github.tonywasher.joceanus.gordianknot.api.keyset.GordianKeySet;
import io.github.tonywasher.joceanus.gordianknot.api.lock.GordianKeySetLock;
import io.github.tonywasher.joceanus.gordianknot.api.lock.GordianLockFactory;
import io.github.tonywasher.joceanus.gordianknot.api.lock.GordianPasswordLockSpec;
import io.github.tonywasher.joceanus.gordianknot.impl.core.cert.GordianCoreCertificate;
import io.github.tonywasher.joceanus.gordianknot.impl.core.keystore.GordianBaseKeyStore.GordianKeyStoreCertificateKey;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* KeyStoreElement.
* <p>
* These are the entries as held in the keyStore.
* </p>
*/
public interface GordianKeyStoreElement {
/**
* KeyStore Certificate.
*/
interface GordianKeyStoreCertificateHolder {
/**
* Obtain the key.
*
* @return the key
*/
GordianKeyStoreCertificateKey getCertificateKey();
}
/**
* KeyStore Certificate Element.
*/
class GordianKeyStoreCertificateElement
extends GordianCoreKeyStoreEntry
implements GordianKeyStoreCertificateHolder {
/**
* The certificate Id.
*/
private final GordianKeyStoreCertificateKey theKey;
/**
* Constructor.
*
* @param pCertificate the certificate.
*/
GordianKeyStoreCertificateElement(final GordianCertificate pCertificate) {
theKey = new GordianKeyStoreCertificateKey(pCertificate);
}
/**
* Constructor.
*
* @param pKey the key.
* @param pDate the creation date
*/
GordianKeyStoreCertificateElement(final GordianKeyStoreCertificateKey pKey,
final LocalDate pDate) {
super(pDate);
theKey = pKey;
}
@Override
public GordianKeyStoreCertificateKey getCertificateKey() {
return theKey;
}
/**
* Obtain the corresponding keyStoreEntry.
*
* @param pKeyStore the keyStore
* @return the keyStore certificate entry
*/
GordianCoreKeyStoreCertificate buildEntry(final GordianBaseKeyStore pKeyStore) {
final GordianCoreCertificate myCert = (GordianCoreCertificate) pKeyStore.getCertificate(getCertificateKey());
return new GordianCoreKeyStoreCertificate(myCert, getCreationDate());
}
@Override
public boolean equals(final Object pThat) {
/* Handle the trivial case */
if (pThat == this) {
return true;
}
if (pThat == null) {
return false;
}
/* Ensure object is correct class */
if (!(pThat instanceof GordianKeyStoreCertificateElement)) {
return false;
}
final GordianKeyStoreCertificateElement myThat = (GordianKeyStoreCertificateElement) pThat;
/* Check that the keys match */
return theKey.equals(myThat.getCertificateKey())
&& super.equals(pThat);
}
@Override
public int hashCode() {
return theKey.hashCode()
+ super.hashCode();
}
}
/**
* KeyStore KeyPair Element.
*/
class GordianKeyStorePairElement
extends GordianCoreKeyStoreEntry
implements GordianKeyStoreCertificateHolder {
/**
* The securedPrivateKey.
*/
private final byte[] theSecuredKey;
/**
* The securing lock.
*/
private final GordianKeyStoreLockElement theSecuringLock;
/**
* The certificate chain.
*/
private final List<GordianKeyStoreCertificateKey> theChain;
/**
* Constructor.
*
* @param pFactory the factory
* @param pSpec the passwordLockSpec
* @param pKeyPair the keyPair
* @param pPassword the securing password.
* @param pChain the certificate chain.
* @throws GordianException on error
*/
GordianKeyStorePairElement(final GordianFactory pFactory,
final GordianPasswordLockSpec pSpec,
final GordianKeyPair pKeyPair,
final char[] pPassword,
final List<GordianCertificate> pChain) throws GordianException {
/* Create a securing lock */
final GordianLockFactory myFactory = pFactory.getLockFactory();
final GordianKeySetLock myLock = myFactory.newKeySetLock(pSpec, pPassword);
theSecuringLock = new GordianKeyStoreLockElement(myLock);
final GordianKeySet myKeySet = myLock.getKeySet();
/* Secure the privateKey */
theSecuredKey = securePrivateKey(myKeySet, pKeyPair);
/* Create the chain */
theChain = new ArrayList<>();
for (GordianCertificate myCert : pChain) {
theChain.add(new GordianKeyStoreCertificateKey(myCert));
}
}
/**
* Constructor.
*
* @param pSecuredKey the secured privateKey
* @param pSecuringLock the securing keySetLock.
* @param pChain the certificate chain.
* @param pDate the creation date
*/
GordianKeyStorePairElement(final byte[] pSecuredKey,
final byte[] pSecuringLock,
final List<GordianKeyStoreCertificateKey> pChain,
final LocalDate pDate) {
/* Store details */
super(pDate);
theSecuredKey = pSecuredKey;
theSecuringLock = new GordianKeyStoreLockElement(pSecuringLock, pDate);
theChain = new ArrayList<>(pChain);
}
/**
* Obtain the securedKey.
*
* @return the securedKey
*/
byte[] getSecuredKey() {
return theSecuredKey;
}
/**
* Obtain the securingLock.
*
* @return the securingLock
*/
GordianKeyStoreLockElement getSecuringLock() {
return theSecuringLock;
}
/**
* Obtain the securingLockBytes.
*
* @return the securingLockBytes
*/
byte[] getSecuringLockBytes() {
return theSecuringLock.getLock();
}
@Override
public GordianKeyStoreCertificateKey getCertificateKey() {
return theChain.get(0);
}
/**
* Obtain the certificateChain.
*
* @return the certificateChain
*/
List<GordianKeyStoreCertificateKey> getCertificateChain() {
return theChain;
}
/**
* Update the chain.
*
* @param pChain the new chain.
*/
void updateChain(final List<GordianCertificate> pChain) {
theChain.clear();
for (GordianCertificate myCert : pChain) {
theChain.add(new GordianKeyStoreCertificateKey(myCert));
}
}
/**
* Obtain the secured privateKey.
*
* @param pKeySet the keySet
* @param pKeyPair the keyPair
* @return the securedPrivateKey
* @throws GordianException on error
*/
byte[] securePrivateKey(final GordianKeySet pKeySet,
final GordianKeyPair pKeyPair) throws GordianException {
return pKeySet.securePrivateKey(pKeyPair);
}
/**
* Build the corresponding certificate chain.
*
* @param pKeyStore the keyStore
* @return the certificate chain
*/
List<GordianCertificate> buildChain(final GordianBaseKeyStore pKeyStore) {
/* Create the chain */
final List<GordianKeyStoreCertificateKey> myKeys = getCertificateChain();
final List<GordianCertificate> myChain = new ArrayList<>();
for (GordianKeyStoreCertificateKey myKey : myKeys) {
myChain.add(pKeyStore.getCertificate(myKey));
}
return myChain;
}
/**
* Build the corresponding keyStoreEntry.
*
* @param pKeyStore the keyStore
* @param pPassword the password
* @return the keyStorePair entry
* @throws GordianException on error
*/
GordianCoreKeyStorePair buildEntry(final GordianBaseKeyStore pKeyStore,
final char[] pPassword) throws GordianException {
/* Create the chain */
final List<GordianCertificate> myChain = buildChain(pKeyStore);
/* Resolve securing lock */
final GordianKeySetLock myHash = getSecuringLock().buildEntry(pKeyStore, pPassword);
/* derive the keyPair */
final GordianKeySet myKeySet = myHash.getKeySet();
final GordianCoreCertificate myCert = (GordianCoreCertificate) myChain.get(0);
final GordianKeyPair myPair = myKeySet.deriveKeyPair(myCert.getX509KeySpec(), getSecuredKey());
/* Create the entry */
return new GordianCoreKeyStorePair(myPair, myChain, getCreationDate());
}
@Override
public boolean equals(final Object pThat) {
/* Handle the trivial case */
if (pThat == this) {
return true;
}
if (pThat == null) {
return false;
}
/* Ensure object is correct class */
if (!(pThat instanceof GordianKeyStorePairElement)) {
return false;
}
final GordianKeyStorePairElement myThat = (GordianKeyStorePairElement) pThat;
/* Check that the hashes match */
return Arrays.equals(theSecuredKey, myThat.getSecuredKey())
&& Arrays.equals(getSecuringLockBytes(), myThat.getSecuringLockBytes())
&& theChain.equals(myThat.getCertificateChain())
&& super.equals(pThat);
}
@Override
public int hashCode() {
return Arrays.hashCode(theSecuredKey)
+ Arrays.hashCode(getSecuringLockBytes())
+ theChain.hashCode()
+ super.hashCode();
}
}
/**
* KeyStore lock Element.
*/
class GordianKeyStoreLockElement
extends GordianCoreKeyStoreEntry {
/**
* The hash.
*/
private final byte[] theLock;
/**
* Constructor.
*
* @param pLock the lock.
*/
GordianKeyStoreLockElement(final GordianKeySetLock pLock) {
/* Store details */
theLock = pLock.getLockBytes();
}
/**
* Constructor.
*
* @param pLock the lock.
* @param pDate the creation date
*/
GordianKeyStoreLockElement(final byte[] pLock,
final LocalDate pDate) {
/* Store details */
super(pDate);
theLock = pLock;
}
/**
* Obtain the hash.
*
* @return the hash
*/
byte[] getLock() {
return theLock;
}
/**
* Obtain the corresponding keyStoreEntry.
*
* @param pKeyStore the keyStore
* @param pPassword the password
* @return the keyStore certificate entry
* @throws GordianException on error
*/
GordianKeySetLock buildEntry(final GordianBaseKeyStore pKeyStore,
final char[] pPassword) throws GordianException {
/* Resolve the hash */
final GordianLockFactory myFactory = pKeyStore.getFactory().getLockFactory();
return myFactory.resolveKeySetLock(theLock, pPassword);
}
@Override
public boolean equals(final Object pThat) {
/* Handle the trivial case */
if (pThat == this) {
return true;
}
if (pThat == null) {
return false;
}
/* Ensure object is correct class */
if (!(pThat instanceof GordianKeyStoreLockElement)) {
return false;
}
final GordianKeyStoreLockElement myThat = (GordianKeyStoreLockElement) pThat;
/* Check that the hashes match */
return Arrays.equals(theLock, myThat.getLock())
&& super.equals(pThat);
}
@Override
public int hashCode() {
return Arrays.hashCode(theLock)
+ super.hashCode();
}
}
/**
* KeyStore key Element.
*
* @param <T> the key type
*/
class GordianKeyStoreKeyElement<T extends GordianKeySpec>
extends GordianCoreKeyStoreEntry {
/**
* The keyType.
*/
private final T theKeyType;
/**
* The securedKey.
*/
private final byte[] theSecuredKey;
/**
* The securing lock.
*/
private final GordianKeyStoreLockElement theSecuringLock;
/**
* Constructor.
*
* @param pFactory the factory
* @param pSpec the passwordLockSpec
* @param pKey the key
* @param pPassword the securing password.
* @throws GordianException on error
*/
GordianKeyStoreKeyElement(final GordianFactory pFactory,
final GordianPasswordLockSpec pSpec,
final GordianKey<T> pKey,
final char[] pPassword) throws GordianException {
/* Create a securing lock */
final GordianLockFactory myFactory = pFactory.getLockFactory();
final GordianKeySetLock myLock = myFactory.newKeySetLock(pSpec, pPassword);
final GordianKeySet myKeySet = myLock.getKeySet();
/* Store details */
theKeyType = pKey.getKeyType();
theSecuredKey = myKeySet.secureKey(pKey);
theSecuringLock = new GordianKeyStoreLockElement(myLock);
}
/**
* Constructor.
*
* @param pKeyType the keyType
* @param pSecuredKey the key
* @param pSecuringLock the securing lock.
* @param pDate the creation date
*/
GordianKeyStoreKeyElement(final T pKeyType,
final byte[] pSecuredKey,
final byte[] pSecuringLock,
final LocalDate pDate) {
/* Store details */
super(pDate);
theKeyType = pKeyType;
theSecuredKey = pSecuredKey;
theSecuringLock = new GordianKeyStoreLockElement(pSecuringLock, pDate);
}
/**
* Obtain the keyType.
*
* @return the keyType
*/
T getKeyType() {
return theKeyType;
}
/**
* Obtain the securedKey.
*
* @return the securedKey
*/
byte[] getSecuredKey() {
return theSecuredKey;
}
/**
* Obtain the securingLock.
*
* @return the securingLock
*/
GordianKeyStoreLockElement getSecuringLock() {
return theSecuringLock;
}
/**
* Obtain the securingLockBytes.
*
* @return the securingLockBytes
*/
byte[] getSecuringLockBytes() {
return theSecuringLock.getLock();
}
/**
* Obtain the corresponding keyStoreEntry.
*
* @param pKeyStore the keyStore
* @param pPassword the password
* @return the keyStore certificate entry
* @throws GordianException on error
*/
GordianCoreKeyStoreKey<T> buildEntry(final GordianBaseKeyStore pKeyStore,
final char[] pPassword) throws GordianException {
/* Resolve securing lock */
final GordianKeySetLock myLock = theSecuringLock.buildEntry(pKeyStore, pPassword);
/* derive the key */
final GordianKeySet myKeySet = myLock.getKeySet();
final GordianKey<T> myKey = myKeySet.deriveKey(theSecuredKey, theKeyType);
return new GordianCoreKeyStoreKey<>(myKey, getCreationDate());
}
@Override
public boolean equals(final Object pThat) {
/* Handle the trivial case */
if (pThat == this) {
return true;
}
if (pThat == null) {
return false;
}
/* Ensure object is correct class */
if (!(pThat instanceof GordianKeyStoreKeyElement)) {
return false;
}
final GordianKeyStoreKeyElement<?> myThat = (GordianKeyStoreKeyElement<?>) pThat;
/* Check that the hashes match */
return theKeyType.equals(myThat.getKeyType())
&& Arrays.equals(theSecuredKey, myThat.getSecuredKey())
&& Arrays.equals(getSecuringLockBytes(), myThat.getSecuringLockBytes())
&& super.equals(pThat);
}
@Override
public int hashCode() {
return theKeyType.hashCode()
+ Arrays.hashCode(theSecuredKey)
+ Arrays.hashCode(getSecuringLockBytes())
+ super.hashCode();
}
}
/**
* KeyStore keySet Element.
*/
class GordianKeyStoreSetElement
extends GordianCoreKeyStoreEntry {
/**
* The keyMap.
*/
private final byte[] theSecuredKeySet;
/**
* The securing lock.
*/
private final GordianKeyStoreLockElement theSecuringLock;
/**
* Constructor.
*
* @param pFactory the factory
* @param pSpec the keySetHashSpec
* @param pKeySet the keySet
* @param pPassword the securing password.
* @throws GordianException on error
*/
GordianKeyStoreSetElement(final GordianFactory pFactory,
final GordianPasswordLockSpec pSpec,
final GordianKeySet pKeySet,
final char[] pPassword) throws GordianException {
/* Create a securing hash */
final GordianLockFactory myFactory = pFactory.getLockFactory();
final GordianKeySetLock myLock = myFactory.newKeySetLock(pSpec, pPassword);
final GordianKeySet myKeySet = myLock.getKeySet();
theSecuringLock = new GordianKeyStoreLockElement(myLock);
/* Secure the keySet */
theSecuredKeySet = myKeySet.secureKeySet(pKeySet);
}
/**
* Constructor.
*
* @param pSecuredKeySet the securedKeySet
* @param pSecuringLock the securing lock.
* @param pDate the creation date
*/
GordianKeyStoreSetElement(final byte[] pSecuredKeySet,
final byte[] pSecuringLock,
final LocalDate pDate) {
/* Store details */
super(pDate);
theSecuredKeySet = pSecuredKeySet;
theSecuringLock = new GordianKeyStoreLockElement(pSecuringLock, pDate);
}
/**
* Obtain the keyType.
*
* @return the keyType
*/
byte[] getSecuredKeySet() {
return theSecuredKeySet;
}
/**
* Obtain the securingLock.
*
* @return the securingLock
*/
GordianKeyStoreLockElement getSecuringLock() {
return theSecuringLock;
}
/**
* Obtain the securingLockBytes.
*
* @return the securingLockBytes
*/
byte[] getSecuringLockBytes() {
return theSecuringLock.getLock();
}
/**
* Obtain the corresponding keyStoreEntry.
*
* @param pKeyStore the keyStore
* @param pPassword the password
* @return the keyStore certificate entry
* @throws GordianException on error
*/
GordianCoreKeyStoreSet buildEntry(final GordianBaseKeyStore pKeyStore,
final char[] pPassword) throws GordianException {
/* Resolve the lock */
final GordianKeySetLock myLock = theSecuringLock.buildEntry(pKeyStore, pPassword);
final GordianKeySet mySecuringKeySet = myLock.getKeySet();
/* Derive the keySet */
final GordianKeySet myKeySet = mySecuringKeySet.deriveKeySet(theSecuredKeySet);
/* build the new entry */
return new GordianCoreKeyStoreSet(myKeySet, getCreationDate());
}
@Override
public boolean equals(final Object pThat) {
/* Handle the trivial case */
if (pThat == this) {
return true;
}
if (pThat == null) {
return false;
}
/* Ensure object is correct class */
if (!(pThat instanceof GordianKeyStoreSetElement)) {
return false;
}
final GordianKeyStoreSetElement myThat = (GordianKeyStoreSetElement) pThat;
/* Check that the hashes match */
return Arrays.equals(theSecuredKeySet, myThat.getSecuredKeySet())
&& Arrays.equals(getSecuringLockBytes(), myThat.getSecuringLockBytes())
&& super.equals(pThat);
}
@Override
public int hashCode() {
return Arrays.hashCode(theSecuredKeySet)
+ Arrays.hashCode(getSecuringLockBytes())
+ super.hashCode();
}
}
}