View Javadoc
1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.wss4j.stax.impl.processor.input;
20  
21  import java.security.Key;
22  import java.util.Deque;
23  import java.util.List;
24  
25  import javax.crypto.spec.SecretKeySpec;
26  import jakarta.xml.bind.JAXBElement;
27  import javax.xml.namespace.QName;
28  
29  import org.apache.wss4j.binding.wssc.AbstractDerivedKeyTokenType;
30  import org.apache.wss4j.common.derivedKey.DerivedKeyUtils;
31  import org.apache.wss4j.common.ext.WSSecurityException;
32  import org.apache.wss4j.stax.ext.WSInboundSecurityContext;
33  import org.apache.wss4j.stax.ext.WSSConstants;
34  import org.apache.wss4j.stax.ext.WSSSecurityProperties;
35  import org.apache.wss4j.stax.impl.securityToken.SecurityTokenFactoryImpl;
36  import org.apache.wss4j.stax.securityEvent.DerivedKeyTokenSecurityEvent;
37  import org.apache.wss4j.stax.securityToken.UsernameSecurityToken;
38  import org.apache.wss4j.stax.securityToken.WSSecurityTokenConstants;
39  import org.apache.xml.security.exceptions.XMLSecurityException;
40  import org.apache.xml.security.stax.config.JCEAlgorithmMapper;
41  import org.apache.xml.security.stax.ext.AbstractInputSecurityHeaderHandler;
42  import org.apache.xml.security.stax.ext.InputProcessorChain;
43  import org.apache.xml.security.stax.ext.XMLSecurityConstants;
44  import org.apache.xml.security.stax.ext.XMLSecurityProperties;
45  import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
46  import org.apache.xml.security.stax.impl.securityToken.AbstractInboundSecurityToken;
47  import org.apache.xml.security.stax.impl.util.IDGenerator;
48  import org.apache.xml.security.stax.securityEvent.AlgorithmSuiteSecurityEvent;
49  import org.apache.xml.security.stax.securityToken.InboundSecurityToken;
50  import org.apache.xml.security.stax.securityToken.SecurityTokenProvider;
51  
52  /**
53   * Processor for the SecurityContextToken XML Structure
54   */
55  public class DerivedKeyTokenInputHandler extends AbstractInputSecurityHeaderHandler {
56  
57      @Override
58      public void handle(final InputProcessorChain inputProcessorChain, final XMLSecurityProperties securityProperties,
59                         Deque<XMLSecEvent> eventQueue, Integer index) throws XMLSecurityException {
60  
61          @SuppressWarnings("unchecked")
62          final AbstractDerivedKeyTokenType derivedKeyTokenType =
63                  ((JAXBElement<AbstractDerivedKeyTokenType>) parseStructure(eventQueue, index, securityProperties)).getValue();
64          if (derivedKeyTokenType.getId() == null) {
65              derivedKeyTokenType.setId(IDGenerator.generateID(null));
66          }
67          if (derivedKeyTokenType.getSecurityTokenReference() == null) {
68              throw new WSSecurityException(WSSecurityException.ErrorCode.SECURITY_TOKEN_UNAVAILABLE, "noReference");
69          }
70  
71          final List<QName> elementPath = getElementPath(eventQueue);
72          final XMLSecEvent responsibleXMLSecStartXMLEvent = getResponsibleStartXMLEvent(eventQueue, index);
73  
74          SecurityTokenProvider<InboundSecurityToken> securityTokenProvider = new SecurityTokenProvider<InboundSecurityToken>() {
75  
76              private AbstractInboundSecurityToken derivedKeySecurityToken;
77  
78              @Override
79              public InboundSecurityToken getSecurityToken() throws XMLSecurityException {
80  
81                  if (this.derivedKeySecurityToken != null) {
82                      return this.derivedKeySecurityToken;
83                  }
84  
85                  //todo implement interface to access all derivedKeys? The same would be needed in UserNameToken
86                  this.derivedKeySecurityToken = new AbstractInboundSecurityToken(
87                          (WSInboundSecurityContext) inputProcessorChain.getSecurityContext(),
88                          derivedKeyTokenType.getId(), WSSecurityTokenConstants.KEYIDENTIFIER_SECURITY_TOKEN_DIRECT_REFERENCE,
89                          true) {
90  
91                      private InboundSecurityToken referencedSecurityToken;
92  
93                      private InboundSecurityToken getReferencedSecurityToken() throws XMLSecurityException {
94                          if (this.referencedSecurityToken != null) {
95                              return referencedSecurityToken;
96                          }
97  
98                          this.referencedSecurityToken = SecurityTokenFactoryImpl.getSecurityToken(
99                                  derivedKeyTokenType.getSecurityTokenReference(),
100                                 ((WSSSecurityProperties) securityProperties).getDecryptionCrypto(),
101                                 ((WSSSecurityProperties)securityProperties).getCallbackHandler(),
102                                 inputProcessorChain.getSecurityContext(),
103                                 (WSSSecurityProperties)securityProperties
104                         );
105                         this.referencedSecurityToken.addWrappedToken(this);
106                         return this.referencedSecurityToken;
107                     }
108 
109                     @Override
110                     protected Key getKey(String algorithmURI, XMLSecurityConstants.AlgorithmUsage algorithmUsage,
111                                          String correlationID) throws XMLSecurityException {
112                         byte[] secret;
113                         InboundSecurityToken referencedSecurityToken = getReferencedSecurityToken();
114                         if (referencedSecurityToken != null) {
115                             if (referencedSecurityToken instanceof UsernameSecurityToken) {
116                                 UsernameSecurityToken usernameSecurityToken = (UsernameSecurityToken) referencedSecurityToken;
117                                 secret = usernameSecurityToken.generateDerivedKey();
118                             } else {
119                                 secret = referencedSecurityToken.getSecretKey(algorithmURI, algorithmUsage, correlationID).getEncoded();
120                             }
121                         } else {
122                             throw new WSSecurityException(WSSecurityException.ErrorCode.SECURITY_TOKEN_UNAVAILABLE, "unsupportedKeyId");
123                         }
124                         byte[] nonce = derivedKeyTokenType.getNonce();
125                         if (nonce == null || nonce.length == 0) {
126                             throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN, "empty",
127                                                           new Object[] {"Missing wsc:Nonce value"});
128                         }
129                         String derivedKeyAlgorithm = derivedKeyTokenType.getAlgorithm();
130                         if (derivedKeyAlgorithm == null) {
131                             derivedKeyAlgorithm = WSSConstants.P_SHA_1;
132                         }
133                         byte[] keyBytes = DerivedKeyUtils.deriveKey(
134                                 derivedKeyAlgorithm,
135                                 derivedKeyTokenType.getLabel(),
136                                 derivedKeyTokenType.getLength().intValue(),
137                                 secret,
138                                 nonce,
139                                 derivedKeyTokenType.getOffset().intValue()
140                         );
141                         XMLSecurityConstants.AlgorithmUsage derivedKeyAlgorithmUsage;
142                         if (WSSConstants.Enc.equals(algorithmUsage)) {
143                             derivedKeyAlgorithmUsage = WSSConstants.ENC_KD;
144                         } else {
145                             derivedKeyAlgorithmUsage = WSSConstants.SIG_KD;
146                         }
147                         AlgorithmSuiteSecurityEvent algorithmSuiteSecurityEvent = new AlgorithmSuiteSecurityEvent();
148                         algorithmSuiteSecurityEvent.setAlgorithmURI(derivedKeyAlgorithm);
149                         algorithmSuiteSecurityEvent.setAlgorithmUsage(derivedKeyAlgorithmUsage);
150                         algorithmSuiteSecurityEvent.setKeyLength(keyBytes.length * 8);
151                         algorithmSuiteSecurityEvent.setCorrelationID(correlationID);
152                         inputProcessorChain.getSecurityContext().registerSecurityEvent(algorithmSuiteSecurityEvent);
153 
154                         String algo = JCEAlgorithmMapper.getJCEKeyAlgorithmFromURI(algorithmURI);
155                         return new SecretKeySpec(keyBytes, algo);
156                     }
157 
158                     @Override
159                     public InboundSecurityToken getKeyWrappingToken() throws XMLSecurityException {
160                         return getReferencedSecurityToken();
161                     }
162 
163                     @Override
164                     public WSSecurityTokenConstants.TokenType getTokenType() {
165                         return WSSecurityTokenConstants.DerivedKeyToken;
166                     }
167                 };
168                 this.derivedKeySecurityToken.setElementPath(elementPath);
169                 this.derivedKeySecurityToken.setXMLSecEvent(responsibleXMLSecStartXMLEvent);
170                 return this.derivedKeySecurityToken;
171             }
172 
173             @Override
174             public String getId() {
175                 return derivedKeyTokenType.getId();
176             }
177         };
178         inputProcessorChain.getSecurityContext().registerSecurityTokenProvider(derivedKeyTokenType.getId(), securityTokenProvider);
179 
180         //fire a tokenSecurityEvent
181         DerivedKeyTokenSecurityEvent derivedKeyTokenSecurityEvent = new DerivedKeyTokenSecurityEvent();
182         derivedKeyTokenSecurityEvent.setSecurityToken(securityTokenProvider.getSecurityToken());
183         derivedKeyTokenSecurityEvent.setCorrelationID(derivedKeyTokenType.getId());
184         inputProcessorChain.getSecurityContext().registerSecurityEvent(derivedKeyTokenSecurityEvent);
185     }
186 }