e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
281 lines
13 KiB
C#
281 lines
13 KiB
C#
//------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------
|
|
namespace System.IdentityModel.Tokens
|
|
{
|
|
using System;
|
|
using System.IdentityModel.Configuration;
|
|
using System.IdentityModel.Protocols.WSTrust;
|
|
using RSTR = System.IdentityModel.Protocols.WSTrust.RequestSecurityTokenResponse;
|
|
|
|
/// <summary>
|
|
/// This class can be used for issuing the symmetric key based token.
|
|
/// </summary>
|
|
public class SymmetricProofDescriptor : ProofDescriptor
|
|
{
|
|
byte[] _key;
|
|
int _keySizeInBits;
|
|
byte[] _sourceEntropy;
|
|
byte[] _targetEntropy;
|
|
SecurityKeyIdentifier _ski;
|
|
|
|
//
|
|
// It is for encrypting the proof token or the entropy that can decrypted
|
|
// by the token requestor
|
|
//
|
|
EncryptingCredentials _requestorWrappingCredentials;
|
|
|
|
//
|
|
// It is for encrypting the key materials inside the issued token that
|
|
// can be decrypted by the relying party
|
|
//
|
|
EncryptingCredentials _targetWrappingCredentials;
|
|
|
|
/// <summary>
|
|
/// Use this constructor if you want the sts to use the given key bytes.
|
|
/// This happens when client sends the entropy, and the sts would just use that
|
|
/// as the key for the issued token.
|
|
/// </summary>
|
|
/// <param name="key">The symmetric key that are used inside the issued token.</param>
|
|
/// <param name="targetWrappingCredentials">The key encrypting credentials for the relying party.</param>
|
|
/// <exception cref="ArgumentNullException">When the key is null.</exception>
|
|
public SymmetricProofDescriptor(byte[] key, EncryptingCredentials targetWrappingCredentials)
|
|
{
|
|
if (key == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("key");
|
|
}
|
|
|
|
_keySizeInBits = key.Length;
|
|
_key = key;
|
|
|
|
_targetWrappingCredentials = targetWrappingCredentials;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use this constructor if you want the sts to use the given <see cref="EncryptingCredentials"/>.
|
|
/// </summary>
|
|
/// <param name="targetWrappingCredentials">The <see cref="EncryptingCredentials"/> to be used.</param>
|
|
public SymmetricProofDescriptor(EncryptingCredentials targetWrappingCredentials)
|
|
: this(SecurityTokenServiceConfiguration.DefaultKeySizeInBitsConstant, targetWrappingCredentials)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use this constructor if you want to the sts to autogenerate key using random number generator and
|
|
/// send it in the proof token as binary secret.
|
|
/// </summary>
|
|
/// <param name="keySizeInBits">The size of the symmetric key.</param>
|
|
/// <param name="targetWrappingCredentials">The key encrypting credentials for the relying party.</param>
|
|
public SymmetricProofDescriptor(int keySizeInBits, EncryptingCredentials targetWrappingCredentials)
|
|
: this(keySizeInBits, targetWrappingCredentials, null)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use this constructor to have the STS autogenerate a key and
|
|
/// send it in the proof token as encrypted key. Two cases are covered here
|
|
/// 1. client sends the entropy, but server rejects it
|
|
/// 2. client did not send a entropy, so just use server's entropy
|
|
/// </summary>
|
|
/// <param name="keySizeInBits">the size of the symmetric key</param>
|
|
/// <param name="targetWrappingCredentials">The key encrypting credentials for the relying party.</param>
|
|
/// <param name="requestorWrappingCredentials">The key encrypting credentials for the requestor.</param>
|
|
/// <exception cref="ArgumentOutOfRangeException">When keySizeInBits is less than or equal to zero.</exception>
|
|
public SymmetricProofDescriptor(int keySizeInBits, EncryptingCredentials targetWrappingCredentials, EncryptingCredentials requestorWrappingCredentials)
|
|
: this(keySizeInBits, targetWrappingCredentials, requestorWrappingCredentials, (string)null)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use this constructor to have the STS autogenerate a key and
|
|
/// send it in the proof token as encrypted key. Two cases are covered here
|
|
/// 1. client sends the entropy, but server rejects it
|
|
/// 2. client did not send a entropy, so just use server's entropy
|
|
/// </summary>
|
|
/// <param name="keySizeInBits">the size of the symmetric key</param>
|
|
/// <param name="targetWrappingCredentials">The key encrypting credentials for the relying party.</param>
|
|
/// <param name="requestorWrappingCredentials">The key encrypting credentials for the requestor.</param>
|
|
/// <param name="encryptWith">The a----thm specified in the EncryptWith element of the RST.</param>
|
|
/// <exception cref="ArgumentOutOfRangeException">When keySizeInBits is less than or equal to zero.</exception>
|
|
/// <remarks>If EncryptWith is a DES algorithm, the key is guaranteed not to be a weak DES key.</remarks>
|
|
public SymmetricProofDescriptor(int keySizeInBits, EncryptingCredentials targetWrappingCredentials,
|
|
EncryptingCredentials requestorWrappingCredentials, string encryptWith)
|
|
{
|
|
_keySizeInBits = keySizeInBits;
|
|
|
|
if (encryptWith == SecurityAlgorithms.DesEncryption ||
|
|
encryptWith == SecurityAlgorithms.TripleDesEncryption ||
|
|
encryptWith == SecurityAlgorithms.TripleDesKeyWrap)
|
|
{
|
|
_key = CryptoHelper.KeyGenerator.GenerateDESKey(_keySizeInBits);
|
|
}
|
|
else
|
|
{
|
|
_key = CryptoHelper.KeyGenerator.GenerateSymmetricKey(_keySizeInBits);
|
|
}
|
|
|
|
_requestorWrappingCredentials = requestorWrappingCredentials;
|
|
_targetWrappingCredentials = targetWrappingCredentials;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use this constructor if you want to send combined entropy.
|
|
/// </summary>
|
|
/// <param name="keySizeInBits">The size of the symmetric key.</param>
|
|
/// <param name="targetWrappingCredentials">The encrypting credentials for the relying party used to encrypt the key in the SecurityKeyIdentifier property.</param>
|
|
/// <param name="requestorWrappingCredentials">The encrypting credentials for the requestor used to encrypt the entropy or the proof token.</param>
|
|
/// <param name="sourceEntropy">The requestor's entropy.</param>
|
|
/// <exception cref="ArgumentOutOfRangeException">When keySizeInBits is less than or equal to zero.</exception>
|
|
/// <exception cref="ArgumentNullException">When source entorpy is null or is an empty array.</exception>
|
|
public SymmetricProofDescriptor(int keySizeInBits, EncryptingCredentials targetWrappingCredentials,
|
|
EncryptingCredentials requestorWrappingCredentials, byte[] sourceEntropy)
|
|
: this(keySizeInBits, targetWrappingCredentials, requestorWrappingCredentials, sourceEntropy, null)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use this constructor to send combined entropy.
|
|
/// </summary>
|
|
/// <param name="keySizeInBits">The size of the symmetric key.</param>
|
|
/// <param name="targetWrappingCredentials">The encrypting credentials for the relying party used to encrypt the key in the SecurityKeyIdentifier property.</param>
|
|
/// <param name="requestorWrappingCredentials">The encrypting credentials for the requestor used to encrypt the entropy or the proof token.</param>
|
|
/// <param name="sourceEntropy">The requestor's entropy.</param>
|
|
/// <param name="encryptWith">The algorithm Uri using which to encrypt the proof key.</param>
|
|
/// <exception cref="ArgumentOutOfRangeException">When keySizeInBits is less than or equal to zero.</exception>
|
|
/// <exception cref="ArgumentNullException">When source entorpy is null or is an empty array.</exception>
|
|
public SymmetricProofDescriptor(int keySizeInBits, EncryptingCredentials targetWrappingCredentials,
|
|
EncryptingCredentials requestorWrappingCredentials, byte[] sourceEntropy, string encryptWith)
|
|
{
|
|
if (sourceEntropy == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("sourceEntropy");
|
|
}
|
|
|
|
if (sourceEntropy.Length == 0)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("sourceEntropy", SR.GetString(SR.ID2058));
|
|
}
|
|
|
|
_keySizeInBits = keySizeInBits;
|
|
_sourceEntropy = sourceEntropy;
|
|
//
|
|
// Generate proof key using sender entropy
|
|
//
|
|
if (encryptWith == SecurityAlgorithms.DesEncryption ||
|
|
encryptWith == SecurityAlgorithms.TripleDesEncryption ||
|
|
encryptWith == SecurityAlgorithms.TripleDesKeyWrap)
|
|
{
|
|
_key = CryptoHelper.KeyGenerator.GenerateDESKey(_keySizeInBits, _sourceEntropy, out _targetEntropy);
|
|
}
|
|
else
|
|
{
|
|
_key = CryptoHelper.KeyGenerator.GenerateSymmetricKey(_keySizeInBits, _sourceEntropy, out _targetEntropy);
|
|
}
|
|
|
|
//
|
|
// Set up the wrapping credentials
|
|
//
|
|
_requestorWrappingCredentials = requestorWrappingCredentials;
|
|
_targetWrappingCredentials = targetWrappingCredentials;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the key bytes.
|
|
/// </summary>
|
|
public byte[] GetKeyBytes()
|
|
{
|
|
return _key;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the requestor's encrypting credentials, which may be used to encrypt the
|
|
/// requested proof token or the entropy in the response.
|
|
/// </summary>
|
|
protected EncryptingCredentials RequestorEncryptingCredentials
|
|
{
|
|
get { return _requestorWrappingCredentials; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the source entropy in plain bytes.
|
|
/// </summary>
|
|
protected byte[] GetSourceEntropy()
|
|
{
|
|
return _sourceEntropy;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the target entropy in plain bytes.
|
|
/// </summary>
|
|
protected byte[] GetTargetEntropy()
|
|
{
|
|
return _targetEntropy;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the relying party encrypting credentials, which may be used to encrypt the
|
|
/// requested security token in the response.
|
|
/// </summary>
|
|
protected EncryptingCredentials TargetEncryptingCredentials
|
|
{
|
|
get { return _targetWrappingCredentials; }
|
|
}
|
|
|
|
#region ProofDescriptor Overrides
|
|
|
|
/// <summary>
|
|
/// Sets the appropriate things, such as requested proof token, inside the RSTR
|
|
/// based on what is inside the proof descriptor instance.
|
|
/// </summary>
|
|
/// <param name="response">The RSTR object that this proof descriptor needs to modify.</param>
|
|
/// <exception cref="ArgumentNullException">When the response is null.</exception>
|
|
public override void ApplyTo(RSTR response)
|
|
{
|
|
if (response == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("response");
|
|
}
|
|
|
|
if (_targetEntropy != null)
|
|
{
|
|
//
|
|
// When there is target entropy, then we will send back a computedKeyalgorithm
|
|
// in the proof token case and send the entropy as response.Entropy. By default, this
|
|
// class is doing Psha1.
|
|
//
|
|
response.RequestedProofToken = new RequestedProofToken(ComputedKeyAlgorithms.Psha1);
|
|
response.KeySizeInBits = _keySizeInBits;
|
|
response.Entropy = new Entropy(_targetEntropy, _requestorWrappingCredentials);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// When there is no target entroypy, then we will send back the key either in
|
|
// binary secret format or in the encrypted key format
|
|
//
|
|
response.RequestedProofToken = new RequestedProofToken(_key, _requestorWrappingCredentials);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the key identifier that can be used inside issued to define the key.
|
|
/// It is usually the binary secret or the encrypted key.
|
|
/// </summary>
|
|
public override SecurityKeyIdentifier KeyIdentifier
|
|
{
|
|
get
|
|
{
|
|
if (_ski == null)
|
|
{
|
|
_ski = CryptoHelper.KeyGenerator.GetSecurityKeyIdentifier(_key, _targetWrappingCredentials);
|
|
}
|
|
|
|
return _ski;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|