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