Skip to content

Commit e9fe530

Browse files
committed
Add X509EncryptedCredentials class
If only a certificate is provided, the key wrap algorithm and data encryption algorithm will be set by default to RsaOaepKeyWrap and A128CBC-HS256, respectively. * Add new ctor to EncryptingCredentials to allow users to pass only a 'shared' symmetric key which will be used to encrypt data, but it will not be serialized to a SAML token. * Add internal const strings DefaultAsymmetricKeyWrapAlgorithm and DefaultSymmetricEncryptionAlgorithm to indicate default algorithms used for key wrap and data encryption * Add protected ctor to EncryptingCredentials to check if a certificate passed to X509EncryptedCredentials is null. Provides cleaner stack trace in case of an exception caused by a null cert. * Refactor EncryptingCredentials. Move null/empty checks to setters and provide clearer comments * Add tests for X509EncryiptingCredentials and EncryptingCredentials classes Resolves: #995 See also: #734
1 parent 236bf92 commit e9fe530

File tree

7 files changed

+449
-23
lines changed

7 files changed

+449
-23
lines changed

src/Microsoft.IdentityModel.Tokens/EncryptingCredentials.cs

+58-23
Original file line numberDiff line numberDiff line change
@@ -25,67 +25,102 @@
2525
//
2626
//------------------------------------------------------------------------------
2727

28+
using System;
29+
using System.Security.Cryptography.X509Certificates;
2830
using Microsoft.IdentityModel.Logging;
2931

3032
namespace Microsoft.IdentityModel.Tokens
3133
{
3234
/// <summary>
33-
/// A wrapper class for properties that are used for token encryption.
35+
/// A class for properties that are used for token encryption.
3436
/// </summary>
3537
public class EncryptingCredentials
3638
{
39+
private string _alg;
40+
private string _enc;
41+
private SecurityKey _key;
42+
3743
/// <summary>
3844
/// Initializes a new instance of the <see cref="EncryptingCredentials"/> class.
3945
/// </summary>
40-
/// <param name="key"><see cref="SecurityKey"/></param>
41-
/// <param name="alg">The key encryption algorithm to apply.</param>
42-
/// <param name="enc">The encryption algorithm to apply.</param>
43-
public EncryptingCredentials(SecurityKey key, string alg, string enc)
46+
/// <param name="certificate"><see cref="X509Certificate2"/>.</param>
47+
/// <param name="alg">A key wrap algorithm to use when encrypting a session key.</param>
48+
/// <param name="enc">Data encryption algorithm to apply.</param>
49+
/// <exception cref="ArgumentNullException">if 'certificate' is null.</exception>
50+
/// <exception cref="ArgumentNullException">if 'alg' is null or empty.</exception>
51+
/// <exception cref="ArgumentNullException">if 'enc' is null or empty.</exception>
52+
protected EncryptingCredentials(X509Certificate2 certificate, string alg, string enc)
4453
{
45-
if (key == null)
46-
throw LogHelper.LogArgumentNullException(nameof(key));
47-
48-
if (string.IsNullOrWhiteSpace(alg))
49-
throw LogHelper.LogArgumentNullException(nameof(alg));
50-
51-
if (string.IsNullOrWhiteSpace(enc))
52-
throw LogHelper.LogArgumentNullException(nameof(enc));
54+
if (certificate == null)
55+
throw LogHelper.LogArgumentNullException(nameof(certificate));
5356

57+
Key = new X509SecurityKey(certificate);
5458
Alg = alg;
5559
Enc = enc;
60+
}
61+
62+
/// <summary>
63+
/// Initializes a new instance of the <see cref="EncryptingCredentials"/> class.
64+
/// </summary>
65+
/// <param name="key"><see cref="SecurityKey"/> to use when encrypting a session key.</param>
66+
/// <param name="alg">A key wrap algorithm to use when encrypting a session key.</param>
67+
/// <param name="enc">Data encryption algorithm to apply.</param>
68+
/// <exception cref="ArgumentNullException">if 'key' is null.</exception>
69+
/// <exception cref="ArgumentNullException">if 'alg' is null or empty.</exception>
70+
/// <exception cref="ArgumentNullException">if 'enc' is null or empty.</exception>
71+
public EncryptingCredentials(SecurityKey key, string alg, string enc)
72+
{
5673
Key = key;
74+
Alg = alg;
75+
Enc = enc;
76+
}
77+
78+
/// <summary>
79+
/// Initializes a new instance of the <see cref="EncryptingCredentials"/> class.
80+
/// </summary>
81+
/// <remarks> Used in scenarios when a key represents a 'shared' symmetric key.
82+
/// For example, SAML 2.0 Assertion will be encrypted using a provided symmetric key
83+
/// which won't be serialized to a SAML token.
84+
/// </remarks>
85+
/// <param name="key"><see cref="SymmetricSecurityKey"/> to apply.</param>
86+
/// <param name="enc">Data encryption algorithm to apply.</param>
87+
/// <exception cref="ArgumentException">If the <see cref="SecurityKey"/> is not a <see cref="SymmetricSecurityKey"/>.</exception>
88+
/// <exception cref="ArgumentNullException">if 'enc' is null or empty.</exception>
89+
public EncryptingCredentials(SymmetricSecurityKey key, string enc)
90+
: this(key, SecurityAlgorithms.None, enc)
91+
{
5792
}
5893

5994
/// <summary>
60-
/// Gets the algorithm which used for token encryption.
95+
/// Gets the key wrap algorithm used for session key encryption.
6196
/// </summary>
6297
public string Alg
6398
{
64-
get;
65-
private set;
99+
get => _alg;
100+
private set => _alg = string.IsNullOrEmpty(value) ? throw LogHelper.LogArgumentNullException("alg") : value;
66101
}
67102

68103
/// <summary>
69-
/// Gets the algorithm which used for token encryption.
104+
/// Gets the data encryption algorithm.
70105
/// </summary>
71106
public string Enc
72107
{
73-
get;
74-
private set;
108+
get => _enc;
109+
private set => _enc = string.IsNullOrEmpty(value) ? throw LogHelper.LogArgumentNullException("enc") : value;
75110
}
76111

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

82117
/// <summary>
83-
/// Gets the <see cref="SecurityKey"/> which used for signature valdiation.
118+
/// Gets the <see cref="SecurityKey"/> used for encryption.
84119
/// </summary>
85120
public SecurityKey Key
86121
{
87-
get;
88-
private set;
122+
get => _key;
123+
private set => _key = value ?? throw LogHelper.LogArgumentNullException("key");
89124
}
90125
}
91126
}

