Author: coheigea
Date: Thu Mar 5 16:00:47 2009
New Revision: 750484
URL: http://svn.apache.org/viewvc?rev=750484&view=rev
Log:
[WSS-168] - A fix for different issuer DN formats breaking
decryption/verification
- This fix introduces a compile-time dependency on BouncyCastle.
- The idea is to convert the issuer DN to a java X500Principal object first.
- This is to ensure interop with a DN constructed from .NET, where e.g. it
uses "S" instead of "ST".
- Then convert it to a BouncyCastle X509Name, which will order the attributes
of the DN in a
particular way (see WSS-168).
- If the conversion to an X500Principal object fails (e.g. if the DN contains
"E" instead of
"EMAILADDRESS"), then fall back on a direct conversion to a BC X509Name.
Modified:
webservices/wss4j/trunk/pom.xml
webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/BouncyCastle.java
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/CryptoBase.java
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/CryptoFactory.java
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/Merlin.java
webservices/wss4j/trunk/test/wssec/TestWSSecurityWSS86.java
Modified: webservices/wss4j/trunk/pom.xml
URL:
http://svn.apache.org/viewvc/webservices/wss4j/trunk/pom.xml?rev=750484&r1=750483&r2=750484&view=diff
==============================================================================
--- webservices/wss4j/trunk/pom.xml (original)
+++ webservices/wss4j/trunk/pom.xml Thu Mar 5 16:00:47 2009
@@ -200,6 +200,7 @@
!org.apache.ws.axis.security.*,
javax.xml.crypto.*,
org.apache.xml.security.*,
+ org.bouncycastle.*,
org.jcp.xml.dsig.internal.*,
org.opensaml.*;resolution:=optional,
*;resolution:=optional
@@ -349,7 +350,7 @@
<groupId>bouncycastle</groupId>
<artifactId>bcprov-jdk14</artifactId>
<version>${bcprov.jdk14.version}</version>
- <scope>runtime</scope>
+ <scope>compile</scope>
</dependency>
</dependencies>
</profile>
@@ -363,7 +364,7 @@
<groupId>bouncycastle</groupId>
<artifactId>bcprov-jdk15</artifactId>
<version>${bcprov.jdk15.version}</version>
- <scope>runtime</scope>
+ <scope>compile</scope>
</dependency>
</dependencies>
</profile>
Modified: webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java
URL:
http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java?rev=750484&r1=750483&r2=750484&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java Thu Mar
5 16:00:47 2009
@@ -498,7 +498,7 @@
(java.security.Provider) c.newInstance(), 2
);
if (log.isDebugEnabled()) {
- log.debug("The provider " + id + " was added at: " + ret);
+ log.debug("The provider " + id + " was added at position:
" + ret);
}
}
return true;
Modified:
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/BouncyCastle.java
URL:
http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/BouncyCastle.java?rev=750484&r1=750483&r2=750484&view=diff
==============================================================================
---
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/BouncyCastle.java
(original)
+++
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/BouncyCastle.java
Thu Mar 5 16:00:47 2009
@@ -59,7 +59,8 @@
super(properties);
}
- public BouncyCastle(Properties properties, ClassLoader loader) throws
CredentialException, IOException {
+ public BouncyCastle(Properties properties, ClassLoader loader)
+ throws CredentialException, IOException {
super(properties,loader);
}
@@ -76,7 +77,7 @@
*
*/
public X509Certificate[] getX509Certificates(byte[] data, boolean reverse)
- throws WSSecurityException {
+ throws WSSecurityException {
InputStream in = new ByteArrayInputStream(data);
CertPath path = null;
try {
@@ -109,11 +110,11 @@
*
*/
public byte[] getCertificateData(boolean reverse, X509Certificate[] certs)
- throws WSSecurityException {
- Vector list = new Vector();
+ throws WSSecurityException {
+ List list = new Vector();
for (int i = 0; i < certs.length; i++) {
if (reverse) {
- list.insertElementAt(certs[i], 0);
+ list.add(0, certs[i]);
} else {
list.add(certs[i]);
}
Modified:
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/CryptoBase.java
URL:
http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/CryptoBase.java?rev=750484&r1=750483&r2=750484&view=diff
==============================================================================
---
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/CryptoBase.java
(original)
+++
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/CryptoBase.java
Thu Mar 5 16:00:47 2009
@@ -20,6 +20,8 @@
import org.apache.commons.logging.LogFactory;
import org.apache.ws.security.WSSecurityException;
+import org.bouncycastle.asn1.x509.X509Name;
+
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigInteger;
@@ -81,6 +83,7 @@
}
return s;
}
+
/**
* Singleton certificate factory for this Crypto instance.
* <p/>
@@ -224,8 +227,7 @@
* @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 {
+ public String getAliasForX509Cert(String issuer) throws
WSSecurityException {
return getAliasForX509Cert(issuer, null, false);
}
@@ -243,7 +245,7 @@
* or null if no such certificate was found.
*/
public String getAliasForX509Cert(String issuer, BigInteger serialNumber)
- throws WSSecurityException {
+ throws WSSecurityException {
return getAliasForX509Cert(issuer, serialNumber, true);
}
@@ -255,20 +257,36 @@
* (this should work as well).
* --- remains to be tested in several ways --
*/
- private String getAliasForX509Cert(String issuer, BigInteger serialNumber,
- boolean useSerialNumber)
- throws WSSecurityException {
- X500Principal issuerRDN = new X500Principal(issuer);
- X509Certificate x509cert;
- X500Principal certRDN;
+ private String getAliasForX509Cert(
+ String issuer,
+ BigInteger serialNumber,
+ boolean useSerialNumber
+ ) throws WSSecurityException {
+ X500Principal issuerRDN = null;
+ X509Name issuerName = null;
Certificate cert = null;
+
+ //
+ // Convert the issuer DN to a java X500Principal object first. This is
to ensure
+ // interop with a DN constructed from .NET, where e.g. it uses "S"
instead of "ST".
+ // Then convert it to a BouncyCastle X509Name, which will order the
attributes of
+ // the DN in a particular way (see WSS-168). If the conversion to an
X500Principal
+ // object fails (e.g. if the DN contains "E" instead of
"EMAILADDRESS"), then fall
+ // back on a direct conversion to a BC X509Name
+ //
+ try {
+ issuerRDN = new X500Principal(issuer);
+ issuerName = new X509Name(issuerRDN.getName());
+ } catch (java.lang.IllegalArgumentException ex) {
+ issuerName = new X509Name(issuer);
+ }
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.
+ // no cert chain, so lets check if getCertificate gives us
a result.
cert = keystore.getCertificate(alias);
if (cert == null) {
return null;
@@ -279,11 +297,10 @@
if (!(cert instanceof X509Certificate)) {
continue;
}
- x509cert = (X509Certificate) cert;
- if (!useSerialNumber ||
- useSerialNumber &&
x509cert.getSerialNumber().compareTo(serialNumber) == 0) {
- certRDN = new
X500Principal(x509cert.getIssuerDN().getName());
- if (certRDN.equals(issuerRDN)) {
+ X509Certificate x509cert = (X509Certificate) cert;
+ if (!useSerialNumber ||
x509cert.getSerialNumber().compareTo(serialNumber) == 0) {
+ X509Name certName = new
X509Name(x509cert.getIssuerDN().getName());
+ if (certName.equals(issuerName)) {
return alias;
}
}
@@ -308,7 +325,6 @@
* @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;
@@ -350,15 +366,12 @@
* @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)
+ if (alias != null) {
return alias;
+ }
// Use brute force search
Enumeration e = keystore.aliases();
while (e.hasMoreElements()) {
@@ -436,7 +449,6 @@
* @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;
@@ -509,13 +521,12 @@
* @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.
- */
+ 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) {
@@ -545,10 +556,10 @@
return sha.digest();
}
- /*
- * Strip away first four bytes from the DerValue (tag and length of
- * ExtensionValue OCTET STRING and KeyIdentifier OCTET STRING)
- */
+ //
+ // 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);
@@ -602,7 +613,7 @@
* @throws WSSecurityException
*/
public byte[] getCertificateData(boolean reverse, X509Certificate[] certs)
- throws WSSecurityException {
+ throws WSSecurityException {
Vector list = new Vector();
for (int i = 0; i < certs.length; i++) {
if (reverse) {
@@ -639,7 +650,7 @@
* @throws WSSecurityException
*/
public X509Certificate[] getX509Certificates(byte[] data, boolean reverse)
- throws WSSecurityException {
+ throws WSSecurityException {
InputStream in = new ByteArrayInputStream(data);
CertPath path = null;
try {
@@ -672,7 +683,6 @@
validateCertPath(
java.security.cert.X509Certificate[] certs
) throws org.apache.ws.security.WSSecurityException {
-
try {
// Generate cert path
java.util.List cert_list = java.util.Arrays.asList(certs);
@@ -748,7 +758,6 @@
private Vector getAlias(X500Principal subjectRDN, KeyStore store) throws
WSSecurityException {
// Store the aliases found
Vector aliases = new Vector();
-
Certificate cert = null;
try {
Modified:
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/CryptoFactory.java
URL:
http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/CryptoFactory.java?rev=750484&r1=750483&r2=750484&view=diff
==============================================================================
---
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/CryptoFactory.java
(original)
+++
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/CryptoFactory.java
Thu Mar 5 16:00:47 2009
@@ -255,8 +255,9 @@
if (log.isDebugEnabled()) {
log.debug("Cannot find crypto property file: " + propFilename,
e);
}
- throw new RuntimeException("CryptoFactory: Cannot load properties:
" +
- propFilename, e);
+ throw new RuntimeException(
+ "CryptoFactory: Cannot load properties: " + propFilename, e
+ );
}
return properties;
}
Modified:
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/Merlin.java
URL:
http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/Merlin.java?rev=750484&r1=750483&r2=750484&view=diff
==============================================================================
---
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/Merlin.java
(original)
+++
webservices/wss4j/trunk/src/org/apache/ws/security/components/crypto/Merlin.java
Thu Mar 5 16:00:47 2009
@@ -62,13 +62,12 @@
* @throws CredentialException
* @throws IOException
*/
- public Merlin(Properties properties) throws CredentialException,
- IOException {
+ public Merlin(Properties properties) throws CredentialException,
IOException {
super(properties);
}
public Merlin(Properties properties, ClassLoader loader)
- throws CredentialException, IOException {
+ throws CredentialException, IOException {
super(properties, loader);
}
@@ -85,7 +84,7 @@
* @throws WSSecurityException
*/
public X509Certificate[] getX509Certificates(byte[] data, boolean reverse)
- throws WSSecurityException {
+ throws WSSecurityException {
InputStream in = new ByteArrayInputStream(data);
CertPath path = null;
try {
@@ -99,8 +98,7 @@
X509Certificate[] certs = new X509Certificate[l.size()];
Iterator iterator = l.iterator();
for (int i = 0; i < l.size(); i++) {
- certs[(reverse) ? (l.size() - 1 - i) : i] = (X509Certificate)
iterator
- .next();
+ certs[(reverse) ? (l.size() - 1 - i) : i] = (X509Certificate)
iterator.next();
}
return certs;
}
@@ -118,11 +116,11 @@
* @throws WSSecurityException
*/
public byte[] getCertificateData(boolean reverse, X509Certificate[] certs)
- throws WSSecurityException {
- Vector list = new Vector();
+ throws WSSecurityException {
+ List list = new Vector();
for (int i = 0; i < certs.length; i++) {
if (reverse) {
- list.insertElementAt(certs[i], 0);
+ list.add(0, certs[i]);
} else {
list.add(certs[i]);
}
@@ -141,23 +139,20 @@
}
}
- public boolean validateCertPath(X509Certificate[] certs)
- throws WSSecurityException {
+ public boolean validateCertPath(X509Certificate[] certs) throws
WSSecurityException {
try {
// Generate cert path
java.util.List certList = java.util.Arrays.asList(certs);
- CertPath path = this.getCertificateFactory().generateCertPath(
- certList);
-
- HashSet set = new HashSet();
+ CertPath path =
this.getCertificateFactory().generateCertPath(certList);
+ java.util.Set set = new HashSet();
Enumeration cacertsAliases = this.cacerts.aliases();
while (cacertsAliases.hasMoreElements()) {
String alias = (String) cacertsAliases.nextElement();
- X509Certificate cert = (X509Certificate) this.cacerts
- .getCertificate(alias);
- TrustAnchor anchor = new TrustAnchor(cert, cert
- .getExtensionValue(NAME_CONSTRAINTS_OID));
+ X509Certificate cert =
+ (X509Certificate) this.cacerts.getCertificate(alias);
+ TrustAnchor anchor =
+ new TrustAnchor(cert,
cert.getExtensionValue(NAME_CONSTRAINTS_OID));
set.add(anchor);
}
@@ -165,10 +160,10 @@
Enumeration aliases = this.keystore.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
- X509Certificate cert = (X509Certificate) this.keystore
- .getCertificate(alias);
- TrustAnchor anchor = new TrustAnchor(cert, cert
- .getExtensionValue(NAME_CONSTRAINTS_OID));
+ X509Certificate cert =
+ (X509Certificate) this.keystore.getCertificate(alias);
+ TrustAnchor anchor =
+ new TrustAnchor(cert,
cert.getExtensionValue(NAME_CONSTRAINTS_OID));
set.add(anchor);
}
@@ -178,14 +173,13 @@
param.setRevocationEnabled(false);
// Verify the trust path using the above settings
- String provider = properties
-
.getProperty("org.apache.ws.security.crypto.merlin.cert.provider");
+ String provider =
+
properties.getProperty("org.apache.ws.security.crypto.merlin.cert.provider");
CertPathValidator certPathValidator;
if (provider == null || provider.length() == 0) {
certPathValidator = CertPathValidator.getInstance("PKIX");
} else {
- certPathValidator = CertPathValidator.getInstance("PKIX",
- provider);
+ certPathValidator = CertPathValidator.getInstance("PKIX",
provider);
}
certPathValidator.validate(path, param);
} catch (NoSuchProviderException ex) {
Modified: webservices/wss4j/trunk/test/wssec/TestWSSecurityWSS86.java
URL:
http://svn.apache.org/viewvc/webservices/wss4j/trunk/test/wssec/TestWSSecurityWSS86.java?rev=750484&r1=750483&r2=750484&view=diff
==============================================================================
--- webservices/wss4j/trunk/test/wssec/TestWSSecurityWSS86.java (original)
+++ webservices/wss4j/trunk/test/wssec/TestWSSecurityWSS86.java Thu Mar 5
16:00:47 2009
@@ -32,8 +32,10 @@
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.components.crypto.CryptoFactory;
+import org.apache.ws.security.message.WSSecEncrypt;
import org.apache.ws.security.message.WSSecSignature;
import org.apache.ws.security.message.WSSecHeader;
+import org.apache.xml.security.utils.RFC2253Parser;
import org.w3c.dom.Document;
import javax.security.auth.callback.Callback;
@@ -42,6 +44,8 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
/**
* This is a test for WSS-86 - "CryptoBase.splitAndTrim does not take into
account the format of a
@@ -172,6 +176,53 @@
}
/**
+ * Test loading a certificate using BouncyCastle, and using it to encrypt
a message, but
+ * decrypt the message using the Java Keystore provider
+ */
+ public void testInterop() throws Exception {
+ //
+ // This cert corresponds to the cert in wss86.keystore
+ //
+ byte[] certBytes =
+ org.apache.ws.security.util.Base64.decode(
+
"MIICfDCCAeUCBElPtuwwDQYJKoZIhvcNAQEEBQAwgYQxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIEwZC"
+ +
"YXllcm4xDzANBgNVBAcTBk11bmljaDEPMA0GA1UEChMGQXBhY2hlMQ4wDAYDVQQLEwVXU1M0SjEP"
+ +
"MA0GA1UEAxMGV2VybmVyMSEwHwYJKoZIhvcNAQkBFhJXZXJuZXJAZXhhbXBsZS5jb20wHhcNMDgx"
+ +
"MjIyMTU0OTAwWhcNMDkwMzIyMTU0OTAwWjCBhDELMAkGA1UEBhMCREUxDzANBgNVBAgTBkJheWVy"
+ +
"bjEPMA0GA1UEBxMGTXVuaWNoMQ8wDQYDVQQKEwZBcGFjaGUxDjAMBgNVBAsTBVdTUzRKMQ8wDQYD"
+ +
"VQQDEwZXZXJuZXIxITAfBgkqhkiG9w0BCQEWEldlcm5lckBleGFtcGxlLmNvbTCBnzANBgkqhkiG"
+ +
"9w0BAQEFAAOBjQAwgYkCgYEA0CudLx3cFcAVBZsk4PuMYD2w3fg0pAXP4J2GkWdIw/ydyfBaMcMy"
+ +
"Q6LfIEWITj5IY9M7JSddj9Mil8po5ClvSKiu07pC7ePD7VbcXqA+D4CEjwkkkb3mBJ1ohUraCdI5"
+ +
"/B2PsEY9QpAkoknMEKaKFn5JOE7BKfPG85rCCYC/B8cCAwEAATANBgkqhkiG9w0BAQQFAAOBgQBx"
+ +
"4dlaLgJF74/mwhhWp49pxwk+MY/udrPw6GRiTdTFuAbkODuDL+zvssY6l6nZij2TL22ouTe4H/cf"
+ +
"n/rjslklB73ZIcxgbfHar914UZd970AgbSt2NUGepybdr57zmKdi7wdLVojgdRQMHN6/NoUOicj3"
+ + "TRZG7slsfImuGsxMJw=="
+ );
+ CertificateFactory factory =
+ CertificateFactory.getInstance("X.509", "BC");
+ X509Certificate cert =
+ (X509Certificate)factory.generateCertificate(
+ new java.io.ByteArrayInputStream(certBytes)
+ );
+
+ SOAPEnvelope unsignedEnvelope = message.getSOAPEnvelope();
+ WSSecEncrypt encrypt = new WSSecEncrypt();
+ encrypt.setUseThisCert(cert);
+ Document doc = unsignedEnvelope.getAsDocument();
+ WSSecHeader secHeader = new WSSecHeader();
+ secHeader.insertSecurityHeader(doc);
+ Document encryptedDoc = encrypt.build(doc, crypto, secHeader);
+
+ if (LOG.isDebugEnabled()) {
+ String outputString =
+
org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(encryptedDoc);
+ LOG.debug(outputString);
+ }
+ verify(encryptedDoc);
+
+ }
+
+ /**
* Verifies the soap envelope
* <p/>
*
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]