如何从客户端证书中读取通用名称
本文关键字:读取 客户端 证书 | 更新日期: 2023-09-27 18:20:46
我们的应用程序需要一段数据,该数据包含在客户端证书的通用名称中。目前,我正在尝试从HttpContext.Current.Request.ClientCertificate获取它。我该如何读取它?遗憾的是,当我弄清楚SoapUI为什么不发送证书时,我正试图对其进行盲编码,所以除了在MSDN上阅读有关该对象的信息和浏览空属性之外,我没有尝试过太多,但我不确定我在寻找什么。综上所述,我需要做些什么才能从这个证书中提取通用名称?TIA
我可能来不及回答您的问题,但我希望这能帮助其他正在寻找从证书中获取通用名称的方法的人。
如果使用"主题",则可能需要删除其他不必要的信息。例如,CN=localhost,OU=DepartmentName,O=CompanyName,L=Location,S=State,C=Country
Dim store As New X509Store(StoreName.My, StoreLocation.LocalMachine)
store.Open(OpenFlags.ReadOnly)
store.Certificates(0).Subject
但是,如果您使用下面的代码,您将获得"localhost",它直接为您提供证书的通用名称。
Dim store As New X509Store(StoreName.My, StoreLocation.LocalMachine)
store.Open(OpenFlags.ReadOnly)
store.Certificates(0).GetNameInfo(X509NameType.SimpleName, False)
以下链接可供参考:-https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.getnameinfo(v=vs.110).aspx
我对证书略知一二。这是我的工作流程:
我开始于:
HttpRequest.ClientCertificate
这让我想到:
HttpClientCertificate(作为返回类型)。
它似乎有一些属性,但没有一个明确命名为公共名称。
谷歌搜索:HttpClientCertificate通用名称:
从web服务端上的上下文提取X509证书时出现问题
它有一些代码:
//extracting Common name from certificate
Subject = cert.Subject.ToString();
然后转到:
HttpClientCertificate.Subject
备注:
如果指定了不带子字段的String,HttpClientCertificate集合将返回以逗号分隔的子字段列表。例如,C=US,O=Msft。
根据我所掌握的极其有限的知识,我知道Common Name=在这个列表中。我目前还没有实际的方法来测试这个,但解析这个值以获得您要查找的名称应该不难。
这是一个很好的问题(+1),我很高兴你问它,因为它可能对未来的读者有用。
我创建了一个DotNetFiddle示例,尽管它使用HttpWebRequest来获得X509Certificate类,但它确实有一个Subject属性,该属性在www.google.com上为https返回了以下值:
CN=www.google.com,O=谷歌公司,L=山景城,S=加利福尼亚州,C=美国
所以我倾向于相信HttpClientCertificate上的Subject将是相同的值(知道CN的意思是CommonName)。
只是Linq中的一个oneliner。
var kvs = cert.Subject.Split(',').Select(x => new KeyValuePair<string, string>(x.Split('=')[0], x.Split('=')[1])).ToList();
返回一个通用列表。不要在这里使用字典,因为主题可能包含重复的字段。
由于证书格式的差异,您可能需要进行调整。
这里有一些代码可以做到这一点:
HttpClientCertificate theHttpCertificate = HttpContext.Current.Request.ClientCertificate;
// split the subject into its parts
string[] subjectArray = theHttpCertificate.Subject.Split(',');
string[] nameParts;
string CN = string.Empty;
string firstName = string.Empty;
string lastName = string.Empty;
foreach (string item in subjectArray)
{
string[] oneItem = item.Split('=');
// Split the Subject CN information
if (oneItem[0].Trim() == "CN")
{
CN = oneItem[1];
if (CN.IndexOf(".") > 0)
{// Split the name information
nameParts = CN.Split('.');
lastName = nameParts[0];
firstName = nameParts[1];
}
}
}
我创建了这个扩展来处理主题名称的所有单独元素。
public enum SubjectNameElements {CN,O,L,OU,S,C,}
public static readonly Dictionary<SubjectNameElements, string> SubNameSybms =
new Dictionary<SubjectNameElements, string>{
{ SubjectNameElements.CN,"CN="},
{ SubjectNameElements.O ,"O="},
{ SubjectNameElements.L ,"L="},
{ SubjectNameElements.OU,"OU="},
{ SubjectNameElements.S ,"S="},
{ SubjectNameElements.C ,"C="},
};
/// <summary>
/// Retrieve CN from subject Name of a certificate
/// </summary>
/// <param name="subjName"></param>
/// <param name="symb"></param>
/// <remarks>
/// Example:
/// GetOneElementFromSubjectName("C=IT, S=Italy, L=Torino, O=Example Italy S.p.A., OU=Example-Client, CN=www.google.com",SubjectNameElements.CN) => www.google.com
/// </remarks>
/// <returns> a string value or empty string in case of invalid options </returns>
public static string GetOneElementFromSubjectName(this X500DistinguishedName subjName, SubjectNameElements symb=SubjectNameElements.CN)
{
string subjNameString = subjName.Name;
try
{
string Symb = SubNameSybms[symb];
string CName = subjNameString.Substring(subjNameString.IndexOf(Symb)).Split(",").First().Replace(Symb, string.Empty).Trim();
return CName;
}
catch (Exception ex)
{
Log.Error("Error in GetOneElementFromSubjectName. Ex.Message: '" + ex.Message + "'. Ex.StackTrace: '" + ex.StackTrace + "'");
return string.Empty;
}
}
最好的方法是使用内置的GetNameInfo方法,使用名称类型和布尔标志
假设您使用以下扩展方法:
[return:MaybeNull]
public static X509Certificate2? GetCodeSignCertificate(this Assembly asm)
{
if (asm is null)
{
throw new ArgumentNullException(nameof(asm));
}
if (!File.Exists(asm.Location))
{
return null;
}
using var cert=System.Security.Cryptography.X509Certificates.X509Certificate.CreateFromSignedFile(asm.Location);
if (cert is null)
return null;
return new X509Certificate2(cert);
}
然后,您可以在类中使用一个类型来获得证书,如下所示:
[TestMethod()]
public void TryGetCodeSigning()
{
//var item = new Walter.CallStack();
var item = new List<string>();
using var cert = item.GetType().Assembly.GetCodeSignCertificate();
Assert.IsNotNull(cert.GetNameInfo(X509NameType.SimpleName,true));
}
获取证书签名机构的名称
cert.GetNameInfo(X509NameType.SimpleName,true)
以获取证书签名者的姓名
cert.GetNameInfo(X509NameType.SimpleName,false)
看看X509NameType,看看这是否适合你。