Skip to content

Commit bd0aa21

Browse files
committed
Add X509EncryptedCredentials class
* If only the certificate is provided, key wrap encryption algorithm and data encryption algorithm will be set by default to RsaOaepKeyWrap and A128CBC-HS256, respectively. * Add internal const strings DefaultAsymmetricKeyWrapAlgorithm and DefaultSymmetricAlgorithm to indicate the default algorithms used for encryption * 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 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 so null/empty checks are moved to setters Resolves: #995 See also: #734
1 parent 55db027 commit bd0aa21

File tree

4 files changed

+141
-18
lines changed

4 files changed

+141
-18
lines changed

src/Microsoft.IdentityModel.Tokens/EncryptingCredentials.cs

+60-18
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
//
2626
//------------------------------------------------------------------------------
2727

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

3032
namespace Microsoft.IdentityModel.Tokens
@@ -34,58 +36,98 @@ namespace Microsoft.IdentityModel.Tokens
3436
/// </summary>
3537
public class EncryptingCredentials
3638
{
39+
private string _alg;
40+
private string _enc;
41+
private SecurityKey _key;
42+
43+
/// <summary>
44+
/// Initializes a new instance of the <see cref="EncryptingCredentials"/> class.
45+
/// </summary>
46+
/// <param name="certificate"><see cref="X509Certificate2"/>.</param>
47+
/// <param name="alg">Key encryption algorithm to apply.</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)
53+
{
54+
if (certificate == null)
55+
throw LogHelper.LogArgumentNullException(nameof(certificate));
56+
57+
Key = new X509SecurityKey(certificate);
58+
Alg = alg;
59+
Enc = enc;
60+
}
61+
3762
/// <summary>
3863
/// Initializes a new instance of the <see cref="EncryptingCredentials"/> class.
3964
/// </summary>
4065
/// <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>
66+
/// <param name="alg">Key encryption algorithm to apply.</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>
4371
public EncryptingCredentials(SecurityKey key, string alg, string enc)
4472
{
45-
if (key == null)
46-
throw LogHelper.LogArgumentNullException(nameof(key));
73+
Key = key;
74+
Alg = alg;
75+
Enc = enc;
76+
}
4777

48-
if (string.IsNullOrWhiteSpace(alg))
49-
throw LogHelper.LogArgumentNullException(nameof(alg));
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="SecurityKey"/></param>
86+
/// <param name="enc">Data encryption algorithm to apply</param>
87+
/// <exception cref="ArgumentException">If the <see cref="SecurityKey"/> is not <see cref="SymmetricSecurityKey"/>.</exception>
88+
/// <exception cref="ArgumentNullException">if 'enc' is null or empty.</exception>
89+
public EncryptingCredentials(SecurityKey key, string enc)
90+
{
91+
Key = key;
5092

51-
if (string.IsNullOrWhiteSpace(enc))
52-
throw LogHelper.LogArgumentNullException(nameof(enc));
93+
if (key.GetType() != typeof(SymmetricSecurityKey))
94+
throw LogHelper.LogArgumentException<ArgumentException>("key", LogMessages.IDX10704);
5395

54-
Alg = alg;
96+
//explicitly setting Alg to None
97+
Alg = SecurityAlgorithms.None;
5598
Enc = enc;
56-
Key = key;
5799
}
58100

59101
/// <summary>
60102
/// Gets the algorithm which used for token encryption.
61103
/// </summary>
62104
public string Alg
63105
{
64-
get;
65-
private set;
106+
get => _alg;
107+
private set => _alg = string.IsNullOrEmpty(value) ? throw LogHelper.LogArgumentNullException("alg") : value;
66108
}
67109

68110
/// <summary>
69111
/// Gets the algorithm which used for token encryption.
70112
/// </summary>
71113
public string Enc
72114
{
73-
get;
74-
private set;
115+
get => _enc;
116+
private set => _enc = string.IsNullOrEmpty(value) ? throw LogHelper.LogArgumentNullException("enc") : value;
75117
}
76118

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

82124
/// <summary>
83-
/// Gets the <see cref="SecurityKey"/> which used for signature valdiation.
125+
/// Gets the <see cref="SecurityKey"/> which used for signature validation.
84126
/// </summary>
85127
public SecurityKey Key
86128
{
87-
get;
88-
private set;
129+
get => _key;
130+
private set => _key = value ?? throw LogHelper.LogArgumentNullException("key");
89131
}
90132
}
91133
}

src/Microsoft.IdentityModel.Tokens/LogMessages.cs

+1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ internal static class LogMessages
178178
public const string IDX10701 = "IDX10701: Invalid JsonWebKey rsa keying material: '{0}'. Both modulus and exponent should be present";
179179
public const string IDX10702 = "IDX10702: One or more private RSA key parts are null in the JsonWebKey: '{0}'";
180180
public const string IDX10703 = "IDX10703: Cannot create symmetric security key. Key length is zero.";
181+
public const string IDX10704 = "IDX10704: The SecurityKey provided is not a SymmetricSecurityKey.";
181182

182183
// Json specific errors
183184
public const string IDX10801 = "IDX10801: Unable to create an RSA public key from the Exponent and Modulus found in the JsonWebKey: E: '{0}', N: '{1}'. See inner exception for additional details.";

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 DefaultSymmetricAlgorithm = Aes128CbcHmacSha256;
118+
116119
#pragma warning restore 1591
117120
}
118121
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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 for to construct an <see cref="EncryptingCredentials"/> based on a x509 certificate.
35+
/// </summary>
36+
public class X509EncryptingCredentials : EncryptingCredentials
37+
{
38+
/// <summary>
39+
/// Constructs an <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"/> algorithm will be used by default as a key wrap encryption algorithm
44+
/// <see cref="SecurityAlgorithms.DefaultSymmetricAlgorithm"/> algorithm will be used by default as a 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.DefaultSymmetricAlgorithm)
49+
{
50+
51+
}
52+
53+
/// <summary>
54+
/// Constructs an <see cref="EncryptingCredentials"/> based on the x509 certificate, key wrapping algorithm, and data encryption algorithm.
55+
/// </summary>
56+
/// <param name="certificate">A <see cref="X509Certificate2"/></param>
57+
/// <param name="keyWrapEncryptionAlgorithm">A key wrapping algorithm</param>
58+
/// <param name="dataEncryptionAlgorithm">A data encryption algorithm</param>
59+
/// <exception cref="ArgumentNullException">if 'certificate' is null.</exception>
60+
/// <exception cref="ArgumentNullException">if 'keyWrapEncryptionAlgorithm' is null or empty.</exception>
61+
/// <exception cref="ArgumentNullException">if 'dataEncryptionAlgorithm' is null or empty.</exception>
62+
public X509EncryptingCredentials(X509Certificate2 certificate, string keyWrapEncryptionAlgorithm, string dataEncryptionAlgorithm)
63+
: base(new X509SecurityKey(certificate), keyWrapEncryptionAlgorithm, dataEncryptionAlgorithm)
64+
{
65+
Certificate = certificate;
66+
}
67+
68+
/// <summary>
69+
/// Gets a <see cref="X509Certificate2"/> used by this instance.
70+
/// </summary>
71+
public X509Certificate2 Certificate
72+
{
73+
get;
74+
private set;
75+
}
76+
}
77+
}

0 commit comments

Comments
 (0)