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.WSEncryptionPart;
24 import org.apache.ws.security.WSSConfig;
25 import org.apache.ws.security.WSSecurityException;
26 import org.apache.ws.security.components.crypto.Crypto;
27 import org.apache.ws.security.components.crypto.CryptoType;
28 import org.apache.ws.security.message.token.KerberosSecurity;
29 import org.apache.ws.security.message.token.Reference;
30 import org.apache.ws.security.message.token.SecurityTokenReference;
31 import org.apache.ws.security.util.Base64;
32 import org.apache.ws.security.util.WSSecurityUtil;
33 import org.apache.xml.security.encryption.EncryptedData;
34 import org.apache.xml.security.encryption.XMLCipher;
35 import org.apache.xml.security.encryption.XMLEncryptionException;
36 import org.apache.xml.security.keys.KeyInfo;
37 import org.w3c.dom.Attr;
38 import org.w3c.dom.Document;
39 import org.w3c.dom.Element;
40 import org.w3c.dom.NamedNodeMap;
41 import org.w3c.dom.Node;
42
43 import javax.crypto.KeyGenerator;
44 import javax.crypto.SecretKey;
45
46 import java.security.cert.X509Certificate;
47 import java.util.ArrayList;
48 import java.util.List;
49
50
51
52
53
54
55
56
57 public class WSSecEncrypt extends WSSecEncryptedKey {
58 private static org.apache.commons.logging.Log log =
59 org.apache.commons.logging.LogFactory.getLog(WSSecEncrypt.class);
60
61 protected byte[] embeddedKey = null;
62
63 protected String embeddedKeyName = null;
64
65
66
67
68 protected SecurityTokenReference securityTokenReference = null;
69
70
71
72
73
74 private boolean encryptSymmKey = true;
75
76
77
78
79 private String customReferenceValue;
80
81
82
83
84 private boolean encKeyIdDirectId;
85
86 private boolean embedEncryptedKey;
87
88 public WSSecEncrypt() {
89 super();
90 }
91
92 public WSSecEncrypt(WSSConfig config) {
93 super(config);
94 }
95
96
97
98
99
100
101
102 public void setKey(byte[] key) {
103 embeddedKey = key;
104 }
105
106
107
108
109
110
111
112
113
114
115 public void setKeyEnc(String keyEnc) {
116 keyEncAlgo = keyEnc;
117 }
118
119
120
121
122
123
124 public void setEmbeddedKeyName(String embeddedKeyName) {
125 this.embeddedKeyName = embeddedKeyName;
126 }
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143 public void prepare(Document doc, Crypto crypto) throws WSSecurityException {
144 document = doc;
145
146
147
148
149
150
151 if (ephemeralKey == null) {
152 if (symmetricKey == null) {
153 KeyGenerator keyGen = getKeyGenerator();
154 symmetricKey = keyGen.generateKey();
155 }
156 ephemeralKey = symmetricKey.getEncoded();
157 }
158
159 if (symmetricKey == null) {
160 symmetricKey = WSSecurityUtil.prepareSecretKey(symEncAlgo, ephemeralKey);
161 }
162
163
164
165
166
167 if (encryptSymmKey) {
168 X509Certificate remoteCert = useThisCert;
169 if (remoteCert == null) {
170 CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
171 cryptoType.setAlias(user);
172 X509Certificate[] certs = crypto.getX509Certificates(cryptoType);
173 if (certs == null || certs.length <= 0) {
174 throw new WSSecurityException(
175 WSSecurityException.FAILURE,
176 "noUserCertsFound",
177 new Object[] { user, "encryption" }
178 );
179 }
180 remoteCert = certs[0];
181 }
182 prepareInternal(symmetricKey, remoteCert, crypto);
183 } else {
184 encryptedEphemeralKey = ephemeralKey;
185 }
186 }
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204 public Document build(Document doc, Crypto crypto, WSSecHeader secHeader)
205 throws WSSecurityException {
206 doDebug = log.isDebugEnabled();
207
208 if (keyIdentifierType == WSConstants.EMBEDDED_KEYNAME
209 || keyIdentifierType == WSConstants.EMBED_SECURITY_TOKEN_REF) {
210 encryptSymmKey = false;
211 document = doc;
212
213
214
215
216 if (symmetricKey == null) {
217 if (embeddedKey == null) {
218 throw new WSSecurityException(WSSecurityException.FAILURE, "noKeySupplied");
219 }
220 symmetricKey = WSSecurityUtil.prepareSecretKey(symEncAlgo, embeddedKey);
221 }
222 } else {
223 prepare(doc, crypto);
224 }
225
226 if (envelope == null) {
227 envelope = document.getDocumentElement();
228 }
229
230 if (parts == null) {
231 parts = new ArrayList<WSEncryptionPart>(1);
232 String soapNamespace = WSSecurityUtil.getSOAPNamespace(envelope);
233 WSEncryptionPart encP =
234 new WSEncryptionPart(
235 WSConstants.ELEM_BODY,
236 soapNamespace,
237 "Content"
238 );
239 parts.add(encP);
240 }
241
242 if (doDebug) {
243 log.debug("Beginning Encryption...");
244 }
245
246 Element refs = encryptForRef(null, parts);
247 if (encryptedKeyElement != null) {
248 addInternalRefElement(refs);
249 prependToHeader(secHeader);
250 } else {
251 addExternalRefElement(refs, secHeader);
252 }
253
254 if (bstToken != null) {
255 prependBSTElementToHeader(secHeader);
256 }
257
258 log.debug("Encryption complete.");
259 return doc;
260 }
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283 public Element encryptForRef(
284 Element dataRef,
285 List<WSEncryptionPart> references
286 ) throws WSSecurityException {
287
288 KeyInfo keyInfo = createKeyInfo();
289 List<String> encDataRefs =
290 doEncryption(
291 document, getWsConfig(), keyInfo, symmetricKey, symEncAlgo, references, callbackLookup
292 );
293 if (dataRef == null) {
294 dataRef =
295 document.createElementNS(
296 WSConstants.ENC_NS,
297 WSConstants.ENC_PREFIX + ":ReferenceList"
298 );
299
300
301
302
303 if (!encryptSymmKey) {
304 WSSecurityUtil.setNamespace(
305 dataRef, WSConstants.ENC_NS, WSConstants.ENC_PREFIX
306 );
307 }
308 }
309 return createDataRefList(document, dataRef, encDataRefs);
310 }
311
312
313
314
315 public Element encryptForInternalRef(Element dataRef, List<WSEncryptionPart> references)
316 throws WSSecurityException {
317 return encryptForRef(dataRef, references);
318 }
319
320
321
322
323 public Element encryptForExternalRef(Element dataRef, List<WSEncryptionPart> references)
324 throws WSSecurityException {
325 return encryptForRef(dataRef, references);
326 }
327
328
329
330
331
332
333
334
335
336
337 public void addInternalRefElement(Element dataRef) {
338 encryptedKeyElement.appendChild(dataRef);
339 }
340
341
342
343
344
345
346
347
348
349
350
351 public void addExternalRefElement(Element dataRef, WSSecHeader secHeader) {
352 WSSecurityUtil.prependChildElement(secHeader.getSecurityHeader(), dataRef);
353 }
354
355
356
357
358
359
360
361
362
363
364
365
366 public static List<String> doEncryption(
367 Document doc,
368 WSSConfig config,
369 KeyInfo keyInfo,
370 SecretKey secretKey,
371 String encryptionAlgorithm,
372 List<WSEncryptionPart> references,
373 CallbackLookup callbackLookup
374 ) throws WSSecurityException {
375
376 XMLCipher xmlCipher = null;
377 try {
378 xmlCipher = XMLCipher.getInstance(encryptionAlgorithm);
379 } catch (XMLEncryptionException ex) {
380 throw new WSSecurityException(
381 WSSecurityException.UNSUPPORTED_ALGORITHM, null, null, ex
382 );
383 }
384
385 List<String> encDataRef = new ArrayList<String>();
386 for (int part = 0; part < references.size(); part++) {
387 WSEncryptionPart encPart = references.get(part);
388
389
390
391 if (callbackLookup == null) {
392 callbackLookup = new DOMCallbackLookup(doc);
393 }
394 List<Element> elementsToEncrypt =
395 WSSecurityUtil.findElements(encPart, callbackLookup, doc);
396 if (elementsToEncrypt == null || elementsToEncrypt.size() == 0) {
397 throw new WSSecurityException(
398 WSSecurityException.FAILURE,
399 "noEncElement",
400 new Object[] {"{" + encPart.getNamespace() + "}" + encPart.getName()}
401 );
402 }
403
404 String modifier = encPart.getEncModifier();
405 for (Element elementToEncrypt : elementsToEncrypt) {
406 String id =
407 encryptElement(doc, elementToEncrypt, modifier, config, xmlCipher,
408 secretKey, keyInfo);
409 encPart.setEncId(id);
410 encDataRef.add("#" + id);
411 }
412
413 if (part != (references.size() - 1)) {
414 try {
415 keyInfo = new KeyInfo((Element) keyInfo.getElement().cloneNode(true), null);
416 } catch (Exception ex) {
417 throw new WSSecurityException(
418 WSSecurityException.FAILED_ENCRYPTION, null, null, ex
419 );
420 }
421 }
422 }
423 return encDataRef;
424 }
425
426
427
428
429 private static String encryptElement(
430 Document doc,
431 Element elementToEncrypt,
432 String modifier,
433 WSSConfig config,
434 XMLCipher xmlCipher,
435 SecretKey secretKey,
436 KeyInfo keyInfo
437 ) throws WSSecurityException {
438
439 boolean content = "Content".equals(modifier) ? true : false;
440
441
442
443 String xencEncryptedDataId =
444 config.getIdAllocator().createId("ED-", elementToEncrypt);
445 try {
446 String headerId = "";
447 if ("Header".equals(modifier)) {
448 Element elem =
449 doc.createElementNS(
450 WSConstants.WSSE11_NS, "wsse11:" + WSConstants.ENCRYPTED_HEADER
451 );
452 WSSecurityUtil.setNamespace(elem, WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX);
453 String wsuPrefix =
454 WSSecurityUtil.setNamespace(elem, WSConstants.WSU_NS, WSConstants.WSU_PREFIX);
455 headerId = config.getIdAllocator().createId("EH-", elementToEncrypt);
456 elem.setAttributeNS(
457 WSConstants.WSU_NS, wsuPrefix + ":Id", headerId
458 );
459
460
461
462
463
464 Node parent = elementToEncrypt.getParentNode();
465 elementToEncrypt = (Element)parent.replaceChild(elem, elementToEncrypt);
466 elem.appendChild(elementToEncrypt);
467
468 NamedNodeMap map = elementToEncrypt.getAttributes();
469 for (int i = 0; i < map.getLength(); i++) {
470 Attr attr = (Attr)map.item(i);
471 if (attr.getNamespaceURI().equals(WSConstants.URI_SOAP11_ENV)
472 || attr.getNamespaceURI().equals(WSConstants.URI_SOAP12_ENV)) {
473 String soapEnvPrefix =
474 WSSecurityUtil.setNamespace(
475 elem, attr.getNamespaceURI(), WSConstants.DEFAULT_SOAP_PREFIX
476 );
477 elem.setAttributeNS(
478 attr.getNamespaceURI(),
479 soapEnvPrefix + ":" + attr.getLocalName(),
480 attr.getValue()
481 );
482 }
483 }
484 }
485
486 xmlCipher.init(XMLCipher.ENCRYPT_MODE, secretKey);
487 EncryptedData encData = xmlCipher.getEncryptedData();
488 encData.setId(xencEncryptedDataId);
489 encData.setKeyInfo(keyInfo);
490 xmlCipher.doFinal(doc, elementToEncrypt, content);
491 return xencEncryptedDataId;
492 } catch (Exception ex) {
493 throw new WSSecurityException(
494 WSSecurityException.FAILED_ENCRYPTION, null, null, ex
495 );
496 }
497 }
498
499
500
501
502 private KeyInfo createKeyInfo() throws WSSecurityException {
503
504 KeyInfo keyInfo = new KeyInfo(document);
505 if (embedEncryptedKey) {
506 keyInfo.addUnknownElement(getEncryptedKeyElement());
507 } else if (keyIdentifierType == WSConstants.ENCRYPTED_KEY_SHA1_IDENTIFIER) {
508 SecurityTokenReference secToken = new SecurityTokenReference(document);
509 secToken.addWSSENamespace();
510 if (customReferenceValue != null) {
511 secToken.setKeyIdentifierEncKeySHA1(customReferenceValue);
512 } else {
513 byte[] encodedBytes = WSSecurityUtil.generateDigest(encryptedEphemeralKey);
514 secToken.setKeyIdentifierEncKeySHA1(Base64.encode(encodedBytes));
515 }
516 secToken.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
517 keyInfo.addUnknownElement(secToken.getElement());
518 } else if (keyIdentifierType == WSConstants.EMBEDDED_KEYNAME) {
519 keyInfo.addKeyName(embeddedKeyName == null ? user : embeddedKeyName);
520 } else if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customReferenceValue)) {
521 SecurityTokenReference secToken = new SecurityTokenReference(document);
522 secToken.addWSSENamespace();
523 secToken.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
524 secToken.setKeyIdentifier(WSConstants.WSS_SAML_KI_VALUE_TYPE, encKeyId);
525 keyInfo.addUnknownElement(secToken.getElement());
526 } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customReferenceValue)) {
527 SecurityTokenReference secToken = new SecurityTokenReference(document);
528 secToken.addWSSENamespace();
529 secToken.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
530 secToken.setKeyIdentifier(WSConstants.WSS_SAML2_KI_VALUE_TYPE, encKeyId);
531 keyInfo.addUnknownElement(secToken.getElement());
532 } else if (WSConstants.WSS_KRB_KI_VALUE_TYPE.equals(customReferenceValue)) {
533 SecurityTokenReference secToken = new SecurityTokenReference(document);
534 secToken.addWSSENamespace();
535 secToken.addTokenType(WSConstants.WSS_GSS_KRB_V5_AP_REQ);
536 secToken.setKeyIdentifier(customReferenceValue, encKeyId, true);
537 keyInfo.addUnknownElement(secToken.getElement());
538 } else if (securityTokenReference != null) {
539 Element tmpE = securityTokenReference.getElement();
540 tmpE.setAttributeNS(
541 WSConstants.XMLNS_NS, "xmlns:" + tmpE.getPrefix(), tmpE.getNamespaceURI()
542 );
543 keyInfo.addUnknownElement(securityTokenReference.getElement());
544 } else {
545 SecurityTokenReference secToken = new SecurityTokenReference(document);
546 secToken.addWSSENamespace();
547 Reference ref = new Reference(document);
548 if (encKeyIdDirectId) {
549 ref.setURI(encKeyId);
550 } else {
551 ref.setURI("#" + encKeyId);
552 }
553 if (customReferenceValue != null) {
554 ref.setValueType(customReferenceValue);
555 }
556 secToken.setReference(ref);
557 if (KerberosSecurity.isKerberosToken(customReferenceValue)) {
558 secToken.addTokenType(customReferenceValue);
559 } else if (!WSConstants.WSS_USERNAME_TOKEN_VALUE_TYPE.equals(customReferenceValue)) {
560 secToken.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
561 }
562 keyInfo.addUnknownElement(secToken.getElement());
563 }
564 Element keyInfoElement = keyInfo.getElement();
565 keyInfoElement.setAttributeNS(
566 WSConstants.XMLNS_NS, "xmlns:" + WSConstants.SIG_PREFIX, WSConstants.SIG_NS
567 );
568
569 return keyInfo;
570 }
571
572
573
574
575
576
577
578
579
580 public static Element createDataRefList(
581 Document doc,
582 Element referenceList,
583 List<String> encDataRefs
584 ) {
585 for (String dataReferenceUri : encDataRefs) {
586 Element dataReference =
587 doc.createElementNS(
588 WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":DataReference"
589 );
590 dataReference.setAttributeNS(null, "URI", dataReferenceUri);
591 referenceList.appendChild(dataReference);
592 }
593 return referenceList;
594 }
595
596
597
598
599 public SecurityTokenReference getSecurityTokenReference() {
600 return securityTokenReference;
601 }
602
603
604
605
606 public void setSecurityTokenReference(SecurityTokenReference reference) {
607 securityTokenReference = reference;
608 }
609
610 public boolean isEncryptSymmKey() {
611 return encryptSymmKey;
612 }
613
614 public void setEncryptSymmKey(boolean encryptSymmKey) {
615 this.encryptSymmKey = encryptSymmKey;
616 }
617
618 public void setCustomReferenceValue(String customReferenceValue) {
619 this.customReferenceValue = customReferenceValue;
620 }
621
622 public void setEncKeyIdDirectId(boolean b) {
623 encKeyIdDirectId = b;
624 }
625
626 public void setEmbedEncryptedKey(boolean embedEncryptedKey) {
627 this.embedEncryptedKey = embedEncryptedKey;
628 }
629
630 public boolean isEmbedEncryptedKey() {
631 return embedEncryptedKey;
632 }
633 }