From d1da9a60959aafbe61b6e82cc67c824a8f420d83 Mon Sep 17 00:00:00 2001 From: Lijun Liao Date: Mon, 1 Jan 2024 22:05:57 +0100 Subject: [PATCH 01/11] Prepare for next development iteration. --- CHANGELOG.md | 3 +++ audit-extra/pom.xml | 2 +- audit/pom.xml | 2 +- datasource/pom.xml | 2 +- password/pom.xml | 2 +- pom.xml | 2 +- security-shell/pom.xml | 2 +- security/pom.xml | 2 +- servlet3-common/pom.xml | 2 +- servlet5-common/pom.xml | 2 +- shell-base/pom.xml | 2 +- util/pom.xml | 2 +- xipki-tomcat-password/pom.xml | 2 +- 13 files changed, 15 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52e0719..1618ff2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ See also +## 6.3.5 +- Release date: 2024/mm/dd + ## 6.3.4 - Release date: 2024/01/01 - Features: diff --git a/audit-extra/pom.xml b/audit-extra/pom.xml index cb0bff2..b0c0a9d 100644 --- a/audit-extra/pom.xml +++ b/audit-extra/pom.xml @@ -6,7 +6,7 @@ org.xipki.commons xipki-commons-parent - 6.3.4 + 6.3.5-SNAPSHOT bundle audit-extra diff --git a/audit/pom.xml b/audit/pom.xml index d3a60fc..cb57a78 100644 --- a/audit/pom.xml +++ b/audit/pom.xml @@ -6,7 +6,7 @@ org.xipki.commons xipki-commons-parent - 6.3.4 + 6.3.5-SNAPSHOT bundle audit diff --git a/datasource/pom.xml b/datasource/pom.xml index 32f587a..8105f86 100644 --- a/datasource/pom.xml +++ b/datasource/pom.xml @@ -6,7 +6,7 @@ org.xipki.commons xipki-commons-parent - 6.3.4 + 6.3.5-SNAPSHOT bundle datasource diff --git a/password/pom.xml b/password/pom.xml index 0ba286d..4bebd19 100644 --- a/password/pom.xml +++ b/password/pom.xml @@ -6,7 +6,7 @@ org.xipki.commons xipki-commons-parent - 6.3.4 + 6.3.5-SNAPSHOT bundle password diff --git a/pom.xml b/pom.xml index 5641ab7..042e819 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.xipki.commons xipki-commons-parent pom - 6.3.4 + 6.3.5-SNAPSHOT XiPKI :: ${project.artifactId} XiPKI Parent http://xipki.org diff --git a/security-shell/pom.xml b/security-shell/pom.xml index c086fdc..c82dfbd 100644 --- a/security-shell/pom.xml +++ b/security-shell/pom.xml @@ -6,7 +6,7 @@ org.xipki.commons xipki-commons-parent - 6.3.4 + 6.3.5-SNAPSHOT security-shell bundle diff --git a/security/pom.xml b/security/pom.xml index c14345c..c9b46bc 100644 --- a/security/pom.xml +++ b/security/pom.xml @@ -6,7 +6,7 @@ org.xipki.commons xipki-commons-parent - 6.3.4 + 6.3.5-SNAPSHOT security bundle diff --git a/servlet3-common/pom.xml b/servlet3-common/pom.xml index b69864c..d67bd2b 100644 --- a/servlet3-common/pom.xml +++ b/servlet3-common/pom.xml @@ -6,7 +6,7 @@ org.xipki.commons xipki-commons-parent - 6.3.4 + 6.3.5-SNAPSHOT servlet3-common XiPKI :: ${project.artifactId} diff --git a/servlet5-common/pom.xml b/servlet5-common/pom.xml index 340c57e..469116f 100644 --- a/servlet5-common/pom.xml +++ b/servlet5-common/pom.xml @@ -6,7 +6,7 @@ org.xipki.commons xipki-commons-parent - 6.3.4 + 6.3.5-SNAPSHOT servlet5-common XiPKI :: ${project.artifactId} diff --git a/shell-base/pom.xml b/shell-base/pom.xml index e98b954..7a870ef 100644 --- a/shell-base/pom.xml +++ b/shell-base/pom.xml @@ -6,7 +6,7 @@ org.xipki.commons xipki-commons-parent - 6.3.4 + 6.3.5-SNAPSHOT shell-base bundle diff --git a/util/pom.xml b/util/pom.xml index 3c56474..04241e4 100644 --- a/util/pom.xml +++ b/util/pom.xml @@ -6,7 +6,7 @@ org.xipki.commons xipki-commons-parent - 6.3.4 + 6.3.5-SNAPSHOT bundle util diff --git a/xipki-tomcat-password/pom.xml b/xipki-tomcat-password/pom.xml index 7bce74c..cd28f45 100644 --- a/xipki-tomcat-password/pom.xml +++ b/xipki-tomcat-password/pom.xml @@ -6,7 +6,7 @@ org.xipki.commons xipki-commons-parent - 6.3.4 + 6.3.5-SNAPSHOT xipki-tomcat-password From 8e4df63b600e61790e80d437203e49f9893e0085 Mon Sep 17 00:00:00 2001 From: Lijun Liao Date: Tue, 16 Jan 2024 21:39:17 +0100 Subject: [PATCH 02/11] fixed typo. --- .../src/main/java/org/xipki/security/ObjectIdentifiers.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/src/main/java/org/xipki/security/ObjectIdentifiers.java b/security/src/main/java/org/xipki/security/ObjectIdentifiers.java index aeb7fce..691dd20 100644 --- a/security/src/main/java/org/xipki/security/ObjectIdentifiers.java +++ b/security/src/main/java/org/xipki/security/ObjectIdentifiers.java @@ -577,7 +577,7 @@ public static final class Extn { public static final ASN1ObjectIdentifier id_ccc_extn = id_ccc.branch("5"); public static final ASN1ObjectIdentifier id_ccc_Vehicle_Cert_K = id_ccc_extn.branch("1"); public static final ASN1ObjectIdentifier id_ccc_External_CA_Cert_F = id_ccc_extn.branch("2"); - public static final ASN1ObjectIdentifier id_ccc_Internal_CA_Cert_E = id_ccc_extn.branch("3"); + public static final ASN1ObjectIdentifier id_ccc_Instance_CA_Cert_E = id_ccc_extn.branch("3"); public static final ASN1ObjectIdentifier id_ccc_Endpoint_Cert_H = id_ccc_extn.branch("4"); public static final ASN1ObjectIdentifier id_ccc_VehicleOEM_Enc_Cert = id_ccc_extn.branch("5"); public static final ASN1ObjectIdentifier id_ccc_VehicleOEM_Sig_Cert = id_ccc_extn.branch("6"); @@ -654,7 +654,7 @@ private static class OidNameMap { // CCC oidNameMap.put(Extn.id_ccc_Vehicle_Cert_K, "CCC Vehicle Certificate [K]"); oidNameMap.put(Extn.id_ccc_External_CA_Cert_F, "CCC External CA Certificate [F]"); - oidNameMap.put(Extn.id_ccc_Internal_CA_Cert_E, "CCC External CA Certificate [E]"); + oidNameMap.put(Extn.id_ccc_Instance_CA_Cert_E, "CCC Instance CA Certificate [E]"); oidNameMap.put(Extn.id_ccc_Endpoint_Cert_H, "Endpoint Certificate [H]"); oidNameMap.put(Extn.id_ccc_VehicleOEM_Enc_Cert, "CCC VehicleOEM.Enc.Cert"); oidNameMap.put(Extn.id_ccc_VehicleOEM_Sig_Cert, "CCC VehicleOEM.Sig.Cert"); From ef789acc7a827664c1b0f522db626b7b115990b1 Mon Sep 17 00:00:00 2001 From: Lijun Liao Date: Fri, 19 Jan 2024 20:08:41 +0100 Subject: [PATCH 03/11] add end new line. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8811f68..da89db8 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,5 @@ Just [create issue](https://github.com/xipki/commons/issues). For bug-report please upload the test data and log files, describe the version of XiPKI Commons, OS and -JRE/JDK, and the steps to reproduce the bug. \ No newline at end of file +JRE/JDK, and the steps to reproduce the bug. + From 74b721fcf67938c414fc81cd95ac425cd295e588 Mon Sep 17 00:00:00 2001 From: Lijun Liao Date: Fri, 12 Apr 2024 21:55:03 +0200 Subject: [PATCH 04/11] ConcurrentBag does not have a fair borrow mechanism, use BlockingQueue instead --- .../org/xipki/security/shell/Actions.java | 5 +- .../security/ConcurrentContentSigner.java | 7 +- .../security/DfltConcurrentContentSigner.java | 43 +- .../java/org/xipki/security/HashAlgo.java | 25 +- .../org/xipki/security/HashCalculator.java | 189 ------ .../java/org/xipki/security/IssuerHash.java | 4 +- .../pkcs11/emulator/EmulatorP11Key.java | 62 +- .../security/pkcs12/P12KeyGenerator.java | 2 +- .../test/CrlTestVectorGenerateMain.java | 7 +- .../java/org/xipki/util/ConcurrentBag.java | 553 ------------------ 10 files changed, 81 insertions(+), 816 deletions(-) delete mode 100644 security/src/main/java/org/xipki/security/HashCalculator.java delete mode 100644 util/src/main/java/org/xipki/util/ConcurrentBag.java diff --git a/security-shell/src/main/java/org/xipki/security/shell/Actions.java b/security-shell/src/main/java/org/xipki/security/shell/Actions.java index 4ab9d79..1d8ec1f 100644 --- a/security-shell/src/main/java/org/xipki/security/shell/Actions.java +++ b/security-shell/src/main/java/org/xipki/security/shell/Actions.java @@ -74,7 +74,6 @@ import org.xipki.util.Base64; import org.xipki.util.CollectionUtil; import org.xipki.util.CompareUtil; -import org.xipki.util.ConcurrentBag; import org.xipki.util.DateUtil; import org.xipki.util.Hex; import org.xipki.util.IoUtil; @@ -875,7 +874,7 @@ private PKCS10CertificationRequest generateRequest( } } - ConcurrentBag.BagEntry signer0; + XiContentSigner signer0; try { signer0 = signer.borrowSigner(); } catch (NoIdleSignerException ex) { @@ -883,7 +882,7 @@ private PKCS10CertificationRequest generateRequest( } try { - return csrBuilder.build(signer0.value()); + return csrBuilder.build(signer0); } finally { signer.requiteSigner(signer0); } diff --git a/security/src/main/java/org/xipki/security/ConcurrentContentSigner.java b/security/src/main/java/org/xipki/security/ConcurrentContentSigner.java index 96f8ce8..baac18f 100644 --- a/security/src/main/java/org/xipki/security/ConcurrentContentSigner.java +++ b/security/src/main/java/org/xipki/security/ConcurrentContentSigner.java @@ -4,7 +4,6 @@ package org.xipki.security; import org.bouncycastle.operator.ContentSigner; -import org.xipki.util.ConcurrentBag.BagEntry; import java.io.Closeable; import java.security.Key; @@ -98,7 +97,7 @@ public interface ConcurrentContentSigner extends Closeable { * @throws NoIdleSignerException * If no idle signer is available */ - BagEntry borrowSigner() throws NoIdleSignerException; + XiContentSigner borrowSigner() throws NoIdleSignerException; /** * Borrows a signer with the given {@code soTimeout}. @@ -107,9 +106,9 @@ public interface ConcurrentContentSigner extends Closeable { * @throws NoIdleSignerException * If no idle signer is available */ - BagEntry borrowSigner(int soTimeout) throws NoIdleSignerException; + XiContentSigner borrowSigner(int soTimeout) throws NoIdleSignerException; - void requiteSigner(BagEntry signer); + void requiteSigner(XiContentSigner signer); boolean isHealthy(); diff --git a/security/src/main/java/org/xipki/security/DfltConcurrentContentSigner.java b/security/src/main/java/org/xipki/security/DfltConcurrentContentSigner.java index f6baa9b..048f454 100644 --- a/security/src/main/java/org/xipki/security/DfltConcurrentContentSigner.java +++ b/security/src/main/java/org/xipki/security/DfltConcurrentContentSigner.java @@ -7,8 +7,6 @@ import org.slf4j.LoggerFactory; import org.xipki.util.Args; import org.xipki.util.CollectionUtil; -import org.xipki.util.ConcurrentBag; -import org.xipki.util.ConcurrentBag.BagEntry; import org.xipki.util.LogUtil; import java.io.IOException; @@ -20,6 +18,7 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -38,7 +37,7 @@ public class DfltConcurrentContentSigner implements ConcurrentContentSigner { private static int defaultSignServiceTimeout = 10000; // 10 seconds - private final ConcurrentBag signers = new ConcurrentBag<>(); + private final ArrayBlockingQueue signers; private final String name; @@ -80,10 +79,8 @@ public DfltConcurrentContentSigner(boolean mac, List signers, K this.mac = mac; this.algorithm = SignAlgo.getInstance(signers.get(0).getAlgorithmIdentifier()); - - for (XiContentSigner signer : signers) { - this.signers.add(new BagEntry<>(signer)); - } + this.signers = new ArrayBlockingQueue<>(signers.size()); + this.signers.addAll(signers); this.signingKey = signingKey; this.name = "defaultSigner-" + NAME_INDEX.getAndIncrement(); @@ -120,7 +117,7 @@ public SignAlgo getAlgorithm() { } @Override - public BagEntry borrowSigner() throws NoIdleSignerException { + public XiContentSigner borrowSigner() throws NoIdleSignerException { return borrowSigner(defaultSignServiceTimeout); } @@ -130,10 +127,10 @@ public BagEntry borrowSigner() throws NoIdleSignerException { * @param soTimeout timeout in milliseconds, 0 for infinitely. */ @Override - public BagEntry borrowSigner(int soTimeout) throws NoIdleSignerException { - BagEntry signer = null; + public XiContentSigner borrowSigner(int soTimeout) throws NoIdleSignerException { + XiContentSigner signer = null; try { - signer = signers.borrow(soTimeout, TimeUnit.MILLISECONDS); + signer = signers.poll(soTimeout, TimeUnit.MILLISECONDS); } catch (InterruptedException ex) { } @@ -142,8 +139,8 @@ public BagEntry borrowSigner(int soTimeout) throws NoIdleSigner } @Override - public void requiteSigner(BagEntry signer) { - signers.requite(signer); + public void requiteSigner(XiContentSigner signer) { + signers.add(signer); } @Override @@ -188,12 +185,12 @@ public X509Cert[] getCertificateChain() { @Override public boolean isHealthy() { - BagEntry signer = null; + XiContentSigner signer = null; try { signer = borrowSigner(); - OutputStream stream = signer.value().getOutputStream(); + OutputStream stream = signer.getOutputStream(); stream.write(new byte[]{1, 2, 3, 4}); - byte[] signature = signer.value().getSignature(); + byte[] signature = signer.getSignature(); return signature != null && signature.length > 0; } catch (Exception ex) { LogUtil.error(LOG, ex); @@ -211,15 +208,15 @@ public void close() { @Override public byte[] sign(byte[] data) throws NoIdleSignerException, SignatureException { - BagEntry signer = borrowSigner(); + XiContentSigner signer = borrowSigner(); try { - OutputStream signatureStream = signer.value().getOutputStream(); + OutputStream signatureStream = signer.getOutputStream(); try { signatureStream.write(data); } catch (IOException ex) { throw new SignatureException("could not write data to SignatureStream: " + ex.getMessage(), ex); } - return signer.value().getSignature(); + return signer.getSignature(); } finally { requiteSigner(signer); } @@ -228,19 +225,17 @@ public byte[] sign(byte[] data) throws NoIdleSignerException, SignatureException @Override public byte[][] sign(byte[][] data) throws NoIdleSignerException, SignatureException { byte[][] signatures = new byte[data.length][]; - BagEntry signer = borrowSigner(); + XiContentSigner signer = borrowSigner(); try { - XiContentSigner xiSigner = signer.value(); - for (int i = 0; i < data.length; i++) { - OutputStream signatureStream = xiSigner.getOutputStream(); + OutputStream signatureStream = signer.getOutputStream(); try { signatureStream.write(data[i]); } catch (IOException ex) { throw new SignatureException("could not write data to SignatureStream: " + ex.getMessage(), ex); } - signatures[i] = xiSigner.getSignature(); + signatures[i] = signer.getSignature(); } } finally { requiteSigner(signer); diff --git a/security/src/main/java/org/xipki/security/HashAlgo.java b/security/src/main/java/org/xipki/security/HashAlgo.java index 86e4630..78fa517 100644 --- a/security/src/main/java/org/xipki/security/HashAlgo.java +++ b/security/src/main/java/org/xipki/security/HashAlgo.java @@ -9,6 +9,7 @@ import org.bouncycastle.asn1.gm.GMObjectIdentifiers; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.ExtendedDigest; import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.digests.SHA224Digest; @@ -19,6 +20,8 @@ import org.bouncycastle.crypto.digests.SHAKEDigest; import org.bouncycastle.crypto.digests.SM3Digest; import org.xipki.util.Args; +import org.xipki.util.Base64; +import org.xipki.util.Hex; import java.io.IOException; import java.security.NoSuchAlgorithmException; @@ -226,27 +229,37 @@ public ExtendedDigest createDigest() { } public String hexHash(byte[]... datas) { - return HashCalculator.hexHash(this, datas); + return Hex.encode(hash(datas)); } public String hexHash(byte[] data, int offset, int len) { - return HashCalculator.hexHash(this, data, offset, len); + return Hex.encode(hash(data, offset, len)); } public String base64Hash(byte[]... datas) { - return HashCalculator.base64Hash(this, datas); + return Base64.encodeToString(hash(datas)); } public String base64Hash(byte[] data, int offset, int len) { - return HashCalculator.base64Hash(this, data, offset, len); + return Base64.encodeToString(hash(data, offset, len)); } public byte[] hash(byte[]... datas) { - return HashCalculator.hash(this, datas); + Digest digest = createDigest(); + for (byte[] data : datas) { + digest.update(data, 0, data.length); + } + byte[] rv = new byte[length]; + digest.doFinal(rv, 0); + return rv; } public byte[] hash(byte[] data, int offset, int len) { - return HashCalculator.hash(this, data, offset, len); + Digest digest = createDigest(); + digest.update(data, offset, len); + byte[] rv = new byte[length]; + digest.doFinal(rv, 0); + return rv; } public int getEncodedLength() { diff --git a/security/src/main/java/org/xipki/security/HashCalculator.java b/security/src/main/java/org/xipki/security/HashCalculator.java deleted file mode 100644 index 03ad35f..0000000 --- a/security/src/main/java/org/xipki/security/HashCalculator.java +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) 2013-2024 xipki. All rights reserved. -// License Apache License 2.0 - -package org.xipki.security; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.operator.RuntimeOperatorException; -import org.xipki.util.Args; -import org.xipki.util.Base64; -import org.xipki.util.ConcurrentBag; -import org.xipki.util.ConcurrentBag.BagEntry; -import org.xipki.util.Hex; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -/** - * Utility class to calculate hash values. - * - * @author Lijun Liao (xipki) - * @since 2.0.0 - */ - -class HashCalculator { - - private static final int PARALLELISM = 50; - - private static final ConcurrentHashMap> - MDS_MAP = new ConcurrentHashMap<>(); - - static { - for (HashAlgo ha : HashAlgo.values()) { - MDS_MAP.put(ha, getMessageDigests(ha)); - } - } - - private HashCalculator() { - } - - private static ConcurrentBag getMessageDigests(HashAlgo hashAlgo) { - ConcurrentBag mds = new ConcurrentBag<>(); - for (int i = 0; i < PARALLELISM; i++) { - mds.add(new BagEntry<>(hashAlgo.createDigest())); - } - return mds; - } - - public static String base64Sha1(byte[]... datas) { - return Base64.encodeToString(hash(HashAlgo.SHA1, datas)); - } - - public static String base64Sha1(byte[] data, int offset, int len) { - return Base64.encodeToString(hash(HashAlgo.SHA1, data, offset, len)); - } - - public static String hexSha1(byte[]... datas) { - return Hex.encode(hash(HashAlgo.SHA1, datas)); - } - - public static String hexSha1(byte[] data, int offset, int len) { - return Hex.encode(hash(HashAlgo.SHA1, data, offset, len)); - } - - public static byte[] sha1(byte[]... datas) { - return hash(HashAlgo.SHA1, datas); - } - - public static byte[] sha1(byte[] data, int offset, int len) { - return hash(HashAlgo.SHA1, data, offset, len); - } - - public static String base64Sha256(byte[]... datas) { - return Base64.encodeToString(hash(HashAlgo.SHA256, datas)); - } - - public static String base64Sha256(byte[] data, int offset, int len) { - return Base64.encodeToString(hash(HashAlgo.SHA256, data, offset, len)); - } - - public static String hexSha256(byte[]... datas) { - return Hex.encode(hash(HashAlgo.SHA256, datas)); - } - - public static String hexSha256(byte[] data, int offset, int len) { - return Hex.encode(hash(HashAlgo.SHA256, data, offset, len)); - } - - public static byte[] sha256(byte[]... datas) { - return hash(HashAlgo.SHA256, datas); - } - - public static byte[] sha256(byte[] data, int offset, int len) { - return hash(HashAlgo.SHA256, data, offset, len); - } - - public static String hexHash(HashAlgo hashAlgo, byte[]... datas) { - return Hex.encode(hash(hashAlgo, datas)); - } - - public static String hexHash(HashAlgo hashAlgo, byte[] data, int offset, int len) { - return Hex.encode(hash(hashAlgo, data, offset, len)); - } - - public static String base64Hash(HashAlgo hashAlgo, byte[]... datas) { - return Base64.encodeToString(hash(hashAlgo, datas)); - } - - public static String base64Hash(HashAlgo hashAlgo, byte[] data, int offset, int len) { - return Base64.encodeToString(hash(hashAlgo, data, offset, len)); - } - - public static byte[] hash(HashAlgo hashAlgo, byte[]... datas) { - Args.notNull(datas, "datas"); - - if (!MDS_MAP.containsKey(Args.notNull(hashAlgo, "hashAlgo"))) { - throw new IllegalArgumentException("unknown hash algo " + hashAlgo); - } - - ConcurrentBag mds = MDS_MAP.get(hashAlgo); - - BagEntry md0 = null; - for (int i = 0; i < 3; i++) { - try { - md0 = mds.borrow(10, TimeUnit.SECONDS); - break; - } catch (InterruptedException ex) { - } - } - - if (md0 == null) { - throw new RuntimeOperatorException("could not get idle MessageDigest"); - } - - try { - Digest md = md0.value(); - md.reset(); - for (byte[] data : datas) { - if (data != null && data.length > 0) { - md.update(data, 0, data.length); - } - } - - byte[] bytes = new byte[md.getDigestSize()]; - md.doFinal(bytes, 0); - return bytes; - } finally { - mds.requite(md0); - } - } // method hash - - public static byte[] hash(HashAlgo hashAlgo, byte[] data, int offset, int len) { - Args.notNull(hashAlgo, "hashAlgo"); - - if (Args.notNull(data, "data").length - offset < len) { - throw new IndexOutOfBoundsException("data.length - offset < len"); - } - - if (!MDS_MAP.containsKey(hashAlgo)) { - throw new IllegalArgumentException("unknown hash algo " + hashAlgo); - } - - ConcurrentBag mds = MDS_MAP.get(hashAlgo); - - BagEntry md0 = null; - for (int i = 0; i < 3; i++) { - try { - md0 = mds.borrow(10, TimeUnit.SECONDS); - break; - } catch (InterruptedException ex) { - } - } - - if (md0 == null) { - throw new RuntimeOperatorException("could not get idle MessageDigest"); - } - - try { - Digest md = md0.value(); - md.reset(); - md.update(data, offset, len); - byte[] bytes = new byte[md.getDigestSize()]; - md.doFinal(bytes, 0); - return bytes; - } finally { - mds.requite(md0); - } - } // method hash - -} diff --git a/security/src/main/java/org/xipki/security/IssuerHash.java b/security/src/main/java/org/xipki/security/IssuerHash.java index d0e3725..7c376c5 100644 --- a/security/src/main/java/org/xipki/security/IssuerHash.java +++ b/security/src/main/java/org/xipki/security/IssuerHash.java @@ -36,8 +36,8 @@ public IssuerHash(HashAlgo hashAlgo, X509Cert issuerCert) throws IOException { this.hashAlgo = Args.notNull(hashAlgo, "hashAlgo"); byte[] encodedName = Args.notNull(issuerCert, "issuerCert").getSubject().getEncoded(); byte[] encodedKey = issuerCert.getSubjectPublicKeyInfo().getPublicKeyData().getBytes(); - this.issuerNameHash = HashCalculator.hash(hashAlgo, encodedName); - this.issuerKeyHash = HashCalculator.hash(hashAlgo, encodedKey); + this.issuerNameHash = hashAlgo.hash(encodedName); + this.issuerKeyHash = hashAlgo.hash(encodedKey); } public HashAlgo getHashAlgo() { diff --git a/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Key.java b/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Key.java index 6c96b73..c5a19f7 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Key.java +++ b/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Key.java @@ -28,8 +28,6 @@ import org.xipki.security.util.PKCS1Util; import org.xipki.security.util.SignerUtil; import org.xipki.util.Args; -import org.xipki.util.ConcurrentBag; -import org.xipki.util.ConcurrentBag.BagEntry; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -48,6 +46,8 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import static org.xipki.pkcs11.wrapper.PKCS11Constants.CKG_MGF1_SHA1; @@ -159,13 +159,13 @@ class EmulatorP11Key extends P11Key { private final Key signingKey; - private final ConcurrentBag rsaCiphers = new ConcurrentBag<>(); + private final ArrayBlockingQueue rsaCiphers; - private final ConcurrentBag dsaSignatures = new ConcurrentBag<>(); + private final ArrayBlockingQueue dsaSignatures; - private final ConcurrentBag eddsaSignatures = new ConcurrentBag<>(); + private final ArrayBlockingQueue eddsaSignatures; - private final ConcurrentBag sm2Signers = new ConcurrentBag<>(); + private final ArrayBlockingQueue sm2Signers; private final SecureRandom random; @@ -264,6 +264,10 @@ public EmulatorP11Key( this.signingKey = Args.notNull(signingKey, "signingKey"); this.random = Args.notNull(random, "random"); this.maxSessions = maxSessions; + this.dsaSignatures = new ArrayBlockingQueue<>(maxSessions); + this.eddsaSignatures = new ArrayBlockingQueue<>(maxSessions); + this.sm2Signers = new ArrayBlockingQueue<>(maxSessions); + this.rsaCiphers = new ArrayBlockingQueue<>(maxSessions); } // constructor public void setEcParams(ASN1ObjectIdentifier ecParams) { @@ -312,7 +316,7 @@ private synchronized void init() throws TokenException { } } rsaCipher.init(Cipher.ENCRYPT_MODE, signingKey); - rsaCiphers.add(new BagEntry<>(rsaCipher)); + rsaCiphers.add(rsaCipher); } } else { String algorithm; @@ -334,7 +338,7 @@ private synchronized void init() throws TokenException { for (int i = 0; i < maxSessions; i++) { Signature dsaSignature = Signature.getInstance(algorithm, "BC"); dsaSignature.initSign((PrivateKey) signingKey, random); - dsaSignatures.add(new BagEntry<>(dsaSignature)); + dsaSignatures.add(dsaSignature); } } else if (keyType == CKK_EC_EDWARDS) { algorithm = EdECConstants.getName(getEcParams()); @@ -344,7 +348,7 @@ private synchronized void init() throws TokenException { for (int i = 0; i < maxSessions; i++) { Signature signature = Signature.getInstance(algorithm, "BC"); signature.initSign((PrivateKey) signingKey); - eddsaSignatures.add(new BagEntry<>(signature)); + eddsaSignatures.add(signature); } } else if (keyType == CKK_EC_MONTGOMERY) { // do nothing. not suitable for sign. @@ -352,7 +356,7 @@ private synchronized void init() throws TokenException { for (int i = 0; i < maxSessions; i++) { EmulatorSM2Signer sm2signer = new EmulatorSM2Signer(ECUtil.generatePrivateKeyParameter((PrivateKey) signingKey)); - sm2Signers.add(new BagEntry<>(sm2signer)); + sm2Signers.add(sm2signer); } } } @@ -509,38 +513,37 @@ private byte[] rsaPkcsSign(byte[] contentToSign, HashAlgo hashAlgo) throws Token } // method rsaPkcsSign private byte[] rsaX509Sign(byte[] dataToSign) throws TokenException { - BagEntry cipher; + Cipher cipher; try { - cipher = Optional.ofNullable(rsaCiphers.borrow(5000, TimeUnit.MILLISECONDS)).orElseThrow( + cipher = Optional.ofNullable(rsaCiphers.poll(5000, TimeUnit.MILLISECONDS)).orElseThrow( () -> new TokenException("no idle RSA cipher available")); } catch (InterruptedException ex) { throw new TokenException("could not take any idle signer"); } try { - return cipher.value().doFinal(dataToSign); + return cipher.doFinal(dataToSign); } catch (BadPaddingException ex) { throw new TokenException("BadPaddingException: " + ex.getMessage(), ex); } catch (IllegalBlockSizeException ex) { throw new TokenException("IllegalBlockSizeException: " + ex.getMessage(), ex); } finally { - rsaCiphers.requite(cipher); + rsaCiphers.add(cipher); } } // method rsaX509Sign private byte[] dsaAndEcdsaSign(byte[] dataToSign, HashAlgo hashAlgo) throws TokenException { byte[] hash = (hashAlgo == null) ? dataToSign : hashAlgo.hash(dataToSign); - BagEntry sig0; + Signature sig; try { - sig0 = Optional.ofNullable(dsaSignatures.borrow(5000, TimeUnit.MILLISECONDS)) + sig = Optional.ofNullable(dsaSignatures.poll(5000, TimeUnit.MILLISECONDS)) .orElseThrow(() -> new TokenException("no idle DSA Signature available")); } catch (InterruptedException ex) { throw new TokenException("InterruptedException occurs while retrieving idle signature"); } try { - Signature sig = sig0.value(); sig.update(hash); byte[] x962Signature = sig.sign(); return SignerUtil.dsaSigX962ToPlain(x962Signature, dsaOrderBitLen); @@ -549,7 +552,7 @@ private byte[] dsaAndEcdsaSign(byte[] dataToSign, HashAlgo hashAlgo) throws Toke } catch (XiSecurityException ex) { throw new TokenException("XiSecurityException: " + ex.getMessage(), ex); } finally { - dsaSignatures.requite(sig0); + dsaSignatures.add(sig); } } // method dsaAndEcdsaSign @@ -558,43 +561,42 @@ private byte[] eddsaSign(byte[] dataToSign) throws TokenException { throw new TokenException("given signing key is not suitable for EdDSA sign"); } - BagEntry sig0; + Signature sig; try { - sig0 = Optional.ofNullable(eddsaSignatures.borrow(5000, TimeUnit.MILLISECONDS)) + sig = Optional.ofNullable(eddsaSignatures.poll(5000, TimeUnit.MILLISECONDS)) .orElseThrow(() -> new TokenException("no idle DSA Signature available")); } catch (InterruptedException ex) { throw new TokenException("InterruptedException occurs while retrieving idle signature"); } try { - Signature sig = sig0.value(); sig.update(dataToSign); return sig.sign(); } catch (SignatureException ex) { throw new TokenException("SignatureException: " + ex.getMessage(), ex); } finally { - eddsaSignatures.requite(sig0); + eddsaSignatures.add(sig); } } // method eddsaSign private byte[] sm2SignHash(byte[] hash) throws TokenException { - BagEntry sig; + EmulatorSM2Signer sig; try { - sig = Optional.ofNullable(sm2Signers.borrow(5000, TimeUnit.MILLISECONDS)).orElseThrow( + sig = Optional.ofNullable(sm2Signers.poll(5000, TimeUnit.MILLISECONDS)).orElseThrow( () -> new TokenException("no idle SM2 Signer available")); } catch (InterruptedException ex) { throw new TokenException("InterruptedException occurs while retrieving idle signature"); } try { - byte[] x962Signature = sig.value().generateSignatureForHash(hash); + byte[] x962Signature = sig.generateSignatureForHash(hash); return SignerUtil.dsaSigX962ToPlain(x962Signature, dsaOrderBitLen); } catch (CryptoException ex) { throw new TokenException("CryptoException: " + ex.getMessage(), ex); } catch (XiSecurityException ex) { throw new TokenException("XiSecurityException: " + ex.getMessage(), ex); } finally { - sm2Signers.requite(sig); + sm2Signers.add(sig); } } // method sm2SignHash @@ -610,23 +612,23 @@ private byte[] sm2Sign(P11Params params, byte[] dataToSign) throws TokenExceptio throw new TokenException("params must be instanceof P11ByteArrayParams"); } - BagEntry sig0; + EmulatorSM2Signer sig; try { - sig0 = Optional.ofNullable(sm2Signers.borrow(5000, TimeUnit.MILLISECONDS)).orElseThrow( + sig = Optional.ofNullable(sm2Signers.poll(5000, TimeUnit.MILLISECONDS)).orElseThrow( () -> new TokenException("no idle SM2 Signer available")); } catch (InterruptedException ex) { throw new TokenException("InterruptedException occurs while retrieving idle signature"); } try { - byte[] x962Signature = sig0.value().generateSignatureForMessage(userId, dataToSign); + byte[] x962Signature = sig.generateSignatureForMessage(userId, dataToSign); return SignerUtil.dsaSigX962ToPlain(x962Signature, dsaOrderBitLen); } catch (CryptoException ex) { throw new TokenException("CryptoException: " + ex.getMessage(), ex); } catch (XiSecurityException ex) { throw new TokenException("XiSecurityException: " + ex.getMessage(), ex); } finally { - sm2Signers.requite(sig0); + sm2Signers.add(sig); } } // method sm2Sign diff --git a/security/src/main/java/org/xipki/security/pkcs12/P12KeyGenerator.java b/security/src/main/java/org/xipki/security/pkcs12/P12KeyGenerator.java index 301663f..cd57612 100644 --- a/security/src/main/java/org/xipki/security/pkcs12/P12KeyGenerator.java +++ b/security/src/main/java/org/xipki/security/pkcs12/P12KeyGenerator.java @@ -291,7 +291,7 @@ public static ContentSigner getContentSigner(PrivateKey key, PublicKey publicKey P12ContentSignerBuilder builder = new P12ContentSignerBuilder(key, publicKey); ConcurrentContentSigner csigner = builder.createSigner(algo, 1, null); - return csigner.borrowSigner().value(); + return csigner.borrowSigner(); } // method getContentSigner } diff --git a/security/src/test/java/org/xipki/security/test/CrlTestVectorGenerateMain.java b/security/src/test/java/org/xipki/security/test/CrlTestVectorGenerateMain.java index 4a69d0b..86eeba5 100644 --- a/security/src/test/java/org/xipki/security/test/CrlTestVectorGenerateMain.java +++ b/security/src/test/java/org/xipki/security/test/CrlTestVectorGenerateMain.java @@ -14,7 +14,6 @@ import org.xipki.security.SignerConf; import org.xipki.security.X509Cert; import org.xipki.security.XiContentSigner; -import org.xipki.util.ConcurrentBag.BagEntry; import org.xipki.util.ConfPairs; import org.xipki.util.IoUtil; @@ -53,7 +52,7 @@ private static void genTestVectors() throws Exception { "PKCS12", sconf, (X509Cert) null); X509Cert caCert = csigner.getCertificate(); - BagEntry signer = csigner.borrowSigner(); + XiContentSigner signer = csigner.borrowSigner(); // no revoked certs X509v2CRLBuilder builder = getBuilder(caCert, true, true); buildCrl(builder, signer, "no-revoked-certs.crl"); @@ -87,9 +86,9 @@ private static void genTestVectors() throws Exception { } } - private static void buildCrl(X509v2CRLBuilder builder, BagEntry signer, String fn) + private static void buildCrl(X509v2CRLBuilder builder, XiContentSigner signer, String fn) throws Exception { - byte[] encoded = builder.build(signer.value()).getEncoded(); + byte[] encoded = builder.build(signer).getEncoded(); IoUtil.save("output/" + fn, encoded); } diff --git a/util/src/main/java/org/xipki/util/ConcurrentBag.java b/util/src/main/java/org/xipki/util/ConcurrentBag.java deleted file mode 100644 index dafd500..0000000 --- a/util/src/main/java/org/xipki/util/ConcurrentBag.java +++ /dev/null @@ -1,553 +0,0 @@ -// #THIRDPARTY# HikariCP - -/* - * Copyright (C) 2013, 2014 Brett Wooldridge - * - * 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 org.xipki.util; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.lang.ref.WeakReference; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.NoSuchElementException; -import java.util.RandomAccess; -import java.util.Spliterator; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; -import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.function.UnaryOperator; - -import static java.util.concurrent.TimeUnit.MICROSECONDS; -import static java.util.concurrent.TimeUnit.NANOSECONDS; -import static java.util.concurrent.locks.LockSupport.parkNanos; - -/** - * This is a specialized concurrent bag that achieves superior performance - * to LinkedBlockingQueue and LinkedTransferQueue for the purposes of a - * connection pool. It uses ThreadLocal storage when possible to avoid - * locks, but resorts to scanning a common collection if there are no - * available items in the ThreadLocal list. Not-in-use items in the - * ThreadLocal lists can be "stolen" when the borrowing thread has none - * of its own. It is a "lock-less" implementation using a specialized - * AbstractQueuedLongSynchronizer to manage cross-thread signaling. - *

- * Note that items that are "borrowed" from the bag are not actually - * removed from any collection, so garbage collection will not occur - * even if the reference is abandoned. Thus care must be taken to - * "requite" borrowed objects otherwise a memory leak will result. Only - * the "remove" method can completely remove an object from the bag. - * - * @author Brett Wooldridge - * @author Lijun Liao (xipki) - * - * @param the templated type to store in the bag - */ -public class ConcurrentBag implements AutoCloseable { - - private static final Logger LOG = LoggerFactory.getLogger(ConcurrentBag.class); - - private final CopyOnWriteArrayList> sharedList; - private final boolean weakThreadLocals; - - private final ThreadLocal> threadList; - private final AtomicInteger waiters; - private volatile boolean closed; - - private final SynchronousQueue> handoffQueue; - - private static final int STATE_NOT_IN_USE = 0; - private static final int STATE_IN_USE = 1; - private static final int STATE_REMOVED = -1; - private static final int STATE_RESERVED = -2; - - /** - * Construct a ConcurrentBag with the specified listener. - */ - public ConcurrentBag() { - this.weakThreadLocals = useWeakThreadLocals(); - - this.handoffQueue = new SynchronousQueue<>(true); - this.waiters = new AtomicInteger(); - this.sharedList = new CopyOnWriteArrayList<>(); - if (weakThreadLocals) { - this.threadList = ThreadLocal.withInitial(() -> new ArrayList<>(16)); - } else { - this.threadList = ThreadLocal.withInitial(() -> new FastList<>(BagEntry.class, 16)); - } - } - - /** - * The method will borrow a BagEntry from the bag, blocking for the - * specified timeout if none are available. - * - * @param timeout how long to wait before giving up, in units of unit - * @param timeUnit a TimeUnit determining how to interpret the timeout parameter - * @return a borrowed instance from the bag or null if a timeout occurs - * @throws InterruptedException if interrupted while waiting - */ - public BagEntry borrow(long timeout, final TimeUnit timeUnit) throws InterruptedException { - // Try the thread-local list first - final List list = threadList.get(); - for (int i = list.size() - 1; i >= 0; i--) { - final Object entry = list.remove(i); - @SuppressWarnings("unchecked") - final BagEntry bagEntry = weakThreadLocals ? ((WeakReference>) entry).get() : (BagEntry) entry; - if (bagEntry != null && bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) { - return bagEntry; - } - } - - try { - for (BagEntry bagEntry : sharedList) { - if (bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) { - return bagEntry; - } - } - - timeout = timeUnit.toNanos(timeout); - do { - final long start = System.nanoTime(); - final BagEntry bagEntry = handoffQueue.poll(timeout, NANOSECONDS); - if (bagEntry == null || bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) { - return bagEntry; - } - - timeout -= System.nanoTime() - start; - } while (timeout > 10_000); - - return null; - } finally { - waiters.decrementAndGet(); - } - } - - /** - * This method will return a borrowed object to the bag. Objects - * that are borrowed from the bag but never "requited" will result - * in a memory leak. - * - * @param bagEntry the value to return to the bag - * @throws NullPointerException if value is null - * @throws IllegalStateException if the bagEntry was not borrowed from the bag - */ - public void requite(final BagEntry bagEntry) { - bagEntry.setState(STATE_NOT_IN_USE); - - for (int i = 0; waiters.get() > 0; i++) { - if (bagEntry.getState() != STATE_NOT_IN_USE || handoffQueue.offer(bagEntry)) { - return; - } else if ((i & 0xff) == 0xff) { - parkNanos(MICROSECONDS.toNanos(10)); - } else { - Thread.yield(); - } - } - - final List threadLocalList = threadList.get(); - if (threadLocalList.size() < 50) { - threadLocalList.add(weakThreadLocals ? new WeakReference<>(bagEntry) : bagEntry); - } - } - - /** - * Add a new object to the bag for others to borrow. - * - * @param bagEntry an object to add to the bag - */ - public void add(final BagEntry bagEntry) { - if (closed) { - LOG.info("ConcurrentBag has been closed, ignoring add()"); - throw new IllegalStateException("ConcurrentBag has been closed, ignoring add()"); - } - - sharedList.add(bagEntry); - - // spin until a thread takes it or none are waiting - while (waiters.get() > 0 && bagEntry.getState() == STATE_NOT_IN_USE && !handoffQueue.offer(bagEntry)) { - Thread.yield(); - } - } - - /** - * Remove a value from the bag. This method should only be called - * with objects obtained by borrow(long, TimeUnit) or reserve(T) - * - * @param bagEntry the value to remove - * @return true if the entry was removed, false otherwise - * @throws IllegalStateException if an attempt is made to remove an object - * from the bag that was not borrowed or reserved first - */ - public boolean remove(final BagEntry bagEntry) { - if (!bagEntry.compareAndSet(STATE_IN_USE, STATE_REMOVED) - && !bagEntry.compareAndSet(STATE_RESERVED, STATE_REMOVED) && !closed) { - LOG.warn("Attempt to remove an object from the bag that was not borrowed or reserved: {}", bagEntry); - return false; - } - - final boolean removed = sharedList.remove(bagEntry); - if (!removed && !closed) { - LOG.warn("Attempt to remove an object from the bag that does not exist: {}", bagEntry); - } - - threadList.get().remove(bagEntry); - - return removed; - } - - /** - * Close the bag to further adds. - */ - @Override - public void close() { - closed = true; - } - - /** - * This method provides a "snapshot" in time of the bag items. It - * does not "lock" or reserve items in any way. Call reserve(T) - * on items in the list, or understand the concurrency implications of - * modifying items, before performing any action on them. - * - * @return a possibly empty list of (all) bag items - */ - @SuppressWarnings("unchecked") - public List> values() { - return (List>) sharedList.clone(); - } - - /** - * Get the total number of items in the bag. - * - * @return the number of items in the bag - */ - public int size() { - return sharedList.size(); - } - - /** - * Determine whether to use WeakReferences based on whether there is a - * custom ClassLoader implementation sitting between this class and the - * System ClassLoader. - * - * @return true if we should use WeakReferences in our ThreadLocals, false otherwise - */ - private boolean useWeakThreadLocals() { - try { - return getClass().getClassLoader() != ClassLoader.getSystemClassLoader(); - } catch (SecurityException se) { - return true; - } - } - - public static class BagEntry { - - @SuppressWarnings({ "unused" }) - private volatile int state = 0; // Don't delete me and add final declaration, will be used by the stateUpdater - - private static final AtomicIntegerFieldUpdater stateUpdater; - - private final T value; - - static { - stateUpdater = AtomicIntegerFieldUpdater.newUpdater(BagEntry.class, "state"); - } - - public BagEntry(T value) { - this.value = value; - } - - public T value() { - return value; - } - - public int getState() { - return stateUpdater.get(this); - } - - public boolean compareAndSet(int expect, int update) { - return stateUpdater.compareAndSet(this, expect, update); - } - - public void setState(int update) { - stateUpdater.set(this, update); - } - - } - - /** - * Fast list without range checking. - * - * @author Brett Wooldridge - */ - private static final class FastList implements List, RandomAccess { - - private final Class clazz; - private T[] elementData; - private int size; - - /** - * Construct a FastList with a specified size. - * @param clazz the Class stored in the collection - * @param capacity the initial size of the FastList - */ - @SuppressWarnings("unchecked") - public FastList(Class clazz, int capacity) { - this.elementData = (T[]) Array.newInstance(clazz, capacity); - this.clazz = clazz; - } - - /** - * Add an element to the tail of the FastList. - * - * @param element the element to add - */ - @Override - public boolean add(T element) { - if (size < elementData.length) { - elementData[size++] = element; - } else { - // overflow-conscious code - final int oldCapacity = elementData.length; - final int newCapacity = oldCapacity << 1; - @SuppressWarnings("unchecked") - final T[] newElementData = (T[]) Array.newInstance(clazz, newCapacity); - System.arraycopy(elementData, 0, newElementData, 0, oldCapacity); - newElementData[size++] = element; - elementData = newElementData; - } - - return true; - } - - /** - * Get the element at the specified index. - * - * @param index the index of the element to get - * @return the element, or ArrayIndexOutOfBounds is thrown if the index is invalid - */ - @Override - public T get(int index) { - return elementData[index]; - } - - /** - * This remove method is most efficient when the element being removed - * is the last element. Equality is identity based, not equals() based. - * Only the first matching element is removed. - * - * @param element the element to remove - */ - @Override - public boolean remove(Object element) { - for (int index = size - 1; index >= 0; index--) { - if (element == elementData[index]) { - final int numMoved = size - index - 1; - if (numMoved > 0) { - System.arraycopy(elementData, index + 1, elementData, index, numMoved); - } - elementData[--size] = null; - return true; - } - } - - return false; - } - - /** - * Clear the FastList. - */ - @Override - public void clear() { - for (int i = 0; i < size; i++) { - elementData[i] = null; - } - - size = 0; - } - - /** - * Get the current number of elements in the FastList. - * - * @return the number of current elements - */ - @Override - public int size() { - return size; - } - - @Override - public boolean isEmpty() { - return size == 0; - } - - @Override - public T set(int index, T element) { - T old = elementData[index]; - elementData[index] = element; - return old; - } - - @Override - public T remove(int index) { - if (size == 0) { - return null; - } - - final T old = elementData[index]; - - final int numMoved = size - index - 1; - if (numMoved > 0) { - System.arraycopy(elementData, index + 1, elementData, index, numMoved); - } - - elementData[--size] = null; - - return old; - } - - @Override - public boolean contains(Object o) { - throw new UnsupportedOperationException(); - } - - @Override - public Iterator iterator() { - return new Iterator<>() { - private int index; - - @Override - public boolean hasNext() { - return index < size; - } - - @Override - public T next() { - if (index < size) { - return elementData[index++]; - } - - throw new NoSuchElementException("No more elements in FastList"); - } - }; - } - - @Override - public Object[] toArray() { - throw new UnsupportedOperationException(); - } - - @Override - public E[] toArray(E[] a) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean containsAll(Collection c) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean addAll(Collection c) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean addAll(int index, Collection c) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean removeAll(Collection c) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean retainAll(Collection c) { - throw new UnsupportedOperationException(); - } - - @Override - public void add(int index, T element) { - throw new UnsupportedOperationException(); - } - - @Override - public int indexOf(Object o) { - throw new UnsupportedOperationException(); - } - - @Override - public int lastIndexOf(Object o) { - throw new UnsupportedOperationException(); - } - - @Override - public ListIterator listIterator() { - throw new UnsupportedOperationException(); - } - - @Override - public ListIterator listIterator(int index) { - throw new UnsupportedOperationException(); - } - - @Override - public List subList(int fromIndex, int toIndex) { - throw new UnsupportedOperationException(); - } - - @Override - public Object clone() { - throw new UnsupportedOperationException(); - } - - @Override - public void forEach(Consumer action) { - throw new UnsupportedOperationException(); - } - - @Override - public Spliterator spliterator() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean removeIf(Predicate filter) { - throw new UnsupportedOperationException(); - } - - @Override - public void replaceAll(UnaryOperator operator) { - throw new UnsupportedOperationException(); - } - - @Override - public void sort(Comparator c) { - throw new UnsupportedOperationException(); - } - - } -} From 15dadeee10b3900550041dc6af2254966773925a Mon Sep 17 00:00:00 2001 From: Lijun Liao Date: Fri, 12 Apr 2024 21:55:31 +0200 Subject: [PATCH 05/11] rename .security.shell.Actions to security.shell.SecurityActions. --- .../main/java/org/xipki/security/shell/JceActions.java | 2 +- .../main/java/org/xipki/security/shell/P11Actions.java | 6 +++--- .../main/java/org/xipki/security/shell/P12Actions.java | 6 +++--- .../java/org/xipki/security/shell/PasswordActions.java | 2 +- .../java/org/xipki/security/shell/QaSecurityActions.java | 8 ++++---- .../security/shell/{Actions.java => SecurityActions.java} | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) rename security-shell/src/main/java/org/xipki/security/shell/{Actions.java => SecurityActions.java} (99%) diff --git a/security-shell/src/main/java/org/xipki/security/shell/JceActions.java b/security-shell/src/main/java/org/xipki/security/shell/JceActions.java index 07ec241..d16eaa0 100644 --- a/security-shell/src/main/java/org/xipki/security/shell/JceActions.java +++ b/security-shell/src/main/java/org/xipki/security/shell/JceActions.java @@ -23,7 +23,7 @@ public class JceActions { @Command(scope = "xi", name = "csr-jce", description = "generate CSR request with JCE device") @Service - public static class CsrJce extends Actions.BaseCsrGenAction { + public static class CsrJce extends SecurityActions.BaseCsrGenAction { @Option(name = "--type", required = true, description = "JCE signer type") private String type; diff --git a/security-shell/src/main/java/org/xipki/security/shell/P11Actions.java b/security-shell/src/main/java/org/xipki/security/shell/P11Actions.java index c4bf624..b078fb4 100644 --- a/security-shell/src/main/java/org/xipki/security/shell/P11Actions.java +++ b/security-shell/src/main/java/org/xipki/security/shell/P11Actions.java @@ -28,8 +28,8 @@ import org.xipki.security.pkcs11.P11Slot; import org.xipki.security.pkcs11.P11Slot.P11NewKeyControl; import org.xipki.security.pkcs11.P11SlotId; -import org.xipki.security.shell.Actions.CsrGenAction; -import org.xipki.security.shell.Actions.SecurityAction; +import org.xipki.security.shell.SecurityActions.CsrGenAction; +import org.xipki.security.shell.SecurityActions.SecurityAction; import org.xipki.security.util.AlgorithmUtil; import org.xipki.security.util.KeyUtil; import org.xipki.shell.Completers; @@ -384,7 +384,7 @@ public static class RsaP11 extends P11KeyGenAction { private Integer keysize = 2048; @Option(name = "-e", description = "public exponent") - private String publicExponent = Actions.TEXT_F4; + private String publicExponent = SecurityActions.TEXT_F4; @Override protected Object execute0() throws Exception { diff --git a/security-shell/src/main/java/org/xipki/security/shell/P12Actions.java b/security-shell/src/main/java/org/xipki/security/shell/P12Actions.java index 54ebcb8..457ae42 100644 --- a/security-shell/src/main/java/org/xipki/security/shell/P12Actions.java +++ b/security-shell/src/main/java/org/xipki/security/shell/P12Actions.java @@ -21,8 +21,8 @@ import org.xipki.security.pkcs12.KeypairWithCert; import org.xipki.security.pkcs12.KeystoreGenerationParameters; import org.xipki.security.pkcs12.P12KeyGenerator; -import org.xipki.security.shell.Actions.CsrGenAction; -import org.xipki.security.shell.Actions.SecurityAction; +import org.xipki.security.shell.SecurityActions.CsrGenAction; +import org.xipki.security.shell.SecurityActions.SecurityAction; import org.xipki.security.util.AlgorithmUtil; import org.xipki.security.util.KeyUtil; import org.xipki.security.util.X509Util; @@ -387,7 +387,7 @@ public static class RsaP12 extends P12KeyGenAction { private Integer keysize = 2048; @Option(name = "-e", description = "public exponent") - private String publicExponent = Actions.TEXT_F4; + private String publicExponent = SecurityActions.TEXT_F4; @Override protected Object execute0() throws Exception { diff --git a/security-shell/src/main/java/org/xipki/security/shell/PasswordActions.java b/security-shell/src/main/java/org/xipki/security/shell/PasswordActions.java index b38ff88..0065418 100644 --- a/security-shell/src/main/java/org/xipki/security/shell/PasswordActions.java +++ b/security-shell/src/main/java/org/xipki/security/shell/PasswordActions.java @@ -11,7 +11,7 @@ import org.xipki.password.OBFPasswordService; import org.xipki.password.PBEPasswordService; import org.xipki.password.Passwords; -import org.xipki.security.shell.Actions.SecurityAction; +import org.xipki.security.shell.SecurityActions.SecurityAction; import org.xipki.shell.IllegalCmdParamException; import org.xipki.util.Args; import org.xipki.util.IoUtil; diff --git a/security-shell/src/main/java/org/xipki/security/shell/QaSecurityActions.java b/security-shell/src/main/java/org/xipki/security/shell/QaSecurityActions.java index 86e2a7d..b502e30 100644 --- a/security-shell/src/main/java/org/xipki/security/shell/QaSecurityActions.java +++ b/security-shell/src/main/java/org/xipki/security/shell/QaSecurityActions.java @@ -545,7 +545,7 @@ public static class SpeedRsaGenP11 extends SpeedP11ActionQa { private Integer keysize = 2048; @Option(name = "--exponent", aliases = "-e", description = "public exponent") - private String publicExponent = Actions.TEXT_F4; + private String publicExponent = SecurityActions.TEXT_F4; @Override protected BenchmarkExecutor getTester() throws Exception { @@ -568,7 +568,7 @@ public static class SpeedRsaSignP11 extends SpeedP11SignActionQa { private Integer keysize = 2048; @Option(name = "-e", description = "public exponent") - private String publicExponent = Actions.TEXT_F4; + private String publicExponent = SecurityActions.TEXT_F4; @Option(name = "--sig-algo", required = true, description = "signature algorithm") @Completion(QaCompleters.RSASigAlgCompleter.class) @@ -892,7 +892,7 @@ public static class SpeedRsaGenP12 extends SingleSpeedActionQa { private Integer keysize = 2048; @Option(name = "-e", description = "public exponent") - private String publicExponent = Actions.TEXT_F4; + private String publicExponent = SecurityActions.TEXT_F4; @Override protected BenchmarkExecutor getTester() throws Exception { @@ -910,7 +910,7 @@ public static class SpeedRsaSignP12 extends SpeedP12SignActionQa { private Integer keysize = 2048; @Option(name = "-e", description = "public exponent") - private String publicExponent = Actions.TEXT_F4; + private String publicExponent = SecurityActions.TEXT_F4; @Option(name = "--sig-algo", required = true, description = "signature algorithm") @Completion(QaCompleters.RSASigAlgCompleter.class) diff --git a/security-shell/src/main/java/org/xipki/security/shell/Actions.java b/security-shell/src/main/java/org/xipki/security/shell/SecurityActions.java similarity index 99% rename from security-shell/src/main/java/org/xipki/security/shell/Actions.java rename to security-shell/src/main/java/org/xipki/security/shell/SecurityActions.java index 1d8ec1f..0cf03fc 100644 --- a/security-shell/src/main/java/org/xipki/security/shell/Actions.java +++ b/security-shell/src/main/java/org/xipki/security/shell/SecurityActions.java @@ -118,7 +118,7 @@ * @author Lijun Liao (xipki) */ -public class Actions { +public class SecurityActions { public static final String TEXT_F4 = "0x10001"; From cc69e0372beabf1dbf79ba94f5e6e0bf2ae3f2a4 Mon Sep 17 00:00:00 2001 From: Lijun Liao Date: Thu, 18 Jul 2024 22:04:29 +0200 Subject: [PATCH 06/11] removed instable hsm-proxy module and multiple pkcs11 devices support --- .../org/xipki/security/shell/P11Actions.java | 40 +- .../security/shell/QaSecurityActions.java | 18 +- .../security/shell/SecurityCompleters.java | 22 - .../java/org/xipki/security/Securities.java | 2 - .../security/pkcs11/NativeP11Module.java | 28 +- .../xipki/security/pkcs11/NativeP11Slot.java | 7 +- .../pkcs11/P11CryptServiceFactory.java | 9 +- .../pkcs11/P11CryptServiceFactoryImpl.java | 70 +- .../org/xipki/security/pkcs11/P11Module.java | 4 - .../xipki/security/pkcs11/P11ModuleConf.java | 255 +-- .../security/pkcs11/P11SignerFactory.java | 3 +- .../org/xipki/security/pkcs11/P11Slot.java | 30 +- .../org/xipki/security/pkcs11/Pkcs11conf.java | 440 ++--- .../pkcs11/emulator/EmulatorP11Module.java | 14 +- .../pkcs11/emulator/EmulatorP11Slot.java | 9 +- .../pkcs11/hsmproxy/HsmProxyP11Key.java | 78 - .../pkcs11/hsmproxy/HsmProxyP11Module.java | 428 ----- .../hsmproxy/HsmProxyP11ModuleFactory.java | 34 - .../pkcs11/hsmproxy/HsmProxyP11Slot.java | 375 ----- .../security/pkcs11/hsmproxy/ProxyAction.java | 82 - .../pkcs11/hsmproxy/ProxyMessage.java | 1465 ----------------- .../org/xipki/security/qa/P11SignSpeed.java | 8 +- .../resources/OSGI-INF/blueprint/config.xml | 8 - util/src/main/java/org/xipki/util/Args.java | 1 + 24 files changed, 218 insertions(+), 3212 deletions(-) delete mode 100644 security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Key.java delete mode 100644 security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Module.java delete mode 100644 security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11ModuleFactory.java delete mode 100644 security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Slot.java delete mode 100644 security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyAction.java delete mode 100644 security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyMessage.java diff --git a/security-shell/src/main/java/org/xipki/security/shell/P11Actions.java b/security-shell/src/main/java/org/xipki/security/shell/P11Actions.java index b078fb4..f049a67 100644 --- a/security-shell/src/main/java/org/xipki/security/shell/P11Actions.java +++ b/security-shell/src/main/java/org/xipki/security/shell/P11Actions.java @@ -79,10 +79,6 @@ public static class CsrP11 extends CsrGenAction { + "either keyId or keyLabel must be specified") private String label; - @Option(name = "--module", description = "name of the PKCS#11 module") - @Completion(SecurityCompleters.P11ModuleNameCompleter.class) - private String moduleName = "default"; - @Override protected ConcurrentContentSigner getSigner() throws Exception { SignatureAlgoControl signatureAlgoControl = getSignatureAlgoControl(); @@ -92,13 +88,13 @@ protected ConcurrentContentSigner getSigner() throws Exception { idBytes = Hex.decode(id); } - SignerConf conf = getPkcs11SignerConf(moduleName, Integer.parseInt(slotIndex), label, + SignerConf conf = getPkcs11SignerConf(Integer.parseInt(slotIndex), label, idBytes, 1, null, signatureAlgoControl); return securityFactory.createSigner("PKCS11", conf, (X509Cert[]) null); } public static SignerConf getPkcs11SignerConf( - String pkcs11ModuleName, int slotIndex, String keyLabel, byte[] keyId, int parallelism, + int slotIndex, String keyLabel, byte[] keyId, int parallelism, HashAlgo hashAlgo, SignatureAlgoControl signatureAlgoControl) { Args.positive(parallelism, "parallelism"); @@ -109,10 +105,6 @@ public static SignerConf getPkcs11SignerConf( ConfPairs conf = new ConfPairs(); conf.putPair("parallelism", Integer.toString(parallelism)); - if (pkcs11ModuleName != null && !pkcs11ModuleName.isEmpty()) { - conf.putPair("module", pkcs11ModuleName); - } - conf.putPair("slot", Integer.toString(slotIndex)); if (keyId != null) { @@ -564,30 +556,21 @@ protected char[] getPassword() throws IOException, PasswordResolverException { public abstract static class P11SecurityAction extends SecurityAction { - protected static final String DEFAULT_P11MODULE_NAME = P11CryptServiceFactory.DEFAULT_P11MODULE_NAME; - @Option(name = "--slot", description = "slot index") protected String slotIndex = "0"; // use String instead int so that the default value 0 will be shown in the help. - @Option(name = "--module", description = "name of the PKCS#11 module") - @Completion(SecurityCompleters.P11ModuleNameCompleter.class) - protected String moduleName = DEFAULT_P11MODULE_NAME; - @Reference (optional = true) protected P11CryptServiceFactory p11CryptServiceFactory; protected P11Slot getSlot() throws XiSecurityException, TokenException, IllegalCmdParamException { - P11Module module = getP11Module(moduleName); + P11Module module = getP11Module(); P11SlotId slotId = module.getSlotIdForIndex(Integer.parseInt(slotIndex)); return module.getSlot(slotId); } - protected P11Module getP11Module(String moduleName) - throws XiSecurityException, TokenException, IllegalCmdParamException { - P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(moduleName); - if (p11Service == null) { - throw new IllegalCmdParamException("undefined module " + moduleName); - } + protected P11Module getP11Module() + throws XiSecurityException, TokenException { + P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(); return p11Service.getModule(); } @@ -620,10 +603,6 @@ public static class TokenInfoP11 extends SecurityAction { @Option(name = "--verbose", aliases = "-v", description = "show object information verbosely") private Boolean verbose = Boolean.FALSE; - @Option(name = "--module", description = "name of the PKCS#11 module.") - @Completion(SecurityCompleters.P11ModuleNameCompleter.class) - private String moduleName = P11SecurityAction.DEFAULT_P11MODULE_NAME; - @Option(name = "--slot", description = "slot index") private Integer slotIndex; @@ -635,13 +614,8 @@ public static class TokenInfoP11 extends SecurityAction { @Override protected Object execute0() throws Exception { - P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(moduleName); - if (p11Service == null) { - throw new IllegalCmdParamException("undefined module " + moduleName); - } - + P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(); P11Module module = p11Service.getModule(); - println("module: " + moduleName); println(module.getDescription()); List slots = module.getSlotIds(); diff --git a/security-shell/src/main/java/org/xipki/security/shell/QaSecurityActions.java b/security-shell/src/main/java/org/xipki/security/shell/QaSecurityActions.java index b502e30..7b10af8 100644 --- a/security-shell/src/main/java/org/xipki/security/shell/QaSecurityActions.java +++ b/security-shell/src/main/java/org/xipki/security/shell/QaSecurityActions.java @@ -183,15 +183,8 @@ public abstract static class BSpeedP11ActionQa extends BatchSpeedActionQa { @Option(name = "--slot", description = "slot index") protected int slotIndex = 0; - @Option(name = "--module", description = "name of the PKCS#11 module.") - @Completion(SecurityCompleters.P11ModuleNameCompleter.class) - protected String moduleName = P11CryptServiceFactory.DEFAULT_P11MODULE_NAME; - protected P11Slot getSlot() throws XiSecurityException, TokenException, IllegalCmdParamException { - P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(moduleName); - if (p11Service == null) { - throw new IllegalCmdParamException("undefined module " + moduleName); - } + P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(); P11Module module = p11Service.getModule(); return module.getSlot(module.getSlotIdForIndex(slotIndex)); } @@ -358,16 +351,9 @@ public abstract static class SpeedP11ActionQa extends SingleSpeedActionQa { @Option(name = "--slot", description = "slot index") protected int slotIndex = 0; - @Option(name = "--module", description = "Name of the PKCS#11 module.") - @Completion(SecurityCompleters.P11ModuleNameCompleter.class) - protected String moduleName = P11CryptServiceFactory.DEFAULT_P11MODULE_NAME; - protected P11Slot getSlot() throws XiSecurityException, TokenException, IllegalCmdParamException { - P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(moduleName); - if (p11Service == null) { - throw new IllegalCmdParamException("undefined module " + moduleName); - } + P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(); P11Module module = p11Service.getModule(); return module.getSlot(module.getSlotIdForIndex(slotIndex)); } diff --git a/security-shell/src/main/java/org/xipki/security/shell/SecurityCompleters.java b/security-shell/src/main/java/org/xipki/security/shell/SecurityCompleters.java index ac3e5d6..bae05ae 100644 --- a/security-shell/src/main/java/org/xipki/security/shell/SecurityCompleters.java +++ b/security-shell/src/main/java/org/xipki/security/shell/SecurityCompleters.java @@ -3,16 +3,11 @@ package org.xipki.security.shell; -import org.apache.karaf.shell.api.action.lifecycle.Reference; import org.apache.karaf.shell.api.action.lifecycle.Service; import org.xipki.security.SignAlgo; -import org.xipki.security.pkcs11.P11CryptServiceFactory; import org.xipki.security.pkcs11.P11Slot.P11KeyUsage; -import org.xipki.shell.DynamicEnumCompleter; import org.xipki.shell.EnumCompleter; -import org.xipki.util.CollectionUtil; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -62,23 +57,6 @@ public static Set parseUsages(List usageTexts) { } // class P11KeyUsageCompleter - @Service - public static class P11ModuleNameCompleter extends DynamicEnumCompleter { - - @Reference (optional = true) - private P11CryptServiceFactory p11CryptServiceFactory; - - @Override - protected Set getEnums() { - Set names = p11CryptServiceFactory.getModuleNames(); - if (CollectionUtil.isEmpty(names)) { - return Collections.emptySet(); - } - return names; - } - - } // class P11ModuleNameCompleter - @Service public static class SecretKeyTypeCompleter extends EnumCompleter { diff --git a/security/src/main/java/org/xipki/security/Securities.java b/security/src/main/java/org/xipki/security/Securities.java index 648fccf..048ceb8 100644 --- a/security/src/main/java/org/xipki/security/Securities.java +++ b/security/src/main/java/org/xipki/security/Securities.java @@ -15,7 +15,6 @@ import org.xipki.security.pkcs11.P11SignerFactory; import org.xipki.security.pkcs11.Pkcs11conf; import org.xipki.security.pkcs11.emulator.EmulatorP11ModuleFactory; -import org.xipki.security.pkcs11.hsmproxy.HsmProxyP11ModuleFactory; import org.xipki.security.pkcs12.P12SignerFactory; import org.xipki.util.CollectionUtil; import org.xipki.util.FileOrValue; @@ -142,7 +141,6 @@ private static List createDefaultFactories() { List factories = new ArrayList<>(3); factories.add(new NativeP11ModuleFactory()); factories.add(new EmulatorP11ModuleFactory()); - factories.add(new HsmProxyP11ModuleFactory()); return factories; } diff --git a/security/src/main/java/org/xipki/security/pkcs11/NativeP11Module.java b/security/src/main/java/org/xipki/security/pkcs11/NativeP11Module.java index 9c29488..8673623 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/NativeP11Module.java +++ b/security/src/main/java/org/xipki/security/pkcs11/NativeP11Module.java @@ -22,6 +22,8 @@ import org.xipki.util.StringUtil; import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Optional; @@ -71,7 +73,7 @@ private NativeP11Module(PKCS11Module module, P11ModuleConf moduleConf) throws To try { slotList = module.getSlotList(false); } catch (Throwable th) { - final String msg = "could not getSlotList of module " + moduleConf.getName(); + final String msg = "could not getSlotList of module"; LogUtil.error(LOG, th, msg); throw new TokenException(msg); } @@ -129,7 +131,7 @@ private NativeP11Module(PKCS11Module module, P11ModuleConf moduleConf) throws To } } - List pwd; + char[] pwd; try { pwd = moduleConf.getPasswordRetriever().getPassword(slotId); } catch (PasswordResolverException ex) { @@ -140,15 +142,15 @@ private NativeP11Module(PKCS11Module module, P11ModuleConf moduleConf) throws To slot.getModule().nameToCode(PKCS11Constants.Category.CKU, getConf().getUserType())).orElseThrow( () -> new TokenException("Unknown user type " + getConf().getUserType())); - PKCS11Token token = new PKCS11Token(slot.getToken(), moduleConf.isReadOnly(), userType, - moduleConf.getUserName(), pwd, moduleConf.getNumSessions()); + PKCS11Token token = new PKCS11Token(slot.getToken(), moduleConf.isReadOnly(), userType, null, + pwd == null ? null : Collections.singletonList(pwd), moduleConf.getNumSessions()); token.setMaxMessageSize(moduleConf.getMaxMessageSize()); if (moduleConf.getNewSessionTimeout() != null) { token.setTimeOutWaitNewSession(moduleConf.getNewSessionTimeout()); } - P11Slot p11Slot = new NativeP11Slot(moduleConf.getName(), slotId, token , moduleConf.getP11MechanismFilter(), - moduleConf.getP11NewObjectConf(), moduleConf.getSecretKeyTypes(), moduleConf.getKeyPairTypes()); + P11Slot p11Slot = new NativeP11Slot(slotId, token, moduleConf.getP11NewObjectConf(), + moduleConf.getSecretKeyTypes(), moduleConf.getKeyPairTypes()); slots.add(p11Slot); } @@ -177,7 +179,7 @@ public static P11Module getInstance(P11ModuleConf moduleConf) throws TokenExcept try { module = PKCS11Module.getInstance(path); } catch (IOException ex) { - final String msg = "could not load the PKCS#11 module " + moduleConf.getName() + ": " + path; + final String msg = "could not load the PKCS#11 module: " + path; LogUtil.error(LOG, ex, msg); throw new TokenException(msg, ex); } @@ -187,7 +189,7 @@ public static P11Module getInstance(P11ModuleConf moduleConf) throws TokenExcept } catch (PKCS11Exception ex) { if (ex.getErrorCode() != PKCS11Constants.CKR_CRYPTOKI_ALREADY_INITIALIZED) { LogUtil.error(LOG, ex); - close(moduleConf.getName(), module); + closeModule(moduleConf.getNativeLibrary(), module); throw ex; } else { LOG.info("PKCS#11 module already initialized"); @@ -199,7 +201,7 @@ public static P11Module getInstance(P11ModuleConf moduleConf) throws TokenExcept } } catch (Throwable th) { LOG.error("unexpected Exception", th); - close(moduleConf.getName(), module); + closeModule(moduleConf.getNativeLibrary(), module); throw new TokenException(th.getMessage()); } @@ -221,19 +223,19 @@ public void close() { } } - close(conf.getNativeLibrary(), module); + closeModule(conf.getNativeLibrary(), module); } - private static void close(String modulePath, PKCS11Module module) { + private static void closeModule(String path, PKCS11Module module) { if (module == null) { return; } - LOG.info("close PKCS#11 module: {}", modulePath); + LOG.info("close PKCS#11 module {}", path); try { module.finalize(null); } catch (Throwable th) { - LogUtil.error(LOG, th, "could not close module " + modulePath); + LogUtil.error(LOG, th, "could not close module " + path); } } } diff --git a/security/src/main/java/org/xipki/security/pkcs11/NativeP11Slot.java b/security/src/main/java/org/xipki/security/pkcs11/NativeP11Slot.java index 5282a37..86762e8 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/NativeP11Slot.java +++ b/security/src/main/java/org/xipki/security/pkcs11/NativeP11Slot.java @@ -37,7 +37,6 @@ import org.xipki.pkcs11.wrapper.TokenInfo; import org.xipki.pkcs11.wrapper.params.ExtraParams; import org.xipki.security.EdECConstants; -import org.xipki.security.pkcs11.P11ModuleConf.P11MechanismFilter; import org.xipki.security.pkcs11.P11ModuleConf.P11NewObjectConf; import org.xipki.security.util.KeyUtil; import org.xipki.util.Args; @@ -156,10 +155,10 @@ class NativeP11Slot extends P11Slot { private String libDesc; - NativeP11Slot(String moduleName, P11SlotId slotId, PKCS11Token token, P11MechanismFilter mechanismFilter, + NativeP11Slot(P11SlotId slotId, PKCS11Token token, P11NewObjectConf newObjectConf, List secretKeyTypes, List keyPairTypes) throws TokenException { - super(moduleName, slotId, token.isReadOnly(), secretKeyTypes, keyPairTypes, newObjectConf); + super(slotId, token.isReadOnly(), secretKeyTypes, keyPairTypes, newObjectConf); if (slotId.getId() != token.getTokenId()) { throw new IllegalArgumentException("slotId != token.getTokenId"); } @@ -172,7 +171,7 @@ class NativeP11Slot extends P11Slot { libDesc = ""; } - initMechanisms(getSupportedMechanisms(), mechanismFilter); + initMechanisms(getSupportedMechanisms()); rsaKeyPairGenMech = supportsMechanism(CKM_RSA_X9_31_KEY_PAIR_GEN, CKF_GENERATE_KEY_PAIR) ? CKM_RSA_X9_31_KEY_PAIR_GEN : CKM_RSA_PKCS_KEY_PAIR_GEN; diff --git a/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactory.java b/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactory.java index 23b51e8..c1d896a 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactory.java +++ b/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactory.java @@ -7,7 +7,6 @@ import org.xipki.security.XiSecurityException; import java.io.Closeable; -import java.util.Set; /** * Factory to create {@link P11CryptService}. @@ -18,20 +17,14 @@ public interface P11CryptServiceFactory extends Closeable { - String DEFAULT_P11MODULE_NAME = "default"; - /** * Gets the {@link P11CryptService} of the given module {@code moduleName}. - * @param moduleName - * Module name. {@code null} for default module name. * @return the {@link P11CryptService} of the given module. * @throws TokenException * if PKCS#11 token error occurs. * @throws XiSecurityException * if security error occurs. */ - P11CryptService getP11CryptService(String moduleName) throws TokenException, XiSecurityException; - - Set getModuleNames(); + P11CryptService getP11CryptService() throws TokenException, XiSecurityException; } diff --git a/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactoryImpl.java b/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactoryImpl.java index 4619a2d..65ce210 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactoryImpl.java +++ b/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactoryImpl.java @@ -32,11 +32,9 @@ public class P11CryptServiceFactoryImpl implements P11CryptServiceFactory { private static final Logger LOG = LoggerFactory.getLogger(P11CryptServiceFactoryImpl.class); - private static final Map services = new HashMap<>(); + private P11CryptService service; - private Map moduleConfs; - - private Set moduleNames; + private P11ModuleConf moduleConf; private String pkcs11ConfFile; @@ -49,7 +47,7 @@ public P11CryptServiceFactoryImpl(P11ModuleFactoryRegister p11ModuleFactoryRegis } public synchronized void init() throws InvalidConfException { - if (moduleConfs != null) { + if (moduleConf != null) { return; } @@ -67,62 +65,31 @@ public synchronized void init() throws InvalidConfException { } } - try { - Map confs = geModuleConfs(); - this.moduleConfs = Collections.unmodifiableMap(confs); - this.moduleNames = Set.copyOf(confs.keySet()); - } catch (RuntimeException ex) { - throw new InvalidConfException("could not create P11Conf: " + ex.getMessage(), ex); - } + this.moduleConf = new P11ModuleConf(pkcs11Conf); } // method init - private Map geModuleConfs() throws InvalidConfException { - List moduleTypes = pkcs11Conf.getModules(); - List mechanismSets = pkcs11Conf.getMechanismSets(); - - Map confs = new HashMap<>(); - for (Pkcs11conf.Module moduleType : moduleTypes) { - P11ModuleConf conf = new P11ModuleConf(moduleType, mechanismSets); - confs.put(conf.getName(), conf); - } - - if (!confs.containsKey(P11CryptServiceFactory.DEFAULT_P11MODULE_NAME)) { - throw new InvalidConfException("module '" + P11CryptServiceFactory.DEFAULT_P11MODULE_NAME + "' is not defined"); - } - return confs; - } - - public synchronized P11CryptService getP11CryptService(String moduleName) - throws XiSecurityException, TokenException { + @Override + public synchronized P11CryptService getP11CryptService() + throws TokenException { try { init(); } catch (InvalidConfException ex) { throw new IllegalStateException("could not initialize P11CryptServiceFactory: " + ex.getMessage(), ex); } - if (moduleConfs == null) { + if (moduleConf == null) { throw new IllegalStateException("please set pkcs11ConfFile and then call init() first"); } - final String name = getModuleName(moduleName); - P11ModuleConf conf = Optional.ofNullable(moduleConfs.get(name)).orElseThrow(() -> - new XiSecurityException("PKCS#11 module " + name + " is not defined")); - - P11CryptService instance = services.get(name); - if (instance == null) { - P11Module p11Module = p11ModuleFactoryRegister.getP11Module(conf); - instance = new P11CryptService(p11Module); - LOG.info("added PKCS#11 module {}\n{}", name, instance.getModule().getDescription()); - services.put(name, instance); + if (service == null) { + P11Module p11Module = p11ModuleFactoryRegister.getP11Module(moduleConf); + service = new P11CryptService(p11Module); + LOG.info("initialized PKCS#11 module \n{}", service.getModule().getDescription()); } - return instance; + return service; } // method getP11CryptService - private String getModuleName(String moduleName) { - return (moduleName == null) ? DEFAULT_P11MODULE_NAME : moduleName; - } - public void setPkcs11ConfFile(String confFile) { this.pkcs11ConfFile = StringUtil.isBlank(confFile) ? null : IoUtil.expandFilepath(confFile); this.pkcs11Conf = null; @@ -138,17 +105,6 @@ public void setPkcs11Conf(Pkcs11conf conf) throws InvalidConfException { @Override public void close() { - services.clear(); - } - - @Override - public Set getModuleNames() { - try { - init(); - } catch (InvalidConfException ex) { - throw new IllegalStateException("could not initialize P11CryptServiceFactory: " + ex.getMessage(), ex); - } - return moduleNames; } } diff --git a/security/src/main/java/org/xipki/security/pkcs11/P11Module.java b/security/src/main/java/org/xipki/security/pkcs11/P11Module.java index 45d15df..68926da 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/P11Module.java +++ b/security/src/main/java/org/xipki/security/pkcs11/P11Module.java @@ -36,10 +36,6 @@ public P11Module(P11ModuleConf conf) { public abstract String getDescription(); - public String getName() { - return conf.getName(); - } - public boolean isReadOnly() { return conf.isReadOnly(); } diff --git a/security/src/main/java/org/xipki/security/pkcs11/P11ModuleConf.java b/security/src/main/java/org/xipki/security/pkcs11/P11ModuleConf.java index 5c67b64..5d202f6 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/P11ModuleConf.java +++ b/security/src/main/java/org/xipki/security/pkcs11/P11ModuleConf.java @@ -8,16 +8,13 @@ import org.xipki.password.PasswordResolverException; import org.xipki.password.Passwords; import org.xipki.pkcs11.wrapper.PKCS11Constants; -import org.xipki.pkcs11.wrapper.PKCS11Module; import org.xipki.util.Args; import org.xipki.util.CollectionUtil; import org.xipki.util.StringUtil; import org.xipki.util.exception.InvalidConfException; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -62,135 +59,17 @@ boolean match(P11SlotId slotId) { } // class P11SlotIdFilter - private static final class MechanismSet { - private Set includeMechanisms; - private Set excludeMechanisms; - } - - private static final class P11SingleMechanismFilter { - - private static final Object NULL_MODULE = new Object(); - - private final Set slots; - - private final Collection includeMechanisms; - - private final Collection excludeMechanisms; - - private Object module; - - private final Set includeMechanismCodes = new HashSet<>(); - - private final Set excludeMechanismCodes = new HashSet<>(); - - private P11SingleMechanismFilter(Set slots, Collection includeMechanisms, - Collection excludeMechanisms) { - this.slots = slots; - this.includeMechanisms = CollectionUtil.isEmpty(includeMechanisms) ? null : includeMechanisms; - this.excludeMechanisms = CollectionUtil.isEmpty(excludeMechanisms) ? null : excludeMechanisms; - } - - public boolean match(P11SlotId slot) { - if (slots == null) { - return true; - } - for (P11SlotIdFilter m : slots) { - if (m.match(slot)) { - return true; - } - } - - return false; - } - - public boolean isMechanismSupported(long mechanism, PKCS11Module module) { - if (includeMechanisms == null && excludeMechanisms == null) { - return true; - } - - synchronized (this) { - boolean computeCodes = (module != null) ? (this.module != module) : (this.module != NULL_MODULE); - if (computeCodes) { - includeMechanismCodes.clear(); - excludeMechanismCodes.clear(); - - if (includeMechanisms != null) { - for (String mechName : includeMechanisms) { - Long mechCode = (module != null) ? module.nameToCode(PKCS11Constants.Category.CKM, mechName) - : PKCS11Constants.nameToCode(PKCS11Constants.Category.CKM, mechName); - if (mechCode != null) { - includeMechanismCodes.add(mechCode); - } - } - } - - if (excludeMechanisms != null) { - for (String mechName : excludeMechanisms) { - Long mechCode = (module != null) ? module.nameToCode(PKCS11Constants.Category.CKM, mechName) - : PKCS11Constants.nameToCode(PKCS11Constants.Category.CKM, mechName); - if (mechCode != null) { - excludeMechanismCodes.add(mechCode); - } - } - } - - this.module = (module != null) ? module : NULL_MODULE; - } - } - - if (excludeMechanismCodes.contains(mechanism)) { - return false; - } - - return includeMechanisms == null || includeMechanismCodes.contains(mechanism); - } - - } // class P11SingleMechanismFilter - - public static class P11MechanismFilter { - - private final List singleFilters; - - P11MechanismFilter() { - singleFilters = new LinkedList<>(); - } - - void addEntry(Set slots, Collection includeMechanisms, - Collection excludeMechanisms) { - singleFilters.add( - new P11SingleMechanismFilter(slots, - includeMechanisms, - excludeMechanisms)); - } - - public boolean isMechanismPermitted(P11SlotId slotId, long mechanism, PKCS11Module module) { - Args.notNull(slotId, "slotId"); - if (CollectionUtil.isEmpty(singleFilters)) { - return true; - } - - for (P11SingleMechanismFilter sr : singleFilters) { - if (sr.match(slotId)) { - return sr.isMechanismSupported(mechanism, module); - } - } - - return true; - } - - } // class P11MechanismFilter - public static class P11PasswordsRetriever { private static final class P11SinglePasswordRetriever { private final Set slots; - private final List passwords; + private final String password; - private P11SinglePasswordRetriever(Set slots, List passwords) { + private P11SinglePasswordRetriever(Set slots, String password) { this.slots = slots; - this.passwords = CollectionUtil.isEmpty(passwords) ? null : passwords; + this.password = password; } public boolean match(P11SlotId slot) { @@ -206,17 +85,12 @@ public boolean match(P11SlotId slot) { return false; } - public List getPasswords() throws PasswordResolverException { - if (passwords == null) { + public char[] getPassword() throws PasswordResolverException { + if (password == null) { return null; } - List ret = new ArrayList<>(passwords.size()); - for (String password : passwords) { - ret.add(Passwords.resolvePassword(password)); - } - - return ret; + return Passwords.resolvePassword(password); } } // class P11PasswordsRetriever @@ -227,11 +101,11 @@ public List getPasswords() throws PasswordResolverException { singleRetrievers = new LinkedList<>(); } - void addPasswordEntry(Set slots, List passwords) { - singleRetrievers.add(new P11SinglePasswordRetriever(slots, passwords)); + void addPasswordEntry(Set slots, String password) { + singleRetrievers.add(new P11SinglePasswordRetriever(slots, password)); } - public List getPassword(P11SlotId slotId) throws PasswordResolverException { + public char[] getPassword(P11SlotId slotId) throws PasswordResolverException { Args.notNull(slotId, "slotId"); if (CollectionUtil.isEmpty(singleRetrievers)) { return null; @@ -239,7 +113,7 @@ public List getPassword(P11SlotId slotId) throws PasswordResolverExcepti for (P11SinglePasswordRetriever sr : singleRetrievers) { if (sr.match(slotId)) { - return sr.getPasswords(); + return sr.getPassword(); } } @@ -285,8 +159,6 @@ public void setIdLength(int idLength) { private static final Logger LOG = LoggerFactory.getLogger(P11ModuleConf.class); - private final String name; - private final String type; private final String nativeLibrary; @@ -299,14 +171,10 @@ public void setIdLength(int idLength) { private final P11PasswordsRetriever passwordRetriever; - private final P11MechanismFilter mechanismFilter; - private final Integer newSessionTimeout; private final String userType; - private final char[] userName; - private boolean readOnly; private int maxMessageSize; @@ -319,25 +187,22 @@ public void setIdLength(int idLength) { private List keyPairTypes; - public P11ModuleConf( - Pkcs11conf.Module moduleType, List mechanismSets) + public P11ModuleConf(Pkcs11conf conf) throws InvalidConfException { - this.name = Args.notNull(moduleType, "moduleType").getName(); - this.readOnly = moduleType.isReadonly(); + this.readOnly = conf.isReadonly(); - this.userType = moduleType.getUser().toUpperCase(); - this.userName = (moduleType.getUserName() == null) ? null : moduleType.getUserName().toCharArray(); + this.userType = conf.getUser().toUpperCase(); - this.maxMessageSize = moduleType.getMaxMessageSize(); - this.type = moduleType.getType(); + this.maxMessageSize = conf.getMaxMessageSize(); + this.type = conf.getType(); if (maxMessageSize < 256) { throw new InvalidConfException("invalid maxMessageSize (< 256): " + maxMessageSize); } - this.numSessions = moduleType.getNumSessions(); - this.newSessionTimeout = moduleType.getNewSessionTimeout(); + this.numSessions = conf.getNumSessions(); + this.newSessionTimeout = conf.getNewSessionTimeout(); - List list = moduleType.getSecretKeyTypes(); + List list = conf.getSecretKeyTypes(); if (list == null) { this.secretKeyTypes = null; } else { @@ -351,7 +216,7 @@ public P11ModuleConf( this.secretKeyTypes = Collections.unmodifiableList(ll); } - list = moduleType.getKeyPairTypes(); + list = conf.getKeyPairTypes(); if (list == null) { this.keyPairTypes = null; } else { @@ -365,83 +230,34 @@ public P11ModuleConf( this.keyPairTypes = Collections.unmodifiableList(ll); } - Map mechanismSetsMap = new HashMap<>(); - // parse mechanismSets - if (mechanismSets != null) { - for (Pkcs11conf.MechanismSet m : mechanismSets) { - String name = m.getName(); - if (mechanismSetsMap.containsKey(name)) { - throw new InvalidConfException("Duplication mechanismSets named " + name); - } - - MechanismSet mechanismSet = new MechanismSet(); - mechanismSet.includeMechanisms = new HashSet<>(); - mechanismSet.excludeMechanisms = new HashSet<>(); - - for (String mechStr : m.getMechanisms()) { - mechStr = mechStr.trim().toUpperCase(); - if (mechStr.equals("ALL")) { - mechanismSet.includeMechanisms = null; // accept all mechanisms - break; - } - - mechanismSet.includeMechanisms.add(mechStr); - } - - for (String mechStr : m.getExcludeMechanisms()) { - mechanismSet.excludeMechanisms.add(mechStr.trim().toUpperCase()); - } - - mechanismSetsMap.put(name, mechanismSet); - } - } - - // Mechanism filter - mechanismFilter = new P11MechanismFilter(); - - List mechFilters = moduleType.getMechanismFilters(); - if (CollectionUtil.isNotEmpty(mechFilters)) { - for (Pkcs11conf.MechanismFilter filterType : mechFilters) { - Set slots = getSlotIdFilters(filterType.getSlots()); - String mechanismSetName = filterType.getMechanismSet(); - - MechanismSet mechanismSet = mechanismSetsMap.get(mechanismSetName); - if (mechanismSet == null) { - throw new InvalidConfException("MechanismSet '" + mechanismSetName + "' is not defined"); - } else { - mechanismFilter.addEntry(slots, mechanismSet.includeMechanisms, mechanismSet.excludeMechanisms); - } - } - } - // Password retriever passwordRetriever = new P11PasswordsRetriever(); - List passwordsList = moduleType.getPasswordSets(); + List passwordsList = conf.getPasswordSets(); if (CollectionUtil.isNotEmpty(passwordsList)) { for (Pkcs11conf.PasswordSet passwordType : passwordsList) { Set slots = getSlotIdFilters(passwordType.getSlots()); - passwordRetriever.addPasswordEntry(slots, new ArrayList<>(passwordType.getPasswords())); + passwordRetriever.addPasswordEntry(slots, passwordType.getPassword()); } } - includeSlots = getSlotIdFilters(moduleType.getIncludeSlots()); - excludeSlots = getSlotIdFilters(moduleType.getExcludeSlots()); + includeSlots = getSlotIdFilters(conf.getIncludeSlots()); + excludeSlots = getSlotIdFilters(conf.getExcludeSlots()); final String osName = System.getProperty("os.name").toLowerCase(); - Pkcs11conf.NativeLibrary matchLibrary = getNativeLibrary(moduleType, osName); + Pkcs11conf.NativeLibrary matchLibrary = getNativeLibrary(conf, osName); this.nativeLibrary = matchLibrary.getPath(); this.nativeLibraryProperties = matchLibrary.getProperties(); - this.newObjectConf = (moduleType.getNewObjectConf() == null) ? new P11NewObjectConf() - : new P11NewObjectConf(moduleType.getNewObjectConf()); + this.newObjectConf = (conf.getNewObjectConf() == null) ? new P11NewObjectConf() + : new P11NewObjectConf(conf.getNewObjectConf()); } // constructor - private static Pkcs11conf.NativeLibrary getNativeLibrary(Pkcs11conf.Module moduleType, String osName) + private static Pkcs11conf.NativeLibrary getNativeLibrary(Pkcs11conf conf, String osName) throws InvalidConfException { Pkcs11conf.NativeLibrary matchLibrary = null; - for (Pkcs11conf.NativeLibrary library : moduleType.getNativeLibraries()) { + for (Pkcs11conf.NativeLibrary library : conf.getNativeLibraries()) { List osNames = library.getOperationSystems(); if (CollectionUtil.isEmpty(osNames)) { matchLibrary = library; @@ -461,10 +277,6 @@ private static Pkcs11conf.NativeLibrary getNativeLibrary(Pkcs11conf.Module modul return matchLibrary; } - public String getName() { - return name; - } - public String getType() { return type; } @@ -505,10 +317,6 @@ public String getUserType() { return userType; } - public char[] getUserName() { - return userName; - } - public P11PasswordsRetriever getPasswordRetriever() { return passwordRetriever; } @@ -573,15 +381,12 @@ public boolean isSlotIncluded(P11SlotId slotId) { return true; } // method isSlotIncluded - public P11MechanismFilter getP11MechanismFilter() { - return mechanismFilter; - } - public P11NewObjectConf getP11NewObjectConf() { return newObjectConf; } - private static Set getSlotIdFilters(List slotTypes) throws InvalidConfException { + private static Set getSlotIdFilters(List slotTypes) + throws InvalidConfException { if (CollectionUtil.isEmpty(slotTypes)) { return null; } diff --git a/security/src/main/java/org/xipki/security/pkcs11/P11SignerFactory.java b/security/src/main/java/org/xipki/security/pkcs11/P11SignerFactory.java index 00c3fc4..e607a91 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/P11SignerFactory.java +++ b/security/src/main/java/org/xipki/security/pkcs11/P11SignerFactory.java @@ -88,7 +88,6 @@ public ConcurrentContentSigner newSigner(String type, SignerConf conf, X509Cert[ } } - String moduleName = conf.getConfValue("module"); str = conf.getConfValue("slot"); Integer slotIndex = (str == null) ? null : Integer.parseInt(str); @@ -112,7 +111,7 @@ public ConcurrentContentSigner newSigner(String type, SignerConf conf, X509Cert[ P11Slot slot; try { - P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(moduleName); + P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(); P11Module module = p11Service.getModule(); P11SlotId p11SlotId = (slotId != null) ? module.getSlotIdForId(slotId) : module.getSlotIdForIndex(slotIndex); diff --git a/security/src/main/java/org/xipki/security/pkcs11/P11Slot.java b/security/src/main/java/org/xipki/security/pkcs11/P11Slot.java index b4cda56..ae2e2f7 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/P11Slot.java +++ b/security/src/main/java/org/xipki/security/pkcs11/P11Slot.java @@ -14,7 +14,6 @@ import org.xipki.pkcs11.wrapper.TokenException; import org.xipki.pkcs11.wrapper.params.ExtraParams; import org.xipki.security.EdECConstants; -import org.xipki.security.pkcs11.P11ModuleConf.P11MechanismFilter; import org.xipki.security.pkcs11.P11ModuleConf.P11NewObjectConf; import org.xipki.security.util.DSAParameterCache; import org.xipki.util.Args; @@ -139,8 +138,6 @@ public void setUsages(Set usages) { private static final Logger LOG = LoggerFactory.getLogger(P11Slot.class); - protected final String moduleName; - protected final P11SlotId slotId; private final boolean readOnly; @@ -155,10 +152,9 @@ public void setUsages(Set usages) { protected final P11NewObjectConf newObjectConf; protected P11Slot( - String moduleName, P11SlotId slotId, boolean readOnly, + P11SlotId slotId, boolean readOnly, List secretKeyTypes, List keyPairTypes, P11NewObjectConf newObjectConf) { this.newObjectConf = Args.notNull(newObjectConf, "newObjectConf"); - this.moduleName = Args.notBlank(moduleName, "moduleName"); this.slotId = Args.notNull(slotId, "slotId"); this.readOnly = readOnly; this.secretKeyTypes = secretKeyTypes; @@ -381,25 +377,19 @@ protected PKCS11Module getPKCS11Module() { @Override public abstract void close(); - protected void initMechanisms(Map supportedMechanisms, P11MechanismFilter mechanismFilter) { + protected void initMechanisms(Map supportedMechanisms) { mechanisms.clear(); - List ignoreMechs = new ArrayList<>(); PKCS11Module pkcs11Module = getPKCS11Module(); for (Map.Entry entry : supportedMechanisms.entrySet()) { long mech = entry.getKey(); - if (mechanismFilter.isMechanismPermitted(slotId, mech, pkcs11Module)) { - mechanisms.put(mech, entry.getValue()); - } else { - ignoreMechs.add(mech); - } + mechanisms.put(mech, entry.getValue()); } - Collections.sort(ignoreMechs); if (LOG.isInfoEnabled()) { StringBuilder sb = new StringBuilder(); - sb.append("initialized module ").append(moduleName).append(", slot ").append(slotId); + sb.append("initialized slot ").append(slotId); sb.append("\nsupported mechanisms:\n"); if (mechanisms.isEmpty()) { @@ -408,14 +398,6 @@ protected void initMechanisms(Map supportedMechanisms, P11M printMechanisms(sb, mechanisms); } - sb.append("\nsupported by device but ignored mechanisms:\n"); - if (ignoreMechs.isEmpty()) { - sb.append(" NONE\n"); - } else { - for (Long mech : ignoreMechs) { - sb.append("\n ").append(mechanismCodeToName(mech)); - } - } LOG.info(sb.toString()); } } @@ -446,10 +428,6 @@ public void assertMechanismSupported(long mechanism, long flagBit) throws TokenE } } - public String getModuleName() { - return moduleName; - } - public P11SlotId getSlotId() { return slotId; } diff --git a/security/src/main/java/org/xipki/security/pkcs11/Pkcs11conf.java b/security/src/main/java/org/xipki/security/pkcs11/Pkcs11conf.java index 27cdc82..3bd910b 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/Pkcs11conf.java +++ b/security/src/main/java/org/xipki/security/pkcs11/Pkcs11conf.java @@ -19,306 +19,175 @@ public class Pkcs11conf extends ValidableConf { - public static class MechanismFilter extends ValidableConf { + private String type; - /** - * name of the mechanismSet. - */ - private String mechanismSet; - - /** - * To which slots the mechanism should be applied. - * Absent for all slots. - */ - private List slots; - - public String getMechanismSet() { - return mechanismSet; - } - - public void setMechanismSet(String mechanismSet) { - this.mechanismSet = mechanismSet; - } - - public List getSlots() { - if (slots == null) { - slots = new LinkedList<>(); - } - return slots; - } - - public void setSlots(List slots) { - this.slots = slots; - } - - @Override - public void validate() throws InvalidConfException { - notBlank(mechanismSet, "mechanismSet"); - validate(slots); - } - - } // class MechanismFilter - - public static class MechanismSet extends ValidableConf { - - private String name; - - /** - * The mechanism. Set mechanism to ALL to accept all available mechanisms. - */ - private List mechanisms; - - /** - * The mechanism to be excluded. - */ - private List excludeMechanisms; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public List getMechanisms() { - if (mechanisms == null) { - mechanisms = new LinkedList<>(); - } - return mechanisms; - } - - public void setMechanisms(List mechanisms) { - this.mechanisms = mechanisms; - } - - public List getExcludeMechanisms() { - if (excludeMechanisms == null) { - excludeMechanisms = new LinkedList<>(); - } - return excludeMechanisms; - } - - public void setExcludeMechanisms(List excludeMechanisms) { - this.excludeMechanisms = excludeMechanisms; - } - - @Override - public void validate() throws InvalidConfException { - notBlank(name, "name"); - notEmpty(mechanisms, "mechanisms"); - } - - } // class MechanismSet - - public static class Module extends ValidableConf { - - private String name; - - private String type; - - private List nativeLibraries; - - private NewObjectConf newObjectConf; - - /** - * Which slots should be considered. Absent for all slots. - */ - private List includeSlots; - - /** - * Which slots should be considered. Absent for no slot. - */ - private List excludeSlots; - - private boolean readonly; - - private List secretKeyTypes; + private List nativeLibraries; - private List keyPairTypes; + private NewObjectConf newObjectConf; - private Integer numSessions; - - /** - * specify the user type, use either the long value or identifier as - * defined in the PKCS#11 standards. In version up to 2.40 the - * following users are defined. - * - 0 or 0x0 or CKU_SO - * - 1 or 0x1 or CKU_USER - * - 2 or 0x2 or CKU_CONTEXT_SPECIFIC - * For vendor user type, only the long value is allowed. - */ - private String user; - - private String userName; - - /** - * maximal size of the message sent to the PKCS#11 device. - */ - private Integer maxMessageSize; - - /** - * Timeout to borrow a new session. - */ - private Integer newSessionTimeout; - - private List passwordSets; + /** + * Which slots should be considered. Absent for all slots. + */ + private List includeSlots; - private List mechanismFilters; + /** + * Which slots should be considered. Absent for no slot. + */ + private List excludeSlots; - public String getName() { - return name; - } + private boolean readonly; - public void setName(String name) { - this.name = name; - } + private List secretKeyTypes; - public String getType() { - return type; - } + private List keyPairTypes; - public void setType(String type) { - this.type = type; - } + private Integer numSessions; - public List getNativeLibraries() { - if (nativeLibraries == null) { - nativeLibraries = new LinkedList<>(); - } - return nativeLibraries; - } + /** + * specify the user type, use either the long value or identifier as + * defined in the PKCS#11 standards. In version up to 2.40 the + * following users are defined. + * - 0 or 0x0 or CKU_SO + * - 1 or 0x1 or CKU_USER + * - 2 or 0x2 or CKU_CONTEXT_SPECIFIC + * For vendor user type, only the long value is allowed. + */ + private String user; - public void setNativeLibraries(List nativeLibraries) { - this.nativeLibraries = nativeLibraries; - } + /** + * maximal size of the message sent to the PKCS#11 device. + */ + private Integer maxMessageSize; - public NewObjectConf getNewObjectConf() { - return newObjectConf; - } + /** + * Timeout to borrow a new session. + */ + private Integer newSessionTimeout; - public void setNewObjectConf(NewObjectConf newObjectConf) { - this.newObjectConf = newObjectConf; - } + private List passwordSets; - public List getIncludeSlots() { - if (includeSlots == null) { - includeSlots = new LinkedList<>(); - } - return includeSlots; - } + public String getType() { + return type; + } - public void setIncludeSlots(List includeSlots) { - this.includeSlots = includeSlots; - } + public void setType(String type) { + this.type = type; + } - public List getExcludeSlots() { - if (excludeSlots == null) { - excludeSlots = new LinkedList<>(); - } - return excludeSlots; + public List getNativeLibraries() { + if (nativeLibraries == null) { + nativeLibraries = new LinkedList<>(); } + return nativeLibraries; + } - public void setExcludeSlots(List excludeSlots) { - this.excludeSlots = excludeSlots; - } + public void setNativeLibraries(List nativeLibraries) { + this.nativeLibraries = nativeLibraries; + } - public boolean isReadonly() { - return readonly; - } + public NewObjectConf getNewObjectConf() { + return newObjectConf; + } - public void setReadonly(boolean readonly) { - this.readonly = readonly; - } + public void setNewObjectConf(NewObjectConf newObjectConf) { + this.newObjectConf = newObjectConf; + } - public List getPasswordSets() { - if (passwordSets == null) { - passwordSets = new LinkedList<>(); - } - return passwordSets; + public List getIncludeSlots() { + if (includeSlots == null) { + includeSlots = new LinkedList<>(); } + return includeSlots; + } - public void setPasswordSets(List passwordSets) { - this.passwordSets = passwordSets; - } + public void setIncludeSlots(List includeSlots) { + this.includeSlots = includeSlots; + } - public List getMechanismFilters() { - if (mechanismFilters == null) { - mechanismFilters = new LinkedList<>(); - } - return mechanismFilters; + public List getExcludeSlots() { + if (excludeSlots == null) { + excludeSlots = new LinkedList<>(); } + return excludeSlots; + } - public void setMechanismFilters(List mechanismFilters) { - this.mechanismFilters = mechanismFilters; - } + public void setExcludeSlots(List excludeSlots) { + this.excludeSlots = excludeSlots; + } - public void setUser(String user) { - this.user = user; - } + public boolean isReadonly() { + return readonly; + } - public void setUserName(String userName) { - this.userName = userName; - } + public void setReadonly(boolean readonly) { + this.readonly = readonly; + } - public void setMaxMessageSize(Integer maxMessageSize) { - this.maxMessageSize = maxMessageSize; + public List getPasswordSets() { + if (passwordSets == null) { + passwordSets = new LinkedList<>(); } + return passwordSets; + } - public String getUser() { - return user == null ? "CKU_USER" : user; - } + public void setPasswordSets(List passwordSets) { + this.passwordSets = passwordSets; + } - public String getUserName() { - return userName; - } + public void setUser(String user) { + this.user = user; + } - public int getMaxMessageSize() { - return maxMessageSize == null ? 16384 : maxMessageSize; - } + public void setMaxMessageSize(Integer maxMessageSize) { + this.maxMessageSize = maxMessageSize; + } - public List getSecretKeyTypes() { - return secretKeyTypes; - } + public String getUser() { + return user == null ? "CKU_USER" : user; + } - public void setSecretKeyTypes(List secretKeyTypes) { - this.secretKeyTypes = secretKeyTypes; - } + public int getMaxMessageSize() { + return maxMessageSize == null ? 16384 : maxMessageSize; + } - public List getKeyPairTypes() { - return keyPairTypes; - } + public List getSecretKeyTypes() { + return secretKeyTypes; + } - public void setKeyPairTypes(List keyPairTypes) { - this.keyPairTypes = keyPairTypes; - } + public void setSecretKeyTypes(List secretKeyTypes) { + this.secretKeyTypes = secretKeyTypes; + } - public Integer getNumSessions() { - return numSessions; - } + public List getKeyPairTypes() { + return keyPairTypes; + } - public void setNumSessions(Integer numSessions) { - this.numSessions = numSessions; - } + public void setKeyPairTypes(List keyPairTypes) { + this.keyPairTypes = keyPairTypes; + } - public Integer getNewSessionTimeout() { - return newSessionTimeout; - } + public Integer getNumSessions() { + return numSessions; + } - public void setNewSessionTimeout(Integer newSessionTimeout) { - this.newSessionTimeout = newSessionTimeout; - } + public void setNumSessions(Integer numSessions) { + this.numSessions = numSessions; + } - @Override - public void validate() throws InvalidConfException { - notBlank(name, "name"); - notBlank(type, "type"); - notEmpty(nativeLibraries, "nativeLibraries"); + public Integer getNewSessionTimeout() { + return newSessionTimeout; + } - validate(nativeLibraries, includeSlots, excludeSlots, passwordSets, mechanismFilters); - } + public void setNewSessionTimeout(Integer newSessionTimeout) { + this.newSessionTimeout = newSessionTimeout; + } - } // class Module + @Override + public void validate() throws InvalidConfException { + notBlank(type, "type"); + notEmpty(nativeLibraries, "nativeLibraries"); + validate(nativeLibraries, includeSlots, excludeSlots, passwordSets); + } public static class NativeLibrary extends ValidableConf { @@ -397,7 +266,7 @@ public static class PasswordSet extends ValidableConf { private List slots; - private List passwords; + private String password; public List getSlots() { if (slots == null) { @@ -410,20 +279,16 @@ public void setSlots(List slots) { this.slots = slots; } - public List getPasswords() { - if (passwords == null) { - passwords = new LinkedList<>(); - } - return passwords; + public String getPassword() { + return password; } - public void setPasswords(List passwords) { - this.passwords = passwords; + public void setPassword(String password) { + this.password = password; } @Override public void validate() throws InvalidConfException { - notEmpty(passwords, "passwords"); } } // class PasswordSet @@ -459,47 +324,4 @@ public void validate() throws InvalidConfException { } // class Slot - /** - * exactly one module must have the name 'default'. - */ - private List modules; - - private List mechanismSets; - - public List getModules() { - return modules; - } - - public void setModules(List modules) { - if (modules == null) { - modules = new LinkedList<>(); - } - this.modules = modules; - } - - public List getMechanismSets() { - if (mechanismSets == null) { - mechanismSets = new LinkedList<>(); - } - return mechanismSets; - } - - public void setMechanismSets(List mechanismSets) { - this.mechanismSets = mechanismSets; - } - - public void addModule(Module module) { - getModules().add(module); - } - - public void addMechanismSet(MechanismSet mechanismSet) { - getMechanismSets().add(mechanismSet); - } - - @Override - public void validate() throws InvalidConfException { - notEmpty(modules, "modules"); - validate(modules, mechanismSets); - } - } diff --git a/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Module.java b/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Module.java index 34f7b62..19f32e7 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Module.java +++ b/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Module.java @@ -141,7 +141,7 @@ private EmulatorP11Module(P11ModuleConf moduleConf) throws TokenException { Set slots = new HashSet<>(); for (P11SlotId slotId : slotIds) { - List pwd; + char[] pwd; try { pwd = moduleConf.getPasswordRetriever().getPassword(slotId); } catch (PasswordResolverException ex) { @@ -154,14 +154,8 @@ private EmulatorP11Module(P11ModuleConf moduleConf) throws TokenException { throw new TokenException("no password is configured"); } - if (pwd.size() != 1) { - throw new TokenException(pwd.size() + " passwords are configured, but 1 is permitted"); - } - - char[] firstPwd = pwd.get(0); - - slots.add(new EmulatorP11Slot(moduleConf.getName(), slotDir, slotId, - moduleConf.isReadOnly(), new EmulatorKeyCryptor(firstPwd), moduleConf.getP11MechanismFilter(), + slots.add(new EmulatorP11Slot(slotDir, slotId, + moduleConf.isReadOnly(), new EmulatorKeyCryptor(pwd), moduleConf.getP11NewObjectConf(), moduleConf.getNumSessions(), moduleConf.getSecretKeyTypes(), moduleConf.getKeyPairTypes())); } @@ -180,7 +174,7 @@ public String getDescription() { @Override public void close() { - LOG.info("close PKCS#11 module: {}", getName()); + LOG.info("close PKCS#11 module"); } private void createExampleRepository(File dir) throws IOException { diff --git a/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Slot.java b/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Slot.java index df7ba33..46ae4c9 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Slot.java +++ b/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Slot.java @@ -32,7 +32,6 @@ import org.xipki.security.EdECConstants; import org.xipki.security.HashAlgo; import org.xipki.security.pkcs11.P11Key; -import org.xipki.security.pkcs11.P11ModuleConf.P11MechanismFilter; import org.xipki.security.pkcs11.P11ModuleConf.P11NewObjectConf; import org.xipki.security.pkcs11.P11Params; import org.xipki.security.pkcs11.P11Slot; @@ -222,11 +221,11 @@ public boolean accept(File dir, String name) { } EmulatorP11Slot( - String moduleName, File slotDir, P11SlotId slotId, boolean readOnly, - EmulatorKeyCryptor keyCryptor, P11MechanismFilter mechanismFilter, P11NewObjectConf newObjectConf, + File slotDir, P11SlotId slotId, boolean readOnly, + EmulatorKeyCryptor keyCryptor, P11NewObjectConf newObjectConf, Integer numSessions, List secretKeyTypes, List keypairTypes) throws TokenException { - super(moduleName, slotId, readOnly, secretKeyTypes, keypairTypes, newObjectConf); + super(slotId, readOnly, secretKeyTypes, keypairTypes, newObjectConf); this.keyCryptor = Args.notNull(keyCryptor, "keyCryptor"); this.maxSessions = numSessions == null ? 20 : Args.positive(numSessions, "numSessions"); @@ -250,7 +249,7 @@ public boolean accept(File dir, String name) { this.namedCurveSupported = true; } - initMechanisms(supportedMechs, mechanismFilter); + initMechanisms(supportedMechs); } // constructor private List getFilesForLabel(File dir, String label) throws TokenException { diff --git a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Key.java b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Key.java deleted file mode 100644 index 80749a4..0000000 --- a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Key.java +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2013-2024 xipki. All rights reserved. -// License Apache License 2.0 - -package org.xipki.security.pkcs11.hsmproxy; - -import org.xipki.pkcs11.wrapper.PKCS11KeyId; -import org.xipki.pkcs11.wrapper.TokenException; -import org.xipki.pkcs11.wrapper.params.ExtraParams; -import org.xipki.security.pkcs11.P11Key; -import org.xipki.security.pkcs11.P11Params; -import org.xipki.security.util.KeyUtil; -import org.xipki.util.Args; - -import java.security.PublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.RSAPublicKeySpec; - -import static org.xipki.pkcs11.wrapper.PKCS11Constants.CKK_RSA; - -/** - * {@link P11Key} based on the HSM proxy. - * - * @author Lijun Liao (xipki) - */ - -class HsmProxyP11Key extends P11Key { - - public HsmProxyP11Key(HsmProxyP11Slot slot, PKCS11KeyId keyId) { - super(slot, keyId); - } - - @Override - protected byte[] digestSecretKey0(long mechanism) throws TokenException { - return slot.digestSecretKey(mechanism, keyId.getHandle()); - } - - @Override - protected PublicKey getPublicKey0() throws TokenException { - long keyType = keyId.getKeyType(); - if (keyType == CKK_RSA) { - try { - return KeyUtil.generateRSAPublicKey( - new RSAPublicKeySpec(rsaModulus, rsaPublicExponent)); - } catch (InvalidKeySpecException ex) { - throw new TokenException(ex.getMessage(), ex); - } - } - - Long publicKeyHandle = keyId.getPublicKeyHandle(); - return (publicKeyHandle == null) ? null : slot.getPublicKey(publicKeyHandle); - } - - @Override - public void destroy() throws TokenException { - long[] failedHandles; - if (keyId.getPublicKeyHandle() == null) { - failedHandles = slot.destroyObjectsByHandle(keyId.getHandle()); - } else { - failedHandles = slot.destroyObjectsByHandle(keyId.getHandle(), keyId.getPublicKeyHandle()); - } - if (failedHandles != null && failedHandles.length > 0) { - throw new TokenException("error destroying key " + keyId); - } - } - - @Override - protected byte[] sign0(long mechanism, P11Params parameters, byte[] content) throws TokenException { - Args.notNull(content, "content"); - ExtraParams extraParams = null; - if (ecOrderBitSize != null) { - extraParams = new ExtraParams(); - extraParams.ecOrderBitSize(ecOrderBitSize); - } - - return slot.sign(mechanism, parameters, extraParams, keyId.getHandle(), content); - } - -} diff --git a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Module.java b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Module.java deleted file mode 100644 index be128f5..0000000 --- a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Module.java +++ /dev/null @@ -1,428 +0,0 @@ -// Copyright (c) 2013-2024 xipki. All rights reserved. -// License Apache License 2.0 - -package org.xipki.security.pkcs11.hsmproxy; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xipki.pkcs11.wrapper.PKCS11Constants; -import org.xipki.pkcs11.wrapper.PKCS11Exception; -import org.xipki.pkcs11.wrapper.TokenException; -import org.xipki.security.pkcs11.P11Module; -import org.xipki.security.pkcs11.P11ModuleConf; -import org.xipki.security.pkcs11.P11Slot; -import org.xipki.security.pkcs11.P11SlotId; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.BooleanMessage; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.ByteArrayMessage; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.ErrorResponse; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GetMechanismInfosResponse; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.IntMessage; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.KeyIdMessage; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.LongArrayMessage; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.ModuleCapsResponse; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.P11KeyResponse; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.SlotIdsResponse; -import org.xipki.util.Args; -import org.xipki.util.FileOrBinary; -import org.xipki.util.IoUtil; -import org.xipki.util.LogUtil; -import org.xipki.util.StringUtil; -import org.xipki.util.cbor.ByteArrayCborDecoder; -import org.xipki.util.cbor.CborConstants; -import org.xipki.util.cbor.CborDecoder; -import org.xipki.util.cbor.CborType; -import org.xipki.util.exception.DecodeException; -import org.xipki.util.exception.ObjectCreationException; -import org.xipki.util.http.HostnameVerifiers; -import org.xipki.util.http.SslConf; -import org.xipki.util.http.SslContextConf; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSocketFactory; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; - -/** - * {@link P11Module} for PKCS#11 proxy. - * - * @author Lijun Liao (xipki) - */ - -class HsmProxyP11Module extends P11Module { - - public static final String TYPE = "hsmproxy"; - - private static final String PROP_SSL_STORETYPE = "ssl.storeType"; - - private static final String PROP_SSL_KEYSTORE = "ssl.keystore"; - - private static final String PROP_SSL_KEYSTOREPASSWORD = "ssl.keystorePassword"; - - private static final String PROP_SSL_TRUSTCERTS = "ssl.trustcerts"; - - private static final String PROP_SSL_HOStNAMEVERIFIER = "ssl.hostnameVerifier"; - - private static final Logger LOG = LoggerFactory.getLogger(HsmProxyP11Module.class); - - private static final String REQUEST_MIMETYPE = "application/x-xipki-pkcs11"; - - private static final String RESPONSE_MIMETYPE = "application/x-xipki-pkcs11"; - - private static final byte[] SLOT_ID_NULL_CONTENT_NULL_REQUEST = new byte[]{(byte) 0x82, (byte) 0xf6, (byte) 0xf6}; - - private final String description; - - private final String serverUrl; - - private final SSLSocketFactory sslSocketFactory; - - private final HostnameVerifier hostnameVerifier; - - private HsmProxyP11Module(P11ModuleConf moduleConf) throws TokenException { - super(moduleConf); - - final String modulePath = moduleConf.getNativeLibrary(); - - Map properties = moduleConf.getNativeLibraryProperties(); - if (properties == null) { - throw new TokenException("The properties field is not present"); - } - this.description = StringUtil.concat("PKCS#11 proxy", "\nPath: ", modulePath); - this.serverUrl = modulePath.endsWith("/") ? modulePath.substring(0, modulePath.length() - 1) : modulePath; - - SslConf sslConf = new SslConf(); - - String sslStoreType = properties.get(PROP_SSL_STORETYPE); - sslConf.setStoreType(sslStoreType); - - String sslKeystore = properties.get(PROP_SSL_KEYSTORE); - sslConf.setKeystore(FileOrBinary.ofFile(sslKeystore)); - - String sslKeystorePassword = properties.get(PROP_SSL_KEYSTOREPASSWORD); - sslConf.setKeystorePassword(sslKeystorePassword); - - String sslTrustCerts = properties.get(PROP_SSL_TRUSTCERTS); - if (sslTrustCerts != null) { - StringTokenizer tokens = new StringTokenizer(sslTrustCerts, ",;:"); - List files = new ArrayList<>(tokens.countTokens()); - while (tokens.hasMoreTokens()) { - String file = tokens.nextToken().trim(); - files.add(FileOrBinary.ofFile(file)); - } - sslConf.setTrustanchors(files.toArray(new FileOrBinary[0])); - } - - String sslHostnameVerifier = properties.get(PROP_SSL_HOStNAMEVERIFIER); - if (sslHostnameVerifier != null) { - sslConf.setHostnameVerifier(sslHostnameVerifier); - } - - SslContextConf sslContextConf = SslContextConf.ofSslConf(sslConf); - - try { - this.sslSocketFactory = sslContextConf.getSslSocketFactory(); - } catch (ObjectCreationException ex) { - throw new TokenException("could not build SSLSocketFactroy", ex); - } - try { - this.hostnameVerifier = HostnameVerifiers.createHostnameVerifier(sslHostnameVerifier); - } catch (ObjectCreationException ex) { - throw new TokenException("could not create HostnameVerifier", ex); - } - - ModuleCapsResponse moduleCaps = - (ModuleCapsResponse) sendModuleAction(ProxyAction.moduleCaps); - if (!moduleConf.isReadOnly()) { - moduleConf.setReadOnly(moduleCaps.isReadOnly()); - } - - if (moduleConf.getMaxMessageSize() > moduleCaps.getMaxMessageSize()) { - moduleConf.setMaxMessageSize(moduleCaps.getMaxMessageSize()); - } - - if (moduleCaps.getNewObjectConf() != null) { - moduleConf.setNewObjectConf(moduleCaps.getNewObjectConf()); - } - - if (moduleCaps.getSecretKeyTypes() != null) { - moduleConf.setSecretKeyTypes( - intersect(moduleConf.getSecretKeyTypes(), moduleCaps.getSecretKeyTypes())); - } - - if (moduleCaps.getKeyPairTypes() != null) { - moduleConf.setKeyPairTypes( - intersect(moduleConf.getKeyPairTypes(), moduleCaps.getKeyPairTypes())); - } - - // initialize the slots - SlotIdsResponse resp = (SlotIdsResponse) sendModuleAction(ProxyAction.slotIds); - Set slots = new HashSet<>(); - for (P11SlotId slotId : resp.getSlotIds() ) { - if (!conf.isSlotIncluded(slotId)) { - continue; - } - - if (!conf.isSlotIncluded(slotId)) { - LOG.info("skipped slot {}", slotId); - continue; - } - - HsmProxyP11Slot slot = new HsmProxyP11Slot(slotId, moduleConf.isReadOnly(), this, - conf.getP11MechanismFilter(), moduleCaps.getNewObjectConf(), - moduleCaps.getSecretKeyTypes(), moduleCaps.getKeyPairTypes()); - slots.add(slot); - } - setSlots(slots); - } // constructor - - private static List intersect(List a, List b) { - if (a == null) { - return b; - } else if (b == null) { - return a; - } - - if (new HashSet<>(a).containsAll(b) && a.size() == b.size()) { - return a; - } - - List r = new ArrayList<>(Math.min(a.size(), b.size())); - for (T ta : a) { - if (b.contains(ta)) { - r.add(ta); - } - } - return r; - } - - public static P11Module getInstance(P11ModuleConf moduleConf) throws TokenException { - Args.notNull(moduleConf, "moduleConf"); - if (moduleConf.getUserName() != null) { - throw new TokenException("userName is present but shall be null"); - } - - return new HsmProxyP11Module(moduleConf); - } - - @Override - public String getDescription() { - return description; - } - - @Override - public void close() { - for (P11SlotId slotId : getSlotIds()) { - try { - getSlot(slotId).close(); - } catch (Throwable th) { - LogUtil.error(LOG, th, "could not close PKCS#11 slot " + slotId); - } - } - } - - protected byte[] doSend(ProxyAction action, byte[] request) throws IOException { - Args.notNull(request, "request"); - - String thisUrl = serverUrl + "/" + action.getAlias(); - - HttpURLConnection httpUrlConnection = IoUtil.openHttpConn(new URL(thisUrl)); - - if (httpUrlConnection instanceof HttpsURLConnection) { - if (sslSocketFactory != null) { - ((HttpsURLConnection) httpUrlConnection).setSSLSocketFactory(sslSocketFactory); - } - - if (hostnameVerifier != null) { - ((HttpsURLConnection) httpUrlConnection).setHostnameVerifier(hostnameVerifier); - } - } - - httpUrlConnection.setDoOutput(true); - httpUrlConnection.setUseCaches(false); - - int size = request.length; - - httpUrlConnection.setRequestMethod("POST"); - httpUrlConnection.setRequestProperty("Content-Type", REQUEST_MIMETYPE); - httpUrlConnection.setRequestProperty("Content-Length", Integer.toString(size)); - OutputStream outputstream = httpUrlConnection.getOutputStream(); - outputstream.write(request); - outputstream.flush(); - - if (httpUrlConnection.getResponseCode() != HttpURLConnection.HTTP_OK) { - try { - try { - InputStream is = httpUrlConnection.getInputStream(); - if (is != null) { - is.close(); - } - } catch (IOException ex) { - InputStream errStream = httpUrlConnection.getErrorStream(); - if (errStream != null) { - errStream.close(); - } - } - } catch (Throwable th) { - // ignore it - } - - throw new IOException("bad response: code=" + httpUrlConnection.getResponseCode() - + ", message=" + httpUrlConnection.getResponseMessage()); - } - - InputStream inputstream; - try { - inputstream = httpUrlConnection.getInputStream(); - } catch (IOException ex) { - InputStream errStream = httpUrlConnection.getErrorStream(); - if (errStream != null) { - errStream.close(); - } - throw ex; - } - - try { - String responseContentType = httpUrlConnection.getContentType(); - boolean isValidContentType = false; - if (responseContentType != null) { - if (responseContentType.equalsIgnoreCase(RESPONSE_MIMETYPE)) { - isValidContentType = true; - } - } - if (!isValidContentType) { - throw new IOException("bad response: mime type " + responseContentType - + " is not supported!"); - } - - byte[] buf = new byte[4096]; - ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(); - do { - int readedByte = inputstream.read(buf); - if (readedByte == -1) { - break; - } - bytearrayoutputstream.write(buf, 0, readedByte); - } while (true); - - return bytearrayoutputstream.toByteArray(); - } finally { - inputstream.close(); - } - } // method send - - public ProxyMessage sendModuleAction(ProxyAction action) throws TokenException { - return send(action, SLOT_ID_NULL_CONTENT_NULL_REQUEST.clone()); - } - - public ProxyMessage send(ProxyAction action, byte[] request) throws TokenException { - Args.notNull(request, "request"); - - byte[] respBytes; - try { - respBytes = doSend(action, request); - } catch (IOException ex) { - LOG.error("IO error", request); - throw new TokenException(ex.getMessage(), ex); - } - - CborDecoder decoder = new ByteArrayCborDecoder(respBytes); - ErrorResponse errorResp = null; - - try { - CborType type = decoder.peekType(); - if (CborDecoder.isNull(type)) { - decoder.readNull(); - return null; - } else if (type.getMajorType() == CborConstants.TYPE_TAG) { - long tag = decoder.readTag(); - if (ErrorResponse.CBOR_TAG_ERROR_RESPONSE != tag) { - throw new TokenException("response is tagged but not with tag CBOR_TAG_ERROR_RESPONSE"); - } - - errorResp = ErrorResponse.decode(decoder); - } - } catch (IOException ex) { - throw new TokenException("IO error decoding response", ex); - } catch (DecodeException ex) { - throw new TokenException("DecodeException decoding response", ex); - } - - if (errorResp != null) { - ErrorResponse.ProxyErrorCode errorCode = errorResp.getErrorCode(); - String detail = errorResp.getDetail(); - - switch (errorCode) { - case badRequest: - case internalError: - throw new TokenException(errorCode + ": " + detail); - case pkcs11Exception: - long ckrCode; - try { - ckrCode = detail.startsWith("CKR_") || detail.startsWith("ckr_") - ? PKCS11Constants.ckrNameToCode(detail) : Long.parseLong(detail); - } catch (Exception ex) { - LOG.warn("could not parse CKR code '" + detail + "'"); - ckrCode = PKCS11Constants.CKR_GENERAL_ERROR; - } - throw new PKCS11Exception(ckrCode); - case tokenException: - throw new TokenException(detail); - } - } - - try { - switch (action) { - case moduleCaps: - return ModuleCapsResponse.decode(decoder); - case slotIds: - return SlotIdsResponse.decode(decoder); - case mechInfos: - return GetMechanismInfosResponse.decode(decoder); - case keyByKeyId: - case keyByIdLabel: - return P11KeyResponse.decode(decoder); - case objectExistsByIdLabel: - return BooleanMessage.decode(decoder); - case destroyAllObjects: - case destroyObjectsByIdLabel: - return IntMessage.decode(decoder); - case destroyObjectsByHandle: - return LongArrayMessage.decode(decoder); - case keyIdByIdLabel: - case genSecretKey: - case importSecretKey: - case genRSAKeypair: - case genDSAKeypair2: - case genDSAKeypair: - case genECKeypair: - case genSM2Keypair: - return KeyIdMessage.decode(decoder); - case genRSAKeypairOtf: - case genDSAKeypairOtf: - case genECKeypairOtf: - case genSM2KeypairOtf: - case publicKeyByHandle: - case showDetails: - case sign: - case digestSecretKey: - return ByteArrayMessage.decode(decoder); - default: - throw new IllegalStateException("should not reach here, unknown action " + action); - } - } catch (DecodeException ex) { - throw new TokenException("DecodingException while decoding response.", ex); - } - } - -} diff --git a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11ModuleFactory.java b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11ModuleFactory.java deleted file mode 100644 index 5d6c593..0000000 --- a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11ModuleFactory.java +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2013-2024 xipki. All rights reserved. -// License Apache License 2.0 - -package org.xipki.security.pkcs11.hsmproxy; - -import org.xipki.pkcs11.wrapper.TokenException; -import org.xipki.security.pkcs11.P11Module; -import org.xipki.security.pkcs11.P11ModuleConf; -import org.xipki.security.pkcs11.P11ModuleFactory; -import org.xipki.util.XipkiBaseDir; - -/** - * {@link P11ModuleFactory} to create {@link P11Module} of type "hsmproxy". - * - * @author Lijun Liao (xipki) - * - */ -public class HsmProxyP11ModuleFactory implements P11ModuleFactory { - - public HsmProxyP11ModuleFactory() { - XipkiBaseDir.init(); - } - - @Override - public boolean canCreateModule(String type) { - return HsmProxyP11Module.TYPE.equalsIgnoreCase(type); - } - - @Override - public P11Module newModule(P11ModuleConf conf) throws TokenException { - return HsmProxyP11Module.getInstance(conf); - } - -} diff --git a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Slot.java b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Slot.java deleted file mode 100644 index 88409b0..0000000 --- a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Slot.java +++ /dev/null @@ -1,375 +0,0 @@ -// Copyright (c) 2013-2024 xipki. All rights reserved. -// License Apache License 2.0 - -package org.xipki.security.pkcs11.hsmproxy; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xipki.pkcs11.wrapper.MechanismInfo; -import org.xipki.pkcs11.wrapper.PKCS11KeyId; -import org.xipki.pkcs11.wrapper.TokenException; -import org.xipki.pkcs11.wrapper.params.ExtraParams; -import org.xipki.security.pkcs11.P11Key; -import org.xipki.security.pkcs11.P11ModuleConf.P11MechanismFilter; -import org.xipki.security.pkcs11.P11ModuleConf.P11NewObjectConf; -import org.xipki.security.pkcs11.P11Params; -import org.xipki.security.pkcs11.P11Slot; -import org.xipki.security.pkcs11.P11SlotId; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.BooleanMessage; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.ByteArrayMessage; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.DigestSecretKeyRequest; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateDSAKeyPairByKeysizeRequest; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateDSAKeyPairOtfRequest; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateDSAKeyPairRequest; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateECKeyPairOtfRequest; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateECKeyPairRequest; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateRSAKeyPairOtfRequest; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateRSAKeyPairRequest; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateSM2KeyPairRequest; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateSecretKeyRequest; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GetMechanismInfosResponse; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.IdLabelMessage; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.ImportSecretKeyRequest; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.IntMessage; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.KeyIdMessage; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.LongArrayMessage; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.LongMessage; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.P11KeyResponse; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.ShowDetailsRequest; -import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.SignRequest; -import org.xipki.security.util.KeyUtil; -import org.xipki.util.LogUtil; -import org.xipki.util.cbor.ByteArrayCborEncoder; -import org.xipki.util.exception.EncodeException; - -import java.io.IOException; -import java.io.OutputStream; -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; -import java.security.PublicKey; -import java.security.spec.InvalidKeySpecException; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * {@link P11Slot} based on the HSM proxy. - * - * @author Lijun Liao (xipki) - */ -class HsmProxyP11Slot extends P11Slot { - - private static final Logger LOG = LoggerFactory.getLogger(HsmProxyP11Slot.class); - - private final HsmProxyP11Module module; - - HsmProxyP11Slot(P11SlotId slotId, boolean readOnly, HsmProxyP11Module module, P11MechanismFilter mechanismFilter, - P11NewObjectConf newObjectConf, List secretKeyTypes, List keyPairTypes) - throws TokenException { - super(module.getName(), slotId, readOnly, secretKeyTypes, keyPairTypes, newObjectConf); - - this.module = module; - GetMechanismInfosResponse resp = (GetMechanismInfosResponse) send(ProxyAction.mechInfos, null); - Map mechanismInfoMap = resp == null ? Collections.emptyMap() : resp.getMechamismInfoMap(); - initMechanisms(mechanismInfoMap, mechanismFilter); - } - - @Override - public final void close() { - } - - @Override - public P11Key getKey(PKCS11KeyId keyId) throws TokenException { - return toP11Key(send(ProxyAction.keyByKeyId, new KeyIdMessage(keyId))); - } - - @Override - public P11Key getKey(byte[] keyId, String keyLabel) throws TokenException { - return toP11Key(send(ProxyAction.keyByIdLabel, new IdLabelMessage(keyId, keyLabel))); - } - - @Override - public PKCS11KeyId getKeyId(byte[] keyId, String keyLabel) throws TokenException { - return toPKCS11KeyId(send(ProxyAction.keyIdByIdLabel, new IdLabelMessage(keyId, keyLabel))); - } - - @Override - public byte[] sign(long mechanism, P11Params params, ExtraParams extraParams, - long keyHandle, byte[] content) throws TokenException { - SignRequest req = new SignRequest(keyHandle, mechanism, params, extraParams, content); - return toByteArray(send(ProxyAction.sign, req)); - } - - @Override - public PublicKey getPublicKey(long handle) throws TokenException { - byte[] bytes = toByteArray(send(ProxyAction.publicKeyByHandle, new LongMessage(handle))); - try { - return bytes == null ? null : KeyUtil.generatePublicKey( - SubjectPublicKeyInfo.getInstance(bytes)); - } catch (InvalidKeySpecException ex) { - throw new TokenException("error parsing SubjectPublicKeyInfo", ex); - } - } - - @Override - public byte[] digestSecretKey(long mechanism, long handle) throws TokenException { - DigestSecretKeyRequest req = new DigestSecretKeyRequest(mechanism, handle); - return toByteArray(send(ProxyAction.digestSecretKey, req)); - } - - @Override - public boolean objectExistsByIdLabel(byte[] id, String label) throws TokenException { - return ((BooleanMessage) send(ProxyAction.objectExistsByIdLabel, new IdLabelMessage(id, label))).getValue(); - } - - @Override - public int destroyAllObjects() { - try { - return ((IntMessage) send(ProxyAction.destroyAllObjects, null)).getValue(); - } catch (TokenException e) { - LogUtil.warn(LOG, e, "error destroyAllObjects()"); - return 0; - } - } - - @Override - public long[] destroyObjectsByHandle(long[] handles) { - try { - LongArrayMessage resp = ((LongArrayMessage) send( - ProxyAction.destroyObjectsByHandle, new LongArrayMessage(handles))); - return resp == null ? null : resp.getValue(); - } catch (Exception e) { - LogUtil.warn(LOG, e, "error destroyObjectsByHandle()"); - return handles.clone(); - } - } - - @Override - public int destroyObjectsByIdLabel(byte[] id, String label) throws TokenException { - try { - return ((IntMessage) send(ProxyAction.destroyObjectsByIdLabel, new IdLabelMessage(id, label))).getValue(); - } catch (TokenException e) { - LogUtil.warn(LOG, e, "error destroyAllObjects()"); - return 0; - } - } - - @Override - public PKCS11KeyId generateSecretKey(long keyType, Integer keysize, P11NewKeyControl control) - throws TokenException { - return toPKCS11KeyId(send(ProxyAction.genSecretKey, new GenerateSecretKeyRequest(keyType, keysize, control))); - } // method generateSecretKey0 - - @Override - public PKCS11KeyId importSecretKey(long keyType, byte[] keyValue, P11NewKeyControl control) throws TokenException { - return toPKCS11KeyId(send(ProxyAction.importSecretKey, new ImportSecretKeyRequest(keyType, keyValue, control))); - } // method importSecretKey0 - - @Override - public PKCS11KeyId generateRSAKeypair(int keysize, BigInteger publicExponent, P11NewKeyControl control) - throws TokenException { - return toPKCS11KeyId(send(ProxyAction.genRSAKeypair, - new GenerateRSAKeyPairRequest(keysize, publicExponent, control))); - } - - @Override - public PrivateKeyInfo generateRSAKeypairOtf(int keysize, BigInteger publicExponent) throws TokenException { - return toPrivateKeyInfo(send(ProxyAction.genRSAKeypairOtf, - new GenerateRSAKeyPairOtfRequest(keysize, publicExponent))); - } - - @Override - public PKCS11KeyId generateDSAKeypair(int plength, int qlength, P11NewKeyControl control) throws TokenException { - return toPKCS11KeyId(send(ProxyAction.genDSAKeypair2, - new GenerateDSAKeyPairByKeysizeRequest(plength, qlength, control))); - } - - @Override - public PKCS11KeyId generateDSAKeypair(BigInteger p, BigInteger q, BigInteger g, P11NewKeyControl control) - throws TokenException { - return toPKCS11KeyId(send(ProxyAction.genDSAKeypair, new GenerateDSAKeyPairRequest(p, q, g, control))); - } - - @Override - public PrivateKeyInfo generateDSAKeypairOtf(BigInteger p, BigInteger q, BigInteger g) throws TokenException { - return toPrivateKeyInfo(send(ProxyAction.genDSAKeypairOtf, new GenerateDSAKeyPairOtfRequest(p, q, g))); - } - - @Override - public PKCS11KeyId generateECKeypair(ASN1ObjectIdentifier curveId, P11NewKeyControl control) throws TokenException { - return toPKCS11KeyId(send(ProxyAction.genECKeypair, new GenerateECKeyPairRequest(curveId, control))); - } - - @Override - public PrivateKeyInfo generateECKeypairOtf(ASN1ObjectIdentifier curveId) throws TokenException { - return toPrivateKeyInfo(send(ProxyAction.genECKeypair, new GenerateECKeyPairOtfRequest(curveId))); - } - - @Override - public PKCS11KeyId generateSM2Keypair(P11NewKeyControl control) throws TokenException { - return toPKCS11KeyId(send(ProxyAction.genSM2Keypair, new GenerateSM2KeyPairRequest(control))); - } - - @Override - public PrivateKeyInfo generateSM2KeypairOtf() throws TokenException { - return toPrivateKeyInfo(send(ProxyAction.genSM2KeypairOtf, null)); - } - - private P11Key toP11Key(ProxyMessage response) throws TokenException { - if (response == null) { - return null; - } - - if (!(response instanceof P11KeyResponse)) { - throw new TokenException("response is not a P11KeyResponse"); - } - - return ((P11KeyResponse) response).getP11Key(this); - } - - private static byte[] toByteArray(ProxyMessage response) throws TokenException { - if (response == null) { - return null; - } - - if (!(response instanceof ByteArrayMessage)) { - throw new TokenException("response is not a ByteArrayMessage"); - } - - return ((ByteArrayMessage) response).getValue(); - } - - private static PKCS11KeyId toPKCS11KeyId(ProxyMessage response) throws TokenException { - if (response == null) { - return null; - } - - if (!(response instanceof KeyIdMessage)) { - throw new TokenException("response is not a KeyIdMessage"); - } - - return ((KeyIdMessage) response).getKeyId(); - } - - private static PrivateKeyInfo toPrivateKeyInfo(ProxyMessage response) throws TokenException { - byte[] bytes = toByteArray(response); - if (bytes == null) { - return null; - } - - try { - return PrivateKeyInfo.getInstance(bytes); - } catch (IllegalArgumentException ex) { - throw new TokenException("invalid PrivateKeyInfo", ex); - } - } - - /** - * The specified stream remains open after this method returns. - */ - @Override - public void showDetails(OutputStream stream, Long objectHandle, boolean verbose) throws IOException { - ShowDetailsRequest req = new ShowDetailsRequest(objectHandle, verbose); - byte[] details; - try { - details = ((ByteArrayMessage) send(ProxyAction.showDetails, req)).getValue(); - } catch (TokenException e) { - details = ("ERROR: " + e.getMessage()).getBytes(StandardCharsets.UTF_8); - } - stream.write(details); - } - - private ProxyMessage send(ProxyAction action, ProxyMessage request) throws TokenException { - ByteArrayCborEncoder encoder = new ByteArrayCborEncoder(); - try { - encoder.writeArrayStart(2); - // slot id - encoder.writeInt(slotId.getId()); - if (request == null) { - encoder.writeNull(); - } else { - request.encode(encoder); - } - } catch (EncodeException ex) { - throw new TokenException("Encode error while building request", ex); - } catch (IOException ex) { - throw new TokenException("IO error while building request", ex); - } - - return module.send(action, encoder.toByteArray()); - } - - @Override - protected PKCS11KeyId doGenerateSecretKey(long keyType, Integer keysize, P11NewKeyControl control) { - throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); - } - - @Override - protected PKCS11KeyId doImportSecretKey(long keyType, byte[] keyValue, P11NewKeyControl control) { - throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); - } - - @Override - protected PKCS11KeyId doGenerateDSAKeypair(BigInteger p, BigInteger q, BigInteger g, P11NewKeyControl control) { - throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); - } - - @Override - protected PKCS11KeyId doGenerateECEdwardsKeypair(ASN1ObjectIdentifier curveId, P11NewKeyControl control) { - throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); - } - - @Override - protected PrivateKeyInfo doGenerateECEdwardsKeypairOtf(ASN1ObjectIdentifier curveId) { - throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); - } - - @Override - protected PKCS11KeyId doGenerateECMontgomeryKeypair(ASN1ObjectIdentifier curveId, P11NewKeyControl control) { - throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); - } - - @Override - protected PrivateKeyInfo doGenerateECMontgomeryKeypairOtf(ASN1ObjectIdentifier curveId) { - throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); - } - - @Override - protected PKCS11KeyId doGenerateECKeypair(ASN1ObjectIdentifier curveId, P11NewKeyControl control) { - throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); - } - - @Override - protected PrivateKeyInfo doGenerateECKeypairOtf(ASN1ObjectIdentifier curveId) { - throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); - } - - @Override - protected PKCS11KeyId doGenerateSM2Keypair(P11NewKeyControl control) { - throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); - } - - @Override - protected PrivateKeyInfo doGenerateSM2KeypairOtf() { - throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); - } - - @Override - protected PKCS11KeyId doGenerateRSAKeypair(int keysize, BigInteger publicExponent, P11NewKeyControl control) { - throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); - } - - @Override - protected PrivateKeyInfo doGenerateRSAKeypairOtf(int keysize, BigInteger publicExponent) { - throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); - } - - @Override - protected PrivateKeyInfo generateDSAKeypairOtf0(BigInteger p, BigInteger q, BigInteger g) { - throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); - } - -} diff --git a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyAction.java b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyAction.java deleted file mode 100644 index df2dbc3..0000000 --- a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyAction.java +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2013-2024 xipki. All rights reserved. -// License Apache License 2.0 - -package org.xipki.security.pkcs11.hsmproxy; - -import java.util.HashMap; -import java.util.Map; - -/** - * The HSM proxy action enumeration. - * - * @author Lijun Liao (xipki) - */ - -public enum ProxyAction { - - moduleCaps ("mcaps"), - slotIds ("sids"), - - // mechanism infos - mechInfos ("mis"), - - publicKeyByHandle ("pkbh"), - - keyByKeyId ("kbi"), - keyByIdLabel ("kbil"), - keyIdByIdLabel ("kibil"), - - objectExistsByIdLabel ("ebil"), - - destroyAllObjects ("dao"), - destroyObjectsByHandle ("dobh"), - destroyObjectsByIdLabel ("dobil"), - - genSecretKey ("gsk"), - importSecretKey ("isk"), - - genRSAKeypair ("grsa"), - genRSAKeypairOtf ("grsao"), - // genDSAKeypairByKeysize - genDSAKeypair2 ("gdsa2"), - genDSAKeypair ("gdsa"), - genDSAKeypairOtf ("gdsao"), - genECKeypair ("gec"), - genECKeypairOtf ("geco"), - genSM2Keypair ("gsm2"), - genSM2KeypairOtf ("gsm2o"), - showDetails ("d"), - sign ("s"), - digestSecretKey ("dsk"); - - private final String alias; - - private static final Map namealiasActionMap = new HashMap<>(); - - static { - for (ProxyAction p : ProxyAction.values()) { - namealiasActionMap.put(p.name().toLowerCase(), p); - } - - for (ProxyAction p : ProxyAction.values()) { - String lc = p.alias.toLowerCase(); - if (namealiasActionMap.containsKey(lc)) { - throw new IllegalStateException("invalid alias " + p.alias); - } - namealiasActionMap.put(lc, p); - } - } - - ProxyAction(String alias) { - this.alias = alias; - } - - public String getAlias() { - return alias; - } - - public static ProxyAction ofNameIgnoreCase(String name) { - return namealiasActionMap.get(name.toLowerCase()); - } - -} diff --git a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyMessage.java b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyMessage.java deleted file mode 100644 index 71d76de..0000000 --- a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyMessage.java +++ /dev/null @@ -1,1465 +0,0 @@ -// Copyright (c) 2013-2024 xipki. All rights reserved. -// License Apache License 2.0 - -package org.xipki.security.pkcs11.hsmproxy; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.xipki.pkcs11.wrapper.MechanismInfo; -import org.xipki.pkcs11.wrapper.PKCS11Exception; -import org.xipki.pkcs11.wrapper.PKCS11KeyId; -import org.xipki.pkcs11.wrapper.TokenException; -import org.xipki.pkcs11.wrapper.params.ExtraParams; -import org.xipki.security.pkcs11.P11Key; -import org.xipki.security.pkcs11.P11ModuleConf; -import org.xipki.security.pkcs11.P11Params; -import org.xipki.security.pkcs11.P11Slot; -import org.xipki.security.pkcs11.P11SlotId; -import org.xipki.util.Args; -import org.xipki.util.cbor.CborDecoder; -import org.xipki.util.cbor.CborEncodable; -import org.xipki.util.cbor.CborEncoder; -import org.xipki.util.exception.DecodeException; -import org.xipki.util.exception.EncodeException; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -/** - * The CBOR message. - * - * @author Lijun Liao (xipki) - */ -public abstract class ProxyMessage implements CborEncodable { - - protected abstract void encode0(CborEncoder encoder) throws EncodeException, IOException; - - @Override - public final void encode(CborEncoder encoder) throws EncodeException { - try { - encode0(encoder); - } catch (IOException ex) { - throw new EncodeException("IO error", ex); - } - } - - private static boolean isNotNullOrElseWriteNull(CborEncoder encoder, Object obj) throws IOException { - if (obj == null) { - encoder.writeNull(); - return false; - } - return true; - } - - private static void writeBigInt(CborEncoder encoder, BigInteger value) throws IOException { - if (isNotNullOrElseWriteNull(encoder, value)) { - encoder.writeByteString(value.toByteArray()); - } - } - - private static void writeOid(CborEncoder encoder, ASN1ObjectIdentifier value) throws IOException { - if (isNotNullOrElseWriteNull(encoder, value)) { - encoder.writeTextString(value.getId()); - } - } - - private static ASN1ObjectIdentifier readOid(CborDecoder decoder) throws IOException, DecodeException { - String text = decoder.readTextString(); - if (text == null) { - return null; - } - - try { - return new ASN1ObjectIdentifier(text); - } catch (IllegalArgumentException ex) { - throw new DecodeException(text + " is not a valid ObjectIdentifier"); - } - } - - private static void writeNewKeyControl(CborEncoder encoder, P11Slot.P11NewKeyControl control) throws IOException { - if (control == null) { - encoder.writeNull(); - return; - } - - encoder.writeArrayStart(5); - encoder.writeByteString(control.getId()); - encoder.writeTextString(control.getLabel()); - encoder.writeBooleanObj(control.getSensitive()); - encoder.writeBooleanObj(control.getExtractable()); - - Set usages = control.getUsages(); - if (usages == null) { - encoder.writeNull(); - } else { - encoder.writeArrayStart(usages.size()); - for (P11Slot.P11KeyUsage usage: usages) { - encoder.writeTextString(usage.name()); - } - } - } - - private static P11Slot.P11NewKeyControl decodeNewKeyControl(CborDecoder decoder) throws DecodeException { - try { - if (decoder.readNullOrArrayLength(5)) { - return null; - } - - byte[] id = decoder.readByteString(); - String label = decoder.readTextString(); - P11Slot.P11NewKeyControl control = new P11Slot.P11NewKeyControl(id, label); - control.setSensitive(decoder.readBooleanObj()); - control.setExtractable(decoder.readBooleanObj()); - - // usages - Integer usagesLen = decoder.readNullOrArrayLength(); - if (usagesLen != null) { - Set usages = new HashSet<>(usagesLen * 5 / 4); - for (int i = 0; i < usagesLen; i++) { - String usageText = decoder.readTextString(); - P11Slot.P11KeyUsage usage; - try { - usage = P11Slot.P11KeyUsage.valueOf(usageText); - } catch (IllegalArgumentException e) { - throw new DecodeException("unknown P11KeyUsage " + usageText); - } - usages.add(usage); - } - - control.setUsages(usages); - } - - return control; - } catch (IOException ex) { - throw new DecodeException("IO error", ex); - } - } - - private static void writeKeyId(CborEncoder encoder, PKCS11KeyId keyId) throws IOException { - encoder.writeArrayStart(6); - encoder.writeInt(keyId.getHandle()); - encoder.writeInt(keyId.getObjectCLass()); - encoder.writeInt(keyId.getKeyType()); - encoder.writeByteString(keyId.getId()); - encoder.writeTextString(keyId.getLabel()); - encoder.writeIntObj(keyId.getPublicKeyHandle()); - } - - private static PKCS11KeyId decodeKeyId(CborDecoder decoder) throws DecodeException { - try { - if (decoder.readNullOrArrayLength(6)) { - return null; - } - - long handle = decoder.readLong(); - long objectCLass = decoder.readLong(); - long keyType = decoder.readLong(); - byte[] id = decoder.readByteString(); - String label = decoder.readTextString(); - Long publicKeyHandle = decoder.readLongObj(); - - PKCS11KeyId keyId = new PKCS11KeyId(handle, objectCLass, keyType, id, label); - keyId.setPublicKeyHandle(publicKeyHandle); - return keyId; - } catch (IOException ex) { - throw new DecodeException("IO error decoding PKCS11KeyId", ex); - } - } - - private static void assertArraySize(CborDecoder decoder, int arraySize, String name) throws DecodeException { - try { - if (decoder.readNullOrArrayLength(arraySize)) { - throw new DecodeException(name + " shall not be null"); - } - } catch (IOException ex) { - throw new DecodeException("IO error reading arrayLength of " + name); - } - } - - /** - * The message wrapper for boolean. - */ - public static class BooleanMessage extends ProxyMessage { - - private final boolean value; - - public BooleanMessage(boolean value) { - this.value = value; - } - - public boolean getValue() { - return value; - } - - @Override - public void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeBoolean(value); - } - - public static BooleanMessage decode(CborDecoder decoder) throws DecodeException { - try { - boolean b = Optional.ofNullable(decoder.readBooleanObj()).orElseThrow( - () -> new DecodeException("BooleanMessage shall not be null")); - return new BooleanMessage(b); - } catch (IOException ex) { - throw new DecodeException("IO error decoding BooleanMessage", ex); - } - } - - } - - /** - * The message wrapper for byte[]. - */ - public static class ByteArrayMessage extends ProxyMessage { - - private final byte[] value; - - public ByteArrayMessage(byte[] value) { - this.value = Args.notNull(value, "value"); - } - - public byte[] getValue() { - return value; - } - - @Override - protected void encode0(CborEncoder encoder) throws IOException { - encoder.writeByteString(value); - } - - public static ByteArrayMessage decode(CborDecoder decoder) throws DecodeException { - try { - byte[] b = Optional.ofNullable(decoder.readByteString()).orElseThrow( - () -> new DecodeException("ByteArrayMessage shall not be null")); - - return new ByteArrayMessage(b); - } catch (IOException ex) { - throw new DecodeException("IO error decoding ByteArrayMessage", ex); - } - } - - } - - /** - * The request to digest secret key. - */ - public static class DigestSecretKeyRequest extends ProxyMessage { - - private static final int NUM_FIELDS = 2; - - private final long mechanism; - - private final long objectHandle; - - public DigestSecretKeyRequest(long mechanism, long objectHandle) { - this.mechanism = mechanism; - this.objectHandle = objectHandle; - } - - public long getMechanism() { - return mechanism; - } - - public long getObjectHandle() { - return objectHandle; - } - - @Override - protected void encode0(CborEncoder encoder) throws IOException { - encoder.writeArrayStart(NUM_FIELDS); - encoder.writeInt(mechanism); - encoder.writeInt(objectHandle); - } - - public static DigestSecretKeyRequest decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "DigestSecretKeyRequest"); - try { - long mechanism = decoder.readLong(); - long objectHandle = decoder.readLong(); - return new DigestSecretKeyRequest(mechanism, objectHandle); - } catch (IOException ex) { - throw new DecodeException("IO error decoding DigestSecretKeyRequest", ex); - } - } - - } - - public enum ProxyErrorCode { - - internalError(1), - badRequest(2), - tokenException(3), - pkcs11Exception(4); - - private final int code; - - ProxyErrorCode(int code) { - this.code = code; - } - - public int getCode() { - return code; - } - - public static ProxyErrorCode ofCode(int code) { - for (ProxyErrorCode m : ProxyErrorCode.values()) { - if (m.code == code) { - return m; - } - } - return null; - } - - } - - /** - * The error response. - */ - public static class ErrorResponse extends ProxyMessage { - - public static final long CBOR_TAG_ERROR_RESPONSE = 0x80000; - - private static final int NUM_FIELDS = 2; - - private final ProxyErrorCode errorCode; - - private final String detail; - - public ErrorResponse(ProxyErrorCode errorCode, String detail) { - this.errorCode = errorCode; - this.detail = detail; - } - - public ErrorResponse(Throwable t) { - if (t instanceof PKCS11Exception) { - this.errorCode = ProxyErrorCode.pkcs11Exception; - this.detail = Long.toString(((PKCS11Exception) t).getErrorCode()); - } else if (t instanceof TokenException) { - this.errorCode = ProxyErrorCode.tokenException; - this.detail = t.getMessage(); - } else { - this.errorCode = ProxyErrorCode.tokenException; - this.detail = t.getMessage(); - } - } - - public ProxyErrorCode getErrorCode() { - return errorCode; - } - - public String getDetail() { - return detail; - } - - @Override - public void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - encoder.writeInt(errorCode.code); - encoder.writeTextString(detail); - } - - public static ErrorResponse decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "ErrorResponnse"); - try { - int code = decoder.readInt(); - ProxyErrorCode errorCode = Optional.ofNullable(ProxyErrorCode.ofCode(code)).orElseThrow( - () -> new DecodeException("unknown error code " + code)); - String detail = decoder.readTextString(); - return new ErrorResponse(errorCode, detail); - } catch (IOException ex) { - throw new DecodeException("IO error decoding ErrorResponse", ex); - } - } - - } - - /** - * The request to generate-then-save DSA keypair for given keysize. - */ - public static class GenerateDSAKeyPairByKeysizeRequest extends ProxyMessage { - - private static final int NUM_FIELDS = 3; - - private final int plength; - - private final int qlength; - - private final P11Slot.P11NewKeyControl newKeyControl; - - public GenerateDSAKeyPairByKeysizeRequest(int plength, int qlength, P11Slot.P11NewKeyControl newKeyControl) { - this.plength = plength; - this.qlength = qlength; - this.newKeyControl = newKeyControl; - } - - public int getPlength() { - return plength; - } - - public int getQlength() { - return qlength; - } - - public P11Slot.P11NewKeyControl getNewKeyControl() { - return newKeyControl; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - encoder.writeInt(plength); - encoder.writeInt(qlength); - writeNewKeyControl(encoder, newKeyControl); - } - - public static GenerateDSAKeyPairByKeysizeRequest decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "GenerateDSAKeyPairByKeysizeRequest"); - try { - int plength = decoder.readInt(); - int qlength = decoder.readInt(); - P11Slot.P11NewKeyControl control = decodeNewKeyControl(decoder); - return new GenerateDSAKeyPairByKeysizeRequest(plength, qlength, control); - } catch (IOException ex) { - throw new DecodeException("IO error decoding GenerateDSAKeyPairByKeysizeRequest", ex); - } - } - - } - - /** - * The request to generate-then-destroy DSA keypair for given (P, Q, G). - */ - public static class GenerateDSAKeyPairOtfRequest extends ProxyMessage { - - private static final int NUM_FIELDS = 3; - - protected final BigInteger p; - - protected final BigInteger q; - - protected final BigInteger g; - - public GenerateDSAKeyPairOtfRequest(BigInteger p, BigInteger q, BigInteger g) { - this.p = Args.notNull(p, "p"); - this.q = Args.notNull(q, "q"); - this.g = Args.notNull(g, "g"); - } - - public BigInteger getP() { - return p; - } - - public BigInteger getQ() { - return q; - } - - public BigInteger getG() { - return g; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - encoder.writeByteString(p.toByteArray()); - encoder.writeByteString(q.toByteArray()); - encoder.writeByteString(g.toByteArray()); - } - - public static GenerateDSAKeyPairOtfRequest decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "GenerateDSAKeyPairOtfRequest"); - try { - BigInteger p = decoder.readBigInt(); - BigInteger q = decoder.readBigInt(); - BigInteger g = decoder.readBigInt(); - return new GenerateDSAKeyPairOtfRequest(p, q, g); - } catch (IOException ex) { - throw new DecodeException("IO error decoding GenerateDSAKeyPairOtfRequest", ex); - } - } - - } - - /** - * The request to generate-then-save DSA keypair for given (P, Q, G). - */ - public static class GenerateDSAKeyPairRequest extends GenerateDSAKeyPairOtfRequest { - - private static final int NUM_FIELDS = 4; - - private final P11Slot.P11NewKeyControl newKeyControl; - - public GenerateDSAKeyPairRequest(BigInteger p, BigInteger q, BigInteger g, P11Slot.P11NewKeyControl newKeyControl) { - super(p, q, g); - this.newKeyControl = newKeyControl; - } - - public P11Slot.P11NewKeyControl getNewKeyControl() { - return newKeyControl; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - encoder.writeByteString(p.toByteArray()); - encoder.writeByteString(q.toByteArray()); - encoder.writeByteString(g.toByteArray()); - writeNewKeyControl(encoder, newKeyControl); - } - - public static GenerateDSAKeyPairRequest decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "GenerateDSAKeyPairRequest"); - try { - BigInteger p = decoder.readBigInt(); - BigInteger q = decoder.readBigInt(); - BigInteger g = decoder.readBigInt(); - P11Slot.P11NewKeyControl control = decodeNewKeyControl(decoder); - return new GenerateDSAKeyPairRequest(p, q, g, control); - } catch (IOException ex) { - throw new DecodeException("IO error decoding GenerateDSAKeyPairRequest", ex); - } - } - - } - - /** - * The request to generate-then-destroy EC keypair. - */ - public static class GenerateECKeyPairOtfRequest extends ProxyMessage { - - private static final int NUM_FIELDS = 1; - - protected final ASN1ObjectIdentifier curveOid; - - public GenerateECKeyPairOtfRequest(ASN1ObjectIdentifier curveOid) { - this.curveOid = Args.notNull(curveOid, "curveOid"); - } - - public ASN1ObjectIdentifier getCurveOid() { - return curveOid; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - writeOid(encoder, curveOid); - } - - public static GenerateECKeyPairOtfRequest decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "GenerateECKeyPairOtfRequest"); - try { - ASN1ObjectIdentifier curveOid = readOid(decoder); - return new GenerateECKeyPairOtfRequest(curveOid); - } catch (IOException ex) { - throw new DecodeException("IO error decoding GenerateECKeyPairOtfRequest", ex); - } - } - - } - - /** - * The request to generate-then-save EC keypair. - */ - public static class GenerateECKeyPairRequest extends GenerateECKeyPairOtfRequest { - - private static final int NUM_FIELDS = 2; - - private final P11Slot.P11NewKeyControl newKeyControl; - - public GenerateECKeyPairRequest(ASN1ObjectIdentifier curveOid, P11Slot.P11NewKeyControl newKeyControl) { - super(curveOid); - this.newKeyControl = newKeyControl; - } - - public P11Slot.P11NewKeyControl getNewKeyControl() { - return newKeyControl; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - ProxyMessage.writeOid(encoder, curveOid); - ProxyMessage.writeNewKeyControl(encoder, newKeyControl); - } - - public static GenerateECKeyPairRequest decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "GenerateECKeyPairRequest"); - try { - ASN1ObjectIdentifier curveOid = ProxyMessage.readOid(decoder); - P11Slot.P11NewKeyControl control = ProxyMessage.decodeNewKeyControl(decoder); - return new GenerateECKeyPairRequest(curveOid, control); - } catch (IOException ex) { - throw new DecodeException("IO error decoding GenerateECKeyPairRequest", ex); - } - } - - } - - /** - * The request to generate-then-destroy RSA keypair. - */ - public static class GenerateRSAKeyPairOtfRequest extends ProxyMessage { - - private static final int NUM_FIELDS = 2; - - protected final int keySize; - - protected final BigInteger publicExponent; - - public GenerateRSAKeyPairOtfRequest(int keySize, BigInteger publicExponent) { - this.keySize = keySize; - this.publicExponent = publicExponent; - } - - public int getKeySize() { - return keySize; - } - - public BigInteger getPublicExponent() { - return publicExponent; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - encoder.writeInt(keySize); - encoder.writeByteString(publicExponent == null ? null : publicExponent.toByteArray()); - } - - public static GenerateRSAKeyPairOtfRequest decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "GenerateRSAKeyPairOtfRequest"); - try { - int keysize = decoder.readInt(); - BigInteger publicExponent = decoder.readBigInt(); - return new GenerateRSAKeyPairOtfRequest(keysize, publicExponent); - } catch (IOException ex) { - throw new DecodeException("IO error decoding GenerateRSAKeyPairOtfRequest", ex); - } - } - - } - - /** - * The request to generate-then-save RSA keypair. - */ - public static class GenerateRSAKeyPairRequest extends GenerateRSAKeyPairOtfRequest { - - private static final int NUM_FIELDS = 2; - - private final P11Slot.P11NewKeyControl newKeyControl; - - public GenerateRSAKeyPairRequest(int keySize, BigInteger publicExponent, P11Slot.P11NewKeyControl newKeyControl) { - super(keySize, publicExponent); - this.newKeyControl = newKeyControl; - } - - public P11Slot.P11NewKeyControl getNewKeyControl() { - return newKeyControl; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - encoder.writeInt(keySize); - writeBigInt(encoder, publicExponent); - writeNewKeyControl(encoder, newKeyControl); - } - - public static GenerateRSAKeyPairRequest decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "GenerateRSAKeyPairRequest"); - try { - int keysize = decoder.readInt(); - BigInteger publicExponent = decoder.readBigInt(); - P11Slot.P11NewKeyControl control = decodeNewKeyControl(decoder); - return new GenerateRSAKeyPairRequest(keysize, publicExponent, control); - } catch (IOException ex) { - throw new DecodeException("IO error decoding GenerateRSAKeyPairRequest", ex); - } - } - - } - - /** - * The request to generate-then-destroy SM2 keypair. - */ - public static class GenerateSecretKeyRequest extends ProxyMessage { - - private static final int NUM_FIELDS = 3; - private final long keyType; - private final Integer keySize; - private final P11Slot.P11NewKeyControl newKeyControl; - - public GenerateSecretKeyRequest(long keyType, Integer keySize, P11Slot.P11NewKeyControl newKeyControl) { - this.keyType = keyType; - this.keySize = keySize; - this.newKeyControl = newKeyControl; - } - - public long getKeyType() { - return keyType; - } - - public Integer getKeySize() { - return keySize; - } - - public P11Slot.P11NewKeyControl getNewOKeyControl() { - return newKeyControl; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - encoder.writeInt(keyType); - encoder.writeIntObj(keySize); - writeNewKeyControl(encoder, newKeyControl); - } - - public static GenerateSecretKeyRequest decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "GenerateSecretKeyRequest"); - try { - long keyType = decoder.readLong(); - Integer keySize = decoder.readIntObj(); - P11Slot.P11NewKeyControl control = decodeNewKeyControl(decoder); - return new GenerateSecretKeyRequest(keyType, keySize, control); - } catch (IOException ex) { - throw new DecodeException("IO error decoding GenerateSecretKeyRequest", ex); - } - } - - } - - /** - * The request to generate-then-save SM2 keypair. - */ - public static class GenerateSM2KeyPairRequest extends ProxyMessage { - - private static final int NUM_FIELDS = 1; - - private final P11Slot.P11NewKeyControl newKeyControl; - - public GenerateSM2KeyPairRequest(P11Slot.P11NewKeyControl newKeyControl) { - this.newKeyControl = newKeyControl; - } - - public P11Slot.P11NewKeyControl getNewKeyControl() { - return newKeyControl; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - writeNewKeyControl(encoder, newKeyControl); - } - - public static GenerateSM2KeyPairRequest decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "GenerateSM2KeyPairRequest"); - P11Slot.P11NewKeyControl control = decodeNewKeyControl(decoder); - return new GenerateSM2KeyPairRequest(control); - } - - } - - /** - * The request to get mechanism infos. - */ - public static class GetMechanismInfosResponse extends ProxyMessage { - - private final Map mechamismInfoMap; - - public GetMechanismInfosResponse(Map mechamismInfoMap) { - this.mechamismInfoMap = mechamismInfoMap; - } - - @Override - public void encode0(CborEncoder encoder) throws IOException, EncodeException { - encoder.writeMapStart(mechamismInfoMap.size()); - for (Map.Entry entry : mechamismInfoMap.entrySet()) { - encoder.writeInt(entry.getKey()); - MechanismInfo mi = entry.getValue(); - if (entry.getValue() == null) { - encoder.writeNull(); - } else { - encoder.writeArrayStart(3); - encoder.writeInt(mi.getMinKeySize()); - encoder.writeInt(mi.getMaxKeySize()); - encoder.writeInt(mi.getFlags()); - } - } - } - - public Map getMechamismInfoMap() { - return mechamismInfoMap; - } - - public static GetMechanismInfosResponse decode(CborDecoder decoder) throws DecodeException { - try { - Integer mapLen = decoder.readNullOrMapLength(); - if (mapLen == null) { - throw new DecodeException("GetMechanismInfosResponse shall not be null"); - } - - Map map = new HashMap<>(mapLen * 5 / 4); - for (int i = 0; i < mapLen; i++) { - long code = decoder.readLong(); - boolean isNull = decoder.readNullOrArrayLength(3); - if (isNull) { - map.put(code, null); - } else { - long minSize = decoder.readLong(); - long maxSize = decoder.readLong(); - long flags = decoder.readLong(); - map.put(code, new MechanismInfo(minSize, maxSize, flags)); - } - } - - return new GetMechanismInfosResponse(map); - } catch (IOException ex) { - throw new DecodeException("IO error decoding GetMechanismInfosResponse", ex); - } - } - - } - - /** - * The message wrapper for ia and label. - */ - public static class IdLabelMessage extends ProxyMessage { - - private static final int NUM_FIELDS = 2; - - private final byte[] id; - - private final String label; - - public IdLabelMessage(byte[] id, String label) { - this.id = id; - this.label = label; - } - - public byte[] getId() { - return id; - } - - public String getLabel() { - return label; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - encoder.writeByteString(id); - encoder.writeTextString(label); - } - - public static IdLabelMessage decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "IdLabelMessage"); - try { - byte[] id = decoder.readByteString(); - String label = decoder.readTextString(); - return new IdLabelMessage(id, label); - } catch (IOException ex) { - throw new DecodeException("IO error decoding IdLabelMessage", ex); - } - } - - } - - /** - * The request to import secret key. - */ - public static class ImportSecretKeyRequest extends ProxyMessage { - private static final int NUM_FIELDS = 3; - private final long keyType; - private final byte[] keyValue; - private final P11Slot.P11NewKeyControl newKeyControl; - - public ImportSecretKeyRequest(long keyType, byte[] keyValue, P11Slot.P11NewKeyControl newKeyControl) { - this.keyType = keyType; - this.keyValue = Args.notNull(keyValue, "keyValue"); - this.newKeyControl = newKeyControl; - } - - public long getKeyType() { - return keyType; - } - - public byte[] getKeyValue() { - return keyValue; - } - - public P11Slot.P11NewKeyControl getNewKeyControl() { - return newKeyControl; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - encoder.writeInt(keyType); - encoder.writeByteString(keyValue); - writeNewKeyControl(encoder, newKeyControl); - } - - public static ImportSecretKeyRequest decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "ImportSecretKeyRequest"); - try { - long keyType = decoder.readLong(); - byte[] keyValue = decoder.readByteString(); - P11Slot.P11NewKeyControl control = decodeNewKeyControl(decoder); - return new ImportSecretKeyRequest(keyType, keyValue, control); - } catch (IOException ex) { - throw new DecodeException("IO error decoding ImportSecretKeyRequest", ex); - } - } - - } - - /** - * The message wrapper for int. - */ - public static class IntMessage extends ProxyMessage { - - private final int value; - - public IntMessage(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeInt(value); - } - - public static IntMessage decode(CborDecoder decoder) throws DecodeException { - try { - int b = Optional.ofNullable(decoder.readIntObj()).orElseThrow( - () -> new DecodeException("IntMessage shall not be null")); - return new IntMessage(b); - } catch (IOException ex) { - throw new DecodeException("IO error decoding IntMessage", ex); - } - } - - } - - /** - * The message wrapper for {@link PKCS11KeyId}. - */ - public static class KeyIdMessage extends ProxyMessage { - private static final int NUM_FIELDS = 6; - private final PKCS11KeyId keyId; - - public KeyIdMessage(PKCS11KeyId keyId) { - this.keyId = keyId; - } - - public PKCS11KeyId getKeyId() { - return keyId; - } - - @Override - public void encode0(CborEncoder encoder) throws IOException, EncodeException { - if (keyId == null) { - encoder.writeNull(); - return; - } - - encoder.writeArrayStart(NUM_FIELDS); - encoder.writeInt(keyId.getHandle()); - encoder.writeInt(keyId.getKeyType()); - encoder.writeInt(keyId.getObjectCLass()); - encoder.writeByteString(keyId.getId()); - encoder.writeTextString(keyId.getLabel()); - encoder.writeIntObj(keyId.getPublicKeyHandle()); - } - - public static KeyIdMessage decode(CborDecoder decoder) throws DecodeException { - PKCS11KeyId keyId = Optional.ofNullable(decodeKeyId(decoder)).orElseThrow( - () -> new DecodeException("KeyIdMessage shall not be null")); - return new KeyIdMessage(keyId); - } - - } - - /** - * The message wrapper for long[]. - */ - public static class LongArrayMessage extends ProxyMessage { - - private final long[] value; - - public LongArrayMessage(long[] value) { - this.value = value; - } - - public long[] getValue() { - return value; - } - - @Override - public void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeLongs(value); - } - - public static LongArrayMessage decode(CborDecoder decoder) throws DecodeException { - try { - long[] value = Optional.ofNullable(decoder.readLongs()).orElseThrow( - () -> new DecodeException("LongMessage shall not be null")); - return new LongArrayMessage(value); - } catch (IOException ex) { - throw new DecodeException("IO error decoding LongArrayMessage", ex); - } - } - - } - - /** - * The message wrapper for long. - */ - public static class LongMessage extends ProxyMessage { - - private final long value; - - public LongMessage(long value) { - this.value = value; - } - - public long getValue() { - return value; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeInt(value); - } - - public static LongMessage decode(CborDecoder decoder) throws DecodeException { - try { - long b = Optional.ofNullable(decoder.readLongObj()).orElseThrow( - () -> new DecodeException("LongMessage shall not be null")); - return new LongMessage(b); - } catch (IOException ex) { - throw new DecodeException("IO error decoding LongMessage", ex); - } - } - - } - - /** - * The response of getting module capability. - */ - public static class ModuleCapsResponse extends ProxyMessage { - - private static final int NUM_FIELDS = 5; - - private final boolean readOnly; - - private final int maxMessageSize; - - private final P11ModuleConf.P11NewObjectConf newObjectConf; - - private final List secretKeyTypes; - - private final List keyPairTypes; - - public ModuleCapsResponse(boolean readOnly, int maxMessageSize, P11ModuleConf.P11NewObjectConf newObjectConf, - List secretKeyTypes, List keyPairTypes) { - this.readOnly = readOnly; - this.maxMessageSize = maxMessageSize; - this.newObjectConf = newObjectConf; - this.secretKeyTypes = secretKeyTypes; - this.keyPairTypes = keyPairTypes; - } - - public boolean isReadOnly() { - return readOnly; - } - - public int getMaxMessageSize() { - return maxMessageSize; - } - - public P11ModuleConf.P11NewObjectConf getNewObjectConf() { - return newObjectConf; - } - - public List getSecretKeyTypes() { - return secretKeyTypes; - } - - public List getKeyPairTypes() { - return keyPairTypes; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - encoder.writeBoolean(readOnly); - encoder.writeInt(maxMessageSize); - if (newObjectConf == null) { - encoder.writeNull(); - } else { - encoder.writeArrayStart(2); - encoder.writeBoolean(newObjectConf.isIgnoreLabel()); - encoder.writeInt(newObjectConf.getIdLength()); - } - - encoder.writeLongs(secretKeyTypes); - encoder.writeLongs(keyPairTypes); - } - - public static ModuleCapsResponse decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "ModuleCapsResponse"); - try { - boolean readOnly = decoder.readBoolean(); - int maxMessageSize = decoder.readInt(); - P11ModuleConf.P11NewObjectConf newObjectConf; - if (decoder.readNullOrArrayLength(2)) { - newObjectConf = null; - } else { - newObjectConf = new P11ModuleConf.P11NewObjectConf(); - newObjectConf.setIgnoreLabel(decoder.readBoolean()); - newObjectConf.setIdLength(decoder.readInt()); - } - - List secretKeyTypes = decoder.readLongList(); - List keyPairTypes = decoder.readLongList(); - - return new ModuleCapsResponse(readOnly, maxMessageSize, newObjectConf, secretKeyTypes, keyPairTypes); - } catch (IOException ex) { - throw new DecodeException("IO error decoding ModuleCapsResponse", ex); - } - } - - } // class ServerCaps - - /** - * The response of getting PKCS#11 key. - */ - public static class P11KeyResponse extends ProxyMessage { - - private static final int NUM_FIELDS = 9; - - private final PKCS11KeyId keyId; - - private boolean sign; - - private ASN1ObjectIdentifier ecParams; - - private Integer ecOrderBitSize; - - private BigInteger rsaModulus; - - private BigInteger rsaPublicExponent; - - private BigInteger dsaP; - - private BigInteger dsaQ; - - private BigInteger dsaG; - - public P11KeyResponse(P11Key key) { - Args.notNull(key, "key"); - this.keyId = key.getKeyId(); - this.ecParams = key.getEcParams(); - this.ecOrderBitSize = key.getEcOrderBitSize(); - this.dsaP = key.getDsaP(); - this.dsaQ = key.getDsaQ(); - this.dsaG = key.getDsaG(); - this.rsaModulus = key.getRsaModulus(); - this.rsaPublicExponent = key.getRsaPublicExponent(); - this.sign = key.isSign(); - } - - public P11KeyResponse(PKCS11KeyId keyId) { - this.keyId = Args.notNull(keyId, "keyId"); - } - - public P11Key getP11Key(HsmProxyP11Slot slot) { - HsmProxyP11Key key = new HsmProxyP11Key(slot, keyId); - key.setEcParams(ecParams); - key.setDsaParameters(dsaP, dsaQ, dsaG); - key.setRsaMParameters(rsaModulus, rsaPublicExponent); - key.sign(sign); - return key; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - writeKeyId(encoder, keyId); - encoder.writeBoolean(sign); - writeOid(encoder, ecParams); - encoder.writeIntObj(ecOrderBitSize); - writeBigInt(encoder, rsaModulus); - writeBigInt(encoder, rsaPublicExponent); - writeBigInt(encoder, dsaP); - writeBigInt(encoder, dsaQ); - writeBigInt(encoder, dsaG); - } - - public static P11KeyResponse decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "ModuleCapsResponse"); - try { - PKCS11KeyId keyId = decodeKeyId(decoder); - P11KeyResponse ret = new P11KeyResponse(keyId); - ret.sign = decoder.readBoolean(); - ret.ecParams = readOid(decoder); - ret.ecOrderBitSize = decoder.readIntObj(); - ret.rsaModulus = decoder.readBigInt(); - ret.rsaPublicExponent = decoder.readBigInt(); - ret.dsaP = decoder.readBigInt(); - ret.dsaQ = decoder.readBigInt(); - ret.dsaG = decoder.readBigInt(); - - return ret; - } catch (IOException ex) { - throw new DecodeException("IO error decoding P11KeyResponse", ex); - } - } - - } - - /** - * The request to show details of given slot, and optional given object handle. - */ - public static class ShowDetailsRequest extends ProxyMessage { - - private static final int NUM_FIELDS = 2; - - private final Long objectHandle; - - private final boolean verbose; - - public ShowDetailsRequest(Long objectHandle, boolean verbose) { - this.objectHandle = objectHandle; - this.verbose = verbose; - } - - public Long getObjectHandle() { - return objectHandle; - } - - public boolean isVerbose() { - return verbose; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - encoder.writeIntObj(objectHandle); - encoder.writeBoolean(verbose); - } - - public static ShowDetailsRequest decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "ShowDetailsRequest"); - try { - Long objectHandle = decoder.readLongObj(); - boolean verbose = decoder.readBoolean(); - return new ShowDetailsRequest(objectHandle, verbose); - } catch (IOException ex) { - throw new DecodeException("IO error decoding P11KeyResponse", ex); - } - } - - } - - /** - * The request to sign message. - */ - public static class SignRequest extends ProxyMessage { - - private static final int NUM_FIELDS = 5; - - private static final int TAG_P11ByteArrayParams = 80000; - - private static final int TAG_P11RSAPkcsPssParams = 80001; - - private final long keyHandle; - - private final long mechanism; - - private final P11Params p11params; - - private final ExtraParams extraParams; - - private final byte[] content; - - public SignRequest(long keyHandle, long mechanism, P11Params p11params, ExtraParams extraParams, byte[] content) { - this.keyHandle = keyHandle; - this.mechanism = mechanism; - this.p11params = p11params; - this.extraParams = extraParams; - this.content = content; - } - - public long getKeyHandle() { - return keyHandle; - } - - public byte[] getContent() { - return content; - } - - public long getMechanism() { - return mechanism; - } - - public P11Params getP11params() { - return p11params; - } - - public ExtraParams getExtraParams() { - return extraParams; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(NUM_FIELDS); - encoder.writeInt(keyHandle); - encoder.writeInt(mechanism); - writeP11Params(encoder, p11params); - writeExtraParams(encoder, extraParams); - encoder.writeByteString(content); - } - - public static SignRequest decode(CborDecoder decoder) throws DecodeException { - assertArraySize(decoder, NUM_FIELDS, "SignRequest"); - try { - long handle = decoder.readLong(); - long mechanism = decoder.readLong(); - P11Params params = decodeP11Params(decoder); - ExtraParams extraParams = decodeExtraParams(decoder); - byte[] content = decoder.readByteString(); - return new SignRequest(handle, mechanism, params, extraParams, content); - } catch (IOException ex) { - throw new DecodeException("IO error decoding SignRequest", ex); - } - } - - private static void writeExtraParams(CborEncoder encoder, ExtraParams params) throws IOException { - if (params == null) { - encoder.writeNull(); - return; - } - encoder.writeArrayStart(1); - encoder.writeInt(params.ecOrderBitSize()); - } - - private static ExtraParams decodeExtraParams(CborDecoder decoder) throws DecodeException { - try { - if (decoder.readNullOrArrayLength(1)) { - return null; - } - - return new ExtraParams().ecOrderBitSize(decoder.readInt()); - } catch (IOException ex) { - throw new DecodeException("IO error", ex); - } - } - - protected static void writeP11Params(CborEncoder encoder, P11Params params) - throws IOException { - if (params == null) { - encoder.writeNull(); - return; - } - - if (params instanceof P11Params.P11ByteArrayParams) { - P11Params.P11ByteArrayParams tParams = (P11Params.P11ByteArrayParams) params; - encoder.writeTag(TAG_P11ByteArrayParams); - encoder.writeArrayStart(1); - encoder.writeByteString(tParams.getBytes()); - } else if (params instanceof P11Params.P11RSAPkcsPssParams) { - P11Params.P11RSAPkcsPssParams tParams = (P11Params.P11RSAPkcsPssParams) params; - encoder.writeTag(TAG_P11RSAPkcsPssParams); - encoder.writeArrayStart(3); - encoder.writeInt(tParams.getHashAlgorithm()); - encoder.writeInt(tParams.getMaskGenerationFunction()); - encoder.writeInt(tParams.getSaltLength()); - } else { - throw new IllegalStateException("unknown params " + params.getClass().getName()); - } - } - - public static P11Params decodeP11Params(CborDecoder decoder) throws DecodeException { - try { - Long tag = decoder.readTagObj(); - if (tag == null) { - return null; - } - - if (TAG_P11ByteArrayParams == tag) { - assertArraySize(decoder, 1, "P11ByteArrayParams"); - return new P11Params.P11ByteArrayParams(decoder.readByteString()); - } else if (TAG_P11RSAPkcsPssParams == tag) { - assertArraySize(decoder, 3, "P11RSAPkcsPssParams"); - long hashAlgorithm = decoder.readLong(); - long maskGenerationFunction = decoder.readLong(); - int saltLength = decoder.readInt(); - return new P11Params.P11RSAPkcsPssParams(hashAlgorithm, maskGenerationFunction, saltLength); - } else { - throw new DecodeException("unknown tag " + tag); - } - } catch (IOException ex) { - throw new DecodeException("IO error", ex); - } - } - - } - - /** - * The response of getting slot identifiers. - */ - public static class SlotIdsResponse extends ProxyMessage { - - private final List slotIds; - - public SlotIdsResponse(List slotIds) { - this.slotIds = Args.notNull(slotIds, "slotIds"); - } - - public List getSlotIds() { - return slotIds; - } - - @Override - protected void encode0(CborEncoder encoder) throws EncodeException, IOException { - encoder.writeArrayStart(slotIds.size()); - for (P11SlotId slotId : slotIds) { - encoder.writeArrayStart(2); - encoder.writeInt(slotId.getIndex()); - encoder.writeInt(slotId.getId()); - } - } - - public static SlotIdsResponse decode(CborDecoder decoder) throws DecodeException { - try { - int arrayLen = Optional.ofNullable(decoder.readNullOrArrayLength()).orElseThrow( - () -> new DecodeException("SlotIdsResponse shall not be null")); - - List list = new ArrayList<>(arrayLen); - for (int i = 0; i < arrayLen; i++) { - assertArraySize(decoder, 2, "P11SlotId"); - int index = decoder.readInt(); - long id = decoder.readLong(); - list.add(new P11SlotId(index, id)); - } - - return new SlotIdsResponse(list); - } catch (IOException ex) { - throw new DecodeException("IO error decoding SlotIdsResponse", ex); - } - } - } -} diff --git a/security/src/main/java/org/xipki/security/qa/P11SignSpeed.java b/security/src/main/java/org/xipki/security/qa/P11SignSpeed.java index ce68688..849d604 100644 --- a/security/src/main/java/org/xipki/security/qa/P11SignSpeed.java +++ b/security/src/main/java/org/xipki/security/qa/P11SignSpeed.java @@ -252,7 +252,7 @@ public P11SignSpeed(SecurityFactory securityFactory, P11Slot slot, String signat this.deleteKeyAfterTest = deleteKeyAfterTest; P11SlotId slotId = slot.getSlotId(); - SignerConf signerConf = getPkcs11SignerConf(slot.getModuleName(), + SignerConf signerConf = getPkcs11SignerConf( slotId.getId(), keyId.getId(), Args.notBlank(signatureAlgorithm, "signatureAlgorithm"), threads + Math.max(2, threads * 5 / 4)); @@ -297,14 +297,10 @@ protected Runnable getTester() throws Exception { } private static SignerConf getPkcs11SignerConf( - String pkcs11ModuleName, Long slotId, byte[] keyId, String signatureAlgorithm, int parallelism) { + Long slotId, byte[] keyId, String signatureAlgorithm, int parallelism) { ConfPairs conf = new ConfPairs("algo", signatureAlgorithm) .putPair("parallelism", Integer.toString(parallelism)); - if (pkcs11ModuleName != null && !pkcs11ModuleName.isEmpty()) { - conf.putPair("module", pkcs11ModuleName); - } - if (slotId != null) { conf.putPair("slot-id", slotId.toString()); } diff --git a/security/src/main/resources/OSGI-INF/blueprint/config.xml b/security/src/main/resources/OSGI-INF/blueprint/config.xml index 063bfba..d5bd74c 100644 --- a/security/src/main/resources/OSGI-INF/blueprint/config.xml +++ b/security/src/main/resources/OSGI-INF/blueprint/config.xml @@ -92,12 +92,4 @@ - - - - - - diff --git a/util/src/main/java/org/xipki/util/Args.java b/util/src/main/java/org/xipki/util/Args.java index 72fb98c..18bb2a0 100644 --- a/util/src/main/java/org/xipki/util/Args.java +++ b/util/src/main/java/org/xipki/util/Args.java @@ -3,6 +3,7 @@ package org.xipki.util; +import java.util.Arrays; import java.util.Collection; import java.util.Dictionary; import java.util.List; From 05822d4c89be2f0f6c9c6eaea40f582c57e946ff Mon Sep 17 00:00:00 2001 From: Lijun Liao Date: Thu, 7 Nov 2024 17:44:24 +0100 Subject: [PATCH 07/11] Revert "removed instable hsm-proxy module and multiple pkcs11 devices support" This reverts commit cc69e0372beabf1dbf79ba94f5e6e0bf2ae3f2a4. --- .../org/xipki/security/shell/P11Actions.java | 40 +- .../security/shell/QaSecurityActions.java | 18 +- .../security/shell/SecurityCompleters.java | 22 + .../java/org/xipki/security/Securities.java | 2 + .../security/pkcs11/NativeP11Module.java | 28 +- .../xipki/security/pkcs11/NativeP11Slot.java | 7 +- .../pkcs11/P11CryptServiceFactory.java | 9 +- .../pkcs11/P11CryptServiceFactoryImpl.java | 70 +- .../org/xipki/security/pkcs11/P11Module.java | 4 + .../xipki/security/pkcs11/P11ModuleConf.java | 255 ++- .../security/pkcs11/P11SignerFactory.java | 3 +- .../org/xipki/security/pkcs11/P11Slot.java | 30 +- .../org/xipki/security/pkcs11/Pkcs11conf.java | 440 +++-- .../pkcs11/emulator/EmulatorP11Module.java | 14 +- .../pkcs11/emulator/EmulatorP11Slot.java | 9 +- .../pkcs11/hsmproxy/HsmProxyP11Key.java | 78 + .../pkcs11/hsmproxy/HsmProxyP11Module.java | 428 +++++ .../hsmproxy/HsmProxyP11ModuleFactory.java | 34 + .../pkcs11/hsmproxy/HsmProxyP11Slot.java | 375 +++++ .../security/pkcs11/hsmproxy/ProxyAction.java | 82 + .../pkcs11/hsmproxy/ProxyMessage.java | 1465 +++++++++++++++++ .../org/xipki/security/qa/P11SignSpeed.java | 8 +- .../resources/OSGI-INF/blueprint/config.xml | 8 + util/src/main/java/org/xipki/util/Args.java | 1 - 24 files changed, 3212 insertions(+), 218 deletions(-) create mode 100644 security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Key.java create mode 100644 security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Module.java create mode 100644 security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11ModuleFactory.java create mode 100644 security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Slot.java create mode 100644 security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyAction.java create mode 100644 security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyMessage.java diff --git a/security-shell/src/main/java/org/xipki/security/shell/P11Actions.java b/security-shell/src/main/java/org/xipki/security/shell/P11Actions.java index f049a67..b078fb4 100644 --- a/security-shell/src/main/java/org/xipki/security/shell/P11Actions.java +++ b/security-shell/src/main/java/org/xipki/security/shell/P11Actions.java @@ -79,6 +79,10 @@ public static class CsrP11 extends CsrGenAction { + "either keyId or keyLabel must be specified") private String label; + @Option(name = "--module", description = "name of the PKCS#11 module") + @Completion(SecurityCompleters.P11ModuleNameCompleter.class) + private String moduleName = "default"; + @Override protected ConcurrentContentSigner getSigner() throws Exception { SignatureAlgoControl signatureAlgoControl = getSignatureAlgoControl(); @@ -88,13 +92,13 @@ protected ConcurrentContentSigner getSigner() throws Exception { idBytes = Hex.decode(id); } - SignerConf conf = getPkcs11SignerConf(Integer.parseInt(slotIndex), label, + SignerConf conf = getPkcs11SignerConf(moduleName, Integer.parseInt(slotIndex), label, idBytes, 1, null, signatureAlgoControl); return securityFactory.createSigner("PKCS11", conf, (X509Cert[]) null); } public static SignerConf getPkcs11SignerConf( - int slotIndex, String keyLabel, byte[] keyId, int parallelism, + String pkcs11ModuleName, int slotIndex, String keyLabel, byte[] keyId, int parallelism, HashAlgo hashAlgo, SignatureAlgoControl signatureAlgoControl) { Args.positive(parallelism, "parallelism"); @@ -105,6 +109,10 @@ public static SignerConf getPkcs11SignerConf( ConfPairs conf = new ConfPairs(); conf.putPair("parallelism", Integer.toString(parallelism)); + if (pkcs11ModuleName != null && !pkcs11ModuleName.isEmpty()) { + conf.putPair("module", pkcs11ModuleName); + } + conf.putPair("slot", Integer.toString(slotIndex)); if (keyId != null) { @@ -556,21 +564,30 @@ protected char[] getPassword() throws IOException, PasswordResolverException { public abstract static class P11SecurityAction extends SecurityAction { + protected static final String DEFAULT_P11MODULE_NAME = P11CryptServiceFactory.DEFAULT_P11MODULE_NAME; + @Option(name = "--slot", description = "slot index") protected String slotIndex = "0"; // use String instead int so that the default value 0 will be shown in the help. + @Option(name = "--module", description = "name of the PKCS#11 module") + @Completion(SecurityCompleters.P11ModuleNameCompleter.class) + protected String moduleName = DEFAULT_P11MODULE_NAME; + @Reference (optional = true) protected P11CryptServiceFactory p11CryptServiceFactory; protected P11Slot getSlot() throws XiSecurityException, TokenException, IllegalCmdParamException { - P11Module module = getP11Module(); + P11Module module = getP11Module(moduleName); P11SlotId slotId = module.getSlotIdForIndex(Integer.parseInt(slotIndex)); return module.getSlot(slotId); } - protected P11Module getP11Module() - throws XiSecurityException, TokenException { - P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(); + protected P11Module getP11Module(String moduleName) + throws XiSecurityException, TokenException, IllegalCmdParamException { + P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(moduleName); + if (p11Service == null) { + throw new IllegalCmdParamException("undefined module " + moduleName); + } return p11Service.getModule(); } @@ -603,6 +620,10 @@ public static class TokenInfoP11 extends SecurityAction { @Option(name = "--verbose", aliases = "-v", description = "show object information verbosely") private Boolean verbose = Boolean.FALSE; + @Option(name = "--module", description = "name of the PKCS#11 module.") + @Completion(SecurityCompleters.P11ModuleNameCompleter.class) + private String moduleName = P11SecurityAction.DEFAULT_P11MODULE_NAME; + @Option(name = "--slot", description = "slot index") private Integer slotIndex; @@ -614,8 +635,13 @@ public static class TokenInfoP11 extends SecurityAction { @Override protected Object execute0() throws Exception { - P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(); + P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(moduleName); + if (p11Service == null) { + throw new IllegalCmdParamException("undefined module " + moduleName); + } + P11Module module = p11Service.getModule(); + println("module: " + moduleName); println(module.getDescription()); List slots = module.getSlotIds(); diff --git a/security-shell/src/main/java/org/xipki/security/shell/QaSecurityActions.java b/security-shell/src/main/java/org/xipki/security/shell/QaSecurityActions.java index 7b10af8..b502e30 100644 --- a/security-shell/src/main/java/org/xipki/security/shell/QaSecurityActions.java +++ b/security-shell/src/main/java/org/xipki/security/shell/QaSecurityActions.java @@ -183,8 +183,15 @@ public abstract static class BSpeedP11ActionQa extends BatchSpeedActionQa { @Option(name = "--slot", description = "slot index") protected int slotIndex = 0; + @Option(name = "--module", description = "name of the PKCS#11 module.") + @Completion(SecurityCompleters.P11ModuleNameCompleter.class) + protected String moduleName = P11CryptServiceFactory.DEFAULT_P11MODULE_NAME; + protected P11Slot getSlot() throws XiSecurityException, TokenException, IllegalCmdParamException { - P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(); + P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(moduleName); + if (p11Service == null) { + throw new IllegalCmdParamException("undefined module " + moduleName); + } P11Module module = p11Service.getModule(); return module.getSlot(module.getSlotIdForIndex(slotIndex)); } @@ -351,9 +358,16 @@ public abstract static class SpeedP11ActionQa extends SingleSpeedActionQa { @Option(name = "--slot", description = "slot index") protected int slotIndex = 0; + @Option(name = "--module", description = "Name of the PKCS#11 module.") + @Completion(SecurityCompleters.P11ModuleNameCompleter.class) + protected String moduleName = P11CryptServiceFactory.DEFAULT_P11MODULE_NAME; + protected P11Slot getSlot() throws XiSecurityException, TokenException, IllegalCmdParamException { - P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(); + P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(moduleName); + if (p11Service == null) { + throw new IllegalCmdParamException("undefined module " + moduleName); + } P11Module module = p11Service.getModule(); return module.getSlot(module.getSlotIdForIndex(slotIndex)); } diff --git a/security-shell/src/main/java/org/xipki/security/shell/SecurityCompleters.java b/security-shell/src/main/java/org/xipki/security/shell/SecurityCompleters.java index bae05ae..ac3e5d6 100644 --- a/security-shell/src/main/java/org/xipki/security/shell/SecurityCompleters.java +++ b/security-shell/src/main/java/org/xipki/security/shell/SecurityCompleters.java @@ -3,11 +3,16 @@ package org.xipki.security.shell; +import org.apache.karaf.shell.api.action.lifecycle.Reference; import org.apache.karaf.shell.api.action.lifecycle.Service; import org.xipki.security.SignAlgo; +import org.xipki.security.pkcs11.P11CryptServiceFactory; import org.xipki.security.pkcs11.P11Slot.P11KeyUsage; +import org.xipki.shell.DynamicEnumCompleter; import org.xipki.shell.EnumCompleter; +import org.xipki.util.CollectionUtil; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -57,6 +62,23 @@ public static Set parseUsages(List usageTexts) { } // class P11KeyUsageCompleter + @Service + public static class P11ModuleNameCompleter extends DynamicEnumCompleter { + + @Reference (optional = true) + private P11CryptServiceFactory p11CryptServiceFactory; + + @Override + protected Set getEnums() { + Set names = p11CryptServiceFactory.getModuleNames(); + if (CollectionUtil.isEmpty(names)) { + return Collections.emptySet(); + } + return names; + } + + } // class P11ModuleNameCompleter + @Service public static class SecretKeyTypeCompleter extends EnumCompleter { diff --git a/security/src/main/java/org/xipki/security/Securities.java b/security/src/main/java/org/xipki/security/Securities.java index 048ceb8..648fccf 100644 --- a/security/src/main/java/org/xipki/security/Securities.java +++ b/security/src/main/java/org/xipki/security/Securities.java @@ -15,6 +15,7 @@ import org.xipki.security.pkcs11.P11SignerFactory; import org.xipki.security.pkcs11.Pkcs11conf; import org.xipki.security.pkcs11.emulator.EmulatorP11ModuleFactory; +import org.xipki.security.pkcs11.hsmproxy.HsmProxyP11ModuleFactory; import org.xipki.security.pkcs12.P12SignerFactory; import org.xipki.util.CollectionUtil; import org.xipki.util.FileOrValue; @@ -141,6 +142,7 @@ private static List createDefaultFactories() { List factories = new ArrayList<>(3); factories.add(new NativeP11ModuleFactory()); factories.add(new EmulatorP11ModuleFactory()); + factories.add(new HsmProxyP11ModuleFactory()); return factories; } diff --git a/security/src/main/java/org/xipki/security/pkcs11/NativeP11Module.java b/security/src/main/java/org/xipki/security/pkcs11/NativeP11Module.java index 8673623..9c29488 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/NativeP11Module.java +++ b/security/src/main/java/org/xipki/security/pkcs11/NativeP11Module.java @@ -22,8 +22,6 @@ import org.xipki.util.StringUtil; import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Optional; @@ -73,7 +71,7 @@ private NativeP11Module(PKCS11Module module, P11ModuleConf moduleConf) throws To try { slotList = module.getSlotList(false); } catch (Throwable th) { - final String msg = "could not getSlotList of module"; + final String msg = "could not getSlotList of module " + moduleConf.getName(); LogUtil.error(LOG, th, msg); throw new TokenException(msg); } @@ -131,7 +129,7 @@ private NativeP11Module(PKCS11Module module, P11ModuleConf moduleConf) throws To } } - char[] pwd; + List pwd; try { pwd = moduleConf.getPasswordRetriever().getPassword(slotId); } catch (PasswordResolverException ex) { @@ -142,15 +140,15 @@ private NativeP11Module(PKCS11Module module, P11ModuleConf moduleConf) throws To slot.getModule().nameToCode(PKCS11Constants.Category.CKU, getConf().getUserType())).orElseThrow( () -> new TokenException("Unknown user type " + getConf().getUserType())); - PKCS11Token token = new PKCS11Token(slot.getToken(), moduleConf.isReadOnly(), userType, null, - pwd == null ? null : Collections.singletonList(pwd), moduleConf.getNumSessions()); + PKCS11Token token = new PKCS11Token(slot.getToken(), moduleConf.isReadOnly(), userType, + moduleConf.getUserName(), pwd, moduleConf.getNumSessions()); token.setMaxMessageSize(moduleConf.getMaxMessageSize()); if (moduleConf.getNewSessionTimeout() != null) { token.setTimeOutWaitNewSession(moduleConf.getNewSessionTimeout()); } - P11Slot p11Slot = new NativeP11Slot(slotId, token, moduleConf.getP11NewObjectConf(), - moduleConf.getSecretKeyTypes(), moduleConf.getKeyPairTypes()); + P11Slot p11Slot = new NativeP11Slot(moduleConf.getName(), slotId, token , moduleConf.getP11MechanismFilter(), + moduleConf.getP11NewObjectConf(), moduleConf.getSecretKeyTypes(), moduleConf.getKeyPairTypes()); slots.add(p11Slot); } @@ -179,7 +177,7 @@ public static P11Module getInstance(P11ModuleConf moduleConf) throws TokenExcept try { module = PKCS11Module.getInstance(path); } catch (IOException ex) { - final String msg = "could not load the PKCS#11 module: " + path; + final String msg = "could not load the PKCS#11 module " + moduleConf.getName() + ": " + path; LogUtil.error(LOG, ex, msg); throw new TokenException(msg, ex); } @@ -189,7 +187,7 @@ public static P11Module getInstance(P11ModuleConf moduleConf) throws TokenExcept } catch (PKCS11Exception ex) { if (ex.getErrorCode() != PKCS11Constants.CKR_CRYPTOKI_ALREADY_INITIALIZED) { LogUtil.error(LOG, ex); - closeModule(moduleConf.getNativeLibrary(), module); + close(moduleConf.getName(), module); throw ex; } else { LOG.info("PKCS#11 module already initialized"); @@ -201,7 +199,7 @@ public static P11Module getInstance(P11ModuleConf moduleConf) throws TokenExcept } } catch (Throwable th) { LOG.error("unexpected Exception", th); - closeModule(moduleConf.getNativeLibrary(), module); + close(moduleConf.getName(), module); throw new TokenException(th.getMessage()); } @@ -223,19 +221,19 @@ public void close() { } } - closeModule(conf.getNativeLibrary(), module); + close(conf.getNativeLibrary(), module); } - private static void closeModule(String path, PKCS11Module module) { + private static void close(String modulePath, PKCS11Module module) { if (module == null) { return; } - LOG.info("close PKCS#11 module {}", path); + LOG.info("close PKCS#11 module: {}", modulePath); try { module.finalize(null); } catch (Throwable th) { - LogUtil.error(LOG, th, "could not close module " + path); + LogUtil.error(LOG, th, "could not close module " + modulePath); } } } diff --git a/security/src/main/java/org/xipki/security/pkcs11/NativeP11Slot.java b/security/src/main/java/org/xipki/security/pkcs11/NativeP11Slot.java index 86762e8..5282a37 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/NativeP11Slot.java +++ b/security/src/main/java/org/xipki/security/pkcs11/NativeP11Slot.java @@ -37,6 +37,7 @@ import org.xipki.pkcs11.wrapper.TokenInfo; import org.xipki.pkcs11.wrapper.params.ExtraParams; import org.xipki.security.EdECConstants; +import org.xipki.security.pkcs11.P11ModuleConf.P11MechanismFilter; import org.xipki.security.pkcs11.P11ModuleConf.P11NewObjectConf; import org.xipki.security.util.KeyUtil; import org.xipki.util.Args; @@ -155,10 +156,10 @@ class NativeP11Slot extends P11Slot { private String libDesc; - NativeP11Slot(P11SlotId slotId, PKCS11Token token, + NativeP11Slot(String moduleName, P11SlotId slotId, PKCS11Token token, P11MechanismFilter mechanismFilter, P11NewObjectConf newObjectConf, List secretKeyTypes, List keyPairTypes) throws TokenException { - super(slotId, token.isReadOnly(), secretKeyTypes, keyPairTypes, newObjectConf); + super(moduleName, slotId, token.isReadOnly(), secretKeyTypes, keyPairTypes, newObjectConf); if (slotId.getId() != token.getTokenId()) { throw new IllegalArgumentException("slotId != token.getTokenId"); } @@ -171,7 +172,7 @@ class NativeP11Slot extends P11Slot { libDesc = ""; } - initMechanisms(getSupportedMechanisms()); + initMechanisms(getSupportedMechanisms(), mechanismFilter); rsaKeyPairGenMech = supportsMechanism(CKM_RSA_X9_31_KEY_PAIR_GEN, CKF_GENERATE_KEY_PAIR) ? CKM_RSA_X9_31_KEY_PAIR_GEN : CKM_RSA_PKCS_KEY_PAIR_GEN; diff --git a/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactory.java b/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactory.java index c1d896a..23b51e8 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactory.java +++ b/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactory.java @@ -7,6 +7,7 @@ import org.xipki.security.XiSecurityException; import java.io.Closeable; +import java.util.Set; /** * Factory to create {@link P11CryptService}. @@ -17,14 +18,20 @@ public interface P11CryptServiceFactory extends Closeable { + String DEFAULT_P11MODULE_NAME = "default"; + /** * Gets the {@link P11CryptService} of the given module {@code moduleName}. + * @param moduleName + * Module name. {@code null} for default module name. * @return the {@link P11CryptService} of the given module. * @throws TokenException * if PKCS#11 token error occurs. * @throws XiSecurityException * if security error occurs. */ - P11CryptService getP11CryptService() throws TokenException, XiSecurityException; + P11CryptService getP11CryptService(String moduleName) throws TokenException, XiSecurityException; + + Set getModuleNames(); } diff --git a/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactoryImpl.java b/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactoryImpl.java index 65ce210..4619a2d 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactoryImpl.java +++ b/security/src/main/java/org/xipki/security/pkcs11/P11CryptServiceFactoryImpl.java @@ -32,9 +32,11 @@ public class P11CryptServiceFactoryImpl implements P11CryptServiceFactory { private static final Logger LOG = LoggerFactory.getLogger(P11CryptServiceFactoryImpl.class); - private P11CryptService service; + private static final Map services = new HashMap<>(); - private P11ModuleConf moduleConf; + private Map moduleConfs; + + private Set moduleNames; private String pkcs11ConfFile; @@ -47,7 +49,7 @@ public P11CryptServiceFactoryImpl(P11ModuleFactoryRegister p11ModuleFactoryRegis } public synchronized void init() throws InvalidConfException { - if (moduleConf != null) { + if (moduleConfs != null) { return; } @@ -65,31 +67,62 @@ public synchronized void init() throws InvalidConfException { } } - this.moduleConf = new P11ModuleConf(pkcs11Conf); + try { + Map confs = geModuleConfs(); + this.moduleConfs = Collections.unmodifiableMap(confs); + this.moduleNames = Set.copyOf(confs.keySet()); + } catch (RuntimeException ex) { + throw new InvalidConfException("could not create P11Conf: " + ex.getMessage(), ex); + } } // method init - @Override - public synchronized P11CryptService getP11CryptService() - throws TokenException { + private Map geModuleConfs() throws InvalidConfException { + List moduleTypes = pkcs11Conf.getModules(); + List mechanismSets = pkcs11Conf.getMechanismSets(); + + Map confs = new HashMap<>(); + for (Pkcs11conf.Module moduleType : moduleTypes) { + P11ModuleConf conf = new P11ModuleConf(moduleType, mechanismSets); + confs.put(conf.getName(), conf); + } + + if (!confs.containsKey(P11CryptServiceFactory.DEFAULT_P11MODULE_NAME)) { + throw new InvalidConfException("module '" + P11CryptServiceFactory.DEFAULT_P11MODULE_NAME + "' is not defined"); + } + return confs; + } + + public synchronized P11CryptService getP11CryptService(String moduleName) + throws XiSecurityException, TokenException { try { init(); } catch (InvalidConfException ex) { throw new IllegalStateException("could not initialize P11CryptServiceFactory: " + ex.getMessage(), ex); } - if (moduleConf == null) { + if (moduleConfs == null) { throw new IllegalStateException("please set pkcs11ConfFile and then call init() first"); } - if (service == null) { - P11Module p11Module = p11ModuleFactoryRegister.getP11Module(moduleConf); - service = new P11CryptService(p11Module); - LOG.info("initialized PKCS#11 module \n{}", service.getModule().getDescription()); + final String name = getModuleName(moduleName); + P11ModuleConf conf = Optional.ofNullable(moduleConfs.get(name)).orElseThrow(() -> + new XiSecurityException("PKCS#11 module " + name + " is not defined")); + + P11CryptService instance = services.get(name); + if (instance == null) { + P11Module p11Module = p11ModuleFactoryRegister.getP11Module(conf); + instance = new P11CryptService(p11Module); + LOG.info("added PKCS#11 module {}\n{}", name, instance.getModule().getDescription()); + services.put(name, instance); } - return service; + return instance; } // method getP11CryptService + private String getModuleName(String moduleName) { + return (moduleName == null) ? DEFAULT_P11MODULE_NAME : moduleName; + } + public void setPkcs11ConfFile(String confFile) { this.pkcs11ConfFile = StringUtil.isBlank(confFile) ? null : IoUtil.expandFilepath(confFile); this.pkcs11Conf = null; @@ -105,6 +138,17 @@ public void setPkcs11Conf(Pkcs11conf conf) throws InvalidConfException { @Override public void close() { + services.clear(); + } + + @Override + public Set getModuleNames() { + try { + init(); + } catch (InvalidConfException ex) { + throw new IllegalStateException("could not initialize P11CryptServiceFactory: " + ex.getMessage(), ex); + } + return moduleNames; } } diff --git a/security/src/main/java/org/xipki/security/pkcs11/P11Module.java b/security/src/main/java/org/xipki/security/pkcs11/P11Module.java index 68926da..45d15df 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/P11Module.java +++ b/security/src/main/java/org/xipki/security/pkcs11/P11Module.java @@ -36,6 +36,10 @@ public P11Module(P11ModuleConf conf) { public abstract String getDescription(); + public String getName() { + return conf.getName(); + } + public boolean isReadOnly() { return conf.isReadOnly(); } diff --git a/security/src/main/java/org/xipki/security/pkcs11/P11ModuleConf.java b/security/src/main/java/org/xipki/security/pkcs11/P11ModuleConf.java index 5d202f6..5c67b64 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/P11ModuleConf.java +++ b/security/src/main/java/org/xipki/security/pkcs11/P11ModuleConf.java @@ -8,13 +8,16 @@ import org.xipki.password.PasswordResolverException; import org.xipki.password.Passwords; import org.xipki.pkcs11.wrapper.PKCS11Constants; +import org.xipki.pkcs11.wrapper.PKCS11Module; import org.xipki.util.Args; import org.xipki.util.CollectionUtil; import org.xipki.util.StringUtil; import org.xipki.util.exception.InvalidConfException; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -59,17 +62,135 @@ boolean match(P11SlotId slotId) { } // class P11SlotIdFilter + private static final class MechanismSet { + private Set includeMechanisms; + private Set excludeMechanisms; + } + + private static final class P11SingleMechanismFilter { + + private static final Object NULL_MODULE = new Object(); + + private final Set slots; + + private final Collection includeMechanisms; + + private final Collection excludeMechanisms; + + private Object module; + + private final Set includeMechanismCodes = new HashSet<>(); + + private final Set excludeMechanismCodes = new HashSet<>(); + + private P11SingleMechanismFilter(Set slots, Collection includeMechanisms, + Collection excludeMechanisms) { + this.slots = slots; + this.includeMechanisms = CollectionUtil.isEmpty(includeMechanisms) ? null : includeMechanisms; + this.excludeMechanisms = CollectionUtil.isEmpty(excludeMechanisms) ? null : excludeMechanisms; + } + + public boolean match(P11SlotId slot) { + if (slots == null) { + return true; + } + for (P11SlotIdFilter m : slots) { + if (m.match(slot)) { + return true; + } + } + + return false; + } + + public boolean isMechanismSupported(long mechanism, PKCS11Module module) { + if (includeMechanisms == null && excludeMechanisms == null) { + return true; + } + + synchronized (this) { + boolean computeCodes = (module != null) ? (this.module != module) : (this.module != NULL_MODULE); + if (computeCodes) { + includeMechanismCodes.clear(); + excludeMechanismCodes.clear(); + + if (includeMechanisms != null) { + for (String mechName : includeMechanisms) { + Long mechCode = (module != null) ? module.nameToCode(PKCS11Constants.Category.CKM, mechName) + : PKCS11Constants.nameToCode(PKCS11Constants.Category.CKM, mechName); + if (mechCode != null) { + includeMechanismCodes.add(mechCode); + } + } + } + + if (excludeMechanisms != null) { + for (String mechName : excludeMechanisms) { + Long mechCode = (module != null) ? module.nameToCode(PKCS11Constants.Category.CKM, mechName) + : PKCS11Constants.nameToCode(PKCS11Constants.Category.CKM, mechName); + if (mechCode != null) { + excludeMechanismCodes.add(mechCode); + } + } + } + + this.module = (module != null) ? module : NULL_MODULE; + } + } + + if (excludeMechanismCodes.contains(mechanism)) { + return false; + } + + return includeMechanisms == null || includeMechanismCodes.contains(mechanism); + } + + } // class P11SingleMechanismFilter + + public static class P11MechanismFilter { + + private final List singleFilters; + + P11MechanismFilter() { + singleFilters = new LinkedList<>(); + } + + void addEntry(Set slots, Collection includeMechanisms, + Collection excludeMechanisms) { + singleFilters.add( + new P11SingleMechanismFilter(slots, + includeMechanisms, + excludeMechanisms)); + } + + public boolean isMechanismPermitted(P11SlotId slotId, long mechanism, PKCS11Module module) { + Args.notNull(slotId, "slotId"); + if (CollectionUtil.isEmpty(singleFilters)) { + return true; + } + + for (P11SingleMechanismFilter sr : singleFilters) { + if (sr.match(slotId)) { + return sr.isMechanismSupported(mechanism, module); + } + } + + return true; + } + + } // class P11MechanismFilter + public static class P11PasswordsRetriever { private static final class P11SinglePasswordRetriever { private final Set slots; - private final String password; + private final List passwords; - private P11SinglePasswordRetriever(Set slots, String password) { + private P11SinglePasswordRetriever(Set slots, List passwords) { this.slots = slots; - this.password = password; + this.passwords = CollectionUtil.isEmpty(passwords) ? null : passwords; } public boolean match(P11SlotId slot) { @@ -85,12 +206,17 @@ public boolean match(P11SlotId slot) { return false; } - public char[] getPassword() throws PasswordResolverException { - if (password == null) { + public List getPasswords() throws PasswordResolverException { + if (passwords == null) { return null; } - return Passwords.resolvePassword(password); + List ret = new ArrayList<>(passwords.size()); + for (String password : passwords) { + ret.add(Passwords.resolvePassword(password)); + } + + return ret; } } // class P11PasswordsRetriever @@ -101,11 +227,11 @@ public char[] getPassword() throws PasswordResolverException { singleRetrievers = new LinkedList<>(); } - void addPasswordEntry(Set slots, String password) { - singleRetrievers.add(new P11SinglePasswordRetriever(slots, password)); + void addPasswordEntry(Set slots, List passwords) { + singleRetrievers.add(new P11SinglePasswordRetriever(slots, passwords)); } - public char[] getPassword(P11SlotId slotId) throws PasswordResolverException { + public List getPassword(P11SlotId slotId) throws PasswordResolverException { Args.notNull(slotId, "slotId"); if (CollectionUtil.isEmpty(singleRetrievers)) { return null; @@ -113,7 +239,7 @@ public char[] getPassword(P11SlotId slotId) throws PasswordResolverException { for (P11SinglePasswordRetriever sr : singleRetrievers) { if (sr.match(slotId)) { - return sr.getPassword(); + return sr.getPasswords(); } } @@ -159,6 +285,8 @@ public void setIdLength(int idLength) { private static final Logger LOG = LoggerFactory.getLogger(P11ModuleConf.class); + private final String name; + private final String type; private final String nativeLibrary; @@ -171,10 +299,14 @@ public void setIdLength(int idLength) { private final P11PasswordsRetriever passwordRetriever; + private final P11MechanismFilter mechanismFilter; + private final Integer newSessionTimeout; private final String userType; + private final char[] userName; + private boolean readOnly; private int maxMessageSize; @@ -187,22 +319,25 @@ public void setIdLength(int idLength) { private List keyPairTypes; - public P11ModuleConf(Pkcs11conf conf) + public P11ModuleConf( + Pkcs11conf.Module moduleType, List mechanismSets) throws InvalidConfException { - this.readOnly = conf.isReadonly(); + this.name = Args.notNull(moduleType, "moduleType").getName(); + this.readOnly = moduleType.isReadonly(); - this.userType = conf.getUser().toUpperCase(); + this.userType = moduleType.getUser().toUpperCase(); + this.userName = (moduleType.getUserName() == null) ? null : moduleType.getUserName().toCharArray(); - this.maxMessageSize = conf.getMaxMessageSize(); - this.type = conf.getType(); + this.maxMessageSize = moduleType.getMaxMessageSize(); + this.type = moduleType.getType(); if (maxMessageSize < 256) { throw new InvalidConfException("invalid maxMessageSize (< 256): " + maxMessageSize); } - this.numSessions = conf.getNumSessions(); - this.newSessionTimeout = conf.getNewSessionTimeout(); + this.numSessions = moduleType.getNumSessions(); + this.newSessionTimeout = moduleType.getNewSessionTimeout(); - List list = conf.getSecretKeyTypes(); + List list = moduleType.getSecretKeyTypes(); if (list == null) { this.secretKeyTypes = null; } else { @@ -216,7 +351,7 @@ public P11ModuleConf(Pkcs11conf conf) this.secretKeyTypes = Collections.unmodifiableList(ll); } - list = conf.getKeyPairTypes(); + list = moduleType.getKeyPairTypes(); if (list == null) { this.keyPairTypes = null; } else { @@ -230,34 +365,83 @@ public P11ModuleConf(Pkcs11conf conf) this.keyPairTypes = Collections.unmodifiableList(ll); } + Map mechanismSetsMap = new HashMap<>(); + // parse mechanismSets + if (mechanismSets != null) { + for (Pkcs11conf.MechanismSet m : mechanismSets) { + String name = m.getName(); + if (mechanismSetsMap.containsKey(name)) { + throw new InvalidConfException("Duplication mechanismSets named " + name); + } + + MechanismSet mechanismSet = new MechanismSet(); + mechanismSet.includeMechanisms = new HashSet<>(); + mechanismSet.excludeMechanisms = new HashSet<>(); + + for (String mechStr : m.getMechanisms()) { + mechStr = mechStr.trim().toUpperCase(); + if (mechStr.equals("ALL")) { + mechanismSet.includeMechanisms = null; // accept all mechanisms + break; + } + + mechanismSet.includeMechanisms.add(mechStr); + } + + for (String mechStr : m.getExcludeMechanisms()) { + mechanismSet.excludeMechanisms.add(mechStr.trim().toUpperCase()); + } + + mechanismSetsMap.put(name, mechanismSet); + } + } + + // Mechanism filter + mechanismFilter = new P11MechanismFilter(); + + List mechFilters = moduleType.getMechanismFilters(); + if (CollectionUtil.isNotEmpty(mechFilters)) { + for (Pkcs11conf.MechanismFilter filterType : mechFilters) { + Set slots = getSlotIdFilters(filterType.getSlots()); + String mechanismSetName = filterType.getMechanismSet(); + + MechanismSet mechanismSet = mechanismSetsMap.get(mechanismSetName); + if (mechanismSet == null) { + throw new InvalidConfException("MechanismSet '" + mechanismSetName + "' is not defined"); + } else { + mechanismFilter.addEntry(slots, mechanismSet.includeMechanisms, mechanismSet.excludeMechanisms); + } + } + } + // Password retriever passwordRetriever = new P11PasswordsRetriever(); - List passwordsList = conf.getPasswordSets(); + List passwordsList = moduleType.getPasswordSets(); if (CollectionUtil.isNotEmpty(passwordsList)) { for (Pkcs11conf.PasswordSet passwordType : passwordsList) { Set slots = getSlotIdFilters(passwordType.getSlots()); - passwordRetriever.addPasswordEntry(slots, passwordType.getPassword()); + passwordRetriever.addPasswordEntry(slots, new ArrayList<>(passwordType.getPasswords())); } } - includeSlots = getSlotIdFilters(conf.getIncludeSlots()); - excludeSlots = getSlotIdFilters(conf.getExcludeSlots()); + includeSlots = getSlotIdFilters(moduleType.getIncludeSlots()); + excludeSlots = getSlotIdFilters(moduleType.getExcludeSlots()); final String osName = System.getProperty("os.name").toLowerCase(); - Pkcs11conf.NativeLibrary matchLibrary = getNativeLibrary(conf, osName); + Pkcs11conf.NativeLibrary matchLibrary = getNativeLibrary(moduleType, osName); this.nativeLibrary = matchLibrary.getPath(); this.nativeLibraryProperties = matchLibrary.getProperties(); - this.newObjectConf = (conf.getNewObjectConf() == null) ? new P11NewObjectConf() - : new P11NewObjectConf(conf.getNewObjectConf()); + this.newObjectConf = (moduleType.getNewObjectConf() == null) ? new P11NewObjectConf() + : new P11NewObjectConf(moduleType.getNewObjectConf()); } // constructor - private static Pkcs11conf.NativeLibrary getNativeLibrary(Pkcs11conf conf, String osName) + private static Pkcs11conf.NativeLibrary getNativeLibrary(Pkcs11conf.Module moduleType, String osName) throws InvalidConfException { Pkcs11conf.NativeLibrary matchLibrary = null; - for (Pkcs11conf.NativeLibrary library : conf.getNativeLibraries()) { + for (Pkcs11conf.NativeLibrary library : moduleType.getNativeLibraries()) { List osNames = library.getOperationSystems(); if (CollectionUtil.isEmpty(osNames)) { matchLibrary = library; @@ -277,6 +461,10 @@ private static Pkcs11conf.NativeLibrary getNativeLibrary(Pkcs11conf conf, String return matchLibrary; } + public String getName() { + return name; + } + public String getType() { return type; } @@ -317,6 +505,10 @@ public String getUserType() { return userType; } + public char[] getUserName() { + return userName; + } + public P11PasswordsRetriever getPasswordRetriever() { return passwordRetriever; } @@ -381,12 +573,15 @@ public boolean isSlotIncluded(P11SlotId slotId) { return true; } // method isSlotIncluded + public P11MechanismFilter getP11MechanismFilter() { + return mechanismFilter; + } + public P11NewObjectConf getP11NewObjectConf() { return newObjectConf; } - private static Set getSlotIdFilters(List slotTypes) - throws InvalidConfException { + private static Set getSlotIdFilters(List slotTypes) throws InvalidConfException { if (CollectionUtil.isEmpty(slotTypes)) { return null; } diff --git a/security/src/main/java/org/xipki/security/pkcs11/P11SignerFactory.java b/security/src/main/java/org/xipki/security/pkcs11/P11SignerFactory.java index e607a91..00c3fc4 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/P11SignerFactory.java +++ b/security/src/main/java/org/xipki/security/pkcs11/P11SignerFactory.java @@ -88,6 +88,7 @@ public ConcurrentContentSigner newSigner(String type, SignerConf conf, X509Cert[ } } + String moduleName = conf.getConfValue("module"); str = conf.getConfValue("slot"); Integer slotIndex = (str == null) ? null : Integer.parseInt(str); @@ -111,7 +112,7 @@ public ConcurrentContentSigner newSigner(String type, SignerConf conf, X509Cert[ P11Slot slot; try { - P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(); + P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(moduleName); P11Module module = p11Service.getModule(); P11SlotId p11SlotId = (slotId != null) ? module.getSlotIdForId(slotId) : module.getSlotIdForIndex(slotIndex); diff --git a/security/src/main/java/org/xipki/security/pkcs11/P11Slot.java b/security/src/main/java/org/xipki/security/pkcs11/P11Slot.java index ae2e2f7..b4cda56 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/P11Slot.java +++ b/security/src/main/java/org/xipki/security/pkcs11/P11Slot.java @@ -14,6 +14,7 @@ import org.xipki.pkcs11.wrapper.TokenException; import org.xipki.pkcs11.wrapper.params.ExtraParams; import org.xipki.security.EdECConstants; +import org.xipki.security.pkcs11.P11ModuleConf.P11MechanismFilter; import org.xipki.security.pkcs11.P11ModuleConf.P11NewObjectConf; import org.xipki.security.util.DSAParameterCache; import org.xipki.util.Args; @@ -138,6 +139,8 @@ public void setUsages(Set usages) { private static final Logger LOG = LoggerFactory.getLogger(P11Slot.class); + protected final String moduleName; + protected final P11SlotId slotId; private final boolean readOnly; @@ -152,9 +155,10 @@ public void setUsages(Set usages) { protected final P11NewObjectConf newObjectConf; protected P11Slot( - P11SlotId slotId, boolean readOnly, + String moduleName, P11SlotId slotId, boolean readOnly, List secretKeyTypes, List keyPairTypes, P11NewObjectConf newObjectConf) { this.newObjectConf = Args.notNull(newObjectConf, "newObjectConf"); + this.moduleName = Args.notBlank(moduleName, "moduleName"); this.slotId = Args.notNull(slotId, "slotId"); this.readOnly = readOnly; this.secretKeyTypes = secretKeyTypes; @@ -377,19 +381,25 @@ protected PKCS11Module getPKCS11Module() { @Override public abstract void close(); - protected void initMechanisms(Map supportedMechanisms) { + protected void initMechanisms(Map supportedMechanisms, P11MechanismFilter mechanismFilter) { mechanisms.clear(); + List ignoreMechs = new ArrayList<>(); PKCS11Module pkcs11Module = getPKCS11Module(); for (Map.Entry entry : supportedMechanisms.entrySet()) { long mech = entry.getKey(); - mechanisms.put(mech, entry.getValue()); + if (mechanismFilter.isMechanismPermitted(slotId, mech, pkcs11Module)) { + mechanisms.put(mech, entry.getValue()); + } else { + ignoreMechs.add(mech); + } } + Collections.sort(ignoreMechs); if (LOG.isInfoEnabled()) { StringBuilder sb = new StringBuilder(); - sb.append("initialized slot ").append(slotId); + sb.append("initialized module ").append(moduleName).append(", slot ").append(slotId); sb.append("\nsupported mechanisms:\n"); if (mechanisms.isEmpty()) { @@ -398,6 +408,14 @@ protected void initMechanisms(Map supportedMechanisms) { printMechanisms(sb, mechanisms); } + sb.append("\nsupported by device but ignored mechanisms:\n"); + if (ignoreMechs.isEmpty()) { + sb.append(" NONE\n"); + } else { + for (Long mech : ignoreMechs) { + sb.append("\n ").append(mechanismCodeToName(mech)); + } + } LOG.info(sb.toString()); } } @@ -428,6 +446,10 @@ public void assertMechanismSupported(long mechanism, long flagBit) throws TokenE } } + public String getModuleName() { + return moduleName; + } + public P11SlotId getSlotId() { return slotId; } diff --git a/security/src/main/java/org/xipki/security/pkcs11/Pkcs11conf.java b/security/src/main/java/org/xipki/security/pkcs11/Pkcs11conf.java index 3bd910b..27cdc82 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/Pkcs11conf.java +++ b/security/src/main/java/org/xipki/security/pkcs11/Pkcs11conf.java @@ -19,175 +19,306 @@ public class Pkcs11conf extends ValidableConf { - private String type; + public static class MechanismFilter extends ValidableConf { - private List nativeLibraries; + /** + * name of the mechanismSet. + */ + private String mechanismSet; - private NewObjectConf newObjectConf; + /** + * To which slots the mechanism should be applied. + * Absent for all slots. + */ + private List slots; - /** - * Which slots should be considered. Absent for all slots. - */ - private List includeSlots; + public String getMechanismSet() { + return mechanismSet; + } - /** - * Which slots should be considered. Absent for no slot. - */ - private List excludeSlots; + public void setMechanismSet(String mechanismSet) { + this.mechanismSet = mechanismSet; + } - private boolean readonly; + public List getSlots() { + if (slots == null) { + slots = new LinkedList<>(); + } + return slots; + } - private List secretKeyTypes; + public void setSlots(List slots) { + this.slots = slots; + } - private List keyPairTypes; + @Override + public void validate() throws InvalidConfException { + notBlank(mechanismSet, "mechanismSet"); + validate(slots); + } - private Integer numSessions; + } // class MechanismFilter - /** - * specify the user type, use either the long value or identifier as - * defined in the PKCS#11 standards. In version up to 2.40 the - * following users are defined. - * - 0 or 0x0 or CKU_SO - * - 1 or 0x1 or CKU_USER - * - 2 or 0x2 or CKU_CONTEXT_SPECIFIC - * For vendor user type, only the long value is allowed. - */ - private String user; + public static class MechanismSet extends ValidableConf { - /** - * maximal size of the message sent to the PKCS#11 device. - */ - private Integer maxMessageSize; + private String name; - /** - * Timeout to borrow a new session. - */ - private Integer newSessionTimeout; + /** + * The mechanism. Set mechanism to ALL to accept all available mechanisms. + */ + private List mechanisms; - private List passwordSets; + /** + * The mechanism to be excluded. + */ + private List excludeMechanisms; - public String getType() { - return type; - } + public String getName() { + return name; + } - public void setType(String type) { - this.type = type; - } + public void setName(String name) { + this.name = name; + } - public List getNativeLibraries() { - if (nativeLibraries == null) { - nativeLibraries = new LinkedList<>(); + public List getMechanisms() { + if (mechanisms == null) { + mechanisms = new LinkedList<>(); + } + return mechanisms; } - return nativeLibraries; - } - public void setNativeLibraries(List nativeLibraries) { - this.nativeLibraries = nativeLibraries; - } + public void setMechanisms(List mechanisms) { + this.mechanisms = mechanisms; + } - public NewObjectConf getNewObjectConf() { - return newObjectConf; - } + public List getExcludeMechanisms() { + if (excludeMechanisms == null) { + excludeMechanisms = new LinkedList<>(); + } + return excludeMechanisms; + } - public void setNewObjectConf(NewObjectConf newObjectConf) { - this.newObjectConf = newObjectConf; - } + public void setExcludeMechanisms(List excludeMechanisms) { + this.excludeMechanisms = excludeMechanisms; + } - public List getIncludeSlots() { - if (includeSlots == null) { - includeSlots = new LinkedList<>(); + @Override + public void validate() throws InvalidConfException { + notBlank(name, "name"); + notEmpty(mechanisms, "mechanisms"); } - return includeSlots; - } - public void setIncludeSlots(List includeSlots) { - this.includeSlots = includeSlots; - } + } // class MechanismSet + + public static class Module extends ValidableConf { + + private String name; + + private String type; + + private List nativeLibraries; + + private NewObjectConf newObjectConf; + + /** + * Which slots should be considered. Absent for all slots. + */ + private List includeSlots; + + /** + * Which slots should be considered. Absent for no slot. + */ + private List excludeSlots; + + private boolean readonly; + + private List secretKeyTypes; + + private List keyPairTypes; + + private Integer numSessions; + + /** + * specify the user type, use either the long value or identifier as + * defined in the PKCS#11 standards. In version up to 2.40 the + * following users are defined. + * - 0 or 0x0 or CKU_SO + * - 1 or 0x1 or CKU_USER + * - 2 or 0x2 or CKU_CONTEXT_SPECIFIC + * For vendor user type, only the long value is allowed. + */ + private String user; + + private String userName; + + /** + * maximal size of the message sent to the PKCS#11 device. + */ + private Integer maxMessageSize; + + /** + * Timeout to borrow a new session. + */ + private Integer newSessionTimeout; + + private List passwordSets; + + private List mechanismFilters; - public List getExcludeSlots() { - if (excludeSlots == null) { - excludeSlots = new LinkedList<>(); + public String getName() { + return name; } - return excludeSlots; - } - public void setExcludeSlots(List excludeSlots) { - this.excludeSlots = excludeSlots; - } + public void setName(String name) { + this.name = name; + } - public boolean isReadonly() { - return readonly; - } + public String getType() { + return type; + } - public void setReadonly(boolean readonly) { - this.readonly = readonly; - } + public void setType(String type) { + this.type = type; + } - public List getPasswordSets() { - if (passwordSets == null) { - passwordSets = new LinkedList<>(); + public List getNativeLibraries() { + if (nativeLibraries == null) { + nativeLibraries = new LinkedList<>(); + } + return nativeLibraries; } - return passwordSets; - } - public void setPasswordSets(List passwordSets) { - this.passwordSets = passwordSets; - } + public void setNativeLibraries(List nativeLibraries) { + this.nativeLibraries = nativeLibraries; + } - public void setUser(String user) { - this.user = user; - } + public NewObjectConf getNewObjectConf() { + return newObjectConf; + } - public void setMaxMessageSize(Integer maxMessageSize) { - this.maxMessageSize = maxMessageSize; - } + public void setNewObjectConf(NewObjectConf newObjectConf) { + this.newObjectConf = newObjectConf; + } - public String getUser() { - return user == null ? "CKU_USER" : user; - } + public List getIncludeSlots() { + if (includeSlots == null) { + includeSlots = new LinkedList<>(); + } + return includeSlots; + } - public int getMaxMessageSize() { - return maxMessageSize == null ? 16384 : maxMessageSize; - } + public void setIncludeSlots(List includeSlots) { + this.includeSlots = includeSlots; + } - public List getSecretKeyTypes() { - return secretKeyTypes; - } + public List getExcludeSlots() { + if (excludeSlots == null) { + excludeSlots = new LinkedList<>(); + } + return excludeSlots; + } - public void setSecretKeyTypes(List secretKeyTypes) { - this.secretKeyTypes = secretKeyTypes; - } + public void setExcludeSlots(List excludeSlots) { + this.excludeSlots = excludeSlots; + } - public List getKeyPairTypes() { - return keyPairTypes; - } + public boolean isReadonly() { + return readonly; + } - public void setKeyPairTypes(List keyPairTypes) { - this.keyPairTypes = keyPairTypes; - } + public void setReadonly(boolean readonly) { + this.readonly = readonly; + } - public Integer getNumSessions() { - return numSessions; - } + public List getPasswordSets() { + if (passwordSets == null) { + passwordSets = new LinkedList<>(); + } + return passwordSets; + } - public void setNumSessions(Integer numSessions) { - this.numSessions = numSessions; - } + public void setPasswordSets(List passwordSets) { + this.passwordSets = passwordSets; + } - public Integer getNewSessionTimeout() { - return newSessionTimeout; - } + public List getMechanismFilters() { + if (mechanismFilters == null) { + mechanismFilters = new LinkedList<>(); + } + return mechanismFilters; + } - public void setNewSessionTimeout(Integer newSessionTimeout) { - this.newSessionTimeout = newSessionTimeout; - } + public void setMechanismFilters(List mechanismFilters) { + this.mechanismFilters = mechanismFilters; + } - @Override - public void validate() throws InvalidConfException { - notBlank(type, "type"); - notEmpty(nativeLibraries, "nativeLibraries"); - validate(nativeLibraries, includeSlots, excludeSlots, passwordSets); - } + public void setUser(String user) { + this.user = user; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public void setMaxMessageSize(Integer maxMessageSize) { + this.maxMessageSize = maxMessageSize; + } + + public String getUser() { + return user == null ? "CKU_USER" : user; + } + + public String getUserName() { + return userName; + } + + public int getMaxMessageSize() { + return maxMessageSize == null ? 16384 : maxMessageSize; + } + + public List getSecretKeyTypes() { + return secretKeyTypes; + } + + public void setSecretKeyTypes(List secretKeyTypes) { + this.secretKeyTypes = secretKeyTypes; + } + + public List getKeyPairTypes() { + return keyPairTypes; + } + + public void setKeyPairTypes(List keyPairTypes) { + this.keyPairTypes = keyPairTypes; + } + + public Integer getNumSessions() { + return numSessions; + } + + public void setNumSessions(Integer numSessions) { + this.numSessions = numSessions; + } + + public Integer getNewSessionTimeout() { + return newSessionTimeout; + } + + public void setNewSessionTimeout(Integer newSessionTimeout) { + this.newSessionTimeout = newSessionTimeout; + } + + @Override + public void validate() throws InvalidConfException { + notBlank(name, "name"); + notBlank(type, "type"); + notEmpty(nativeLibraries, "nativeLibraries"); + + validate(nativeLibraries, includeSlots, excludeSlots, passwordSets, mechanismFilters); + } + + } // class Module public static class NativeLibrary extends ValidableConf { @@ -266,7 +397,7 @@ public static class PasswordSet extends ValidableConf { private List slots; - private String password; + private List passwords; public List getSlots() { if (slots == null) { @@ -279,16 +410,20 @@ public void setSlots(List slots) { this.slots = slots; } - public String getPassword() { - return password; + public List getPasswords() { + if (passwords == null) { + passwords = new LinkedList<>(); + } + return passwords; } - public void setPassword(String password) { - this.password = password; + public void setPasswords(List passwords) { + this.passwords = passwords; } @Override public void validate() throws InvalidConfException { + notEmpty(passwords, "passwords"); } } // class PasswordSet @@ -324,4 +459,47 @@ public void validate() throws InvalidConfException { } // class Slot + /** + * exactly one module must have the name 'default'. + */ + private List modules; + + private List mechanismSets; + + public List getModules() { + return modules; + } + + public void setModules(List modules) { + if (modules == null) { + modules = new LinkedList<>(); + } + this.modules = modules; + } + + public List getMechanismSets() { + if (mechanismSets == null) { + mechanismSets = new LinkedList<>(); + } + return mechanismSets; + } + + public void setMechanismSets(List mechanismSets) { + this.mechanismSets = mechanismSets; + } + + public void addModule(Module module) { + getModules().add(module); + } + + public void addMechanismSet(MechanismSet mechanismSet) { + getMechanismSets().add(mechanismSet); + } + + @Override + public void validate() throws InvalidConfException { + notEmpty(modules, "modules"); + validate(modules, mechanismSets); + } + } diff --git a/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Module.java b/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Module.java index 19f32e7..34f7b62 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Module.java +++ b/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Module.java @@ -141,7 +141,7 @@ private EmulatorP11Module(P11ModuleConf moduleConf) throws TokenException { Set slots = new HashSet<>(); for (P11SlotId slotId : slotIds) { - char[] pwd; + List pwd; try { pwd = moduleConf.getPasswordRetriever().getPassword(slotId); } catch (PasswordResolverException ex) { @@ -154,8 +154,14 @@ private EmulatorP11Module(P11ModuleConf moduleConf) throws TokenException { throw new TokenException("no password is configured"); } - slots.add(new EmulatorP11Slot(slotDir, slotId, - moduleConf.isReadOnly(), new EmulatorKeyCryptor(pwd), + if (pwd.size() != 1) { + throw new TokenException(pwd.size() + " passwords are configured, but 1 is permitted"); + } + + char[] firstPwd = pwd.get(0); + + slots.add(new EmulatorP11Slot(moduleConf.getName(), slotDir, slotId, + moduleConf.isReadOnly(), new EmulatorKeyCryptor(firstPwd), moduleConf.getP11MechanismFilter(), moduleConf.getP11NewObjectConf(), moduleConf.getNumSessions(), moduleConf.getSecretKeyTypes(), moduleConf.getKeyPairTypes())); } @@ -174,7 +180,7 @@ public String getDescription() { @Override public void close() { - LOG.info("close PKCS#11 module"); + LOG.info("close PKCS#11 module: {}", getName()); } private void createExampleRepository(File dir) throws IOException { diff --git a/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Slot.java b/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Slot.java index 46ae4c9..df7ba33 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Slot.java +++ b/security/src/main/java/org/xipki/security/pkcs11/emulator/EmulatorP11Slot.java @@ -32,6 +32,7 @@ import org.xipki.security.EdECConstants; import org.xipki.security.HashAlgo; import org.xipki.security.pkcs11.P11Key; +import org.xipki.security.pkcs11.P11ModuleConf.P11MechanismFilter; import org.xipki.security.pkcs11.P11ModuleConf.P11NewObjectConf; import org.xipki.security.pkcs11.P11Params; import org.xipki.security.pkcs11.P11Slot; @@ -221,11 +222,11 @@ public boolean accept(File dir, String name) { } EmulatorP11Slot( - File slotDir, P11SlotId slotId, boolean readOnly, - EmulatorKeyCryptor keyCryptor, P11NewObjectConf newObjectConf, + String moduleName, File slotDir, P11SlotId slotId, boolean readOnly, + EmulatorKeyCryptor keyCryptor, P11MechanismFilter mechanismFilter, P11NewObjectConf newObjectConf, Integer numSessions, List secretKeyTypes, List keypairTypes) throws TokenException { - super(slotId, readOnly, secretKeyTypes, keypairTypes, newObjectConf); + super(moduleName, slotId, readOnly, secretKeyTypes, keypairTypes, newObjectConf); this.keyCryptor = Args.notNull(keyCryptor, "keyCryptor"); this.maxSessions = numSessions == null ? 20 : Args.positive(numSessions, "numSessions"); @@ -249,7 +250,7 @@ public boolean accept(File dir, String name) { this.namedCurveSupported = true; } - initMechanisms(supportedMechs); + initMechanisms(supportedMechs, mechanismFilter); } // constructor private List getFilesForLabel(File dir, String label) throws TokenException { diff --git a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Key.java b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Key.java new file mode 100644 index 0000000..80749a4 --- /dev/null +++ b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Key.java @@ -0,0 +1,78 @@ +// Copyright (c) 2013-2024 xipki. All rights reserved. +// License Apache License 2.0 + +package org.xipki.security.pkcs11.hsmproxy; + +import org.xipki.pkcs11.wrapper.PKCS11KeyId; +import org.xipki.pkcs11.wrapper.TokenException; +import org.xipki.pkcs11.wrapper.params.ExtraParams; +import org.xipki.security.pkcs11.P11Key; +import org.xipki.security.pkcs11.P11Params; +import org.xipki.security.util.KeyUtil; +import org.xipki.util.Args; + +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.RSAPublicKeySpec; + +import static org.xipki.pkcs11.wrapper.PKCS11Constants.CKK_RSA; + +/** + * {@link P11Key} based on the HSM proxy. + * + * @author Lijun Liao (xipki) + */ + +class HsmProxyP11Key extends P11Key { + + public HsmProxyP11Key(HsmProxyP11Slot slot, PKCS11KeyId keyId) { + super(slot, keyId); + } + + @Override + protected byte[] digestSecretKey0(long mechanism) throws TokenException { + return slot.digestSecretKey(mechanism, keyId.getHandle()); + } + + @Override + protected PublicKey getPublicKey0() throws TokenException { + long keyType = keyId.getKeyType(); + if (keyType == CKK_RSA) { + try { + return KeyUtil.generateRSAPublicKey( + new RSAPublicKeySpec(rsaModulus, rsaPublicExponent)); + } catch (InvalidKeySpecException ex) { + throw new TokenException(ex.getMessage(), ex); + } + } + + Long publicKeyHandle = keyId.getPublicKeyHandle(); + return (publicKeyHandle == null) ? null : slot.getPublicKey(publicKeyHandle); + } + + @Override + public void destroy() throws TokenException { + long[] failedHandles; + if (keyId.getPublicKeyHandle() == null) { + failedHandles = slot.destroyObjectsByHandle(keyId.getHandle()); + } else { + failedHandles = slot.destroyObjectsByHandle(keyId.getHandle(), keyId.getPublicKeyHandle()); + } + if (failedHandles != null && failedHandles.length > 0) { + throw new TokenException("error destroying key " + keyId); + } + } + + @Override + protected byte[] sign0(long mechanism, P11Params parameters, byte[] content) throws TokenException { + Args.notNull(content, "content"); + ExtraParams extraParams = null; + if (ecOrderBitSize != null) { + extraParams = new ExtraParams(); + extraParams.ecOrderBitSize(ecOrderBitSize); + } + + return slot.sign(mechanism, parameters, extraParams, keyId.getHandle(), content); + } + +} diff --git a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Module.java b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Module.java new file mode 100644 index 0000000..be128f5 --- /dev/null +++ b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Module.java @@ -0,0 +1,428 @@ +// Copyright (c) 2013-2024 xipki. All rights reserved. +// License Apache License 2.0 + +package org.xipki.security.pkcs11.hsmproxy; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xipki.pkcs11.wrapper.PKCS11Constants; +import org.xipki.pkcs11.wrapper.PKCS11Exception; +import org.xipki.pkcs11.wrapper.TokenException; +import org.xipki.security.pkcs11.P11Module; +import org.xipki.security.pkcs11.P11ModuleConf; +import org.xipki.security.pkcs11.P11Slot; +import org.xipki.security.pkcs11.P11SlotId; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.BooleanMessage; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.ByteArrayMessage; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.ErrorResponse; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GetMechanismInfosResponse; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.IntMessage; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.KeyIdMessage; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.LongArrayMessage; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.ModuleCapsResponse; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.P11KeyResponse; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.SlotIdsResponse; +import org.xipki.util.Args; +import org.xipki.util.FileOrBinary; +import org.xipki.util.IoUtil; +import org.xipki.util.LogUtil; +import org.xipki.util.StringUtil; +import org.xipki.util.cbor.ByteArrayCborDecoder; +import org.xipki.util.cbor.CborConstants; +import org.xipki.util.cbor.CborDecoder; +import org.xipki.util.cbor.CborType; +import org.xipki.util.exception.DecodeException; +import org.xipki.util.exception.ObjectCreationException; +import org.xipki.util.http.HostnameVerifiers; +import org.xipki.util.http.SslConf; +import org.xipki.util.http.SslContextConf; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSocketFactory; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; + +/** + * {@link P11Module} for PKCS#11 proxy. + * + * @author Lijun Liao (xipki) + */ + +class HsmProxyP11Module extends P11Module { + + public static final String TYPE = "hsmproxy"; + + private static final String PROP_SSL_STORETYPE = "ssl.storeType"; + + private static final String PROP_SSL_KEYSTORE = "ssl.keystore"; + + private static final String PROP_SSL_KEYSTOREPASSWORD = "ssl.keystorePassword"; + + private static final String PROP_SSL_TRUSTCERTS = "ssl.trustcerts"; + + private static final String PROP_SSL_HOStNAMEVERIFIER = "ssl.hostnameVerifier"; + + private static final Logger LOG = LoggerFactory.getLogger(HsmProxyP11Module.class); + + private static final String REQUEST_MIMETYPE = "application/x-xipki-pkcs11"; + + private static final String RESPONSE_MIMETYPE = "application/x-xipki-pkcs11"; + + private static final byte[] SLOT_ID_NULL_CONTENT_NULL_REQUEST = new byte[]{(byte) 0x82, (byte) 0xf6, (byte) 0xf6}; + + private final String description; + + private final String serverUrl; + + private final SSLSocketFactory sslSocketFactory; + + private final HostnameVerifier hostnameVerifier; + + private HsmProxyP11Module(P11ModuleConf moduleConf) throws TokenException { + super(moduleConf); + + final String modulePath = moduleConf.getNativeLibrary(); + + Map properties = moduleConf.getNativeLibraryProperties(); + if (properties == null) { + throw new TokenException("The properties field is not present"); + } + this.description = StringUtil.concat("PKCS#11 proxy", "\nPath: ", modulePath); + this.serverUrl = modulePath.endsWith("/") ? modulePath.substring(0, modulePath.length() - 1) : modulePath; + + SslConf sslConf = new SslConf(); + + String sslStoreType = properties.get(PROP_SSL_STORETYPE); + sslConf.setStoreType(sslStoreType); + + String sslKeystore = properties.get(PROP_SSL_KEYSTORE); + sslConf.setKeystore(FileOrBinary.ofFile(sslKeystore)); + + String sslKeystorePassword = properties.get(PROP_SSL_KEYSTOREPASSWORD); + sslConf.setKeystorePassword(sslKeystorePassword); + + String sslTrustCerts = properties.get(PROP_SSL_TRUSTCERTS); + if (sslTrustCerts != null) { + StringTokenizer tokens = new StringTokenizer(sslTrustCerts, ",;:"); + List files = new ArrayList<>(tokens.countTokens()); + while (tokens.hasMoreTokens()) { + String file = tokens.nextToken().trim(); + files.add(FileOrBinary.ofFile(file)); + } + sslConf.setTrustanchors(files.toArray(new FileOrBinary[0])); + } + + String sslHostnameVerifier = properties.get(PROP_SSL_HOStNAMEVERIFIER); + if (sslHostnameVerifier != null) { + sslConf.setHostnameVerifier(sslHostnameVerifier); + } + + SslContextConf sslContextConf = SslContextConf.ofSslConf(sslConf); + + try { + this.sslSocketFactory = sslContextConf.getSslSocketFactory(); + } catch (ObjectCreationException ex) { + throw new TokenException("could not build SSLSocketFactroy", ex); + } + try { + this.hostnameVerifier = HostnameVerifiers.createHostnameVerifier(sslHostnameVerifier); + } catch (ObjectCreationException ex) { + throw new TokenException("could not create HostnameVerifier", ex); + } + + ModuleCapsResponse moduleCaps = + (ModuleCapsResponse) sendModuleAction(ProxyAction.moduleCaps); + if (!moduleConf.isReadOnly()) { + moduleConf.setReadOnly(moduleCaps.isReadOnly()); + } + + if (moduleConf.getMaxMessageSize() > moduleCaps.getMaxMessageSize()) { + moduleConf.setMaxMessageSize(moduleCaps.getMaxMessageSize()); + } + + if (moduleCaps.getNewObjectConf() != null) { + moduleConf.setNewObjectConf(moduleCaps.getNewObjectConf()); + } + + if (moduleCaps.getSecretKeyTypes() != null) { + moduleConf.setSecretKeyTypes( + intersect(moduleConf.getSecretKeyTypes(), moduleCaps.getSecretKeyTypes())); + } + + if (moduleCaps.getKeyPairTypes() != null) { + moduleConf.setKeyPairTypes( + intersect(moduleConf.getKeyPairTypes(), moduleCaps.getKeyPairTypes())); + } + + // initialize the slots + SlotIdsResponse resp = (SlotIdsResponse) sendModuleAction(ProxyAction.slotIds); + Set slots = new HashSet<>(); + for (P11SlotId slotId : resp.getSlotIds() ) { + if (!conf.isSlotIncluded(slotId)) { + continue; + } + + if (!conf.isSlotIncluded(slotId)) { + LOG.info("skipped slot {}", slotId); + continue; + } + + HsmProxyP11Slot slot = new HsmProxyP11Slot(slotId, moduleConf.isReadOnly(), this, + conf.getP11MechanismFilter(), moduleCaps.getNewObjectConf(), + moduleCaps.getSecretKeyTypes(), moduleCaps.getKeyPairTypes()); + slots.add(slot); + } + setSlots(slots); + } // constructor + + private static List intersect(List a, List b) { + if (a == null) { + return b; + } else if (b == null) { + return a; + } + + if (new HashSet<>(a).containsAll(b) && a.size() == b.size()) { + return a; + } + + List r = new ArrayList<>(Math.min(a.size(), b.size())); + for (T ta : a) { + if (b.contains(ta)) { + r.add(ta); + } + } + return r; + } + + public static P11Module getInstance(P11ModuleConf moduleConf) throws TokenException { + Args.notNull(moduleConf, "moduleConf"); + if (moduleConf.getUserName() != null) { + throw new TokenException("userName is present but shall be null"); + } + + return new HsmProxyP11Module(moduleConf); + } + + @Override + public String getDescription() { + return description; + } + + @Override + public void close() { + for (P11SlotId slotId : getSlotIds()) { + try { + getSlot(slotId).close(); + } catch (Throwable th) { + LogUtil.error(LOG, th, "could not close PKCS#11 slot " + slotId); + } + } + } + + protected byte[] doSend(ProxyAction action, byte[] request) throws IOException { + Args.notNull(request, "request"); + + String thisUrl = serverUrl + "/" + action.getAlias(); + + HttpURLConnection httpUrlConnection = IoUtil.openHttpConn(new URL(thisUrl)); + + if (httpUrlConnection instanceof HttpsURLConnection) { + if (sslSocketFactory != null) { + ((HttpsURLConnection) httpUrlConnection).setSSLSocketFactory(sslSocketFactory); + } + + if (hostnameVerifier != null) { + ((HttpsURLConnection) httpUrlConnection).setHostnameVerifier(hostnameVerifier); + } + } + + httpUrlConnection.setDoOutput(true); + httpUrlConnection.setUseCaches(false); + + int size = request.length; + + httpUrlConnection.setRequestMethod("POST"); + httpUrlConnection.setRequestProperty("Content-Type", REQUEST_MIMETYPE); + httpUrlConnection.setRequestProperty("Content-Length", Integer.toString(size)); + OutputStream outputstream = httpUrlConnection.getOutputStream(); + outputstream.write(request); + outputstream.flush(); + + if (httpUrlConnection.getResponseCode() != HttpURLConnection.HTTP_OK) { + try { + try { + InputStream is = httpUrlConnection.getInputStream(); + if (is != null) { + is.close(); + } + } catch (IOException ex) { + InputStream errStream = httpUrlConnection.getErrorStream(); + if (errStream != null) { + errStream.close(); + } + } + } catch (Throwable th) { + // ignore it + } + + throw new IOException("bad response: code=" + httpUrlConnection.getResponseCode() + + ", message=" + httpUrlConnection.getResponseMessage()); + } + + InputStream inputstream; + try { + inputstream = httpUrlConnection.getInputStream(); + } catch (IOException ex) { + InputStream errStream = httpUrlConnection.getErrorStream(); + if (errStream != null) { + errStream.close(); + } + throw ex; + } + + try { + String responseContentType = httpUrlConnection.getContentType(); + boolean isValidContentType = false; + if (responseContentType != null) { + if (responseContentType.equalsIgnoreCase(RESPONSE_MIMETYPE)) { + isValidContentType = true; + } + } + if (!isValidContentType) { + throw new IOException("bad response: mime type " + responseContentType + + " is not supported!"); + } + + byte[] buf = new byte[4096]; + ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(); + do { + int readedByte = inputstream.read(buf); + if (readedByte == -1) { + break; + } + bytearrayoutputstream.write(buf, 0, readedByte); + } while (true); + + return bytearrayoutputstream.toByteArray(); + } finally { + inputstream.close(); + } + } // method send + + public ProxyMessage sendModuleAction(ProxyAction action) throws TokenException { + return send(action, SLOT_ID_NULL_CONTENT_NULL_REQUEST.clone()); + } + + public ProxyMessage send(ProxyAction action, byte[] request) throws TokenException { + Args.notNull(request, "request"); + + byte[] respBytes; + try { + respBytes = doSend(action, request); + } catch (IOException ex) { + LOG.error("IO error", request); + throw new TokenException(ex.getMessage(), ex); + } + + CborDecoder decoder = new ByteArrayCborDecoder(respBytes); + ErrorResponse errorResp = null; + + try { + CborType type = decoder.peekType(); + if (CborDecoder.isNull(type)) { + decoder.readNull(); + return null; + } else if (type.getMajorType() == CborConstants.TYPE_TAG) { + long tag = decoder.readTag(); + if (ErrorResponse.CBOR_TAG_ERROR_RESPONSE != tag) { + throw new TokenException("response is tagged but not with tag CBOR_TAG_ERROR_RESPONSE"); + } + + errorResp = ErrorResponse.decode(decoder); + } + } catch (IOException ex) { + throw new TokenException("IO error decoding response", ex); + } catch (DecodeException ex) { + throw new TokenException("DecodeException decoding response", ex); + } + + if (errorResp != null) { + ErrorResponse.ProxyErrorCode errorCode = errorResp.getErrorCode(); + String detail = errorResp.getDetail(); + + switch (errorCode) { + case badRequest: + case internalError: + throw new TokenException(errorCode + ": " + detail); + case pkcs11Exception: + long ckrCode; + try { + ckrCode = detail.startsWith("CKR_") || detail.startsWith("ckr_") + ? PKCS11Constants.ckrNameToCode(detail) : Long.parseLong(detail); + } catch (Exception ex) { + LOG.warn("could not parse CKR code '" + detail + "'"); + ckrCode = PKCS11Constants.CKR_GENERAL_ERROR; + } + throw new PKCS11Exception(ckrCode); + case tokenException: + throw new TokenException(detail); + } + } + + try { + switch (action) { + case moduleCaps: + return ModuleCapsResponse.decode(decoder); + case slotIds: + return SlotIdsResponse.decode(decoder); + case mechInfos: + return GetMechanismInfosResponse.decode(decoder); + case keyByKeyId: + case keyByIdLabel: + return P11KeyResponse.decode(decoder); + case objectExistsByIdLabel: + return BooleanMessage.decode(decoder); + case destroyAllObjects: + case destroyObjectsByIdLabel: + return IntMessage.decode(decoder); + case destroyObjectsByHandle: + return LongArrayMessage.decode(decoder); + case keyIdByIdLabel: + case genSecretKey: + case importSecretKey: + case genRSAKeypair: + case genDSAKeypair2: + case genDSAKeypair: + case genECKeypair: + case genSM2Keypair: + return KeyIdMessage.decode(decoder); + case genRSAKeypairOtf: + case genDSAKeypairOtf: + case genECKeypairOtf: + case genSM2KeypairOtf: + case publicKeyByHandle: + case showDetails: + case sign: + case digestSecretKey: + return ByteArrayMessage.decode(decoder); + default: + throw new IllegalStateException("should not reach here, unknown action " + action); + } + } catch (DecodeException ex) { + throw new TokenException("DecodingException while decoding response.", ex); + } + } + +} diff --git a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11ModuleFactory.java b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11ModuleFactory.java new file mode 100644 index 0000000..5d6c593 --- /dev/null +++ b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11ModuleFactory.java @@ -0,0 +1,34 @@ +// Copyright (c) 2013-2024 xipki. All rights reserved. +// License Apache License 2.0 + +package org.xipki.security.pkcs11.hsmproxy; + +import org.xipki.pkcs11.wrapper.TokenException; +import org.xipki.security.pkcs11.P11Module; +import org.xipki.security.pkcs11.P11ModuleConf; +import org.xipki.security.pkcs11.P11ModuleFactory; +import org.xipki.util.XipkiBaseDir; + +/** + * {@link P11ModuleFactory} to create {@link P11Module} of type "hsmproxy". + * + * @author Lijun Liao (xipki) + * + */ +public class HsmProxyP11ModuleFactory implements P11ModuleFactory { + + public HsmProxyP11ModuleFactory() { + XipkiBaseDir.init(); + } + + @Override + public boolean canCreateModule(String type) { + return HsmProxyP11Module.TYPE.equalsIgnoreCase(type); + } + + @Override + public P11Module newModule(P11ModuleConf conf) throws TokenException { + return HsmProxyP11Module.getInstance(conf); + } + +} diff --git a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Slot.java b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Slot.java new file mode 100644 index 0000000..88409b0 --- /dev/null +++ b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Slot.java @@ -0,0 +1,375 @@ +// Copyright (c) 2013-2024 xipki. All rights reserved. +// License Apache License 2.0 + +package org.xipki.security.pkcs11.hsmproxy; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xipki.pkcs11.wrapper.MechanismInfo; +import org.xipki.pkcs11.wrapper.PKCS11KeyId; +import org.xipki.pkcs11.wrapper.TokenException; +import org.xipki.pkcs11.wrapper.params.ExtraParams; +import org.xipki.security.pkcs11.P11Key; +import org.xipki.security.pkcs11.P11ModuleConf.P11MechanismFilter; +import org.xipki.security.pkcs11.P11ModuleConf.P11NewObjectConf; +import org.xipki.security.pkcs11.P11Params; +import org.xipki.security.pkcs11.P11Slot; +import org.xipki.security.pkcs11.P11SlotId; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.BooleanMessage; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.ByteArrayMessage; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.DigestSecretKeyRequest; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateDSAKeyPairByKeysizeRequest; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateDSAKeyPairOtfRequest; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateDSAKeyPairRequest; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateECKeyPairOtfRequest; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateECKeyPairRequest; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateRSAKeyPairOtfRequest; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateRSAKeyPairRequest; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateSM2KeyPairRequest; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GenerateSecretKeyRequest; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.GetMechanismInfosResponse; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.IdLabelMessage; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.ImportSecretKeyRequest; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.IntMessage; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.KeyIdMessage; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.LongArrayMessage; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.LongMessage; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.P11KeyResponse; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.ShowDetailsRequest; +import org.xipki.security.pkcs11.hsmproxy.ProxyMessage.SignRequest; +import org.xipki.security.util.KeyUtil; +import org.xipki.util.LogUtil; +import org.xipki.util.cbor.ByteArrayCborEncoder; +import org.xipki.util.exception.EncodeException; + +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * {@link P11Slot} based on the HSM proxy. + * + * @author Lijun Liao (xipki) + */ +class HsmProxyP11Slot extends P11Slot { + + private static final Logger LOG = LoggerFactory.getLogger(HsmProxyP11Slot.class); + + private final HsmProxyP11Module module; + + HsmProxyP11Slot(P11SlotId slotId, boolean readOnly, HsmProxyP11Module module, P11MechanismFilter mechanismFilter, + P11NewObjectConf newObjectConf, List secretKeyTypes, List keyPairTypes) + throws TokenException { + super(module.getName(), slotId, readOnly, secretKeyTypes, keyPairTypes, newObjectConf); + + this.module = module; + GetMechanismInfosResponse resp = (GetMechanismInfosResponse) send(ProxyAction.mechInfos, null); + Map mechanismInfoMap = resp == null ? Collections.emptyMap() : resp.getMechamismInfoMap(); + initMechanisms(mechanismInfoMap, mechanismFilter); + } + + @Override + public final void close() { + } + + @Override + public P11Key getKey(PKCS11KeyId keyId) throws TokenException { + return toP11Key(send(ProxyAction.keyByKeyId, new KeyIdMessage(keyId))); + } + + @Override + public P11Key getKey(byte[] keyId, String keyLabel) throws TokenException { + return toP11Key(send(ProxyAction.keyByIdLabel, new IdLabelMessage(keyId, keyLabel))); + } + + @Override + public PKCS11KeyId getKeyId(byte[] keyId, String keyLabel) throws TokenException { + return toPKCS11KeyId(send(ProxyAction.keyIdByIdLabel, new IdLabelMessage(keyId, keyLabel))); + } + + @Override + public byte[] sign(long mechanism, P11Params params, ExtraParams extraParams, + long keyHandle, byte[] content) throws TokenException { + SignRequest req = new SignRequest(keyHandle, mechanism, params, extraParams, content); + return toByteArray(send(ProxyAction.sign, req)); + } + + @Override + public PublicKey getPublicKey(long handle) throws TokenException { + byte[] bytes = toByteArray(send(ProxyAction.publicKeyByHandle, new LongMessage(handle))); + try { + return bytes == null ? null : KeyUtil.generatePublicKey( + SubjectPublicKeyInfo.getInstance(bytes)); + } catch (InvalidKeySpecException ex) { + throw new TokenException("error parsing SubjectPublicKeyInfo", ex); + } + } + + @Override + public byte[] digestSecretKey(long mechanism, long handle) throws TokenException { + DigestSecretKeyRequest req = new DigestSecretKeyRequest(mechanism, handle); + return toByteArray(send(ProxyAction.digestSecretKey, req)); + } + + @Override + public boolean objectExistsByIdLabel(byte[] id, String label) throws TokenException { + return ((BooleanMessage) send(ProxyAction.objectExistsByIdLabel, new IdLabelMessage(id, label))).getValue(); + } + + @Override + public int destroyAllObjects() { + try { + return ((IntMessage) send(ProxyAction.destroyAllObjects, null)).getValue(); + } catch (TokenException e) { + LogUtil.warn(LOG, e, "error destroyAllObjects()"); + return 0; + } + } + + @Override + public long[] destroyObjectsByHandle(long[] handles) { + try { + LongArrayMessage resp = ((LongArrayMessage) send( + ProxyAction.destroyObjectsByHandle, new LongArrayMessage(handles))); + return resp == null ? null : resp.getValue(); + } catch (Exception e) { + LogUtil.warn(LOG, e, "error destroyObjectsByHandle()"); + return handles.clone(); + } + } + + @Override + public int destroyObjectsByIdLabel(byte[] id, String label) throws TokenException { + try { + return ((IntMessage) send(ProxyAction.destroyObjectsByIdLabel, new IdLabelMessage(id, label))).getValue(); + } catch (TokenException e) { + LogUtil.warn(LOG, e, "error destroyAllObjects()"); + return 0; + } + } + + @Override + public PKCS11KeyId generateSecretKey(long keyType, Integer keysize, P11NewKeyControl control) + throws TokenException { + return toPKCS11KeyId(send(ProxyAction.genSecretKey, new GenerateSecretKeyRequest(keyType, keysize, control))); + } // method generateSecretKey0 + + @Override + public PKCS11KeyId importSecretKey(long keyType, byte[] keyValue, P11NewKeyControl control) throws TokenException { + return toPKCS11KeyId(send(ProxyAction.importSecretKey, new ImportSecretKeyRequest(keyType, keyValue, control))); + } // method importSecretKey0 + + @Override + public PKCS11KeyId generateRSAKeypair(int keysize, BigInteger publicExponent, P11NewKeyControl control) + throws TokenException { + return toPKCS11KeyId(send(ProxyAction.genRSAKeypair, + new GenerateRSAKeyPairRequest(keysize, publicExponent, control))); + } + + @Override + public PrivateKeyInfo generateRSAKeypairOtf(int keysize, BigInteger publicExponent) throws TokenException { + return toPrivateKeyInfo(send(ProxyAction.genRSAKeypairOtf, + new GenerateRSAKeyPairOtfRequest(keysize, publicExponent))); + } + + @Override + public PKCS11KeyId generateDSAKeypair(int plength, int qlength, P11NewKeyControl control) throws TokenException { + return toPKCS11KeyId(send(ProxyAction.genDSAKeypair2, + new GenerateDSAKeyPairByKeysizeRequest(plength, qlength, control))); + } + + @Override + public PKCS11KeyId generateDSAKeypair(BigInteger p, BigInteger q, BigInteger g, P11NewKeyControl control) + throws TokenException { + return toPKCS11KeyId(send(ProxyAction.genDSAKeypair, new GenerateDSAKeyPairRequest(p, q, g, control))); + } + + @Override + public PrivateKeyInfo generateDSAKeypairOtf(BigInteger p, BigInteger q, BigInteger g) throws TokenException { + return toPrivateKeyInfo(send(ProxyAction.genDSAKeypairOtf, new GenerateDSAKeyPairOtfRequest(p, q, g))); + } + + @Override + public PKCS11KeyId generateECKeypair(ASN1ObjectIdentifier curveId, P11NewKeyControl control) throws TokenException { + return toPKCS11KeyId(send(ProxyAction.genECKeypair, new GenerateECKeyPairRequest(curveId, control))); + } + + @Override + public PrivateKeyInfo generateECKeypairOtf(ASN1ObjectIdentifier curveId) throws TokenException { + return toPrivateKeyInfo(send(ProxyAction.genECKeypair, new GenerateECKeyPairOtfRequest(curveId))); + } + + @Override + public PKCS11KeyId generateSM2Keypair(P11NewKeyControl control) throws TokenException { + return toPKCS11KeyId(send(ProxyAction.genSM2Keypair, new GenerateSM2KeyPairRequest(control))); + } + + @Override + public PrivateKeyInfo generateSM2KeypairOtf() throws TokenException { + return toPrivateKeyInfo(send(ProxyAction.genSM2KeypairOtf, null)); + } + + private P11Key toP11Key(ProxyMessage response) throws TokenException { + if (response == null) { + return null; + } + + if (!(response instanceof P11KeyResponse)) { + throw new TokenException("response is not a P11KeyResponse"); + } + + return ((P11KeyResponse) response).getP11Key(this); + } + + private static byte[] toByteArray(ProxyMessage response) throws TokenException { + if (response == null) { + return null; + } + + if (!(response instanceof ByteArrayMessage)) { + throw new TokenException("response is not a ByteArrayMessage"); + } + + return ((ByteArrayMessage) response).getValue(); + } + + private static PKCS11KeyId toPKCS11KeyId(ProxyMessage response) throws TokenException { + if (response == null) { + return null; + } + + if (!(response instanceof KeyIdMessage)) { + throw new TokenException("response is not a KeyIdMessage"); + } + + return ((KeyIdMessage) response).getKeyId(); + } + + private static PrivateKeyInfo toPrivateKeyInfo(ProxyMessage response) throws TokenException { + byte[] bytes = toByteArray(response); + if (bytes == null) { + return null; + } + + try { + return PrivateKeyInfo.getInstance(bytes); + } catch (IllegalArgumentException ex) { + throw new TokenException("invalid PrivateKeyInfo", ex); + } + } + + /** + * The specified stream remains open after this method returns. + */ + @Override + public void showDetails(OutputStream stream, Long objectHandle, boolean verbose) throws IOException { + ShowDetailsRequest req = new ShowDetailsRequest(objectHandle, verbose); + byte[] details; + try { + details = ((ByteArrayMessage) send(ProxyAction.showDetails, req)).getValue(); + } catch (TokenException e) { + details = ("ERROR: " + e.getMessage()).getBytes(StandardCharsets.UTF_8); + } + stream.write(details); + } + + private ProxyMessage send(ProxyAction action, ProxyMessage request) throws TokenException { + ByteArrayCborEncoder encoder = new ByteArrayCborEncoder(); + try { + encoder.writeArrayStart(2); + // slot id + encoder.writeInt(slotId.getId()); + if (request == null) { + encoder.writeNull(); + } else { + request.encode(encoder); + } + } catch (EncodeException ex) { + throw new TokenException("Encode error while building request", ex); + } catch (IOException ex) { + throw new TokenException("IO error while building request", ex); + } + + return module.send(action, encoder.toByteArray()); + } + + @Override + protected PKCS11KeyId doGenerateSecretKey(long keyType, Integer keysize, P11NewKeyControl control) { + throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); + } + + @Override + protected PKCS11KeyId doImportSecretKey(long keyType, byte[] keyValue, P11NewKeyControl control) { + throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); + } + + @Override + protected PKCS11KeyId doGenerateDSAKeypair(BigInteger p, BigInteger q, BigInteger g, P11NewKeyControl control) { + throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); + } + + @Override + protected PKCS11KeyId doGenerateECEdwardsKeypair(ASN1ObjectIdentifier curveId, P11NewKeyControl control) { + throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); + } + + @Override + protected PrivateKeyInfo doGenerateECEdwardsKeypairOtf(ASN1ObjectIdentifier curveId) { + throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); + } + + @Override + protected PKCS11KeyId doGenerateECMontgomeryKeypair(ASN1ObjectIdentifier curveId, P11NewKeyControl control) { + throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); + } + + @Override + protected PrivateKeyInfo doGenerateECMontgomeryKeypairOtf(ASN1ObjectIdentifier curveId) { + throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); + } + + @Override + protected PKCS11KeyId doGenerateECKeypair(ASN1ObjectIdentifier curveId, P11NewKeyControl control) { + throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); + } + + @Override + protected PrivateKeyInfo doGenerateECKeypairOtf(ASN1ObjectIdentifier curveId) { + throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); + } + + @Override + protected PKCS11KeyId doGenerateSM2Keypair(P11NewKeyControl control) { + throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); + } + + @Override + protected PrivateKeyInfo doGenerateSM2KeypairOtf() { + throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); + } + + @Override + protected PKCS11KeyId doGenerateRSAKeypair(int keysize, BigInteger publicExponent, P11NewKeyControl control) { + throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); + } + + @Override + protected PrivateKeyInfo doGenerateRSAKeypairOtf(int keysize, BigInteger publicExponent) { + throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); + } + + @Override + protected PrivateKeyInfo generateDSAKeypairOtf0(BigInteger p, BigInteger q, BigInteger g) { + throw new UnsupportedOperationException("doGenerateSecretKey() unsupported"); + } + +} diff --git a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyAction.java b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyAction.java new file mode 100644 index 0000000..df2dbc3 --- /dev/null +++ b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyAction.java @@ -0,0 +1,82 @@ +// Copyright (c) 2013-2024 xipki. All rights reserved. +// License Apache License 2.0 + +package org.xipki.security.pkcs11.hsmproxy; + +import java.util.HashMap; +import java.util.Map; + +/** + * The HSM proxy action enumeration. + * + * @author Lijun Liao (xipki) + */ + +public enum ProxyAction { + + moduleCaps ("mcaps"), + slotIds ("sids"), + + // mechanism infos + mechInfos ("mis"), + + publicKeyByHandle ("pkbh"), + + keyByKeyId ("kbi"), + keyByIdLabel ("kbil"), + keyIdByIdLabel ("kibil"), + + objectExistsByIdLabel ("ebil"), + + destroyAllObjects ("dao"), + destroyObjectsByHandle ("dobh"), + destroyObjectsByIdLabel ("dobil"), + + genSecretKey ("gsk"), + importSecretKey ("isk"), + + genRSAKeypair ("grsa"), + genRSAKeypairOtf ("grsao"), + // genDSAKeypairByKeysize + genDSAKeypair2 ("gdsa2"), + genDSAKeypair ("gdsa"), + genDSAKeypairOtf ("gdsao"), + genECKeypair ("gec"), + genECKeypairOtf ("geco"), + genSM2Keypair ("gsm2"), + genSM2KeypairOtf ("gsm2o"), + showDetails ("d"), + sign ("s"), + digestSecretKey ("dsk"); + + private final String alias; + + private static final Map namealiasActionMap = new HashMap<>(); + + static { + for (ProxyAction p : ProxyAction.values()) { + namealiasActionMap.put(p.name().toLowerCase(), p); + } + + for (ProxyAction p : ProxyAction.values()) { + String lc = p.alias.toLowerCase(); + if (namealiasActionMap.containsKey(lc)) { + throw new IllegalStateException("invalid alias " + p.alias); + } + namealiasActionMap.put(lc, p); + } + } + + ProxyAction(String alias) { + this.alias = alias; + } + + public String getAlias() { + return alias; + } + + public static ProxyAction ofNameIgnoreCase(String name) { + return namealiasActionMap.get(name.toLowerCase()); + } + +} diff --git a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyMessage.java b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyMessage.java new file mode 100644 index 0000000..71d76de --- /dev/null +++ b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/ProxyMessage.java @@ -0,0 +1,1465 @@ +// Copyright (c) 2013-2024 xipki. All rights reserved. +// License Apache License 2.0 + +package org.xipki.security.pkcs11.hsmproxy; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.xipki.pkcs11.wrapper.MechanismInfo; +import org.xipki.pkcs11.wrapper.PKCS11Exception; +import org.xipki.pkcs11.wrapper.PKCS11KeyId; +import org.xipki.pkcs11.wrapper.TokenException; +import org.xipki.pkcs11.wrapper.params.ExtraParams; +import org.xipki.security.pkcs11.P11Key; +import org.xipki.security.pkcs11.P11ModuleConf; +import org.xipki.security.pkcs11.P11Params; +import org.xipki.security.pkcs11.P11Slot; +import org.xipki.security.pkcs11.P11SlotId; +import org.xipki.util.Args; +import org.xipki.util.cbor.CborDecoder; +import org.xipki.util.cbor.CborEncodable; +import org.xipki.util.cbor.CborEncoder; +import org.xipki.util.exception.DecodeException; +import org.xipki.util.exception.EncodeException; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * The CBOR message. + * + * @author Lijun Liao (xipki) + */ +public abstract class ProxyMessage implements CborEncodable { + + protected abstract void encode0(CborEncoder encoder) throws EncodeException, IOException; + + @Override + public final void encode(CborEncoder encoder) throws EncodeException { + try { + encode0(encoder); + } catch (IOException ex) { + throw new EncodeException("IO error", ex); + } + } + + private static boolean isNotNullOrElseWriteNull(CborEncoder encoder, Object obj) throws IOException { + if (obj == null) { + encoder.writeNull(); + return false; + } + return true; + } + + private static void writeBigInt(CborEncoder encoder, BigInteger value) throws IOException { + if (isNotNullOrElseWriteNull(encoder, value)) { + encoder.writeByteString(value.toByteArray()); + } + } + + private static void writeOid(CborEncoder encoder, ASN1ObjectIdentifier value) throws IOException { + if (isNotNullOrElseWriteNull(encoder, value)) { + encoder.writeTextString(value.getId()); + } + } + + private static ASN1ObjectIdentifier readOid(CborDecoder decoder) throws IOException, DecodeException { + String text = decoder.readTextString(); + if (text == null) { + return null; + } + + try { + return new ASN1ObjectIdentifier(text); + } catch (IllegalArgumentException ex) { + throw new DecodeException(text + " is not a valid ObjectIdentifier"); + } + } + + private static void writeNewKeyControl(CborEncoder encoder, P11Slot.P11NewKeyControl control) throws IOException { + if (control == null) { + encoder.writeNull(); + return; + } + + encoder.writeArrayStart(5); + encoder.writeByteString(control.getId()); + encoder.writeTextString(control.getLabel()); + encoder.writeBooleanObj(control.getSensitive()); + encoder.writeBooleanObj(control.getExtractable()); + + Set usages = control.getUsages(); + if (usages == null) { + encoder.writeNull(); + } else { + encoder.writeArrayStart(usages.size()); + for (P11Slot.P11KeyUsage usage: usages) { + encoder.writeTextString(usage.name()); + } + } + } + + private static P11Slot.P11NewKeyControl decodeNewKeyControl(CborDecoder decoder) throws DecodeException { + try { + if (decoder.readNullOrArrayLength(5)) { + return null; + } + + byte[] id = decoder.readByteString(); + String label = decoder.readTextString(); + P11Slot.P11NewKeyControl control = new P11Slot.P11NewKeyControl(id, label); + control.setSensitive(decoder.readBooleanObj()); + control.setExtractable(decoder.readBooleanObj()); + + // usages + Integer usagesLen = decoder.readNullOrArrayLength(); + if (usagesLen != null) { + Set usages = new HashSet<>(usagesLen * 5 / 4); + for (int i = 0; i < usagesLen; i++) { + String usageText = decoder.readTextString(); + P11Slot.P11KeyUsage usage; + try { + usage = P11Slot.P11KeyUsage.valueOf(usageText); + } catch (IllegalArgumentException e) { + throw new DecodeException("unknown P11KeyUsage " + usageText); + } + usages.add(usage); + } + + control.setUsages(usages); + } + + return control; + } catch (IOException ex) { + throw new DecodeException("IO error", ex); + } + } + + private static void writeKeyId(CborEncoder encoder, PKCS11KeyId keyId) throws IOException { + encoder.writeArrayStart(6); + encoder.writeInt(keyId.getHandle()); + encoder.writeInt(keyId.getObjectCLass()); + encoder.writeInt(keyId.getKeyType()); + encoder.writeByteString(keyId.getId()); + encoder.writeTextString(keyId.getLabel()); + encoder.writeIntObj(keyId.getPublicKeyHandle()); + } + + private static PKCS11KeyId decodeKeyId(CborDecoder decoder) throws DecodeException { + try { + if (decoder.readNullOrArrayLength(6)) { + return null; + } + + long handle = decoder.readLong(); + long objectCLass = decoder.readLong(); + long keyType = decoder.readLong(); + byte[] id = decoder.readByteString(); + String label = decoder.readTextString(); + Long publicKeyHandle = decoder.readLongObj(); + + PKCS11KeyId keyId = new PKCS11KeyId(handle, objectCLass, keyType, id, label); + keyId.setPublicKeyHandle(publicKeyHandle); + return keyId; + } catch (IOException ex) { + throw new DecodeException("IO error decoding PKCS11KeyId", ex); + } + } + + private static void assertArraySize(CborDecoder decoder, int arraySize, String name) throws DecodeException { + try { + if (decoder.readNullOrArrayLength(arraySize)) { + throw new DecodeException(name + " shall not be null"); + } + } catch (IOException ex) { + throw new DecodeException("IO error reading arrayLength of " + name); + } + } + + /** + * The message wrapper for boolean. + */ + public static class BooleanMessage extends ProxyMessage { + + private final boolean value; + + public BooleanMessage(boolean value) { + this.value = value; + } + + public boolean getValue() { + return value; + } + + @Override + public void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeBoolean(value); + } + + public static BooleanMessage decode(CborDecoder decoder) throws DecodeException { + try { + boolean b = Optional.ofNullable(decoder.readBooleanObj()).orElseThrow( + () -> new DecodeException("BooleanMessage shall not be null")); + return new BooleanMessage(b); + } catch (IOException ex) { + throw new DecodeException("IO error decoding BooleanMessage", ex); + } + } + + } + + /** + * The message wrapper for byte[]. + */ + public static class ByteArrayMessage extends ProxyMessage { + + private final byte[] value; + + public ByteArrayMessage(byte[] value) { + this.value = Args.notNull(value, "value"); + } + + public byte[] getValue() { + return value; + } + + @Override + protected void encode0(CborEncoder encoder) throws IOException { + encoder.writeByteString(value); + } + + public static ByteArrayMessage decode(CborDecoder decoder) throws DecodeException { + try { + byte[] b = Optional.ofNullable(decoder.readByteString()).orElseThrow( + () -> new DecodeException("ByteArrayMessage shall not be null")); + + return new ByteArrayMessage(b); + } catch (IOException ex) { + throw new DecodeException("IO error decoding ByteArrayMessage", ex); + } + } + + } + + /** + * The request to digest secret key. + */ + public static class DigestSecretKeyRequest extends ProxyMessage { + + private static final int NUM_FIELDS = 2; + + private final long mechanism; + + private final long objectHandle; + + public DigestSecretKeyRequest(long mechanism, long objectHandle) { + this.mechanism = mechanism; + this.objectHandle = objectHandle; + } + + public long getMechanism() { + return mechanism; + } + + public long getObjectHandle() { + return objectHandle; + } + + @Override + protected void encode0(CborEncoder encoder) throws IOException { + encoder.writeArrayStart(NUM_FIELDS); + encoder.writeInt(mechanism); + encoder.writeInt(objectHandle); + } + + public static DigestSecretKeyRequest decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "DigestSecretKeyRequest"); + try { + long mechanism = decoder.readLong(); + long objectHandle = decoder.readLong(); + return new DigestSecretKeyRequest(mechanism, objectHandle); + } catch (IOException ex) { + throw new DecodeException("IO error decoding DigestSecretKeyRequest", ex); + } + } + + } + + public enum ProxyErrorCode { + + internalError(1), + badRequest(2), + tokenException(3), + pkcs11Exception(4); + + private final int code; + + ProxyErrorCode(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + + public static ProxyErrorCode ofCode(int code) { + for (ProxyErrorCode m : ProxyErrorCode.values()) { + if (m.code == code) { + return m; + } + } + return null; + } + + } + + /** + * The error response. + */ + public static class ErrorResponse extends ProxyMessage { + + public static final long CBOR_TAG_ERROR_RESPONSE = 0x80000; + + private static final int NUM_FIELDS = 2; + + private final ProxyErrorCode errorCode; + + private final String detail; + + public ErrorResponse(ProxyErrorCode errorCode, String detail) { + this.errorCode = errorCode; + this.detail = detail; + } + + public ErrorResponse(Throwable t) { + if (t instanceof PKCS11Exception) { + this.errorCode = ProxyErrorCode.pkcs11Exception; + this.detail = Long.toString(((PKCS11Exception) t).getErrorCode()); + } else if (t instanceof TokenException) { + this.errorCode = ProxyErrorCode.tokenException; + this.detail = t.getMessage(); + } else { + this.errorCode = ProxyErrorCode.tokenException; + this.detail = t.getMessage(); + } + } + + public ProxyErrorCode getErrorCode() { + return errorCode; + } + + public String getDetail() { + return detail; + } + + @Override + public void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + encoder.writeInt(errorCode.code); + encoder.writeTextString(detail); + } + + public static ErrorResponse decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "ErrorResponnse"); + try { + int code = decoder.readInt(); + ProxyErrorCode errorCode = Optional.ofNullable(ProxyErrorCode.ofCode(code)).orElseThrow( + () -> new DecodeException("unknown error code " + code)); + String detail = decoder.readTextString(); + return new ErrorResponse(errorCode, detail); + } catch (IOException ex) { + throw new DecodeException("IO error decoding ErrorResponse", ex); + } + } + + } + + /** + * The request to generate-then-save DSA keypair for given keysize. + */ + public static class GenerateDSAKeyPairByKeysizeRequest extends ProxyMessage { + + private static final int NUM_FIELDS = 3; + + private final int plength; + + private final int qlength; + + private final P11Slot.P11NewKeyControl newKeyControl; + + public GenerateDSAKeyPairByKeysizeRequest(int plength, int qlength, P11Slot.P11NewKeyControl newKeyControl) { + this.plength = plength; + this.qlength = qlength; + this.newKeyControl = newKeyControl; + } + + public int getPlength() { + return plength; + } + + public int getQlength() { + return qlength; + } + + public P11Slot.P11NewKeyControl getNewKeyControl() { + return newKeyControl; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + encoder.writeInt(plength); + encoder.writeInt(qlength); + writeNewKeyControl(encoder, newKeyControl); + } + + public static GenerateDSAKeyPairByKeysizeRequest decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "GenerateDSAKeyPairByKeysizeRequest"); + try { + int plength = decoder.readInt(); + int qlength = decoder.readInt(); + P11Slot.P11NewKeyControl control = decodeNewKeyControl(decoder); + return new GenerateDSAKeyPairByKeysizeRequest(plength, qlength, control); + } catch (IOException ex) { + throw new DecodeException("IO error decoding GenerateDSAKeyPairByKeysizeRequest", ex); + } + } + + } + + /** + * The request to generate-then-destroy DSA keypair for given (P, Q, G). + */ + public static class GenerateDSAKeyPairOtfRequest extends ProxyMessage { + + private static final int NUM_FIELDS = 3; + + protected final BigInteger p; + + protected final BigInteger q; + + protected final BigInteger g; + + public GenerateDSAKeyPairOtfRequest(BigInteger p, BigInteger q, BigInteger g) { + this.p = Args.notNull(p, "p"); + this.q = Args.notNull(q, "q"); + this.g = Args.notNull(g, "g"); + } + + public BigInteger getP() { + return p; + } + + public BigInteger getQ() { + return q; + } + + public BigInteger getG() { + return g; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + encoder.writeByteString(p.toByteArray()); + encoder.writeByteString(q.toByteArray()); + encoder.writeByteString(g.toByteArray()); + } + + public static GenerateDSAKeyPairOtfRequest decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "GenerateDSAKeyPairOtfRequest"); + try { + BigInteger p = decoder.readBigInt(); + BigInteger q = decoder.readBigInt(); + BigInteger g = decoder.readBigInt(); + return new GenerateDSAKeyPairOtfRequest(p, q, g); + } catch (IOException ex) { + throw new DecodeException("IO error decoding GenerateDSAKeyPairOtfRequest", ex); + } + } + + } + + /** + * The request to generate-then-save DSA keypair for given (P, Q, G). + */ + public static class GenerateDSAKeyPairRequest extends GenerateDSAKeyPairOtfRequest { + + private static final int NUM_FIELDS = 4; + + private final P11Slot.P11NewKeyControl newKeyControl; + + public GenerateDSAKeyPairRequest(BigInteger p, BigInteger q, BigInteger g, P11Slot.P11NewKeyControl newKeyControl) { + super(p, q, g); + this.newKeyControl = newKeyControl; + } + + public P11Slot.P11NewKeyControl getNewKeyControl() { + return newKeyControl; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + encoder.writeByteString(p.toByteArray()); + encoder.writeByteString(q.toByteArray()); + encoder.writeByteString(g.toByteArray()); + writeNewKeyControl(encoder, newKeyControl); + } + + public static GenerateDSAKeyPairRequest decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "GenerateDSAKeyPairRequest"); + try { + BigInteger p = decoder.readBigInt(); + BigInteger q = decoder.readBigInt(); + BigInteger g = decoder.readBigInt(); + P11Slot.P11NewKeyControl control = decodeNewKeyControl(decoder); + return new GenerateDSAKeyPairRequest(p, q, g, control); + } catch (IOException ex) { + throw new DecodeException("IO error decoding GenerateDSAKeyPairRequest", ex); + } + } + + } + + /** + * The request to generate-then-destroy EC keypair. + */ + public static class GenerateECKeyPairOtfRequest extends ProxyMessage { + + private static final int NUM_FIELDS = 1; + + protected final ASN1ObjectIdentifier curveOid; + + public GenerateECKeyPairOtfRequest(ASN1ObjectIdentifier curveOid) { + this.curveOid = Args.notNull(curveOid, "curveOid"); + } + + public ASN1ObjectIdentifier getCurveOid() { + return curveOid; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + writeOid(encoder, curveOid); + } + + public static GenerateECKeyPairOtfRequest decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "GenerateECKeyPairOtfRequest"); + try { + ASN1ObjectIdentifier curveOid = readOid(decoder); + return new GenerateECKeyPairOtfRequest(curveOid); + } catch (IOException ex) { + throw new DecodeException("IO error decoding GenerateECKeyPairOtfRequest", ex); + } + } + + } + + /** + * The request to generate-then-save EC keypair. + */ + public static class GenerateECKeyPairRequest extends GenerateECKeyPairOtfRequest { + + private static final int NUM_FIELDS = 2; + + private final P11Slot.P11NewKeyControl newKeyControl; + + public GenerateECKeyPairRequest(ASN1ObjectIdentifier curveOid, P11Slot.P11NewKeyControl newKeyControl) { + super(curveOid); + this.newKeyControl = newKeyControl; + } + + public P11Slot.P11NewKeyControl getNewKeyControl() { + return newKeyControl; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + ProxyMessage.writeOid(encoder, curveOid); + ProxyMessage.writeNewKeyControl(encoder, newKeyControl); + } + + public static GenerateECKeyPairRequest decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "GenerateECKeyPairRequest"); + try { + ASN1ObjectIdentifier curveOid = ProxyMessage.readOid(decoder); + P11Slot.P11NewKeyControl control = ProxyMessage.decodeNewKeyControl(decoder); + return new GenerateECKeyPairRequest(curveOid, control); + } catch (IOException ex) { + throw new DecodeException("IO error decoding GenerateECKeyPairRequest", ex); + } + } + + } + + /** + * The request to generate-then-destroy RSA keypair. + */ + public static class GenerateRSAKeyPairOtfRequest extends ProxyMessage { + + private static final int NUM_FIELDS = 2; + + protected final int keySize; + + protected final BigInteger publicExponent; + + public GenerateRSAKeyPairOtfRequest(int keySize, BigInteger publicExponent) { + this.keySize = keySize; + this.publicExponent = publicExponent; + } + + public int getKeySize() { + return keySize; + } + + public BigInteger getPublicExponent() { + return publicExponent; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + encoder.writeInt(keySize); + encoder.writeByteString(publicExponent == null ? null : publicExponent.toByteArray()); + } + + public static GenerateRSAKeyPairOtfRequest decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "GenerateRSAKeyPairOtfRequest"); + try { + int keysize = decoder.readInt(); + BigInteger publicExponent = decoder.readBigInt(); + return new GenerateRSAKeyPairOtfRequest(keysize, publicExponent); + } catch (IOException ex) { + throw new DecodeException("IO error decoding GenerateRSAKeyPairOtfRequest", ex); + } + } + + } + + /** + * The request to generate-then-save RSA keypair. + */ + public static class GenerateRSAKeyPairRequest extends GenerateRSAKeyPairOtfRequest { + + private static final int NUM_FIELDS = 2; + + private final P11Slot.P11NewKeyControl newKeyControl; + + public GenerateRSAKeyPairRequest(int keySize, BigInteger publicExponent, P11Slot.P11NewKeyControl newKeyControl) { + super(keySize, publicExponent); + this.newKeyControl = newKeyControl; + } + + public P11Slot.P11NewKeyControl getNewKeyControl() { + return newKeyControl; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + encoder.writeInt(keySize); + writeBigInt(encoder, publicExponent); + writeNewKeyControl(encoder, newKeyControl); + } + + public static GenerateRSAKeyPairRequest decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "GenerateRSAKeyPairRequest"); + try { + int keysize = decoder.readInt(); + BigInteger publicExponent = decoder.readBigInt(); + P11Slot.P11NewKeyControl control = decodeNewKeyControl(decoder); + return new GenerateRSAKeyPairRequest(keysize, publicExponent, control); + } catch (IOException ex) { + throw new DecodeException("IO error decoding GenerateRSAKeyPairRequest", ex); + } + } + + } + + /** + * The request to generate-then-destroy SM2 keypair. + */ + public static class GenerateSecretKeyRequest extends ProxyMessage { + + private static final int NUM_FIELDS = 3; + private final long keyType; + private final Integer keySize; + private final P11Slot.P11NewKeyControl newKeyControl; + + public GenerateSecretKeyRequest(long keyType, Integer keySize, P11Slot.P11NewKeyControl newKeyControl) { + this.keyType = keyType; + this.keySize = keySize; + this.newKeyControl = newKeyControl; + } + + public long getKeyType() { + return keyType; + } + + public Integer getKeySize() { + return keySize; + } + + public P11Slot.P11NewKeyControl getNewOKeyControl() { + return newKeyControl; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + encoder.writeInt(keyType); + encoder.writeIntObj(keySize); + writeNewKeyControl(encoder, newKeyControl); + } + + public static GenerateSecretKeyRequest decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "GenerateSecretKeyRequest"); + try { + long keyType = decoder.readLong(); + Integer keySize = decoder.readIntObj(); + P11Slot.P11NewKeyControl control = decodeNewKeyControl(decoder); + return new GenerateSecretKeyRequest(keyType, keySize, control); + } catch (IOException ex) { + throw new DecodeException("IO error decoding GenerateSecretKeyRequest", ex); + } + } + + } + + /** + * The request to generate-then-save SM2 keypair. + */ + public static class GenerateSM2KeyPairRequest extends ProxyMessage { + + private static final int NUM_FIELDS = 1; + + private final P11Slot.P11NewKeyControl newKeyControl; + + public GenerateSM2KeyPairRequest(P11Slot.P11NewKeyControl newKeyControl) { + this.newKeyControl = newKeyControl; + } + + public P11Slot.P11NewKeyControl getNewKeyControl() { + return newKeyControl; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + writeNewKeyControl(encoder, newKeyControl); + } + + public static GenerateSM2KeyPairRequest decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "GenerateSM2KeyPairRequest"); + P11Slot.P11NewKeyControl control = decodeNewKeyControl(decoder); + return new GenerateSM2KeyPairRequest(control); + } + + } + + /** + * The request to get mechanism infos. + */ + public static class GetMechanismInfosResponse extends ProxyMessage { + + private final Map mechamismInfoMap; + + public GetMechanismInfosResponse(Map mechamismInfoMap) { + this.mechamismInfoMap = mechamismInfoMap; + } + + @Override + public void encode0(CborEncoder encoder) throws IOException, EncodeException { + encoder.writeMapStart(mechamismInfoMap.size()); + for (Map.Entry entry : mechamismInfoMap.entrySet()) { + encoder.writeInt(entry.getKey()); + MechanismInfo mi = entry.getValue(); + if (entry.getValue() == null) { + encoder.writeNull(); + } else { + encoder.writeArrayStart(3); + encoder.writeInt(mi.getMinKeySize()); + encoder.writeInt(mi.getMaxKeySize()); + encoder.writeInt(mi.getFlags()); + } + } + } + + public Map getMechamismInfoMap() { + return mechamismInfoMap; + } + + public static GetMechanismInfosResponse decode(CborDecoder decoder) throws DecodeException { + try { + Integer mapLen = decoder.readNullOrMapLength(); + if (mapLen == null) { + throw new DecodeException("GetMechanismInfosResponse shall not be null"); + } + + Map map = new HashMap<>(mapLen * 5 / 4); + for (int i = 0; i < mapLen; i++) { + long code = decoder.readLong(); + boolean isNull = decoder.readNullOrArrayLength(3); + if (isNull) { + map.put(code, null); + } else { + long minSize = decoder.readLong(); + long maxSize = decoder.readLong(); + long flags = decoder.readLong(); + map.put(code, new MechanismInfo(minSize, maxSize, flags)); + } + } + + return new GetMechanismInfosResponse(map); + } catch (IOException ex) { + throw new DecodeException("IO error decoding GetMechanismInfosResponse", ex); + } + } + + } + + /** + * The message wrapper for ia and label. + */ + public static class IdLabelMessage extends ProxyMessage { + + private static final int NUM_FIELDS = 2; + + private final byte[] id; + + private final String label; + + public IdLabelMessage(byte[] id, String label) { + this.id = id; + this.label = label; + } + + public byte[] getId() { + return id; + } + + public String getLabel() { + return label; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + encoder.writeByteString(id); + encoder.writeTextString(label); + } + + public static IdLabelMessage decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "IdLabelMessage"); + try { + byte[] id = decoder.readByteString(); + String label = decoder.readTextString(); + return new IdLabelMessage(id, label); + } catch (IOException ex) { + throw new DecodeException("IO error decoding IdLabelMessage", ex); + } + } + + } + + /** + * The request to import secret key. + */ + public static class ImportSecretKeyRequest extends ProxyMessage { + private static final int NUM_FIELDS = 3; + private final long keyType; + private final byte[] keyValue; + private final P11Slot.P11NewKeyControl newKeyControl; + + public ImportSecretKeyRequest(long keyType, byte[] keyValue, P11Slot.P11NewKeyControl newKeyControl) { + this.keyType = keyType; + this.keyValue = Args.notNull(keyValue, "keyValue"); + this.newKeyControl = newKeyControl; + } + + public long getKeyType() { + return keyType; + } + + public byte[] getKeyValue() { + return keyValue; + } + + public P11Slot.P11NewKeyControl getNewKeyControl() { + return newKeyControl; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + encoder.writeInt(keyType); + encoder.writeByteString(keyValue); + writeNewKeyControl(encoder, newKeyControl); + } + + public static ImportSecretKeyRequest decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "ImportSecretKeyRequest"); + try { + long keyType = decoder.readLong(); + byte[] keyValue = decoder.readByteString(); + P11Slot.P11NewKeyControl control = decodeNewKeyControl(decoder); + return new ImportSecretKeyRequest(keyType, keyValue, control); + } catch (IOException ex) { + throw new DecodeException("IO error decoding ImportSecretKeyRequest", ex); + } + } + + } + + /** + * The message wrapper for int. + */ + public static class IntMessage extends ProxyMessage { + + private final int value; + + public IntMessage(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeInt(value); + } + + public static IntMessage decode(CborDecoder decoder) throws DecodeException { + try { + int b = Optional.ofNullable(decoder.readIntObj()).orElseThrow( + () -> new DecodeException("IntMessage shall not be null")); + return new IntMessage(b); + } catch (IOException ex) { + throw new DecodeException("IO error decoding IntMessage", ex); + } + } + + } + + /** + * The message wrapper for {@link PKCS11KeyId}. + */ + public static class KeyIdMessage extends ProxyMessage { + private static final int NUM_FIELDS = 6; + private final PKCS11KeyId keyId; + + public KeyIdMessage(PKCS11KeyId keyId) { + this.keyId = keyId; + } + + public PKCS11KeyId getKeyId() { + return keyId; + } + + @Override + public void encode0(CborEncoder encoder) throws IOException, EncodeException { + if (keyId == null) { + encoder.writeNull(); + return; + } + + encoder.writeArrayStart(NUM_FIELDS); + encoder.writeInt(keyId.getHandle()); + encoder.writeInt(keyId.getKeyType()); + encoder.writeInt(keyId.getObjectCLass()); + encoder.writeByteString(keyId.getId()); + encoder.writeTextString(keyId.getLabel()); + encoder.writeIntObj(keyId.getPublicKeyHandle()); + } + + public static KeyIdMessage decode(CborDecoder decoder) throws DecodeException { + PKCS11KeyId keyId = Optional.ofNullable(decodeKeyId(decoder)).orElseThrow( + () -> new DecodeException("KeyIdMessage shall not be null")); + return new KeyIdMessage(keyId); + } + + } + + /** + * The message wrapper for long[]. + */ + public static class LongArrayMessage extends ProxyMessage { + + private final long[] value; + + public LongArrayMessage(long[] value) { + this.value = value; + } + + public long[] getValue() { + return value; + } + + @Override + public void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeLongs(value); + } + + public static LongArrayMessage decode(CborDecoder decoder) throws DecodeException { + try { + long[] value = Optional.ofNullable(decoder.readLongs()).orElseThrow( + () -> new DecodeException("LongMessage shall not be null")); + return new LongArrayMessage(value); + } catch (IOException ex) { + throw new DecodeException("IO error decoding LongArrayMessage", ex); + } + } + + } + + /** + * The message wrapper for long. + */ + public static class LongMessage extends ProxyMessage { + + private final long value; + + public LongMessage(long value) { + this.value = value; + } + + public long getValue() { + return value; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeInt(value); + } + + public static LongMessage decode(CborDecoder decoder) throws DecodeException { + try { + long b = Optional.ofNullable(decoder.readLongObj()).orElseThrow( + () -> new DecodeException("LongMessage shall not be null")); + return new LongMessage(b); + } catch (IOException ex) { + throw new DecodeException("IO error decoding LongMessage", ex); + } + } + + } + + /** + * The response of getting module capability. + */ + public static class ModuleCapsResponse extends ProxyMessage { + + private static final int NUM_FIELDS = 5; + + private final boolean readOnly; + + private final int maxMessageSize; + + private final P11ModuleConf.P11NewObjectConf newObjectConf; + + private final List secretKeyTypes; + + private final List keyPairTypes; + + public ModuleCapsResponse(boolean readOnly, int maxMessageSize, P11ModuleConf.P11NewObjectConf newObjectConf, + List secretKeyTypes, List keyPairTypes) { + this.readOnly = readOnly; + this.maxMessageSize = maxMessageSize; + this.newObjectConf = newObjectConf; + this.secretKeyTypes = secretKeyTypes; + this.keyPairTypes = keyPairTypes; + } + + public boolean isReadOnly() { + return readOnly; + } + + public int getMaxMessageSize() { + return maxMessageSize; + } + + public P11ModuleConf.P11NewObjectConf getNewObjectConf() { + return newObjectConf; + } + + public List getSecretKeyTypes() { + return secretKeyTypes; + } + + public List getKeyPairTypes() { + return keyPairTypes; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + encoder.writeBoolean(readOnly); + encoder.writeInt(maxMessageSize); + if (newObjectConf == null) { + encoder.writeNull(); + } else { + encoder.writeArrayStart(2); + encoder.writeBoolean(newObjectConf.isIgnoreLabel()); + encoder.writeInt(newObjectConf.getIdLength()); + } + + encoder.writeLongs(secretKeyTypes); + encoder.writeLongs(keyPairTypes); + } + + public static ModuleCapsResponse decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "ModuleCapsResponse"); + try { + boolean readOnly = decoder.readBoolean(); + int maxMessageSize = decoder.readInt(); + P11ModuleConf.P11NewObjectConf newObjectConf; + if (decoder.readNullOrArrayLength(2)) { + newObjectConf = null; + } else { + newObjectConf = new P11ModuleConf.P11NewObjectConf(); + newObjectConf.setIgnoreLabel(decoder.readBoolean()); + newObjectConf.setIdLength(decoder.readInt()); + } + + List secretKeyTypes = decoder.readLongList(); + List keyPairTypes = decoder.readLongList(); + + return new ModuleCapsResponse(readOnly, maxMessageSize, newObjectConf, secretKeyTypes, keyPairTypes); + } catch (IOException ex) { + throw new DecodeException("IO error decoding ModuleCapsResponse", ex); + } + } + + } // class ServerCaps + + /** + * The response of getting PKCS#11 key. + */ + public static class P11KeyResponse extends ProxyMessage { + + private static final int NUM_FIELDS = 9; + + private final PKCS11KeyId keyId; + + private boolean sign; + + private ASN1ObjectIdentifier ecParams; + + private Integer ecOrderBitSize; + + private BigInteger rsaModulus; + + private BigInteger rsaPublicExponent; + + private BigInteger dsaP; + + private BigInteger dsaQ; + + private BigInteger dsaG; + + public P11KeyResponse(P11Key key) { + Args.notNull(key, "key"); + this.keyId = key.getKeyId(); + this.ecParams = key.getEcParams(); + this.ecOrderBitSize = key.getEcOrderBitSize(); + this.dsaP = key.getDsaP(); + this.dsaQ = key.getDsaQ(); + this.dsaG = key.getDsaG(); + this.rsaModulus = key.getRsaModulus(); + this.rsaPublicExponent = key.getRsaPublicExponent(); + this.sign = key.isSign(); + } + + public P11KeyResponse(PKCS11KeyId keyId) { + this.keyId = Args.notNull(keyId, "keyId"); + } + + public P11Key getP11Key(HsmProxyP11Slot slot) { + HsmProxyP11Key key = new HsmProxyP11Key(slot, keyId); + key.setEcParams(ecParams); + key.setDsaParameters(dsaP, dsaQ, dsaG); + key.setRsaMParameters(rsaModulus, rsaPublicExponent); + key.sign(sign); + return key; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + writeKeyId(encoder, keyId); + encoder.writeBoolean(sign); + writeOid(encoder, ecParams); + encoder.writeIntObj(ecOrderBitSize); + writeBigInt(encoder, rsaModulus); + writeBigInt(encoder, rsaPublicExponent); + writeBigInt(encoder, dsaP); + writeBigInt(encoder, dsaQ); + writeBigInt(encoder, dsaG); + } + + public static P11KeyResponse decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "ModuleCapsResponse"); + try { + PKCS11KeyId keyId = decodeKeyId(decoder); + P11KeyResponse ret = new P11KeyResponse(keyId); + ret.sign = decoder.readBoolean(); + ret.ecParams = readOid(decoder); + ret.ecOrderBitSize = decoder.readIntObj(); + ret.rsaModulus = decoder.readBigInt(); + ret.rsaPublicExponent = decoder.readBigInt(); + ret.dsaP = decoder.readBigInt(); + ret.dsaQ = decoder.readBigInt(); + ret.dsaG = decoder.readBigInt(); + + return ret; + } catch (IOException ex) { + throw new DecodeException("IO error decoding P11KeyResponse", ex); + } + } + + } + + /** + * The request to show details of given slot, and optional given object handle. + */ + public static class ShowDetailsRequest extends ProxyMessage { + + private static final int NUM_FIELDS = 2; + + private final Long objectHandle; + + private final boolean verbose; + + public ShowDetailsRequest(Long objectHandle, boolean verbose) { + this.objectHandle = objectHandle; + this.verbose = verbose; + } + + public Long getObjectHandle() { + return objectHandle; + } + + public boolean isVerbose() { + return verbose; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + encoder.writeIntObj(objectHandle); + encoder.writeBoolean(verbose); + } + + public static ShowDetailsRequest decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "ShowDetailsRequest"); + try { + Long objectHandle = decoder.readLongObj(); + boolean verbose = decoder.readBoolean(); + return new ShowDetailsRequest(objectHandle, verbose); + } catch (IOException ex) { + throw new DecodeException("IO error decoding P11KeyResponse", ex); + } + } + + } + + /** + * The request to sign message. + */ + public static class SignRequest extends ProxyMessage { + + private static final int NUM_FIELDS = 5; + + private static final int TAG_P11ByteArrayParams = 80000; + + private static final int TAG_P11RSAPkcsPssParams = 80001; + + private final long keyHandle; + + private final long mechanism; + + private final P11Params p11params; + + private final ExtraParams extraParams; + + private final byte[] content; + + public SignRequest(long keyHandle, long mechanism, P11Params p11params, ExtraParams extraParams, byte[] content) { + this.keyHandle = keyHandle; + this.mechanism = mechanism; + this.p11params = p11params; + this.extraParams = extraParams; + this.content = content; + } + + public long getKeyHandle() { + return keyHandle; + } + + public byte[] getContent() { + return content; + } + + public long getMechanism() { + return mechanism; + } + + public P11Params getP11params() { + return p11params; + } + + public ExtraParams getExtraParams() { + return extraParams; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(NUM_FIELDS); + encoder.writeInt(keyHandle); + encoder.writeInt(mechanism); + writeP11Params(encoder, p11params); + writeExtraParams(encoder, extraParams); + encoder.writeByteString(content); + } + + public static SignRequest decode(CborDecoder decoder) throws DecodeException { + assertArraySize(decoder, NUM_FIELDS, "SignRequest"); + try { + long handle = decoder.readLong(); + long mechanism = decoder.readLong(); + P11Params params = decodeP11Params(decoder); + ExtraParams extraParams = decodeExtraParams(decoder); + byte[] content = decoder.readByteString(); + return new SignRequest(handle, mechanism, params, extraParams, content); + } catch (IOException ex) { + throw new DecodeException("IO error decoding SignRequest", ex); + } + } + + private static void writeExtraParams(CborEncoder encoder, ExtraParams params) throws IOException { + if (params == null) { + encoder.writeNull(); + return; + } + encoder.writeArrayStart(1); + encoder.writeInt(params.ecOrderBitSize()); + } + + private static ExtraParams decodeExtraParams(CborDecoder decoder) throws DecodeException { + try { + if (decoder.readNullOrArrayLength(1)) { + return null; + } + + return new ExtraParams().ecOrderBitSize(decoder.readInt()); + } catch (IOException ex) { + throw new DecodeException("IO error", ex); + } + } + + protected static void writeP11Params(CborEncoder encoder, P11Params params) + throws IOException { + if (params == null) { + encoder.writeNull(); + return; + } + + if (params instanceof P11Params.P11ByteArrayParams) { + P11Params.P11ByteArrayParams tParams = (P11Params.P11ByteArrayParams) params; + encoder.writeTag(TAG_P11ByteArrayParams); + encoder.writeArrayStart(1); + encoder.writeByteString(tParams.getBytes()); + } else if (params instanceof P11Params.P11RSAPkcsPssParams) { + P11Params.P11RSAPkcsPssParams tParams = (P11Params.P11RSAPkcsPssParams) params; + encoder.writeTag(TAG_P11RSAPkcsPssParams); + encoder.writeArrayStart(3); + encoder.writeInt(tParams.getHashAlgorithm()); + encoder.writeInt(tParams.getMaskGenerationFunction()); + encoder.writeInt(tParams.getSaltLength()); + } else { + throw new IllegalStateException("unknown params " + params.getClass().getName()); + } + } + + public static P11Params decodeP11Params(CborDecoder decoder) throws DecodeException { + try { + Long tag = decoder.readTagObj(); + if (tag == null) { + return null; + } + + if (TAG_P11ByteArrayParams == tag) { + assertArraySize(decoder, 1, "P11ByteArrayParams"); + return new P11Params.P11ByteArrayParams(decoder.readByteString()); + } else if (TAG_P11RSAPkcsPssParams == tag) { + assertArraySize(decoder, 3, "P11RSAPkcsPssParams"); + long hashAlgorithm = decoder.readLong(); + long maskGenerationFunction = decoder.readLong(); + int saltLength = decoder.readInt(); + return new P11Params.P11RSAPkcsPssParams(hashAlgorithm, maskGenerationFunction, saltLength); + } else { + throw new DecodeException("unknown tag " + tag); + } + } catch (IOException ex) { + throw new DecodeException("IO error", ex); + } + } + + } + + /** + * The response of getting slot identifiers. + */ + public static class SlotIdsResponse extends ProxyMessage { + + private final List slotIds; + + public SlotIdsResponse(List slotIds) { + this.slotIds = Args.notNull(slotIds, "slotIds"); + } + + public List getSlotIds() { + return slotIds; + } + + @Override + protected void encode0(CborEncoder encoder) throws EncodeException, IOException { + encoder.writeArrayStart(slotIds.size()); + for (P11SlotId slotId : slotIds) { + encoder.writeArrayStart(2); + encoder.writeInt(slotId.getIndex()); + encoder.writeInt(slotId.getId()); + } + } + + public static SlotIdsResponse decode(CborDecoder decoder) throws DecodeException { + try { + int arrayLen = Optional.ofNullable(decoder.readNullOrArrayLength()).orElseThrow( + () -> new DecodeException("SlotIdsResponse shall not be null")); + + List list = new ArrayList<>(arrayLen); + for (int i = 0; i < arrayLen; i++) { + assertArraySize(decoder, 2, "P11SlotId"); + int index = decoder.readInt(); + long id = decoder.readLong(); + list.add(new P11SlotId(index, id)); + } + + return new SlotIdsResponse(list); + } catch (IOException ex) { + throw new DecodeException("IO error decoding SlotIdsResponse", ex); + } + } + } +} diff --git a/security/src/main/java/org/xipki/security/qa/P11SignSpeed.java b/security/src/main/java/org/xipki/security/qa/P11SignSpeed.java index 849d604..ce68688 100644 --- a/security/src/main/java/org/xipki/security/qa/P11SignSpeed.java +++ b/security/src/main/java/org/xipki/security/qa/P11SignSpeed.java @@ -252,7 +252,7 @@ public P11SignSpeed(SecurityFactory securityFactory, P11Slot slot, String signat this.deleteKeyAfterTest = deleteKeyAfterTest; P11SlotId slotId = slot.getSlotId(); - SignerConf signerConf = getPkcs11SignerConf( + SignerConf signerConf = getPkcs11SignerConf(slot.getModuleName(), slotId.getId(), keyId.getId(), Args.notBlank(signatureAlgorithm, "signatureAlgorithm"), threads + Math.max(2, threads * 5 / 4)); @@ -297,10 +297,14 @@ protected Runnable getTester() throws Exception { } private static SignerConf getPkcs11SignerConf( - Long slotId, byte[] keyId, String signatureAlgorithm, int parallelism) { + String pkcs11ModuleName, Long slotId, byte[] keyId, String signatureAlgorithm, int parallelism) { ConfPairs conf = new ConfPairs("algo", signatureAlgorithm) .putPair("parallelism", Integer.toString(parallelism)); + if (pkcs11ModuleName != null && !pkcs11ModuleName.isEmpty()) { + conf.putPair("module", pkcs11ModuleName); + } + if (slotId != null) { conf.putPair("slot-id", slotId.toString()); } diff --git a/security/src/main/resources/OSGI-INF/blueprint/config.xml b/security/src/main/resources/OSGI-INF/blueprint/config.xml index d5bd74c..063bfba 100644 --- a/security/src/main/resources/OSGI-INF/blueprint/config.xml +++ b/security/src/main/resources/OSGI-INF/blueprint/config.xml @@ -92,4 +92,12 @@ + + + + + + diff --git a/util/src/main/java/org/xipki/util/Args.java b/util/src/main/java/org/xipki/util/Args.java index 18bb2a0..72fb98c 100644 --- a/util/src/main/java/org/xipki/util/Args.java +++ b/util/src/main/java/org/xipki/util/Args.java @@ -3,7 +3,6 @@ package org.xipki.util; -import java.util.Arrays; import java.util.Collection; import java.util.Dictionary; import java.util.List; From ddaa2fd491bc000cae232afe2e2cfd8d84ca50cd Mon Sep 17 00:00:00 2001 From: Lijun Liao Date: Thu, 7 Nov 2024 19:39:24 +0100 Subject: [PATCH 08/11] merged ByteArrayCborDecoder to CborDecoder --- .../xipki/util/cbor/ByteArrayCborDecoder.java | 44 ------------------- .../java/org/xipki/util/cbor/CborDecoder.java | 18 ++++++-- 2 files changed, 15 insertions(+), 47 deletions(-) delete mode 100644 util/src/main/java/org/xipki/util/cbor/ByteArrayCborDecoder.java diff --git a/util/src/main/java/org/xipki/util/cbor/ByteArrayCborDecoder.java b/util/src/main/java/org/xipki/util/cbor/ByteArrayCborDecoder.java deleted file mode 100644 index 787ab49..0000000 --- a/util/src/main/java/org/xipki/util/cbor/ByteArrayCborDecoder.java +++ /dev/null @@ -1,44 +0,0 @@ -// #THIRDPARTY -/* - * JACOB - CBOR implementation in Java. - * - * (C) Copyright - 2013 - J.W. Janssen - * - * Licensed under Apache License v2.0. - */ -package org.xipki.util.cbor; - -import org.xipki.util.Args; - -import java.io.ByteArrayInputStream; - -public class ByteArrayCborDecoder extends CborDecoder { - - /** - * Creates a new {@link ByteArrayCborDecoder} instance. - * @param bytes the encoded cbor message. - */ - public ByteArrayCborDecoder(byte[] bytes) { - this(bytes, 0, bytes.length); - } - - /** - * Creates a new {@link ByteArrayCborDecoder} instance. - * @param bytes the encoded cbor message. - * @param offset offset of bytes. - */ - public ByteArrayCborDecoder(byte[] bytes, int offset) { - this(bytes, offset, bytes.length - offset); - } - - /** - * Creates a new {@link ByteArrayCborDecoder} instance. - * @param bytes the encoded cbor message. - * @param offset offset of bytes for the cbor message. - * @param len length of the bytes for the cbor message. - */ - public ByteArrayCborDecoder(byte[] bytes, int offset, int len) { - super(new ByteArrayInputStream(bytes, Args.min(offset, "offset", 0), Args.min(len, "len", 0))); - } - -} diff --git a/util/src/main/java/org/xipki/util/cbor/CborDecoder.java b/util/src/main/java/org/xipki/util/cbor/CborDecoder.java index 6d046ed..d1600f4 100644 --- a/util/src/main/java/org/xipki/util/cbor/CborDecoder.java +++ b/util/src/main/java/org/xipki/util/cbor/CborDecoder.java @@ -10,6 +10,7 @@ import org.xipki.util.DateUtil; import org.xipki.util.exception.DecodeException; +import java.io.ByteArrayInputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -27,6 +28,17 @@ public class CborDecoder implements AutoCloseable { protected final PushbackInputStream m_is; + + public CborDecoder(byte[] bytes) { + this(bytes, 0, bytes.length); + } + + public CborDecoder(byte[] bytes, int offset, int length) { + this(new ByteArrayInputStream(bytes, + Args.min(offset, "offset", 0), + Args.min(length, "length", 0))); + } + /** * Creates a new {@link CborDecoder} instance. * @@ -533,7 +545,7 @@ protected int readUInt16() throws IOException { */ protected long readUInt32() throws IOException { byte[] buf = readFully(new byte[4]); - return ((buf[0] & 0xFF) << 24 | (buf[1] & 0xFF) << 16 | (buf[2] & 0xFF) << 8 | (buf[3] & 0xFF)) & 0xffffffffL; + return ((buf[0] & 0xFFL) << 24 | (buf[1] & 0xFF) << 16 | (buf[2] & 0xFF) << 8 | (buf[3] & 0xFF)) & 0xffffffffL; } /** @@ -619,7 +631,7 @@ public Integer readNullOrArrayLength() throws IOException, DecodeException { } } - public Integer readNullOrArrayLength(Class clazz) throws DecodeException { + public Integer readNullOrArrayLength(Class clazz) throws DecodeException { try { return readNullOrArrayLength(); } catch (IOException ex) { @@ -777,7 +789,7 @@ public BigInteger[] readBigInts() throws IOException, DecodeException { } BigInteger[] ret = new BigInteger[arrayLen]; - for (int i = 0; i < arrayLen.intValue(); i++) { + for (int i = 0; i < arrayLen; i++) { ret[i] = readBigInt(); } From dcbf6251e9eff1da92caedc34bbe1b1321c56b7a Mon Sep 17 00:00:00 2001 From: Lijun Liao Date: Thu, 7 Nov 2024 19:39:54 +0100 Subject: [PATCH 09/11] Use static method correctly. --- .../pkcs11/hsmproxy/HsmProxyP11Module.java | 3 +-- .../java/org/xipki/security/qa/P12SignSpeed.java | 14 +++++++------- .../java/org/xipki/security/util/PKCS1Util.java | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Module.java b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Module.java index be128f5..d1e7e09 100644 --- a/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Module.java +++ b/security/src/main/java/org/xipki/security/pkcs11/hsmproxy/HsmProxyP11Module.java @@ -27,7 +27,6 @@ import org.xipki.util.IoUtil; import org.xipki.util.LogUtil; import org.xipki.util.StringUtil; -import org.xipki.util.cbor.ByteArrayCborDecoder; import org.xipki.util.cbor.CborConstants; import org.xipki.util.cbor.CborDecoder; import org.xipki.util.cbor.CborType; @@ -336,7 +335,7 @@ public ProxyMessage send(ProxyAction action, byte[] request) throws TokenExcepti throw new TokenException(ex.getMessage(), ex); } - CborDecoder decoder = new ByteArrayCborDecoder(respBytes); + CborDecoder decoder = new CborDecoder(respBytes); ErrorResponse errorResp = null; try { diff --git a/security/src/main/java/org/xipki/security/qa/P12SignSpeed.java b/security/src/main/java/org/xipki/security/qa/P12SignSpeed.java index 8c30f44..07ff7a8 100644 --- a/security/src/main/java/org/xipki/security/qa/P12SignSpeed.java +++ b/security/src/main/java/org/xipki/security/qa/P12SignSpeed.java @@ -46,7 +46,7 @@ public AESGmac(SecurityFactory securityFactory, String signatureAlgorithm, int t private static byte[] generateKeystore(String signatureAlgorithm) throws Exception { int keysize = getKeysize(signatureAlgorithm); - KeyStoreWrapper identity = new P12KeyGenerator().generateSecretKey( + KeyStoreWrapper identity = P12KeyGenerator.generateSecretKey( "AES", keysize, new KeystoreGenerationParameters(PASSWORD.toCharArray())); return identity.keystore(); } @@ -86,7 +86,7 @@ private static byte[] generateKeystore(int plength, int qlength) throws Exceptio if (keystoreBytes == null) { KeystoreGenerationParameters params = new KeystoreGenerationParameters(PASSWORD.toCharArray()); params.setRandom(new SecureRandom()); - KeyStoreWrapper identity = new P12KeyGenerator().generateDSAKeypair(plength, qlength, params, null); + KeyStoreWrapper identity = P12KeyGenerator.generateDSAKeypair(plength, qlength, params, null); keystoreBytes = identity.keystore(); } return keystoreBytes; @@ -108,8 +108,8 @@ private static byte[] generateKeystore(ASN1ObjectIdentifier curveOid) throws Exc KeystoreGenerationParameters params = new KeystoreGenerationParameters(PASSWORD.toCharArray()); params.setRandom(new SecureRandom()); KeyStoreWrapper identity = EdECConstants.isEdwardsOrMontgomeryCurve(curveOid) - ? new P12KeyGenerator().generateEdECKeypair(curveOid, params, null) - : new P12KeyGenerator().generateECKeypair(curveOid, params, null); + ? P12KeyGenerator.generateEdECKeypair(curveOid, params, null) + : P12KeyGenerator.generateECKeypair(curveOid, params, null); keystoreBytes = identity.keystore(); } @@ -127,7 +127,7 @@ public HMAC(SecurityFactory securityFactory, String signatureAlgorithm, int thre private static byte[] generateKeystore(String signatureAlgorithm) throws Exception { int keysize = getKeysize(signatureAlgorithm); - KeyStoreWrapper identity = new P12KeyGenerator().generateSecretKey( + KeyStoreWrapper identity = P12KeyGenerator.generateSecretKey( "GENERIC", keysize, new KeystoreGenerationParameters(PASSWORD.toCharArray())); return identity.keystore(); } @@ -177,7 +177,7 @@ private static byte[] generateKeystore(int keysize, BigInteger publicExponent) t if (keystoreBytes == null) { KeystoreGenerationParameters params = new KeystoreGenerationParameters(PASSWORD.toCharArray()); params.setRandom(new SecureRandom()); - KeyStoreWrapper identity = new P12KeyGenerator().generateRSAKeypair(keysize, publicExponent, params, null); + KeyStoreWrapper identity = P12KeyGenerator.generateRSAKeypair(keysize, publicExponent, params, null); keystoreBytes = identity.keystore(); } return keystoreBytes; @@ -197,7 +197,7 @@ private static byte[] generateKeystore(ASN1ObjectIdentifier curveNOid) throws Ex if (keystoreBytes == null) { KeystoreGenerationParameters params = new KeystoreGenerationParameters(PASSWORD.toCharArray()); params.setRandom(new SecureRandom()); - KeyStoreWrapper identity = new P12KeyGenerator().generateECKeypair(curveNOid, params, null); + KeyStoreWrapper identity = P12KeyGenerator.generateECKeypair(curveNOid, params, null); keystoreBytes = identity.keystore(); } return keystoreBytes; diff --git a/security/src/main/java/org/xipki/security/util/PKCS1Util.java b/security/src/main/java/org/xipki/security/util/PKCS1Util.java index 26fa96b..4fbdfc3 100644 --- a/security/src/main/java/org/xipki/security/util/PKCS1Util.java +++ b/security/src/main/java/org/xipki/security/util/PKCS1Util.java @@ -142,7 +142,7 @@ public static byte[] EMSA_PSS_ENCODE(HashAlgo contentDigest, byte[] hashValue, H block[i] ^= dbMask[i]; } - block[0] &= (0xff >> ((block.length * 8) - emBits)); + block[0] &= (byte) (0xff >> ((block.length * 8) - emBits)); System.arraycopy(hv, 0, block, block.length - hLen - 1, hLen); @@ -211,7 +211,7 @@ public static boolean EMSA_PSS_DECODE(HashAlgo mgfDigest, byte[] mHash, byte[] E DB[i] = (byte)(DB[i] ^ dbMask[i]); } // 9. Set the leftmost 8.emLen ? emBits bits of DB to zero. - DB[0] &= (0xFF >>> (8*emLen - emBits)); + DB[0] &= (byte) (0xFF >>> (8*emLen - emBits)); // 10. If the emLen - hLen -sLen -2 leftmost octets of DB are not zero or // if the octet at position emLen -hLen -sLen -1 is not equal to 0x01, // output 'inconsistent' and stop. From e836126eae2bbe914af1aef2a49fb0f8ee3c0350 Mon Sep 17 00:00:00 2001 From: Lijun Liao Date: Thu, 7 Nov 2024 19:57:17 +0100 Subject: [PATCH 10/11] update dependencies --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 042e819..358edda 100644 --- a/pom.xml +++ b/pom.xml @@ -29,12 +29,12 @@ UTF-8 - 1.77 + 1.78.1 1.7.36 - 1.0.8 + 1.0.9 4.0.3 2.16.1 - 4.4.4 + 4.4.6 4.13.1 From 7afbae83307a32ae1b8aa5b3195335ba12cf23df Mon Sep 17 00:00:00 2001 From: Lijun Liao Date: Thu, 7 Nov 2024 22:43:04 +0100 Subject: [PATCH 11/11] remove support of servlet3 --- pom.xml | 3 +- {servlet5-common => servlet-common}/pom.xml | 2 +- .../org/xipki/servlet}/ServletFilter.java | 2 +- .../org/xipki/servlet}/XiHttpRequestImpl.java | 2 +- .../xipki/servlet}/XiHttpResponseImpl.java | 2 +- servlet3-common/pom.xml | 26 ------ .../org/xipki/servlet3/ServletFilter.java | 73 ---------------- .../org/xipki/servlet3/XiHttpRequestImpl.java | 83 ------------------- .../xipki/servlet3/XiHttpResponseImpl.java | 59 ------------- xipki-tomcat-password/pom.xml | 2 +- 10 files changed, 6 insertions(+), 248 deletions(-) rename {servlet5-common => servlet-common}/pom.xml (95%) rename {servlet5-common/src/main/java/org/xipki/servlet5 => servlet-common/src/main/java/org/xipki/servlet}/ServletFilter.java (98%) rename {servlet5-common/src/main/java/org/xipki/servlet5 => servlet-common/src/main/java/org/xipki/servlet}/XiHttpRequestImpl.java (98%) rename {servlet5-common/src/main/java/org/xipki/servlet5 => servlet-common/src/main/java/org/xipki/servlet}/XiHttpResponseImpl.java (97%) delete mode 100644 servlet3-common/pom.xml delete mode 100644 servlet3-common/src/main/java/org/xipki/servlet3/ServletFilter.java delete mode 100644 servlet3-common/src/main/java/org/xipki/servlet3/XiHttpRequestImpl.java delete mode 100644 servlet3-common/src/main/java/org/xipki/servlet3/XiHttpResponseImpl.java diff --git a/pom.xml b/pom.xml index 358edda..e213a0c 100644 --- a/pom.xml +++ b/pom.xml @@ -49,8 +49,7 @@ shell-base security-shell xipki-tomcat-password - servlet3-common - servlet5-common + servlet-common scm:git:git@github.com:xipki/commons.git diff --git a/servlet5-common/pom.xml b/servlet-common/pom.xml similarity index 95% rename from servlet5-common/pom.xml rename to servlet-common/pom.xml index 469116f..0298965 100644 --- a/servlet5-common/pom.xml +++ b/servlet-common/pom.xml @@ -8,7 +8,7 @@ xipki-commons-parent 6.3.5-SNAPSHOT - servlet5-common + servlet-common XiPKI :: ${project.artifactId} bundle diff --git a/servlet5-common/src/main/java/org/xipki/servlet5/ServletFilter.java b/servlet-common/src/main/java/org/xipki/servlet/ServletFilter.java similarity index 98% rename from servlet5-common/src/main/java/org/xipki/servlet5/ServletFilter.java rename to servlet-common/src/main/java/org/xipki/servlet/ServletFilter.java index 3d465f5..2a6a088 100644 --- a/servlet5-common/src/main/java/org/xipki/servlet5/ServletFilter.java +++ b/servlet-common/src/main/java/org/xipki/servlet/ServletFilter.java @@ -1,7 +1,7 @@ // Copyright (c) 2013-2024 xipki. All rights reserved. // License Apache License 2.0 -package org.xipki.servlet5; +package org.xipki.servlet; import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; diff --git a/servlet5-common/src/main/java/org/xipki/servlet5/XiHttpRequestImpl.java b/servlet-common/src/main/java/org/xipki/servlet/XiHttpRequestImpl.java similarity index 98% rename from servlet5-common/src/main/java/org/xipki/servlet5/XiHttpRequestImpl.java rename to servlet-common/src/main/java/org/xipki/servlet/XiHttpRequestImpl.java index c49c4a3..20e84ea 100644 --- a/servlet5-common/src/main/java/org/xipki/servlet5/XiHttpRequestImpl.java +++ b/servlet-common/src/main/java/org/xipki/servlet/XiHttpRequestImpl.java @@ -1,6 +1,6 @@ // Copyright (c) 2013-2024 xipki. All rights reserved. // License Apache License 2.0 -package org.xipki.servlet5; +package org.xipki.servlet; import jakarta.servlet.http.HttpServletRequest; import org.xipki.util.http.XiHttpRequest; diff --git a/servlet5-common/src/main/java/org/xipki/servlet5/XiHttpResponseImpl.java b/servlet-common/src/main/java/org/xipki/servlet/XiHttpResponseImpl.java similarity index 97% rename from servlet5-common/src/main/java/org/xipki/servlet5/XiHttpResponseImpl.java rename to servlet-common/src/main/java/org/xipki/servlet/XiHttpResponseImpl.java index c4e1934..f1e1a19 100644 --- a/servlet5-common/src/main/java/org/xipki/servlet5/XiHttpResponseImpl.java +++ b/servlet-common/src/main/java/org/xipki/servlet/XiHttpResponseImpl.java @@ -1,6 +1,6 @@ // Copyright (c) 2013-2024 xipki. All rights reserved. // License Apache License 2.0 -package org.xipki.servlet5; +package org.xipki.servlet; import jakarta.servlet.http.HttpServletResponse; import org.xipki.util.Args; diff --git a/servlet3-common/pom.xml b/servlet3-common/pom.xml deleted file mode 100644 index d67bd2b..0000000 --- a/servlet3-common/pom.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - 4.0.0 - - org.xipki.commons - xipki-commons-parent - 6.3.5-SNAPSHOT - - servlet3-common - XiPKI :: ${project.artifactId} - bundle - - - ${project.groupId} - util - ${project.version} - - - javax.servlet - javax.servlet-api - 3.1.0 - - - diff --git a/servlet3-common/src/main/java/org/xipki/servlet3/ServletFilter.java b/servlet3-common/src/main/java/org/xipki/servlet3/ServletFilter.java deleted file mode 100644 index 95f10e0..0000000 --- a/servlet3-common/src/main/java/org/xipki/servlet3/ServletFilter.java +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2013-2024 xipki. All rights reserved. -// License Apache License 2.0 - -package org.xipki.servlet3; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xipki.util.http.XiHttpFilter; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * Filter. - * - * @author Lijun Liao (xipki) - * @since 6.0.0 - */ -public abstract class ServletFilter implements Filter { - - private static final Logger LOG = LoggerFactory.getLogger(ServletFilter.class); - - private XiHttpFilter filter0; - - protected abstract XiHttpFilter initFilter(FilterConfig filterConfig) throws Exception; - - @Override - public void init(FilterConfig filterConfig) throws ServletException { - try { - filter0 = initFilter(filterConfig); - } catch (Exception ex) { - LOG.error("error initializing ServletFiler", ex); - throw new ServletException(ex); - } - } - - @Override - public void destroy() { - if (filter0 != null) { - filter0.destroy(); - filter0 = null; - } - } - - @Override - public final void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { - if (filter0 == null) { - throw new ServletException("filter is not initialized"); - } - - if (!(request instanceof HttpServletRequest & response instanceof HttpServletResponse)) { - throw new ServletException("Only HTTP request is supported"); - } - - try { - filter0.doFilter(new XiHttpRequestImpl((HttpServletRequest) request), - new XiHttpResponseImpl((HttpServletResponse) response)); - } catch (IOException ex) { - throw ex; - } catch (Exception ex) { - throw new ServletException(ex); - } - } - -} diff --git a/servlet3-common/src/main/java/org/xipki/servlet3/XiHttpRequestImpl.java b/servlet3-common/src/main/java/org/xipki/servlet3/XiHttpRequestImpl.java deleted file mode 100644 index 5eedfe9..0000000 --- a/servlet3-common/src/main/java/org/xipki/servlet3/XiHttpRequestImpl.java +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2013-2024 xipki. All rights reserved. -// License Apache License 2.0 -package org.xipki.servlet3; - -import org.xipki.util.Args; -import org.xipki.util.http.XiHttpRequest; - -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.io.InputStream; -import java.security.cert.X509Certificate; - -/** - * HTTP request wrapper. - * - * @author Lijun Liao (xipki) - * @since 3.0.1 - */ - -public class XiHttpRequestImpl implements XiHttpRequest { - - private final HttpServletRequest req; - - public XiHttpRequestImpl(HttpServletRequest req) { - this.req = Args.notNull(req, "req"); - } - - @Override - public String getHeader(String headerName) { - return req.getHeader(headerName); - } - - @Override - public String getParameter(String paramName) { - return req.getParameter(paramName); - } - - @Override - public String getMethod() { - return req.getMethod(); - } - - @Override - public String getServletPath() { - return req.getServletPath(); - } - - @Override - public String getContentType() { - return req.getContentType(); - } - - @Override - public Object getAttribute(String name) { - return req.getAttribute(name); - } - - @Override - public String getRequestURI() { - return req.getRequestURI(); - } - - @Override - public String getContextPath() { - return req.getContextPath(); - } - - @Override - public X509Certificate[] getCertificateChain() { - return (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate"); - } - - @Override - public InputStream getInputStream() throws IOException { - return req.getInputStream(); - } - - @Override - public void setAttribute(String name, String value) { - req.setAttribute(name, value); - } - -} diff --git a/servlet3-common/src/main/java/org/xipki/servlet3/XiHttpResponseImpl.java b/servlet3-common/src/main/java/org/xipki/servlet3/XiHttpResponseImpl.java deleted file mode 100644 index bfed8a3..0000000 --- a/servlet3-common/src/main/java/org/xipki/servlet3/XiHttpResponseImpl.java +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2013-2024 xipki. All rights reserved. -// License Apache License 2.0 -package org.xipki.servlet3; - -import org.xipki.util.Args; -import org.xipki.util.http.XiHttpResponse; - -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.OutputStream; - -/** - * HTTP response wrapper. - * - * @author Lijun Liao (xipki) - */ -public class XiHttpResponseImpl implements XiHttpResponse { - - private final HttpServletResponse resp; - - public XiHttpResponseImpl(HttpServletResponse resp) { - this.resp = Args.notNull(resp, "resp"); - } - - @Override - public void setStatus(int sc) { - resp.setStatus(sc); - } - - @Override - public void sendError(int sc) throws IOException { - resp.sendError(sc); - } - - @Override - public void setContentType(String type) { - resp.setContentType(type); - } - - @Override - public void addHeader(String name, String value) { - resp.addHeader(name, value); - } - - @Override - public void setHeader(String name, String value) { - resp.setHeader(name, value); - } - - @Override - public void setContentLength(int len) { - resp.setContentLength(len); - } - - @Override - public OutputStream getOutputStream() throws IOException { - return resp.getOutputStream(); - } -} diff --git a/xipki-tomcat-password/pom.xml b/xipki-tomcat-password/pom.xml index cd28f45..8f0eb0a 100644 --- a/xipki-tomcat-password/pom.xml +++ b/xipki-tomcat-password/pom.xml @@ -14,7 +14,7 @@ org.apache.tomcat tomcat-coyote - 9.0.73 + 10.1.31 ${project.groupId}