src/Microsoft.IdentityModel.Tokens/SecurityAlgorithms.cs

+3
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ public static class SecurityAlgorithms
113113
public const string Aes192CbcHmacSha384 = "A192CBC-HS384";
114114
public const string Aes256CbcHmacSha512 = "A256CBC-HS512";
115115

116+
internal const string DefaultAsymmetricKeyWrapAlgorithm = RsaOaepKeyWrap;
117+
internal const string DefaultSymmetricEncryptionAlgorithm = Aes128CbcHmacSha256;
118+
116119
#pragma warning restore 1591
117120
}
118121
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//------------------------------------------------------------------------------
2+
//
3+
// Copyright (c) Microsoft Corporation.
4+
// All rights reserved.
5+
//
6+
// This code is licensed under the MIT License.
7+
//
8+
// Permission is hereby granted, free of charge, to any person obtaining a copy
9+
// of this software and associated documentation files(the "Software"), to deal
10+
// in the Software without restriction, including without limitation the rights
11+
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
12+
// copies of the Software, and to permit persons to whom the Software is
13+
// furnished to do so, subject to the following conditions :
14+
//
15+
// The above copyright notice and this permission notice shall be included in
16+
// all copies or substantial portions of the Software.
17+
//
18+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
21+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
// THE SOFTWARE.
25+
//
26+
//------------------------------------------------------------------------------
27+
28+
using System;
29+
using System.Security.Cryptography.X509Certificates;
30+
31+
namespace Microsoft.IdentityModel.Tokens
32+
{
33+
/// <summary>
34+
/// An <see cref="X509EncryptingCredentials"/> designed to construct <see cref="EncryptingCredentials"/> based on a x509 certificate.
35+
/// </summary>
36+
public class X509EncryptingCredentials : EncryptingCredentials
37+
{
38+
/// <summary>
39+
/// Designed to construct <see cref="EncryptingCredentials"/> based on a x509 certificate.
40+
/// </summary>
41+
/// <param name="certificate">A <see cref="X509Certificate2"/></param>
42+
/// <remarks>
43+
/// <see cref="SecurityAlgorithms.DefaultAsymmetricKeyWrapAlgorithm"/> will be used as the key wrap algorithm
44+
/// <see cref="SecurityAlgorithms.DefaultSymmetricEncryptionAlgorithm"/> will be used as the data encryption algorithm
45+
/// </remarks>
46+
/// <exception cref="ArgumentNullException">if 'certificate' is null.</exception>
47+
public X509EncryptingCredentials(X509Certificate2 certificate)
48+
: this(certificate, SecurityAlgorithms.DefaultAsymmetricKeyWrapAlgorithm, SecurityAlgorithms.DefaultSymmetricEncryptionAlgorithm)
49+
{
50+
}
51+
52+
/// <summary>
53+
/// Designed to construct <see cref="EncryptingCredentials"/> based on the x509 certificate, a key wrap algorithm, and data encryption algorithm.
54+
/// </summary>
55+
/// <param name="certificate">A <see cref="X509Certificate2"/></param>
56+
/// <param name="keyWrapAlgorithm">A key wrap algorithm</param>
57+
/// <param name="dataEncryptionAlgorithm">Data encryption algorithm</param>
58+
/// <exception cref="ArgumentNullException">if 'certificate' is null.</exception>
59+
/// <exception cref="ArgumentNullException">if 'keyWrapAlgorithm' is null or empty.</exception>
60+
/// <exception cref="ArgumentNullException">if 'dataEncryptionAlgorithm' is null or empty.</exception>
61+
public X509EncryptingCredentials(X509Certificate2 certificate, string keyWrapAlgorithm, string dataEncryptionAlgorithm)
62+
: base(certificate, keyWrapAlgorithm, dataEncryptionAlgorithm)
63+
{
64+
Certificate = certificate;
65+
}
66+
67+
/// <summary>
68+
/// Gets the <see cref="X509Certificate2"/> used by this instance.
69+
/// </summary>
70+
public X509Certificate2 Certificate
71+
{
72+
get;
73+
private set;
74+
}
75+
}
76+
}

