[
https://issues.apache.org/jira/browse/WSS-59?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Colm O hEigeartaigh resolved WSS-59.
------------------------------------
Resolution: Won't Fix
Marking this as "won't fix" as per Ruchith's comments.
> Crypto.properties doesn't allow encoded password for keystore - WSS4J1.5
> ------------------------------------------------------------------------
>
> Key: WSS-59
> URL: https://issues.apache.org/jira/browse/WSS-59
> Project: WSS4J
> Issue Type: New Feature
> Environment: ALL
> Reporter: Soumadeep
> Priority: Minor
>
> Crypto.properties file doesn't allow encoded passwords for keystore and
> alias. The plain text password would be unacceptable for most of the
> enterprises.
> The load method of AbstractCrypto.java file actually picks up the passwords
> from the crypto.properties file. I have made the required changes and am
> putting it below. This only accounts for the keystore password as the alias
> password would be usage specific. Please check the two files
> crypto.properties and AbstractCrypto.java. The files are from the wss4j main
> trunk - svn
> Thanks
> Soumadeep
> Crypto.properties
> =============
> org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
> org.apache.ws.security.crypto.merlin.keystore.type=jks
> // This property has been added
> org.apache.ws.security.crypto.merlin.keystore.base64.encoded=false
> org.apache.ws.security.crypto.merlin.keystore.password=soumadeep
> org.apache.ws.security.crypto.merlin.keystore.alias=soumadeep
> org.apache.ws.security.crypto.merlin.alias.password=soumadeep
> org.apache.ws.security.crypto.merlin.file=resources/soumadeep.jks
> AbstractCrypto.java
> ===============
> /*
> * Copyright 2003-2004 The Apache Software Foundation.
> *
> * 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.apache.ws.security.components.crypto;
> import org.apache.commons.logging.Log;
> import org.apache.commons.logging.LogFactory;
> import org.apache.ws.security.WSSecurityException;
> import org.apache.ws.security.util.Base64;
> import org.apache.ws.security.util.Loader;
> import java.io.FileInputStream;
> import java.io.IOException;
> import java.io.InputStream;
> import java.math.BigInteger;
> import java.security.GeneralSecurityException;
> import java.security.Key;
> import java.security.KeyStore;
> import java.security.KeyStoreException;
> import java.security.MessageDigest;
> import java.security.NoSuchAlgorithmException;
> import java.security.NoSuchProviderException;
> import java.security.PrivateKey;
> import java.security.PublicKey;
> import java.security.cert.Certificate;
> import java.security.cert.CertificateEncodingException;
> import java.security.cert.CertificateException;
> import java.security.cert.CertificateFactory;
> import java.security.cert.X509Certificate;
> import java.security.interfaces.RSAPublicKey;
> import java.util.Arrays;
> import java.util.Enumeration;
> import java.util.Properties;
> import java.util.Vector;
> /**
> * Created by IntelliJ IDEA.
> * User: dims
> * Date: Sep 15, 2005
> * Time: 9:50:40 AM
> * To change this template use File | Settings | File Templates.
> */
> public abstract class AbstractCrypto implements Crypto {
> private static Log log = LogFactory.getLog(AbstractCrypto.class);
> protected static CertificateFactory certFact;
> protected Properties properties = null;
> protected KeyStore keystore = null;
> static String SKI_OID = "2.5.29.14";
> /**
> * Constructor
> *
> * @param properties
> */
> public AbstractCrypto(Properties properties) throws CredentialException,
> IOException {
> this(properties,AbstractCrypto.class.getClassLoader());
> }
> /**
> * This allows providing a custom class loader to load the resources, etc
> * @param properties
> * @param loader
> * @throws CredentialException
> * @throws IOException
> */
> public AbstractCrypto(Properties properties, ClassLoader loader) throws
> CredentialException, IOException {
> /*
> * if no properties .. just return an instance, the rest will be
> * done later or this instance is just used to handle certificate
> * conversions in this implementatio
> */
> if (properties == null) {
> return;
> }
> this.properties = properties;
> String location =
> this.properties.getProperty("org.apache.ws.security.crypto.merlin.file");
> InputStream is = null;
> java.net.URL url = Loader.getResource(loader, location);
> if(url != null) {
> is = url.openStream();
> } else {
> is = new java.io.FileInputStream(location);
> }
> /**
> * If we don't find it, then look on the file system.
> */
> if (is == null) {
> try {
> is = new FileInputStream(location);
> } catch (Exception e) {
> throw new CredentialException(3, "proxyNotFound", new
> Object[]{location});
> }
> }
> /**
> * Load the keystore
> */
> try {
> load(is);
> } finally {
> is.close();
> }
> }
>
> /**
> * Singleton certificate factory for this Crypto instance.
> * <p/>
> *
> * @return Returns a <code>CertificateFactory</code> to construct
> * X509 certficates
> * @throws org.apache.ws.security.WSSecurityException
> *
> */
> public synchronized CertificateFactory getCertificateFactory() throws
> WSSecurityException {
> if (certFact == null) {
> try {
> String provider =
> properties.getProperty("org.apache.ws.security.crypto.merlin.cert.provider");
> if (provider == null || provider.length() == 0) {
> certFact = CertificateFactory.getInstance("X.509");
> } else {
> certFact = CertificateFactory.getInstance("X.509",
> provider);
> }
> } catch (CertificateException e) {
> throw new
> WSSecurityException(WSSecurityException.SECURITY_TOKEN_UNAVAILABLE,
> "unsupportedCertType");
> } catch (NoSuchProviderException e) {
> throw new
> WSSecurityException(WSSecurityException.SECURITY_TOKEN_UNAVAILABLE,
> "noSecProvider");
> }
> }
> return certFact;
> }
> /**
> * load a X509Certificate from the input stream.
> * <p/>
> *
> * @param in The <code>InputStream</code> array containg the X509 data
> * @return Returns a X509 certificate
> * @throws org.apache.ws.security.WSSecurityException
> *
> */
> public X509Certificate loadCertificate(InputStream in) throws
> WSSecurityException {
> X509Certificate cert = null;
> try {
> cert =
> (X509Certificate)
> getCertificateFactory().generateCertificate(in);
> } catch (CertificateException e) {
> throw new
> WSSecurityException(WSSecurityException.SECURITY_TOKEN_UNAVAILABLE,
> "parseError");
> }
> return cert;
> }
> /**
> * Gets the private key identified by <code>alias</> and
> <code>password</code>.
> * <p/>
> *
> * @param alias The alias (<code>KeyStore</code>) of the key owner
> * @param password The password needed to access the private key
> * @return The private key
> * @throws Exception
> */
> public PrivateKey getPrivateKey(String alias, String password) throws
> Exception {
> if (alias == null) {
> throw new Exception("alias is null");
> }
> boolean b = keystore.isKeyEntry(alias);
> if (!b) {
> log.error("Cannot find key for alias: " + alias);
> throw new Exception("Cannot find key for alias: " + alias);
> }
> Key keyTmp = keystore.getKey(alias, password.toCharArray());
> if (!(keyTmp instanceof PrivateKey)) {
> throw new Exception("Key is not a private key, alias: " + alias);
> }
> return (PrivateKey) keyTmp;
> }
> private Vector splitAndTrim(String inString) {
> X509NameTokenizer nmTokens = new X509NameTokenizer(inString);
> Vector vr = new Vector();
> while (nmTokens.hasMoreTokens()) {
> vr.add(nmTokens.nextToken());
> }
> java.util.Collections.sort(vr);
> return vr;
> }
> /**
> * Lookup a X509 Certificate in the keystore according to a given
> * the issuer of a Certficate.
> * <p/>
> * The search gets all alias names of the keystore and gets the
> certificate chain
> * for each alias. Then the Issuer fo each certificate of the chain
> * is compared with the parameters.
> *
> * @param issuer The issuer's name for the certificate
> * @return alias name of the certificate that matches the issuer name
> * or null if no such certificate was found.
> */
> public String getAliasForX509Cert(String issuer)
> throws WSSecurityException {
> return getAliasForX509Cert(issuer, null, false);
> }
> /**
> * Lookup a X509 Certificate in the keystore according to a given serial
> number and
> * the issuer of a Certficate.
> * <p/>
> * The search gets all alias names of the keystore and gets the
> certificate chain
> * for each alias. Then the SerialNumber and Issuer fo each certificate
> of the chain
> * is compared with the parameters.
> *
> * @param issuer The issuer's name for the certificate
> * @param serialNumber The serial number of the certificate from the
> named issuer
> * @return alias name of the certificate that matches serialNumber and
> issuer name
> * or null if no such certificate was found.
> */
> public String getAliasForX509Cert(String issuer, BigInteger serialNumber)
> throws WSSecurityException {
> return getAliasForX509Cert(issuer, serialNumber, true);
> }
> /*
> * need to check if "getCertificateChain" also finds certificates that are
> * used for enryption only, i.e. they may not be signed by a CA
> * Otherwise we must define a restriction how to use certificate:
> * each certificate must be signed by a CA or is a self signed Certificate
> * (this should work as well).
> * --- remains to be tested in several ways --
> */
> private String getAliasForX509Cert(String issuer, BigInteger serialNumber,
> boolean useSerialNumber)
> throws WSSecurityException {
> Vector issuerRDN = splitAndTrim(issuer);
> X509Certificate x509cert = null;
> Vector certRDN = null;
> Certificate cert = null;
> try {
> for (Enumeration e = keystore.aliases(); e.hasMoreElements();) {
> String alias = (String) e.nextElement();
> Certificate[] certs = keystore.getCertificateChain(alias);
> if (certs == null || certs.length == 0) {
> // no cert chain, so lets check if getCertificate gives
> us a result.
> cert = keystore.getCertificate(alias);
> if (cert == null) {
> return null;
> }
> } else {
> cert = certs[0];
> }
> if (!(cert instanceof X509Certificate)) {
> continue;
> }
> x509cert = (X509Certificate) cert;
> if (!useSerialNumber ||
> useSerialNumber &&
> x509cert.getSerialNumber().compareTo(serialNumber) == 0) {
> certRDN = splitAndTrim(x509cert.getIssuerDN().getName());
> if (certRDN.equals(issuerRDN)) {
> return alias;
> }
> }
> }
> } catch (KeyStoreException e) {
> throw new WSSecurityException(WSSecurityException.FAILURE,
> "keystore");
> }
> return null;
> }
> /**
> * Lookup a X509 Certificate in the keystore according to a given
> * SubjectKeyIdentifier.
> * <p/>
> * The search gets all alias names of the keystore and gets the
> certificate chain
> * or certificate for each alias. Then the SKI for each user certificate
> * is compared with the SKI parameter.
> *
> * @param skiBytes The SKI info bytes
> * @return alias name of the certificate that matches serialNumber and
> issuer name
> * or null if no such certificate was found.
> * @throws org.apache.ws.security.WSSecurityException
> * if problems during keystore handling or wrong certificate (no
> SKI data)
> */
> public String getAliasForX509Cert(byte[] skiBytes) throws
> WSSecurityException {
> Certificate cert = null;
> boolean found = false;
> try {
> for (Enumeration e = keystore.aliases(); e.hasMoreElements();) {
> String alias = (String) e.nextElement();
> Certificate[] certs = keystore.getCertificateChain(alias);
> if (certs == null || certs.length == 0) {
> // no cert chain, so lets check if getCertificate gives
> us a result.
> cert = keystore.getCertificate(alias);
> if (cert == null) {
> return null;
> }
> } else {
> cert = certs[0];
> }
> if (!(cert instanceof X509Certificate)) {
> continue;
> }
> byte[] data = getSKIBytesFromCert((X509Certificate) cert);
> if (data.length != skiBytes.length) {
> continue;
> }
> if (Arrays.equals(data, skiBytes)) {
> return alias;
> }
> }
> } catch (KeyStoreException e) {
> throw new WSSecurityException(WSSecurityException.FAILURE,
> "keystore");
> }
> return null;
> }
> /**
> * Return a X509 Certificate alias in the keystore according to a given
> Certificate
> * <p/>
> *
> * @param cert The certificate to lookup
> * @return alias name of the certificate that matches the given
> certificate
> * or null if no such certificate was found.
> */
> /*
> * See comment above
> */
> public String getAliasForX509Cert(Certificate cert) throws
> WSSecurityException {
> try {
> String alias = keystore.getCertificateAlias(cert);
> if (alias != null)
> return alias;
> // Use brute force search
> Enumeration e = keystore.aliases();
> while (e.hasMoreElements()) {
> alias = (String) e.nextElement();
> X509Certificate cert2 = (X509Certificate)
> keystore.getCertificate(alias);
> if (cert2.equals(cert)) {
> return alias;
> }
> }
> } catch (KeyStoreException e) {
> throw new WSSecurityException(WSSecurityException.FAILURE,
> "keystore");
> }
> return null;
> }
> /**
> * Retrieves the alias name of the default certificate which has been
> * specified as a property. This should be the certificate that is used
> for
> * signature and encryption. This alias corresponds to the certificate
> that
> * should be used whenever KeyInfo is not poresent in a signed or
> * an encrypted message. May return null.
> *
> * @return alias name of the default X509 certificate
> */
> public String getDefaultX509Alias() {
> if (properties == null) {
> return null;
> }
> return
> properties.getProperty("org.apache.ws.security.crypto.merlin.keystore.alias");
> }
> /**
> * Gets the list of certificates for a given alias.
> * <p/>
> *
> * @param alias Lookup certificate chain for this alias
> * @return Array of X509 certificates for this alias name, or
> * null if this alias does not exist in the keystore
> */
> public X509Certificate[] getCertificates(String alias) throws
> WSSecurityException {
> Certificate[] certs = null;
> try {
> certs = keystore.getCertificateChain(alias);
> if (certs == null || certs.length == 0) {
> // no cert chain, so lets check if getCertificate gives us a
> result.
> Certificate cert = keystore.getCertificate(alias);
> if (cert == null) {
> return null;
> }
> certs = new Certificate[]{cert};
> }
> } catch (KeyStoreException e) {
> throw new WSSecurityException(WSSecurityException.FAILURE,
> "keystore");
> }
> X509Certificate[] x509certs = new X509Certificate[certs.length];
> for (int i = 0; i < certs.length; i++) {
> x509certs[i] = (X509Certificate) certs[i];
> }
> return x509certs;
> }
> /**
> * Lookup a X509 Certificate in the keystore according to a given
> * Thumbprint.
> * <p/>
> * The search gets all alias names of the keystore, then reads the
> certificate chain
> * or certificate for each alias. Then the thumbprint for each user
> certificate
> * is compared with the thumbprint parameter.
> *
> * @param thumb The SHA1 thumbprint info bytes
> * @return alias name of the certificate that matches the thumbprint
> * or null if no such certificate was found.
> * @throws org.apache.ws.security.WSSecurityException
> * if problems during keystore handling or wrong certificate
> */
> public String getAliasForX509CertThumb(byte[] thumb) throws
> WSSecurityException {
> Certificate cert = null;
> MessageDigest sha = null;
> try {
> sha = MessageDigest.getInstance("SHA-1");
> } catch (NoSuchAlgorithmException e1) {
> throw new WSSecurityException(
> 0,
> "noSHA1availabe");
> }
> try {
> for (Enumeration e = keystore.aliases(); e.hasMoreElements();) {
> String alias = (String) e.nextElement();
> Certificate[] certs = keystore.getCertificateChain(alias);
> if (certs == null || certs.length == 0) {
> // no cert chain, so lets check if getCertificate gives
> us a result.
> cert = keystore.getCertificate(alias);
> if (cert == null) {
> return null;
> }
> } else {
> cert = certs[0];
> }
> if (!(cert instanceof X509Certificate)) {
> continue;
> }
> sha.reset();
> try {
> sha.update(cert.getEncoded());
> } catch (CertificateEncodingException e1) {
> throw new WSSecurityException(
> WSSecurityException.SECURITY_TOKEN_UNAVAILABLE,
> "encodeError");
> }
> byte[] data = sha.digest();
> if (Arrays.equals(data, thumb)) {
> return alias;
> }
> }
> } catch (KeyStoreException e) {
> throw new WSSecurityException(WSSecurityException.FAILURE,
> "keystore");
> }
> return null;
> }
> /**
> * A Hook for subclasses to set the keystore without having to
> * load it from an <code>InputStream</code>.
> *
> * @param ks existing keystore
> */
> public void setKeyStore(KeyStore ks) {
> keystore = ks;
> }
> /**
> * Loads the the keystore from an <code>InputStream </code>.
> * <p/>
> *
> * @param input <code>InputStream</code> to read from
> * @throws CredentialException
> */
> public void load(InputStream input) throws CredentialException {
> if (input == null) {
> throw new IllegalArgumentException("input stream cannot be null");
> }
> try {
> String provider =
> properties.getProperty("org.apache.ws.security.crypto.merlin.keystore.provider");
> if (provider == null || provider.length() == 0) {
> keystore = KeyStore.getInstance
>
> (properties.getProperty("org.apache.ws.security.crypto.merlin.keystore.type",
> KeyStore.getDefaultType()));
> } else {
> keystore = KeyStore.getInstance
>
> (properties.getProperty("org.apache.ws.security.crypto.merlin.keystore.type",
> KeyStore.getDefaultType()), provider);
> }
> String password = null;
> String base64Encoded =
> properties.getProperty("org.apache.ws.security.crypto.merlin.keystore.base64.encoded","false");
> password =
> properties.getProperty("org.apache.ws.security.crypto.merlin.keystore.password",
> "security");
> if(base64Encoded.equalsIgnoreCase("true")){
> password = new String(Base64.decode(password));
> }
>
> keystore.load(input, (password == null || password.length() == 0)
> ? new char[0] : password.toCharArray());
> } catch (IOException e) {
> e.printStackTrace();
> throw new CredentialException(3, "ioError00", e);
> } catch (GeneralSecurityException e) {
> e.printStackTrace();
> throw new CredentialException(3, "secError00", e);
> } catch (Exception e) {
> e.printStackTrace();
> throw new CredentialException(-1, "error00", e);
> }
> }
> /**
> * Reads the SubjectKeyIdentifier information from the certificate.
> * <p/>
> * If the the certificate does not contain a SKI extension then
> * try to compute the SKI according to RFC3280 using the
> * SHA-1 hash value of the public key. The second method described
> * in RFC3280 is not support. Also only RSA public keys are supported.
> * If we cannot compute the SKI throw a WSSecurityException.
> *
> * @param cert The certificate to read SKI
> * @return The byte array conating the binary SKI data
> */
> public byte[] getSKIBytesFromCert(X509Certificate cert)
> throws WSSecurityException {
> /*
> * Gets the DER-encoded OCTET string for the extension value
> (extnValue)
> * identified by the passed-in oid String. The oid string is
> represented
> * by a set of positive whole numbers separated by periods.
> */
> byte[] derEncodedValue = cert.getExtensionValue(SKI_OID);
> if (cert.getVersion() < 3 || derEncodedValue == null) {
> PublicKey key = cert.getPublicKey();
> if (!(key instanceof RSAPublicKey)) {
> throw new WSSecurityException(
> 1,
> "noSKIHandling",
> new Object[]{"Support for RSA key only"});
> }
> byte[] encoded = key.getEncoded();
> // remove 22-byte algorithm ID and header
> byte[] value = new byte[encoded.length - 22];
> System.arraycopy(encoded, 22, value, 0, value.length);
> MessageDigest sha;
> try {
> sha = MessageDigest.getInstance("SHA-1");
> } catch (NoSuchAlgorithmException ex) {
> throw new WSSecurityException(
> 1,
> "noSKIHandling",
> new Object[]{"Wrong certificate version (<3) and no
> SHA1 message digest availabe"});
> }
> sha.reset();
> sha.update(value);
> return sha.digest();
> }
> /**
> * Strip away first four bytes from the DerValue (tag and length of
> * ExtensionValue OCTET STRING and KeyIdentifier OCTET STRING)
> */
> byte abyte0[] = new byte[derEncodedValue.length - 4];
> System.arraycopy(derEncodedValue, 4, abyte0, 0, abyte0.length);
> return abyte0;
> }
> public KeyStore getKeyStore() {
> return this.keystore;
> }
> /**
> * Lookup X509 Certificates in the keystore according to a given DN of
> the subject of the certificate
> * <p/>
> * The search gets all alias names of the keystore and gets the
> certificate (chain)
> * for each alias. Then the DN of the certificate is compared with the
> parameters.
> *
> * @param subjectDN The DN of subject to look for in the keystore
> * @return Vector with all alias of certificates with the same DN as
> given in the parameters
> * @throws org.apache.ws.security.WSSecurityException
> *
> */
> public String[] getAliasesForDN(String subjectDN) throws
> WSSecurityException {
> // Store the aliases found
> Vector aliases = new Vector();
> Certificate cert = null;
> // The DN to search the keystore for
> Vector subjectRDN = splitAndTrim(subjectDN);
> // Look at every certificate in the keystore
> try {
> for (Enumeration e = keystore.aliases(); e.hasMoreElements();) {
> String alias = (String) e.nextElement();
> Certificate[] certs = keystore.getCertificateChain(alias);
> if (certs == null || certs.length == 0) {
> // no cert chain, so lets check if getCertificate gives
> us a result.
> cert = keystore.getCertificate(alias);
> if (cert == null) {
> return null;
> }
> certs = new Certificate[]{cert};
> } else {
> cert = certs[0];
> }
> if (cert instanceof X509Certificate) {
> Vector foundRDN = splitAndTrim(((X509Certificate)
> cert).getSubjectDN().getName());
> if (subjectRDN.equals(foundRDN)) {
> aliases.add(alias);
> }
> }
> }
> } catch (KeyStoreException e) {
> throw new WSSecurityException(WSSecurityException.FAILURE,
> "keystore");
> }
> // Convert the vector into an array
> String[] result = new String[aliases.size()];
> for (int i = 0; i < aliases.size(); i++)
> result[i] = (String) aliases.elementAt(i);
> return result;
> }
> }
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]