Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add X509EncryptedCredentials class #1000

Merged
merged 1 commit into from
Aug 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 58 additions & 23 deletions src/Microsoft.IdentityModel.Tokens/EncryptingCredentials.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,67 +25,102 @@
//
//------------------------------------------------------------------------------

using System;
using System.Security.Cryptography.X509Certificates;
using Microsoft.IdentityModel.Logging;

namespace Microsoft.IdentityModel.Tokens
{
/// <summary>
/// A wrapper class for properties that are used for token encryption.
/// A class for properties that are used for token encryption.
/// </summary>
public class EncryptingCredentials
{
private string _alg;
private string _enc;
private SecurityKey _key;

/// <summary>
/// Initializes a new instance of the <see cref="EncryptingCredentials"/> class.
/// </summary>
/// <param name="key"><see cref="SecurityKey"/></param>
/// <param name="alg">The key encryption algorithm to apply.</param>
/// <param name="enc">The encryption algorithm to apply.</param>
public EncryptingCredentials(SecurityKey key, string alg, string enc)
/// <param name="certificate"><see cref="X509Certificate2"/>.</param>
/// <param name="alg">A key wrap algorithm to use when encrypting a session key.</param>
/// <param name="enc">Data encryption algorithm to apply.</param>
/// <exception cref="ArgumentNullException">if 'certificate' is null.</exception>
/// <exception cref="ArgumentNullException">if 'alg' is null or empty.</exception>
/// <exception cref="ArgumentNullException">if 'enc' is null or empty.</exception>
protected EncryptingCredentials(X509Certificate2 certificate, string alg, string enc)
{
if (key == null)
throw LogHelper.LogArgumentNullException(nameof(key));

if (string.IsNullOrWhiteSpace(alg))
throw LogHelper.LogArgumentNullException(nameof(alg));

if (string.IsNullOrWhiteSpace(enc))
throw LogHelper.LogArgumentNullException(nameof(enc));
if (certificate == null)
throw LogHelper.LogArgumentNullException(nameof(certificate));

Key = new X509SecurityKey(certificate);
Alg = alg;
Enc = enc;
}

/// <summary>
/// Initializes a new instance of the <see cref="EncryptingCredentials"/> class.
/// </summary>
/// <param name="key"><see cref="SecurityKey"/> to use when encrypting a session key.</param>
/// <param name="alg">A key wrap algorithm to use when encrypting a session key.</param>
/// <param name="enc">Data encryption algorithm to apply.</param>
/// <exception cref="ArgumentNullException">if 'key' is null.</exception>
/// <exception cref="ArgumentNullException">if 'alg' is null or empty.</exception>
/// <exception cref="ArgumentNullException">if 'enc' is null or empty.</exception>
public EncryptingCredentials(SecurityKey key, string alg, string enc)
{
Key = key;
Alg = alg;
Enc = enc;
}

/// <summary>
/// Initializes a new instance of the <see cref="EncryptingCredentials"/> class.
/// </summary>
/// <remarks> Used in scenarios when a key represents a 'shared' symmetric key.
/// For example, SAML 2.0 Assertion will be encrypted using a provided symmetric key
/// which won't be serialized to a SAML token.
/// </remarks>
/// <param name="key"><see cref="SymmetricSecurityKey"/> to apply.</param>
/// <param name="enc">Data encryption algorithm to apply.</param>
/// <exception cref="ArgumentException">If the <see cref="SecurityKey"/> is not a <see cref="SymmetricSecurityKey"/>.</exception>
/// <exception cref="ArgumentNullException">if 'enc' is null or empty.</exception>
public EncryptingCredentials(SymmetricSecurityKey key, string enc)
: this(key, SecurityAlgorithms.None, enc)
{
}

/// <summary>
/// Gets the algorithm which used for token encryption.
/// Gets the key wrap algorithm used for session key encryption.
/// </summary>
public string Alg
{
get;
private set;
get => _alg;
private set => _alg = string.IsNullOrEmpty(value) ? throw LogHelper.LogArgumentNullException("alg") : value;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe pass in nameof(value) instead of "alg" to LogArgumentNullException()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it makes sense as the resulting log message would look something like this:
IDX10000: The parameter value cannot be a 'null' or an empty object.

Using reflection, we can get names of parameters from a constructor but I don't believe that is a good solution.


/// <summary>
/// Gets the algorithm which used for token encryption.
/// Gets the data encryption algorithm.
/// </summary>
public string Enc
{
get;
private set;
get => _enc;
private set => _enc = string.IsNullOrEmpty(value) ? throw LogHelper.LogArgumentNullException("enc") : value;
}

/// <summary>
/// Users can override the default <see cref="CryptoProviderFactory"/> with this property. This factory will be used for creating encryition providers.
/// Users can override the default <see cref="CryptoProviderFactory"/> with this property. This factory will be used for creating encryption providers.
/// </summary>
public CryptoProviderFactory CryptoProviderFactory { get; set; }

/// <summary>
/// Gets the <see cref="SecurityKey"/> which used for signature valdiation.
/// Gets the <see cref="SecurityKey"/> used for encryption.
/// </summary>
public SecurityKey Key
{
get;
private set;
get => _key;
private set => _key = value ?? throw LogHelper.LogArgumentNullException("key");
}
}
}
3 changes: 3 additions & 0 deletions src/Microsoft.IdentityModel.Tokens/SecurityAlgorithms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ public static class SecurityAlgorithms
public const string Aes192CbcHmacSha384 = "A192CBC-HS384";
public const string Aes256CbcHmacSha512 = "A256CBC-HS512";

internal const string DefaultAsymmetricKeyWrapAlgorithm = RsaOaepKeyWrap;
internal const string DefaultSymmetricEncryptionAlgorithm = Aes128CbcHmacSha256;

#pragma warning restore 1591
}
}
76 changes: 76 additions & 0 deletions src/Microsoft.IdentityModel.Tokens/X509EncryptingCredentials.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//------------------------------------------------------------------------------

