Added: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/EncryptedKeySTRParser.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/EncryptedKeySTRParser.java?rev=1051143&view=auto ============================================================================== --- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/EncryptedKeySTRParser.java (added) +++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/EncryptedKeySTRParser.java Mon Dec 20 15:22:01 2010 @@ -0,0 +1,174 @@ +/** + * 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.str; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.ws.security.WSConstants; +import org.apache.ws.security.WSDocInfo; +import org.apache.ws.security.WSSConfig; +import org.apache.ws.security.WSSecurityEngine; +import org.apache.ws.security.WSSecurityEngineResult; +import org.apache.ws.security.WSSecurityException; +import org.apache.ws.security.components.crypto.Crypto; +import org.apache.ws.security.message.token.SecurityTokenReference; +import org.apache.ws.security.message.token.X509Security; +import org.apache.ws.security.saml.SAMLKeyInfo; +import org.apache.ws.security.saml.SAMLUtil; +import org.w3c.dom.Element; + +import java.security.Principal; +import java.security.PublicKey; +import java.security.cert.X509Certificate; + +import javax.security.auth.callback.CallbackHandler; +import javax.xml.namespace.QName; + +public class EncryptedKeySTRParser implements STRParser { + + private static final Log LOG = LogFactory.getLog(EncryptedKeySTRParser.class.getName()); + + private X509Certificate[] certs; + + public void parseSecurityTokenReference( + Element strElement, + String algorithm, + Crypto crypto, + CallbackHandler cb, + WSDocInfo wsDocInfo, + WSSConfig wssConfig + ) throws WSSecurityException { + SecurityTokenReference secRef = new SecurityTokenReference(strElement); + // + // handle X509IssuerSerial here. First check if all elements are available, + // get the appropriate data, check if all data is available. + // If all is ok up to that point, look up the certificate alias according + // to issuer name and serial number. + // This method is recommended by OASIS WS-S specification, X509 profile + // + if (secRef.containsX509Data() || secRef.containsX509IssuerSerial()) { + String alias = secRef.getX509IssuerSerialAlias(crypto); + if (alias != null) { + certs = crypto.getCertificates(alias); + } + if (LOG.isDebugEnabled()) { + LOG.debug("X509IssuerSerial alias: " + alias); + } + } + // + // If wsse:KeyIdentifier found, then the public key of the attached cert was used to + // encrypt the session (symmetric) key that encrypts the data. Extract the certificate + // using the BinarySecurity token (was enhanced to handle KeyIdentifier too). + // This method is _not_ recommended by OASIS WS-S specification, X509 profile + // + else if (secRef.containsKeyIdentifier()) { + if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(secRef.getKeyIdentifierValueType())) { + Element token = + secRef.getKeyIdentifierTokenElement(strElement.getOwnerDocument(), wsDocInfo, cb); + + if (crypto == null) { + throw new WSSecurityException( + WSSecurityException.FAILURE, "noSigCryptoFile" + ); + } + SAMLKeyInfo samlKi = SAMLUtil.getSAMLKeyInfo(token, crypto, cb); + certs = samlKi.getCerts(); + } else { + certs = secRef.getKeyIdentifier(crypto); + } + } else if (secRef.containsReference()) { + if (wsDocInfo != null) { + String uri = secRef.getReference().getURI(); + WSSecurityEngineResult result = wsDocInfo.getResult(uri); + + if (result != null) { + int action = ((Integer)result.get(WSSecurityEngineResult.TAG_ACTION)).intValue(); + if (WSConstants.BST == action) { + certs = + (X509Certificate[])result.get( + WSSecurityEngineResult.TAG_X509_CERTIFICATES + ); + } else { + throw new WSSecurityException( + WSSecurityException.UNSUPPORTED_SECURITY_TOKEN, + "unsupportedBinaryTokenType", + null + ); + } + } + } + if (certs == null) { + Element bstElement = + secRef.getTokenElement(strElement.getOwnerDocument(), null, cb); + + // at this point ... check token type: Binary + QName el = new QName(bstElement.getNamespaceURI(), bstElement.getLocalName()); + if (el.equals(WSSecurityEngine.BINARY_TOKEN)) { + X509Security token = new X509Security(bstElement); + if (token == null) { + throw new WSSecurityException( + WSSecurityException.UNSUPPORTED_SECURITY_TOKEN, + "unsupportedBinaryTokenType", + new Object[] {"for decryption (BST)"} + ); + } + certs = new X509Certificate[]{token.getX509Certificate(crypto)}; + } else { + throw new WSSecurityException( + WSSecurityException.UNSUPPORTED_SECURITY_TOKEN, + "unsupportedBinaryTokenType", + null + ); + } + } + } else { + throw new WSSecurityException( + WSSecurityException.INVALID_SECURITY, "unsupportedKeyId" + ); + } + + if (LOG.isDebugEnabled() && certs != null && certs[0] != null) { + LOG.debug("cert: " + certs[0]); + } + } + + + public void validateCredentials() throws WSSecurityException { + // + } + + public X509Certificate[] getCertificates() { + return certs; + } + + public Principal getPrincipal() { + return null; + } + + public PublicKey getPublicKey() { + return null; + } + + public byte[] getSecretKey() { + return null; + } + + +}
Added: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/STRParser.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/STRParser.java?rev=1051143&view=auto ============================================================================== --- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/STRParser.java (added) +++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/STRParser.java Mon Dec 20 15:22:01 2010 @@ -0,0 +1,54 @@ +/** + * 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.str; + +import org.apache.ws.security.WSDocInfo; +import org.apache.ws.security.WSSConfig; +import org.apache.ws.security.WSSecurityException; +import org.apache.ws.security.components.crypto.Crypto; +import org.w3c.dom.Element; + +import java.security.Principal; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import javax.security.auth.callback.CallbackHandler; + +public interface STRParser { + + public void parseSecurityTokenReference( + Element strElement, + String algorithm, + Crypto crypto, + CallbackHandler cb, + WSDocInfo wsDocInfo, + WSSConfig wssConfig + ) throws WSSecurityException; + + public void validateCredentials() throws WSSecurityException; + + public X509Certificate[] getCertificates(); + + public Principal getPrincipal(); + + public PublicKey getPublicKey(); + + public byte[] getSecretKey(); + +} Added: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SecurityTokenRefSTRParser.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SecurityTokenRefSTRParser.java?rev=1051143&view=auto ============================================================================== --- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SecurityTokenRefSTRParser.java (added) +++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SecurityTokenRefSTRParser.java Mon Dec 20 15:22:01 2010 @@ -0,0 +1,174 @@ +/** + * 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.str; + +import org.apache.ws.security.WSConstants; +import org.apache.ws.security.WSDocInfo; +import org.apache.ws.security.WSPasswordCallback; +import org.apache.ws.security.WSSConfig; +import org.apache.ws.security.WSSecurityEngineResult; +import org.apache.ws.security.WSSecurityException; +import org.apache.ws.security.components.crypto.Crypto; +import org.apache.ws.security.message.token.DerivedKeyToken; +import org.apache.ws.security.message.token.Reference; +import org.apache.ws.security.message.token.SecurityTokenReference; +import org.apache.ws.security.saml.SAMLKeyInfo; +import org.apache.ws.security.saml.SAMLUtil; +import org.apache.ws.security.util.WSSecurityUtil; +import org.w3c.dom.Element; + +import java.security.Principal; +import java.security.PublicKey; +import java.security.cert.X509Certificate; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; + +public class SecurityTokenRefSTRParser implements STRParser { + + private byte[] secretKey; + + public void parseSecurityTokenReference( + Element strElement, + String algorithm, + Crypto crypto, + CallbackHandler cb, + WSDocInfo wsDocInfo, + WSSConfig wssConfig + ) throws WSSecurityException { + + SecurityTokenReference secRef = new SecurityTokenReference(strElement); + + if (secRef.containsReference()) { + Reference reference = secRef.getReference(); + String uri = reference.getURI(); + String id = uri; + if (id.charAt(0) == '#') { + id = id.substring(1); + } + WSSecurityEngineResult result = wsDocInfo.getResult(id); + if (result != null) { + int action = ((Integer)result.get(WSSecurityEngineResult.TAG_ACTION)).intValue(); + if (WSConstants.ENCR == action) { + secretKey = (byte[])result.get(WSSecurityEngineResult.TAG_DECRYPTED_KEY); + } else if (WSConstants.DKT == action) { + DerivedKeyToken dkt = + (DerivedKeyToken)result.get(WSSecurityEngineResult.TAG_DERIVED_KEY_TOKEN); + byte[] secret = + (byte[])result.get(WSSecurityEngineResult.TAG_SECRET); + secretKey = dkt.deriveKey(WSSecurityUtil.getKeyLength(algorithm), secret); + } else if (WSConstants.ST_UNSIGNED == action) { + Element samlElement = wsDocInfo.getTokenElement(id); + SAMLKeyInfo keyInfo = + SAMLUtil.getSAMLKeyInfo(samlElement, crypto, cb); + // TODO Handle malformed SAML tokens where they don't have the + // secret in them + secretKey = keyInfo.getSecret(); + } else if (WSConstants.SCT == action) { + secretKey = (byte[])result.get(WSSecurityEngineResult.TAG_SECRET); + } + } else { + // Try custom token + WSPasswordCallback pwcb = + new WSPasswordCallback(id, WSPasswordCallback.CUSTOM_TOKEN); + try { + Callback[] callbacks = new Callback[]{pwcb}; + cb.handle(callbacks); + } catch (Exception e) { + throw new WSSecurityException( + WSSecurityException.FAILURE, + "noPassword", + new Object[] {id}, + e + ); + } + secretKey = pwcb.getKey(); + + if (secretKey == null) { + throw new WSSecurityException( + WSSecurityException.FAILED_CHECK, "unsupportedKeyId" + ); + } + } + } else if (secRef.containsKeyIdentifier()){ + if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(secRef.getKeyIdentifierValueType())) { + Element token = + secRef.getKeyIdentifierTokenElement(strElement.getOwnerDocument(), wsDocInfo, cb); + + if (crypto == null) { + throw new WSSecurityException( + WSSecurityException.FAILURE, "noSigCryptoFile" + ); + } + SAMLKeyInfo keyInfo = SAMLUtil.getSAMLKeyInfo(token, crypto, cb); + // TODO Handle malformed SAML tokens where they don't have the + // secret in them + secretKey = keyInfo.getSecret(); + } else { + String keyIdentifierValue = secRef.getKeyIdentifierValue(); + WSPasswordCallback pwcb = + new WSPasswordCallback( + keyIdentifierValue, + null, + secRef.getKeyIdentifierValueType(), + WSPasswordCallback.ENCRYPTED_KEY_TOKEN + ); + + try { + Callback[] callbacks = new Callback[]{pwcb}; + cb.handle(callbacks); + } catch (Exception e) { + throw new WSSecurityException( + WSSecurityException.FAILURE, + "noPassword", + new Object[] {keyIdentifierValue}, + e + ); + } + secretKey = pwcb.getKey(); + } + } else { + throw new WSSecurityException(WSSecurityException.FAILED_CHECK, "noReference"); + } + } + + + public void validateCredentials() throws WSSecurityException { + // + } + + public X509Certificate[] getCertificates() { + return null; + } + + public Principal getPrincipal() { + return null; + } + + public PublicKey getPublicKey() { + return null; + } + + public byte[] getSecretKey() { + return secretKey; + } + + +} Added: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SignatureSTRParser.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SignatureSTRParser.java?rev=1051143&view=auto ============================================================================== --- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SignatureSTRParser.java (added) +++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SignatureSTRParser.java Mon Dec 20 15:22:01 2010 @@ -0,0 +1,574 @@ +/** + * 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.str; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.ws.security.CustomTokenPrincipal; +import org.apache.ws.security.WSConstants; +import org.apache.ws.security.WSDocInfo; +import org.apache.ws.security.WSPasswordCallback; +import org.apache.ws.security.WSSConfig; +import org.apache.ws.security.WSSecurityEngine; +import org.apache.ws.security.WSSecurityEngineResult; +import org.apache.ws.security.WSSecurityException; +import org.apache.ws.security.components.crypto.Crypto; +import org.apache.ws.security.message.token.BinarySecurity; +import org.apache.ws.security.message.token.DerivedKeyToken; +import org.apache.ws.security.message.token.PKIPathSecurity; +import org.apache.ws.security.message.token.SecurityContextToken; +import org.apache.ws.security.message.token.SecurityTokenReference; +import org.apache.ws.security.message.token.UsernameToken; +import org.apache.ws.security.message.token.X509Security; +import org.apache.ws.security.processor.EncryptedKeyProcessor; +import org.apache.ws.security.saml.SAMLKeyInfo; +import org.apache.ws.security.saml.SAMLUtil; +import org.apache.ws.security.util.WSSecurityUtil; +import org.opensaml.SAMLAssertion; +import org.w3c.dom.Element; + +import java.math.BigInteger; +import java.security.Principal; +import java.security.PublicKey; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509Certificate; +import java.util.List; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.xml.namespace.QName; + +public class SignatureSTRParser implements STRParser { + + private static final Log LOG = LogFactory.getLog(SignatureSTRParser.class.getName()); + + private X509Certificate[] certs; + + private byte[] secretKey; + + private PublicKey publicKey; + + private Principal principal; + + private boolean validateCertChain; + + private Crypto crypto; + + public void parseSecurityTokenReference( + Element strElement, + String algorithm, + Crypto crypto, + CallbackHandler cb, + WSDocInfo wsDocInfo, + WSSConfig wssConfig + ) throws WSSecurityException { + this.crypto = crypto; + SecurityTokenReference secRef = new SecurityTokenReference(strElement); + // + // Here we get some information about the document that is being + // processed, in particular the crypto implementation, and already + // detected BST that may be used later during dereferencing. + // + if (secRef.containsReference()) { + org.apache.ws.security.message.token.Reference ref = secRef.getReference(); + + String uri = ref.getURI(); + if (uri.charAt(0) == '#') { + uri = uri.substring(1); + } + WSSecurityEngineResult result = wsDocInfo.getResult(uri); + if (result == null) { + Element token = + secRef.getTokenElement(strElement.getOwnerDocument(), wsDocInfo, cb); + QName el = new QName(token.getNamespaceURI(), token.getLocalName()); + if (el.equals(WSSecurityEngine.BINARY_TOKEN)) { + certs = getCertificatesTokenReference(token, crypto); + if (certs != null && certs.length > 1) { + validateCertChain = true; + } + } else if (el.equals(WSSecurityEngine.SAML_TOKEN)) { + if (crypto == null) { + throw new WSSecurityException( + WSSecurityException.FAILURE, "noSigCryptoFile" + ); + } + SAMLKeyInfo samlKi = SAMLUtil.getSAMLKeyInfo(token, crypto, cb); + certs = samlKi.getCerts(); + secretKey = samlKi.getSecret(); + principal = createPrincipalFromSAMLKeyInfo(samlKi); + } else if (el.equals(WSSecurityEngine.ENCRYPTED_KEY)){ + EncryptedKeyProcessor proc = + new EncryptedKeyProcessor(); + WSDocInfo docInfo = new WSDocInfo(token.getOwnerDocument()); + List<WSSecurityEngineResult> encrResult = + proc.handleToken(token, null, crypto, cb, docInfo, null); + secretKey = + (byte[])encrResult.get(0).get( + WSSecurityEngineResult.TAG_DECRYPTED_KEY + ); + principal = new CustomTokenPrincipal(token.getAttribute("Id")); + } else { + String id = secRef.getReference().getURI(); + secretKey = getSecretKeyFromCustomToken(id, cb); + principal = new CustomTokenPrincipal(id); + } + } else { + int action = ((Integer)result.get(WSSecurityEngineResult.TAG_ACTION)).intValue(); + if (WSConstants.UT == action) { + UsernameToken usernameToken = + (UsernameToken)result.get(WSSecurityEngineResult.TAG_USERNAME_TOKEN); + + if (usernameToken.isDerivedKey()) { + secretKey = usernameToken.getDerivedKey(); + } else { + secretKey = usernameToken.getSecretKey(wssConfig.getSecretKeyLength()); + } + principal = usernameToken.createPrincipal(); + } else if (WSConstants.BST == action) { + certs = + (X509Certificate[])result.get(WSSecurityEngineResult.TAG_X509_CERTIFICATES); + if (certs != null && certs.length > 1) { + validateCertChain = true; + } + } else if (WSConstants.ENCR == action) { + secretKey = (byte[])result.get(WSSecurityEngineResult.TAG_DECRYPTED_KEY); + String id = (String)result.get(WSSecurityEngineResult.TAG_ID); + principal = new CustomTokenPrincipal(id); + } else if (WSConstants.SCT == action) { + secretKey = (byte[])result.get(WSSecurityEngineResult.TAG_SECRET); + SecurityContextToken sct = + (SecurityContextToken)result.get( + WSSecurityEngineResult.TAG_SECURITY_CONTEXT_TOKEN + ); + principal = new CustomTokenPrincipal(sct.getIdentifier()); + } else if (WSConstants.DKT == action) { + DerivedKeyToken dkt = + (DerivedKeyToken)result.get(WSSecurityEngineResult.TAG_DERIVED_KEY_TOKEN); + int keyLength = dkt.getLength(); + if (keyLength <= 0) { + keyLength = WSSecurityUtil.getKeyLength(algorithm); + } + byte[] secret = (byte[])result.get(WSSecurityEngineResult.TAG_SECRET); + secretKey = dkt.deriveKey(keyLength, secret); + principal = dkt.createPrincipal(); + } else if (WSConstants.ST_UNSIGNED == action) { + if (crypto == null) { + throw new WSSecurityException( + WSSecurityException.FAILURE, "noSigCryptoFile" + ); + } + Element samlElement = wsDocInfo.getTokenElement(uri); + SAMLKeyInfo keyInfo = + SAMLUtil.getSAMLKeyInfo(samlElement, crypto, cb); + certs = keyInfo.getCerts(); + secretKey = keyInfo.getSecret(); + publicKey = keyInfo.getPublicKey(); + principal = createPrincipalFromSAMLKeyInfo(keyInfo); + } + } + } else if (secRef.containsX509Data() || secRef.containsX509IssuerSerial()) { + certs = secRef.getX509IssuerSerial(crypto); + } else if (secRef.containsKeyIdentifier()) { + if (secRef.getKeyIdentifierValueType().equals(SecurityTokenReference.ENC_KEY_SHA1_URI)) { + String id = secRef.getKeyIdentifierValue(); + secretKey = getSecretKeyFromEncKeySHA1KI(id, cb); + principal = new CustomTokenPrincipal(id); + } else if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(secRef.getKeyIdentifierValueType())) { + Element token = + secRef.getKeyIdentifierTokenElement(strElement.getOwnerDocument(), wsDocInfo, cb); + + if (crypto == null) { + throw new WSSecurityException( + WSSecurityException.FAILURE, "noSigCryptoFile" + ); + } + SAMLKeyInfo samlKi = SAMLUtil.getSAMLKeyInfo(token, crypto, cb); + certs = samlKi.getCerts(); + secretKey = samlKi.getSecret(); + publicKey = samlKi.getPublicKey(); + principal = createPrincipalFromSAMLKeyInfo(samlKi); + } else { + certs = secRef.getKeyIdentifier(crypto); + } + } else { + throw new WSSecurityException( + WSSecurityException.INVALID_SECURITY, + "unsupportedKeyInfo", + new Object[]{strElement.toString()} + ); + } + } + + public void validateCredentials() throws WSSecurityException { + // + // Validate certificates and verify trust + // + validateCertificates(certs); + if (certs != null) { + if (principal == null) { + principal = certs[0].getSubjectX500Principal(); + } + boolean trust = false; + if (!validateCertChain || certs.length == 1) { + trust = verifyTrust(certs[0], crypto); + } else if (validateCertChain && certs.length > 1) { + trust = verifyTrust(certs, crypto); + } + if (!trust) { + throw new WSSecurityException(WSSecurityException.FAILED_CHECK); + } + } + } + + public X509Certificate[] getCertificates() { + return certs; + } + + public Principal getPrincipal() { + return principal; + } + + public PublicKey getPublicKey() { + return publicKey; + } + + public byte[] getSecretKey() { + return secretKey; + } + + /** + * Validate an array of certificates by checking the validity of each cert + * @param certsToValidate The array of certificates to validate + * @throws WSSecurityException + */ + private static void validateCertificates( + X509Certificate[] certsToValidate + ) throws WSSecurityException { + if (certsToValidate != null && certsToValidate.length > 0) { + try { + for (int i = 0; i < certsToValidate.length; i++) { + certsToValidate[i].checkValidity(); + } + } catch (CertificateExpiredException e) { + throw new WSSecurityException( + WSSecurityException.FAILED_CHECK, "invalidCert", null, e + ); + } catch (CertificateNotYetValidException e) { + throw new WSSecurityException( + WSSecurityException.FAILED_CHECK, "invalidCert", null, e + ); + } + } + } + + + /** + * Evaluate whether a given certificate should be trusted. + * + * Policy used in this implementation: + * 1. Search the keystore for the transmitted certificate + * 2. Search the keystore for a connection to the transmitted certificate + * (that is, search for certificate(s) of the issuer of the transmitted certificate + * 3. Verify the trust path for those certificates found because the search for the issuer + * might be fooled by a phony DN (String!) + * + * @param cert the certificate that should be validated against the keystore + * @return true if the certificate is trusted, false if not + * @throws WSSecurityException + */ + private static boolean verifyTrust(X509Certificate cert, Crypto crypto) + throws WSSecurityException { + + // If no certificate was transmitted, do not trust the signature + if (cert == null) { + return false; + } + + String subjectString = cert.getSubjectX500Principal().getName(); + String issuerString = cert.getIssuerX500Principal().getName(); + BigInteger issuerSerial = cert.getSerialNumber(); + + if (LOG.isDebugEnabled()) { + LOG.debug("Transmitted certificate has subject " + subjectString); + LOG.debug( + "Transmitted certificate has issuer " + issuerString + " (serial " + + issuerSerial + ")" + ); + } + + // + // FIRST step - Search the keystore for the transmitted certificate + // + if (crypto.isCertificateInKeyStore(cert)) { + return true; + } + + // + // SECOND step - Search for the issuer of the transmitted certificate in the + // keystore or the truststore + // + String[] aliases = crypto.getAliasesForDN(issuerString); + + // If the alias has not been found, the issuer is not in the keystore/truststore + // As a direct result, do not trust the transmitted certificate + if (aliases == null || aliases.length < 1) { + if (LOG.isDebugEnabled()) { + LOG.debug( + "No aliases found in keystore for issuer " + issuerString + + " of certificate for " + subjectString + ); + } + return false; + } + + // + // THIRD step + // Check the certificate trust path for every alias of the issuer found in the + // keystore/truststore + // + for (int i = 0; i < aliases.length; i++) { + String alias = aliases[i]; + + if (LOG.isDebugEnabled()) { + LOG.debug( + "Preparing to validate certificate path with alias " + alias + + " for issuer " + issuerString + ); + } + + // Retrieve the certificate(s) for the alias from the keystore/truststore + X509Certificate[] certs = crypto.getCertificates(alias); + + // If no certificates have been found, there has to be an error: + // The keystore/truststore can find an alias but no certificate(s) + if (certs == null || certs.length < 1) { + throw new WSSecurityException( + "Could not get certificates for alias " + alias + ); + } + + // + // Form a certificate chain from the transmitted certificate + // and the certificate(s) of the issuer from the keystore/truststore + // + X509Certificate[] x509certs = new X509Certificate[certs.length + 1]; + x509certs[0] = cert; + for (int j = 0; j < certs.length; j++) { + x509certs[j + 1] = certs[j]; + } + + // + // Use the validation method from the crypto to check whether the subjects' + // certificate was really signed by the issuer stated in the certificate + // + if (crypto.validateCertPath(x509certs)) { + if (LOG.isDebugEnabled()) { + LOG.debug( + "Certificate path has been verified for certificate with subject " + + subjectString + ); + } + return true; + } + } + + if (LOG.isDebugEnabled()) { + LOG.debug( + "Certificate path could not be verified for certificate with subject " + + subjectString + ); + } + return false; + } + + + /** + * Evaluate whether the given certificate chain should be trusted. + * + * @param certificates the certificate chain that should be validated against the keystore + * @return true if the certificate chain is trusted, false if not + * @throws WSSecurityException + */ + private static boolean verifyTrust(X509Certificate[] certificates, Crypto crypto) + throws WSSecurityException { + String subjectString = certificates[0].getSubjectX500Principal().getName(); + // + // Use the validation method from the crypto to check whether the subjects' + // certificate was really signed by the issuer stated in the certificate + // + if (certificates != null && certificates.length > 1 + && crypto.validateCertPath(certificates)) { + if (LOG.isDebugEnabled()) { + LOG.debug( + "Certificate path has been verified for certificate with subject " + + subjectString + ); + } + return true; + } + + if (LOG.isDebugEnabled()) { + LOG.debug( + "Certificate path could not be verified for certificate with subject " + + subjectString + ); + } + + return false; + } + + + /** + * Extracts the certificate(s) from the Binary Security token reference. + * + * @param elem The element containing the binary security token. This is + * either X509 certificate(s) or a PKIPath. + * @return an array of X509 certificates + * @throws WSSecurityException + */ + private static X509Certificate[] getCertificatesTokenReference(Element elem, Crypto crypto) + throws WSSecurityException { + if (crypto == null) { + throw new WSSecurityException(WSSecurityException.FAILURE, "noSigCryptoFile"); + } + BinarySecurity token = createSecurityToken(elem); + if (token instanceof PKIPathSecurity) { + return ((PKIPathSecurity) token).getX509Certificates(crypto); + } else { + X509Certificate cert = ((X509Security) token).getX509Certificate(crypto); + return new X509Certificate[]{cert}; + } + } + + + /** + * Checks the <code>element</code> and creates appropriate binary security object. + * + * @param element The XML element that contains either a <code>BinarySecurityToken + * </code> or a <code>PKIPath</code> element. Other element types a not + * supported + * @return the BinarySecurity object, either a <code>X509Security</code> or a + * <code>PKIPathSecurity</code> object. + * @throws WSSecurityException + */ + private static BinarySecurity createSecurityToken(Element element) throws WSSecurityException { + + String type = element.getAttribute("ValueType"); + if (X509Security.X509_V3_TYPE.equals(type)) { + X509Security x509 = new X509Security(element); + return (BinarySecurity) x509; + } else if (PKIPathSecurity.getType().equals(type)) { + PKIPathSecurity pkiPath = new PKIPathSecurity(element); + return (BinarySecurity) pkiPath; + } + throw new WSSecurityException( + WSSecurityException.UNSUPPORTED_SECURITY_TOKEN, + "unsupportedBinaryTokenType", + new Object[]{type} + ); + } + + /** + * A method to create a Principal from a SAML KeyInfo + * @param samlKeyInfo The SAML KeyInfo object + * @return A principal + */ + private static Principal createPrincipalFromSAMLKeyInfo( + SAMLKeyInfo samlKeyInfo + ) { + X509Certificate[] samlCerts = samlKeyInfo.getCerts(); + Principal principal = null; + if (samlCerts != null && samlCerts.length > 0) { + principal = samlCerts[0].getSubjectX500Principal(); + } else { + final SAMLAssertion assertion = samlKeyInfo.getAssertion(); + principal = new CustomTokenPrincipal(assertion.getId()); + ((CustomTokenPrincipal)principal).setTokenObject(assertion); + } + return principal; + } + + /** + * Get the Secret Key from a CallbackHandler for a custom token + * @param id The id of the element + * @param cb The CallbackHandler object + * @return A Secret Key + * @throws WSSecurityException + */ + private byte[] getSecretKeyFromCustomToken( + String id, + CallbackHandler cb + ) throws WSSecurityException { + if (id.charAt(0) == '#') { + id = id.substring(1); + } + WSPasswordCallback pwcb = + new WSPasswordCallback(id, WSPasswordCallback.CUSTOM_TOKEN); + try { + Callback[] callbacks = new Callback[]{pwcb}; + cb.handle(callbacks); + } catch (Exception e) { + throw new WSSecurityException( + WSSecurityException.FAILURE, + "noPassword", + new Object[] {id}, + e + ); + } + + return pwcb.getKey(); + } + + + /** + * Get the Secret Key from a CallbackHandler for the Encrypted Key SHA1 case. + * @param id The id of the element + * @param cb The CallbackHandler object + * @return A Secret Key + * @throws WSSecurityException + */ + private byte[] getSecretKeyFromEncKeySHA1KI( + String id, + CallbackHandler cb + ) throws WSSecurityException { + WSPasswordCallback pwcb = + new WSPasswordCallback( + id, + null, + SecurityTokenReference.ENC_KEY_SHA1_URI, + WSPasswordCallback.ENCRYPTED_KEY_TOKEN + ); + try { + Callback[] callbacks = new Callback[]{pwcb}; + cb.handle(callbacks); + } catch (Exception e) { + throw new WSSecurityException( + WSSecurityException.FAILURE, + "noPassword", + new Object[] {id}, + e + ); + } + return pwcb.getKey(); + } + + +} Modified: webservices/wss4j/trunk/src/test/java/org/apache/ws/security/components/crypto/CryptoProviderTest.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/test/java/org/apache/ws/security/components/crypto/CryptoProviderTest.java?rev=1051143&r1=1051142&r2=1051143&view=diff ============================================================================== --- webservices/wss4j/trunk/src/test/java/org/apache/ws/security/components/crypto/CryptoProviderTest.java (original) +++ webservices/wss4j/trunk/src/test/java/org/apache/ws/security/components/crypto/CryptoProviderTest.java Mon Dec 20 15:22:01 2010 @@ -192,8 +192,7 @@ public class CryptoProviderTest extends verify(encryptedDoc); fail("Failure expected on encryption with a key that does not exist in the keystore"); } catch (Exception ex) { - assertTrue(ex.getMessage().indexOf( - "The private key for the supplied alias does not exist in the keystore") != -1); + // expected } }
