View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.ws.security.message;
21  
22  import org.apache.ws.security.WSConstants;
23  import org.apache.ws.security.WSDocInfo;
24  import org.apache.ws.security.WSEncryptionPart;
25  import org.apache.ws.security.WSSConfig;
26  import org.apache.ws.security.WSSecurityException;
27  import org.apache.ws.security.components.crypto.Crypto;
28  import org.apache.ws.security.components.crypto.CryptoType;
29  import org.apache.ws.security.message.token.BinarySecurity;
30  import org.apache.ws.security.message.token.DOMX509Data;
31  import org.apache.ws.security.message.token.DOMX509IssuerSerial;
32  import org.apache.ws.security.message.token.KerberosSecurity;
33  import org.apache.ws.security.message.token.PKIPathSecurity;
34  import org.apache.ws.security.message.token.Reference;
35  import org.apache.ws.security.message.token.SecurityTokenReference;
36  import org.apache.ws.security.message.token.X509Security;
37  import org.apache.ws.security.transform.STRTransform;
38  import org.apache.ws.security.util.Base64;
39  import org.apache.ws.security.util.WSSecurityUtil;
40  
41  import org.w3c.dom.Document;
42  import org.w3c.dom.Element;
43  import org.w3c.dom.Node;
44  
45  import java.security.NoSuchProviderException;
46  import java.security.cert.X509Certificate;
47  import java.util.ArrayList;
48  import java.util.List;
49  
50  import javax.xml.crypto.XMLStructure;
51  import javax.xml.crypto.dom.DOMStructure;
52  import javax.xml.crypto.dsig.CanonicalizationMethod;
53  import javax.xml.crypto.dsig.SignatureMethod;
54  import javax.xml.crypto.dsig.SignedInfo;
55  import javax.xml.crypto.dsig.XMLSignature;
56  import javax.xml.crypto.dsig.XMLSignatureFactory;
57  import javax.xml.crypto.dsig.XMLSignContext;
58  import javax.xml.crypto.dsig.dom.DOMSignContext;
59  import javax.xml.crypto.dsig.keyinfo.KeyInfo;
60  import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
61  import javax.xml.crypto.dsig.keyinfo.KeyValue;
62  import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
63  import javax.xml.crypto.dsig.spec.ExcC14NParameterSpec;
64  
65  
66  /**
67   * Creates a Signature according to WS Specification, X509 profile.
68   * 
69   * This class is a re-factored implementation of the previous WSS4J class
70   * <code>WSSignEnvelope</code>. This new class allows better control of
71   * the process to create a Signature and to add it to the Security header.
72   * 
73   * The flexibility and fine granular control is required to implement a handler
74   * that uses WSSecurityPolicy files to control the setup of a Security header.
75   * 
76   * @author Davanum Srinivas (dims@yahoo.com)
77   * @author Werner Dittmann (werner@apache.org)
78   */
79  public class WSSecSignature extends WSSecSignatureBase {
80  
81      private static org.apache.commons.logging.Log log = 
82          org.apache.commons.logging.LogFactory.getLog(WSSecSignature.class);
83  
84      protected boolean useSingleCert = true;
85      protected String sigAlgo = null;
86      protected String canonAlgo = WSConstants.C14N_EXCL_OMIT_COMMENTS;
87      protected byte[] signatureValue = null;
88      protected Document document = null;
89      protected WSDocInfo wsDocInfo = null;
90      protected String certUri = null;
91      protected String keyInfoUri = null;
92      protected SecurityTokenReference secRef = null;
93      protected String strUri = null;
94      protected BinarySecurity bstToken = null;
95      
96      protected KeyInfoFactory keyInfoFactory;
97      protected XMLSignatureFactory signatureFactory;
98      protected KeyInfo keyInfo;
99      protected CanonicalizationMethod c14nMethod;
100     protected XMLSignature sig;
101     protected byte[] secretKey = null;
102     protected String customTokenValueType;
103     protected String customTokenId;
104     
105     private String encrKeySha1value = null;
106     private Crypto crypto = null;
107     private String digestAlgo = WSConstants.SHA1;
108     private X509Certificate useThisCert = null;
109     private Element securityHeader = null;
110     private boolean useCustomSecRef;
111 
112     public WSSecSignature() {
113         super();
114         init();
115     }
116     
117     public WSSecSignature(WSSConfig config) {
118         super(config);
119         init();
120     }
121     
122     private void init() {
123         // Try to install the Santuario Provider - fall back to the JDK provider if this does
124         // not work
125         try {
126             signatureFactory = XMLSignatureFactory.getInstance("DOM", "ApacheXMLDSig");
127         } catch (NoSuchProviderException ex) {
128             signatureFactory = XMLSignatureFactory.getInstance("DOM");
129         }
130         try {
131             keyInfoFactory = KeyInfoFactory.getInstance("DOM", "ApacheXMLDSig");
132         } catch (NoSuchProviderException ex) {
133             keyInfoFactory = KeyInfoFactory.getInstance("DOM");
134         }
135     }
136    
137     /**
138      * Initialize a WSSec Signature.
139      * 
140      * The method sets up and initializes a WSSec Signature structure after the
141      * relevant information was set. After setup of the references to elements
142      * to sign may be added. After all references are added they can be signed.
143      * 
144      * This method does not add the Signature element to the security header.
145      * See <code>prependSignatureElementToHeader()</code> method.
146      * 
147      * @param doc The SOAP envelope as <code>Document</code>
148      * @param cr An instance of the Crypto API to handle keystore and certificates
149      * @param secHeader The security header that will hold the Signature. This is used
150      *                   to construct namespace prefixes for Signature. This method
151      * @throws WSSecurityException
152      */
153     public void prepare(Document doc, Crypto cr, WSSecHeader secHeader)
154         throws WSSecurityException {
155         //
156         // Gather some info about the document to process and store it for
157         // retrieval
158         //
159         crypto = cr;
160         document = doc;
161         wsDocInfo = new WSDocInfo(doc);
162         wsDocInfo.setCrypto(cr);
163         securityHeader = secHeader.getSecurityHeader();
164         
165         //
166         // At first get the security token (certificate) according to the parameters.
167         //
168         X509Certificate[] certs = getSigningCerts();
169 
170         try {
171             C14NMethodParameterSpec c14nSpec = null;
172             if (getWsConfig().isWsiBSPCompliant() && canonAlgo.equals(WSConstants.C14N_EXCL_OMIT_COMMENTS)) {
173                 List<String> prefixes = 
174                     getInclusivePrefixes(secHeader.getSecurityHeader(), false);
175                 c14nSpec = new ExcC14NParameterSpec(prefixes);
176             }
177             
178            c14nMethod = signatureFactory.newCanonicalizationMethod(canonAlgo, c14nSpec);
179         } catch (Exception ex) {
180             log.error("", ex);
181             throw new WSSecurityException(
182                 WSSecurityException.FAILED_SIGNATURE, "noXMLSig", null, ex
183             );
184         }
185 
186         keyInfoUri = getWsConfig().getIdAllocator().createSecureId("KI-", keyInfo);
187         if (!useCustomSecRef) {
188             secRef = new SecurityTokenReference(doc);
189             strUri = getWsConfig().getIdAllocator().createSecureId("STR-", secRef);
190             secRef.setID(strUri);
191             
192             //
193             // Get an initialized XMLSignature element.
194             //
195             
196             //
197             // Prepare and setup the token references for this Signature
198             //
199             switch (keyIdentifierType) {
200             case WSConstants.BST_DIRECT_REFERENCE:
201                 Reference ref = new Reference(document);
202                 ref.setURI("#" + certUri);
203                 if (!useSingleCert) {
204                     bstToken = new PKIPathSecurity(document);
205                     ((PKIPathSecurity) bstToken).setX509Certificates(certs, crypto);
206                     secRef.addTokenType(PKIPathSecurity.PKI_TYPE);
207                 } else {
208                     bstToken = new X509Security(document);
209                     ((X509Security) bstToken).setX509Certificate(certs[0]);
210                 }
211                 ref.setValueType(bstToken.getValueType());
212                 secRef.setReference(ref);
213                 bstToken.setID(certUri);
214                 wsDocInfo.addTokenElement(bstToken.getElement(), false);
215                 break;
216     
217             case WSConstants.ISSUER_SERIAL:
218                 String issuer = certs[0].getIssuerX500Principal().getName();
219                 java.math.BigInteger serialNumber = certs[0].getSerialNumber();
220                 DOMX509IssuerSerial domIssuerSerial = 
221                     new DOMX509IssuerSerial(doc, issuer, serialNumber);
222                 DOMX509Data domX509Data = new DOMX509Data(doc, domIssuerSerial);
223                 secRef.setX509Data(domX509Data);
224                 break;
225     
226             case WSConstants.X509_KEY_IDENTIFIER:
227                 secRef.setKeyIdentifier(certs[0]);
228                 break;
229     
230             case WSConstants.SKI_KEY_IDENTIFIER:
231                 secRef.setKeyIdentifierSKI(certs[0], crypto);
232                 break;
233     
234             case WSConstants.THUMBPRINT_IDENTIFIER:
235                 secRef.setKeyIdentifierThumb(certs[0]);
236                 break;
237                 
238             case WSConstants.ENCRYPTED_KEY_SHA1_IDENTIFIER:
239                 if (encrKeySha1value != null) {
240                     secRef.setKeyIdentifierEncKeySHA1(encrKeySha1value);
241                 } else {
242                     byte[] digestBytes = WSSecurityUtil.generateDigest(secretKey);
243                     secRef.setKeyIdentifierEncKeySHA1(Base64.encode(digestBytes));
244                 }
245                 secRef.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
246                 break;
247     
248             case WSConstants.CUSTOM_SYMM_SIGNING :
249                 Reference refCust = new Reference(document);
250                 if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customTokenValueType)) {
251                     secRef.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
252                     refCust.setValueType(customTokenValueType);
253                 } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customTokenValueType)) {
254                     secRef.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
255                 } else if (WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(customTokenValueType)) {
256                     secRef.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
257                     refCust.setValueType(customTokenValueType);
258                 } else if (KerberosSecurity.isKerberosToken(customTokenValueType)) {
259                     secRef.addTokenType(customTokenValueType);
260                     refCust.setValueType(customTokenValueType);
261                 } else {
262                     refCust.setValueType(customTokenValueType);
263                 }
264                 refCust.setURI("#" + customTokenId);
265                 secRef.setReference(refCust);
266                 break;
267     
268             case WSConstants.CUSTOM_SYMM_SIGNING_DIRECT :
269                 Reference refCustd = new Reference(document);
270                 if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customTokenValueType)) {
271                     secRef.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
272                     refCustd.setValueType(customTokenValueType);
273                 } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customTokenValueType)) {
274                     secRef.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
275                 } else if (WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(customTokenValueType)) {
276                     secRef.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
277                     refCustd.setValueType(customTokenValueType);
278                 } else if (KerberosSecurity.isKerberosToken(customTokenValueType)) {
279                     secRef.addTokenType(customTokenValueType);
280                     refCustd.setValueType(customTokenValueType);
281                 } else {
282                     refCustd.setValueType(customTokenValueType);
283                 }
284                 refCustd.setURI(customTokenId);
285                 secRef.setReference(refCustd);
286                 break;
287                 
288             case WSConstants.CUSTOM_KEY_IDENTIFIER:
289                 if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customTokenValueType)) {
290                     secRef.setKeyIdentifier(customTokenValueType, customTokenId);
291                     secRef.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
292                 } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customTokenValueType)) {
293                     secRef.setKeyIdentifier(customTokenValueType, customTokenId);
294                     secRef.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
295                 } else if (WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(customTokenValueType)) {
296                     secRef.setKeyIdentifier(customTokenValueType, customTokenId, true);
297                     secRef.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
298                 } else if (SecurityTokenReference.ENC_KEY_SHA1_URI.equals(customTokenValueType)) {
299                     secRef.setKeyIdentifier(customTokenValueType, customTokenId, true);
300                     secRef.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
301                 } else if (WSConstants.WSS_KRB_KI_VALUE_TYPE.equals(customTokenValueType)) {
302                     secRef.setKeyIdentifier(customTokenValueType, customTokenId, true);
303                     secRef.addTokenType(WSConstants.WSS_GSS_KRB_V5_AP_REQ);
304                 } 
305                 break;
306                 
307             case WSConstants.KEY_VALUE:
308                 java.security.PublicKey publicKey = certs[0].getPublicKey();
309                 
310                 try {
311                     KeyValue keyValue = keyInfoFactory.newKeyValue(publicKey);
312                     keyInfo = 
313                         keyInfoFactory.newKeyInfo(
314                             java.util.Collections.singletonList(keyValue), keyInfoUri
315                         );
316                 } catch (java.security.KeyException ex) {
317                     log.error("", ex);
318                     throw new WSSecurityException(
319                         WSSecurityException.FAILED_SIGNATURE, "noXMLSig", null, ex
320                     );
321                 }
322                 break;
323             default:
324                 throw new WSSecurityException(WSSecurityException.FAILURE, "unsupportedKeyId");
325             }
326         }
327         
328         if (keyIdentifierType != WSConstants.KEY_VALUE) {
329             XMLStructure structure = new DOMStructure(secRef.getElement());
330             wsDocInfo.addTokenElement(secRef.getElement(), false);
331             keyInfo = 
332                 keyInfoFactory.newKeyInfo(
333                     java.util.Collections.singletonList(structure), keyInfoUri
334                 );
335         }
336     }
337     
338     
339     /**
340      * Builds a signed soap envelope.
341      * 
342      * This is a convenience method and for backward compatibility. The method
343      * creates a Signature and puts it into the Security header. It does so by
344      * calling the single functions in order to perform a <i>one shot signature</i>.
345      * This method is compatible with the build method of the previous version
346      * with the exception of the additional WSSecHeader parameter.
347      * 
348      * @param doc The unsigned SOAP envelope as <code>Document</code>
349      * @param cr An instance of the Crypto API to handle keystore and certificates
350      * @param secHeader the security header element to hold the encrypted key element.
351      * @return A signed SOAP envelope as <code>Document</code>
352      * @throws WSSecurityException
353      */
354     public Document build(Document doc, Crypto cr, WSSecHeader secHeader)
355         throws WSSecurityException {
356         doDebug = log.isDebugEnabled();
357 
358         if (doDebug) {
359             log.debug("Beginning signing...");
360         }
361 
362         prepare(doc, cr, secHeader);
363         if (parts == null) {
364             parts = new ArrayList<WSEncryptionPart>(1);
365             String soapNamespace = WSSecurityUtil.getSOAPNamespace(doc.getDocumentElement());
366             WSEncryptionPart encP = 
367                 new WSEncryptionPart(
368                     WSConstants.ELEM_BODY, 
369                     soapNamespace, 
370                     "Content"
371                 );
372             parts.add(encP);
373         } else {
374             for (WSEncryptionPart part : parts) {
375                 if ("STRTransform".equals(part.getName()) && part.getId() == null) {
376                     part.setId(strUri);
377                 }
378             }
379         }
380 
381         List<javax.xml.crypto.dsig.Reference> referenceList = 
382             addReferencesToSign(parts, secHeader);
383 
384         computeSignature(referenceList);
385         
386         //
387         // if we have a BST prepend it in front of the Signature according to
388         // strict layout rules.
389         //
390         if (bstToken != null) {
391             prependBSTElementToHeader(secHeader);
392         }
393 
394         return doc;
395     }
396     
397     
398     /**
399      * This method adds references to the Signature.
400      * 
401      * @param references The list of references to sign
402      * @param secHeader The Security Header
403      * @throws WSSecurityException
404      */
405     public List<javax.xml.crypto.dsig.Reference> addReferencesToSign(
406         List<WSEncryptionPart> references, 
407         WSSecHeader secHeader
408     ) throws WSSecurityException {
409         return 
410             addReferencesToSign(
411                 document, 
412                 references,
413                 wsDocInfo,
414                 signatureFactory, 
415                 secHeader, 
416                 getWsConfig(), 
417                 digestAlgo
418             );
419     }
420 
421     /**
422      * Returns the SignatureElement.
423      * The method can be called any time after <code>prepare()</code>.
424      * @return The DOM Element of the signature.
425      */
426     public Element getSignatureElement() {
427         return
428             WSSecurityUtil.getDirectChildElement(
429                 securityHeader,
430                 WSConstants.SIG_LN,
431                 WSConstants.SIG_NS
432             );
433     }
434     
435     /**
436      * Prepend the BinarySecurityToken to the elements already in the Security
437      * header.
438      * 
439      * The method can be called any time after <code>prepare()</code>.
440      * This allows to insert the BST element at any position in the Security
441      * header.
442      * 
443      * @param secHeader The security header
444      */
445     public void prependBSTElementToHeader(WSSecHeader secHeader) {
446         if (bstToken != null) {
447             WSSecurityUtil.prependChildElement(secHeader.getSecurityHeader(), bstToken.getElement());
448         }
449         bstToken = null;
450     }
451 
452     /**
453      * Append the BinarySecurityToken to the security header. 
454      * @param secHeader The security header
455      */
456     public void appendBSTElementToHeader(WSSecHeader secHeader) {
457         if (bstToken != null) {
458             Element secHeaderElement = secHeader.getSecurityHeader();
459             secHeaderElement.appendChild(bstToken.getElement());
460         }
461         bstToken = null;
462     }
463     
464     /**
465      * Compute the Signature over the references. The signature element will be 
466      * prepended to the security header.
467      * 
468      * This method can be called any time after the references were set. See
469      * <code>addReferencesToSign()</code>.
470      * 
471      * @param referenceList The list of references to sign
472      * 
473      * @throws WSSecurityException
474      */
475     public void computeSignature(
476         List<javax.xml.crypto.dsig.Reference> referenceList 
477     ) throws WSSecurityException {
478         computeSignature(referenceList, true, null);
479     }
480     
481     /**
482      * Compute the Signature over the references.
483      * 
484      * This method can be called any time after the references were set. See
485      * <code>addReferencesToSign()</code>.
486      * 
487      * @param referenceList The list of references to sign
488      * @param prepend Whether to prepend the signature element to the security header
489      * @param siblingElement If prepending, then prepend before this sibling Element
490      * 
491      * @throws WSSecurityException
492      */
493     public void computeSignature(
494         List<javax.xml.crypto.dsig.Reference> referenceList, 
495         boolean prepend,
496         Element siblingElement
497     ) throws WSSecurityException {
498         try {
499             java.security.Key key;
500             if (secretKey == null) {
501                 key = crypto.getPrivateKey(user, password);
502             } else {
503                 key = WSSecurityUtil.prepareSecretKey(sigAlgo, secretKey);
504             }
505             SignatureMethod signatureMethod = 
506                 signatureFactory.newSignatureMethod(sigAlgo, null);
507             SignedInfo signedInfo = 
508                 signatureFactory.newSignedInfo(c14nMethod, signatureMethod, referenceList);
509             
510             sig = signatureFactory.newXMLSignature(
511                     signedInfo, 
512                     keyInfo,
513                     null,
514                     getWsConfig().getIdAllocator().createId("SIG-", null),
515                     null);
516             
517             //
518             // Figure out where to insert the signature element
519             //
520             XMLSignContext signContext = null;
521             if (prepend) {
522                 if (siblingElement == null) {
523                     Node child = securityHeader.getFirstChild();
524                     while (child != null && child.getNodeType() != Node.ELEMENT_NODE) {
525                         child = child.getNextSibling();
526                     } 
527                     siblingElement = (Element)child;
528                 }
529                 if (siblingElement == null) {
530                     signContext = new DOMSignContext(key, securityHeader);
531                 } else {
532                     signContext = new DOMSignContext(key, securityHeader, siblingElement);
533                 }
534             } else {
535                 signContext = new DOMSignContext(key, securityHeader);
536             }
537             
538             signContext.putNamespacePrefix(WSConstants.SIG_NS, WSConstants.SIG_PREFIX);
539             if (WSConstants.C14N_EXCL_OMIT_COMMENTS.equals(canonAlgo)) {
540                 signContext.putNamespacePrefix(
541                     WSConstants.C14N_EXCL_OMIT_COMMENTS, 
542                     WSConstants.C14N_EXCL_OMIT_COMMENTS_PREFIX
543                 );
544             }
545             signContext.setProperty(STRTransform.TRANSFORM_WS_DOC_INFO, wsDocInfo);
546             wsDocInfo.setCallbackLookup(callbackLookup);
547             
548             // Add the elements to sign to the Signature Context
549             wsDocInfo.setTokensOnContext((DOMSignContext)signContext);
550             if (secRef != null && secRef.getElement() != null) {
551                 WSSecurityUtil.storeElementInContext((DOMSignContext)signContext, secRef.getElement());
552             }
553             sig.sign(signContext);
554             
555             signatureValue = sig.getSignatureValue().getValue();
556         } catch (Exception ex) {
557             log.error(ex);
558             throw new WSSecurityException(
559                 WSSecurityException.FAILED_SIGNATURE, null, null, ex
560             );
561         }
562     }
563     
564     /**
565      * Set the single cert flag.
566      * 
567      * @param useSingleCert
568      */
569     public void setUseSingleCertificate(boolean useSingleCert) {
570         this.useSingleCert = useSingleCert;
571     }
572 
573     /**
574      * Get the single cert flag.
575      * 
576      * @return A boolean if single certificate is set.
577      */
578     public boolean isUseSingleCertificate() {
579         return useSingleCert;
580     }
581 
582     /**
583      * Set the name (uri) of the signature encryption algorithm to use.
584      * 
585      * If the algorithm is not set then an automatic detection of the signature
586      * algorithm to use is performed during the <code>prepare()</code>
587      * method. Refer to WSConstants which algorithms are supported.
588      * 
589      * @param algo the name of the signature algorithm
590      * @see WSConstants#RSA
591      * @see WSConstants#DSA
592      */
593     public void setSignatureAlgorithm(String algo) {
594         sigAlgo = algo;
595     }
596 
597     /**
598      * Get the name (uri) of the signature algorithm that is being used.
599      * 
600      * Call this method after <code>prepare</code> to get the information
601      * which signature algorithm was automatically detected if no signature
602      * algorithm was preset.
603      * 
604      * @return the identifier URI of the signature algorithm
605      */
606     public String getSignatureAlgorithm() {
607         return sigAlgo;
608     }
609 
610     /**
611      * Set the canonicalization method to use.
612      * 
613      * If the canonicalization method is not set then the recommended Exclusive
614      * XML Canonicalization is used by default. Refer to WSConstants which
615      * algorithms are supported.
616      * 
617      * @param algo Is the name of the signature algorithm
618      * @see WSConstants#C14N_OMIT_COMMENTS
619      * @see WSConstants#C14N_WITH_COMMENTS
620      * @see WSConstants#C14N_EXCL_OMIT_COMMENTS
621      * @see WSConstants#C14N_EXCL_WITH_COMMENTS
622      */
623     public void setSigCanonicalization(String algo) {
624         canonAlgo = algo;
625     }
626 
627     /**
628      * Get the canonicalization method.
629      * 
630      * If the canonicalization method was not set then Exclusive XML
631      * Canonicalization is used by default.
632      * 
633      * @return The string describing the canonicalization algorithm.
634      */
635     public String getSigCanonicalization() {
636         return canonAlgo;
637     }
638 
639     /**
640      * @return the digest algorithm to use
641      */
642     public String getDigestAlgo() {
643         return digestAlgo;
644     }
645 
646     /**
647      * Set the string that defines which digest algorithm to use. 
648      * The default is Constants.ALGO_ID_DIGEST_SHA1.
649      * 
650      * @param digestAlgo the digestAlgo to set
651      */
652     public void setDigestAlgo(String digestAlgo) {
653         this.digestAlgo = digestAlgo;
654     }
655     
656     
657     /**
658      * Returns the computed Signature value.
659      * 
660      * Call this method after <code>computeSignature()</code> or <code>build()</code>
661      * methods were called.
662      * 
663      * @return Returns the signatureValue.
664      */
665     public byte[] getSignatureValue() {
666         return signatureValue;
667     }
668 
669     /**
670      * Get the id generated during <code>prepare()</code>.
671      * 
672      * Returns the the value of wsu:Id attribute of the Signature element.
673      * 
674      * @return Return the wsu:Id of this token or null if <code>prepare()</code>
675      *         was not called before.
676      */
677     public String getId() {
678         if (sig == null) {
679             return null;
680         }
681         return sig.getId();
682     }
683     
684     /**
685      * Get the id of the BST generated  during <code>prepare()</code>.
686      * 
687      * @return Returns the the value of wsu:Id attribute of the 
688      * BinaruSecurityToken element.
689      */
690     public String getBSTTokenId() {
691         if (bstToken == null) {
692             return null;
693         }
694         return bstToken.getID();
695     }
696     
697     /**
698      * Set the secret key to use
699      * @param secretKey the secret key to use
700      */
701     public void setSecretKey(byte[] secretKey) {
702         this.secretKey = secretKey;
703     }
704 
705     /**
706      * Set the custom token value type to use
707      * @param customTokenValueType the custom token value type to use
708      */
709     public void setCustomTokenValueType(String customTokenValueType) {
710         this.customTokenValueType = customTokenValueType;
711     }
712 
713     /**
714      * Set the custom token id
715      * @param customTokenId the custom token id
716      */
717     public void setCustomTokenId(String customTokenId) {
718         this.customTokenId = customTokenId;
719     }
720 
721     /**
722      * Set the encrypted key sha1 value
723      * @param encrKeySha1value the encrypted key sha1 value
724      */
725     public void setEncrKeySha1value(String encrKeySha1value) {
726         this.encrKeySha1value = encrKeySha1value;
727     }
728     
729     /**
730      * Set the X509 Certificate to use
731      * @param cer the X509 Certificate to use
732      */
733     public void setX509Certificate(X509Certificate cer) {
734         this.useThisCert = cer;
735     }
736     
737     /**
738      * Returns the BST Token element.
739      * The method can be called any time after <code>prepare()</code>.
740      * @return the BST Token element
741      */
742     public Element getBinarySecurityTokenElement() {
743         if (bstToken != null) {
744             return bstToken.getElement();
745         }
746         return null;
747     }
748     
749     /**
750      * @return the URI associated with the SecurityTokenReference
751      * (must be called after {@link #prepare(Document, Crypto, WSSecHeader)}
752      */
753     public String getSecurityTokenReferenceURI() {
754         return strUri;
755     }
756     
757     /**
758      * Get the SecurityTokenReference to be used in the KeyInfo element.
759      */
760     public SecurityTokenReference getSecurityTokenReference() {
761         return secRef;
762     }
763     
764     /**
765      * Set the SecurityTokenReference to be used in the KeyInfo element. If this
766      * method is not called, a SecurityTokenRefence will be generated.
767      */
768     public void setSecurityTokenReference(SecurityTokenReference secRef) {
769         useCustomSecRef = true;
770         this.secRef = secRef;
771     }
772 
773     /**
774      * Set up the X509 Certificate(s) for signing.
775      */
776     private X509Certificate[] getSigningCerts() throws WSSecurityException {
777         X509Certificate[] certs = null;
778         if (!(keyIdentifierType == WSConstants.CUSTOM_SYMM_SIGNING
779             || keyIdentifierType == WSConstants.CUSTOM_SYMM_SIGNING_DIRECT
780             || keyIdentifierType == WSConstants.ENCRYPTED_KEY_SHA1_IDENTIFIER
781             || keyIdentifierType == WSConstants.CUSTOM_KEY_IDENTIFIER)) {
782             if (useThisCert == null) {
783                 CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
784                 cryptoType.setAlias(user);
785                 certs = crypto.getX509Certificates(cryptoType);
786             } else {
787                 certs = new X509Certificate[] {useThisCert};
788             }
789             if (certs == null || certs.length <= 0) {
790                 throw new WSSecurityException(
791                         WSSecurityException.FAILURE,
792                         "noUserCertsFound", 
793                         new Object[] { user, "signature" }
794                 );
795             }
796             certUri = getWsConfig().getIdAllocator().createSecureId("X509-", certs[0]);  
797             //
798             // If no signature algorithm was set try to detect it according to the
799             // data stored in the certificate.
800             //
801             if (sigAlgo == null) {
802                 String pubKeyAlgo = certs[0].getPublicKey().getAlgorithm();
803                 log.debug("Automatic signature algorithm detection: " + pubKeyAlgo);
804                 if (pubKeyAlgo.equalsIgnoreCase("DSA")) {
805                     sigAlgo = WSConstants.DSA;
806                 } else if (pubKeyAlgo.equalsIgnoreCase("RSA")) {
807                     sigAlgo = WSConstants.RSA;
808                 } else {
809                     throw new WSSecurityException(
810                         WSSecurityException.FAILURE,
811                         "unknownSignatureAlgorithm",
812                         new Object[] {pubKeyAlgo}
813                     );
814                 }
815             }
816         }
817         return certs;
818     }
819     
820 }