使用本地帐户访问证书密钥时域帐户被锁定
The domain account is locked out when certificate key is accessed with local account
当我访问从使用 BouncyCastle 生成的对象初始化的 X509Certificate2.PublicKey 或 X509Certificate2.PrivateKey 时,我的域帐户被锁定(如果我多次这样做)。如果我 运行 代表具有相同名称但密码不同的本地帐户的程序,则会发生这种情况。这是代码:
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using System.IO;
using System.Security.Cryptography.X509Certificates;
namespace TestCertificateConversion
{
class Program
{
static void Main(string[] args)
{
var certString = GetCertificateString();
var textReader = new StringReader(certString);
var pemReader = new PemReader(textReader);
var bcCert = pemReader.ReadObject() as Org.BouncyCastle.X509.X509Certificate;
var netCert = DotNetUtilities.ToX509Certificate(bcCert);
var netCert2 = new X509Certificate2(netCert);
var publicKey = netCert2.PublicKey; // this locks out domain account
}
private static string GetCertificateString()
{
return @"-----BEGIN CERTIFICATE-----
MIICvDCCAaSgAwIBAgIQANDHl0sFjYUG3j76dYTadzANBgkqhkiG9w0BAQsFADAQ
MQ4wDAYDVQQDDAVwYWNlbTAgFw0xNjAxMDExMjQ4MzdaGA8yMjAwMDEwMTIyNTg0
N1owEDEOMAwGA1UEAwwFcGFjZW0wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQC5AKAkYnerRUmeAX0Z+aZsX39LXTVZiUd8U6waw7Hzd9E0YA50tHWizfEI
w7IBZwXS0aiXwHqJvrslc3NNs0grwu/iYQl+FGdudKmgXVE7Riu0uFAHo6eFr0dO
o0IP3LS+dPSWarXEBLbymaXRiPJDyHLefvslcSM9UQ2BHOe7dnHh9K1h+XMKTw3Z
/3szAyABBX9hsJU/mc9XjrMNXHJXALSxTfLIPzDrfh+aJtlopWpnb6vQcXwKksyk
4hyVUfw1klhglJgN0LgBGU7Ps3oxCbOqns7fB+tzkBV1E5Q97otgvMR14qLZgc8k
NQrdMl57GaWQJl6mAP1NR1gZt2f1AgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ
KoZIhvcNAQELBQADggEBAAEz3vJOfqao9QXPWSz8YCjbWG1FeVG0NdYpd422dC2V
Vrzlo5zrkRv5XPhBOY3o81OhUe7iByiiM9suYfXLNxxd29TBGB5amO8Yv1ZX0hS/
zvVF6QS0+zZvOiujVhfHGiJxKypqgaigI6NM80ZDKPzsRPwFLIJiZYwQ7eQUlrpt
WGgFkZC23/mSOkY6VMmO5zugeMoiXRyFq33uWLlaAr+zJtRh1IPRmkA1lJv0bkC1
SslO0oSDoT2lcvZkQ5odFKX5i1z7T/wioQqG62i8nsDSz+iZOqUyDx7bL8fIEHog
qgwizgr2aAPLO/VQKU9pRTyRNFl/GL5bi7w8NN+rLxE=
-----END CERTIFICATE-----";
}
}
}
我不确定自己做错了什么,是否需要更改任何安全设置以防止它锁定域帐户?
您能否检查并确认服务帐户是否采用这种格式
我检查了 .net 源代码并在 X509Certificate2.PublicKey 中找到了导致身份验证问题的原因。它是一个新的 OID 对象的创建:
public PublicKey PublicKey {
[SecuritySafeCritical]
get {
if (m_safeCertContext.IsInvalid)
throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
if (m_publicKey == null) {
string friendlyName = this.GetKeyAlgorithm();
byte[] parameters = this.GetKeyAlgorithmParameters();
byte[] keyValue = this.GetPublicKey();
Oid oid = new Oid(friendlyName, OidGroup.PublicKeyAlgorithm, true); // this line
m_publicKey = new PublicKey(oid, new AsnEncodedData(oid, parameters), new AsnEncodedData(oid, keyValue));
}
return m_publicKey;
}
}
调用 OID 构造函数时将 lookupFriendlyName 设置为 'true',这会导致 FindOidInfoWithFallback 函数:
// Try to find OID info within a specific group, and if that doesn't work fall back to all
// groups for compatibility with previous frameworks
internal static string FindOidInfoWithFallback(uint key, string value, OidGroup group)
{
string info = FindOidInfo(key, value, group);
// If we couldn't find it in the requested group, then try again in all groups
if (info == null && group != OidGroup.All)
{
info = FindOidInfo(key, value, OidGroup.All);
}
return info;
}
第一次FindOidInfo returns null 然后第二次用OidGroup.All调用。最终它导致 cryptAPI 调用:
CAPIMethods.CryptFindOIDInfo(dwKeyType, pvKey, dwGroupId);
The CryptFindOIDInfo function performs a lookup in the active
directory to retrieve the friendly names of OIDs under the following
conditions:
- The key type in the dwKeyType parameter is set to CRYPT_OID_INFO_OID_KEY or CRYPT_OID_INFO_NAME_KEY.
- No group identifier is specified in the dwGroupId parameter or the GroupID refers to EKU OIDs, policy OIDs or template OIDs.
然后它尝试使用本地用户帐户进行身份验证,结果我的域帐户被锁定。从对代码的评论中,我看到添加了第二个 FindOidInfo 调用是为了与旧框架兼容,我可能可以将其删除。不幸的是,更改代码并不容易,因为它在框架本身中。我可能会尝试继承 X509Certificate2 对象并重写 PublicKey 和 PrivateKey,但我不太喜欢这个想法。
当我访问从使用 BouncyCastle 生成的对象初始化的 X509Certificate2.PublicKey 或 X509Certificate2.PrivateKey 时,我的域帐户被锁定(如果我多次这样做)。如果我 运行 代表具有相同名称但密码不同的本地帐户的程序,则会发生这种情况。这是代码:
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using System.IO;
using System.Security.Cryptography.X509Certificates;
namespace TestCertificateConversion
{
class Program
{
static void Main(string[] args)
{
var certString = GetCertificateString();
var textReader = new StringReader(certString);
var pemReader = new PemReader(textReader);
var bcCert = pemReader.ReadObject() as Org.BouncyCastle.X509.X509Certificate;
var netCert = DotNetUtilities.ToX509Certificate(bcCert);
var netCert2 = new X509Certificate2(netCert);
var publicKey = netCert2.PublicKey; // this locks out domain account
}
private static string GetCertificateString()
{
return @"-----BEGIN CERTIFICATE-----
MIICvDCCAaSgAwIBAgIQANDHl0sFjYUG3j76dYTadzANBgkqhkiG9w0BAQsFADAQ
MQ4wDAYDVQQDDAVwYWNlbTAgFw0xNjAxMDExMjQ4MzdaGA8yMjAwMDEwMTIyNTg0
N1owEDEOMAwGA1UEAwwFcGFjZW0wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQC5AKAkYnerRUmeAX0Z+aZsX39LXTVZiUd8U6waw7Hzd9E0YA50tHWizfEI
w7IBZwXS0aiXwHqJvrslc3NNs0grwu/iYQl+FGdudKmgXVE7Riu0uFAHo6eFr0dO
o0IP3LS+dPSWarXEBLbymaXRiPJDyHLefvslcSM9UQ2BHOe7dnHh9K1h+XMKTw3Z
/3szAyABBX9hsJU/mc9XjrMNXHJXALSxTfLIPzDrfh+aJtlopWpnb6vQcXwKksyk
4hyVUfw1klhglJgN0LgBGU7Ps3oxCbOqns7fB+tzkBV1E5Q97otgvMR14qLZgc8k
NQrdMl57GaWQJl6mAP1NR1gZt2f1AgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ
KoZIhvcNAQELBQADggEBAAEz3vJOfqao9QXPWSz8YCjbWG1FeVG0NdYpd422dC2V
Vrzlo5zrkRv5XPhBOY3o81OhUe7iByiiM9suYfXLNxxd29TBGB5amO8Yv1ZX0hS/
zvVF6QS0+zZvOiujVhfHGiJxKypqgaigI6NM80ZDKPzsRPwFLIJiZYwQ7eQUlrpt
WGgFkZC23/mSOkY6VMmO5zugeMoiXRyFq33uWLlaAr+zJtRh1IPRmkA1lJv0bkC1
SslO0oSDoT2lcvZkQ5odFKX5i1z7T/wioQqG62i8nsDSz+iZOqUyDx7bL8fIEHog
qgwizgr2aAPLO/VQKU9pRTyRNFl/GL5bi7w8NN+rLxE=
-----END CERTIFICATE-----";
}
}
}
我不确定自己做错了什么,是否需要更改任何安全设置以防止它锁定域帐户?
您能否检查并确认服务帐户是否采用这种格式
我检查了 .net 源代码并在 X509Certificate2.PublicKey 中找到了导致身份验证问题的原因。它是一个新的 OID 对象的创建:
public PublicKey PublicKey {
[SecuritySafeCritical]
get {
if (m_safeCertContext.IsInvalid)
throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
if (m_publicKey == null) {
string friendlyName = this.GetKeyAlgorithm();
byte[] parameters = this.GetKeyAlgorithmParameters();
byte[] keyValue = this.GetPublicKey();
Oid oid = new Oid(friendlyName, OidGroup.PublicKeyAlgorithm, true); // this line
m_publicKey = new PublicKey(oid, new AsnEncodedData(oid, parameters), new AsnEncodedData(oid, keyValue));
}
return m_publicKey;
}
}
调用 OID 构造函数时将 lookupFriendlyName 设置为 'true',这会导致 FindOidInfoWithFallback 函数:
// Try to find OID info within a specific group, and if that doesn't work fall back to all
// groups for compatibility with previous frameworks
internal static string FindOidInfoWithFallback(uint key, string value, OidGroup group)
{
string info = FindOidInfo(key, value, group);
// If we couldn't find it in the requested group, then try again in all groups
if (info == null && group != OidGroup.All)
{
info = FindOidInfo(key, value, OidGroup.All);
}
return info;
}
第一次FindOidInfo returns null 然后第二次用OidGroup.All调用。最终它导致 cryptAPI 调用:
CAPIMethods.CryptFindOIDInfo(dwKeyType, pvKey, dwGroupId);
The CryptFindOIDInfo function performs a lookup in the active directory to retrieve the friendly names of OIDs under the following conditions:
- The key type in the dwKeyType parameter is set to CRYPT_OID_INFO_OID_KEY or CRYPT_OID_INFO_NAME_KEY.
- No group identifier is specified in the dwGroupId parameter or the GroupID refers to EKU OIDs, policy OIDs or template OIDs.
然后它尝试使用本地用户帐户进行身份验证,结果我的域帐户被锁定。从对代码的评论中,我看到添加了第二个 FindOidInfo 调用是为了与旧框架兼容,我可能可以将其删除。不幸的是,更改代码并不容易,因为它在框架本身中。我可能会尝试继承 X509Certificate2 对象并重写 PublicKey 和 PrivateKey,但我不太喜欢这个想法。