/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.cxf.sts.token.provider; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.cxf.common.logging.LogUtils; import org.apache.cxf.sts.STSConstants; import org.apache.cxf.sts.STSPropertiesMBean; import org.apache.cxf.sts.SignatureProperties; import org.apache.cxf.sts.request.BinarySecret; import org.apache.cxf.sts.request.Entropy; import org.apache.cxf.sts.request.KeyRequirements; import org.apache.cxf.ws.security.sts.provider.STSException; import org.apache.wss4j.common.derivedKey.P_SHA1; import org.apache.wss4j.common.ext.WSSecurityException; import org.apache.wss4j.dom.WSConstants; import org.apache.wss4j.dom.util.WSSecurityUtil; /** * Some common functionality relating to parsing and generating Symmetric Keys. */ public class SymmetricKeyHandler { private static final Logger LOG = LogUtils.getL7dLogger(SymmetricKeyHandler.class); private int keySize = 256; private Entropy clientEntropy; private byte[] entropyBytes; private byte[] secret; private boolean computedKey; public SymmetricKeyHandler(TokenProviderParameters tokenParameters) { KeyRequirements keyRequirements = tokenParameters.getKeyRequirements(); keySize = Long.valueOf(keyRequirements.getKeySize()).intValue(); STSPropertiesMBean stsProperties = tokenParameters.getStsProperties(); SignatureProperties signatureProperties = stsProperties.getSignatureProperties(); // Test EncryptWith String encryptWith = keyRequirements.getEncryptWith(); if (encryptWith != null) { if ((WSConstants.AES_128.equals(encryptWith) || WSConstants.AES_128_GCM.equals(encryptWith)) && keySize < 128) { keySize = 128; } else if ((WSConstants.AES_192.equals(encryptWith) || WSConstants.AES_192_GCM.equals(encryptWith)) && keySize < 192) { keySize = 192; } else if ((WSConstants.AES_256.equals(encryptWith) || WSConstants.AES_256_GCM.equals(encryptWith)) && keySize < 256) { keySize = 256; } else if (WSConstants.TRIPLE_DES.equals(encryptWith) && keySize < 192) { keySize = 192; } } // Test KeySize if (keySize < signatureProperties.getMinimumKeySize() || keySize > signatureProperties.getMaximumKeySize()) { keySize = Long.valueOf(signatureProperties.getKeySize()).intValue(); LOG.log( Level.WARNING, "Received KeySize of " + keyRequirements.getKeySize() + " not accepted so defaulting to " + signatureProperties.getKeySize() ); } // Test Entropy clientEntropy = keyRequirements.getEntropy(); if (clientEntropy == null) { LOG.log(Level.WARNING, "A SymmetricKey KeyType is requested, but no client entropy is provided"); } else if (clientEntropy.getBinarySecret() != null) { BinarySecret binarySecret = clientEntropy.getBinarySecret(); if (STSConstants.NONCE_TYPE.equals(binarySecret.getBinarySecretType())) { byte[] nonce = binarySecret.getBinarySecretValue(); if (nonce == null || (nonce.length < (keySize / 8))) { LOG.log(Level.WARNING, "User Entropy rejected"); clientEntropy = null; } String computedKeyAlgorithm = keyRequirements.getComputedKeyAlgorithm(); if (!STSConstants.COMPUTED_KEY_PSHA1.equals(computedKeyAlgorithm)) { LOG.log( Level.WARNING, "The computed key algorithm of " + computedKeyAlgorithm + " is not supported" ); throw new STSException( "Computed Key Algorithm not supported", STSException.INVALID_REQUEST ); } } else if (STSConstants.SYMMETRIC_KEY_TYPE.equals(binarySecret.getBinarySecretType()) || binarySecret.getBinarySecretType() == null) { byte[] secretValue = binarySecret.getBinarySecretValue(); if (((long)secretValue.length * 8L) < signatureProperties.getMinimumKeySize() || ((long)secretValue.length * 8L) > signatureProperties.getMaximumKeySize()) { LOG.log( Level.WARNING, "Received secret of length " + secretValue.length + " bits is not accepted" ); LOG.log(Level.WARNING, "User Entropy rejected"); clientEntropy = null; } } else { LOG.log( Level.WARNING, "The type " + binarySecret.getBinarySecretType() + " is not supported" ); throw new STSException( "No user supplied entropy for SymmetricKey case", STSException.INVALID_REQUEST ); } } else if (clientEntropy.getDecryptedKey() != null) { byte[] secretValue = clientEntropy.getDecryptedKey(); if (((long)secretValue.length * 8L) < signatureProperties.getMinimumKeySize() || ((long)secretValue.length * 8L) > signatureProperties.getMaximumKeySize()) { LOG.log( Level.WARNING, "Received secret of length " + secretValue.length + " bits is not accepted" ); LOG.log(Level.WARNING, "User Entropy rejected"); clientEntropy = null; } } else { LOG.log(Level.WARNING, "The user supplied Entropy structure is invalid"); throw new STSException( "The user supplied Entropy structure is invalid", STSException.INVALID_REQUEST ); } } /** * Create the Symmetric Key */ public void createSymmetricKey() { computedKey = false; boolean generateEntropy = true; if (clientEntropy != null) { BinarySecret binarySecret = clientEntropy.getBinarySecret(); if (binarySecret != null && (STSConstants.SYMMETRIC_KEY_TYPE.equals(binarySecret.getBinarySecretType()) || binarySecret.getBinarySecretType() == null)) { secret = binarySecret.getBinarySecretValue(); generateEntropy = false; } else if (clientEntropy.getDecryptedKey() != null) { secret = clientEntropy.getDecryptedKey(); generateEntropy = false; } } if (generateEntropy) { try { entropyBytes = WSSecurityUtil.generateNonce(keySize / 8); secret = entropyBytes; } catch (WSSecurityException ex) { LOG.log(Level.WARNING, "", ex); throw new STSException("Error in creating symmetric key", ex, STSException.INVALID_REQUEST); } if (clientEntropy != null && clientEntropy.getBinarySecret() != null) { byte[] nonce = clientEntropy.getBinarySecret().getBinarySecretValue(); try { P_SHA1 psha1 = new P_SHA1(); secret = psha1.createKey(nonce, entropyBytes, 0, keySize / 8); computedKey = true; } catch (WSSecurityException ex) { LOG.log(Level.WARNING, "", ex); throw new STSException("Error in creating symmetric key", STSException.INVALID_REQUEST); } } } } /** * Get the KeySize. */ public long getKeySize() { return keySize; } /** * Get the Entropy bytes */ public byte[] getEntropyBytes() { return entropyBytes; } /** * Get the secret */ public byte[] getSecret() { return secret; } /** * Get whether this is a computed key or not */ public boolean isComputedKey() { return computedKey; } }