blob: f3605811bf319a77db50fc0f7af079eae363dcc1 [file] [log] [blame]
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.ws.security.processor;
import org.apache.ws.security.WSDocInfo;
import org.apache.ws.security.WSPasswordCallback;
import org.apache.ws.security.WSSConfig;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.conversation.ConversationConstants;
import org.apache.ws.security.conversation.dkalgo.AlgoFactory;
import org.apache.ws.security.conversation.dkalgo.DerivationAlgorithm;
import org.apache.ws.security.message.token.DerivedKeyToken;
import org.apache.ws.security.message.token.Reference;
import org.apache.ws.security.message.token.SecurityTokenReference;
import org.apache.ws.security.saml.SAMLKeyInfo;
import org.apache.ws.security.saml.SAMLUtil;
import org.apache.ws.security.util.Base64;
import org.w3c.dom.Element;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;
import java.util.Vector;
/**
* The processor to process <code>wsc:DerivedKeyToken</code>.
*
* @author Ruchith Fernando (ruchith.fernando@gmail.com)
*/
public class DerivedKeyTokenProcessor implements Processor {
private String id;
private byte[] keyBytes;
private byte[] secret;
private int length;
private int offset;
private byte[] nonce;
private String label;
private String algorithm;
public void handleToken(Element elem, Crypto crypto, Crypto decCrypto,
CallbackHandler cb, WSDocInfo wsDocInfo, Vector returnResults,
WSSConfig config) throws WSSecurityException {
//Deserialize the DKT
DerivedKeyToken dkt = new DerivedKeyToken(elem);
this.extractSecret(wsDocInfo, dkt, cb, crypto);
String tempNonce = dkt.getNonce();
if(tempNonce == null) {
throw new WSSecurityException("Missing wsc:Nonce value");
}
this.nonce = Base64.decode(tempNonce);
this.length = dkt.getLength();
this.label = dkt.getLabel();
this.algorithm = dkt.getAlgorithm();
this.id = dkt.getID();
if(length > 0) {
this.deriveKey();
}
}
private void deriveKey() throws WSSecurityException{
try {
DerivationAlgorithm algo = AlgoFactory.getInstance(this.algorithm);
byte[] labelBytes = null;
if(label == null || (label != null && label.length() == 0)) {
labelBytes = (ConversationConstants.DEFAULT_LABEL + ConversationConstants.DEFAULT_LABEL)
.getBytes("UTF-8");
} else {
labelBytes = this.label.getBytes("UTF-8");
}
byte[] seed = new byte[labelBytes.length + nonce.length];
System.arraycopy(labelBytes, 0, seed, 0, labelBytes.length);
System.arraycopy(nonce, 0, seed, labelBytes.length, nonce.length);
this.keyBytes = algo.createKey(this.secret, seed, offset, length);
} catch (Exception e) {
throw new WSSecurityException(
WSSecurityException.FAILURE, null, null, e
);
}
}
/**
* @param wsDocInfo
* @param dkt
* @throws WSSecurityException
*/
private void extractSecret(WSDocInfo wsDocInfo, DerivedKeyToken dkt, CallbackHandler cb, Crypto crypto)
throws WSSecurityException {
SecurityTokenReference str = dkt.getSecurityTokenReference();
if (str != null) {
Processor processor;
String uri = null;
String keyIdentifierValueType = null;
String keyIdentifierValue = null;
if(str.containsReference()) {
Reference ref = str.getReference();
uri = ref.getURI();
processor = wsDocInfo.getProcessor(uri.substring(1));
} else {
//Contains key identifier
keyIdentifierValue = str.getKeyIdentifierValue();
keyIdentifierValueType = str.getKeyIdentifierValueType();
processor = wsDocInfo.getProcessor(keyIdentifierValue);
}
if(processor == null && uri != null) {
//Now use the callback and get it
this.secret = this.getSecret(cb, uri.substring(1));
} else if (processor == null && keyIdentifierValue != null
&& keyIdentifierValueType != null) {
this.secret = this.getSecret(cb, keyIdentifierValue, keyIdentifierValueType);
} else if (processor instanceof EncryptedKeyProcessor) {
this.secret = ((EncryptedKeyProcessor) processor)
.getDecryptedBytes();
} else if (processor instanceof SecurityContextTokenProcessor) {
this.secret = ((SecurityContextTokenProcessor) processor)
.getSecret();
} else if (processor instanceof SAMLTokenProcessor) {
SAMLTokenProcessor samlp = (SAMLTokenProcessor) processor;
SAMLKeyInfo keyInfo = SAMLUtil.getSAMLKeyInfo(samlp
.getSamlTokenElement(), crypto, cb);
//TODO Handle malformed SAML tokens where they don't have the
//secret in them
this.secret = keyInfo.getSecret();
} else {
throw new WSSecurityException(
WSSecurityException.FAILED_CHECK, "unsupportedKeyId");
}
} else {
throw new WSSecurityException(WSSecurityException.FAILED_CHECK,
"noReference");
}
}
private byte[] getSecret(CallbackHandler cb, String id)
throws WSSecurityException {
if (cb == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noCallback");
}
WSPasswordCallback callback = new WSPasswordCallback(id, WSPasswordCallback.SECURITY_CONTEXT_TOKEN);
Callback[] callbacks = new Callback[1];
callbacks[0] = callback;
try {
cb.handle(callbacks);
} catch (IOException e) {
throw new WSSecurityException(WSSecurityException.FAILURE, "noKey",
new Object[] { id }, e);
} catch (UnsupportedCallbackException e) {
throw new WSSecurityException(WSSecurityException.FAILURE, "noKey",
new Object[] { id }, e);
}
return callback.getKey();
}
private byte[] getSecret(CallbackHandler cb, String keyIdentifierValue, String keyIdentifierType)
throws WSSecurityException {
if (cb == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noCallback");
}
WSPasswordCallback pwcb = null;
//Handle the EncryptedKeySHA1 type key references
if (keyIdentifierType.equals
(SecurityTokenReference.ENC_KEY_SHA1_URI)) {
pwcb = new WSPasswordCallback(keyIdentifierValue,
WSPasswordCallback.ENCRYPTED_KEY_TOKEN);
try {
cb.handle(new Callback[]{pwcb});
} catch (IOException e) {
throw new WSSecurityException(WSSecurityException.FAILURE, "noKey",
new Object[] { id }, e);
} catch (UnsupportedCallbackException e) {
throw new WSSecurityException(WSSecurityException.FAILURE, "noKey",
new Object[] { id }, e);
}
}
return pwcb.getKey();
}
/**
* Returns the wsu:Id of the DerivedKeyToken
* @see org.apache.ws.security.processor.Processor#getId()
*/
public String getId() {
return this.id;
}
/**
* @return Returns the keyBytes.
*/
public byte[] getKeyBytes() {
return keyBytes;
}
/**
* Get the derived key bytes for a given length
* @return Returns the keyBytes.
*/
public byte[] getKeyBytes(int len) throws WSSecurityException {
this.length = len;
this.deriveKey();
return keyBytes;
}
}