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 java.security.InvalidAlgorithmParameterException;
23 import java.security.InvalidKeyException;
24 import java.security.NoSuchAlgorithmException;
25 import java.security.cert.X509Certificate;
26 import java.security.spec.MGF1ParameterSpec;
27
28 import javax.crypto.Cipher;
29 import javax.crypto.IllegalBlockSizeException;
30 import javax.crypto.KeyGenerator;
31 import javax.crypto.SecretKey;
32 import javax.crypto.spec.OAEPParameterSpec;
33 import javax.crypto.spec.PSource;
34
35 import org.apache.ws.security.WSConstants;
36 import org.apache.ws.security.WSSConfig;
37 import org.apache.ws.security.WSSecurityException;
38 import org.apache.ws.security.components.crypto.Crypto;
39 import org.apache.ws.security.components.crypto.CryptoType;
40 import org.apache.ws.security.message.token.BinarySecurity;
41 import org.apache.ws.security.message.token.DOMX509Data;
42 import org.apache.ws.security.message.token.DOMX509IssuerSerial;
43 import org.apache.ws.security.message.token.Reference;
44 import org.apache.ws.security.message.token.SecurityTokenReference;
45 import org.apache.ws.security.message.token.X509Security;
46 import org.apache.ws.security.util.UUIDGenerator;
47 import org.apache.ws.security.util.WSSecurityUtil;
48 import org.apache.xml.security.algorithms.JCEMapper;
49 import org.apache.xml.security.utils.Constants;
50 import org.apache.xml.security.utils.XMLUtils;
51
52 import org.w3c.dom.Document;
53 import org.w3c.dom.Element;
54 import org.w3c.dom.Text;
55
56
57
58
59
60
61
62
63
64
65 public class WSSecEncryptedKey extends WSSecBase {
66
67 private static org.apache.commons.logging.Log log =
68 org.apache.commons.logging.LogFactory.getLog(WSSecEncryptedKey.class);
69
70 protected Document document;
71
72
73
74
75 protected Element envelope = null;
76
77
78
79
80 protected byte[] ephemeralKey;
81
82
83
84
85 protected SecretKey symmetricKey = null;
86
87
88
89
90 protected byte[] encryptedEphemeralKey;
91
92
93
94
95 protected String encrUser = null;
96
97
98
99
100 protected String keyEncAlgo = WSConstants.KEYTRANSPORT_RSAOEP;
101
102
103
104
105 protected String symEncAlgo = WSConstants.AES_128;
106
107
108
109
110
111 protected String digestAlgo = null;
112
113
114
115
116 protected Element encryptedKeyElement = null;
117
118
119
120
121
122 protected String encKeyId = null;
123
124
125
126
127 protected String customEKTokenValueType;
128
129
130
131
132 protected String customEKTokenId;
133
134
135
136
137
138 protected BinarySecurity bstToken = null;
139
140 protected X509Certificate useThisCert = null;
141
142 public WSSecEncryptedKey() {
143 super();
144 }
145
146 public WSSecEncryptedKey(WSSConfig config) {
147 super(config);
148 }
149
150
151
152
153
154
155
156
157
158 public void setUserInfo(String user) {
159 this.user = user;
160 }
161
162
163
164
165
166
167
168
169
170 public String getId() {
171 return encKeyId;
172 }
173
174
175
176
177
178
179
180
181
182 public void prepare(Document doc, Crypto crypto) throws WSSecurityException {
183
184 document = doc;
185
186
187
188
189 if (ephemeralKey == null) {
190 if (symmetricKey == null) {
191 KeyGenerator keyGen = getKeyGenerator();
192 symmetricKey = keyGen.generateKey();
193 }
194 ephemeralKey = symmetricKey.getEncoded();
195 }
196
197 if (symmetricKey == null) {
198 symmetricKey = WSSecurityUtil.prepareSecretKey(symEncAlgo, ephemeralKey);
199 }
200
201
202
203
204
205 X509Certificate remoteCert = useThisCert;
206 if (remoteCert == null) {
207 CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
208 cryptoType.setAlias(user);
209 X509Certificate[] certs = crypto.getX509Certificates(cryptoType);
210 if (certs == null || certs.length <= 0) {
211 throw new WSSecurityException(
212 WSSecurityException.FAILURE,
213 "noUserCertsFound",
214 new Object[] {user, "encryption"}
215 );
216 }
217 remoteCert = certs[0];
218 }
219
220 prepareInternal(symmetricKey, remoteCert, crypto);
221 }
222
223
224
225
226
227
228
229
230
231
232
233
234
235 protected void prepareInternal(
236 SecretKey secretKey,
237 X509Certificate remoteCert,
238 Crypto crypto
239 ) throws WSSecurityException {
240 Cipher cipher = WSSecurityUtil.getCipherInstance(keyEncAlgo);
241 try {
242 OAEPParameterSpec oaepParameterSpec = null;
243 if (WSConstants.KEYTRANSPORT_RSAOEP.equals(keyEncAlgo)) {
244 String jceDigestAlgorithm = "SHA-1";
245 if (digestAlgo != null) {
246 jceDigestAlgorithm = JCEMapper.translateURItoJCEID(digestAlgo);
247 }
248
249 oaepParameterSpec =
250 new OAEPParameterSpec(
251 jceDigestAlgorithm, "MGF1", new MGF1ParameterSpec("SHA-1"), PSource.PSpecified.DEFAULT
252 );
253 }
254 if (oaepParameterSpec == null) {
255 cipher.init(Cipher.WRAP_MODE, remoteCert);
256 } else {
257 cipher.init(Cipher.WRAP_MODE, remoteCert.getPublicKey(), oaepParameterSpec);
258 }
259 } catch (InvalidKeyException e) {
260 throw new WSSecurityException(
261 WSSecurityException.FAILED_ENCRYPTION, null, null, e
262 );
263 } catch (InvalidAlgorithmParameterException e) {
264 throw new WSSecurityException(
265 WSSecurityException.FAILED_ENCRYPTION, null, null, e
266 );
267 }
268 int blockSize = cipher.getBlockSize();
269 if (doDebug) {
270 log.debug(
271 "cipher blksize: " + blockSize + ", symm key: " + secretKey.toString()
272 );
273 }
274
275 try {
276 encryptedEphemeralKey = cipher.wrap(secretKey);
277 } catch (IllegalStateException ex) {
278 throw new WSSecurityException(
279 WSSecurityException.FAILED_ENCRYPTION, null, null, ex
280 );
281 } catch (IllegalBlockSizeException ex) {
282 throw new WSSecurityException(
283 WSSecurityException.FAILED_ENCRYPTION, null, null, ex
284 );
285 } catch (InvalidKeyException ex) {
286 throw new WSSecurityException(
287 WSSecurityException.FAILED_ENCRYPTION, null, null, ex
288 );
289 }
290 Text keyText =
291 WSSecurityUtil.createBase64EncodedTextNode(document, encryptedEphemeralKey);
292
293
294
295
296
297
298
299
300
301 encryptedKeyElement = createEncryptedKey(document, keyEncAlgo);
302 if (encKeyId == null || "".equals(encKeyId)) {
303 encKeyId = "EK-" + UUIDGenerator.getUUID();
304 }
305 encryptedKeyElement.setAttributeNS(null, "Id", encKeyId);
306
307 SecurityTokenReference secToken = new SecurityTokenReference(document);
308
309 switch (keyIdentifierType) {
310 case WSConstants.X509_KEY_IDENTIFIER:
311 secToken.setKeyIdentifier(remoteCert);
312 break;
313
314 case WSConstants.SKI_KEY_IDENTIFIER:
315 secToken.setKeyIdentifierSKI(remoteCert, crypto);
316 break;
317
318 case WSConstants.THUMBPRINT_IDENTIFIER:
319 case WSConstants.ENCRYPTED_KEY_SHA1_IDENTIFIER:
320
321
322
323
324 secToken.setKeyIdentifierThumb(remoteCert);
325 break;
326
327 case WSConstants.ISSUER_SERIAL:
328 String issuer = remoteCert.getIssuerX500Principal().getName();
329 java.math.BigInteger serialNumber = remoteCert.getSerialNumber();
330 DOMX509IssuerSerial domIssuerSerial =
331 new DOMX509IssuerSerial(
332 document, issuer, serialNumber
333 );
334 DOMX509Data domX509Data = new DOMX509Data(document, domIssuerSerial);
335 secToken.setX509Data(domX509Data);
336 break;
337
338 case WSConstants.BST_DIRECT_REFERENCE:
339 Reference ref = new Reference(document);
340 String certUri = UUIDGenerator.getUUID();
341 ref.setURI("#" + certUri);
342 bstToken = new X509Security(document);
343 ((X509Security) bstToken).setX509Certificate(remoteCert);
344 bstToken.setID(certUri);
345 ref.setValueType(bstToken.getValueType());
346 secToken.setReference(ref);
347 break;
348
349 case WSConstants.CUSTOM_SYMM_SIGNING :
350 Reference refCust = new Reference(document);
351 if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
352 secToken.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
353 refCust.setValueType(customEKTokenValueType);
354 } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
355 secToken.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
356 } else if (WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(customEKTokenValueType)) {
357 secToken.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
358 refCust.setValueType(customEKTokenValueType);
359 } else {
360 refCust.setValueType(customEKTokenValueType);
361 }
362 refCust.setURI("#" + customEKTokenId);
363 secToken.setReference(refCust);
364 break;
365
366 case WSConstants.CUSTOM_SYMM_SIGNING_DIRECT :
367 Reference refCustd = new Reference(document);
368 if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
369 secToken.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
370 refCustd.setValueType(customEKTokenValueType);
371 } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
372 secToken.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
373 } else if (WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(customEKTokenValueType)) {
374 secToken.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
375 refCustd.setValueType(customEKTokenValueType);
376 } else {
377 refCustd.setValueType(customEKTokenValueType);
378 }
379 refCustd.setURI(customEKTokenId);
380 secToken.setReference(refCustd);
381 break;
382
383 case WSConstants.CUSTOM_KEY_IDENTIFIER:
384 secToken.setKeyIdentifier(customEKTokenValueType, customEKTokenId);
385 if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
386 secToken.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
387 } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
388 secToken.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
389 } else if (WSConstants.WSS_ENC_KEY_VALUE_TYPE.equals(customEKTokenValueType)) {
390 secToken.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
391 } else if (SecurityTokenReference.ENC_KEY_SHA1_URI.equals(customEKTokenValueType)) {
392 secToken.addTokenType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
393 }
394 break;
395
396 default:
397 throw new WSSecurityException(WSSecurityException.FAILURE, "unsupportedKeyId");
398 }
399 Element keyInfoElement =
400 document.createElementNS(
401 WSConstants.SIG_NS, WSConstants.SIG_PREFIX + ":" + WSConstants.KEYINFO_LN
402 );
403 keyInfoElement.setAttributeNS(
404 WSConstants.XMLNS_NS, "xmlns:" + WSConstants.SIG_PREFIX, WSConstants.SIG_NS
405 );
406 keyInfoElement.appendChild(secToken.getElement());
407 encryptedKeyElement.appendChild(keyInfoElement);
408
409 Element xencCipherValue = createCipherValue(document, encryptedKeyElement);
410 xencCipherValue.appendChild(keyText);
411
412 envelope = document.getDocumentElement();
413 }
414
415 protected KeyGenerator getKeyGenerator() throws WSSecurityException {
416 try {
417
418
419
420 String keyAlgorithm = JCEMapper.getJCEKeyAlgorithmFromURI(symEncAlgo);
421 if (keyAlgorithm == null || "".equals(keyAlgorithm)) {
422 keyAlgorithm = JCEMapper.translateURItoJCEID(symEncAlgo);
423 }
424 KeyGenerator keyGen = KeyGenerator.getInstance(keyAlgorithm);
425 if (symEncAlgo.equalsIgnoreCase(WSConstants.AES_128)
426 || symEncAlgo.equalsIgnoreCase(WSConstants.AES_128_GCM)) {
427 keyGen.init(128);
428 } else if (symEncAlgo.equalsIgnoreCase(WSConstants.AES_192)
429 || symEncAlgo.equalsIgnoreCase(WSConstants.AES_192_GCM)) {
430 keyGen.init(192);
431 } else if (symEncAlgo.equalsIgnoreCase(WSConstants.AES_256)
432 || symEncAlgo.equalsIgnoreCase(WSConstants.AES_256_GCM)) {
433 keyGen.init(256);
434 }
435 return keyGen;
436 } catch (NoSuchAlgorithmException e) {
437 throw new WSSecurityException(
438 WSSecurityException.UNSUPPORTED_ALGORITHM, null, null, e
439 );
440 }
441 }
442
443
444
445
446
447
448
449
450 protected Element createEncryptedKey(Document doc, String keyTransportAlgo) {
451 Element encryptedKey =
452 doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":EncryptedKey");
453
454 WSSecurityUtil.setNamespace(encryptedKey, WSConstants.ENC_NS, WSConstants.ENC_PREFIX);
455 Element encryptionMethod =
456 doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":EncryptionMethod");
457 encryptionMethod.setAttributeNS(null, "Algorithm", keyTransportAlgo);
458
459 if (digestAlgo != null) {
460 Element digestElement =
461 XMLUtils.createElementInSignatureSpace(doc, Constants._TAG_DIGESTMETHOD);
462 digestElement.setAttributeNS(null, "Algorithm", digestAlgo);
463 encryptionMethod.appendChild(digestElement);
464 }
465
466 encryptedKey.appendChild(encryptionMethod);
467 return encryptedKey;
468 }
469
470 protected Element createCipherValue(Document doc, Element encryptedKey) {
471 Element cipherData =
472 doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":CipherData");
473 Element cipherValue =
474 doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":CipherValue");
475 cipherData.appendChild(cipherValue);
476 encryptedKey.appendChild(cipherData);
477 return cipherValue;
478 }
479
480
481
482
483
484
485
486
487
488
489
490 public void prependToHeader(WSSecHeader secHeader) {
491 WSSecurityUtil.prependChildElement(secHeader.getSecurityHeader(), encryptedKeyElement);
492 }
493
494
495
496
497
498
499
500
501
502
503
504 public void appendToHeader(WSSecHeader secHeader) {
505 Element secHeaderElement = secHeader.getSecurityHeader();
506 secHeaderElement.appendChild(encryptedKeyElement);
507 }
508
509
510
511
512
513
514
515
516
517
518 public void prependBSTElementToHeader(WSSecHeader secHeader) {
519 if (bstToken != null) {
520 WSSecurityUtil.prependChildElement(
521 secHeader.getSecurityHeader(), bstToken.getElement()
522 );
523 }
524 bstToken = null;
525 }
526
527
528
529
530
531
532
533
534
535
536 public void appendBSTElementToHeader(WSSecHeader secHeader) {
537 if (bstToken != null) {
538 Element secHeaderElement = secHeader.getSecurityHeader();
539 secHeaderElement.appendChild(bstToken.getElement());
540 }
541 bstToken = null;
542 }
543
544
545
546
547 public byte[] getEphemeralKey() {
548 return ephemeralKey;
549 }
550
551
552
553
554
555
556
557
558
559
560 public void setUseThisCert(X509Certificate cert) {
561 useThisCert = cert;
562 }
563
564
565
566
567 public Element getEncryptedKeyElement() {
568 return encryptedKeyElement;
569 }
570
571
572
573
574
575 public void setEncryptedKeyElement(Element encryptedKeyElement) {
576 this.encryptedKeyElement = encryptedKeyElement;
577 }
578
579
580
581
582 public Element getBinarySecurityTokenElement() {
583 if (bstToken != null) {
584 return bstToken.getElement();
585 }
586 return null;
587 }
588
589 public void setKeyEncAlgo(String keyEncAlgo) {
590 this.keyEncAlgo = keyEncAlgo;
591 }
592
593
594
595
596 public void setEphemeralKey(byte[] ephemeralKey) {
597 this.ephemeralKey = ephemeralKey;
598 }
599
600
601
602
603
604
605
606 public String getBSTTokenId() {
607 if (bstToken == null) {
608 return null;
609 }
610
611 return bstToken.getID();
612 }
613
614
615
616
617 public void setDocument(Document document) {
618 this.document = document;
619 }
620
621
622
623
624 public void setEncKeyId(String encKeyId) {
625 this.encKeyId = encKeyId;
626 }
627
628 public boolean isCertSet() {
629 if (useThisCert == null) {
630 return false;
631 }
632 return true;
633 }
634
635 public byte[] getEncryptedEphemeralKey() {
636 return encryptedEphemeralKey;
637 }
638
639 public void setCustomEKTokenValueType(String customEKTokenValueType) {
640 this.customEKTokenValueType = customEKTokenValueType;
641 }
642
643 public void setCustomEKTokenId(String customEKTokenId) {
644 this.customEKTokenId = customEKTokenId;
645 }
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660 public void setSymmetricEncAlgorithm(String algo) {
661 symEncAlgo = algo;
662 }
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677 public String getSymmetricEncAlgorithm() {
678 return symEncAlgo;
679 }
680
681
682
683
684
685
686
687 public void setDigestAlgorithm(String digestAlgorithm) {
688 this.digestAlgo = digestAlgorithm;
689 }
690
691
692
693
694
695 public String getDigestAlgorithm() {
696 return digestAlgo;
697 }
698
699
700
701
702 public SecretKey getSymmetricKey() {
703 return symmetricKey;
704 }
705
706
707
708
709
710
711 public void setSymmetricKey(SecretKey key) {
712 this.symmetricKey = key;
713 }
714
715
716 }