org.apache.ws.security.components.crypto.CryptoBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of wss4j Show documentation
Show all versions of wss4j Show documentation
The Apache WSS4J project provides a Java implementation of the primary security standards
for Web Services, namely the OASIS Web Services Security (WS-Security) specifications
from the OASIS Web Services Security TC.
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.ws.security.WSSecurityException;
import org.apache.ws.security.util.WSSecurityUtil;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.security.NoSuchProviderException;
import java.security.cert.CertPath;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.security.auth.x500.X500Principal;
/**
* This Abstract Base Class implements the accessor and keystore-independent methods and
* functionality of the Crypto interface.
*/
public abstract class CryptoBase implements Crypto {
public static final String SKI_OID = "2.5.29.14";
/**
* OID For the NameConstraints Extension to X.509
*
* http://java.sun.com/j2se/1.4.2/docs/api/
* http://www.ietf.org/rfc/rfc3280.txt (s. 4.2.1.11)
*/
public static final String NAME_CONSTRAINTS_OID = "2.5.29.30";
private static final Constructor> BC_509CLASS_CONS;
protected Map certFactMap =
new HashMap();
protected String defaultAlias = null;
protected String cryptoProvider = null;
static {
Constructor> cons = null;
try {
Class> c = Class.forName("org.bouncycastle.asn1.x509.X509Name");
cons = c.getConstructor(new Class[] {String.class});
} catch (Exception e) {
//ignore
}
BC_509CLASS_CONS = cons;
}
/**
* Constructor
*/
protected CryptoBase() {
}
/**
* Get the crypto provider associated with this implementation
* @return the crypto provider
*/
public String getCryptoProvider() {
return cryptoProvider;
}
/**
* Set the crypto provider associated with this implementation
* @param provider the crypto provider to set
*/
public void setCryptoProvider(String provider) {
cryptoProvider = provider;
}
/**
* Retrieves the identifier name of the default certificate. This should be the certificate
* that is used for signature and encryption. This identifier corresponds to the certificate
* that should be used whenever KeyInfo is not present in a signed or an encrypted
* message. May return null. The identifier is implementation specific, e.g. it could be the
* KeyStore alias.
*
* @return name of the default X509 certificate.
*/
public String getDefaultX509Identifier() throws WSSecurityException {
return defaultAlias;
}
/**
* Sets the identifier name of the default certificate. This should be the certificate
* that is used for signature and encryption. This identifier corresponds to the certificate
* that should be used whenever KeyInfo is not present in a signed or an encrypted
* message. The identifier is implementation specific, e.g. it could be the KeyStore alias.
*
* @param identifier name of the default X509 certificate.
*/
public void setDefaultX509Identifier(String identifier) {
defaultAlias = identifier;
}
/**
* Sets the CertificateFactory instance on this Crypto instance
*
* @param provider the CertificateFactory provider name
* @param certFactory the CertificateFactory the CertificateFactory instance to set
*/
public void setCertificateFactory(String provider, CertificateFactory certFactory) {
if (provider == null || provider.length() == 0) {
certFactMap.put(certFactory.getProvider().getName(), certFactory);
} else {
certFactMap.put(provider, certFactory);
}
}
/**
* Get the CertificateFactory instance on this Crypto instance
*
* @return Returns a CertificateFactory
to construct
* X509 certificates
* @throws org.apache.ws.security.WSSecurityException
*/
public CertificateFactory getCertificateFactory() throws WSSecurityException {
String provider = getCryptoProvider();
//Try to find a CertificateFactory that generates certs that are fully
//compatible with the certs in the KeyStore (Sun -> Sun, BC -> BC, etc...)
CertificateFactory factory = null;
if (provider != null && provider.length() != 0) {
factory = certFactMap.get(provider);
} else {
factory = certFactMap.get("DEFAULT");
}
if (factory == null) {
try {
if (provider == null || provider.length() == 0) {
factory = CertificateFactory.getInstance("X.509");
certFactMap.put("DEFAULT", factory);
} else {
factory = CertificateFactory.getInstance("X.509", provider);
certFactMap.put(provider, factory);
}
certFactMap.put(factory.getProvider().getName(), factory);
} catch (CertificateException e) {
throw new WSSecurityException(
WSSecurityException.SECURITY_TOKEN_UNAVAILABLE, "unsupportedCertType",
null, e
);
} catch (NoSuchProviderException e) {
throw new WSSecurityException(
WSSecurityException.SECURITY_TOKEN_UNAVAILABLE, "noSecProvider",
null, e
);
}
}
return factory;
}
/**
* Load a X509Certificate from the input stream.
*
* @param in The InputStream
containing the X509Certificate
* @return An X509 certificate
* @throws org.apache.ws.security.WSSecurityException
*/
public X509Certificate loadCertificate(InputStream in) throws WSSecurityException {
try {
CertificateFactory certFactory = getCertificateFactory();
return (X509Certificate) certFactory.generateCertificate(in);
} catch (CertificateException e) {
throw new WSSecurityException(
WSSecurityException.SECURITY_TOKEN_UNAVAILABLE, "parseError",
null, e
);
}
}
/**
* Reads the SubjectKeyIdentifier information from the certificate.
*
* 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 containing 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) {
X509SubjectPublicKeyInfo spki = new X509SubjectPublicKeyInfo(cert.getPublicKey());
byte[] value = spki.getSubjectPublicKey();
try {
return WSSecurityUtil.generateDigest(value);
} catch (WSSecurityException ex) {
throw new WSSecurityException(
WSSecurityException.UNSUPPORTED_SECURITY_TOKEN, "noSKIHandling",
new Object[]{"No SKI certificate extension and no SHA1 message digest available"},
ex
);
}
}
//
// Strip away first (four) bytes from the DerValue (tag and length of
// ExtensionValue OCTET STRING and KeyIdentifier OCTET STRING)
//
DERDecoder extVal = new DERDecoder(derEncodedValue);
extVal.expect(DERDecoder.TYPE_OCTET_STRING); // ExtensionValue OCTET STRING
extVal.getLength();
extVal.expect(DERDecoder.TYPE_OCTET_STRING); // KeyIdentifier OCTET STRING
int keyIDLen = extVal.getLength();
return extVal.getBytes(keyIDLen);
}
/**
* Get a byte array given an array of X509 certificates.
*
*
* @param certs The certificates to convert
* @return The byte array for the certificates
* @throws WSSecurityException
*/
public byte[] getBytesFromCertificates(X509Certificate[] certs)
throws WSSecurityException {
try {
CertPath path = getCertificateFactory().generateCertPath(Arrays.asList(certs));
return path.getEncoded();
} catch (CertificateEncodingException e) {
throw new WSSecurityException(
WSSecurityException.SECURITY_TOKEN_UNAVAILABLE, "encodeError",
null, e
);
} catch (CertificateException e) {
throw new WSSecurityException(
WSSecurityException.SECURITY_TOKEN_UNAVAILABLE, "parseError",
null, e
);
}
}
/**
* Construct an array of X509Certificate's from the byte array.
*
*
* @param data The byte
array containing the X509 data
* @return An array of X509 certificates
* @throws WSSecurityException
*/
public X509Certificate[] getCertificatesFromBytes(byte[] data)
throws WSSecurityException {
InputStream in = new ByteArrayInputStream(data);
CertPath path = null;
try {
path = getCertificateFactory().generateCertPath(in);
} catch (CertificateException e) {
throw new WSSecurityException(
WSSecurityException.SECURITY_TOKEN_UNAVAILABLE, "parseError",
null, e
);
}
List> l = path.getCertificates();
X509Certificate[] certs = new X509Certificate[l.size()];
int i = 0;
for (Iterator> iterator = l.iterator(); iterator.hasNext(); ) {
certs[i++] = (X509Certificate) iterator.next();
}
return certs;
}
protected Object createBCX509Name(String s) {
if (BC_509CLASS_CONS != null) {
try {
return BC_509CLASS_CONS.newInstance(new Object[] {s});
} catch (Exception e) {
//ignore
}
}
return new X500Principal(s);
}
}