| /** |
| * 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.wss4j.dom.message; |
| |
| import java.security.NoSuchProviderException; |
| import java.security.Provider; |
| import java.util.List; |
| |
| import javax.xml.crypto.XMLStructure; |
| import javax.xml.crypto.dom.DOMStructure; |
| import javax.xml.crypto.dsig.CanonicalizationMethod; |
| import javax.xml.crypto.dsig.SignatureMethod; |
| import javax.xml.crypto.dsig.SignedInfo; |
| import javax.xml.crypto.dsig.XMLSignContext; |
| import javax.xml.crypto.dsig.XMLSignature; |
| import javax.xml.crypto.dsig.XMLSignatureFactory; |
| import javax.xml.crypto.dsig.dom.DOMSignContext; |
| import javax.xml.crypto.dsig.keyinfo.KeyInfo; |
| import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory; |
| import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec; |
| import javax.xml.crypto.dsig.spec.ExcC14NParameterSpec; |
| |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| |
| import org.apache.wss4j.common.WSEncryptionPart; |
| import org.apache.wss4j.common.derivedKey.ConversationConstants; |
| import org.apache.wss4j.common.ext.WSSecurityException; |
| import org.apache.wss4j.common.token.Reference; |
| import org.apache.wss4j.common.token.SecurityTokenReference; |
| import org.apache.wss4j.common.util.KeyUtils; |
| import org.apache.wss4j.common.util.XMLUtils; |
| import org.apache.wss4j.dom.WSConstants; |
| import org.apache.wss4j.dom.WSDocInfo; |
| import org.apache.wss4j.dom.transform.STRTransform; |
| import org.apache.wss4j.dom.util.WSSecurityUtil; |
| |
| /** |
| * Builder to sign with derived keys |
| */ |
| public class WSSecDKSign extends WSSecDerivedKeyBase { |
| |
| private static final org.slf4j.Logger LOG = |
| org.slf4j.LoggerFactory.getLogger(WSSecDKSign.class); |
| |
| private String sigAlgo = WSConstants.HMAC_SHA1; |
| private String digestAlgo = WSConstants.SHA1; |
| private String canonAlgo = WSConstants.C14N_EXCL_OMIT_COMMENTS; |
| private byte[] signatureValue; |
| |
| private String keyInfoUri; |
| private SecurityTokenReference secRef; |
| private String strUri; |
| private WSDocInfo wsDocInfo; |
| |
| private XMLSignatureFactory signatureFactory; |
| private XMLSignature sig; |
| private KeyInfo keyInfo; |
| private CanonicalizationMethod c14nMethod; |
| private int derivedKeyLength = -1; |
| private boolean addInclusivePrefixes = true; |
| |
| public WSSecDKSign(WSSecHeader securityHeader) { |
| super(securityHeader); |
| init(null); |
| } |
| |
| public WSSecDKSign(Document doc) { |
| this(doc, null); |
| } |
| |
| public WSSecDKSign(Document doc, Provider provider) { |
| super(doc); |
| init(provider); |
| } |
| |
| private void init(Provider provider) { |
| if (provider == null) { |
| // Try to install the Santuario Provider - fall back to the JDK provider if this does |
| // not work |
| try { |
| signatureFactory = XMLSignatureFactory.getInstance("DOM", "ApacheXMLDSig"); |
| } catch (NoSuchProviderException ex) { |
| signatureFactory = XMLSignatureFactory.getInstance("DOM"); |
| } |
| } else { |
| signatureFactory = XMLSignatureFactory.getInstance("DOM", provider); |
| } |
| } |
| |
| public Document build(byte[] ephemeralKey) throws WSSecurityException { |
| |
| prepare(ephemeralKey); |
| if (getParts().isEmpty()) { |
| getParts().add(WSSecurityUtil.getDefaultEncryptionPart(getDocument())); |
| } else { |
| for (WSEncryptionPart part : getParts()) { |
| if ("STRTransform".equals(part.getName()) && part.getId() == null) { |
| part.setId(strUri); |
| } |
| } |
| } |
| |
| List<javax.xml.crypto.dsig.Reference> referenceList = addReferencesToSign(getParts()); |
| computeSignature(referenceList); |
| |
| // |
| // prepend elements in the right order to the security header |
| // |
| prependDKElementToHeader(); |
| |
| return getDocument(); |
| } |
| |
| public void prepare(byte[] ephemeralKey) throws WSSecurityException { |
| super.prepare(ephemeralKey); |
| wsDocInfo = new WSDocInfo(getDocument()); |
| sig = null; |
| |
| try { |
| C14NMethodParameterSpec c14nSpec = null; |
| if (addInclusivePrefixes && canonAlgo.equals(WSConstants.C14N_EXCL_OMIT_COMMENTS)) { |
| Element securityHeaderElement = getSecurityHeader().getSecurityHeaderElement(); |
| List<String> prefixes = |
| getInclusivePrefixes(securityHeaderElement, false); |
| c14nSpec = new ExcC14NParameterSpec(prefixes); |
| } |
| |
| c14nMethod = signatureFactory.newCanonicalizationMethod(canonAlgo, c14nSpec); |
| } catch (Exception ex) { |
| LOG.error("", ex); |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.FAILED_SIGNATURE, ex, "noXMLSig" |
| ); |
| } |
| |
| keyInfoUri = getIdAllocator().createSecureId("KI-", keyInfo); |
| |
| secRef = new SecurityTokenReference(getDocument()); |
| strUri = getIdAllocator().createSecureId("STR-", secRef); |
| secRef.setID(strUri); |
| if (addWSUNamespace) { |
| secRef.addWSUNamespace(); |
| } |
| |
| Reference ref = new Reference(getDocument()); |
| ref.setURI("#" + getId()); |
| String ns = |
| ConversationConstants.getWSCNs(getWscVersion()) |
| + ConversationConstants.TOKEN_TYPE_DERIVED_KEY_TOKEN; |
| ref.setValueType(ns); |
| secRef.setReference(ref); |
| |
| XMLStructure structure = new DOMStructure(secRef.getElement()); |
| wsDocInfo.addTokenElement(secRef.getElement(), false); |
| KeyInfoFactory keyInfoFactory = signatureFactory.getKeyInfoFactory(); |
| keyInfo = |
| keyInfoFactory.newKeyInfo( |
| java.util.Collections.singletonList(structure), keyInfoUri |
| ); |
| |
| } |
| |
| /** |
| * Returns the SignatureElement. |
| * The method can be called any time after <code>prepare()</code>. |
| * @return The DOM Element of the signature. |
| */ |
| public Element getSignatureElement() { |
| Element securityHeaderElement = getSecurityHeader().getSecurityHeaderElement(); |
| return |
| XMLUtils.getDirectChildElement( |
| securityHeaderElement, WSConstants.SIG_LN, WSConstants.SIG_NS |
| ); |
| } |
| |
| /** |
| * This method adds references to the Signature. |
| * |
| * @param references The list of references to sign |
| * @throws WSSecurityException |
| */ |
| public List<javax.xml.crypto.dsig.Reference> addReferencesToSign( |
| List<WSEncryptionPart> references |
| ) throws WSSecurityException { |
| return |
| addReferencesToSign( |
| getDocument(), |
| references, |
| wsDocInfo, |
| signatureFactory, |
| addInclusivePrefixes, |
| digestAlgo |
| ); |
| } |
| |
| /** |
| * Compute the Signature over the references. |
| * |
| * After references are set this method computes the Signature for them. |
| * This method can be called any time after the references were set. See |
| * <code>addReferencesToSign()</code>. |
| * |
| * @throws WSSecurityException |
| */ |
| public void computeSignature( |
| List<javax.xml.crypto.dsig.Reference> referenceList |
| ) throws WSSecurityException { |
| computeSignature(referenceList, true, null); |
| } |
| |
| /** |
| * Compute the Signature over the references. |
| * |
| * After references are set this method computes the Signature for them. |
| * This method can be called any time after the references were set. See |
| * <code>addReferencesToSign()</code>. |
| * |
| * @throws WSSecurityException |
| */ |
| public void computeSignature( |
| List<javax.xml.crypto.dsig.Reference> referenceList, |
| boolean prepend, |
| Element siblingElement |
| ) throws WSSecurityException { |
| try { |
| java.security.Key key = getDerivedKey(sigAlgo); |
| SignatureMethod signatureMethod = |
| signatureFactory.newSignatureMethod(sigAlgo, null); |
| SignedInfo signedInfo = |
| signatureFactory.newSignedInfo(c14nMethod, signatureMethod, referenceList); |
| |
| sig = signatureFactory.newXMLSignature( |
| signedInfo, |
| keyInfo, |
| null, |
| getIdAllocator().createId("SIG-", null), |
| null); |
| |
| // |
| // Figure out where to insert the signature element |
| // |
| XMLSignContext signContext = null; |
| Element securityHeaderElement = getSecurityHeader().getSecurityHeaderElement(); |
| if (prepend) { |
| if (siblingElement == null) { |
| siblingElement = (Element)securityHeaderElement.getFirstChild(); |
| } |
| if (siblingElement == null) { |
| signContext = new DOMSignContext(key, securityHeaderElement); |
| } else { |
| signContext = new DOMSignContext(key, securityHeaderElement, siblingElement); |
| } |
| } else { |
| signContext = new DOMSignContext(key, securityHeaderElement); |
| } |
| |
| signContext.putNamespacePrefix(WSConstants.SIG_NS, WSConstants.SIG_PREFIX); |
| if (WSConstants.C14N_EXCL_OMIT_COMMENTS.equals(canonAlgo)) { |
| signContext.putNamespacePrefix( |
| WSConstants.C14N_EXCL_OMIT_COMMENTS, |
| WSConstants.C14N_EXCL_OMIT_COMMENTS_PREFIX |
| ); |
| } |
| signContext.setProperty(STRTransform.TRANSFORM_WS_DOC_INFO, wsDocInfo); |
| wsDocInfo.setCallbackLookup(callbackLookup); |
| |
| // Add the elements to sign to the Signature Context |
| wsDocInfo.setTokensOnContext((DOMSignContext)signContext); |
| |
| sig.sign(signContext); |
| |
| signatureValue = sig.getSignatureValue().getValue(); |
| } catch (Exception ex) { |
| LOG.error(ex.getMessage(), ex); |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.FAILED_SIGNATURE, ex |
| ); |
| } |
| } |
| |
| protected int getDerivedKeyLength() throws WSSecurityException { |
| return derivedKeyLength > 0 ? derivedKeyLength : KeyUtils.getKeyLength(sigAlgo); |
| } |
| |
| public void setDerivedKeyLength(int keyLength) { |
| derivedKeyLength = keyLength; |
| } |
| |
| /** |
| * Set the signature algorithm to use. The default is WSConstants.SHA1. |
| * @param algorithm the signature algorithm to use. |
| */ |
| public void setSignatureAlgorithm(String algorithm) { |
| sigAlgo = algorithm; |
| } |
| |
| /** |
| * @return the signature algorithm to use |
| */ |
| public String getSignatureAlgorithm() { |
| return sigAlgo; |
| } |
| |
| /** |
| * Returns the the value of wsu:Id attribute of the Signature element. |
| * |
| * @return Return the wsu:Id of this token or null if the signature has not been generated. |
| */ |
| public String getSignatureId() { |
| if (sig == null) { |
| return null; |
| } |
| return sig.getId(); |
| } |
| |
| /** |
| * Set the digest algorithm to use. The default is WSConstants.SHA1. |
| * @param algorithm the digest algorithm to use. |
| */ |
| public void setDigestAlgorithm(String algorithm) { |
| digestAlgo = algorithm; |
| } |
| |
| /** |
| * @return the digest algorithm to use |
| */ |
| public String getDigestAlgorithm() { |
| return digestAlgo; |
| } |
| |
| /** |
| * @return Returns the signatureValue. |
| */ |
| public byte[] getSignatureValue() { |
| return signatureValue; |
| } |
| |
| /** |
| * Set the canonicalization method to use. |
| * |
| * If the canonicalization method is not set then the recommended Exclusive |
| * XML Canonicalization is used by default Refer to WSConstants which |
| * algorithms are supported. |
| * |
| * @param algo Is the name of the signature algorithm |
| * @see WSConstants#C14N_OMIT_COMMENTS |
| * @see WSConstants#C14N_WITH_COMMENTS |
| * @see WSConstants#C14N_EXCL_OMIT_COMMENTS |
| * @see WSConstants#C14N_EXCL_WITH_COMMENTS |
| */ |
| public void setSigCanonicalization(String algo) { |
| canonAlgo = algo; |
| } |
| |
| /** |
| * Get the canonicalization method. |
| * |
| * If the canonicalization method was not set then Exclusive XML |
| * Canonicalization is used by default. |
| * |
| * @return The string describing the canonicalization algorithm. |
| */ |
| public String getSigCanonicalization() { |
| return canonAlgo; |
| } |
| |
| public boolean isAddInclusivePrefixes() { |
| return addInclusivePrefixes; |
| } |
| |
| public void setAddInclusivePrefixes(boolean addInclusivePrefixes) { |
| this.addInclusivePrefixes = addInclusivePrefixes; |
| } |
| } |