/* * * Copyright (c) 2013 - 2017 Lijun Liao * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License version 3 * as published by the Free Software Foundation with the addition of the * following permission added to Section 15 as permitted in Section 7(a): * * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY * THE AUTHOR LIJUN LIAO. LIJUN LIAO DISCLAIMS THE WARRANTY OF NON INFRINGEMENT * OF THIRD PARTY RIGHTS. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License. * * You can be released from the requirements of the license by purchasing * a commercial license. Buying such a license is mandatory as soon as you * develop commercial activities involving the XiPKI software without * disclosing the source code of your own applications. * * For more information, please contact Lijun Liao at this * address: lijun.liao@gmail.com */ package org.xipki.commons.security; import java.io.IOException; import java.io.InputStream; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; import org.xipki.commons.common.ConfPairs; import org.xipki.commons.common.util.IoUtil; import org.xipki.commons.common.util.ParamUtil; import org.xipki.commons.common.util.StringUtil; /** * @author Lijun Liao * @since 2.0.0 */ public class SignerConf { private final ConfPairs confPairs; private final HashAlgoType hashAlgo; private final SignatureAlgoControl signatureAlgoControl; public SignerConf(final String conf) { this.hashAlgo = null; this.signatureAlgoControl = null; ParamUtil.requireNonBlank("conf", conf); this.confPairs = new ConfPairs(conf); if (getConfValue("algo") == null) { throw new IllegalArgumentException("conf must contain the entry 'algo'"); } } public SignerConf(final String confWithoutAlgo, final HashAlgoType hashAlgo, final SignatureAlgoControl signatureAlgoControl) { ParamUtil.requireNonBlank("confWithoutAlgo", confWithoutAlgo); this.hashAlgo = ParamUtil.requireNonNull("hashAlgo", hashAlgo); this.signatureAlgoControl = signatureAlgoControl; this.confPairs = new ConfPairs(confWithoutAlgo); if (getConfValue("algo") != null) { throw new IllegalArgumentException("confWithoutAlgo must not contain the entry 'algo'"); } } public HashAlgoType getHashAlgo() { return hashAlgo; } public SignatureAlgoControl getSignatureAlgoControl() { return signatureAlgoControl; } public void putConfEntry(final String name, final String value) { confPairs.putPair(name, value); } public void removeConfEntry(final String name) { confPairs.removePair(name); } public String getConfValue(String name) { return confPairs.getValue(name); } public String getConf() { return confPairs.getEncoded(); } @Override public String toString() { return toString(true, true); } public String toString(final boolean verbose, final boolean ignoreSensitiveInfo) { String conf = getConf(); if (ignoreSensitiveInfo) { conf = eraseSensitiveData(conf); } StringBuilder sb = new StringBuilder(conf.length() + 50); sb.append("conf: "); sb.append(conf); if (hashAlgo != null) { sb.append("\nhash algo: ").append(hashAlgo.getName()); } if (signatureAlgoControl != null) { sb.append("\nsiganture algo control: ").append(signatureAlgoControl); } return sb.toString(); } public static String toString(final String signerConf, final boolean verbose, final boolean ignoreSensitiveInfo) { String tmpSignerConf = ParamUtil.requireNonBlank("signerConf", signerConf); if (ignoreSensitiveInfo) { tmpSignerConf = eraseSensitiveData(tmpSignerConf); } if (verbose || tmpSignerConf.length() < 101) { return tmpSignerConf; } else { return new StringBuilder().append(tmpSignerConf.substring(0, 97)).append("...") .toString(); } } public static SignerConf getKeystoreSignerConf(final InputStream keystoreStream, final String password, final String signatureAlgorithm, final int parallelism) throws IOException { ParamUtil.requireNonNull("keystoreStream", keystoreStream); ParamUtil.requireNonBlank("password", password); ParamUtil.requireNonNull("signatureAlgorithm", signatureAlgorithm); ParamUtil.requireMin("parallelism", parallelism, 1); ConfPairs conf = new ConfPairs("password", password); conf.putPair("algo", signatureAlgorithm); conf.putPair("parallelism", Integer.toString(parallelism)); conf.putPair("keystore", "base64:" + Base64.toBase64String(IoUtil.read(keystoreStream))); return new SignerConf(conf.getEncoded()); } public static SignerConf getKeystoreSignerConf(final String keystoreFile, final String password, final int parallelism, final HashAlgoType hashAlgo, final SignatureAlgoControl signatureAlgoControl) { ParamUtil.requireNonBlank("keystoreFile", keystoreFile); ParamUtil.requireNonBlank("password", password); ParamUtil.requireMin("parallelism", parallelism, 1); ParamUtil.requireNonNull("hashAlgo", hashAlgo); ConfPairs conf = new ConfPairs("password", password); conf.putPair("parallelism", Integer.toString(parallelism)); conf.putPair("keystore", "file:" + keystoreFile); return new SignerConf(conf.getEncoded(), hashAlgo, signatureAlgoControl); } public static SignerConf getKeystoreSignerConf(final String keystoreFile, final String password, final HashAlgoType hashAlgo, final SignatureAlgoControl signatureAlgoControl) { ParamUtil.requireNonBlank("keystoreFile", keystoreFile); ParamUtil.requireNonBlank("password", password); ParamUtil.requireNonNull("hashAlgo", hashAlgo); ConfPairs conf = new ConfPairs("password", password); conf.putPair("parallelism", "1"); conf.putPair("keystore", "file:" + keystoreFile); return new SignerConf(conf.getEncoded(), hashAlgo, signatureAlgoControl); } public static SignerConf getPkcs11SignerConf(final String pkcs11ModuleName, final Integer slotIndex, final Long slotId, final String keyLabel, final byte[] keyId, final int parallelism, final HashAlgoType hashAlgo, final SignatureAlgoControl signatureAlgoControl) { ParamUtil.requireMin("parallelism", parallelism, 1); ParamUtil.requireNonNull("hashAlgo", hashAlgo); if (slotIndex == null && slotId == null) { throw new IllegalArgumentException( "at least one of slotIndex and slotId must not be null"); } if (keyId == null && keyLabel == null) { throw new IllegalArgumentException( "at least one of keyId and keyLabel must not be null"); } ConfPairs conf = new ConfPairs(); conf.putPair("parallelism", Integer.toString(parallelism)); if (pkcs11ModuleName != null && pkcs11ModuleName.length() > 0) { conf.putPair("module", pkcs11ModuleName); } if (slotId != null) { conf.putPair("slot-id", slotId.toString()); } if (slotIndex != null) { conf.putPair("slot", slotIndex.toString()); } if (keyId != null) { conf.putPair("key-id", Hex.toHexString(keyId)); } if (keyLabel != null) { conf.putPair("key-label", keyLabel); } return new SignerConf(conf.getEncoded(), hashAlgo, signatureAlgoControl); } public static SignerConf getPkcs11SignerConf(final String pkcs11ModuleName, final Integer slotIndex, final Long slotId, final String keyLabel, final byte[] keyId, final String signatureAlgorithm, final int parallelism) { ParamUtil.requireMin("parallelism", parallelism, 1); ParamUtil.requireNonNull("algo", signatureAlgorithm); if (slotIndex == null && slotId == null) { throw new IllegalArgumentException( "at least one of slotIndex and slotId must not be null"); } if (keyId == null && keyLabel == null) { throw new IllegalArgumentException( "at least one of keyId and keyLabel must not be null"); } ConfPairs conf = new ConfPairs("algo", signatureAlgorithm); conf.putPair("parallelism", Integer.toString(parallelism)); if (pkcs11ModuleName != null && pkcs11ModuleName.length() > 0) { conf.putPair("module", pkcs11ModuleName); } if (slotId != null) { conf.putPair("slot-id", slotId.toString()); } if (slotIndex != null) { conf.putPair("slot", slotIndex.toString()); } if (keyId != null) { conf.putPair("key-id", Hex.toHexString(keyId)); } if (keyLabel != null) { conf.putPair("key-label", keyLabel); } return new SignerConf(conf.getEncoded()); } private static String eraseSensitiveData(final String conf) { if (conf == null || !conf.contains("password?")) { return conf; } try { ConfPairs pairs = new ConfPairs(conf); String value = pairs.getValue("password"); if (value != null && !StringUtil.startsWithIgnoreCase(value, "PBE:")) { pairs.putPair("password", "<sensitive>"); } return pairs.getEncoded(); } catch (Exception ex) { return conf; } } }