1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.saml2.encryption;
18
19 import java.security.Key;
20 import java.security.NoSuchAlgorithmException;
21 import java.util.ArrayList;
22 import java.util.List;
23
24 import javax.xml.namespace.QName;
25
26 import org.opensaml.Configuration;
27 import org.opensaml.common.IdentifierGenerator;
28 import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
29 import org.opensaml.saml2.core.Assertion;
30 import org.opensaml.saml2.core.Attribute;
31 import org.opensaml.saml2.core.BaseID;
32 import org.opensaml.saml2.core.EncryptedAssertion;
33 import org.opensaml.saml2.core.EncryptedAttribute;
34 import org.opensaml.saml2.core.EncryptedElementType;
35 import org.opensaml.saml2.core.EncryptedID;
36 import org.opensaml.saml2.core.NameID;
37 import org.opensaml.saml2.core.NewEncryptedID;
38 import org.opensaml.saml2.core.NewID;
39 import org.opensaml.xml.XMLObject;
40 import org.opensaml.xml.XMLObjectBuilderFactory;
41 import org.opensaml.xml.encryption.CarriedKeyName;
42 import org.opensaml.xml.encryption.DataReference;
43 import org.opensaml.xml.encryption.EncryptedData;
44 import org.opensaml.xml.encryption.EncryptedKey;
45 import org.opensaml.xml.encryption.EncryptionConstants;
46 import org.opensaml.xml.encryption.EncryptionException;
47 import org.opensaml.xml.encryption.EncryptionParameters;
48 import org.opensaml.xml.encryption.KeyEncryptionParameters;
49 import org.opensaml.xml.encryption.ReferenceList;
50 import org.opensaml.xml.encryption.XMLEncryptionBuilder;
51 import org.opensaml.xml.security.SecurityException;
52 import org.opensaml.xml.security.SecurityHelper;
53 import org.opensaml.xml.security.keyinfo.KeyInfoGenerator;
54 import org.opensaml.xml.signature.KeyInfo;
55 import org.opensaml.xml.signature.KeyName;
56 import org.opensaml.xml.signature.RetrievalMethod;
57 import org.opensaml.xml.signature.XMLSignatureBuilder;
58 import org.opensaml.xml.util.DatatypeHelper;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61 import org.w3c.dom.Document;
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 public class Encrypter extends org.opensaml.xml.encryption.Encrypter {
96
97
98
99
100
101 public enum KeyPlacement {
102
103 PEER,
104
105
106 INLINE
107 }
108
109
110 private XMLObjectBuilderFactory builderFactory;
111
112
113 private XMLSignatureBuilder<KeyInfo> keyInfoBuilder;
114
115
116 private XMLEncryptionBuilder<DataReference> dataReferenceBuilder;
117
118
119 private XMLEncryptionBuilder<ReferenceList> referenceListBuilder;
120
121
122 private XMLSignatureBuilder<RetrievalMethod> retrievalMethodBuilder;
123
124
125 private XMLSignatureBuilder<KeyName> keyNameBuilder;
126
127
128 private XMLEncryptionBuilder<CarriedKeyName> carriedKeyNameBuilder;
129
130
131 private IdentifierGenerator idGenerator;
132
133
134 private EncryptionParameters encParams;
135
136
137 private List<KeyEncryptionParameters> kekParamsList;
138
139
140 private KeyPlacement keyPlacement;
141
142
143 private final Logger log = LoggerFactory.getLogger(Encrypter.class);
144
145
146
147
148
149
150
151
152 public Encrypter(EncryptionParameters dataEncParams, List<KeyEncryptionParameters> keyEncParams) {
153 super();
154
155 this.encParams = dataEncParams;
156 this.kekParamsList = keyEncParams;
157
158 init();
159 }
160
161
162
163
164
165
166
167 public Encrypter(EncryptionParameters dataEncParams, KeyEncryptionParameters keyEncParam) {
168 super();
169
170 List<KeyEncryptionParameters> keks = new ArrayList<KeyEncryptionParameters>();
171 keks.add(keyEncParam);
172
173 this.encParams = dataEncParams;
174 this.kekParamsList = keks;
175
176 init();
177 }
178
179
180
181
182
183
184 public Encrypter(EncryptionParameters dataEncParams) {
185 super();
186
187 List<KeyEncryptionParameters> keks = new ArrayList<KeyEncryptionParameters>();
188
189 this.encParams = dataEncParams;
190 this.kekParamsList = keks;
191
192 init();
193 }
194
195
196
197
198 private void init() {
199 builderFactory = Configuration.getBuilderFactory();
200 keyInfoBuilder =
201 (XMLSignatureBuilder<KeyInfo>) builderFactory.getBuilder(KeyInfo.DEFAULT_ELEMENT_NAME);
202 dataReferenceBuilder =
203 (XMLEncryptionBuilder<DataReference>) builderFactory.getBuilder(DataReference.DEFAULT_ELEMENT_NAME);
204 referenceListBuilder =
205 (XMLEncryptionBuilder<ReferenceList>) builderFactory.getBuilder(ReferenceList.DEFAULT_ELEMENT_NAME);
206 retrievalMethodBuilder =
207 (XMLSignatureBuilder<RetrievalMethod>) builderFactory.getBuilder(RetrievalMethod.DEFAULT_ELEMENT_NAME);
208 keyNameBuilder =
209 (XMLSignatureBuilder<KeyName>) builderFactory.getBuilder(KeyName.DEFAULT_ELEMENT_NAME);
210 carriedKeyNameBuilder =
211 (XMLEncryptionBuilder<CarriedKeyName>) builderFactory.getBuilder(CarriedKeyName.DEFAULT_ELEMENT_NAME);
212
213 try{
214 idGenerator = new SecureRandomIdentifierGenerator();
215 }catch(NoSuchAlgorithmException e){
216 log.error("JVM does not support SHA1PRNG random number generation algorithm.");
217 }
218
219 keyPlacement = KeyPlacement.PEER;
220 }
221
222
223
224
225
226
227 public void setIDGenerator(IdentifierGenerator newIDGenerator) {
228 this.idGenerator = newIDGenerator;
229 }
230
231
232
233
234
235
236 public KeyPlacement getKeyPlacement() {
237 return this.keyPlacement;
238 }
239
240
241
242
243
244
245 public void setKeyPlacement(KeyPlacement newKeyPlacement) {
246 this.keyPlacement = newKeyPlacement;
247 }
248
249
250
251
252
253
254
255
256 public EncryptedAssertion encrypt(Assertion assertion) throws EncryptionException {
257 return (EncryptedAssertion) encrypt(assertion, EncryptedAssertion.DEFAULT_ELEMENT_NAME);
258 }
259
260
261
262
263
264
265
266
267
268 public EncryptedID encryptAsID(Assertion assertion) throws EncryptionException {
269 return (EncryptedID) encrypt(assertion, EncryptedID.DEFAULT_ELEMENT_NAME);
270 }
271
272
273
274
275
276
277
278
279 public EncryptedAttribute encrypt(Attribute attribute) throws EncryptionException {
280 return (EncryptedAttribute) encrypt(attribute, EncryptedAttribute.DEFAULT_ELEMENT_NAME);
281 }
282
283
284
285
286
287
288
289
290 public EncryptedID encrypt(NameID nameID) throws EncryptionException {
291 return (EncryptedID) encrypt(nameID, EncryptedID.DEFAULT_ELEMENT_NAME);
292 }
293
294
295
296
297
298
299
300
301 public EncryptedID encrypt(BaseID baseID) throws EncryptionException {
302 return (EncryptedID) encrypt(baseID, EncryptedID.DEFAULT_ELEMENT_NAME);
303 }
304
305
306
307
308
309
310
311
312 public NewEncryptedID encrypt(NewID newID) throws EncryptionException {
313 return (NewEncryptedID) encrypt(newID, NewEncryptedID.DEFAULT_ELEMENT_NAME);
314 }
315
316
317
318
319
320
321
322
323
324
325 private EncryptedElementType encrypt(XMLObject xmlObject, QName encElementName) throws EncryptionException {
326
327 checkParams(encParams, kekParamsList);
328
329 EncryptedElementType encElement =
330 (EncryptedElementType) builderFactory.getBuilder(encElementName).buildObject(encElementName);
331
332
333
334 checkAndMarshall(encElement);
335 Document ownerDocument = encElement.getDOM().getOwnerDocument();
336
337 String encryptionAlgorithmURI = encParams.getAlgorithm();
338 Key encryptionKey = SecurityHelper.extractEncryptionKey(encParams.getEncryptionCredential());
339 if (encryptionKey == null) {
340 encryptionKey = generateEncryptionKey(encryptionAlgorithmURI);
341 }
342
343 EncryptedData encryptedData = encryptElement(xmlObject, encryptionKey, encryptionAlgorithmURI, false);
344 if (encParams.getKeyInfoGenerator() != null) {
345 KeyInfoGenerator generator = encParams.getKeyInfoGenerator();
346 log.debug("Dynamically generating KeyInfo from Credential for EncryptedData using generator: {}",
347 generator.getClass().getName());
348 try {
349 encryptedData.setKeyInfo( generator.generate(encParams.getEncryptionCredential()) );
350 } catch (SecurityException e) {
351 throw new EncryptionException("Error generating EncryptedData KeyInfo", e);
352 }
353 }
354
355 List<EncryptedKey> encryptedKeys = new ArrayList<EncryptedKey>();
356 if (kekParamsList != null && ! kekParamsList.isEmpty()) {
357 encryptedKeys.addAll( encryptKey(encryptionKey, kekParamsList, ownerDocument) );
358 }
359
360 return processElements(encElement, encryptedData, encryptedKeys);
361 }
362
363
364
365
366
367
368
369
370
371
372
373
374 protected EncryptedElementType processElements(EncryptedElementType encElement,
375 EncryptedData encData, List<EncryptedKey> encKeys) throws EncryptionException {
376
377 if (encData.getID() == null) {
378 encData.setID(idGenerator.generateIdentifier());
379 }
380
381
382 if (encKeys.isEmpty()) {
383 encElement.setEncryptedData(encData);
384 return encElement;
385 }
386
387 if (encData.getKeyInfo() == null) {
388 encData.setKeyInfo(keyInfoBuilder.buildObject());
389 }
390
391 for (EncryptedKey encKey : encKeys) {
392 if (encKey.getID() == null) {
393 encKey.setID(idGenerator.generateIdentifier());
394 }
395 }
396
397 switch (keyPlacement) {
398 case INLINE:
399 return placeKeysInline(encElement, encData, encKeys);
400 case PEER:
401 return placeKeysAsPeers(encElement, encData, encKeys);
402 default:
403
404 throw new EncryptionException("Unsupported key placement option was specified: " + keyPlacement);
405 }
406 }
407
408
409
410
411
412
413
414
415
416
417
418
419 protected EncryptedElementType placeKeysInline(EncryptedElementType encElement,
420 EncryptedData encData, List<EncryptedKey> encKeys) {
421
422 log.debug("Placing EncryptedKey elements inline inside EncryptedData");
423
424 encData.getKeyInfo().getEncryptedKeys().addAll(encKeys);
425 encElement.setEncryptedData(encData);
426 return encElement;
427 }
428
429
430
431
432
433
434
435
436
437
438
439 protected EncryptedElementType placeKeysAsPeers(EncryptedElementType encElement,
440 EncryptedData encData, List<EncryptedKey> encKeys) {
441
442 log.debug("Placing EncryptedKey elements as peers of EncryptedData in EncryptedElementType");
443
444 for (EncryptedKey encKey : encKeys) {
445 if (encKey.getReferenceList() == null) {
446 encKey.setReferenceList(referenceListBuilder.buildObject());
447 }
448 }
449
450
451
452
453 if (encKeys.size() == 1) {
454 linkSinglePeerKey(encData, encKeys.get(0));
455 } else if (encKeys.size() > 1) {
456 linkMultiplePeerKeys(encData, encKeys);
457 }
458
459 encElement.setEncryptedData(encData);
460 encElement.getEncryptedKeys().addAll(encKeys);
461
462 return encElement;
463 }
464
465
466
467
468
469
470
471 protected void linkSinglePeerKey(EncryptedData encData, EncryptedKey encKey) {
472 log.debug("Linking single peer EncryptedKey with RetrievalMethod and DataReference");
473
474 RetrievalMethod rm = retrievalMethodBuilder.buildObject();
475 rm.setURI("#" + encKey.getID());
476 rm.setType(EncryptionConstants.TYPE_ENCRYPTED_KEY);
477 encData.getKeyInfo().getRetrievalMethods().add(rm);
478
479
480 DataReference dr = dataReferenceBuilder.buildObject();
481 dr.setURI("#" + encData.getID());
482 encKey.getReferenceList().getDataReferences().add(dr);
483 }
484
485
486
487
488
489
490
491
492 protected void linkMultiplePeerKeys(EncryptedData encData, List<EncryptedKey> encKeys) {
493 log.debug("Linking multiple peer EncryptedKeys with CarriedKeyName and DataReference");
494
495 List<KeyName> dataEncKeyNames = encData.getKeyInfo().getKeyNames();
496 String carriedKeyNameValue;
497 if (dataEncKeyNames.size() == 0 || DatatypeHelper.isEmpty(dataEncKeyNames.get(0).getValue()) ) {
498
499 String keyNameValue = idGenerator.generateIdentifier();
500 log.debug("EncryptedData encryption key had no KeyName, generated one for use in CarriedKeyName: {}",
501 keyNameValue);
502
503 KeyName keyName = dataEncKeyNames.get(0);
504 if (keyName == null) {
505 keyName = keyNameBuilder.buildObject();
506 dataEncKeyNames.add(keyName);
507 }
508 keyName.setValue(keyNameValue);
509 carriedKeyNameValue = keyNameValue;
510 } else {
511 carriedKeyNameValue = dataEncKeyNames.get(0).getValue();
512 }
513
514
515 for (EncryptedKey encKey : encKeys) {
516 if (encKey.getCarriedKeyName() == null) {
517 encKey.setCarriedKeyName(carriedKeyNameBuilder.buildObject());
518 }
519 encKey.getCarriedKeyName().setValue(carriedKeyNameValue);
520
521
522 DataReference dr = dataReferenceBuilder.buildObject();
523 dr.setURI("#" + encData.getID());
524 encKey.getReferenceList().getDataReferences().add(dr);
525
526 }
527 }
528
529 }