Class ExternalKeyStoreTest
- java.lang.Object
-
- com.microej.crypto.test.ExternalKeyStoreTest
-
public class ExternalKeyStoreTest extends java.lang.ObjectThis test class validates a LLSEC-External-KeyStore Abstraction Layer implementation.It requires the external key store to be provisioned with at least a private key, a certificate chain, a secret key and a trusted certificate (not attached to a key, i.e. with the same alias). Such a PKCS12 keystore is provided in resources, it must be configured with the Application option:
-Dej.crypto.mock.externalks.path=${project_loc:/security-testsuite}/src/test/resources/test-keystore.p12To configure the tests, set the following properties:
com.microej.crypto.test.ExternalKeyStoreTest.keystore.type: the type of the KeyStore to test (seeKeyStore.getInstance(String)) (defaults to "EXTERNALKS"),com.microej.crypto.test.ExternalKeyStoreTest.keystore.password: the password of the KeyStore to test (seeKeyStore.load(java.io.InputStream, char[])) (defaults to "changeit"),com.microej.crypto.test.ExternalKeyStoreTest.keystore.size: the expected number of entries in the provisioned KeyStore, or a negative value when the number of entries is not known at configuration time (defaults to 4),com.microej.crypto.test.ExternalKeyStoreTest.privatekey.extractable: whetherKeyStore.getKey().getEncoded()returns the raw key bytes for a private key imported viasetKeyEntry. Set tofalsefor HSM-backed keystores (e.g. PKCS#11) where the key never leaves the token, which makes the test require thenullthatjava.security.Key.getEncoded()specifies for a key with no encoded form; set totruefor file-backed keystores like PKCS#12 (defaults to true),com.microej.crypto.test.ExternalKeyStoreTest.privatekey.import.algorithms: the algorithms of the private keys the import tests set throughsetKeyEntry, a comma separated list ofRSAandEC. For each one the tests set the committed key of the first configured RSA key size or EC curve, its certificate, and the same key encrypted with the key store password (defaults to "RSA,EC", also when the property is empty),com.microej.crypto.test.ExternalKeyStoreTest.privatekey.alias: the alias of a valid private key (defaults to "test-entity"),com.microej.crypto.test.ExternalKeyStoreTest.privatekey.tmp.alias: the alias used by tests that mutate a private-key entry (set/delete) so they don't pollute the production private-key alias (defaults to "test-tmp-private"),com.microej.crypto.test.ExternalKeyStoreTest.privatekey.password: the password for this private key (defaults to "changeit"),com.microej.crypto.test.ExternalKeyStoreTest.privatekey.signature.algorithm: the signature algorithm to use for testing the use of the private key from the KeyStore (defaults to "SHA256withECDSA"),com.microej.crypto.test.ExternalKeyStoreTest.privatekey.signature.data: the payload to sign when testing signature with the private key from the KeyStore; the produced signature is verified against the trusted certificate rather than a fixed expected output (defaults to "Hello World!"),com.microej.crypto.test.ExternalKeyStoreTest.privatekey.keyagreement.algorithm: the key agreement algorithm to use for testing key agreement with the private key from the KeyStore (defaults to "ECDH"),com.microej.crypto.test.ExternalKeyStoreTest.privatekey.keyagreement.secret: the expected shared secret (base64-encoded) computed by key agreement between the private key from the KeyStore and the public key from the trusted certificate (defaults to "Lg7mq+j/QKp8sk+zMK0tPmnKvpQhS7yZEAr4Y/HN7JOMp/ePumCoWCY/hA0llZYO"),com.microej.crypto.test.ExternalKeyStoreTest.secretkey.extractable: whetherKeyStore.getKey().getEncoded()returns the raw key bytes for a secret key imported viasetKeyEntry. Set tofalsefor HSM-backed keystores (e.g. PKCS#11), which makes the test require thenullthatjava.security.Key.getEncoded()specifies for a key with no encoded form; set totruefor file-backed keystores like PKCS#12 (defaults to true),com.microej.crypto.test.ExternalKeyStoreTest.secretkey.data: the encoded secret key data in base64 (defaults to "L83/flz9vi46b8aX57Trqg=="),com.microej.crypto.test.ExternalKeyStoreTest.secretkey.algorithm: the algorithm of the secret key (defaults to "AES"),com.microej.crypto.test.ExternalKeyStoreTest.secretkey.alias: the alias of a valid secret key (defaults to "test-secret"),com.microej.crypto.test.ExternalKeyStoreTest.secretkey.tmp.alias: the alias used by tests that mutate a secret-key entry (set/delete) so they don't pollute the production secret-key alias (defaults to "test-tmp-secret"),com.microej.crypto.test.ExternalKeyStoreTest.secretkey.import.loops: the number of set, get and delete cycles of the repeated secret-key import test (defaults to 10),com.microej.crypto.test.ExternalKeyStoreTest.getcertificate.repeat: the number of gets of the repeated certificate get test (defaults to 200),com.microej.crypto.test.ExternalKeyStoreTest.secretkey.password: the password for this secret key (defaults to "changeit"),com.microej.crypto.test.ExternalKeyStoreTest.secretkey.cipher.transformation: the cipher transformation to use for testing the use of the secret key from the KeyStore (defaults to "AES/CBC/NoPadding"),com.microej.crypto.test.ExternalKeyStoreTest.secretkey.cipher.payload: the plaintext payload to encrypt when testing the cipher, as a hex string (defaults to "00112233445566778899AABBCCDDEEFF"),com.microej.crypto.test.ExternalKeyStoreTest.secretkey.cipher.iv: the IV used by the cipher, as a hex string (defaults to "00112233445566778899AABBCCDDEEFF"),com.microej.crypto.test.ExternalKeyStoreTest.secretkey.cipher.encrypted: the expected ciphertext (base64-encoded) produced by the cipher on the configured payload/IV (defaults to "vF23ACh1j3eRnVIkfKq9rb+8FpSYLFE3TcthFDnmOcg="),com.microej.crypto.test.ExternalKeyStoreTest.certificate.data: an X.509 certificate (base64-encoded DER) used by mutation tests when importing a trusted-certificate or certificate-chain entry (defaults to a built-in test certificate),com.microej.crypto.test.ExternalKeyStoreTest.certificate.alias: the alias of a valid trusted certificate, not attached to a key (defaults to "test-trusted-cert"),com.microej.crypto.test.ExternalKeyStoreTest.certificate.tmp.alias: the alias used by tests that mutate a trusted-certificate entry (set/delete) so they don't pollute the production certificate alias (defaults to "test-tmp-cert"),com.microej.crypto.test.ExternalKeyStoreTest.certificatechain.alias: the alias of a valid certificate chain (defaults to "test-entity"),com.microej.crypto.test.ExternalKeyStoreTest.certificatechain.length: the expected length of the certificate chain at the certificatechain alias (defaults to 2),
The tests that set an entry use the
tmpaliases only, and never delete an entry they did not set: a test aborts with the name of the alias when its temporary alias already holds an entry. This matters on a device, where the key store outlives the test image and a run killed mid-test leaves its temporary alias occupied.
-
-
Constructor Summary
Constructors Constructor Description ExternalKeyStoreTest()
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description voidcheckKeyStoreIsProvisioned()Checks the entries these tests get are present, and reports which are missing when they are not.static voidsetUpTime()voidtestCanUsePrivateKeyFromKeyStoreForKeyAgreement()voidtestCanUsePrivateKeyFromKeyStoreForSignatureAndVerifyItWithCertificate()voidtestCanUsePrivateKeyFromKeyStoreForSignatureAndVerifyItWithCertificateWithPayload()voidtestCanUseSecretKeyFromKeyStoreForCipher()voidtestCheckEntryType()voidtestContainsAlias()voidtestDeleteEntryInvalidAlias()voidtestGcConsistency()voidtestGetCertificate()voidtestGetCertificateChain()voidtestGetCertificateChainForInvalidAliasReturnsNull()voidtestGetCertificateChainForNonCertificateAliasReturnsNull()voidtestGetCertificateForCertificateChainAliasReturnsFirstCertificate()voidtestGetCertificateForInvalidAliasReturnsNull()voidtestGetCertificateForNonCertificateAliasReturnsNull()voidtestGetKey()voidtestGetKeyForInvalidAliasReturnsNull()voidtestGetKeyForNonKeyAliasReturnsNull()voidtestImportedPrivateKeyFromDataIsUsable()Checks that a private key imported throughKeyStore.setKeyEntry(String, byte[], Certificate[])is usable, not merely retrievable.voidtestImportedPrivateKeyFromKeyObjectIsUsable()Checks that a private key imported throughKeyStore.setKeyEntry(String, Key, char[], Certificate[])is usable, not merely retrievable.voidtestIsCertificateEntryFollowsWhatIsSet()Checks that a certificate alias is reported as a certificate entry only while it holds a certificate.voidtestListAliases()voidtestListAliasesDoesNotLeakStaleBytes()voidtestLoadWithWrongPasswordIsRejected()Loading the KeyStore with a wrong password fails with anIOExceptioncaused by anUnrecoverableKeyException, asKeyStore.load(InputStream, char[])specifies, so a caller can tell a wrong password from any other load failure.voidtestRepeatedGetCertificate()Gets the trusted certificate repeatedly, to catch a leak or a stale handle in the get path.voidtestRepeatedSetGetDeleteSecretKey()Checks that repeated set, get and delete cycles of a secret key keep returning the value set.voidtestSetCertificateAndDeleteEntry()voidtestSetCertificateEntry()voidtestSetKeyEntryPrivateKeyAndCertificateChain()voidtestSetKeyEntryPrivateKeyProtected()voidtestSetKeyEntrySecretKey()voidtestSetKeyEntryTwiceOnSameAlias()Checks that a second set into an alias that already holds an entry leaves the alias in a consistent state.voidtestSetKeyEntryWithUnencodableCertificateKeepsPreviousEntry()A failedsetKeyEntry()on an alias that holds an entry leaves that entry as it was.voidtestSetKeyEntryWithUnencodableCertificateLeavesAliasFree()A key entry whose certificate chain cannot be fully handed over is not written:setKeyEntry()fails and the alias stays free.voidtestSetPrivateKeyProtectedAndDeleteEntry()voidtestSetSecretKeyAndDeleteEntry()voidtestSizeFollowsSetAndDelete()Checks thatsize()follows what is set: one more after a set, back to the initial value after the delete, and always equal to the number of aliases enumerated.voidtestUnknownAliasIsNotAnEntry()Checks that an unknown alias is reported as absent by every call that takes one.
-
-
-
Method Detail
-
setUpTime
public static void setUpTime()
-
checkKeyStoreIsProvisioned
public void checkKeyStoreIsProvisioned() throws java.lang.ExceptionChecks the entries these tests get are present, and reports which are missing when they are not.Without this, a key store that was never provisioned fails every test on an assertion about a null key, which says nothing about the cause. An alias configured to the empty string is not required.
- Throws:
java.lang.Exception- if the key store cannot be loaded
-
testListAliases
public void testListAliases() throws java.lang.Exception- Throws:
java.lang.Exception
-
testSizeFollowsSetAndDelete
public void testSizeFollowsSetAndDelete() throws java.lang.ExceptionChecks thatsize()follows what is set: one more after a set, back to the initial value after the delete, and always equal to the number of aliases enumerated.- Throws:
java.lang.Exception- on any error
-
testIsCertificateEntryFollowsWhatIsSet
public void testIsCertificateEntryFollowsWhatIsSet() throws java.lang.ExceptionChecks that a certificate alias is reported as a certificate entry only while it holds a certificate.- Throws:
java.lang.Exception- on any error
-
testUnknownAliasIsNotAnEntry
public void testUnknownAliasIsNotAnEntry() throws java.lang.ExceptionChecks that an unknown alias is reported as absent by every call that takes one.- Throws:
java.lang.Exception- on any error
-
testSetKeyEntryTwiceOnSameAlias
public void testSetKeyEntryTwiceOnSameAlias() throws java.lang.ExceptionChecks that a second set into an alias that already holds an entry leaves the alias in a consistent state.The contract allows two outcomes. A key store that accepts the set replaces the entry: the second value is held. A key store that refuses it, because each alias holds one entry until it is deleted, throws a
KeyStoreException: the first value is still held. What the contract forbids is a set that neither throws nor takes effect.- Throws:
java.lang.Exception- on any error
-
testRepeatedGetCertificate
public void testRepeatedGetCertificate() throws java.lang.ExceptionGets the trusted certificate repeatedly, to catch a leak or a stale handle in the get path.Each get allocates a native handle that the library releases once the certificate bytes are copied. A handle left allocated exhausts the native heap after enough gets. Each get must return the same encoded certificate as the first one: a stale buffer that still parses as a certificate is detected by the comparison, not by the null checks.
- Throws:
java.lang.Exception- on any error
-
testListAliasesDoesNotLeakStaleBytes
public void testListAliasesDoesNotLeakStaleBytes() throws java.lang.Exception- Throws:
java.lang.Exception
-
testContainsAlias
public void testContainsAlias() throws java.lang.Exception- Throws:
java.lang.Exception
-
testGetKey
public void testGetKey() throws java.lang.Exception- Throws:
java.lang.Exception
-
testGetKeyForInvalidAliasReturnsNull
public void testGetKeyForInvalidAliasReturnsNull() throws java.lang.Exception- Throws:
java.lang.Exception
-
testGetKeyForNonKeyAliasReturnsNull
public void testGetKeyForNonKeyAliasReturnsNull() throws java.lang.Exception- Throws:
java.lang.Exception
-
testGetCertificate
public void testGetCertificate() throws java.lang.Exception- Throws:
java.lang.Exception
-
testGetCertificateForInvalidAliasReturnsNull
public void testGetCertificateForInvalidAliasReturnsNull() throws java.lang.Exception- Throws:
java.lang.Exception
-
testGetCertificateForNonCertificateAliasReturnsNull
public void testGetCertificateForNonCertificateAliasReturnsNull() throws java.lang.Exception- Throws:
java.lang.Exception
-
testGetCertificateChain
public void testGetCertificateChain() throws java.lang.Exception- Throws:
java.lang.Exception
-
testGetCertificateChainForInvalidAliasReturnsNull
public void testGetCertificateChainForInvalidAliasReturnsNull() throws java.lang.Exception- Throws:
java.lang.Exception
-
testCheckEntryType
public void testCheckEntryType() throws java.lang.Exception- Throws:
java.lang.Exception
-
testSetCertificateAndDeleteEntry
public void testSetCertificateAndDeleteEntry() throws java.lang.Exception- Throws:
java.lang.Exception
-
testSetPrivateKeyProtectedAndDeleteEntry
public void testSetPrivateKeyProtectedAndDeleteEntry() throws java.lang.Exception- Throws:
java.lang.Exception
-
testSetSecretKeyAndDeleteEntry
public void testSetSecretKeyAndDeleteEntry() throws java.lang.Exception- Throws:
java.lang.Exception
-
testLoadWithWrongPasswordIsRejected
public void testLoadWithWrongPasswordIsRejected() throws java.lang.ExceptionLoading the KeyStore with a wrong password fails with anIOExceptioncaused by anUnrecoverableKeyException, asKeyStore.load(InputStream, char[])specifies, so a caller can tell a wrong password from any other load failure.A hardware token counts failed logins and locks after a few in a row. The correct login that follows the wrong one resets that count, so a run of this test uses up no retry of the token.
- Throws:
java.lang.Exception- if the KeyStore cannot be created or loaded with the correct password
-
testDeleteEntryInvalidAlias
public void testDeleteEntryInvalidAlias() throws java.lang.Exception- Throws:
java.lang.Exception
-
testRepeatedSetGetDeleteSecretKey
public void testRepeatedSetGetDeleteSecretKey() throws java.lang.ExceptionChecks that repeated set, get and delete cycles of a secret key keep returning the value set.Each cycle sets a different known value, so a stale native buffer left from a previous cycle cannot pass. The cycles also exercise the release path of the native key entry: a leak shows on a bounded native heap.
- Throws:
java.lang.Exception- on any error
-
testImportedPrivateKeyFromDataIsUsable
public void testImportedPrivateKeyFromDataIsUsable() throws java.lang.ExceptionChecks that a private key imported throughKeyStore.setKeyEntry(String, byte[], Certificate[])is usable, not merely retrievable.- Throws:
java.lang.Exception- on any error
-
testImportedPrivateKeyFromKeyObjectIsUsable
public void testImportedPrivateKeyFromKeyObjectIsUsable() throws java.lang.ExceptionChecks that a private key imported throughKeyStore.setKeyEntry(String, Key, char[], Certificate[])is usable, not merely retrievable.The two overloads reach the native layer by different routes, one hands over the encoded key, the other a key object the native side exports itself, so each needs its own proof that the material set is correct.
- Throws:
java.lang.Exception- on any error
-
testSetCertificateEntry
public void testSetCertificateEntry() throws java.lang.Exception- Throws:
java.lang.Exception
-
testSetKeyEntryPrivateKeyAndCertificateChain
public void testSetKeyEntryPrivateKeyAndCertificateChain() throws java.lang.Exception- Throws:
java.lang.Exception
-
testSetKeyEntryWithUnencodableCertificateLeavesAliasFree
public void testSetKeyEntryWithUnencodableCertificateLeavesAliasFree() throws java.lang.ExceptionA key entry whose certificate chain cannot be fully handed over is not written:setKeyEntry()fails and the alias stays free.The library declares the chain length when it opens the entry, hands the certificates over one by one, and closes the entry from a
finallyblock even when one of them failed. The close is where a backend commits the entry to its store, and the only place that can tell a complete chain from one the library gave up on. A backend that commits what it received leaves an alias holding a key with a truncated chain.- Throws:
java.lang.Exception
-
testSetKeyEntryWithUnencodableCertificateKeepsPreviousEntry
public void testSetKeyEntryWithUnencodableCertificateKeepsPreviousEntry() throws java.lang.ExceptionA failedsetKeyEntry()on an alias that holds an entry leaves that entry as it was.The other half of
testSetKeyEntryWithUnencodableCertificateLeavesAliasFree(): a backend that replaces the entry before the chain is complete, or removes it on the abort, destroys a valid entry on a failed set.- Throws:
java.lang.Exception
-
testSetKeyEntryPrivateKeyProtected
public void testSetKeyEntryPrivateKeyProtected() throws java.lang.Exception- Throws:
java.lang.Exception
-
testSetKeyEntrySecretKey
public void testSetKeyEntrySecretKey() throws java.lang.Exception- Throws:
java.lang.Exception
-
testGetCertificateChainForNonCertificateAliasReturnsNull
public void testGetCertificateChainForNonCertificateAliasReturnsNull() throws java.lang.Exception- Throws:
java.lang.Exception
-
testGetCertificateForCertificateChainAliasReturnsFirstCertificate
public void testGetCertificateForCertificateChainAliasReturnsFirstCertificate() throws java.lang.Exception- Throws:
java.lang.Exception
-
testCanUsePrivateKeyFromKeyStoreForSignatureAndVerifyItWithCertificateWithPayload
public void testCanUsePrivateKeyFromKeyStoreForSignatureAndVerifyItWithCertificateWithPayload() throws java.lang.Exception- Throws:
java.lang.Exception
-
testCanUsePrivateKeyFromKeyStoreForSignatureAndVerifyItWithCertificate
public void testCanUsePrivateKeyFromKeyStoreForSignatureAndVerifyItWithCertificate() throws java.lang.Exception- Throws:
java.lang.Exception
-
testCanUseSecretKeyFromKeyStoreForCipher
public void testCanUseSecretKeyFromKeyStoreForCipher() throws java.lang.Exception- Throws:
java.lang.Exception
-
testCanUsePrivateKeyFromKeyStoreForKeyAgreement
public void testCanUsePrivateKeyFromKeyStoreForKeyAgreement() throws java.lang.Exception- Throws:
java.lang.Exception
-
testGcConsistency
public void testGcConsistency() throws java.lang.Exception- Throws:
java.lang.Exception
-
-