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