test/Microsoft.IdentityModel.Tests/Default.cs

+5
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ public static SecurityKey AsymmetricSigningKeyPublic
117117
get => new X509SecurityKey(KeyingMaterial.DefaultCert_2048_Public);
118118
}
119119

120+
public static SecurityKey AsymmetricEncryptionKeyPublic
121+
{
122+
get => new X509SecurityKey(KeyingMaterial.DefaultCert_2048_Public);
123+
}
124+
120125
#if !CrossVersionTokenValidation
121126
public static TokenValidationParameters AsymmetricEncryptSignTokenValidationParameters
122127
{

test/Microsoft.IdentityModel.Tests/TestUtilities.cs

+8
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,14 @@ public static void CheckForArgumentNull(CompareContext context, string name, Exc
417417
context.Diffs.Add($"!(ex is ArgumentNullException) || !ex.Message.Contains({name})");
418418
}
419419

420+
public static void CheckForArgumentException(CompareContext context, string name, Exception ex)
421+
{
422+
if (ex == null)
423+
context.Diffs.Add($"expecting ArgumentException for parameter {name}. Exception is null.");
424+
else if (!(ex is ArgumentException) || !ex.Message.Contains(name))
425+
context.Diffs.Add($"!(ex is ArgumentException) || !ex.Message.Contains({name})");
426+
}
427+
420428
public static byte[] HexToByteArray(string hexString)
421429
{
422430
byte[] bytes = new byte[hexString.Length / 2];

0 commit comments

Comments
 (0)