-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WIP: Further implement PKCS#11 connection
- Loading branch information
Showing
16 changed files
with
200 additions
and
148 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
app/src/main/java/dev/mieser/tsa/signing/impl/cert/CertificateAndPrivateKey.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package dev.mieser.tsa.signing.impl.cert; | ||
|
||
import java.security.PrivateKey; | ||
import java.security.cert.X509Certificate; | ||
|
||
public record CertificateAndPrivateKey(X509Certificate certificate, PrivateKey privateKey) { | ||
|
||
} |
36 changes: 0 additions & 36 deletions
36
app/src/main/java/dev/mieser/tsa/signing/impl/cert/Pkcs11SigningKeystoreLoader.java
This file was deleted.
Oops, something went wrong.
21 changes: 0 additions & 21 deletions
21
app/src/main/java/dev/mieser/tsa/signing/impl/cert/SigningKeystoreLoader.java
This file was deleted.
Oops, something went wrong.
21 changes: 21 additions & 0 deletions
21
app/src/main/java/dev/mieser/tsa/signing/impl/cert/keystore/KeystoreEntryExtractor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package dev.mieser.tsa.signing.impl.cert.keystore; | ||
|
||
import java.security.KeyStore; | ||
import java.security.KeyStoreException; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.security.UnrecoverableEntryException; | ||
|
||
/** | ||
* Interface abstraction of the {@link KeyStore#getCertificate(String)} and {@link KeyStore#getKey(String, char[])} | ||
* methods. | ||
* | ||
* @param <T> | ||
* The type of the certificate or key to be abstracted from the {@link KeyStore}. | ||
*/ | ||
@FunctionalInterface | ||
interface KeystoreEntryExtractor<T> { | ||
|
||
T extractEntry(KeyStore keyStore, | ||
String alias) throws KeyStoreException, UnrecoverableEntryException, NoSuchAlgorithmException; | ||
|
||
} |
80 changes: 80 additions & 0 deletions
80
app/src/main/java/dev/mieser/tsa/signing/impl/cert/keystore/Pkcs11SigningKeystoreLoader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package dev.mieser.tsa.signing.impl.cert.keystore; | ||
|
||
import java.io.IOException; | ||
import java.security.*; | ||
import java.security.cert.Certificate; | ||
import java.security.cert.CertificateException; | ||
import java.security.cert.X509Certificate; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
import dev.mieser.tsa.signing.impl.cert.CertificateAndPrivateKey; | ||
|
||
/** | ||
* {@link SigningKeystoreLoader} which loads key material from a PKCS#11 token. | ||
*/ | ||
@Slf4j | ||
@RequiredArgsConstructor | ||
public class Pkcs11SigningKeystoreLoader implements SigningKeystoreLoader { | ||
|
||
private static final String KEYSTORE_TYPE = "pkcs11"; | ||
|
||
private final Provider pkcs11JceProvider; | ||
|
||
private final char[] pin; | ||
|
||
// TODO: refactor + unify with Pkcs12 logic | ||
@Override | ||
public CertificateAndPrivateKey loadCertificateAndPrivateKey() { | ||
KeyStore keyStore = loadKeystoreFromToken(); | ||
List<String> keyIdentifiers = extractKeyIdentifiers(keyStore); | ||
if (keyIdentifiers.isEmpty()) { | ||
throw new IllegalStateException("The configured PKCS#11 token contains no certificates."); | ||
} else if (keyIdentifiers.size() > 1) { | ||
throw new IllegalStateException("The configured PKCS#11 token contains than one certificate: " + keyIdentifiers); | ||
} | ||
|
||
String keyIdentifierToUse = keyIdentifiers.getFirst(); | ||
try { | ||
Key key = keyStore.getKey(keyIdentifierToUse, pin); | ||
if (!(key instanceof PrivateKey)) { | ||
throw new IllegalStateException("Key is not a private key!"); | ||
} | ||
|
||
Certificate certificate = keyStore.getCertificate(keyIdentifierToUse); | ||
if (!(certificate instanceof X509Certificate)) { | ||
throw new IllegalStateException("Certificate is not a X509 certificate!"); | ||
} | ||
|
||
return new CertificateAndPrivateKey((X509Certificate) certificate, (PrivateKey) key); | ||
} catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
private KeyStore loadKeystoreFromToken() { | ||
try { | ||
KeyStore pkcs11Keystore = KeyStore.getInstance(KEYSTORE_TYPE, pkcs11JceProvider); | ||
pkcs11Keystore.load(null, pin); | ||
|
||
return pkcs11Keystore; | ||
} catch (KeyStoreException e) { | ||
throw new IllegalStateException("The pseudo-mechanism of the SunPKCS11 provider to read keystores (PCKM_KEYSTORE) " + | ||
"is not enabled. Please add it to the list of enabled mechanisms."); | ||
} catch (CertificateException | IOException | NoSuchAlgorithmException e) { | ||
throw new IllegalStateException("Failed to query certificates and private keys from PKCS#11 token.", e); | ||
} | ||
} | ||
|
||
private List<String> extractKeyIdentifiers(KeyStore keyStore) { | ||
try { | ||
return Collections.list(keyStore.aliases()); | ||
} catch (KeyStoreException e) { | ||
throw new IllegalStateException("Failed to query certificates from PKCS#11 token.", e); | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.