//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ using System; using System.IdentityModel.Selectors; namespace System.IdentityModel.Tokens { /// /// SecurityKeyElement provides delayed resolution of security keys by resolving the SecurityKeyIdentifierClause or SecurityKeyIdentifier /// only when cryptographic functions are needed. This allows a key clause or identifier that is never used by an application /// to be serialized and deserialzied on and off the wire without issue. /// public class SecurityKeyElement : SecurityKey { SecurityKey _securityKey; object _keyLock; SecurityTokenResolver _securityTokenResolver; SecurityKeyIdentifier _securityKeyIdentifier; /// /// Constructor to use when working with SecurityKeyIdentifierClauses /// /// SecurityKeyIdentifierClause that represents a SecuriytKey /// SecurityTokenResolver that can be resolved to a SecurityKey /// Thrown if the 'clause' is null public SecurityKeyElement(SecurityKeyIdentifierClause securityKeyIdentifierClause, SecurityTokenResolver securityTokenResolver) { if (securityKeyIdentifierClause == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("securityKeyIdentifierClause"); } Initialize(new SecurityKeyIdentifier(securityKeyIdentifierClause), securityTokenResolver); } /// /// Constructor to use when working with SecurityKeyIdentifiers /// /// SecurityKeyIdentifier that represents a SecuriytKey /// SecurityTokenResolver that can be resolved to a SecurityKey /// Thrown if the 'securityKeyIdentifier' is null public SecurityKeyElement(SecurityKeyIdentifier securityKeyIdentifier, SecurityTokenResolver securityTokenResolver) { if (securityKeyIdentifier == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("securityKeyIdentifier"); } Initialize(securityKeyIdentifier, securityTokenResolver); } void Initialize(SecurityKeyIdentifier securityKeyIdentifier, SecurityTokenResolver securityTokenResolver) { _keyLock = new object(); _securityKeyIdentifier = securityKeyIdentifier; _securityTokenResolver = securityTokenResolver; } /// /// Decrypts a key using the specified algorithm. /// /// Algorithm to use when decrypting the key. /// Bytes representing the encrypted key. /// Decrypted bytes. public override byte[] DecryptKey(string algorithm, byte[] keyData) { if (_securityKey == null) { ResolveKey(); } return _securityKey.DecryptKey(algorithm, keyData); } /// /// Encrypts a key using the specified algorithm. /// /// Algorithm to use when encrypting the key. /// Bytes representing the key. /// Encrypted bytes. public override byte[] EncryptKey(string algorithm, byte[] keyData) { if (_securityKey == null) { ResolveKey(); } return _securityKey.EncryptKey(algorithm, keyData); } /// /// Answers question: is the algorithm Asymmetric. /// /// Algorithm to check. /// True if algorithm will be processed by runtime as Asymmetric. public override bool IsAsymmetricAlgorithm(string algorithm) { // Copied from System.IdentityModel.CryptoHelper // no need to ResolveKey switch (algorithm) { case SecurityAlgorithms.DsaSha1Signature: case SecurityAlgorithms.RsaSha1Signature: case SecurityAlgorithms.RsaSha256Signature: case SecurityAlgorithms.RsaOaepKeyWrap: case SecurityAlgorithms.RsaV15KeyWrap: return true; default: return false; } } /// /// Answers question: is the algorithm is supported by this key. /// /// Algorithm to check. /// True if algorithm is supported by this key. public override bool IsSupportedAlgorithm(string algorithm) { if (_securityKey == null) { ResolveKey(); } return _securityKey.IsSupportedAlgorithm(algorithm); } /// /// Answers question: is the algorithm Symmetric. /// /// Algorithm to check. /// True if algorithm will be processed by runtime as Symmetric. public override bool IsSymmetricAlgorithm(string algorithm) { // Copied from System.IdentityModel.CryptoHelper // no need to ResolveKey. switch (algorithm) { case SecurityAlgorithms.DsaSha1Signature: case SecurityAlgorithms.RsaSha1Signature: case SecurityAlgorithms.RsaSha256Signature: case SecurityAlgorithms.RsaOaepKeyWrap: case SecurityAlgorithms.RsaV15KeyWrap: return false; case SecurityAlgorithms.HmacSha1Signature: case SecurityAlgorithms.HmacSha256Signature: case SecurityAlgorithms.Aes128Encryption: case SecurityAlgorithms.Aes192Encryption: case SecurityAlgorithms.Aes256Encryption: case SecurityAlgorithms.TripleDesEncryption: case SecurityAlgorithms.Aes128KeyWrap: case SecurityAlgorithms.Aes192KeyWrap: case SecurityAlgorithms.Aes256KeyWrap: case SecurityAlgorithms.TripleDesKeyWrap: case SecurityAlgorithms.Psha1KeyDerivation: case SecurityAlgorithms.Psha1KeyDerivationDec2005: return true; default: return false; } } /// /// Gets the key size in bits. /// /// Key size in bits. public override int KeySize { get { if (_securityKey == null) { ResolveKey(); } return _securityKey.KeySize; } } /// /// Attempts to resolve the _securityKeyIdentifier into a securityKey. If successful, the private _securityKey is set. /// Uses the tokenresolver that was passed in, it may be the case a keyIdentifier can /// generate a securityKey. A RSA key can generate a key with just the public part. /// /// void void ResolveKey() { if (_securityKeyIdentifier == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("ski"); } if (_securityKey == null) { lock (_keyLock) { if (_securityKey == null) { if (_securityTokenResolver != null) { for (int i = 0; i < _securityKeyIdentifier.Count; ++i) { if (_securityTokenResolver.TryResolveSecurityKey(_securityKeyIdentifier[i], out _securityKey)) { return; } } } // most likely a public key, do this last if (_securityKeyIdentifier.CanCreateKey) { _securityKey = _securityKeyIdentifier.CreateKey(); return; } throw DiagnosticUtility.ExceptionUtility.ThrowHelper( new SecurityTokenException(SR.GetString(SR.ID2080, _securityTokenResolver == null ? "null" : _securityTokenResolver.ToString(), _securityKeyIdentifier == null ? "null" : _securityKeyIdentifier.ToString())), System.Diagnostics.TraceEventType.Error); } } } } } }