1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
68
69
70
71
72
73
74
75
76
77
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
125
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154 public void prepare(Document doc, Crypto cr, WSSecHeader secHeader)
155 throws WSSecurityException {
156
157
158
159
160 crypto = cr;
161 document = doc;
162 wsDocInfo = new WSDocInfo(doc);
163 wsDocInfo.setCrypto(cr);
164 securityHeader = secHeader.getSecurityHeader();
165
166
167
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
195
196
197
198
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
342
343
344
345
346
347
348
349
350
351
352
353
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
389
390
391 if (bstToken != null) {
392 prependBSTElementToHeader(secHeader);
393 }
394
395 return doc;
396 }
397
398
399
400
401
402
403
404
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
424
425
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
438
439
440
441
442
443
444
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
455
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
467
468
469
470
471
472
473
474
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
484
485
486
487
488
489
490
491
492
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
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
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
567
568
569
570 public void setUseSingleCertificate(boolean useSingleCert) {
571 this.useSingleCert = useSingleCert;
572 }
573
574
575
576
577
578
579 public boolean isUseSingleCertificate() {
580 return useSingleCert;
581 }
582
583
584
585
586
587
588
589
590
591
592
593
594 public void setSignatureAlgorithm(String algo) {
595 sigAlgo = algo;
596 }
597
598
599
600
601
602
603
604
605
606
607 public String getSignatureAlgorithm() {
608 return sigAlgo;
609 }
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624 public void setSigCanonicalization(String algo) {
625 canonAlgo = algo;
626 }
627
628
629
630
631
632
633
634
635
636 public String getSigCanonicalization() {
637 return canonAlgo;
638 }
639
640
641
642
643 public String getDigestAlgo() {
644 return digestAlgo;
645 }
646
647
648
649
650
651
652
653 public void setDigestAlgo(String digestAlgo) {
654 this.digestAlgo = digestAlgo;
655 }
656
657
658
659
660
661
662
663
664
665
666 public byte[] getSignatureValue() {
667 return signatureValue;
668 }
669
670
671
672
673
674
675
676
677
678 public String getId() {
679 if (sig == null) {
680 return null;
681 }
682 return sig.getId();
683 }
684
685
686
687
688
689
690
691 public String getBSTTokenId() {
692 if (bstToken == null) {
693 return null;
694 }
695 return bstToken.getID();
696 }
697
698
699
700
701
702 public void setSecretKey(byte[] secretKey) {
703 this.secretKey = secretKey;
704 }
705
706
707
708
709
710 public void setCustomTokenValueType(String customTokenValueType) {
711 this.customTokenValueType = customTokenValueType;
712 }
713
714
715
716
717
718 public void setCustomTokenId(String customTokenId) {
719 this.customTokenId = customTokenId;
720 }
721
722
723
724
725
726 public void setEncrKeySha1value(String encrKeySha1value) {
727 this.encrKeySha1value = encrKeySha1value;
728 }
729
730
731
732
733
734 public void setX509Certificate(X509Certificate cer) {
735 this.useThisCert = cer;
736 }
737
738
739
740
741
742
743 public Element getBinarySecurityTokenElement() {
744 if (bstToken != null) {
745 return bstToken.getElement();
746 }
747 return null;
748 }
749
750
751
752
753
754 public String getSecurityTokenReferenceURI() {
755 return strUri;
756 }
757
758
759
760
761 public SecurityTokenReference getSecurityTokenReference() {
762 return secRef;
763 }
764
765
766
767
768
769 public void setSecurityTokenReference(SecurityTokenReference secRef) {
770 useCustomSecRef = true;
771 this.secRef = secRef;
772 }
773
774
775
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
800
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 }