1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.wss4j.stax.impl.processor.output;
20
21 import java.nio.charset.StandardCharsets;
22 import java.security.Key;
23 import java.security.cert.X509Certificate;
24 import java.util.ArrayList;
25 import java.util.List;
26
27 import javax.crypto.spec.SecretKeySpec;
28 import javax.xml.namespace.QName;
29 import javax.xml.stream.XMLStreamException;
30
31 import org.apache.wss4j.common.derivedKey.AlgoFactory;
32 import org.apache.wss4j.common.derivedKey.DerivationAlgorithm;
33 import org.apache.wss4j.common.ext.WSPasswordCallback;
34 import org.apache.wss4j.common.ext.WSSecurityException;
35 import org.apache.wss4j.common.util.KeyUtils;
36 import org.apache.wss4j.stax.ext.WSSConstants;
37 import org.apache.wss4j.stax.ext.WSSSecurityProperties;
38 import org.apache.wss4j.stax.securityToken.WSSecurityTokenConstants;
39 import org.apache.wss4j.stax.utils.WSSUtils;
40 import org.apache.xml.security.exceptions.XMLSecurityException;
41 import org.apache.xml.security.stax.config.JCEAlgorithmMapper;
42 import org.apache.xml.security.stax.ext.AbstractOutputProcessor;
43 import org.apache.xml.security.stax.ext.OutputProcessorChain;
44 import org.apache.xml.security.stax.ext.XMLSecurityConstants;
45 import org.apache.xml.security.stax.ext.stax.XMLSecAttribute;
46 import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
47 import org.apache.xml.security.stax.impl.securityToken.GenericOutboundSecurityToken;
48 import org.apache.xml.security.stax.impl.util.IDGenerator;
49 import org.apache.xml.security.stax.securityToken.OutboundSecurityToken;
50 import org.apache.xml.security.stax.securityToken.SecurityToken;
51 import org.apache.xml.security.stax.securityToken.SecurityTokenProvider;
52 import org.apache.xml.security.utils.XMLUtils;
53
54 public class DerivedKeyTokenOutputProcessor extends AbstractOutputProcessor {
55
56 public DerivedKeyTokenOutputProcessor() throws XMLSecurityException {
57 super();
58 }
59
60 @Override
61 public void processEvent(XMLSecEvent xmlSecEvent, OutputProcessorChain outputProcessorChain)
62 throws XMLStreamException, XMLSecurityException {
63 try {
64
65 String tokenId = outputProcessorChain.getSecurityContext().get(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_DERIVED_KEY);
66 if (tokenId == null) {
67 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE);
68 }
69 SecurityTokenProvider<OutboundSecurityToken> wrappingSecurityTokenProvider =
70 outputProcessorChain.getSecurityContext().getSecurityTokenProvider(tokenId);
71 if (wrappingSecurityTokenProvider == null) {
72 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE);
73 }
74 final OutboundSecurityToken wrappingSecurityToken = wrappingSecurityTokenProvider.getSecurityToken();
75 if (wrappingSecurityToken == null) {
76 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE);
77 }
78
79 final String wsuIdDKT = IDGenerator.generateID(null);
80
81 int offset = 0;
82 int length = 0;
83
84 XMLSecurityConstants.Action action = getAction();
85 if (WSSConstants.SIGNATURE_WITH_DERIVED_KEY.equals(action)) {
86 if (((WSSSecurityProperties)getSecurityProperties()).getDerivedSignatureKeyLength() > 0) {
87 length = ((WSSSecurityProperties)getSecurityProperties()).getDerivedSignatureKeyLength();
88 } else {
89 length = JCEAlgorithmMapper.getKeyLengthFromURI(getSecurityProperties().getSignatureAlgorithm()) / 8;
90 if (length == 0) {
91 length = KeyUtils.getKeyLength(getSecurityProperties().getSignatureAlgorithm()) / 8;
92 }
93 }
94 } else if (WSSConstants.ENCRYPTION_WITH_DERIVED_KEY.equals(action)) {
95 if (((WSSSecurityProperties)getSecurityProperties()).getDerivedEncryptionKeyLength() > 0) {
96 length = ((WSSSecurityProperties)getSecurityProperties()).getDerivedEncryptionKeyLength();
97 } else {
98 length = JCEAlgorithmMapper.getKeyLengthFromURI(getSecurityProperties().getEncryptionSymAlgorithm()) / 8;
99 if (length == 0) {
100 length = KeyUtils.getKeyLength(getSecurityProperties().getEncryptionSymAlgorithm()) / 8;
101 }
102 }
103 }
104
105 String defaultLabel =
106 WSSConstants.WS_SEC_CONV_DEFAULT_LABEL + WSSConstants.WS_SEC_CONV_DEFAULT_LABEL;
107 byte[] label = defaultLabel.getBytes(StandardCharsets.UTF_8);
108
109 byte[] nonce = WSSConstants.generateBytes(16);
110
111 byte[] seed = new byte[label.length + nonce.length];
112 System.arraycopy(label, 0, seed, 0, label.length);
113 System.arraycopy(nonce, 0, seed, label.length, nonce.length);
114
115 DerivationAlgorithm derivationAlgorithm =
116 AlgoFactory.getInstance(WSSConstants.P_SHA_1);
117
118 byte[] secret;
119 if (WSSecurityTokenConstants.SECURITY_CONTEXT_TOKEN.equals(wrappingSecurityToken.getTokenType())) {
120 WSPasswordCallback passwordCallback = new WSPasswordCallback(wsuIdDKT, WSPasswordCallback.SECRET_KEY);
121 WSSUtils.doSecretKeyCallback(((WSSSecurityProperties)securityProperties).getCallbackHandler(), passwordCallback);
122 if (passwordCallback.getKey() == null) {
123 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "noKey",
124 new Object[] {wsuIdDKT});
125 }
126 secret = passwordCallback.getKey();
127 } else {
128 secret = wrappingSecurityToken.getSecretKey("").getEncoded();
129 }
130
131 final byte[] derivedKeyBytes = derivationAlgorithm.createKey(secret, seed, offset, length);
132
133 final GenericOutboundSecurityToken derivedKeySecurityToken =
134 new GenericOutboundSecurityToken(wsuIdDKT, WSSecurityTokenConstants.DerivedKeyToken) {
135
136 @Override
137 public Key getSecretKey(String algorithmURI) throws WSSecurityException {
138
139 Key key = null;
140 try {
141 key = super.getSecretKey(algorithmURI);
142 } catch (XMLSecurityException e) {
143 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
144 }
145 if (key != null) {
146 return key;
147 }
148 String algoFamily = JCEAlgorithmMapper.getJCEKeyAlgorithmFromURI(algorithmURI);
149 key = new SecretKeySpec(derivedKeyBytes, algoFamily);
150 setSecretKey(algorithmURI, key);
151 return key;
152 }
153 };
154
155 derivedKeySecurityToken.setKeyWrappingToken(wrappingSecurityToken);
156 wrappingSecurityToken.addWrappedToken(derivedKeySecurityToken);
157
158 SecurityTokenProvider<OutboundSecurityToken> derivedKeysecurityTokenProvider =
159 new SecurityTokenProvider<OutboundSecurityToken>() {
160
161 @Override
162 public OutboundSecurityToken getSecurityToken() throws WSSecurityException {
163 return derivedKeySecurityToken;
164 }
165
166 @Override
167 public String getId() {
168 return wsuIdDKT;
169 }
170 };
171
172 if (WSSConstants.SIGNATURE_WITH_DERIVED_KEY.equals(action)) {
173 outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_SIGNATURE, wsuIdDKT);
174 } else if (WSSConstants.ENCRYPTION_WITH_DERIVED_KEY.equals(action)) {
175 outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_ENCRYPTION, wsuIdDKT);
176 }
177 outputProcessorChain.getSecurityContext().registerSecurityTokenProvider(wsuIdDKT, derivedKeysecurityTokenProvider);
178 FinalDerivedKeyTokenOutputProcessor finalDerivedKeyTokenOutputProcessor =
179 new FinalDerivedKeyTokenOutputProcessor(derivedKeySecurityToken, offset, length,
180 XMLUtils.encodeToString(nonce),
181 ((WSSSecurityProperties)getSecurityProperties()).isUse200512Namespace(),
182 wrappingSecurityToken.getSha1Identifier());
183 finalDerivedKeyTokenOutputProcessor.setXMLSecurityProperties(getSecurityProperties());
184 finalDerivedKeyTokenOutputProcessor.setAction(getAction(), getActionOrder());
185 if (wrappingSecurityToken.getProcessor() != null) {
186 finalDerivedKeyTokenOutputProcessor.addBeforeProcessor(wrappingSecurityToken.getProcessor().getClass());
187 } else {
188 finalDerivedKeyTokenOutputProcessor.addAfterProcessor(ReferenceListOutputProcessor.class);
189 }
190 finalDerivedKeyTokenOutputProcessor.init(outputProcessorChain);
191 derivedKeySecurityToken.setProcessor(finalDerivedKeyTokenOutputProcessor);
192 } finally {
193 outputProcessorChain.removeProcessor(this);
194 }
195 outputProcessorChain.processEvent(xmlSecEvent);
196 }
197
198 static class FinalDerivedKeyTokenOutputProcessor extends AbstractOutputProcessor {
199
200 private final OutboundSecurityToken securityToken;
201 private final int offset;
202 private final int length;
203 private final String nonce;
204 private final boolean use200512Namespace;
205 private final String sha1Identifier;
206
207 FinalDerivedKeyTokenOutputProcessor(OutboundSecurityToken securityToken, int offset,
208 int length, String nonce, boolean use200512Namespace,
209 String sha1Identifier) throws XMLSecurityException {
210
211 super();
212 this.securityToken = securityToken;
213 this.offset = offset;
214 this.length = length;
215 this.nonce = nonce;
216 this.use200512Namespace = use200512Namespace;
217 this.sha1Identifier = sha1Identifier;
218 }
219
220 @Override
221 public void processEvent(XMLSecEvent xmlSecEvent, OutputProcessorChain outputProcessorChain)
222 throws XMLStreamException, XMLSecurityException {
223
224 outputProcessorChain.processEvent(xmlSecEvent);
225
226 if (WSSUtils.isSecurityHeaderElement(xmlSecEvent, ((WSSSecurityProperties) getSecurityProperties()).getActor())) {
227
228 final QName headerElementName = getHeaderElementName();
229 OutputProcessorUtils.updateSecurityHeaderOrder(outputProcessorChain, headerElementName, getAction(), false);
230
231 OutputProcessorChain subOutputProcessorChain = outputProcessorChain.createSubChain(this);
232
233 List<XMLSecAttribute> attributes = new ArrayList<>(1);
234 attributes.add(createAttribute(WSSConstants.ATT_WSU_ID, securityToken.getId()));
235 createStartElementAndOutputAsEvent(subOutputProcessorChain, headerElementName, true, attributes);
236
237 createSecurityTokenReferenceStructureForDerivedKey(subOutputProcessorChain, securityToken,
238 ((WSSSecurityProperties) getSecurityProperties()).getDerivedKeyKeyIdentifier(),
239 ((WSSSecurityProperties) getSecurityProperties()).getDerivedKeyTokenReference(),
240 getSecurityProperties().isUseSingleCert());
241 createStartElementAndOutputAsEvent(subOutputProcessorChain, getOffsetName(), false, null);
242 createCharactersAndOutputAsEvent(subOutputProcessorChain, "" + offset);
243 createEndElementAndOutputAsEvent(subOutputProcessorChain, getOffsetName());
244 createStartElementAndOutputAsEvent(subOutputProcessorChain, getLengthName(), false, null);
245 createCharactersAndOutputAsEvent(subOutputProcessorChain, "" + length);
246 createEndElementAndOutputAsEvent(subOutputProcessorChain, getLengthName());
247 createStartElementAndOutputAsEvent(subOutputProcessorChain, getNonceName(), false, null);
248 createCharactersAndOutputAsEvent(subOutputProcessorChain, nonce);
249 createEndElementAndOutputAsEvent(subOutputProcessorChain, getNonceName());
250 createEndElementAndOutputAsEvent(subOutputProcessorChain, headerElementName);
251
252 outputProcessorChain.removeProcessor(this);
253 }
254 }
255
256 protected void createSecurityTokenReferenceStructureForDerivedKey(
257 OutputProcessorChain outputProcessorChain,
258 OutboundSecurityToken securityToken,
259 WSSecurityTokenConstants.KeyIdentifier keyIdentifier,
260 WSSConstants.DerivedKeyTokenReference derivedKeyTokenReference,
261 boolean useSingleCertificate)
262 throws XMLStreamException, XMLSecurityException {
263
264 SecurityToken wrappingToken = securityToken.getKeyWrappingToken();
265 List<XMLSecAttribute> attributes = new ArrayList<>(2);
266 attributes.add(createAttribute(WSSConstants.ATT_WSU_ID, IDGenerator.generateID(null)));
267 if (WSSecurityTokenConstants.KEYIDENTIFIER_SECURITY_TOKEN_DIRECT_REFERENCE.equals(keyIdentifier) && !useSingleCertificate) {
268 attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_X509_PKIPATH_V1));
269 } else if (derivedKeyTokenReference == WSSConstants.DerivedKeyTokenReference.EncryptedKey
270 || WSSecurityTokenConstants.KEYIDENTIFIER_ENCRYPTED_KEY_SHA1_IDENTIFIER.equals(keyIdentifier)) {
271 attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_WSS_ENC_KEY_VALUE_TYPE));
272 } else if (WSSecurityTokenConstants.KERBEROS_TOKEN.equals(wrappingToken.getTokenType())) {
273 attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_GSS_KERBEROS5_AP_REQ));
274 }
275 createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE, false, attributes);
276
277 X509Certificate[] x509Certificates = wrappingToken.getX509Certificates();
278 String tokenId = wrappingToken.getId();
279
280 if (derivedKeyTokenReference == WSSConstants.DerivedKeyTokenReference.EncryptedKey) {
281 String valueType = WSSConstants.NS_WSS_ENC_KEY_VALUE_TYPE;
282 WSSUtils.createBSTReferenceStructure(this, outputProcessorChain, tokenId, valueType, true);
283 } else if (WSSecurityTokenConstants.KeyIdentifier_IssuerSerial.equals(keyIdentifier)) {
284 WSSUtils.createX509IssuerSerialStructure(this, outputProcessorChain, x509Certificates);
285 } else if (WSSecurityTokenConstants.KeyIdentifier_SkiKeyIdentifier.equals(keyIdentifier)) {
286 WSSUtils.createX509SubjectKeyIdentifierStructure(this, outputProcessorChain, x509Certificates);
287 } else if (WSSecurityTokenConstants.KeyIdentifier_X509KeyIdentifier.equals(keyIdentifier)) {
288 WSSUtils.createX509KeyIdentifierStructure(this, outputProcessorChain, x509Certificates);
289 } else if (WSSecurityTokenConstants.KEYIDENTIFIER_KERBEROS_SHA1_IDENTIFIER.equals(keyIdentifier)) {
290 String identifier = wrappingToken.getSha1Identifier();
291 WSSUtils.createKerberosSha1IdentifierStructure(this, outputProcessorChain, identifier);
292 } else if (WSSecurityTokenConstants.KEYIDENTIFIER_THUMBPRINT_IDENTIFIER.equals(keyIdentifier)) {
293 WSSUtils.createThumbprintKeyIdentifierStructure(this, outputProcessorChain, x509Certificates);
294 } else if (WSSecurityTokenConstants.KEYIDENTIFIER_SECURITY_TOKEN_DIRECT_REFERENCE.equals(keyIdentifier)) {
295 String valueType;
296 if (WSSecurityTokenConstants.KERBEROS_TOKEN.equals(wrappingToken.getTokenType())) {
297 valueType = WSSConstants.NS_GSS_KERBEROS5_AP_REQ;
298 } else if (WSSecurityTokenConstants.SPNEGO_CONTEXT_TOKEN.equals(wrappingToken.getTokenType())
299 || WSSecurityTokenConstants.SECURITY_CONTEXT_TOKEN.equals(wrappingToken.getTokenType())
300 || WSSecurityTokenConstants.SECURE_CONVERSATION_TOKEN.equals(wrappingToken.getTokenType())) {
301 boolean use200512Namespace = ((WSSSecurityProperties)getSecurityProperties()).isUse200512Namespace();
302 if (use200512Namespace) {
303 valueType = WSSConstants.NS_WSC_05_12 + "/sct";
304 } else {
305 valueType = WSSConstants.NS_WSC_05_02 + "/sct";
306 }
307 } else if (useSingleCertificate) {
308 valueType = WSSConstants.NS_X509_V3_TYPE;
309 } else {
310 valueType = WSSConstants.NS_X509_PKIPATH_V1;
311 }
312 boolean included = ((WSSSecurityProperties)getSecurityProperties()).isIncludeSignatureToken();
313 WSSUtils.createBSTReferenceStructure(this, outputProcessorChain, tokenId, valueType, included);
314 } else if (WSSecurityTokenConstants.KEYIDENTIFIER_ENCRYPTED_KEY_SHA1_IDENTIFIER.equals(keyIdentifier)) {
315 WSSUtils.createEncryptedKeySha1IdentifierStructure(this, outputProcessorChain, sha1Identifier);
316 } else {
317 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "unsupportedSecurityToken");
318 }
319 createEndElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE);
320 }
321
322 private QName getHeaderElementName() {
323 if (use200512Namespace) {
324 return WSSConstants.TAG_WSC0512_DKT;
325 }
326 return WSSConstants.TAG_WSC0502_DKT;
327 }
328
329 private QName getOffsetName() {
330 if (use200512Namespace) {
331 return WSSConstants.TAG_WSC0512_OFFSET;
332 }
333 return WSSConstants.TAG_WSC0502_OFFSET;
334 }
335
336 private QName getLengthName() {
337 if (use200512Namespace) {
338 return WSSConstants.TAG_WSC0512_LENGTH;
339 }
340 return WSSConstants.TAG_WSC0502_LENGTH;
341 }
342
343 private QName getNonceName() {
344 if (use200512Namespace) {
345 return WSSConstants.TAG_WSC0512_NONCE;
346 }
347 return WSSConstants.TAG_WSC0502_NONCE;
348 }
349 }
350 }