using System;
using System.Security.Cryptography.X509Certificates;

namespace Microsoft.IdentityModel.Tokens
{
/// <summary>
/// An <see cref="X509EncryptingCredentials"/> designed to construct <see cref="EncryptingCredentials"/> based on a x509 certificate.
/// </summary>
public class X509EncryptingCredentials : EncryptingCredentials
{
/// <summary>
/// Designed to construct <see cref="EncryptingCredentials"/> based on a x509 certificate.
/// </summary>
/// <param name="certificate">A <see cref="X509Certificate2"/></param>
/// <remarks>
/// <see cref="SecurityAlgorithms.DefaultAsymmetricKeyWrapAlgorithm"/> will be used as the key wrap algorithm
/// <see cref="SecurityAlgorithms.DefaultSymmetricEncryptionAlgorithm"/> will be used as the data encryption algorithm
/// </remarks>
/// <exception cref="ArgumentNullException">if 'certificate' is null.</exception>
public X509EncryptingCredentials(X509Certificate2 certificate)
: this(certificate, SecurityAlgorithms.DefaultAsymmetricKeyWrapAlgorithm, SecurityAlgorithms.DefaultSymmetricEncryptionAlgorithm)
{
}

/// <summary>
/// Designed to construct <see cref="EncryptingCredentials"/> based on the x509 certificate, a key wrap algorithm, and data encryption algorithm.
/// </summary>
/// <param name="certificate">A <see cref="X509Certificate2"/></param>
/// <param name="keyWrapAlgorithm">A key wrap algorithm</param>
/// <param name="dataEncryptionAlgorithm">Data encryption algorithm</param>
/// <exception cref="ArgumentNullException">if 'certificate' is null.</exception>
/// <exception cref="ArgumentNullException">if 'keyWrapAlgorithm' is null or empty.</exception>
/// <exception cref="ArgumentNullException">if 'dataEncryptionAlgorithm' is null or empty.</exception>
public X509EncryptingCredentials(X509Certificate2 certificate, string keyWrapAlgorithm, string dataEncryptionAlgorithm)
: base(certificate, keyWrapAlgorithm, dataEncryptionAlgorithm)
{
Certificate = certificate;
}

/// <summary>
/// Gets the <see cref="X509Certificate2"/> used by this instance.
/// </summary>
public X509Certificate2 Certificate
{
get;
private set;
}
}
}
5 changes: 5 additions & 0 deletions test/Microsoft.IdentityModel.Tests/Default.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ public static SecurityKey AsymmetricSigningKeyPublic
get => new X509SecurityKey(KeyingMaterial.DefaultCert_2048_Public);
}

public static SecurityKey AsymmetricEncryptionKeyPublic
{
get => new X509SecurityKey(KeyingMaterial.DefaultCert_2048_Public);
}

#if !CrossVersionTokenValidation
public static TokenValidationParameters AsymmetricEncryptSignTokenValidationParameters
{
Expand Down
8 changes: 8 additions & 0 deletions test/Microsoft.IdentityModel.Tests/TestUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,14 @@ public static void CheckForArgumentNull(CompareContext context, string name, Exc
context.Diffs.Add($"!(ex is ArgumentNullException) || !ex.Message.Contains({name})");
}

public static void CheckForArgumentException(CompareContext context, string name, Exception ex)
{
if (ex == null)
context.Diffs.Add($"expecting ArgumentException for parameter {name}. Exception is null.");
else if (!(ex is ArgumentException) || !ex.Message.Contains(name))
context.Diffs.Add($"!(ex is ArgumentException) || !ex.Message.Contains({name})");
}

public static byte[] HexToByteArray(string hexString)
{
byte[] bytes = new byte[hexString.Length / 2];
Expand Down
Loading